http://wiki.jabbercn.org/api.php?action=feedcontributions&user=Snowqiang&feedformat=atom
Jabber/XMPP中文翻译计划 - 用户贡献 [zh-cn]
2024-03-28T09:13:06Z
用户贡献
MediaWiki 1.18.2
http://wiki.jabbercn.org/XEP-0060
XEP-0060
2011-05-20T04:40:26Z
<p>Snowqiang: </p>
<hr />
<div>[[Category:XMPP扩展]]<br />
[[Category:翻译中]]<br />
<br />
'''本文的英文原文来自[http://www.xmpp.org/extensions/xep-0060.html XEP-0060]<br />
<br />
'''XEP-0060: 发布-订阅'''<br />
<br />
摘要: 本文定义了一个XMPP协议扩展来实现实现通用的 发布-订阅 功能。这个协议使 XMPP实体能在一个pubsub服务创建节点(主题)并发布信息到那些节点上;然后一个事件通知被广播到所有订阅了该节点的实体. PubSub因此坚持了经典的观察者设计模式,并可以作为广泛应用的服务基础,包括新闻提要,内容整合,富出席信息,地理位置,工作流系统,网络管理系统,以及任何其他需要事件通知的应用。<br />
<br />
作者: Peter Millard, Peter Saint-Andre, Ralph Meijer<br />
<br />
版权: © 1999 - 2010 XMPP标准化基金会(XSF). 参见[[XEP-0060#附录C:法律通告|法律通告]].<br />
<br />
状态: 草案<br />
<br />
类型: 标准跟踪<br />
<br />
版本: 1.13rc6<br />
<br />
最后更新日期: 进展中,2009-10-01<br />
<br />
----<br />
注意: 这里定义的协议是XMPP标准化基金会的一个'''草案标准'''.对本协议的执行是被鼓励的,也适于布署到生产系统,但是在它成为最终标准之前可能还会有一些变动.<br />
----<br />
<br />
==绪论==<br />
<br />
===概览===<br />
<br />
本文定义的XMPP 发布-订阅 扩展提供了一个框架用于广泛的应用, 包括新闻摘要, 内容整合, 扩展的出席信息, 地理位置, 头像管理, 共享的标签, 拍卖和贸易系统, 工作流系统, 网络管理系统, NNTP网关, 资料管理, 以及任何其他需要事件通知的应用.<br />
<br />
这个技术使用了经典的 "发布-订阅" 或曰 "观察者" 设计模式: 一个人或应用发布信息, 同时一个事件通知 (包含或不包含有效载荷) 被广播到所有授权的订阅者. 通常, 发布者和订阅者之间的联系是由一个服务来调节的,这个服务接收发布请求,广播事件通知到订阅者, 并使有权限的实体能够管理被授权发布或订阅的人员或应用列表. 对于发布和订阅的焦点是一个节点 "node" ,它是发布者发送数据的目的地,也是订阅者接收通知的目的地. 节点也维护一个事件历史并提供其他服务以补充纯的 pubsub 模式.<br />
<br />
本文定义一个通用的协议,所有 pubsub 应用都能使用. 兼容的实现不需要实现这里定义的所有特性 (参见 [[XEP-0060#特性汇总|特性汇总]].) 其他协议可以定义 发布-订阅 的子集 "subsets" 或范本 "profiles" 用于特定的场合, 但是这些范本超过了本文的范围.<br />
<br />
===它如何工作===<br />
<br />
尽管本协议很大,因为它定义了很多方面的用例, 基本的思路是简单的:<br />
<br />
# 一个实体发布信息到一个 发布-订阅 服务上的一个节点.<br />
# pubsub服务推送一个通知到所有被授权可以得知该发布信息的实体.<br />
<br />
可能最流行的 发布-订阅 功能的应用是内容联合, 它常见于和博客,新闻网站,以及其他互联网可用的经常更新的信息相关联的 RSS 和 Atom ([http://tools.ietf.org/html/rfc4287 RFC 4287] [[XEP-0060#附录G:备注|1]]) 种子. 设想一个<hamlet@denmark.lit>的博客发布例子. 当 Hamlet 写下一篇新博文, 他的博客软件发布该文到一个位于<pubsub.shakespeare.lit>的pubsub节点:<br />
<br />
'''例子 1. 发布者发布一篇新博文'''<br />
<br />
<source lang="xml"><br />
<iq type='set'<br />
from='hamlet@denmark.lit/blogbot'<br />
to='pubsub.shakespeare.lit'<br />
id='pub1'><br />
<pubsub xmlns='http://jabber.org/protocol/pubsub'><br />
<publish node='princely_musings'><br />
<item><br />
<entry xmlns='http://www.w3.org/2005/Atom'><br />
<title>Soliloquy</title><br />
<summary><br />
To be, or not to be: that is the question:<br />
Whether 'tis nobler in the mind to suffer<br />
The slings and arrows of outrageous fortune,<br />
Or to take arms against a sea of troubles,<br />
And by opposing end them?<br />
</summary><br />
<link rel='alternate' type='text/html'<br />
href='http://denmark.lit/2003/12/13/atom03'/><br />
<id>tag:denmark.lit,2003:entry-32397</id><br />
<published>2003-12-13T18:30:02Z</published><br />
<updated>2003-12-13T18:30:02Z</updated><br />
</entry><br />
</item><br />
</publish><br />
</pubsub><br />
</iq><br />
</source><br />
<br />
所以那就是 发布-订阅 的发布 "pub" 部分.<br />
<br />
现在 pubsub 服务通知所有订阅者新博文:<br />
<br />
'''例子 2. 服务通知订阅者'''<br />
<br />
<source lang="xml"><br />
<message from='pubsub.shakespeare.lit' to='francisco@denmark.lit' id='foo'><br />
<event xmlns='http://jabber.org/protocol/pubsub#event'><br />
<items node='princely_musings'><br />
<item id='ae890ac52d0df67ed7cfdf51b644e901'><br />
[ ... ENTRY ... ]<br />
</item><br />
</items><br />
</event><br />
</message><br />
<br />
<message from='pubsub.shakespeare.lit' to='bernardo@denmark.lit' id='bar'><br />
<event xmlns='http://jabber.org/protocol/pubsub#event'><br />
<items node='princely_musings'><br />
<item id='ae890ac52d0df67ed7cfdf51b644e901'><br />
[ ... ENTRY ... ]<br />
</item><br />
</items><br />
</event><br />
</message><br />
<br />
<message from='pubsub.shakespeare.lit' to='horatio@denmark.lit' id='baz'><br />
<event xmlns='http://jabber.org/protocol/pubsub#event'><br />
<items node='princely_musings'><br />
<item id='ae890ac52d0df67ed7cfdf51b644e901'><br />
[ ... ENTRY ... ]<br />
</item><br />
</items><br />
</event><br />
</message><br />
<br />
<message from='pubsub.shakespeare.lit' to='bard@shakespeare.lit' id='fez'><br />
<event xmlns='http://jabber.org/protocol/pubsub#event'><br />
<items node='princely_musings'><br />
<item id='ae890ac52d0df67ed7cfdf51b644e901'><br />
[ ... ENTRY ... ]<br />
</item><br />
</items><br />
</event><br />
</message><br />
</source><br />
<br />
这里是一个甚至更简单的例子: 一个临时的节点只发送通知而不带有效载荷:<br />
<br />
'''例子 3. 一个临时通知'''<br />
<br />
<source lang="xml"><br />
<message from='pubsub.shakespeare.lit' to='francisco@denmark.lit'><br />
<event xmlns='http://jabber.org/protocol/pubsub#event'><br />
<items node='elsinore/doorbell'/><br />
</event><br />
</message><br />
</source><br />
<br />
自然, 涉及的实体为了得到完整的 pubsub 功能可能需要完成其他用例 -- 例如, 发布者可能需要建立一个节点 (见 [[XEP-0060#新建节点|新建节点]]) 并且订阅者可能需要为通知报名(见 [[XEP-0060#订阅节点|订阅节点]]). 这些用例在本文的 the remainder 有完整的描述. (关于哪些特性是必需的,哪些是推荐的活可选的信息, 参考 [[XEP-0060#特性汇总|特性汇总]].)<br />
<br />
==术语表===<br />
<br />
以下术语用于本文中涉及的pubsub服务中的元素,对象,或动作.(注意: 本文的一些术语在正文中有更详细的解释.)<br />
<br />
'''表 1: 出版-订阅 术语'''<br />
<br />
{|border="1" cellspacing="0" <br />
!术语 !! 译文 !! 术语解释<br />
|-<br />
|Authorize Access Model || 授权访问模式 || 一个节点访问模式,一个实体只能在所有者批准了订阅申请之后才能订阅(订阅申请被接受但是只是临时的),并且只有订阅者可以接收项目.<br />
|-<br />
|Address || 地址 || (1) 一个 JID (定义在 XMPP Core [2])中, 或 (2) 一个JID和一个服务发现的联合 3 节点.<br />
|-<br />
|Collection Node || 集合节点 || 一个节点类型,它包含很多节点 和/或 其他集合,但是不出版项目。集合使得多级节点结构成为可能<br />
|-<br />
|Entity || 实体 || 一个以JID为地址的实体 (客户端,服务,应用程序等).<br />
|-<br />
|Event || 事件 || 一个节点状态的一次变更<br />
|-<br />
|Instant Node || 即时节点 || 一个节点,它的NodeID由pubsub服务自动生成<br />
|-<br />
|Item || 条目 || 一个XML片段,它由一个节点发布, 从而生成一个事件<br />
|-<br />
|ItemID || 条目ID ||在一个一特定的节点中一个项目的唯一标识符<br />
|-<br />
|Leaf Node || 叶子节点 || 一个节点类型,它仅包含已出版的项目. 它不是其他节点的一个容器<br />
|-<br />
|Node || 节点 || 一个虚拟的位置,它的信息可以被发布,并且它的事件通知 和/或 有效载荷可以被接收(在其他pubsub系统中,可能被称为“topic”(主题))<br />
|-<br />
|NodeID || 节点ID || 在一个特定的pubsub服务中一个节点的唯一标识符,节点ID既由节点创建者提供,也由pubsub服务生成(如果节点创建者请求一个即时节点)。节点ID可以(MAY)有语义但是它的含义是可选的(OPTIONAL).<br />
|-<br />
|Notification || 通知 || 一个发送给订阅者的消息通知他们一个事件<br />
|-<br />
|Outcast || 被驱逐者 || 一个不被允许订阅或出版一个节点的实体<br />
|-<br />
|Owner || 所有者 || 一个节点的管理者,可能不止一个; 经常(但不是必要的)是节点创建者<br />
|-<br />
|Payload || 有效载荷 || 和一个事件相关的所有数据而不仅是事件通知本身.<br />
|-<br />
|Open Access Model || 公开访问模式 || 一个节点访问模式,任何实体可以不用申请订阅和接收项目<br />
|-<br />
|Personal Eventing || 私人事件 || 出版-订阅的一个简化的子集,用于即时消息和出席信息应用程序,每个用户的JID是一个虚拟的pubsub服务; 细节请看 Personal Eventing via Pubsub [4].<br />
|-<br />
|Presence Access Model || 出席信息访问模式 || 一个访问模式,任何订阅了所有者出席信息(以类型"from" 或 "both"订阅)的实体,可以订阅一个节点并从节点接收项目;这个访问模式主要应用于即时消息系统。<br />
|-<br />
|Publisher || 出版者 || 一个实体,被允许出版项目给一个节点<br />
|-<br />
|Pubsub Service || 出版服务 || 一个遵循本文所定义的协议的 XMPP 服务器或组件<br />
|-<br />
|Roster Access Model || 好友访问模式 || 一个节点访问模式,一个实体的出席信息被订阅了,只有特定的好友 组成员可以从节点订阅和接收项目;这个访问模式主要用于即时消息系统<br />
|-<br />
|Subscriber || 订阅者 || 订阅了某个节点的一个实体<br />
|-<br />
|Whitelist Access Model || 白名单访问模式 || 一个节点访问模式,一个实体只能被所有者为其添加订阅 ,并且只有订阅者可以接收项目<br />
|}<br />
<br />
==需求==<br />
<br />
pubsub服务的需求可能是由终端用户的需要驱动的,也包括其他可能使用这项服务的组件或服务器。首先,一个用Jabber实现的pubsub服务必须(MUST)提供基本的特性来实现一个纯的 出版-订阅 模式:<br />
<br />
* 一个实体必须(MUST)能够发布事件给一个服务,这样所有某个节点的订阅者能接收到事件通知.<br />
<br />
* 一个实体必须(MUST)被允许和一个节点从属。被允许的从属关系包括所有者(owner)、出版者(publisher)、无(none)、排斥者(outcast)。具体实现的时候,必须(MUST)支持所有者和无的关联,可以(MAY)支持排斥者和出版者的从属关系。<br />
<br />
* 一个实体必须(MUST)被允许查询一个pubsub服务(或一个指定的节点)以确定那些服务提供了本文定义的哪些可选的特性。这个查询必须(MUST)使用服务发现(disco#info)协议.<br />
<br />
* 一个实体必须(MUST)被允许查询一个节点以确定关于那个节点的非特性相关的信息(比如, 服务发现中的 类别和类型(category+type)). 这个查询必须使用服务发现 (disco#info) 协议.<br />
<br />
一些基于Jabber的pubsub服务可能需要使用其他特性,但是这些特性是可选的(OPTIONAL)所以不是和本协议强制兼容的。无论如何,如果以下这些特性被实现了,它们必须(MUST)按照此处本协议的规定来保证兼容性。这些特性包括:<br />
<br />
* 一个服务可以(MAY)对一个节点缓存最近一次出版的项目(甚至即使"persistent-items"未被设置成true);如果它确实把缺省的 "cache-last-item" 设置成 true,它应该(SHOULD)按照"send_last_published_item"的配置发送最近出版的项目(或关于它的通知)给订阅的实体。<br />
<br />
* 一个节点所有者应该(SHOULD)能够指定谁可以订阅这个节点.<br />
<br />
* 一个节点所有者应该(SHOULD)能够指定谁可以发布项目到这个节点.<br />
<br />
* 一个节点可以(MAY)被配置成在事件通知内交付已出版的有效载荷。<br />
<br />
* 一个节点可以(MAY)被配置成持续发布项目给一些持久存储机制.<br />
<br />
* 一个节点可以(MAY)被配置成持续发布有限次数的项目.<br />
<br />
* 一个服务可以(MAY)支持集合.<br />
<br />
* 一个服务或节点可以(MAY)支持扩展的服务发现信息(meta-data).<br />
<br />
==预备==<br />
<br />
===从属关系===<br />
<br />
为了管理许可,在这里协议定义了一个层次从属关系,类似多用户聊天系统中所采用的(Multi-User Chat 6).<br />
<br />
对于 "owner" 和 "none" 的从属关系的支持是必需的(REQUIRED)。其他所有的从属关系的支持是建议的(RECOMMENDED)。特殊种类的pubsub服务可以(MAY)强制额外的需求。<br />
<br />
'''表 2: 从属关系和他们的权限'''<br />
<br />
{|border="1" cellspacing="0" <br />
!从属关系 !! 订阅 !! 发布项目 !! 清理项目 !! 配置节点 !! 删除节点 !! 删除项目<br />
|-<br />
|所有者 || Yes || Yes || Yes || Yes || Yes || Yes<br />
|-<br />
|Publisher || Yes || Yes || No || No || No || Yes/No *<br />
|-<br />
|None ||Yes || No || No || No || No || No<br />
|-<br />
|Outcast || No || No || No || No || No || No<br />
|}<br />
<br />
* 注意: 一旦一个项目已经出版给某个节点,那个服务可以(MAY)允许任何出版者删除任何项目而不是只允许原始的出版者删除它(这是一个可发现的服务,通过"pubsub#delete-any"特性)。<br />
<br />
实体如何变更它和节点的从属关系是很明确的。一般来讲,一个从属关系状态的改变需要所有者的动作。从属关系改变和他们的触发动作定义在下表中。<br />
<br />
'''表 3: 从属关系状态图'''<br />
<br />
{|border="1" cellspacing="0" <br />
|--> ||Outcast ||None ||Publisher ||Owner<br />
|-<br />
|Outcast ||-- ||所有者移除禁令 ||所有者添加实体到出版者列表 ||所有者添加实体到所有者列表<br />
|-<br />
|None ||所有者禁止实体 ||-- ||所有者添加实体到出版者列表 ||所有者添加实体到所有者列表<br />
|-<br />
|Publisher ||所有者禁止实体 ||所有者从出版者列表中移除实体 ||-- ||所有者添加实体到所有者列表<br />
|-<br />
|Owner ||n/a ||所有者辞职 ||n/a ||--<br />
|}<br />
<br />
===订阅状态===<br />
<br />
订阅某个节点可以有很多状态<br />
<br />
'''表 4: 订阅状态'''<br />
<br />
{|border="1" cellspacing="0" <br />
!订阅状态 !! 描述<br />
|-<br />
|无 || 节点不能(MUST NOT)发送事件通知或有效载荷给实体.<br />
|-<br />
|未决的 || 一个实体已经申请订阅一个节点,但是这个申请还没被节点所有者批准。节点在处于这个状态时不能(MUST NOT)发送事件通知或有效载荷给实体。<br />
|-<br />
|未配置的 || 一个节点已经订阅但是它的订阅选项还没有配置。节点在这个状态时可以(MAY)发送事件通知或有效载荷给实体。 服务可以(MAY)让未配置的订阅过期作废。<br />
|-<br />
|已订阅的 || 一个实体已经订阅了一个节点。节点在这个状态下必须(MUST)发送所有事件通知(和有效载荷,如果配置了的话)给实体。<br />
|}<br />
<br />
===事件类型===<br />
<br />
出版-订阅协议需要两个主要的尺度来使我们能够衡量一个事件:持久性和临时性,纯的通知和包含有效载荷的通知。协议的实现应该(SHOULD)让所有者能够从两个尺度都可以配置一个节点。<br />
<br />
无论一个节点是否配置成持久性或者临时性的事件,一个服务可以(MAY)缓存最后一个发布到节点的项目,在这种情况下,它应该(SHOULD)根据"send_last_published_item"选项(参见本文的 项目缓存 章节)的配置情况发送那个项目给订阅者。<br />
<br />
一个pubsub服务必须(MUST)确认发布请求在这两个方面都满足节点的配置。(参见本文的 发布一个项目到一个节点 章节了解相关的出错条件)。<br />
<br />
是否一个项目必须由一个出版者提供,以及是否一个项目ID由出版者提供还是有pubsub服务生成,取决于被发布的事件的类型。我们在下表中概述相关的规则:<br />
<br />
'''表 5: 事件类型,项目,项目ID'''<br />
<br />
{|border="1" cellspacing="0" <br />
|--> || 通知 || 有效载荷<br />
|-<br />
|持久的 || 发布者必须(MUST)包含一个 <item/> 元素,它可以(MAY)是空的或者包含有效载荷;如果项目 ID 不是由发布者提供,它必须(MUST)由pubsub服务生成 || 发布者必须(MUST)包含一个 <item/> 元素,其中包含有效载荷;如果项目 ID 没有被发布者提供,它必须(MUST)由pubsub服务生成<br />
|-<br />
|临时的 || 发布者不能(MUST NOT)包含一个 <item/> 元素(所以项目 ID 不需要提供也不需要生成) 但是通知将包含一个空的 <items/> 元素 || 发布者必须(MUST)包含一个 <item/> 元素,其中包含有效载荷,但是项目 ID 是可选的(OPTIONAL)<br />
|}<br />
<br />
===节点类型===<br />
<br />
有两个节点类型:<br />
<br />
'''表 6: 节点类型'''<br />
<br />
{|border="1" cellspacing="0" <br />
!节点类型 !! 描述<br />
|-<br />
|叶节点 || 一个仅包含发布的项目的节点。它不包含任何其他节点。这是最常见的节点类型。<br />
|-<br />
|集合节点 || 一个包含节点和/或其他集合但是不包含出版项目的节点。集合可以实现多层次的节点结构。<br />
|}<br />
<br />
===节点访问模式===<br />
<br />
为了使节点建立对客户更简单,我们定义了以下节点访问模式(为了公开性):<br />
<br />
'''表 7: 节点访问模式'''<br />
<br />
{|border="1" cellspacing="0" <br />
!访问模式 !! 描述<br />
|-<br />
|开放的 || 任何实体可以订阅这个节点(比如, 订阅不需要批准) ,以及任何实体可以从这个节点接收项目(比如,不需要被订阅);这应该(SHOULD)是一般pubsub幅服务的缺省访问模式。<br />
|-<br />
|持久的 || 任何拥有"from"或"both"类型的订阅的实体可以向节点订阅和接收项目;这个访问模式主要应用于即时消息系统 (参见 RFC 3921).<br />
|-<br />
|名册 || 任何处于指定名册组中的实体可以向节点订阅和接收项目;这种访问模式主要用于即时消息系统 (参见see RFC 3921).<br />
|-<br />
|授权的 || 节点所有者必须批准所有订阅请求,并且只有订阅者可以从节点接收项目.<br />
|-<br />
|白名单 || 一个实体仅仅在被节点所有者加入白名单的时候才可以被订阅(主动提出的订阅请求会被拒绝),并且只有订阅者可以从节点接收项目。换句话说,缺省的从属关系是排斥的。节点所有者必须(MUST)自动进入白名单。为了添加实体进入白名单,节点所有者应该(SHOULD)使用本文的 管理从属关系实体章节中所定义的方式。<br />
|}<br />
<br />
尽管专门的出版-订阅 系统实施可以(MAY)只支持访问模式的一个子集,但一般来说 出版-订阅系统实施应该(SHOULD)支持所有已定义的访问模式。在一个专门部署的系统中,系统服务提供哪些访问模式是一个问题(比如,一些受限的系统部署可能希望锁定许可从而只提供“被授权的”和"白名单"的访问模式,或甚至只提供"白名单"的访问模式)。<br />
<br />
为了使一个节点创建者或所有者指定访问模式,使用了'pubsub#access_model'配置域(参见本文的Create a Node With Default Configuration and Configure a Node(以缺省配置创建一个节点和配置一个节点)章节).<br />
<br />
===寻址===<br />
<br />
如果一个 pubsub 节点是可设定地址的,它必须(MUST)被设定为一个JID或一个JID和一个节点的组合。\[7\]<br />
<br />
====JID====<br />
<br />
如果一个 pubsub 节点的地址被设定成一个JID,节点ID必须(MUST)是资源ID,并且节点ID不能(MUST NOT)是JID中的"user"部分(如"domain.tld/NodeID" 和 "user@domain.tld/NodeID" 是被允许的; "NodeID@domain.tld" 是不允许的)。JID 寻址应该(SHOULD)在使用不支持节点属性的协议和一个 pubsub 节点互动的时候使用.例如,当一个服务允许实体向节点订阅出席信息,它会把节点地址设成JID。如果一个 pubsub 节点可以被设置成 JID ,pubsub 服务必须(MUST)确保节点ID符合 RFC 3920中规定的Resourceprep profile of Stringprep。<br />
<br />
考虑以下例子,pubsub服务定位于主机名 pubsub.shakespeare.lit.<br />
<br />
'''案例 4. 节点地址设定为 domain.tld/NodeID'''<br />
<br />
<source lang="xml"><br />
<iq to='pubsub.shakespeare.lit/news announcements'><br />
...<br />
</iq><br />
</source><br />
<br />
现在再考虑以下例子, pubsub 服务定位于 pubsub@shakespeare.lit.<br />
<br />
'''案例 5. 节点地址设定为 user@domain.tld/NodeID'''<br />
<br />
<source lang="xml"><br />
<iq to='pubsub@shakespeare.lit/news announcements'><br />
...<br />
</iq><br />
</source><br />
<br />
====JID+NodeID====<br />
<br />
如果一个pubsub服务地址可以被设成一个JID加一个节点,这个节点ID必须(MUST)是发现服务中的'node'属性值,同时也是pubsub服务的'node'属性值;用于发现服务时,一个pubsub节点等同于一个发现服务的节点。如果一个pubsub节点可以被设置成 JID 加 node,这个pubsub服务应该(SHOULD)确保节点ID符合 RFC 3920中规定的Resourceprep profile of Stringprep。<br />
<br />
考虑以下例子,(虚拟的)pubsub服务定位于 hamlet@denmark.lit.<br />
<br />
'''案例 6. 节点地址设为 JID+NodeID'''<br />
<br />
<source lang="xml"><br />
<iq to='hamlet@denmark.lit'><br />
<query node='princely_musings'/><br />
</iq><br />
</source><br />
<br />
==实体用例==<br />
<br />
本章规定了使用案例,用于任何希望和出版-订阅服务互动的实体使用的协议,主要集中于发现服务的使用案例。<br />
<br />
===发现特性===<br />
<br />
一个服务必须(MUST)回应符合名字空间'http://jabber.org/protocol/disco#info'的发现服务信息请求。由pubsub服务返回的"disco#info"结果必须(MUST)表明服务的标识符以及支持哪些pubsub特性。<br />
<br />
'''案例 7. 实体查询 Pubsub 服务支持的特性'''<br />
<br />
<source lang="xml"><br />
<iq type='get'<br />
from='francisco@denmark.lit/barracks'<br />
to='pubsub.shakespeare.lit'<br />
id='feature1'><br />
<query xmlns='http://jabber.org/protocol/disco#info'/><br />
</iq><br />
</source><br />
<br />
'''案例 8. Pubsub 服务返回支持的特性组'''<br />
<br />
<source lang="xml"><br />
<iq type='result'<br />
from='pubsub.shakespeare.lit'<br />
to='francisco@denmark.lit/barracks'<br />
id='feature1'><br />
<query xmlns='http://jabber.org/protocol/disco#info'><br />
<identity category='pubsub' type='service'/><br />
<feature var='http://jabber.org/protocol/pubsub'/><br />
</query><br />
</iq><br />
</source><br />
<br />
可能存在的 pubsub 特性在本文中到处都是,并且它们都已经在本文的 XMPP资源注册事项 章节描述了。想了解哪个特性是必需的,建议的,可选的,参见本文的 特性总结 章节。<br />
<br />
===5.2 发现节点===<br />
<br />
如果一个服务实现了一个多层次节点(也就是 集合节点),它必须(MUST)也要让实体能够通过 服务发现协议发现这些多层次节点,在结果集很大的时候遵照 XEP-0030 的建议(这时候应该(SHOULD)使用Jabber search或一些其他协议).以下例子展示在一个多层次 pubsub 服务中如何使用 服务发现 来发现可用的节点.<br />
<br />
<br />
注意: 节点层次和集合节点是可选的(OPTIONAL). 详细情况参照本文的 节点ID术语 和 集合节点章节.<br />
<br />
<br />
<br />
在第一个例子中,一个实体向一个根节点(比如服务本身)发送一个服务发现条目("disco#items")请求,它是一个集合节点:<br />
<br />
<br />
<br />
__案例 9. 实体请求所有一级节点__<br />
<source lang="xml"><br />
<iq type='get'<br />
from='francisco@denmark.lit/barracks'<br />
to='pubsub.shakespeare.lit'<br />
id='nodes1'><br />
<query xmlns='http://jabber.org/protocol/disco#items'/><br />
</iq><br />
<br />
</source><br />
<br />
<br />
<br />
__案例 10. 服务返回所有一级节点__ {anchor:xml}<br />
<source lang="xml"><br />
<iq type='result'<br />
from='pubsub.shakespeare.lit'<br />
to='francisco@denmark.lit/barracks'<br />
id='nodes1'><br />
<query xmlns='http://jabber.org/protocol/disco#items'><br />
<item jid='pubsub.shakespeare.lit' node='blogs' name='Weblog updates'/><br />
<item jid='pubsub.shakespeare.lit' node='news' name='News and announcements'/><br />
</query><br />
</iq><br />
</source><br />
<br />
第二个例子中,一个实体发送一个 disco#items 请求给其中一个一级节点,它也是一个集合节点:<br />
<br />
<br />
<br />
__案例 11. 实体请求二级节点__<br />
<source lang="xml"><br />
<iq type='get'<br />
from='francisco@denmark.lit/barracks'<br />
to='pubsub.shakespeare.lit'<br />
id='nodes2'><br />
<query xmlns='http://jabber.org/protocol/disco#items' node='blogs'/><br />
</iq><br />
</source><br />
<br />
__案例 12. 服务返回二级节点__<br />
<br />
<source lang="xml"><br />
<iq type='result'<br />
from='pubsub.shakespeare.lit'<br />
to='francisco@denmark.lit/barracks'<br />
id='nodes2'><br />
<query xmlns='http://jabber.org/protocol/disco#items' node='blogs'><br />
<item jid='pubsub.shakespeare.lit' node='princely_musings'/><br />
<item jid='pubsub.shakespeare.lit' node='kingly_ravings'/><br />
<item jid='pubsub.shakespeare.lit' node='starcrossed_stories'/><br />
<item jid='pubsub.shakespeare.lit' node='moorish_meanderings'/><br />
</query><br />
</iq><br />
</source><br />
<br />
如果一个叶子节点不仅是一个集合节点,它本身也有条目发行,这个服务可以(MAY)为每一个已出版的条目返回一个 <item/> 元素(参见本文的 从一个节点发现条目 章节),无论如何这些条目一定不能(MUST NOT)包含一个 'node' 属性(因为它们是已发行的条目,不是节点).<br />
<br />
<br />
<br />
__5.3 发现节点信息__ {anchor:发现节点信息}<br />
<br />
<br />
<br />
一个 pubsub 服务必须(MUST)允许实体去查询每个单独的节点来获得该节点的相关信息。必须(MUST)使用服务发现协议来查询这些信息。"disco#info" 结果必须(MUST)包含一个ID,其类别是“pubsub”,类型是“leaf”或“collection”。<br />
<br />
<br />
<br />
注意: 如果一个节点的 id 类型为“leaf”,它一定不能(MUST NOT)包含其它的节点或集合(只有条目);如果一个节点的ID类型是“collection”,它一定不能(MUST NOT)包含条目(只有其它节点或集合)。<br />
<br />
<br />
<br />
__案例 13. 实体查询集合节点的信息__<br />
<source lang="xml"><br />
<iq type='get'<br />
from='francisco@denmark.lit/barracks'<br />
to='pubsub.shakespeare.lit'<br />
id='info2'><br />
<query xmlns='http://jabber.org/protocol/disco#info' node='blogs'/><br />
</iq><br />
</source><br />
<br />
<br />
__案例 14. 服务应答 pubsub/collection ID__<br />
<br />
<source lang="xml"><br />
<iq type='result'<br />
<br />
from='pubsub.shakespeare.lit'<br />
<br />
to='francisco@denmark.lit/barracks'<br />
<br />
id='meta1'><br />
<br />
<br />
<br />
<query xmlns='http://jabber.org/protocol/disco#info' node='blogs'><br />
<br />
<br />
<br />
...<br />
<br />
<br />
<br />
<identity category='pubsub' type='collection'/><br />
<br />
<br />
<br />
...<br />
<br />
<br />
<br />
</query><br />
<br />
<br />
<br />
</iq><br />
<br />
</source><br />
<br />
<br />
<br />
__案例 15. 实体查询叶子节点信息__<br />
<br />
<source lang="xml"><br />
<iq type='get'<br />
<br />
from='francisco@denmark.lit/barracks'<br />
<br />
to='pubsub.shakespeare.lit'<br />
<br />
id='info1'><br />
<br />
<br />
<br />
<query xmlns='http://jabber.org/protocol/disco#info' node='princely_musings'/><br />
<br />
<br />
<br />
</iq><br />
<br />
</source><br />
<br />
<br />
<br />
__案例 16. 服务应答 pubsub/collection ID__<br />
<br />
<br />
<br />
<source lang="xml"><br />
<br />
<iq type='result'<br />
<br />
from='pubsub.shakespeare.lit'<br />
<br />
to='francisco@denmark.lit/barracks'<br />
<br />
id='info1'><br />
<br />
<br />
<br />
<query xmlns='http://jabber.org/protocol/disco#info'><br />
<br />
<br />
<br />
...<br />
<br />
<br />
<br />
<identity category='pubsub' type='leaf'/><br />
<br />
<br />
<br />
...<br />
<br />
<br />
<br />
</query><br />
<br />
<br />
<br />
</iq><br />
</source><br />
<br />
<br />
__5.4 发现节点元数据__ {anchor:发现节点元数据}<br />
<br />
<br />
<br />
"disco#info" 结果可以(MAY)包含节点的详细元数据,封装在数据窗体[第九章]中,其格式参见Service Discovery Extensions(服务发现扩展) [第十章]。数据窗体上下文由 "http://jabber.org/protocol/pubsub#meta-data" 中的 FORM_TYPE 定义,并符合Field Standardization for Data Forms(数据窗体的字段标准化)[第十一章]。如果元数据被提供了,它应该(SHOULD)所有已配置的选项值,像"automatic" 信息一样,比如节点创建日期,出版者列表以及类似的信息。<br />
<br />
<br />
<br />
__案例 17. 实体查询一个节点的信息__<br />
<br />
<br />
<br />
<source lang="xml"><br />
<br />
<iq type='get'<br />
<br />
from='francisco@denmark.lit/barracks'<br />
<br />
to='pubsub.shakespeare.lit'<br />
<br />
id='meta1'><br />
<br />
<br />
<br />
<query xmlns='http://jabber.org/protocol/disco#info' node='princely_musings'/><br />
<br />
<br />
<br />
</iq><br />
<br />
</source><br />
<br />
<br />
<br />
__案例 18. 服务应答信息和元数据__<br />
<br />
<source lang="xml"><br />
<br />
<iq type='result'<br />
<br />
from='pubsub.shakespeare.lit'<br />
<br />
to='francisco@denmark.lit/barracks'<br />
<br />
id='meta1'><br />
<br />
<br />
<br />
<query xmlns='http://jabber.org/protocol/disco#info' node='princely_musings'/><br />
<br />
<br />
<br />
<identity category='pubsub' type='leaf'/><br />
<br />
<br />
<br />
<feature var='http://jabber.org/protocol/pubsub'/><br />
<br />
<br />
<br />
<x xmlns='jabber:x:data' type='result'><br />
<br />
<br />
<br />
<field var='FORM_TYPE' type='hidden'><br />
<br />
<br />
<br />
<value>>>http://jabber.org/protocol/pubsub#meta-data</value><br />
<br />
<br />
<br />
</field><br />
<br />
<br />
<br />
<field var='pubsub#type' label='Payload type'><br />
<br />
<br />
<br />
<value>>>http://www.w3.org/2005/Atom</value><br />
<br />
<br />
<br />
</field><br />
<br />
<br />
<br />
<field var='pubsub#creator' label='Node creator'><br />
<br />
<br />
<br />
<value>hamlet@denmark.lit</value><br />
<br />
<br />
<br />
</field><br />
<br />
<br />
<br />
<field var='pubsub#creation_date' label='Creation date'><br />
<br />
<br />
<br />
<value>2003-07-29T22:56Z</value><br />
<br />
<br />
<br />
</field><br />
<br />
<br />
<br />
<field var='pubsub#title' label='A short name for the node'><br />
<br />
<br />
<br />
<value>Princely Musings (Atom)</value><br />
<br />
<br />
<br />
</field><br />
<br />
<br />
<br />
<field var='pubsub#description' label='A description of the node'><br />
<br />
<br />
<br />
<value>Updates for Hamlet's Princely Musings weblog.</value><br />
<br />
<br />
<br />
</field><br />
<br />
<br />
<br />
<field var='pubsub#language' label='Default language'><br />
<br />
<br />
<br />
<value>en</value><br />
<br />
<br />
<br />
</field><br />
<br />
<br />
<br />
<field var='pubsub#contact' label='People to contact with questions'><br />
<br />
<br />
<br />
<value>bard@shakespeare.lit</value><br />
<br />
<br />
<br />
</field><br />
<br />
<br />
<br />
<field var='pubsub#owner' label='Node owners'><br />
<br />
<br />
<br />
<value>hamlet@denmark.lit</value><br />
<br />
<br />
<br />
</field><br />
<br />
<br />
<br />
<field var='pubsub#publisher' label='Publishers to this node'><br />
<br />
<br />
<br />
<value>hamlet@denmark.lit</value><br />
<br />
<br />
<br />
</field><br />
<br />
<br />
<br />
<field var='pubsub#num_subscribers' label='Number of subscribers to this node'><br />
<br />
<br />
<br />
<value>1066</value><br />
<br />
<br />
<br />
</field><br />
<br />
<br />
<br />
</x><br />
<br />
<br />
<br />
</query><br />
<br />
<br />
<br />
</iq><br />
<br />
</source><br />
<br />
<br />
<br />
注意: 节点元数据可以用多种方法设置。一些是基于节点配置(如所有者的JID),也有的是动态的(如订阅者的号码)。任何在节点元数据中提供的静态信息应该(SHOULD)在节点配置窗体中以字段形式提供。<br />
<br />
<br />
<br />
更多的元数据直接由节点映射表中特定的元数据属性提供。参见Dublin Core Metadata Initiative (DCMI) [第十二章]:<br />
<br />
<br />
<br />
__表 8: Dublin Core Meta-Data Mapping(Dulbin 核心元数据映射表)__<br />
<br />
<br />
<br />
{table}<br />
<br />
Pubsub Field |Dublin Core Meta-Data Attribute<br />
<br />
pubsub#creation_date |Date [第十三章]<br />
<br />
pubsub#creator |Creator<br />
<br />
pubsub#description |Description<br />
<br />
pubsub#language |Language<br />
<br />
pubsub#publisher |Publisher<br />
<br />
pubsub#title |Title<br />
<br />
pubsub#type |Type [第十四章]<br />
<br />
{table}<br />
<br />
<br />
<br />
__5.5 从一个节点查询条目__ {anchor:从一个节点查询条目}<br />
<br />
<br />
<br />
为了查询服务中特定节点的已出版条目,一个实体可以(MAY)发送"disco#items"请求给节点本身,服务可以(MAY)通过< item/>返回每个条目。每个条目的'name'属性必须(MUST)包括它的ItemID,并且条目不能(MUST NOT)有'node'属性。这个 ItemID 可以(MAY)用于接收条目(参见本协议文档中Retrieve Items from a Node(从一个节点接收条目) 章节 ).<br />
<br />
<br />
<br />
__案例 19. 实体请求一个节点的所有条目__<br />
<br />
<source lang="xml"><br />
<br />
<iq type='get'<br />
<br />
from='francisco@denmark.lit/barracks'<br />
<br />
to='pubsub.shakespeare.lit'<br />
<br />
id='items1'><br />
<br />
<br />
<br />
<query xmlns='http://jabber.org/protocol/disco#items' node='princely_musings'/><br />
<br />
<br />
<br />
</iq><br />
<br />
<br />
<br />
<iq type='result' from='pubsub.shakespeare.lit' to='francisco@denmark.lit/barracks' id='items1'><br />
<br />
<br />
<br />
<query xmlns='http://jabber.org/protocol/disco#items' node='princely_musings'><br />
<br />
<br />
<br />
<item jid='pubsub.shakespeare.lit' name='368866411b877c30064a5f62b917cffe'/><br />
<br />
<br />
<br />
<item jid='pubsub.shakespeare.lit' name='3300659945416e274474e469a1f0154c'/><br />
<br />
<br />
<br />
<item jid='pubsub.shakespeare.lit' name='4e30f35051b7b8b42abe083742187228'/><br />
<br />
<br />
<br />
<item jid='pubsub.shakespeare.lit' name='ae890ac52d0df67ed7cfdf51b644e901'/><br />
<br />
<br />
<br />
</query><br />
<br />
<br />
<br />
</iq><br />
<br />
</source><br />
<br />
<br />
<br />
__5.6 找回订阅__ {anchor:找回订阅}<br />
<br />
<br />
<br />
一个服务应该(SHOULD)允许实体查询服务以找回它对服务中所有节点的订阅。为了做出这些查询,请求的实体必须(MUST)发送一个 IQ-get 消息,这个消息的 <pubsub/> 子元素包含一个没有属性的空<subscriptions/>元素。<br />
<br />
<br />
<br />
__案例 20. 实体请求所有当前的订阅__<br />
<br />
<source lang="xml"><br />
<iq type='get'<br />
<br />
from='francisco@denmark.lit/barracks'<br />
<br />
to='pubsub.shakespeare.lit'<br />
<br />
id='subscriptions1'><br />
<br />
<br />
<br />
<pubsub xmlns='http://jabber.org/protocol/pubsub'><br />
<br />
<br />
<br />
<subscriptions/><br />
<br />
<br />
<br />
</pubsub><br />
<br />
<br />
<br />
</iq><br />
<br />
</source><br />
<br />
<br />
<br />
如果服务返回一个订阅列表,它必须(MUST)返回所有和请求消息中'from'属性的 纯JID (<node@domain.tld>) 匹配的 JIDs的信息.<br />
<br />
<br />
<br />
对于每个订阅, 返回一个 <subscription/> 元素以指明 NodeID, 以及这个节点ID相关联的 JID(可以包含资源,视实体如何订阅而定),目前的订阅状态。如果服务支持订阅ID(subscription identifier),'subid' 属性也必须(MUST)出现.<br />
<br />
<br />
<br />
__案例 21. 服务返回所有当前订阅__<br />
<source lang="xml"><br />
<br />
<iq type='result'<br />
<br />
from='pubsub.shakespeare.lit'<br />
<br />
to='francisco@denmark.lit'<br />
<br />
id='subscriptions1'><br />
<br />
<br />
<br />
<pubsub xmlns='http://jabber.org/protocol/pubsub'><br />
<br />
<br />
<br />
<subscriptions><br />
<br />
<br />
<br />
<subscription node='node1' jid='francisco@denmark.lit' subscription='subscribed'/><br />
<br />
<br />
<br />
<subscription node='node2' jid='francisco@denmark.lit' subscription='subscribed'/><br />
<br />
<br />
<br />
<subscription node='node5' jid='francisco@denmark.lit' subscription='unconfigured'/><br />
<br />
<br />
<br />
<subscription node='node6' jid='francisco@denmark.lit' subscription='pending'/><br />
<br />
<br />
<br />
</subscriptions><br />
<br />
<br />
<br />
</pubsub><br />
<br />
<br />
<br />
</iq><br />
<br />
</source><br />
<br />
<br />
<br />
如果请求实体没有订阅,pubsub 服务必须(MUST)返回一个空的 <subscriptions/> 元素.<br />
<br />
<br />
<br />
__案例 22. 没有订阅__<br />
<source lang="xml"><br />
<br />
<iq type='result'<br />
<br />
from='pubsub.shakespeare.lit'<br />
<br />
to='francisco@denmark.lit/barracks'<br />
<br />
id='subscriptions1'><br />
<br />
<br />
<br />
<pubsub xmlns='http://jabber.org/protocol/pubsub'><br />
<br />
<br />
<br />
<subscriptions/><br />
<br />
<br />
<br />
</pubsub><br />
<br />
<br />
<br />
</iq><br />
</source><br />
<br />
<br />
如果服务不支持订阅找回,服务必须(MUST)应答一个<feature-not-implemented/> 错误, 指出 pubsub-specific 的错误条件 <unsupported/> 以及特性 "retrieve-subscriptions".<br />
<br />
<br />
<br />
__案例 23. 不支持订阅找回__<br />
<br />
<source lang="xml"><br />
<br />
<iq type='error'<br />
<br />
from='pubsub.shakespeare.lit'<br />
<br />
to='francisco@denmark.lit/barracks'<br />
<br />
id='subscriptions1'><br />
<br />
<br />
<br />
<pubsub xmlns='http://jabber.org/protocol/pubsub'><br />
<br />
<br />
<br />
<subscriptions/><br />
<br />
<br />
<br />
</pubsub><br />
<br />
<br />
<br />
<error type='cancel'><br />
<br />
<br />
<br />
<feature-not-implemented xmlns='urn:ietf:params:xml:ns:xmpp-stanzas'/><br />
<br />
<br />
<br />
<unsupported xmlns='http://jabber.org/protocol/pubsub#errors' feature='retrieve-subscriptions'/><br />
<br />
<br />
<br />
</error><br />
<br />
<br />
<br />
</iq><br />
<br />
</source><br />
<br />
<br />
<br />
__5.7 找回加入__ {anchor:找回加入}<br />
<br />
<br />
<br />
一个服务应该(SHOULD)允许一个实体查询这个服务以找回它在所有节点的加入信息。为了做出这些请求,实体要在请求消息中包含一个没有属性的空 <affiliations/> 元素。<br />
<br />
<br />
<br />
__案例 24. 实体请求所有当前加入__<br />
<br />
<source lang="xml"><br />
<br />
<iq type='get'<br />
<br />
from='francisco@denmark.lit/barracks'<br />
<br />
to='pubsub.shakespeare.lit'<br />
<br />
id='affil1'><br />
<br />
<br />
<br />
<pubsub xmlns='http://jabber.org/protocol/pubsub'><br />
<br />
<br />
<br />
<affiliations/><br />
<br />
<br />
<br />
</pubsub><br />
<br />
<br />
<br />
</iq><br />
<br />
</source><br />
<br />
<br />
<br />
如果服务返回一个加入的列表,它必须(MUST)返回所有和请求的'form'属性的 纯JID (<node@domain.tld>)相匹配的JID的加入信息。<br />
<br />
<br />
<br />
对于每个加入信息, 返回一个 <affiliation/> 元素,包含 NodeID 和加入状态 (所有这owner, 发布者publisher, or 流浪者outcast).<br />
<br />
<br />
<br />
__案例 25. 服务应答所有当前加入__<br />
<source lang="xml"><br />
<br />
<iq type='result'<br />
<br />
from='pubsub.shakespeare.lit'<br />
<br />
to='francisco@denmark.lit'<br />
<br />
id='affil1'><br />
<br />
<br />
<br />
<pubsub xmlns='http://jabber.org/protocol/pubsub'><br />
<br />
<br />
<br />
<affiliations><br />
<br />
<br />
<br />
<affiliation node='node1' affiliation='owner'/><br />
<br />
<br />
<br />
<affiliation node='node2' affiliation='publisher'/><br />
<br />
<br />
<br />
<affiliation node='node5' affiliation='outcast'/><br />
<br />
<br />
<br />
<affiliation node='node6' affiliation='owner'/><br />
<br />
<br />
<br />
</affiliations><br />
<br />
<br />
<br />
</pubsub><br />
<br />
<br />
<br />
</iq><br />
<br />
</source><br />
<br />
<br />
<br />
如果请求实体没有加入, pubsub 服务必须(MUST)返回一个空的 <affiliations/> 元素.<br />
<br />
<br />
<br />
__案例 26. 没有加入__<br />
<br />
<source lang="xml"><br />
<br />
<iq type='result'<br />
<br />
from='pubsub.shakespeare.lit'<br />
<br />
to='francisco@denmark.lit/barracks'<br />
<br />
id='affil1'><br />
<br />
<br />
<br />
<pubsub xmlns='http://jabber.org/protocol/pubsub'><br />
<br />
<br />
<br />
<affiliations/><br />
<br />
<br />
<br />
</pubsub><br />
<br />
<br />
<br />
</iq><br />
<br />
</source><br />
<br />
<br />
<br />
如果服务不支持加入找回, 服务必须(MUST)应答一个 <feature-not-implemented/> 错误, 指明一个 <unsupported/>的 pubsub-specific 错误条件和 "retrieve-affiliations" 的特性.<br />
<br />
<br />
<br />
__案例 27. 不支持加入找回__<br />
<br />
<source lang="xml"><br />
<br />
<iq type='error'<br />
<br />
from='pubsub.shakespeare.lit'<br />
<br />
to='francisco@denmark.lit/barracks'<br />
<br />
id='affil1'><br />
<br />
<br />
<br />
<pubsub xmlns='http://jabber.org/protocol/pubsub'><br />
<br />
<br />
<br />
<affiliations/><br />
<br />
<br />
<br />
</pubsub><br />
<br />
<br />
<br />
<error type='cancel'><br />
<br />
<br />
<br />
<feature-not-implemented xmlns='urn:ietf:params:xml:ns:xmpp-stanzas'/><br />
<br />
<br />
<br />
<unsupported xmlns='http://jabber.org/protocol/pubsub#errors' feature='retrieve-affiliations'/><br />
<br />
<br />
<br />
</error><br />
<br />
<br />
<br />
</iq><br />
<br />
</source><br />
<br />
<br />
__6. 订阅者用例__ {anchor:订阅者用例}<br />
<br />
<br />
<br />
本节定义了潜在和实际的订阅者使用协议的用例。(注意:本文的实施备注一节描述了一个pubsub服务器必须(MUST)遵守的许多重要的因素和商业规则.另外,所有例子都假定独立的pubsub组件存在并包含任何含有服务器或网络标记的相关'from'地址).<br />
<br />
<br />
<br />
__6.1 向一个节点订阅__ {anchor:向一个节点订阅}<br />
<br />
<br />
<br />
当一个Jabber实体希望从一个节点订阅,它向pubsub服务发送订阅请求。订阅申请是一个 IQ-set 消息,其<pubsub/> 元素包含并且仅包含一个<subscribe/>元素.这个<subscribe/>元素必须(MUST)拥有一个'node' 属性指明实体希望订阅的节点.这个<subscribe/>元素必须(MUST)拥有一个'jid' 属性指明用于订阅的JID确切的 XMPP 地址--通常是一个纯JID(<node@domain.tld>) 或一个全JID(<node@domain.tld/resource>),当然<domain.tld> 或 <domain.tld/resource>格式的JID也可以订阅.<br />
<br />
<br />
<br />
如果指定的JID 是一个纯JID或一个全JID,服务必须(MUST)从接收的IQ请求中的’from’属性中分离出最小化的纯JID部分,以确保发出请求的实体和被加入到订阅者列表的JID是同一个ID。无论如何,一些实现可以(MAY)允许服务管理员配置一个实体列表不进行此项检查;那些实体可能被作为 "trusted proxies"(被信任的代理),可以为其他实体进行订阅.同样的,一些实现可以(MAY)允许实体黑名单,禁止其执行特定的动作(比如订阅或者建立节点).<br />
<br />
<br />
<br />
一个服务可以(MAY)允许实体多次订阅同一个节点.这是一个实体能够用不同的订阅选项进行订阅.如果允许用同一个JID进行多次订阅,服务必须(MUST)使用'subid'属性来区分同一实体的不同订阅(所以SubID必须(MUST)对于每一个node+JID的组合是唯一的,并且在发送给订阅者实体的任何时候SubID必须(MUST)出现在实体元素中)。不建议(NOT RECOMMENDED)客户端生成SubID,因为可能引发冲突;所以一个服务应该(SHOULD)为订阅者生成一个SubID,并且如果订阅者提供了 SubID,服务可以重写它.如果服不允许同一个实体多次订阅但是接收到了额外的订阅请求,服务必须(MUST)返回当前的订阅状态(如果这个订阅以前就被批准了).<br />
<br />
<br />
<br />
这里是一个订阅请求的例子.<br />
<br />
<br />
<br />
__案例 28. 实体向一个节点订阅__<br />
<br />
<source lang="xml"><br />
<br />
<iq type='set'<br />
<br />
from='francisco@denmark.lit/barracks'<br />
<br />
to='pubsub.shakespeare.lit'<br />
<br />
id='sub1'><br />
<br />
<br />
<br />
<pubsub xmlns='http://jabber.org/protocol/pubsub'><br />
<br />
<br />
<br />
<subscribe node='princely_musings' jid='francisco@denmark.lit'/><br />
<br />
<br />
<br />
</pubsub><br />
<br />
<br />
<br />
</iq><br />
<br />
</source><br />
<br />
<br />
<br />
如果订阅请求被成功处理,服务器必须(MUST)通知请求实体它已订阅(可以(MAY)包含一个服务生成的SubID).<br />
<br />
<br />
<br />
__案例 29. 服务返回成功__<br />
<br />
<source lang="xml"><br />
<br />
<iq type='result'<br />
<br />
from='pubsub.shakespeare.lit'<br />
<br />
to='francisco@denmark.lit/barracks'<br />
<br />
id='sub1'><br />
<br />
<br />
<br />
<pubsub xmlns='http://jabber.org/protocol/pubsub'><br />
<br />
<br />
<br />
<subscription node='princely_musings' jid='francisco@denmark.lit' subid='ba49252aaa4f5d320c24d3766f0bdcade78c78d3' subscription='subscribed'/><br />
<br />
<br />
<br />
</pubsub><br />
<br />
<br />
<br />
</iq><br />
<br />
</source><br />
<br />
<br />
<br />
服务也可以(MAY)发送最后一次发行的条目给新的订阅者.包含这个条目的消息应该(SHOULD)被标记为符合'jabber:x:delay'名字空间的扩展信息(参见 Delayed Delivery [第十五章]),以表明它是延时发送的.(注意在这个例子中消息通知发送给纯JID,因为那是已订阅的JID)<br />
<br />
<br />
<br />
__案例 30. 服务发送最后一次发行的条目__<br />
<source lang="xml"><br />
<br />
<message from='pubsub.shakespeare.lit' to='francisco@denmark.lit'><br />
<br />
<br />
<br />
<event xmlns='http://jabber.org/protocol/pubsub#event'><br />
<br />
<br />
<br />
<items node='princely_musings'><br />
<br />
<br />
<br />
<item id='ae890ac52d0df67ed7cfdf51b644e901'><br />
<br />
<br />
<br />
<entry xmlns='http://www.w3.org/2005/Atom'><br />
<br />
<br />
<br />
<title>Soliloquy</title><br />
<br />
<br />
<br />
<summary> To be, or not to be: that is the question: Whether 'tis nobler in the mind to suffer The slings and arrows of outrageous fortune, Or to take arms against a sea of troubles, And by opposing end them? </summary><br />
<br />
<br />
<br />
<link rel='alternate' type='text/html' href='http://denmark.lit/2003/12/13/atom03'/><br />
<br />
<br />
<br />
<id>tag:denmark.lit,2003:entry-32397</id><br />
<br />
<br />
<br />
<published>2003-12-13T18:30:02Z</published><br />
<br />
<br />
<br />
<updated>2003-12-13T18:30:02Z</updated><br />
<br />
<br />
<br />
</entry><br />
<br />
<br />
<br />
</item><br />
<br />
<br />
<br />
</items><br />
<br />
<br />
<br />
</event><br />
<br />
<br />
<br />
<x xmlns='jabber:x:delay' stamp='20031213T23:58:37'/><br />
<br />
<br />
<br />
</message><br />
<br />
</source><br />
<br />
<br />
<br />
有很多原因可能导致订阅请求失败:<br />
<br />
<br />
<br />
1. JID 的纯JID部分不符.<br />
<br />
1. 节点有一个"presence"访问模式并且请求实体没有订阅所有者的出席信息。<br />
<br />
1. 节点有一个"roster"的访问模式并且请求实体不在授权名单组中。<br />
<br />
1. 节点有一个"whitelist"的访问模式并且请求实体不在白名单中。<br />
<br />
1. 订阅节点的时候服务需要付费。<br />
<br />
1. 请求实体是匿名的并且服务不允许匿名实体订阅。<br />
<br />
1. 请求实体有一个未决的订阅。<br />
<br />
1. 请求实体被封锁订阅(例如,因为被加入黑名单)。<br />
<br />
1. 节点不支持订阅。<br />
<br />
1. 节点不存在。<br />
<br />
<br />
<br />
这些错误案例全部描述如下.<br />
<br />
<br />
<br />
如果JID的纯JID部分不符合上述的描述并且请求实体没有一些由实现定义的管理或者代理权限,服务必须(MUST)返回一个<bad-request/>错误,它也应(SHOULD)包含一个pubsub- specific的<invalid-jid/>错误条件。<br />
<br />
<br />
<br />
__案例 31. JID不匹配__<br />
<br />
<source lang="xml"><br />
<br />
<iq type='error'<br />
<br />
from='pubsub.shakespeare.lit'<br />
<br />
to='francisco@denmark.lit/barracks'<br />
<br />
id='sub1'><br />
<br />
<br />
<br />
<pubsub xmlns='http://jabber.org/protocol/pubsub'><br />
<br />
<br />
<br />
<subscribe node='princely_musings' jid='bernardo@denmark.lit'/><br />
<br />
<br />
<br />
</pubsub><br />
<br />
<br />
<br />
<error type='modify'><br />
<br />
<br />
<br />
<bad-request xmlns='urn:ietf:params:xml:ns:xmpp-stanzas'/><br />
<br />
<br />
<br />
<invalid-jid xmlns='http://jabber.org/protocol/pubsub#errors'/><br />
<br />
<br />
<br />
</error><br />
<br />
<br />
<br />
</iq><br />
<br />
</source><br />
<br />
<br />
<br />
对于拥有"presence"访问模式的节点,如果请求实体没有订阅所有者的出席信息,pubsub服务必须(MUST)返回一个 <not-authorized/> 错误,它也应该(SHOULD)包含一个 pubsub-specific 的<presence-subscription-required/>错误条件。<br />
<br />
<br />
<br />
__案例 32. 实体没有被授权建立一个订阅(需要出席信息订阅)__<br />
<br />
<br />
<source lang="xml"><br />
<br />
<iq type='error'<br />
<br />
from='pubsub.shakespeare.lit'<br />
<br />
to='francisco@denmark.lit/barracks'<br />
<br />
id='sub1'><br />
<br />
<br />
<br />
<pubsub xmlns='http://jabber.org/protocol/pubsub'><br />
<br />
<br />
<br />
<subscribe node='princely_musings' jid='francisco@denmark.lit'/><br />
<br />
<br />
<br />
</pubsub><br />
<br />
<br />
<br />
<error type='auth'><br />
<br />
<br />
<br />
<not-authorized xmlns='urn:ietf:params:xml:ns:xmpp-stanzas'/><br />
<br />
<br />
<br />
<presence-subscription-required xmlns='http://jabber.org/protocol/pubsub#errors'/><br />
<br />
<br />
<br />
</error><br />
<br />
<br />
<br />
</iq><br />
<br />
</source><br />
<br />
<br />
<br />
对于拥有"roster"访问模式的节点,如果请求实体不在授权的名单组中,pubsub服务必须(MUST)返回一个 <not-authorized/> 错误,它也应该(SHOULD)包含一个 pubsub-specific 的<not-in-roster-group/>错误条件。<br />
<br />
<br />
<br />
__案例 33. 实体没有被授权建立一个订阅(不在名册组中)__<br />
<source lang="xml"><br />
<br />
<iq type='error'<br />
<br />
from='pubsub.shakespeare.lit'<br />
<br />
to='francisco@denmark.lit/barracks'<br />
<br />
id='sub1'><br />
<br />
<br />
<br />
<pubsub xmlns='http://jabber.org/protocol/pubsub'><br />
<br />
<br />
<br />
<subscribe node='princely_musings' jid='francisco@denmark.lit'/><br />
<br />
<br />
<br />
</pubsub><br />
<br />
<br />
<br />
<error type='auth'><br />
<br />
<br />
<br />
<not-authorized xmlns='urn:ietf:params:xml:ns:xmpp-stanzas'/><br />
<br />
<br />
<br />
<not-in-roster-group xmlns='http://jabber.org/protocol/pubsub#errors'/><br />
<br />
<br />
<br />
</error><br />
<br />
<br />
<br />
</iq><br />
<br />
</source><br />
<br />
<br />
<br />
对于拥有"白名单"访问模式的节点,如果请求实体不在白名单中,pubsub服务必须(MUST)返回一个 <not-authorized/> 错误,它也应该(SHOULD)包含一个 pubsub-specific 的<closed-node/>错误条件。<br />
<br />
<br />
<br />
__案例 34. 节点有白名单访问模式__<br />
<br />
<br />
<source lang="xml"><br />
<br />
<iq type='error'<br />
<br />
from='pubsub.shakespeare.lit'<br />
<br />
to='francisco@denmark.lit/barracks'<br />
<br />
id='sub1'><br />
<br />
<br />
<br />
<pubsub xmlns='http://jabber.org/protocol/pubsub'><br />
<br />
<br />
<br />
<subscribe node='princely_musings' jid='francisco@denmark.lit'/><br />
<br />
<br />
<br />
</pubsub><br />
<br />
<br />
<br />
<error type='cancel'><br />
<br />
<br />
<br />
<not-allowed xmlns='urn:ietf:params:xml:ns:xmpp-stanzas'/><br />
<br />
<br />
<br />
<closed-node xmlns='http://jabber.org/protocol/pubsub#errors'/><br />
<br />
<br />
<br />
</error><br />
<br />
<br />
<br />
</iq><br />
<br />
</source><br />
<br />
<br />
<br />
商业部署可能希望把订阅连接到一个付费客户数据库。如果为了订阅节点需要付费(例如,如果订阅者不在客户数据库中或客户还未付帐),服务应该(SHOULD)返回一个 <payment-required/> 错误给订阅者。<br />
<br />
<br />
<br />
__案例 35. 订阅需要付费__<br />
<br />
<source lang="xml"><br />
<br />
<iq type='error'<br />
<br />
from='pubsub.shakespeare.lit'<br />
<br />
to='francisco@denmark.lit/barracks'<br />
<br />
id='sub1'><br />
<br />
<br />
<br />
<pubsub xmlns='http://jabber.org/protocol/pubsub'><br />
<br />
<br />
<br />
<subscribe node='princely_musings' jid='francisco@denmark.lit'/><br />
<br />
<br />
<br />
</pubsub><br />
<br />
<br />
<br />
<error type='auth'><br />
<br />
<br />
<br />
<payment-required xmlns='urn:ietf:params:xml:ns:xmpp-stanzas'/><br />
<br />
<br />
<br />
</error><br />
<br />
<br />
<br />
</iq><br />
<br />
</source><br />
<br />
<br />
<br />
一些 XMPP 服务器可能允许使用SASL ANONYMOUS验证;无论如何,因为这会导致实体不稳定(分配的JID可能不是同一个负责人in a persistent manner),一个服务可以(MAY)防止匿名实体订阅一个节点并且应该(SHOULD)使用服务发现来决定是否有一个 "account/anonymous"实体.如果一个请求实体是匿名的但是服务器不允许匿名实体订阅,服务应该返回一个< forbidden/>错误给订阅者.<br />
<br />
<br />
<br />
__案例 36. 请求实体是匿名用户__<br />
<br />
<br />
<br />
<source lang="xml"><br />
<br />
<iq type='error'<br />
<br />
from='pubsub.shakespeare.lit'<br />
to='anonymous@denmark.lit/foo'<br />
id='sub1'><br />
<pubsub xmlns='http://jabber.org/protocol/pubsub'><br />
<subscribe node='princely_musings' jid='anonymous@denmark.lit'/><br />
</pubsub><br />
<error type='cancel'><br />
<forbidden xmlns='urn:ietf:params:xml:ns:xmpp-stanzas'/><br />
</error><br />
</iq><br />
</source><br />
<br />
<br />
<br />
如果请求实体有一个未决的订阅, 服务必须(MUST)返回一个<not-authorized/>错误给订阅,表明一个发生了pubsub-specific <pending-subscription/>错误条件.<br />
<br />
<br />
<br />
__案例 37. 请求实体有一个未决的订阅__<br />
<br />
<br />
<br />
<source lang="xml"><br />
<br />
<iq type='error'<br />
from='pubsub.shakespeare.lit'<br />
to='francisco@denmark.lit/barracks'<br />
id='sub1'><br />
<pubsub xmlns='http://jabber.org/protocol/pubsub'><br />
<subscribe node='princely_musings' jid='francisco@denmark.lit'/><br />
</pubsub><br />
<error type='auth'><br />
<not-authorized xmlns='urn:ietf:params:xml:ns:xmpp-stanzas'/><br />
<pending-subscription xmlns='http://jabber.org/protocol/pubsub#errors'/><br />
</error><br />
</iq><br />
<br />
</source><br />
<br />
<br />
<br />
如果请求实体被一个订阅屏蔽了(例如, 因为它在禁止加入的名单中), 服务器必须(MUST)返回一个<forbidden/>错误给订阅者.<br />
<br />
<br />
<br />
__案例 38. 请求实体被屏蔽__<br />
<br />
<br />
<br />
<source lang="xml"><br />
<br />
<iq type='error'<br />
from='pubsub.shakespeare.lit'<br />
to='francisco@denmark.lit/barracks'<br />
id='sub1'><br />
<pubsub xmlns='http://jabber.org/protocol/pubsub'><br />
<subscribe node='princely_musings' jid='francisco@denmark.lit'/><br />
</pubsub><br />
<error type='auth'><br />
<forbidden xmlns='urn:ietf:params:xml:ns:xmpp-stanzas'/><br />
</error><br />
</iq><br />
<br />
</source><br />
<br />
<br />
<br />
如果节点不允许实体订阅, 服务应该(SHOULD)返回一个<feature-not-implemented/>错误给订阅者,提出一个pubsub- specific <unsupported/>错误条件和一个"subscribe"特性.<br />
<br />
<br />
<br />
__案例 39. 订阅不支持__<br />
<br />
<br />
<br />
<source lang="xml"><br />
<br />
<iq type='error'<br />
from='pubsub.shakespeare.lit'<br />
to='francisco@denmark.lit/barracks'<br />
id='sub1'><br />
<pubsub xmlns='http://jabber.org/protocol/pubsub'><br />
<subscribe node='princely_musings' jid='francisco@denmark.lit'/><br />
</pubsub><br />
<error type='cancel'><br />
<feature-not-implemented xmlns='urn:ietf:params:xml:ns:xmpp-stanzas'/><br />
<unsupported xmlns='http://jabber.org/protocol/pubsub#errors' feature='subscribe'/><br />
</error><br />
</iq><br />
<br />
</source><br />
<br />
<br />
<br />
如果节点不存在, 服务应该(SHOULD)返回一个<item-not-found/>错误给订阅者.<br />
<br />
<br />
<br />
__案例 40. 节点不存在__<br />
<br />
<br />
<br />
<source lang="xml"><br />
<br />
<iq type='error'<br />
from='pubsub.shakespeare.lit'<br />
to='francisco@denmark.lit/barracks'<br />
id='sub1'><br />
<pubsub xmlns='http://jabber.org/protocol/pubsub'><br />
<subscribe node='princely_musings' jid='francisco@denmark.lit'/><br />
</pubsub><br />
<error type='cancel'><br />
<item-not-found xmlns='urn:ietf:params:xml:ns:xmpp-stanzas'/><br />
</error><br />
</iq><br />
<br />
</source><br />
<br />
<br />
<br />
对于拥有"authorize"访问模式的节点, 订阅请求必须(MUST)由节点所有者批准; 所以pubsub服务发送一个消息给节点所有者请求授权(参见本文的 Manage Subscription Requests 章节). 因为订阅请求可能被批准也可能不被批准, 服务必须(MUST)返回一个未决通知给订阅者.<br />
<br />
<br />
<br />
__案例 41. 服务应答未决__<br />
<br />
<br />
<br />
<source lang="xml"><br />
<br />
<iq type='result'<br />
from='pubsub.shakespeare.lit'<br />
to='francisco@denmark.lit/barracks'<br />
id='sub1'><br />
<pubsub xmlns='http://jabber.org/protocol/pubsub'><br />
<subscription node='princely_musings' jid='francisco@denmark.lit' subscription='pending'/><br />
</pubsub><br />
</iq><br />
<br />
</source><br />
<br />
<br />
<br />
如果实体在接收通知之前必须配置它的订阅选项(见本文 Configure Subscription Options 章节),服务必须(MUST)通知实体这件事. 它应该(SHOULD)返回一个IQ-result给请求实体一个记号表示需要订阅配置。<br />
<br />
<br />
<br />
__案例 42. 服务应答成功并指出需要配置订阅__<br />
<br />
<br />
<br />
<source lang="xml"><br />
<br />
<iq type='result'<br />
from='pubsub.shakespeare.lit'<br />
to='francisco@denmark.lit/barracks'<br />
id='sub1'><br />
<pubsub xmlns='http://jabber.org/protocol/pubsub'><br />
<subscription node='princely_musings' jid='francisco@denmark.lit' subscription='unconfigured'><br />
<subscribe-options><br />
<required/><br />
</subscribe-options><br />
</subscription><br />
</pubsub><br />
</iq><br />
<br />
</source><br />
<br />
<br />
<br />
注意: 只有订阅者在收到任何通知之前必须配置订阅,节点才应该包含这个<required/>子元素. 如果配置是必需的而配置请求没有在合理的时间内提交,一个服务可以(MAY)判定订阅请求超时(取决于服务或节点的配置).<br />
<br />
<br />
<br />
同样的, 如果没有同步的配置就不能新建这个订阅, 服务可以(MAY)返回一个<not-acceptable/> 错误, 表示发生了一个pubsub-specific <configuration-required/>错误条件.<br />
<br />
<br />
<br />
__案例 43. 服务返回错误说明需要配置订阅__<br />
<br />
<br />
<br />
<source lang="xml"><br />
<br />
<iq type='error'<br />
from='pubsub.shakespeare.lit'<br />
to='francisco@denmark.lit/barracks'<br />
id='sub1'><br />
<pubsub xmlns='http://jabber.org/protocol/pubsub'><br />
<subscribe node='princely_musings' jid='francisco@denmark.lit'/><br />
<options node='princely_musings' jid='francisco@denmark.lit'><br />
<x xmlns='jabber:x:data' type='submit'><br />
<field var='FORM_TYPE' type='hidden'><br />
<value>>>http://jabber.org/protocol/pubsub#subscribe_options</value><br />
</field><br />
<field var='pubsub#deliver'><value>1</value></field><br />
<field var='pubsub#digest'><value>0</value></field><br />
<field var='pubsub#include_body'><value>false</value></field><br />
<field var='pubsub#show-values'><br />
<value>chat</value><br />
<value>online</value><br />
<value>away</value><br />
</field><br />
</x><br />
</options><br />
</pubsub><br />
<error type='modify'><br />
<not-acceptable xmlns='urn:ietf:params:xml:ns:xmpp-stanzas'/><br />
<configuration-required xmlns='http://jabber.org/protocol/pubsub#errors'/><br />
</error><br />
</iq><br />
<br />
</source><br />
<br />
<br />
<br />
如果没有包含<required/>元素也没有错误返回, 订阅立刻生效并且实体可以在任何时间配置这个订阅(服务可以(MAY)通过在IQ-result中包含一个空的<subscribe- options/>元素指出支持订阅选项, 如下案例所示).<br />
<br />
<br />
<br />
__案例 44. 服务应答成功并指出支持订阅配置但不是必需的__<br />
<br />
<br />
<br />
<source lang="xml"><br />
<br />
<iq type='result'<br />
from='pubsub.shakespeare.lit'<br />
to='francisco@denmark.lit/barracks'<br />
id='sub1'><br />
<pubsub xmlns='http://jabber.org/protocol/pubsub'><br />
<subscription node='princely_musings' jid='francisco@denmark.lit' subscription='unconfigured'><br />
<subscribe-options/><br />
</subscription><br />
</pubsub><br />
</iq><br />
<br />
</source><br />
<br />
<br />
<br />
__6.2 从一个节点取消订阅__ {anchor:从一个节点取消订阅}<br />
<br />
<br />
<br />
为了从一个节点取消订阅, 订阅者发送一个 IQ-set, 它的 <pubsub/> 子元素包含一个<unsubscribe/>元素,指明节点和已订阅的 JID.<br />
<br />
<br />
<br />
__案例 45. 实体从一个节点取消订阅__<br />
<br />
<br />
<br />
<source lang="xml"><br />
<br />
<iq type='set'<br />
<br />
from='francisco@denmark.lit/barracks'<br />
to='pubsub.shakespeare.lit'<br />
id='unsub1'><br />
<pubsub xmlns='http://jabber.org/protocol/pubsub'><br />
<unsubscribe node='princely_musings' jid='francisco@denmark.lit'/><br />
</pubsub><br />
</iq><br />
<br />
</source><br />
<br />
<br />
<br />
如果请求可以被成功处理,服务必须(MUST)一个 IQ result.<br />
<br />
<br />
<br />
__案例 46. 服务应答成功__<br />
<br />
<br />
<br />
<source lang="xml"><br />
<br />
<iq type='result'<br />
from='pubsub.shakespeare.lit'<br />
to='francisco@denmark.lit/barracks'<br />
id='unsub1'/><br />
<br />
</source><br />
<br />
<br />
<br />
有很多原因可能导致取消订阅失败:<br />
<br />
<br />
<br />
1. 请求实体有多个订阅指向节点但未指定一个订阅ID.<br />
<br />
1. 请求未指定一个已存在的订阅者.<br />
<br />
1. 请求实体没有足够的权限取消指定JID的订阅.<br />
<br />
1. 节点不存在.<br />
<br />
1. 请求指定的订阅ID不合法或不是当前的.<br />
<br />
<br />
<br />
更多的错误情景描述如下.<br />
<br />
<br />
<br />
如果请求实体有多个订阅指向节点但是没有指定一个订阅ID, 服务必须(MUST)返回一个<bad-request/>错误, 它也应该(SHOULD)包含一个 <subid-required/>的pubsub-specific错误条件 .<br />
<br />
<br />
<br />
__案例 47. 实体未指定SubID__<br />
<br />
<br />
<br />
<source lang="xml"><br />
<br />
<iq type='error'<br />
from='pubsub.shakespeare.lit'<br />
to='francisco@denmark.lit/barracks'<br />
id='unsub1'><br />
<pubsub xmlns='http://jabber.org/protocol/pubsub'><br />
<unsubscribe node='princely_musings' jid='francisco@denmark.lit'/><br />
</pubsub><br />
<error type='modify'><br />
<bad-request xmlns='urn:ietf:params:xml:ns:xmpp-stanzas'/><br />
<subid-required xmlns='http://jabber.org/protocol/pubsub#errors'/><br />
</error><br />
</iq><br />
<br />
</source><br />
<br />
<br />
<br />
如果'jid'属性的值未指定一个已存在的订阅者, pubsub服务必须(MUST)返回一个错误节, 它应该(SHOULD)是<unexpected-request/>并且也应该(SHOULD)包含一个 <not-subscribed/>的pubsub-specific错误条件.<br />
<br />
<br />
<br />
__案例 48. 请求实体不是一个订阅者__<br />
<br />
<br />
<br />
<source lang="xml"><br />
<br />
<iq type='error'<br />
from='pubsub.shakespeare.lit'<br />
to='francisco@denmark.lit/barracks'<br />
id='unsub1'><br />
<pubsub xmlns='http://jabber.org/protocol/pubsub'><br />
<unsubscribe node='princely_musings' jid='francisco@denmark.lit'/><br />
</pubsub><br />
<error type='cancel'><br />
<unexpected-request xmlns='urn:ietf:params:xml:ns:xmpp-stanzas'/><br />
<not-subscribed xmlns='http://jabber.org/protocol/pubsub#errors'/><br />
</error><br />
</iq><br />
<br />
</source><br />
<br />
<br />
<br />
如果请求实体被禁止取消特定JID的订阅, 服务必须(MUST)返回一个<forbidden/>错误. 服务必须(MUST)检查这个做出请求的实体是否被授权可以取消订阅. 如果订阅者的JID格式是<node@domain.tld/resource>, 服务必须(MUST)通过比较两个JID的<node@domain.tld>部分执行这个检查以确保它们是吻合的. 如果这些JID的纯JID部分不吻合并且请求实体没有被授权取消这个JID的订阅(例如, 因为它不是一个服务管理员或被授权的代理), 服务必须(MUST)返回一个<forbidden/>错误.<br />
<br />
<br />
<br />
__案例 49. 请求实体被禁止取消订阅实体__<br />
<br />
<br />
<br />
<source lang="xml"><br />
<br />
<iq type='error'<br />
from='pubsub.shakespeare.lit'<br />
to='francisco@denmark.lit/barracks'<br />
id='unsub1'><br />
<pubsub xmlns='http://jabber.org/protocol/pubsub'><br />
<unsubscribe node='princely_musings' jid='bard@shakespeare.lit'/><br />
</pubsub><br />
<error type='auth'><br />
<forbidden xmlns='urn:ietf:params:xml:ns:xmpp-stanzas'/><br />
</error><br />
</iq><br />
<br />
</source><br />
<br />
<br />
<br />
如果节点不存在, pubsub服务必须(MUST)返回一个 <item-not-found/> 错误.<br />
<br />
<br />
<br />
__案例 50. 节点不存在__<br />
<br />
<br />
<br />
<source lang="xml"><br />
<br />
<iq type='error'<br />
from='pubsub.shakespeare.lit'<br />
to='francisco@denmark.lit/barracks'<br />
id='unsub1'><br />
<pubsub xmlns='http://jabber.org/protocol/pubsub'><br />
<unsubscribe node='princely_musings' jid='francisco@denmark.lit'/><br />
</pubsub><br />
<error type='cancel'><br />
<item-not-found xmlns='urn:ietf:params:xml:ns:xmpp-stanzas'/><br />
</error><br />
</iq><br />
<br />
</source><br />
<br />
<br />
<br />
如果一个订阅标识符关联于某个订阅项, 取消订阅请求必须(MUST)包含一个适当的'subid'属性. 如果这个取消订阅请求包含一个 SubID 但是节点不支持 SubIDs (或订阅者第一次并没有使用 SubID 来订阅), 服务应该(SHOULD)忽略这个 SubID 并简单地取消订阅这个实体. 如果订阅者以前使用一个 SubID 来订阅但是取消订阅申请包含一个不合法或非当前订阅者的 SubID , 服务必须(MUST)返回一个<not-acceptable/>错误, 它应该(SHOULD)也包含一个<invalid-subid/>的pubsub-specific错误条件.<br />
<br />
<br />
<br />
__案例 51. 非法的订阅项标识符__<br />
<br />
<br />
<br />
<source lang="xml"><br />
<br />
<iq type='error'<br />
from='pubsub.shakespeare.lit'<br />
to='francisco@denmark.lit/barracks'<br />
id='unsub1'><br />
<pubsub xmlns='http://jabber.org/protocol/pubsub'><br />
<unsubscribe node='princely_musings' subid='ba49252aaa4f5d320c24d3766f0bdcade78c78d3' jid='francisco@denmark.lit'/><br />
</pubsub><br />
<error type='modify'><br />
<not-acceptable xmlns='urn:ietf:params:xml:ns:xmpp-stanzas'/><br />
<invalid-subid xmlns='http://jabber.org/protocol/pubsub#errors'/><br />
</error><br />
</iq><br />
<br />
</source><br />
<br />
<br />
<br />
__6.3 配置订阅选项__ {anchor:配置订阅选项}<br />
<br />
<br />
<br />
实现可以(MAY)允许订阅者们配置订阅选项. 实现应该(SHOULD)使用数据表单(Data Forms)协议来实现这个配置(无论如何, 一个带外机制如web界面也可能被提供).<br />
<br />
<br />
<br />
如果一个服务支持订阅选项, 它必须(MUST)在它对"disco#info"查询的应答中声明(在应答中包含一个feature,其'var'属性为"pubsub#subscription-options").<br />
<br />
<br />
<br />
__案例 52. Pubsub服务显示对订阅选项的支持__<br />
<br />
<br />
<br />
<source lang="xml"><br />
<br />
<iq type='result'<br />
from='pubsub.shakespeare.lit'<br />
to='francisco@denmark.lit/barracks'<br />
id='feature1'><br />
<query xmlns='http://jabber.org/protocol/disco#info'><br />
...<br />
<feature var='http://jabber.org/protocol/pubsub#subscription-options'/><br />
...<br />
</query><br />
</iq><br />
<br />
</source><br />
<br />
<br />
<br />
一个订阅者通过在IQ-set节中包含一个<options/>元素来请求订阅选项.<br />
<br />
<br />
<br />
__案例 53. 订阅者请求订阅选项表单__<br />
<br />
<br />
<br />
<source lang="xml"><br />
<br />
<iq type='get'<br />
from='francisco@denmark.lit/barracks'<br />
to='pubsub.shakespeare.lit'<br />
id='options1'><br />
<pubsub xmlns='http://jabber.org/protocol/pubsub'><br />
<options node='princely_musings' jid='francisco@denmark.lit'/><br />
</pubsub><br />
</iq><br />
<br />
</source><br />
<br />
<br />
<br />
如果请求被成功的处理, 服务必须(MUST)应答选项.<br />
<br />
<br />
<br />
__案例 54. 服务应答选项表单__<br />
<br />
<br />
<br />
<source lang="xml"><br />
<br />
<iq type='result'<br />
from='pubsub.shakespeare.lit'<br />
to='francisco@denmark.lit/barracks'<br />
id='options1'><br />
<pubsub xmlns='http://jabber.org/protocol/pubsub'><br />
<options node='princely_musings' jid='francisco@denmark.lit'><br />
<x xmlns='jabber:x:data' type='form'><br />
<field var='FORM_TYPE' type='hidden'><br />
<value>>>http://jabber.org/protocol/pubsub#subscribe_options</value><br />
</field><br />
<field var='pubsub#deliver' type='boolean' label='Enable delivery?'><br />
<value>1</value><br />
</field><br />
<field var='pubsub#digest' type='boolean' label='Receive digest notifications (approx. one per day)?'><br />
<value>0</value><br />
</field><br />
<field var='pubsub#include_body' type='boolean' label='Receive message body in addition to payload?'><br />
<value>false</value><br />
</field><br />
<field var='pubsub#show-values' type='list-multi' label='Select the presence types which are allowed to receive notifications'><br />
<option label='Want to Chat'><value>chat</value></option><br />
<option label='Available'><value>online</value></option><br />
<option label='Away'><value>away</value></option><br />
<option label='Extended Away'><value>xa</value></option><br />
<option label='Do Not Disturb'><value>dnd</value></option><br />
<value>chat</value><br />
<value>online</value><br />
</field><br />
</x><br />
</options><br />
</pubsub><br />
</iq><br />
<br />
</source><br />
<br />
<br />
<br />
注意: 前述的例子展示了一些(但不是所有)的可能(MAY)被提供的配置选项. 如果一个实现使用数据表单(Data Forms)协议提供了这些选项, 它必须(MUST)使用那些在和'http://jabber.org/protocol/pubsub'名字空间关联的XMPP Registrar中注册了的字段(以上初步展示了那些字段, 并且在本文的 pubsub#subscribe_options FORM_TYPE 章节也描述了它们, 但是不能(MUST NOT)被当作规范, 因为 XMPP Registrar 以后还可以在不改变本文的情况下标准化更多的字段).<br />
<br />
<br />
<br />
注意: 很多相关的数据表单字段有一个 "boolean" 类型并且必须(MUST)被有效处理. [16]<br />
<br />
<br />
<br />
很多原因可以导致选项请求失败:<br />
<br />
<br />
<br />
1. 请求实体没有足够的权限来修改指定的JID的订阅选项.<br />
<br />
1. 请求实体(或指定的订阅者)未曾订阅.<br />
<br />
1. 请求没有同时指定 NodeID 和订阅者的 JID.<br />
<br />
1. 请求没有指定一个订阅项ID但是它被需要.<br />
<br />
1. 请求指定了一个订阅项ID但不是合法的或当前的.<br />
<br />
1. 订阅选项不知吃.<br />
<br />
1. 节点不存在.<br />
<br />
<br />
<br />
更多的错误案例描述如下.<br />
<br />
<br />
<br />
请求订阅选项的时候, 订阅者必须(MUST)指定向节点订阅的 JID 并且应该(SHOULD)指定一个节点(如果没有指定节点, 服务必须(MUST)认为请求实体希望为它的订阅项向根集合节点请求订阅选项; 详见本文的根集合节点章节).<br />
<br />
<br />
<br />
服务必须(MUST)验证提出请求的实体已经被授权为订阅的实体设置订阅选项. 如果订阅者的JID的格式是<node@domain.tld/resource>, 服务必须(MUST)比较两个JID的<node@domain.tld>部分以确保他们是吻合的. 如果两个JID的纯JID部分不吻合并且请求实体没有被授权修改这个JID的订阅选项(例如, 因为它不是一个服务范围内的管理员或授权代理), 服务必须(MUST)返回一个<forbidden/>错误.<br />
<br />
<br />
<br />
__案例 55. 请求实体没有足够的权限修改订阅选项__<br />
<br />
<br />
<br />
<source lang="xml"><br />
<br />
<iq type='error' from='pubsub.shakespeare.lit' to='francisco@denmark.lit/barracks' id='sub1'><br />
<pubsub xmlns='http://jabber.org/protocol/pubsub'><br />
<options node='princely_musings' jid='bernardo@denmark.lit'/><br />
</pubsub><br />
<error type='auth'><br />
<forbidden xmlns='urn:ietf:params:xml:ns:xmpp-stanzas'/> <br />
</error> <br />
</iq><br />
<br />
</source><br />
<br />
<br />
<br />
如果请求实体(或指定的订阅者, 如果不同的话) 未曾订阅, 服务必须(MUST)返回一个 <unexpected-request/> 错误, 它(SHOULD)也包括一个 <not-subscribed/> 的 pubsub-specific 错误条件.<br />
<br />
<br />
<br />
__案例 56. 没有这个订阅者__<br />
<br />
<br />
<br />
<source lang="xml"><br />
<br />
<iq type='error' from='pubsub.shakespeare.lit' to='francisco@denmark.lit/barracks' id='options1'><br />
<pubsub xmlns='http://jabber.org/protocol/pubsub'> <br />
<options/> <br />
</pubsub> <br />
<error type='modify'> <br />
<unexpected-request xmlns='urn:ietf:params:xml:ns:xmpp-stanzas'/> <br />
<not-subscribed xmlns='http://jabber.org/protocol/pubsub#errors'/> <br />
</error> <br />
</iq><br />
<br />
</source><br />
<br />
<br />
<br />
如果订阅者没有指定一个JID, 服务必须(MUST)返回一个<bad-request/>错误, 它也应该(SHOULD)包含一个<jid-required/>的pubsub-specific错误条件.<br />
<br />
<br />
<br />
__案例 57. 订阅者JID未指定__<br />
<br />
<br />
<br />
<source lang="xml"><br />
<br />
<iq type='error' from='pubsub.shakespeare.lit' to='francisco@denmark.lit/barracks' id='options1'><br />
<pubsub xmlns='http://jabber.org/protocol/pubsub'><br />
<options/> <br />
</pubsub> <br />
<error type='modify'><br />
<bad-request xmlns='urn:ietf:params:xml:ns:xmpp-stanzas'/><br />
<jid-required xmlns='http://jabber.org/protocol/pubsub#errors'/><br />
</error> <br />
</iq><br />
<br />
</source><br />
<br />
<br />
<br />
如果一个订阅项标识符关联于某个订阅项, 为了服务能够区分来自同一实体的订阅,在订阅请求中必须(MUST)带上'subid'属性. 如果'subid'是必需的但未被提供, 服务必须(MUST)返回一个<bad-request/>错误, 它也应该(SHOULD)包含一个<subid-required/>的pubsub-specific错误条件.<br />
<br />
<br />
<br />
__案例 58. 需要SubID__<br />
<br />
<br />
<br />
<source lang="xml"><br />
<br />
<iq type='error' from='pubsub.shakespeare.lit' to='francisco@denmark.lit/barracks' id='sub1'><br />
<pubsub xmlns='http://jabber.org/protocol/pubsub'><br />
<options node='princely_musings' jid='francisco@denmark.lit'/><br />
</pubsub> <error type='modify'><br />
<bad-request xmlns='urn:ietf:params:xml:ns:xmpp-stanzas'/><br />
<subid-required xmlns='http://jabber.org/protocol/pubsub#errors'/><br />
</error> <br />
</iq><br />
<br />
</source><br />
<br />
<br />
<br />
如果一个订阅项标识符关联于某订阅项, 但请求包含的 SubID 不合法或不是当前订阅者的, 服务必须(MUST)返回一个<not-acceptable/>错误, 它也应该(SHOULD)包含一个<invalid-subid/>的pubsub-specific错误条件.<br />
<br />
<br />
<br />
__案例 59. 非法的订阅项标识符__<br />
<br />
<br />
<br />
<source lang="xml"><br />
<br />
<iq type='error' from='pubsub.shakespeare.lit' to='francisco@denmark.lit/barracks' id='unsub1'><br />
<pubsub xmlns='http://jabber.org/protocol/pubsub'><br />
<unsubscribe node='princely_musings' subid='991d7fd1616fd041015064133cd097a10030819e' jid='francisco@denmark.lit'/> <br />
</pubsub><br />
<error type='modify'><br />
<not-acceptable xmlns='urn:ietf:params:xml:ns:xmpp-stanzas'/><br />
<invalid-subid xmlns='http://jabber.org/protocol/pubsub#errors'/><br />
</error> <br />
</iq><br />
<br />
</source><br />
<br />
<br />
<br />
如果节点或服务不支持订阅选项, 服务必须(MUST)应答一个<feature-not-implemented/>错误, 指定一个<unsupported/>的pubsub-specific错误条件和一个"subscription-options"特性.<br />
<br />
<br />
<br />
__案例 60. 订阅选项不支持__<br />
<br />
<br />
<br />
<source lang="xml"><br />
<br />
<iq type='error' from='pubsub.shakespeare.lit' to='francisco@denmark.lit/barracks' id='options1'><br />
<pubsub xmlns='http://jabber.org/protocol/pubsub'><br />
<options node='princely_musings' jid='francisco@denmark.lit'/><br />
</pubsub><br />
<error type='cancel'><br />
<feature-not-implemented xmlns='urn:ietf:params:xml:ns:xmpp-stanzas'/> <br />
<unsupported xmlns='http://jabber.org/protocol/pubsub#errors' feature='subscription-options'/><br />
</error> <br />
</iq><br />
<br />
</source><br />
<br />
<br />
<br />
如果节点不存在, pubsub服务必须(MUST)返回一个<item-not-found/>错误.<br />
<br />
<br />
<br />
__案例 61. 节点不存在__<br />
<br />
<br />
<br />
<source lang="xml"><br />
<br />
<iq type='error' from='pubsub.shakespeare.lit' to='francisco@denmark.lit/barracks' id='options1'><br />
<pubsub xmlns='http://jabber.org/protocol/pubsub'><br />
<br />
<options node='princely_musings' jid='francisco@denmark.lit'/><br />
</pubsub><br />
<error type='cancel'><br />
<item-not-found xmlns='urn:ietf:params:xml:ns:xmpp-stanzas'/><br />
</error> <br />
</iq><br />
<br />
</source><br />
<br />
<br />
<br />
接收了配置表单之后, 请求实体应该(SHOULD)提交这个表单来更新这个实体对于那个节点的订阅选项.<br />
<br />
<br />
<br />
__案例 62. 订阅者提交完整的选项表单__<br />
<br />
<br />
<br />
<source lang="xml"><br />
<br />
<iq type='set' from='francisco@denmark.lit/barracks' to='pubsub.shakespeare.lit' id='options2'><br />
<pubsub xmlns='http://jabber.org/protocol/pubsub'><br />
<options node='princely_musings' jid='francisco@denmark.lit'><br />
<x xmlns='jabber:x:data' type='submit'><br />
<field var='FORM_TYPE' type='hidden'> <br />
<value>http://jabber.org/protocol/pubsub#subscribe_options</value><br />
</field><br />
<field var='pubsub#deliver'><br />
<value>1</value><br />
</field><br />
<field var='pubsub#digest'><br />
<value>0</value><br />
</field><br />
<field var='pubsub#include_body'><br />
<value>false</value><br />
<br />
</field><br />
<field var='pubsub#show-values'> <br />
<value>chat</value> <br />
<value>online</value> <br />
<br />
<value>away</value><br />
</field><br />
</x><br />
</options><br />
</pubsub><br />
</iq><br />
<br />
</source><br />
<br />
<br />
<br />
如果服务能成功处理提交的表单, 它必须(MUST)应答成功.<br />
<br />
<br />
<br />
__案例 63. 服务应答成功__<br />
<br />
<br />
<br />
<source lang="xml"><br />
<br />
<iq type='result' from='pubsub.shakespeare.lit' to='francisco@denmark.lit/barracks' id='options2'/><br />
<br />
</source><br />
<br />
<br />
<br />
如果订阅者尝试设置非法的选项组, 服务必须(MUST)应答一个<bad-request/>错误.<br />
<br />
<br />
<br />
__案例 64. 服务对于非法选项应答错误请求__<br />
<br />
<br />
<br />
<source lang="xml"><br />
<br />
<iq type='error' from='pubsub.shakespeare.lit' to='francisco@denmark.lit/barracks' id='options2'><br />
<pubsub xmlns='http://jabber.org/protocol/pubsub'><br />
<options node='princely_musings' jid='francisco@denmark.lit'><br />
<x xmlns='jabber:x:data'><br />
<field var='FORM_TYPE' type='hidden'> <br />
<value>http://jabber.org/protocol/pubsub#subscribe_options</value><br />
</field><br />
<field var='pubsub#deliver'><br />
<value>1</value><br />
</field> <br />
<br />
<field var='pubsub#digest'><br />
<value>0</value><br />
</field> <br />
<field var='pubsub#include_body'><br />
<value>false</value><br />
</field> <br />
<field var='pubsub#show-values'> <br />
<value>chat</value> <br />
<value>online</value> <br />
<value>away</value> <br />
</field> <br />
</x> <br />
</options> <br />
</pubsub> <br />
<error type='modify'> <br />
<bad-request xmlns='urn:ietf:params:xml:ns:xmpp-stanzas'/> <br />
<invalid-options xmlns='http://jabber.org/protocol/pubsub#errors'/> <br />
</error><br />
</iq><br />
<br />
</source><br />
<br />
<br />
<br />
其他适用于获取订阅选项时发生的错误也同样适用于设置订阅选项的情形.<br />
<br />
<br />
<br />
大家直到, 如果一个服务支持订阅选项, 一个实体可以(MAY)在同一个节中订阅和提供订阅选项.<br />
<br />
<br />
<br />
主意: <options/>元素必须(MUST)跟随在<subscribe/>元素之后并且不能(MUST NOT)拥有一个'node'属性或'jid'属性, 因为<subscribe/>元素的'node'属性值指明了期望的NodeID并且<subscribe/>元素的'jid'属性值指明了订阅者的JID; 如果这些值中的任何一个违规了, 服务必须(MUST)返回一个<bad-request/>错误.<br />
<br />
<br />
<br />
__案例 65. 实体订阅一个节点并且设置配置选项__<br />
<br />
<br />
<br />
<source lang="xml"><br />
<br />
<iq type='set' from='francisco@denmark.lit/barracks' to='pubsub.shakespeare.lit' id='sub1'> <br />
<pubsub xmlns='http://jabber.org/protocol/pubsub'> <br />
<subscribe node='princely_musings' jid='francisco@denmark.lit'/> <br />
<options> <br />
<x xmlns='jabber:x:data'> <br />
<field var='FORM_TYPE' type='hidden'> <br />
<value>http://jabber.org/protocol/pubsub#subscribe_options</value> <br />
</field> <br />
<field var='pubsub#deliver'><br />
<value>1</value><br />
</field> <br />
<br />
<field var='pubsub#digest'><br />
<value>0</value><br />
</field> <br />
<field var='pubsub#include_body'><br />
<value>false</value><br />
</field> <br />
<field var='pubsub#show-values'> <br />
<value>chat</value> <br />
<value>online</value> <br />
<value>away</value> <br />
</field> <br />
</x> <br />
</options> <br />
</pubsub> <br />
</iq><br />
<br />
</source><br />
<br />
<br />
<br />
__6.4 从节点接收条目__ {anchor:从节点接收条目}<br />
<br />
<br />
<br />
选择保留条目的pubsub实现可以(MAY)允许实体从一个节点请求已有的条目(例如, 一个实体可能希望在成功订阅之后这样做以接收这个节点历史上发行的所有条目). 服务必须(MUST)遵守节点访问模式来决定是否向请求它们的实体返回这些条目. 具体来说:<br />
<br />
<br />
<br />
* 如果访问模式是"open", 服务应该(SHOULD)允许任何实体(无论是否订阅)接收条目.<br />
<br />
* 如果访问模式是"presence", 服务应该(SHOULD)允许任何已订阅这个所有者的出席信息的实体接收条目.<br />
<br />
* 如果访问模式是"roster", 服务应该(SHOULD)允许任何已订阅这个所有者的出席信息并处于适当的名册组中的实体接收条目.<br />
<br />
* 如果访问模式是"authorize"或"whitelist", 服务必须(MUST)只允许已订阅的实体来接收条目.<br />
<br />
<br />
<br />
对于将来的访问模式所应有(SHOULD)的需求, 可能的例外是强制本地隐私和安全策略, 更全面的描述见本文的安全事项章节. (另外, 一个服务应该(MUST)总是允许节点所有者从一个节点接收条目并且应该(SHOULD)总是允许一个发行者这样做.)<br />
<br />
<br />
<br />
订阅者可以通过仅仅不加限制地指明节点ID来请求所有的条目.<br />
<br />
<br />
<br />
__案例 66. 订阅者请求所有条目__<br />
<br />
<br />
<br />
<source lang="xml"><br />
<br />
<iq type='get'<br />
from='francisco@denmark.lit/barracks'<br />
to='pubsub.shakespeare.lit'<br />
id='items1'><br />
<pubsub xmlns='http://jabber.org/protocol/pubsub'><br />
<items node='princely_musings'/><br />
</pubsub><br />
</iq><br />
<br />
</source> <br />
<br />
<br />
<br />
服务然后应该(SHOULD)返回所有发行到这个节点的条目, 尽管它可以(MAY)截取结果(如果已发行的条目数量太多的话).<br />
<br />
<br />
<br />
__案例 67. 服务返回所有条目__<br />
<br />
<br />
<br />
<source lang="xml"><br />
<br />
<iq type='result'<br />
from='pubsub.shakespeare.lit'<br />
to='francisco@denmark.lit/barracks'<br />
id='items1'><br />
<pubsub xmlns='http://jabber.org/protocol/pubsub'><br />
<items node='princely_musings'><br />
<item id='368866411b877c30064a5f62b917cffe'><br />
<entry xmlns='http://www.w3.org/2005/Atom'><br />
<title>The Uses of This World</title><br />
<summary><br />
O, that this too too solid flesh would melt<br />
Thaw and resolve itself into a dew!<br />
</summary><br />
<link rel='alternate' type='text/html'<br />
href='http://denmark.lit/2003/12/13/atom03'/><br />
<id>tag:denmark.lit,2003:entry-32396</id><br />
<published>2003-12-12T17:47:23Z</published><br />
<updated>2003-12-12T17:47:23Z</updated><br />
</entry><br />
</item><br />
<item id='3300659945416e274474e469a1f0154c'><br />
<entry xmlns='http://www.w3.org/2005/Atom'><br />
<title>Ghostly Encounters</title><br />
<summary><br />
O all you host of heaven! O earth! what else?<br />
And shall I couple hell? O, fie! Hold, hold, my heart;<br />
And you, my sinews, grow not instant old,<br />
But bear me stiffly up. Remember thee!<br />
</summary><br />
<link rel='alternate' type='text/html'<br />
href='http://denmark.lit/2003/12/13/atom03'/><br />
<id>tag:denmark.lit,2003:entry-32396</id><br />
<published>2003-12-12T23:21:34Z</published><br />
<updated>2003-12-12T23:21:34Z</updated><br />
</entry><br />
</item><br />
<item id='4e30f35051b7b8b42abe083742187228'><br />
<entry xmlns='http://www.w3.org/2005/Atom'><br />
<title>Alone</title><br />
<summary><br />
Now I am alone.<br />
O, what a rogue and peasant slave am I!<br />
</summary><br />
<link rel='alternate' type='text/html'<br />
href='http://denmark.lit/2003/12/13/atom03'/><br />
<id>tag:denmark.lit,2003:entry-32396</id><br />
<published>2003-12-13T11:09:53Z</published><br />
<updated>2003-12-13T11:09:53Z</updated><br />
</entry><br />
</item><br />
<item id='ae890ac52d0df67ed7cfdf51b644e901'><br />
<entry xmlns='http://www.w3.org/2005/Atom'><br />
<title>Soliloquy</title><br />
<summary><br />
To be, or not to be: that is the question:<br />
Whether 'tis nobler in the mind to suffer<br />
The slings and arrows of outrageous fortune,<br />
Or to take arms against a sea of troubles,<br />
And by opposing end them?<br />
</summary><br />
<link rel='alternate' type='text/html'<br />
href='http://denmark.lit/2003/12/13/atom03'/><br />
<id>tag:denmark.lit,2003:entry-32397</id><br />
<published>2003-12-13T18:30:02Z</published><br />
<updated>2003-12-13T18:30:02Z</updated><br />
</entry><br />
</item><br />
</items><br />
</pubsub><br />
</iq><br />
<br />
</source> <br />
<br />
<br />
<br />
即使服务或节点不支持持久化条目, 它也可以(MAY)返回最后发行的条目.<br />
<br />
<br />
<br />
__案例 68. 服务返回最后发行的条目__<br />
<br />
<br />
<br />
<source lang="xml"><br />
<br />
<iq type='result'<br />
from='pubsub.shakespeare.lit'<br />
to='francisco@denmark.lit/barracks'<br />
id='items1'><br />
<pubsub xmlns='http://jabber.org/protocol/pubsub'><br />
<items node='princely_musings'><br />
<item id='ae890ac52d0df67ed7cfdf51b644e901'><br />
<entry xmlns='http://www.w3.org/2005/Atom'><br />
<title>Soliloquy</title><br />
<summary><br />
To be, or not to be: that is the question:<br />
Whether 'tis nobler in the mind to suffer<br />
The slings and arrows of outrageous fortune,<br />
Or to take arms against a sea of troubles,<br />
And by opposing end them?<br />
</summary><br />
<link rel='alternate' type='text/html'<br />
href='http://denmark.lit/2003/12/13/atom03'/><br />
<id>tag:denmark.lit,2003:entry-32397</id><br />
<published>2003-12-13T18:30:02Z</published><br />
<updated>2003-12-13T18:30:02Z</updated><br />
</entry><br />
</item><br />
</items><br />
</pubsub><br />
</iq><br />
<br />
</source><br />
<br />
<br />
<br />
有很多种原因可能导致条目接收请求失败:<br />
<br />
<br />
<br />
1. 请求实体对同一个节点有多个订阅项但是没有指定一个订阅项ID.<br />
<br />
1. 请求实体订阅了但是指定了一个非法的订阅项ID.<br />
<br />
1. 节点没有返回条目给未订阅的实体但是请求实体未曾订阅.<br />
<br />
1. 服务或节点不支持持久条目并且没有返回最后发行的条目.<br />
<br />
1. 服务或节点不支持条目接收.<br />
<br />
1. 节点有一个"presence"访问模式而请求实体没有订阅所有者的出席信息.<br />
<br />
1. 节点有一个"roster"访问模式而请求实体不在授权的名册组中.<br />
<br />
1. 节点有一个"whitelist"访问模式而请求实体不在白名单中.<br />
<br />
1. 服务或节点需要付费才允许接收条目.<br />
<br />
1. 请求实体被屏蔽了从节点接收条目的功能(例如, 因为有一个排斥者的从属关系).<br />
<br />
1. 节点不存在.<br />
<br />
<br />
<br />
这些错误完整描述如下.<br />
<br />
<br />
<br />
如果请求实体对同一个节点有多个订阅项但是没有指定一个订阅项ID, 服务必须(MUST)返回一个<bad-request/>错误给订阅者, 它也应该(SHOULD)包含一个<subid-required/>的pubsub-specific错误条件.<br />
<br />
<br />
<br />
__案例 69. 实体未指定SubID__<br />
<br />
<br />
<br />
<source lang="xml"><br />
<br />
<iq type='error'<br />
from='pubsub.shakespeare.lit'<br />
to='francisco@denmark.lit/barracks'<br />
id='items1'><br />
<pubsub xmlns='http://jabber.org/protocol/pubsub'><br />
<items node='princely_musings'/><br />
</pubsub><br />
<error type='modify'><br />
<bad-request xmlns='urn:ietf:params:xml:ns:xmpp-stanzas'/><br />
<subid-required xmlns='http://jabber.org/protocol/pubsub#errors'/><br />
</error><br />
</iq><br />
<br />
</source><br />
<br />
<br />
<br />
如果请求实体订阅了但是指定了一个非法的订阅项ID, 服务必须(MUST)返回一个<not-acceptable/>错误给订阅者, 它也应该(SHOULD)包含一个<invalid-subid/>的pubsub-specific错误条件.<br />
<br />
<br />
<br />
__案例 70. 实体制定了非法的SubID__<br />
<br />
<br />
<br />
<source lang="xml"><br />
<br />
<iq type='error'<br />
from='pubsub.shakespeare.lit'<br />
to='francisco@denmark.lit/barracks'<br />
id='items1'><br />
<pubsub xmlns='http://jabber.org/protocol/pubsub'><br />
<items node='princely_musings'/><br />
</pubsub><br />
<error type='modify'><br />
<not-acceptable xmlns='urn:ietf:params:xml:ns:xmpp-stanzas'/><br />
<invalid-subid xmlns='http://jabber.org/protocol/pubsub#errors'/><br />
</error><br />
</iq><br />
<br />
</source><br />
<br />
<br />
<br />
如果节点未返回条目给未订阅的实体并且请求实体未曾订阅(包含已有一个未决的订阅项的情形), 服务必须(MUST)返回一个<not-authorized/>错误给订阅者, 它也应该(SHOULD)包含一个<not-subscribed/>的pubsub-specific错误条件.<br />
<br />
<br />
<br />
__案例 71. 实体未订阅__<br />
<br />
<br />
<br />
<source lang="xml"><br />
<br />
<iq type='error'<br />
from='pubsub.shakespeare.lit'<br />
to='francisco@denmark.lit/barracks'<br />
id='items1'><br />
<pubsub xmlns='http://jabber.org/protocol/pubsub'><br />
<items node='princely_musings'/><br />
</pubsub><br />
<error type='auth'><br />
<not-authorized xmlns='urn:ietf:params:xml:ns:xmpp-stanzas'/><br />
<not-subscribed xmlns='http://jabber.org/protocol/pubsub#errors'/><br />
</error><br />
</iq><br />
<br />
</source><br />
<br />
<br />
<br />
如果服务或节点不支持持久条目且没有返回最后发行的条目, 服务必须(MUST)返回一个<feature-not-implemented/>错误给订阅者, 指定一个pubsub-specific错误条件<unsupported/>以及一个特性"persistent-items".<br />
<br />
<br />
<br />
__案例 72. 不支持持久条目__<br />
<br />
<br />
<br />
<source lang="xml"><br />
<br />
<iq type='error'<br />
from='pubsub.shakespeare.lit'<br />
to='francisco@denmark.lit/barracks'<br />
id='items1'><br />
<pubsub xmlns='http://jabber.org/protocol/pubsub'><br />
<items node='princely_musings'/><br />
</pubsub><br />
<error type='cancel'><br />
<feature-not-implemented xmlns='urn:ietf:params:xml:ns:xmpp-stanzas'/><br />
<unsupported xmlns='http://jabber.org/protocol/pubsub#errors'<br />
feature='persistent-items'/><br />
</error><br />
</iq><br />
<br />
</source> <br />
<br />
<br />
<br />
如果服务或节点不支持接收条目(例如, 因为节点是一个集合节点), 服务必须(MUST)返回一个<feature-not-implemented/>错误给订阅者, 指明一个pubsub-specific错误条件<unsupported/>以及一个特性"retrieve-items".<br />
<br />
<br />
<br />
__案例 73. 不支持条目接收__<br />
<br />
<br />
<br />
<source lang="xml"><br />
<br />
<iq type='error'<br />
from='pubsub.shakespeare.lit'<br />
to='francisco@denmark.lit/barracks'<br />
id='items1'><br />
<pubsub xmlns='http://jabber.org/protocol/pubsub'><br />
<items node='princely_musings'/><br />
</pubsub><br />
<error type='cancel'><br />
<feature-not-implemented xmlns='urn:ietf:params:xml:ns:xmpp-stanzas'/><br />
<unsupported xmlns='http://jabber.org/protocol/pubsub#errors'<br />
feature='retrieve-items'/><br />
</error><br />
</iq><br />
<br />
</source> <br />
<br />
<br />
<br />
对于访问模式为"presence"的节点, 如果请求实体没有订阅所有者的出席信息那么pubsub服务必须(MUST)应答一个<not-authorized/>错误, 它还应该(SHOULD)包含一个pubsub-specific错误条件<presence-subscription-required/>.<br />
<br />
<br />
<br />
__案例 74. 实体没有被授权接收条目(要求订阅出席信息)__<br />
<br />
<br />
<br />
<source lang="xml"><br />
<br />
<iq type='error'<br />
from='pubsub.shakespeare.lit'<br />
to='francisco@denmark.lit/barracks'<br />
id='items1'><br />
<pubsub xmlns='http://jabber.org/protocol/pubsub'><br />
<items node='princely_musings'/><br />
</pubsub><br />
<error type='auth'><br />
<not-authorized xmlns='urn:ietf:params:xml:ns:xmpp-stanzas'/><br />
<presence-subscription-required xmlns='http://jabber.org/protocol/pubsub#errors'/><br />
</error><br />
</iq><br />
<br />
</source> <br />
<br />
<br />
<br />
对于访问模式为"roster"的节点, 如果请求实体不在授权名册组中那么pubsub服务必须(MUST)应答一个<not-authorized/>错误, 它也应该(SHOULD)包含一个pubsub-specific错误条件<not-in-roster-group/>.<br />
<br />
<br />
<br />
__案例 75. 实体没有被授权接收条目(不在名册组中)__<br />
<br />
<br />
<br />
<source lang="xml"><br />
<br />
<iq type='error'<br />
from='pubsub.shakespeare.lit'<br />
to='francisco@denmark.lit/barracks'<br />
id='items1'><br />
<pubsub xmlns='http://jabber.org/protocol/pubsub'><br />
<items node='princely_musings'/><br />
</pubsub><br />
<error type='auth'><br />
<not-authorized xmlns='urn:ietf:params:xml:ns:xmpp-stanzas'/><br />
<not-in-roster-group xmlns='http://jabber.org/protocol/pubsub#errors'/><br />
</error><br />
</iq><br />
<br />
</source> <br />
<br />
<br />
<br />
对于访问模式为"whitelist"的节点, 如果请求实体不在白名单中那么服务必须(MUST)返回一个<not-allowed/>错误, 指明一个pubsub-specific错误条件<closed-node/>.<br />
<br />
<br />
<br />
__案例 76. 节点有白名单模式__<br />
<br />
<br />
<br />
<source lang="xml"><br />
<br />
<iq type='error'<br />
from='pubsub.shakespeare.lit'<br />
to='francisco@denmark.lit/barracks'<br />
id='items1'><br />
<pubsub xmlns='http://jabber.org/protocol/pubsub'><br />
<items node='princely_musings'/><br />
</pubsub><br />
<error type='cancel'><br />
<not-allowed xmlns='urn:ietf:params:xml:ns:xmpp-stanzas'/><br />
<closed-node xmlns='http://jabber.org/protocol/pubsub#errors'/><br />
</error><br />
</iq><br />
<br />
</source> <br />
<br />
<br />
<br />
商业开发可能希望把订阅者链接到一个付费客户数据库. 如果订阅者需要付费才能从那个节点接收条目(例如, 如果订阅者不在客户数据库或客户的帐目没有付清), 服务应该(SHOULD)返回一个<payment-required/>错误给订阅者.<br />
<br />
<br />
<br />
__案例 77. 需要付费才能接收条目__<br />
<br />
<br />
<br />
<source lang="xml"><br />
<br />
<iq type='error'<br />
from='pubsub.shakespeare.lit'<br />
to='francisco@denmark.lit/barracks'<br />
id='items1'><br />
<pubsub xmlns='http://jabber.org/protocol/pubsub'><br />
<items node='princely_musings'/><br />
</pubsub><br />
<error type='auth'><br />
<payment-required xmlns='urn:ietf:params:xml:ns:xmpp-stanzas'/><br />
</error><br />
</iq><br />
<br />
</source> <br />
<br />
<br />
<br />
如果请求实体被屏蔽订阅(例如, 因为有一个被排斥者的从属关系), 服务必须(MUST)返回一个<forbidden/>错误给订阅者.<br />
<br />
<br />
<br />
__案例 78. 请求实体被屏蔽__<br />
<br />
<br />
<br />
<source lang="xml"><br />
<br />
<iq type='error'<br />
from='pubsub.shakespeare.lit'<br />
to='francisco@denmark.lit/barracks'<br />
id='items1'><br />
<pubsub xmlns='http://jabber.org/protocol/pubsub'><br />
<items node='princely_musings'/><br />
</pubsub><br />
<error type='auth'><br />
<forbidden xmlns='urn:ietf:params:xml:ns:xmpp-stanzas'/><br />
</error><br />
</iq><br />
<br />
</source> <br />
<br />
<br />
<br />
如果节点不存在, 服务应该(SHOULD)返回一个<item-not-found/>错误给订阅者.<br />
<br />
<br />
<br />
__案例 79. 节点不存在__<br />
<br />
<br />
<br />
<source lang="xml"><br />
<br />
<iq type='error'<br />
from='pubsub.shakespeare.lit'<br />
to='francisco@denmark.lit/barracks'<br />
id='items1'><br />
<pubsub xmlns='http://jabber.org/protocol/pubsub'><br />
<items node='princely_musings'/><br />
</pubsub><br />
<error type='cancel'><br />
<item-not-found xmlns='urn:ietf:params:xml:ns:xmpp-stanzas'/><br />
</error><br />
</iq><br />
<br />
</source> <br />
<br />
<br />
<br />
一个服务可能(MAY)允许实体请求最近的N个条目(使用'max_items'属性). 当 max_items 被使用, 实现应该(SHOULD)返回N个最新的(反之则是N个最旧的)条目. (注意: 一个本协议的未来版本可能建议使用结果集管理Result Set Management \[17\] 替代'max_items'属性.)<br />
<br />
<br />
<br />
__案例 80. 订阅者请求两个最新的条目__<br />
<br />
<br />
<br />
<source lang="xml"><br />
<br />
<iq type='get'<br />
from='francisco@denmark.lit/barracks'<br />
to='pubsub.shakespeare.lit'<br />
id='items2'><br />
<pubsub xmlns='http://jabber.org/protocol/pubsub'><br />
<items node='princely_musings' max_items='2'/><br />
</pubsub><br />
</iq><br />
<br />
</source><br />
<br />
<br />
<br />
__案例 81. 服务返回最新的两个条目__<br />
<br />
<br />
<br />
<source lang="xml"><br />
<br />
<iq type='result'<br />
from='pubsub.shakespeare.lit'<br />
to='francisco@denmark.lit/barracks'<br />
id='items2'><br />
<pubsub xmlns='http://jabber.org/protocol/pubsub'><br />
<items node='princely_musings'><br />
<item id='4e30f35051b7b8b42abe083742187228'><br />
<entry xmlns='http://www.w3.org/2005/Atom'><br />
<title>Alone</title><br />
<summary><br />
Now I am alone.<br />
O, what a rogue and peasant slave am I!<br />
</summary><br />
<link rel='alternate' type='text/html'<br />
href='http://denmark.lit/2003/12/13/atom03'/><br />
<id>tag:denmark.lit,2003:entry-32396</id><br />
<published>2003-12-13T11:09:53Z</published><br />
<updated>2003-12-13T11:09:53Z</updated><br />
</entry><br />
</item><br />
<item id='ae890ac52d0df67ed7cfdf51b644e901'><br />
<entry xmlns='http://www.w3.org/2005/Atom'><br />
<title>Soliloquy</title><br />
<summary><br />
To be, or not to be: that is the question:<br />
Whether 'tis nobler in the mind to suffer<br />
The slings and arrows of outrageous fortune,<br />
Or to take arms against a sea of troubles,<br />
And by opposing end them?<br />
</summary><br />
<link rel='alternate' type='text/html'<br />
href='http://denmark.lit/2003/12/13/atom03'/><br />
<id>tag:denmark.lit,2003:entry-32397</id><br />
<published>2003-12-13T18:30:02Z</published><br />
<updated>2003-12-13T18:30:02Z</updated><br />
</entry><br />
</item><br />
</items><br />
</pubsub><br />
</iq><br />
<br />
</source> <br />
<br />
<br />
<br />
服务可以(MAY)返回事件通知而不是载荷(例如, 为了节省带宽). 如果这样, 客户端为了接收载荷可以(MAY)请求一个指定的条目(使用ItemID). 当一个实体通过ItemID来请求条目, 实现必须(MUST)允许在请求中指定多个条目.<br />
<br />
<br />
<br />
__案例 82. 订阅者通过ItemID请求特定的条目__<br />
<br />
<br />
<br />
<source lang="xml"><br />
<br />
<iq type='get'<br />
from='francisco@denmark.lit/barracks'<br />
to='pubsub.shakespeare.lit'<br />
id='items3'><br />
<pubsub xmlns='http://jabber.org/protocol/pubsub'><br />
<items node='princely_musings'><br />
<item id='368866411b877c30064a5f62b917cffe'/><br />
<item id='4e30f35051b7b8b42abe083742187228'/><br />
</items><br />
</pubsub><br />
</iq><br />
<br />
</source> <br />
<br />
<br />
<br />
__案例 83. 服务发送请求的条目__<br />
<br />
<br />
<br />
<source lang="xml"><br />
<br />
<iq type='result'<br />
from='pubsub.shakespeare.lit'<br />
id='items3'><br />
<pubsub xmlns='http://jabber.org/protocol/pubsub'><br />
<items node='princely_musings'><br />
<item id='368866411b877c30064a5f62b917cffe'><br />
<entry xmlns='http://www.w3.org/2005/Atom'><br />
<title>The Uses of This World</title><br />
<summary><br />
O, that this too too solid flesh would melt<br />
Thaw and resolve itself into a dew!<br />
</summary><br />
<link rel='alternate' type='text/html'<br />
href='http://denmark.lit/2003/12/13/atom03'/><br />
<id>tag:denmark.lit,2003:entry-32396</id><br />
<published>2003-12-12T17:47:23Z</published><br />
<updated>2003-12-12T17:47:23Z</updated><br />
</entry><br />
</item><br />
<item id='4e30f35051b7b8b42abe083742187228'><br />
<entry xmlns='http://www.w3.org/2005/Atom'><br />
<title>Alone</title><br />
<summary><br />
Now I am alone.<br />
O, what a rogue and peasant slave am I!<br />
</summary><br />
<link rel='alternate' type='text/html'<br />
href='http://denmark.lit/2003/12/13/atom03'/><br />
<id>tag:denmark.lit,2003:entry-32396</id><br />
<published>2003-12-13T11:09:53Z</published><br />
<updated>2003-12-13T11:09:53Z</updated><br />
</entry><br />
</item><br />
</items><br />
</pubsub><br />
</iq><br />
<br />
</source> <br />
<br />
<br />
<br />
如果一个订阅项标识符和某个特定的订阅项相关, 服务必须(MUST)要求它, 这样它能基于和这一特定的订阅项相关的订阅选项来生成不同套的条目. 所以实体作出请求的时候必须(MUST)在itmes元素中包含'subid'属性; 如果它没有这样做, 服务必须(MUST)返回一个<not-acceptable/>错误, 指明一个pubsub-specific错误条件<subid-required/>.<br />
<br />
<br />
<br />
__案例 84. 订阅者不带SubID发送请求__<br />
<br />
<br />
<br />
<source lang="xml"><br />
<br />
<iq type='get'<br />
from='francisco@denmark.lit/barracks'<br />
to='pubsub.shakespeare.lit'<br />
id='items5'><br />
<pubsub xmlns='http://jabber.org/protocol/pubsub'><br />
<items node='princely_musings'/><br />
</pubsub><br />
</iq><br />
<br />
</source><br />
<br />
<br />
<br />
__案例 85. 要求SubID__<br />
<br />
<br />
<br />
<source lang="xml"><br />
<br />
<iq type='error'<br />
from='pubsub.shakespeare.lit'<br />
id='items5'><br />
<pubsub xmlns='http://jabber.org/protocol/pubsub'><br />
<items node='princely_musings'/><br />
</pubsub><br />
<error type='modify'><br />
<not-acceptable xmlns='urn:ietf:params:xml:ns:xmpp-stanzas'/><br />
<subid-required xmlns='http://jabber.org/protocol/pubsub#errors'/><br />
</error><br />
</iq><br />
<br />
</source> <br />
<br />
<br />
<br />
__7. 发行者用例__ {anchor:发行者用例}<br />
<br />
<br />
<br />
__7.1 向一个节点发行一个条目__ {anchor:向一个节点发行一个条目}<br />
<br />
<br />
<br />
任何被允许向一个节点发行条目的实体 (也就是说.,一个发行者或一个所有者) 可以通过发送一个包含<publish/>子元素的 IQ-set 给服务来做到这一点; 这个 <publish/> 元素必须( MUST)拥有一个 'node' 属性并且根据这个节点配置可以(MAY)不包含 <item/>元素, 一个 <item/> 元素, 或 (用于批量处理)多个 <item/> 元素.<br />
<br />
<br />
<br />
注意: 为触发一个通知不必要在发行请求中包含载荷或甚至一个 <item/> 元素. 例如, 发行到一个临时的仅用于通知的节点的结果将是一个不包含任何 <item/> 元素的通知 (如本文的Motivating Example章节所示). However, for the sake of convenience we refer to the act of publication as "publishing an item" (rather than, say, "triggering a notification") even though a publication request will not always contain an <item/> element.<br />
<br />
<br />
<br />
Example 86. Publisher publishes an item with an ItemID<br />
<br />
<br />
<source lang="xml"><br />
<iq type='set'<br />
from='hamlet@denmark.lit/blogbot'<br />
to='pubsub.shakespeare.lit'<br />
id='publish1'><br />
<pubsub xmlns='http://jabber.org/protocol/pubsub'><br />
<publish node='princely_musings'><br />
<item id='ae890ac52d0df67ed7cfdf51b644e901'><br />
<entry xmlns='http://www.w3.org/2005/Atom'><br />
<title>Soliloquy</title><br />
<summary><br />
To be, or not to be: that is the question:<br />
Whether 'tis nobler in the mind to suffer<br />
The slings and arrows of outrageous fortune,<br />
Or to take arms against a sea of troubles,<br />
And by opposing end them?<br />
</summary><br />
<link rel='alternate' type='text/html'<br />
href='http://denmark.lit/2003/12/13/atom03'/><br />
<id>tag:denmark.lit,2003:entry-32397</id><br />
<published>2003-12-13T18:30:02Z</published><br />
<updated>2003-12-13T18:30:02Z</updated><br />
</entry><br />
</item><br />
</publish><br />
</pubsub><br />
</iq><br />
</source> <br />
<br />
<br />
<br />
<br />
If the pubsub service can successfully process the request, it MUST inform the publisher of success.<br />
<br />
<br />
<br />
Example 87. Service replies with success<br />
<br />
<source lang="xml"><br />
<br />
<iq type='result'<br />
from='pubsub.shakespeare.lit'<br />
to='hamlet@denmark.lit/blogbot'<br />
id='publish1'/><br />
<br />
If the pubsub service can successfully process the request, it MUST send then one <message/> stanza containing a pubsub event notification to each approved subscriber. Each <message/> stanza generated by a pubsub service SHOULD possess an 'id' attribute with a unique value so that the service can properly track any notification-related errors that may occur (see the Handling Notification-Related Errors section of this document).<br />
Depending on the node configuration, the event notification either will or will not contain the payload, as shown in the following examples.<br />
If the node is configured to include payloads, the subscribers will receive payloads with the event notifications.<br />
Example 88. Subscribers receive event notifications with payloads<br />
<message from='pubsub.shakespeare.lit' to='francisco@denmark.lit' id='foo'><br />
<event xmlns='http://jabber.org/protocol/pubsub#event'><br />
<items node='princely_musings'><br />
<item id='ae890ac52d0df67ed7cfdf51b644e901'><br />
<entry xmlns='http://www.w3.org/2005/Atom'><br />
<title>Soliloquy</title><br />
<summary><br />
To be, or not to be: that is the question:<br />
Whether 'tis nobler in the mind to suffer<br />
The slings and arrows of outrageous fortune,<br />
Or to take arms against a sea of troubles,<br />
And by opposing end them?<br />
</summary><br />
<link rel='alternate' type='text/html'<br />
href='http://denmark.lit/2003/12/13/atom03'/><br />
<id>tag:denmark.lit,2003:entry-32397</id><br />
<published>2003-12-13T18:30:02Z</published><br />
<updated>2003-12-13T18:30:02Z</updated><br />
</entry><br />
</item><br />
</items><br />
</event><br />
</message><br />
<message from='pubsub.shakespeare.lit' to='bernardo@denmark.lit' id='bar'><br />
<event xmlns='http://jabber.org/protocol/pubsub#event'><br />
<items node='princely_musings'><br />
<item id='ae890ac52d0df67ed7cfdf51b644e901'><br />
<entry xmlns='http://www.w3.org/2005/Atom'><br />
<title>Soliloquy</title><br />
<summary><br />
To be, or not to be: that is the question:<br />
Whether 'tis nobler in the mind to suffer<br />
The slings and arrows of outrageous fortune,<br />
Or to take arms against a sea of troubles,<br />
And by opposing end them?<br />
</summary><br />
<link rel='alternate' type='text/html'<br />
href='http://denmark.lit/2003/12/13/atom03'/><br />
<id>tag:denmark.lit,2003:entry-32397</id><br />
<published>2003-12-13T18:30:02Z</published><br />
<updated>2003-12-13T18:30:02Z</updated><br />
</entry><br />
</item><br />
</items><br />
</event><br />
</message><br />
<message from='pubsub.shakespeare.lit' to='horatio@denmark.lit' id='baz'><br />
<event xmlns='http://jabber.org/protocol/pubsub#event'><br />
<items node='princely_musings'><br />
<item id='ae890ac52d0df67ed7cfdf51b644e901'><br />
<entry xmlns='http://www.w3.org/2005/Atom'><br />
<title>Soliloquy</title><br />
<summary><br />
To be, or not to be: that is the question:<br />
Whether 'tis nobler in the mind to suffer<br />
The slings and arrows of outrageous fortune,<br />
Or to take arms against a sea of troubles,<br />
And by opposing end them?<br />
</summary><br />
<link rel='alternate' type='text/html'<br />
href='http://denmark.lit/2003/12/13/atom03'/><br />
<id>tag:denmark.lit,2003:entry-32397</id><br />
<published>2003-12-13T18:30:02Z</published><br />
<updated>2003-12-13T18:30:02Z</updated><br />
</entry><br />
</item><br />
</items><br />
</event><br />
</message><br />
<message from='pubsub.shakespeare.lit' to='marcellus@denmark.lit' id='fez'><br />
<event xmlns='http://jabber.org/protocol/pubsub#event'><br />
<items node='princely_musings'><br />
<item id='ae890ac52d0df67ed7cfdf51b644e901'><br />
<entry xmlns='http://www.w3.org/2005/Atom'><br />
<title>Soliloquy</title><br />
<summary><br />
To be, or not to be: that is the question:<br />
Whether 'tis nobler in the mind to suffer<br />
The slings and arrows of outrageous fortune,<br />
Or to take arms against a sea of troubles,<br />
And by opposing end them?<br />
</summary><br />
<link rel='alternate' type='text/html'<br />
href='http://denmark.lit/2003/12/13/atom03'/><br />
<id>tag:denmark.lit,2003:entry-32397</id><br />
<published>2003-12-13T18:30:02Z</published><br />
<updated>2003-12-13T18:30:02Z</updated><br />
</entry><br />
</item><br />
</items><br />
</event><br />
</message><br />
.<br />
.<br />
.<br />
</source> <br />
<br />
<br />
<br />
<br />
If the node is configured to not include payloads, the subscribers will receive event notifications only. (If payloads are not included, subscribers may request the published item via the protocol defined in the Retrieve Items from a Node section of this document.)<br />
<br />
<br />
<br />
Example 89. Subscribers receive event notifications only<br />
<br />
<br />
<br />
<message from='pubsub.shakespeare.lit' to='francisco@denmark.lit' id='foo'><br />
<event xmlns='http://jabber.org/protocol/pubsub#event'><br />
<items node='princely_musings'><br />
<item id='ae890ac52d0df67ed7cfdf51b644e901'/><br />
</items><br />
</event><br />
</message><br />
<message from='pubsub.shakespeare.lit' to='bernardo@denmark.lit' id='bar'><br />
<event xmlns='http://jabber.org/protocol/pubsub#event'><br />
<items node='princely_musings'><br />
<item id='ae890ac52d0df67ed7cfdf51b644e901'/><br />
</items><br />
</event><br />
</message><br />
<message from='pubsub.shakespeare.lit' to='horatio@denmark.lit' id='baz'><br />
<event xmlns='http://jabber.org/protocol/pubsub#event'><br />
<items node='princely_musings'><br />
<item id='ae890ac52d0df67ed7cfdf51b644e901'/><br />
</items><br />
</event><br />
</message><br />
<message from='pubsub.shakespeare.lit' to='marcellus@denmark.lit' id='fez'><br />
<event xmlns='http://jabber.org/protocol/pubsub#event'><br />
<items node='princely_musings'><br />
<item id='ae890ac52d0df67ed7cfdf51b644e901'/><br />
</items><br />
</event><br />
</message><br />
.<br />
.<br />
.<br />
<br />
<br />
<br />
<br />
<br />
If a single entity is subscribed to a node multiple times, the service SHOULD notate the event notification so that the entity can determine which subscription identifier(s) generated this event. If these notations are included, they MUST use the Stanza Headers and Internet Metadata [18] format and SHOULD be included after the event notification information (i.e., as the last child of the <message/> stanza).<br />
<br />
<br />
<br />
Example 90. Subscriber receives notated event notification<br />
<br />
<br />
<br />
<message from='pubsub.shakespeare.lit' to='francisco@denmark.lit' id='foo'><br />
<event xmlns='http://jabber.org/protocol/pubsub#event'><br />
<items node='princely_musings'><br />
<item id='ae890ac52d0df67ed7cfdf51b644e901'/><br />
</items><br />
</event><br />
<headers xmlns='http://jabber.org/protocol/shim'><br />
<header name='pubsub#subid'>123-abc</header><br />
<header name='pubsub#subid'>004-yyy</header><br />
</headers><br />
</message><br />
<br />
<br />
<br />
<br />
<br />
There are several reasons why the publish request might fail:<br />
<br />
<br />
<br />
1. The requesting entity does not have sufficient privileges to publish.<br />
<br />
2. The node does not support item publication.<br />
<br />
3. The node does not exist.<br />
<br />
4. The payload size exceeds a service-defined limit.<br />
<br />
5. The item contains more than one payload element or the namespace of the root payload element does not match the configured namespace for the node.<br />
<br />
6. The request does not match the node configuration.<br />
<br />
<br />
<br />
These error cases are described more fully below.<br />
<br />
<br />
<br />
Note: If a publisher publishes an item with an Item ID and the ItemID matches that of an existing item, the pubsub service MUST NOT fail the publication but instead MUST overwrite the existing item and generate a new event notification (i.e., re-publication is equivalent to modification).<br />
<br />
<br />
<br />
If the requesting entity does not have sufficient privileges to publish, the service MUST return a <forbidden/> error.<br />
<br />
<br />
<br />
Example 91. Entity does not have sufficient privileges to publish to node<br />
<br />
<br />
<br />
<iq type='error'<br />
from='pubsub.shakespeare.lit'<br />
id='publish1'><br />
<pubsub xmlns='http://jabber.org/protocol/pubsub'><br />
<publish node='princely_musings'><br />
<item id='ae890ac52d0df67ed7cfdf51b644e901'><br />
... PAYLOAD ...<br />
</item><br />
</publish><br />
</pubsub><br />
<error type='auth'><br />
<forbidden xmlns='urn:ietf:params:xml:ns:xmpp-stanzas'/><br />
</error><br />
</iq><br />
<br />
<br />
<br />
<br />
<br />
If the node does not support item publication (because it is a Collection Node), the service MUST return a <feature-not-implemented/> error, specifying a pubsub-specific error condition of <unsupported/> and a feature of "publish".<br />
<br />
<br />
<br />
Example 92. Node does not support item publication<br />
<br />
<br />
<iq type='error'<br />
from='pubsub.shakespeare.lit'<br />
to='hamlet@denmark.lit/elsinore'<br />
id='publish1'><br />
<pubsub xmlns='http://jabber.org/protocol/pubsub'><br />
<publish node='princely_musings'><br />
<item id='ae890ac52d0df67ed7cfdf51b644e901'><br />
... PAYLOAD ...<br />
</item><br />
</publish><br />
</pubsub><br />
<error type='cancel'><br />
<feature-not-implemented xmlns='urn:ietf:params:xml:ns:xmpp-stanzas'/><br />
<unsupported xmlns='http://jabber.org/protocol/pubsub#errors'<br />
feature='publish'/><br />
</error><br />
</iq><br />
<br />
<br />
<br />
<br />
<br />
If the requesting entity attempts to publish an item to a node that does not exist, the service MUST return an <item-not-found/> error.<br />
<br />
<br />
<br />
Example 93. Entity attempts to publish to a non-existent node<br />
<br />
<br />
<br />
<iq type='error'<br />
from='pubsub.shakespeare.lit'<br />
to='hamlet@denmark.lit/elsinore'<br />
id='publish1'><br />
<pubsub xmlns='http://jabber.org/protocol/pubsub'><br />
<publish node='princely_musings'><br />
<item id='ae890ac52d0df67ed7cfdf51b644e901'><br />
... PAYLOAD ...<br />
</item><br />
</publish><br />
</pubsub><br />
<error type='cancel'><br />
<item-not-found xmlns='urn:ietf:params:xml:ns:xmpp-stanzas'/><br />
</error><br />
</iq><br />
<br />
<br />
<br />
<br />
<br />
If the payload size exceeds a service-defined limit, the service MUST return a <not-acceptable/> error, which SHOULD also include a pubsub-specific error condition of <payload-too-big/>.<br />
<br />
<br />
<br />
Example 94. Entity attempts to publish very large payload<br />
<br />
<br />
<br />
<iq type='error'<br />
from='pubsub.shakespeare.lit'<br />
to='hamlet@denmark.lit/elsinore'<br />
id='publish1'><br />
<pubsub xmlns='http://jabber.org/protocol/pubsub'><br />
<publish node='princely_musings'><br />
<item id='ae890ac52d0df67ed7cfdf51b644e901'><br />
... HUGE PAYLOAD ...<br />
</item><br />
</publish><br />
</pubsub><br />
<error type='modify'><br />
<not-acceptable xmlns='urn:ietf:params:xml:ns:xmpp-stanzas'/><br />
<payload-too-big xmlns='http://jabber.org/protocol/pubsub#errors'/><br />
</error><br />
</iq><br />
<br />
<br />
<br />
<br />
<br />
If the <item/> element contains more than one payload element or the namespace of the root payload element does not match the configured namespace for the node, the service MUST bounce the request with a <bad-request/> error, which SHOULD also include a pubsub-specific error condition of <invalid-payload/>.<br />
<br />
<br />
<br />
Example 95. Entity attempts to publish item with multiple payload elements or namespace does not match<br />
<br />
<br />
<br />
<iq type='error'<br />
from='pubsub.shakespeare.lit'<br />
to='hamlet@denmark.lit/elsinore'<br />
id='publish1'><br />
<pubsub xmlns='http://jabber.org/protocol/pubsub'><br />
<publish node='princely_musings'><br />
<item id='ae890ac52d0df67ed7cfdf51b644e901'><br />
... INVALID PAYLOAD ...<br />
</item><br />
</publish><br />
</pubsub><br />
<error type='modify'><br />
<bad-request xmlns='urn:ietf:params:xml:ns:xmpp-stanzas'/><br />
<invalid-payload xmlns='http://jabber.org/protocol/pubsub#errors'/><br />
</error><br />
</iq><br />
<br />
<br />
<br />
<br />
<br />
If the request does not conform to the configured event type for the node, the service MAY bounce the request with a <bad-request/> error, which SHOULD also include a pubsub-specific error condition. The following rules apply:<br />
<br />
<br />
<br />
* If the event type is persistent (either notification or payload) and the publisher does not specify an ItemID, the service MUST generate the ItemID and MUST NOT bounce the publication request.<br />
<br />
* If the event type is persistent (either notification or payload) and the publisher does not include an item, the service MUST bounce the publication request with a <bad-request/> error and a pubsub-specific error condition of <item-required/>.<br />
<br />
* If the event type is payload (either persistent or transient) and the publisher does not include a payload, the service SHOULD bounce the publication request with a <bad-request/> error and a pubsub-specific error condition of <payload-required/>.<br />
<br />
* If the event type is notification + transient and the publisher provides an item, the service MUST bounce the publication request with a <bad-request/> error and a pubsub-specific error condition of <item-forbidden/>.<br />
<br />
<br />
<br />
Examples of these errors are shown below.<br />
<br />
<br />
<br />
Example 96. Publisher attempts to publish to persistent node with no item<br />
<br />
<br />
<br />
<iq type='error'<br />
from='pubsub.shakespeare.lit'<br />
to='hamlet@denmark.lit/elsinore'<br />
id='publish1'><br />
<pubsub xmlns='http://jabber.org/protocol/pubsub'><br />
<publish node='princely_musings'/><br />
</pubsub><br />
<error type='modify'><br />
<bad-request xmlns='urn:ietf:params:xml:ns:xmpp-stanzas'/><br />
<item-required xmlns='http://jabber.org/protocol/pubsub#errors'/><br />
</error><br />
</iq><br />
<br />
<br />
<br />
<br />
<br />
Example 97. Publisher attempts to publish to payload node with no payload<br />
<br />
<br />
<iq type='error'<br />
from='pubsub.shakespeare.lit'<br />
to='hamlet@denmark.lit/elsinore'<br />
id='publish1'><br />
<pubsub xmlns='http://jabber.org/protocol/pubsub'><br />
<publish node='princely_musings'><br />
<item id='ae890ac52d0df67ed7cfdf51b644e901'/><br />
</publish><br />
</pubsub><br />
<error type='modify'><br />
<bad-request xmlns='urn:ietf:params:xml:ns:xmpp-stanzas'/><br />
<payload-required xmlns='http://jabber.org/protocol/pubsub#errors'/><br />
</error><br />
</iq><br />
<br />
<br />
<br />
<br />
<br />
Example 98. Publisher attempts to publish to transient notification node with item<br />
<br />
<iq type='error'<br />
from='pubsub.shakespeare.lit'<br />
to='hamlet@denmark.lit/elsinore'<br />
id='publish1'><br />
<pubsub xmlns='http://jabber.org/protocol/pubsub'><br />
<publish node='princely_musings'><br />
<item id='ae890ac52d0df67ed7cfdf51b644e901'/><br />
</publish><br />
</pubsub><br />
<error type='modify'><br />
<bad-request xmlns='urn:ietf:params:xml:ns:xmpp-stanzas'/><br />
<item-forbidden xmlns='http://jabber.org/protocol/pubsub#errors'/><br />
</error><br />
</iq><br />
<br />
<br />
<br />
<br />
<br />
Finally, in order to facilitate authorization for item removal as described in the Delete an Item from a Node section of this document, implementations that support persistent items SHOULD store the item (if the node is so configured) and maintain a record of the publisher.<br />
<br />
7.2 Delete an Item from a Node<br />
<br />
<br />
<br />
A service SHOULD allow a publisher to delete an item once it has been published to a node that supports persistent items. To delete an item, the publisher sends a retract request as shown in the following examples. The <retract/> element MUST possess a 'node' attribute, MAY possess a 'notify' attribute, and SHOULD contain one <item/> element (but MAY contain more than one <item/> element for Batch Processing of item retractions); the <item/> element MUST be empty and MUST possess an 'id' attribute.<br />
<br />
<br />
<br />
Example 99. Entity deletes an item from a node<br />
<br />
<iq type='set'<br />
from='hamlet@denmark.lit/elsinore'<br />
to='pubsub.shakespeare.lit'<br />
id='retract1'><br />
<pubsub xmlns='http://jabber.org/protocol/pubsub'><br />
<retract node='princely_musings'><br />
<item id='ae890ac52d0df67ed7cfdf51b644e901'/><br />
</retract><br />
</pubsub><br />
</iq><br />
<br />
<br />
<br />
<br />
Example 100. Service replies with success<br />
<br />
<br />
<br />
<iq type='result'<br />
from='pubsub.shakespeare.lit'<br />
to='hamlet@denmark.lit/elsinore'<br />
id='retract1'/><br />
<br />
<br />
<br />
There are several reasons why the item retraction request might fail:<br />
<br />
<br />
<br />
1. The publisher does not have sufficient privileges to delete the requested item.<br />
<br />
2. The node or item does not exist.<br />
<br />
3. The request does not specify a node.<br />
<br />
4. The request does not include an <item/> element or the <item/> element does not specify an ItemID.<br />
<br />
5. The node does not support persistent items.<br />
<br />
6. The service does not support the deletion of items.<br />
<br />
<br />
<br />
These error cases are described more fully below.<br />
<br />
<br />
<br />
If the requesting entity does not have sufficient privileges to delete the item, the service MUST return a <forbidden/> error.<br />
<br />
<br />
<br />
Example 101. Requesting entity does not have sufficient privileges<br />
<br />
<iq type='error'<br />
from='pubsub.shakespeare.lit'<br />
to='hamlet@denmark.lit/elsinore'<br />
id='retract1'><br />
<pubsub xmlns='http://jabber.org/protocol/pubsub'><br />
<retract node='princely_musings'><br />
<item id='ae890ac52d0df67ed7cfdf51b644e901'/><br />
</retract><br />
</pubsub><br />
<error type='auth'><br />
<forbidden xmlns='urn:ietf:params:xml:ns:xmpp-stanzas'/><br />
</error><br />
</iq><br />
<br />
<br />
<br />
<br />
<br />
If the node or item does not exist, the service MUST return an <item-not-found/> error.<br />
<br />
<br />
<br />
Example 102. Non-existent node or item<br />
<br />
<iq type='error'<br />
from='pubsub.shakespeare.lit'<br />
to='hamlet@denmark.lit/elsinore'<br />
id='retract1'><br />
<pubsub xmlns='http://jabber.org/protocol/pubsub'><br />
<retract node='princely_musings'><br />
<item id='ae890ac52d0df67ed7cfdf51b644e901'/><br />
</retract><br />
</pubsub><br />
<error type='cancel'><br />
<item-not-found xmlns='urn:ietf:params:xml:ns:xmpp-stanzas'/><br />
</error><br />
</iq><br />
<br />
<br />
<br />
<br />
<br />
If the request does not specify a node, the service MUST return a <bad-request/> error, which SHOULD also include a pubsub-specific error condition of <node-required/>.<br />
<br />
<br />
<br />
Example 103. Request does not specify a node<br />
<br />
<iq type='error'<br />
from='pubsub.shakespeare.lit'<br />
to='hamlet@denmark.lit/elsinore'<br />
id='retract1'><br />
<pubsub xmlns='http://jabber.org/protocol/pubsub'><br />
<retract/><br />
</pubsub><br />
<error type='modify'><br />
<bad-request xmlns='urn:ietf:params:xml:ns:xmpp-stanzas'/><br />
<node-required xmlns='http://jabber.org/protocol/pubsub#errors'/><br />
</error><br />
</iq><br />
<br />
<br />
<br />
<br />
If the request does not include an <item/> element or the <item/> element does not specify an ItemID, the service MUST return a <bad-request/> error, which SHOULD also include a pubsub-specific error condition of <item-required/>.<br />
<br />
<br />
<br />
Example 104. Request does not specify an item<br />
<br />
<iq type='error'<br />
from='pubsub.shakespeare.lit'<br />
to='hamlet@denmark.lit/elsinore'<br />
id='retract1'><br />
<pubsub xmlns='http://jabber.org/protocol/pubsub'><br />
<retract node='princely_musings'/><br />
</pubsub><br />
<error type='modify'><br />
<bad-request xmlns='urn:ietf:params:xml:ns:xmpp-stanzas'/><br />
<item-required xmlns='http://jabber.org/protocol/pubsub#errors'/><br />
</error><br />
</iq><br />
<br />
<br />
<br />
<br />
<br />
If the node does not support persistent items (e.g., because it is a collection node or a transient node that does not deliver payloads), the service MUST return a <feature-not-implemented/> error, specifying a pubsub-specific error condition of <unsupported/> and a feature of "persistent-items".<br />
<br />
<br />
<br />
Example 105. Node does not support persistent items<br />
<br />
<iq type='error'<br />
from='pubsub.shakespeare.lit'<br />
to='hamlet@denmark.lit/elsinore'<br />
id='retract1'><br />
<pubsub xmlns='http://jabber.org/protocol/pubsub'><br />
<retract node='princely_musings'><br />
<item id='ae890ac52d0df67ed7cfdf51b644e901'/><br />
</retract><br />
</pubsub><br />
<error type='cancel'><br />
<feature-not-implemented xmlns='urn:ietf:params:xml:ns:xmpp-stanzas'/><br />
<unsupported xmlns='http://jabber.org/protocol/pubsub#errors'<br />
feature='persistent-items'/><br />
</error><br />
</iq><br />
<br />
<br />
<br />
<br />
If the service does not support item deletion, it MUST return a <feature-not-implemented/> error, specifying a pubsub-specific error condition of <unsupported/> and a feature of "delete-nodes".<br />
<br />
<br />
<br />
Example 106. Service does not support item deletion<br />
<br />
<iq type='error'<br />
from='pubsub.shakespeare.lit'<br />
to='hamlet@denmark.lit/elsinore'<br />
id='retract1'><br />
<pubsub xmlns='http://jabber.org/protocol/pubsub'><br />
<retract node='princely_musings'><br />
<item id='ae890ac52d0df67ed7cfdf51b644e901'/><br />
</retract><br />
</pubsub><br />
<error type='cancel'><br />
<feature-not-implemented xmlns='urn:ietf:params:xml:ns:xmpp-stanzas'/><br />
<unsupported xmlns='http://jabber.org/protocol/pubsub#errors'<br />
feature='delete-nodes'/><br />
</error><br />
</iq><br />
<br />
<br />
<br />
If none of the foregoing errors occurred, then the service MUST delete the item.<br />
<br />
<br />
<br />
If none of the foregoing errors occurred and the <retract/> element included a 'notify' attribute with a value of "true" or "1" [19], then the service MUST delete the item and MUST send message notifications to all subscribers as shown below. The syntax is identical to publish notifications except that instead of an <item/> element, the notification includes a <retract/> element.<br />
<br />
<br />
<br />
Example 107. Subscribers are notified of deletion<br />
<br />
<message from='pubsub.shakespeare.lit' to='francisco@denmark.lit' id='foo'><br />
<event xmlns='http://jabber.org/protocol/pubsub#event'><br />
<items node='princely_musings'><br />
<retract id='ae890ac52d0df67ed7cfdf51b644e901'/><br />
</items><br />
</event><br />
</message><br />
<message from='pubsub.shakespeare.lit' to='bernardo@denmark.lit' id='bar'><br />
<event xmlns='http://jabber.org/protocol/pubsub#event'><br />
<items node='princely_musings'><br />
<retract id='ae890ac52d0df67ed7cfdf51b644e901'/><br />
</items><br />
</event><br />
</message><br />
.<br />
.<br />
.<br />
<br />
<br />
<br />
<br />
<br />
If a single entity is subscribed to the node multiple times, the service SHOULD notate the notification of item deletion so that the entity can determine which subscription identifier(s) generated this event. As above, if these notations are included, they MUST use the Stanza Headers and Internet Metadata (SHIM) protocol and SHOULD be included after the event notification information (i.e., as the last child of the <message/> stanza).<br />
<br />
<br />
<br />
Example 108. Subscriber receives notated event notification<br />
<br />
<message from='pubsub.shakespeare.lit' to='bernardo@denmark.lit' id='bar'><br />
<event xmlns='http://jabber.org/protocol/pubsub#event'><br />
<items node='princely_musings'><br />
<retract id='ae890ac52d0df67ed7cfdf51b644e901'/><br />
</items><br />
</event><br />
<headers xmlns='http://jabber.org/protocol/shim'><br />
<header name='pubsub#subid'>123-abc</header><br />
<header name='pubsub#subid'>004-yyy</header><br />
</headers><br />
</message><br />
<br />
<br />
<br />
<br />
"<br />
'''文档信息'''<br />
<br />
系列: [[:Category:XMPP扩展|XEP]]<br />
<br />
编号: 0060<br />
<br />
发行者: [[XMPP标准基金会]]<br />
<br />
状态: 草案<br />
<br />
类型: 标准跟踪<br />
<br />
版本: 1.9<br />
<br />
最后更新日期: 2006-09-13<br />
<br />
批准机构: [[XMPP理事会]]<br />
<br />
依赖于: [[RFC3920|XMPP Core]], XEP-0004, XEP-0030, XEP-0068, XEP-0082, XEP-0131<br />
<br />
上文: 无<br />
<br />
下文: 无<br />
<br />
简称: pubsub<br />
<br />
pubsub 名字空间的XML方案: <http://www.xmpp.org/schemas/pubsub.xsd><br />
<br />
pubsub#errors 名字空间的XML方案: <http://www.xmpp.org/schemas/pubsub-errors.xsd><br />
<br />
pubsub#event 名字空间的XML方案: <http://www.xmpp.org/schemas/pubsub-event.xsd><br />
<br />
pubsub#owner 名字空间的XML方案: <http://www.xmpp.org/schemas/pubsub-owner.xsd><br />
<br />
Wiki 页: <http://wiki.jabber.org/index.php/Publish-Subscribe%20(XEP-0060)><br />
<br />
'''作者信息'''<br />
<br />
'''Peter Millard'''<br />
<br />
见[http://www.xmpp.org/extensions/xep-0060.html#authornote 作者介绍]<br />
<br />
'''Peter Saint-Andre'''<br />
<br />
:Email: [mailto:stpeter@jabber.org stpeter@jabber.org]<br />
<br />
:JID: [xmpp:stpeter@jabber.org stpeter@jabber.org]<br />
<br />
'''Ralph Meijer'''<br />
<br />
:Email: [mailto:ralphm@ik.nu ralphm@ik.nu]<br />
<br />
:JID: [xmpp:ralphm@ik.nu ralphm@ik.nu]</div>
Snowqiang
http://wiki.jabbercn.org/RFC3920
RFC3920
2011-05-19T04:30:15Z
<p>Snowqiang: </p>
<hr />
<div>[[Category:XMPP正式RFC标准]]<br />
[[Category:已翻译]]<br />
<br />
"本文的英文原文来自[http://www.ietf.org/rfc/rfc3920.txt RFC 3920]<br />
<br />
{|<br />
|网络工作组 || P. Saint-Andre, Ed.<br />
|-<br />
|申请讨论: 3920 || Jabber软件基金会<br />
|-<br />
|类别: 标准跟踪 || 2004年10月<br />
|}<br />
<br />
<br />
<br />
:::'''可扩展的消息和出席信息协议 (XMPP): 核心协议'''<br />
<br />
'''关于本文的说明'''<br />
<br />
:本文为互联网社区定义了一个互联网标准跟踪协议,并且申请讨论协议和提出了改进的建议。请参照“互联网官方协议标准”的最新版本(STD 1)获得这个协议的标准化进程和状态。本文可以不受限制的分发。<br />
<br />
'''版权声明'''<br />
<br />
:本文版权属于互联网社区 (C) The Internet Society (2004).<br />
<br />
'''摘要'''<br />
<br />
:本文定义了可扩展消息和出席信息协议(XMPP)的核心功能,这个协议采用XML流实现在任意两个网络终端接近实时的交换结构化信息。XMPP提供一个通用的可扩展的框架来交换XML数据,它主要用来建立即时消息和出席信息应用以实现 RFC 2779 的需求。 <br />
<br />
==绪论==<br />
<br />
===概览===<br />
<br />
:XMPP是一个开放式的XML协议,设计用于准实时消息和出席信息以及请求-响应服务。其基本的语法和语义最初主要是由Jabber开放源代码社区于1999年开发的。2002年,XMPP工作组被授权接手开发和改编Jabber协议以适应IETF的即时消息和出席信息技术。作为XMPP工作组的成果,本文定义了 XMPP 1.0 的核心功能;在 RFC 2779 [IMP-REQS] 中指定的提供即时消息和出席信息功能的扩展,定义在 XMPP-IM 协议 [the Extensible Messaging and Presence Protocol (XMPP): Instant Messaging and Presence] 中。<br />
<br />
===术语===<br />
<br />
:本文中大写的关键字 "MUST(必须)", "MUST NOT(不能)", "REQUIRED(必需)", "SHALL(将会)", "SHALL NOT(将不会)", "SHOULD(应该)", "SHOULD NOT(不应该)", "RECOMMENDED(建议)", "MAY(可以)", 和 "OPTIONAL(可选)" 的确切含义符合 BCP 14, RFC 2119 [TERMS].<br />
<br />
==通用的架构==<br />
<br />
===概览===<br />
<br />
:尽管XMPP没有指定任何特定的网络结构,但它通常是采用客户-服务器 架构进行实现,其中客户端通过TCP方式使用XMPP访问服务器,服务器之间也采用TCP方式进行通信。<br />
<br />
:以下是这一架构的抽象的示意图 (这里 "-" 表示使用 XMPP 通讯, "=" 表示可使用任何协议通讯)。<br />
<br />
<br />
C1----S1---S2---C3<br />
|<br />
C2----+--G1===FN1===FC1<br />
<br />
<br />
:符号的含义如下:<br />
<br />
::* C1, C2, C3 = XMPP 客户端<br />
<br />
::* S1, S2 = XMPP 服务器<br />
<br />
::* G1 = 一个XMPP和外部(非XMPP)消息网络之间进行“翻译”的网关<br />
<br />
::* FN1 = 一个外部消息网络<br />
<br />
::* FC1 = 外部消息网络上的一个客户端<br />
<br />
===服务器===<br />
<br />
:服务器充当XMPP通信的一个智能抽象层,它主要负责:<br />
<br />
:* 对受验证的客户端,服务器以及其他实体之间以XML流形式的连接和会话进行管理。<br />
<br />
:* 在这些实体间使用XML流对合理编址的XML节(第九章)进行路由<br />
<br />
:大部分 XMPP 兼容的服务器也负责存储客户端使用的数据 (比如基于XMPP协议的及时消息应用中的联系人名单); 在这种情况下, XML 数据直接服务器来处理,而不需要转发到其他实体。<br />
<br />
===客户端===<br />
<br />
:大部分客户端通过 TCP 连接直接连到服务器,并通过XMPP获得由服务器以及联合服务器所提供的全部功能。多个不同资源(比如不同的设备和地点)的客户端'''可以'''同时登陆并且并发的连接到一个服务器,每个不同资源的客户端通过XMPP地址的资源标识符来区分(比如<node@domain/ home> 和 <node@domain/work>),参见地址空间(第三章)。'''建议'''的客户端和服务器连接的端口是 5222 ,这个端口已经在 IANA(在第十五章第九节查阅端口号码) 注册了。<br />
<br />
===网关===<br />
<br />
:网关是一个特殊用途的服务器端的服务,主要功能是把 XMPP 翻译成外部(非XMPP)消息系统,并把返回的消息翻译成 XMPP 。例如到 email(参见 [SMTP] ),IRC(参见 [IRC] ),SIMPLE(参见 [SIMPLE] ),SMS 的网关;还有和别的消息服务的网关,比如AIM,ICQ,MSN Messenger,Yahoo! Instant Messenger。网关和服务器之间的通信,网关和外部消息系统的通信,不在本文描述范围之内。<br />
<br />
===网络===<br />
<br />
:因为每个服务器都是由一个网络地址来标识的并且服务器之间的通信是 客户-服务器 协议的直接扩展,实际上整个系统是由很多互通的服务器构成的。例如,<juliet@example.com> 可以和 <romeo@example.net> 交换消息,出席信息和其他信息。这种模式常见于那些需要使网络地址标准化的协议(比如 SMTP )。任意两个服务器之间的通信是可选(OPTIONAL)的。如果被激活,那么这种通信应该(SHOULD)通过 XML 流绑定到 TCP 连接上进行。建议的(RECOMMENDED)服务器之间的连接端口为 5269 ,这个端口号已经在 IANA (在第十五章第九节查阅端口号码)注册了。<br />
<br />
==地址空间==<br />
<br />
===概览===<br />
<br />
:一个实体可以是任何一个被认为是一个网络端点的东西(例如网络上的一个 ID ),而且它是通过XMPP进行通信的。所有这些实体都有一个具有唯一性的地址,并符合 RFC 2396 [URI]规范要求的格式。由于历史原因,一个 XMPP 实体的地址被称为 Jabber Identifier 或 JID 。一个合法的 JID 包括一组排列好的元素,包括域名(domain identifier),节点名(node identifier),和资源名(resource identifier)。<br />
<br />
:JID的语法定义,使用 [ABNF] 中的 Augmented Backus-Naur 格式。(IPv4 地址和 IPv6地址规则在 附录B 中的 [IPv6] 中定义;确定节点规则的合法字符顺序由 附录A 的 [STRINGPREP] 的 Nodeprep 部分来定义;确定资源规则的合法字符顺序由 附录B 的 [STRINGPREP] 的Resourceprep 部分来定义;子域名规则参考 [IDNA] 中关于国际域名标签的描述。)。<br />
<br />
::jid = [ node "@" ] domain [ "/" resource ]<br />
<br />
::domain = fqdn / address-literal<br />
<br />
::fqdn = (sub-domain 1*("." sub-domain))<br />
<br />
::sub-domain = (internationalized domain label)<br />
<br />
::address-literal = IPv4address / IPv6address<br />
<br />
:所有 JID 都是基于上述的结构。类似 <user@host/resource> 这种结构,最常用来标识一个即时消息用户,这个用户所连接的服务器,以及这个用户用于连接的资源(比如特定类型的客户端软件)。不过,节点类型不是客户端也是有可能的,比如一个用来提供多用户聊天服务的特定的聊天室,地址可以是 <room@service> (这里 “room“ 是聊天室的名字而 ”service“ 是多用户聊天服务的主机名),而加入了这个聊天室的某个特定的用户的地址则是 <room@service/nick> (这里 ”nick“ 是用户在聊天室的昵称)。许多其他的 JID 类型都是可能的(例如 <domain/resource> 可能是一个服务器端的脚本或服务)。<br />
<br />
:一个 JID 的每个合法部分(节点名,域名,资源名)的长度不能(MUST NOT)超过 1023 字节。也就是整体长度(包括 '@' 和 '/' )不能超过 3071 字节。<br />
<br />
===域名===<br />
<br />
:域名是一个主要的ID并且是 JID 中唯一必需(REQUIRED)的元素(一个纯粹的域名也是一个合法的 JID)。它通常代表网络的网关或者“主”服务器,其他实体通过连接它来实现 XML 转发和数据管理功能。然而,由一个域名标识引用的实体,并非总是一个服务器,它也可能是一个服务器的子域地址,提供额外的功能(比如多用户聊天服务,用户目录,或一个到外部消息系统的网关)。<br />
<br />
:每个服务器或者服务的域名,可以(MAY)是一个 IP 地址,但应该(SHOULD)是一个完全合法的域名(参见 [DNS]).一个域名ID必须(MUST)是 [IANA] 里定义的“国际化域名”,并且按 [STRINGPREP]中的 [NAMEPREP] profile进行成功的字符转换。在比较两个域名ID之前,服务器必须(MUST),客户端应该(SHOULD)首先按照Nameprep profile(定义在[IANA]中) 来转换每个域名的字符。<br />
<br />
===节点名===<br />
<br />
:节点名是一个可选(OPTIONAL)的第二 ID,放在域名之前并用符号"@"分开.它通常表示一个向服务器或网关请求和使用网络服务的实体(比如一个客户端),当然它也能够表示其他的实体(比如在多用户聊天系统中的一个房间). 节点名所代表的实体,它的地址依赖于一个特定的域名;在 XMPP 的即时消息和出席信息应用系统中,这个地址是“纯 JID” <node@domain> 中的一部分。<br />
<br />
:一个节点名必须按 [STRINGPREP] 中的 Nodeprep profile 进行成功的字符转换。在比较两个节点ID之前,服务器必须(MUST),客户端应该(SHOULD)首先按 Nodeprep profile 转换每个ID的字符。<br />
<br />
===资源名===<br />
<br />
:资源名是一个可选的第三 ID,它放在域名的后面并由符号"/"分开。资源名可以跟在 <node@domain>后面也可以跟在 <domain> 后面。它通常表示一个特定的会话,连接(比如设备或者所在位置),或者一个附属于某个节点ID实体相关实体的对象(比如多用户聊天室中的一个参加者)。对于服务器和和其他客户端来说,资源名是不透明的。当它提供必需的信息以完成资源绑定(参见第七章)的时候,通常是由客户端来实现的(尽管可以由客户端向服务器请求完成),然后显示为“已连接的资源”。一个实体可以(MAY)并发维护多个已连接的资源。每个已连接的资源由不同的资源ID来区分。<br />
<br />
:一个资源名必须(MUST)按 [STRINGPREP] 中的 Resourceprep profile 进行成功的格式化。在比较两个资源ID之前,服务器必须(MUST),客户端应该(SHOULD)首先按 Resourceprep profile 转换每个ID的字符。<br />
<br />
===地址的确认===<br />
<br />
:在 SASL (见第六章)握手之后(如果必要的话,也在资源绑定(见第七章)之后),正在接收流信息的实体必须(MUST)确认初始实体的 ID 。<br />
<br />
:对于服务器间的通信,在 SASL 握手时,如果没有指明授权的ID,这个初始的实体应该(SHOULD)是经过认证实体(参见 简单认证和安全层协议 [SASL] 中的定义)授权的ID(见第六章)。<br />
<br />
:对于客户端和服务器的通信,在 SASL 握手时,如果没有指明授权的ID,“纯 JID” (<node@domain>)应该(SHOULD)是经过认证实体(参见 [SASL] 中的定义)授权的ID,“全 JID” (<node@domain/resource>)的资源ID部分应该(SHOULD)是由客户端和服务器在资源绑定的时候商定的(参见第七章)。<br />
<br />
:接收的实体必须(MUST)确保结果JID(包括节点名,域名,资源名以及分隔符)与本章前面部分描述的规则和格式相一致;为了满足这些约束条件,接收实体可能(MAY)需要把初始实体的发送方 JID 替换成接收实体认可的规范 JID。<br />
<br />
==XML流==<br />
<br />
===概览===<br />
<br />
:两个基本概念,XML流和XML节,使得在出席信息已知的实体之间,异步交换低负载的结构化信息成为可能。这两个术语定义如下:<br />
<br />
:XML流的定义:一个XML流是一个容器,包含了两个实体之间通过网络交换的XML元素。一个XML流是由一个XML打开标签 <stream> (包含适当的属性和名字空间声明)开始的,流的结尾则是一个XML关闭L标签 </stream> 。在流的整个生命周期,初始化它的实体可以通过流发送大量的XML元素,用于流的握手(例如 TLS 握手(第五章) 或 SASL 握手(第六章))或XML节(在这里指符合缺省名字空间的元素,包括<message/>,<presence/>, 或 <iq/> 元素)。“初始的流”由初始化实体(通常是一个客户端或服务器)和接收实体(通常是一个服务器)握手,从接收实体来看,它就是那个初始实体的"会话".初始化流允许从初始化实体到接收实体的单向通信;为了使接收实体能够和初始实体交换信息,接收实体必须发起一个反向的握手(应答流).<br />
<br />
:XML节的定义: 一个XML节是一个实体通过 XML 流向另一个实体发送的结构化信息中的一个离散的语义单位。一个XML节直接存在于根元素<stream/>的下一级,这样可以说是很好的匹配了[XML](译者注:在标准参考一节)的第43条.任何XML节都是从一个XML流的下一级的某个打开标签(如 <presence>)开始,到相应的关闭标签(如 </presence>)。一个XML节可以(MAY)包含子元素(相关的属性,元素, 和 XML 字符数据等) 以表达完整的信息.在这里定义的XML节仅限于<message/>, <presence/>, 和 <iq/> 元素,具体描述间见 XML Stanzas(第九章);为TLS握手(第五章)、SASL握手(第六章)、服务器回拨(第八章)的需要而发送的XML元素,不被认为是一个XML节。<br />
<br />
:设想一个客户端和服务器会话的例子。为了连接一个服务器,一个客户端必须(MUST)发送一个打开标签<stream>给服务器,初始化一个XML流,也可选择(OPTIONAL)在这之前发送一段文本声明XML版本和支持的字符集(参见文本声明的内容(第十一章第四节); 也可看字符编码(第十一章第五节))。视本地化策略和提供的服务而定,服务器应该(SHOULD)回复一个XML流给客户端,同样的,也可选择在这之前发送一段文本声明。一旦客户端完成了SASL握手(第六章),客户端可以(MAY)通过流发送不限量的XML节给网络中的任何接收者。当客户端想关闭这个流,它只需要简单的发送一个关闭标签</stream>给服务器(或者作为另一个选择,可能由服务器关闭这个流)。然后,客户端和服务器都应该(SHOULD)彻底地终止这个连接(通常是一个TCP连接)。<br />
<br />
:那些习惯认为XML是一个以文本为中心风格的人可能希望看看一个与服务器连接的客户端会话,包含两个 打开-关闭 XML文档:一个是从客户端到服务器,一个是从服务器到客户端。下图中,根元素<stream/> 可以被认为是每个“文档”的文档实体,这两个“文档”通过累积那些在XML上传输的XML节来搭建的。无论如何,下图只是方便理解;实际上XMPP并不处理文档而是处理XML流和XML节。<br />
<br />
:基本上,一个XML流相当于一个会话期间所有XML节的一个信封。我们可以简单的把它描述成下图:<br />
<br />
|--------------------|<br />
| <stream> |<br />
|--------------------|<br />
| <presence> |<br />
| <show/> |<br />
| </presence> |<br />
|--------------------|<br />
| <message to='foo'> |<br />
| <body/> |<br />
| </message> |<br />
|--------------------|<br />
| <iq to='bar'> |<br />
| <query/> |<br />
| </iq> |<br />
|--------------------|<br />
| ... |<br />
|--------------------|<br />
| </stream> |<br />
|--------------------|<br />
<br />
===绑定到TCP===<br />
<br />
:虽然有很多非必需的连接使用XML流来绑定[TCP]连接(两个实体可以通过别的机制来互联,比如通过[HTPP]连接轮询),本规范只定义了 XMPP 到 TCP 的绑定。在客户和服务器通信的过程中,服务器必须(MUST)允许客户端共享一个TCP连接来传输XML节,包括从客户端传到服务器和从服务器传到客户端。在服务器之间的通信过程中,服务器必须(MUST)用一个 TCP连接 向对方发送 XML节,另一个 TCP连接(由对方初始化)接收对方的XML节,一共两个 TCP连接。<br />
<br />
===流的安全===<br />
<br />
:在XMPP 1.0中,当XML流开始握手时,TLS应该(SHOULD)按 第五章:TLS的使用 中的规定来使用,SASL必须(MUST)按 第六章:SASL的使用 中的规定来使用。尽管可能(MAY)存在某种共有的机制能够保证双向安全,但是“初始化流”(比如从初始化实体发给接收实体的流)和“应答流”(比如从接收实体发给初始化实体的流)还是必须(MUST)安全的分开。在流被验证之间,实体不应该(SHOULD NOT) 尝试通过流发送XML节(第九章);就算它这样做了,对方的实体也不能(MUST NOT)接受这些XML节,并且应该(SHOULD)返回一个 <not-authorized/> 的流错误信息并且终止当前TCP连接上双方的XML流;注意,这仅仅是针对XML节(包含在缺省命名空间中的 <message/>, <presence/>, 和 <iq/> 元素),而不是指那些用于 TLS握手(第五章)、SASL握手(第六章)握手的流。<br />
<br />
===stream 属性===<br />
<br />
:stream 元素的属性如下:<br />
<br />
:* to -- 'to' 属性应(SHOULD)仅出现在初始化实体发给接收实体的 XML 流的头当中,并且它的值必须(MUST)是接收实体所在的主机名。在接收实体发送给初始化实体的 XML 流的头中不应该(SHOULD NOT)出现 'to' 属性。若 'to' 属性出现在应答流中,则初始化实体应(SHOULD)忽略它。<br />
<br />
:* from -- 'from' 属性应(SHOULD)仅出现在接收实体发给初始化实体的 XML 流的头当中,并且它的值必须(MUST)是为当前初始化实体授权的接收实体所在的主机名。注意,不应该(SHOULD NOT)有 'from'属性出现在初始实体发送给接收实体的 XML流的头中;无论如何,如果'from'属性出现在初始化流中,接收实体应该(SHOULD)忽略它。<br />
<br />
:* id -- 'id'属性应该(SHOULD)仅用于接收实体发送给初始化实体 XML流的头。这个属性是一个由接收实体创建的具有唯一性的ID,一个初始实体和接收实体之间的会话ID,并且它在接收方的应用程序中(通常是一个服务器)必须(MUST)是唯一的。注意,这个流 ID 必须是足够安全的,所以它必须是不可预知的和不可重复的(参见[RANDOM] 了解如何获得随机性以保证安全性)。不应该(SHOULD NOT)有 'id'属性出现在初始实体发送给接收实体的 XML流的头中;无论如何,如果'id'属性出现在初始化流中,接收实体应该(SHOULD)忽略它。<br />
<br />
:* xml:lang -- 'xml:lang'属性(定义在[XML]中的第二章第十二节)应该(SHOULD)包含在初始化实体发给接收实体的 XML流的头中,以指定在流中传输的可读XML字符所使用的缺省语言。如果这个属性出现了,接收实体应该(SHOULD)记住它的值,作为初始化流和应答流的缺省属性;如果这个属性没有出现,接收实体应该(SHOULD)用一个可配置的缺省值用于双方的流,这个属性值必须(MUST)在应答流的头中传达。对于所有初始化流中传输的节,如果初始实体没有提供'xml:lang'属性,接收实体应该(SHOULD)应用缺省值;如果初始实体提供了'xml:lang'属性,接收实体不能(MUST NOT)修改或删除它(参见第九章第一节第五小节 xml:lang)。'xml:lang'属性的值必须(MUST)是一个 NMTOKEN (定义在[XML]的第二章第三节) 并且必须(MUST)遵守 RFC 3066 [LANGTAGS] 规定的格式。<br />
<br />
:* version -- version属性(最少需要"1.0")为本规范中和流相关的协议提供了支持。关于这个属性的生成和处理的详细规则将在下文中定义。<br />
<br />
:我们现在可以总结如下:<br />
<br />
{|border="1" cellspacing="0" <br />
! !! 初始化方发给接收方 !! 接收方发给初始化方<br />
|-<br />
|to || 接收方的主机名 || 忽略<br />
|-<br />
|from || 忽略 || 接收方的主机名<br />
|-<br />
|id || 忽略 || 会话键值<br />
|-<br />
|xml:lang || 缺省语言 || 缺省语言<br />
|-<br />
|version || 支持XMPP 1.0 || 支持XMPP 1.0<br />
|}<br />
<br />
====版本支持====<br />
<br />
:在这里XMPP的版本是"1.0";准确地说,这里囊括了和流相关的所有协议(TLS的使用 (第五章),SASL的使用(第六章), 和流错误(第四章第七节)),以及三个定义好的XML节类型(<message/>,<presence/>,和 <iq/>)。XMPP版本号的编号顺序是“<主版本号>.<副版本号>”。主版本和副版本号必须(MUST)是独立的整数并且每个号码可以(MAY)单独以阿拉伯数字增长。这样,"XMPP 2.4"的版本将比"XMPP 2.13"更低。号码前面 的“0”(比如XMPP 6.01)必须(MUST)被接收方忽略并且不能(MUST NOT)被发送出去.<br />
<br />
:如果流和节的格式或者必需的处理方式有了显著的改变,以至于老版本的实体如果只是简单的忽略它不理解的节和属性并且继续像老版本一样的处理方式,会使得老版本的实体不能够和新版本的实体交互,只有在这时候主版本号才应该(SHOULD)增加。副版本号显示新的性能,它必须(MUST)被副版本号更低的实体忽略,但被高(副)版本号的实体用于了解信息。例如,一个副版本号显示处理某种新定义的"type"属性的值(用于message,presence或IQ节)的能力;副版本号高的实体将会了解到与之通信的对方不能够理解这个"type"属性的值,所以将不会发送它。<br />
<br />
:以下规则是用于'版本'属性在实现流的头信息时如何生成和处理:<br />
<br />
:# 初始化实体必须(MUST)在初始化流的头信息中把'版本'的值设置成它所支持的最高版本。(比如,如果最高版本支持就是本规范,那么它必须(MUST)设置成"1.0").<br />
:# 接收实体必须(MUST)在应答流的头信息中把'版本'的值设置成初始化实体所提供的版本或它所支持的最高版本,取其中版本号较低的那一个。接收实体必须(MUST)把主版本号和副版本号作为数字来比较,而不是对"主版本号.副版本号"这个字符串进行比较.<br />
:# 如果在应答流的头信息的版本号中至少有一个主版本号低于初始化流的头信息的版本号,并且如前所述,新版本的实体不能够和旧版本实体交互,初始化实体应该(SHUOULD)生成一个<unsupported-version/>的流错误信息并终止XML流和它的TCP连接。<br />
:# 如果一个实体收到一个头信息中没有'version'属性的流,这个实体必须(MUST)把对方实体的'version'当成'0.0'并且在它发送的应答流的头中也不应该(SHOULD NOT)包含'version'属性.<br />
<br />
===名字空间声明===<br />
<br />
:流的元素必须(MUST)同时满足一个流名字空间声明和一个缺省名字空间声明("名字空间声明"定义在 XML 名字空间定义 [XML-NAMES]中).关于流名字空间和缺省名字空间的详细信息,参考 名字空间的名字和前缀(第十一章第二节).<br />
<br />
===流的特性===<br />
<br />
:如果初始化的实体在初始化流的头信息中设置'version'属性的信息为"1.0",接收实体必须(MUST)向初始化实体发送一个 <features/> 子元素以声明任何可供协商的流一级的特性(或者其他需要声明的能力).目前,这仅用于声明本文中定义的 TLS的使用(第五章),SASL的使用(第六章)和资源绑定(第七章),以及 [XMPP-IM|XMPP文档列表/XMPP正式RFC标准/RFC3921] 中定义的会话的建立;无论如何,流特性这一功能将来可以用于声明任何可协商的特性.如果一个实体不理解或支持安全特性,它应该(SHOULD)忽略它.如果要在一个非安全相关的特性(比如资源绑定)被提议之前,完成一个或多个安全特性(比如TLS和SASL)的协商,这个非安全相关的特性不应该(SHOULD NOT)在相应的安全特性协商完毕之前被声明.<br />
<br />
===流错误===<br />
<br />
:流的根元素可以(MAY)包含一个 <error/> 子元素,由流的名字空间前缀作为它的前缀。这个"错误"子元素必须(MUST)由感知到发生了流级别错误的实体发送(通常是一个服务器而不是一个客户端)。<br />
<br />
====规则====<br />
<br />
:以下规则适用于流级别的错误:<br />
<br />
:* 它假定所有流级别的错误都是不可恢复的;所以,如果一个错误发生在流级别,发现这个错误的实体必须(MUST)发送一个流错误信息给另一个实体,发送一个关闭标签 </stream>,并终止这个流所在的TCP连接。<br />
<br />
:* 如果这个错误发生在流刚开始设置的时候,接收实体必须(MUST)仍然发送一个开放标签 <stream> ,并在流元素中包含一个<error/>的子元素,然后发送一个关闭标签 </stream>,最后终止相应的TCP连接。在这种情况下,如果初始化实体在 'to' 属性中提供了一个未知的主机名,服务器应该(SHOULD)在终止之前,先在流的头信息的 'from' 属性中提供一个服务器认证的主机名.<br />
<br />
====语法====<br />
<br />
:流错误的语法如下:<br />
<br />
<source lang="xml"><br />
<stream:error><br />
<defined-condition xmlns='urn:ietf:params:xml:ns:xmpp-streams'/><br />
<text xmlns='urn:ietf:params:xml:ns:xmpp-streams' xml:lang='langcode'><br />
OPTIONAL descriptive text<br />
</text><br />
[OPTIONAL application-specific condition element]<br />
</stream:error><br />
</source><br />
<br />
:<error/>元素:<br />
:* 必须(MUST)包含一个子元素以描述一个下文定义的节错误条件;这个子元素必须(MUST)符合'urn:ietf:params:xml:ns:xmpp-streams'名字空间.<br />
<br />
:* 可以(MAY)包含一个 <text/> 子元素,用XML字符数据描述错误的细节;这个元素必须(MUST)符合'urn:ietf:params:xml:ns:xmpp-streams'名字空间并且应该(SHOULD)拥有一个'xml:lang'属性表明XML字符数据的自然语言。<br />
<br />
:* 可以(MAY)包含一个子元素用于描述一个明确的应用程序错误条件;这个元素必须(MUST)符合一个应用程序定义的名字空间,并且它的结构是由那个名字空间定义的。<br />
<br />
: <text/> 元素是可选的(OPTIONAL)。如果有这个元素,它应该(SHOULD)仅用于提供描述或调试信息以补充一个已定义的条件或应用程序定义的条件。它不应该(SHOULD NOT)被一个应用程序当成一个可编程的信息。它不应该(SHOULD NOT)被用于向用户表达错误信息,但是可以(MAY)作为和条件元素相关的错误信息之外的附加说明。<br />
<br />
====已定义的条件====<br />
<br />
:以下流级别的错误条件是已定义的:<br />
<br />
:* <bad-format/> -- 实体已经发送XML但是不能被处理;这个错误可以(可以)被更多特定的XML相关的错误替换,比如 <bad-namespace-prefix/>, <invalid-xml/>, <restricted-xml/>, <unsupported-encoding/>, 以及 <xml-not-well-formed/>,尽管更多特定的错误是首选的。 <br />
<br />
:* <bad-namespace-prefix/> -- 实体发送的名字空间前缀不被支持,或者在一个需要某种前缀的元素中没有发送一个名字空间前缀(参见 XML Namespace Names and Prefixes (第十一章第二节)).<br />
<br />
:* <conflict/> -- 服务器正在关闭为这个实体激活的流,因为一个和已经存在的流有冲突的新的流已经被初始化。<br />
<br />
:* <connection-timeout/> -- 实体已经很长时间没有通过这个流发生任何通信流量(可由一个本地服务策略来配置).<br />
<br />
:* <host-gone/> -- 初始化实体在流的头信息中提供的'to'属性的值所指定的主机已经不再由这台服务器提供<br />
<br />
:* <host-unknown/> -- 由初始化实体在流的头信息中提供的 'to' 属性的值和由服务器提供的主机名不一致.<br />
<br />
:* <improper-addressing/> -- 一个在两台服务器之间传送的节缺少 'to' 或 'from' 属性(或者这个属性没有值).<br />
<br />
:* <internal-server-error/> -- 服务器配置错误或者其他未定义的内部错误,使得服务器无法提供流服务.<br />
<br />
:* <invalid-from/> -- 在'from'属性中提供的 JID 或 主机名地址,和认证的 JID不匹配 或服务器之间无法通过SASL(或回拨)协商出合法的域名,或客户端和服务器之间无法通过它进行认证和资源绑定。<br />
<br />
:* <invalid-id/> -- 流 ID 或回拨 ID 是非法的或和以前提供的 ID 不一致.<br />
<br />
:* <invalid-namespace/> -- 流名字空间和 "http://etherx.jabber.org/streams" 不相同或回拨名字空间和 "jabber:server:dialback" 不相同.(参考 XML Namespace Names and Prefixes (第十一章第二节)).<br />
<br />
:* <invalid-xml/> -- 实体通过流发送了一个非法的XML给执行验证的服务器 (参考 Validation (第十一章第三节)).<br />
<br />
:* <not-authorized/> -- 实体试图在流被验证之前发送数据或不被许可执行一个和流协商有关的动作,接收实体在发送错误信息之前不允许(MUST NOT)处理厌恶的节。<br />
<br />
:* <policy-violation/> -- 实体违反了某些本地服务策略;服务器可以(MAY)选择在 <text/> 元素或应用程序定义的错误条件(元素)中详细说明策略。<br />
<br />
:* <remote-connection-failed/> -- 服务器无法正确连接到用于验证或授权的远程实体。<br />
<br />
:* <resource-constraint/> -- 服务器缺乏必要的系统资源为流服务。<br />
<br />
:* <restricted-xml/> -- 实体试图发送受限的XML特性,比如一个注释,处理指示,DTD,实体参考,或保留的字符(参考 Restrictions (第十一章第一节)).<br />
<br />
:* <see-other-host/> -- 服务器将不提供服务给初始化实体但是把它重定向到另一台主机;服务器应该(SHOULD)在<see-other-host/>元素的XML字符数据中指明替代服务器名或IP地址(它必须(必须)是合法的域名标识)。<br />
<br />
:* <system-shutdown/> -- 服务器正在关机并且所有激活的流正在被关闭。<br />
<br />
:* <undefined-condition/> -- 错误条件不在本文已定义的错误条件列表之中;这个错误条件应该(SHOULD)仅用于"应用程序定义条件"元素.<br />
<br />
:* <unsupported-encoding/> -- 初始化实体以一个服务器不不支持的编码方式编码了一个流(参照Character Encoding (第十一章第五节)).<br />
<br />
:* <unsupported-stanza-type/> -- 初始化实体发送了一个流的一级子元素但是服务器不支持.<br />
<br />
:* <unsupported-version/> -- 由初始化实体在流的头信息中指定的'version'属性的值所指定的版本不被服务器支持;服务器可以(MAY)在<text/>元素中指定一个它支持的版本号.<br />
<br />
:* <xml-not-well-formed/> -- 初始化实体发送了一个不规范的XML(参考[XML]).<br />
<br />
====应用程序定义条件====<br />
<br />
:大家知道,应用程序可以(MAY)在error元素中包含一个适当名字空间的子元素来提供一个应用程序定义流错误信息."应用程序定义"元素应该(SHOULD)补充或甚至限定一个已定义的元素.所以 <error/> 元素将包含两个或三个子元素:<br />
<br />
<source lang="xml"><br />
<stream:error><br />
<xml-not-well-formed xmlns='urn:ietf:params:xml:ns:xmpp-streams'/><br />
<text xml:lang='en' xmlns='urn:ietf:params:xml:ns:xmpp-streams'><br />
Some special application diagnostic information!<br />
</text><br />
<escape-your-data xmlns='application-ns'/><br />
</stream:error><br />
</stream:stream><br />
</source><br />
<br />
===简化的流示例===<br />
<br />
:这里包含两个简化的例子,描述了基于流的客户端在服务器上的“会话”(这里"C"表示从客户端发给服务器,"S"表示从服务器发给客户端);这些例子只是用于举例说明原理.<br />
<br />
:一个基本的 "会话":<br />
<br />
<source lang="xml"><br />
C: <?xml version='1.0'?><br />
<stream:stream to='example.com' xmlns='jabber:client' xmlns:stream='http://etherx.jabber.org/streams' version='1.0'><br />
<br />
S: <?xml version='1.0'?><br />
<stream:stream from='example.com' id='someid' xmlns='jabber:client' xmlns:stream='http://etherx.jabber.org/streams' version='1.0'><br />
... encryption, authentication, and resource binding ...<br />
<br />
C: <message from='juliet@example.com' to='romeo@example.net' xml:lang='en'><br />
<br />
C: <body>Art thou not Romeo, and a Montague?</body><br />
<br />
C: </message><br />
<br />
S: <message from='romeo@example.net' to='juliet@example.com' xml:lang='en'><br />
<br />
S: <body>Neither, fair saint, if either thee dislike.</body><br />
<br />
S: </message><br />
<br />
C: </stream:stream><br />
<br />
S: </stream:stream><br />
</source><br />
<br />
<br />
:一个不成功的 "会话" :<br />
<br />
<source lang="xml"><br />
C: <?xml version='1.0'?><br />
<stream:stream to='example.com' xmlns='jabber:client' xmlns:stream='http://etherx.jabber.org/streams' version='1.0'><br />
<br />
S: <?xml version='1.0'?><br />
<stream:stream from='example.com' id='someid' xmlns='jabber:client' xmlns:stream='http://etherx.jabber.org/streams' version='1.0'><br />
... encryption, authentication, and resource binding ...<br />
<br />
C: <message xml:lang='en'><br />
<body>Bad XML, no closing body tag!<br />
</message><br />
<br />
S: <stream:error><br />
<xml-not-well-formed xmlns='urn:ietf:params:xml:ns:xmpp-streams'/><br />
</stream:error><br />
<br />
S: </stream:stream><br />
</source><br />
<br />
==TLS 的使用==<br />
<br />
===概览===<br />
<br />
:XMPP包含的一个保证流安全的方法来防止篡改和偷听.这个传输层安全协议[TLS]的频道加密方法, 模拟了类似的其他"STARTTLS"(见RFC 2595 [USINGTLS])的扩展,如 IMAP [IMAP], POP3 [POP3], and ACAP [ACAP]."STARTTLS"的扩展名字空间是'urn:ietf:params:xml:ns:xmpp-tls'.<br />
<br />
:一个给定域的管理员可以(MAY)要求客户端和服务器通信以及服务器之间通信时使用TLS,或者两者都要求。客户端应该(SHOULD)在尝试完成 SASL (第六章)握手之前使用 TLS,服务器应该(SHOULD)在两个域之间使用 TLS 以保证服务器间通信的安全。<br />
<br />
:以下是使用规则:<br />
<br />
::# 一个遵守本协议的初始化实体必须(MUST)在初始化流的头信息中包含一个'version'属性并把值设为“1.0”。<br />
::# 如果TLS握手发生在两个服务器之间,除非服务器声称的DNS主机名已经被解析(见第十四章第四节 Server-to-Server Communications),通信不能(MUST NOT)继续进行。<br />
::# 当一个遵守本协议的接收实体接收了一个初始化流(它的头信息中包含一个'version'属性并且值设为“1.0”),在发送应答流的的头信息(其中包含版本标记)之后,它必须发送(MUST)<starttls/>元素(名字空间为 'urn:ietf:params:xml:ns:xmpp-tls')以及其他它支持的流特性 。<br />
::# 如果初始化实体选择使用TLS,TLS握手必须在SASL握手之前完成;这个顺序用于帮助保护SASL握手时发送的认证信息的安全,同时可以在必要的时候在TLS握手之前为SASL外部机制提供证书。<br />
::# TLS握手期间,一个实体不能(MUST NOT)在流的根元素中发送任何空格符号作为元素的分隔符(在下面的TLS示例中的任何空格符都仅仅是为了便于阅读);这个禁令用来帮助确保安全层字节精度。<br />
::# 接收实体必须(MUST)在发送<proceed/> 元素的关闭符号">" 之后立刻开始TLS协商。初始化实体必须(MUST)在从接收实体接收到<proceed/> 元素的关闭符号">" 之后立刻开始TLS协商。<br />
::# 初始化实体必须(MUST)验证接收实体出示的证书;关于证书验证流程参见Certificate Validation ( 第十四章第二节)。<br />
::# 证书必须(MUST)检查初始化实体(比如一个用户)提供的主机名;而不是通过DNS系统解析出来的主机名;例如,如果用户指定一个主机名"example.com"而一个DNS SRV [SRV]查询返回"im.example.com",证书必须(MUST)检查"example.com".如果任何种类的XMPP实体(例如客户端或服务器)的JID出现在一个证书里,它必须(MUST)表现为一个别名实体里面的UTF8字符串,存在于subjectAltName之中。如何使用 [ASN.1] 对象标识符 "id-on-xmppAddr" 定义在本文的第五章第一节第一小节。<br />
::# 如果 TLS 握手成功了,接收实体必须(MUST) 丢弃TLS 生效之前从初始化实体得到的任何不可靠的信息.<br />
::# 如果 TLS 握手成功了,初始化实体必须(MUST) 丢弃TLS 生效之前从接收实体得到的任何不可靠的信息. <br />
::# 如果 TLS 握手成功了,接收实体不能(MUST NOT)在流重新开始的时候通过提供其他的流特性来向初始化实体提供 STARTTLS 扩展.<br />
::# 如果 TLS 握手成功了,初始化实体必须(MUST)继续进行SASL握手。<br />
::# 如果 TLS 握手失败了,接收实体必须(MUST)终止XML流和相应的TCP连接。<br />
::# 关于必须(MUST)支持的机制,参照 Mandatory-to-Implement Technologies (第十四章第七节) 。<br />
<br />
====用于 XMPP 地址的 ASN.1 对象标识符====<br />
<br />
:上文提到的[ASN.1] 对象标识符 "id-on-xmppAddr"定义如下:<br />
<br />
::id-pkix OBJECT IDENTIFIER ::= { iso(1) identified-organization(3)<br />
<br />
::dod(6) internet(1) security(5) mechanisms(5) pkix(7) }<br />
<br />
::id-on OBJECT IDENTIFIER ::= { id-pkix 8 } -- other name forms<br />
<br />
::id-on-xmppAddr OBJECT IDENTIFIER ::= { id-on 5 }<br />
<br />
::XmppAddr ::= UTF8String<br />
<br />
:对象标识符也可以(MAY)使用点分隔的格式,如 "1.3.6.1.5.5.7.8.5".<br />
<br />
===叙述===<br />
<br />
:当一个初始化实体用TLS保护一个和接收实体之间的流,其步骤如下:<br />
<br />
::# 初始化实体打开一个TCP连接,发送一个打开的XML流头信息(其'version'属性设置为"1.0")给接收实体以初始化一个流。<br />
::# 接收实体打开一个TCP连接,发送一个XML流头信息(其'version'属性设置为"1.0")给初始化实体作为应答。<br />
::# 接收实体向初始化实体提议STARTTLS范围(包括其他支持的流特性),如果TLS对于和接收实体交互是必需的,它应该(SHOULD)在<starttls/>元素中包含子元素<required/>.<br />
::# 初始化实体发出STARTTLS命令(例如, 一个符合'urn:ietf:params:xml:ns:xmpp-tls'名字空间的 <starttls/> 元素) 以通知接收实体它希望开始一个TLS握手来保护流。<br />
::# 接收实体必须(MUST)以'urn:ietf:params:xml:ns:xmpp-tls'名字空间中的<proceed/>元素或<failure/>元素应答。如果失败,接收实体必须(MUST)终止XML流和相应的TCP连接。如果继续进行,接收实体必须(MUST)尝试通过TCP连接完成TLS握手并且在TLS握手完成之前不能(MUST NOT)发送任何其他XML数据。<br />
::# 初始化实体和接收实体尝试完成TLS握手。(要符合[TLS]规范)<br />
::# 如果 TLS 握手不成功, 接收实体必须(MUST)终止 TCP 连接. 如果 TLS 握手成功, 初始化实体必须(MUST)发送给接收实体一个打开的XML流头信息来初始化一个新的流(先发送一个关闭标签</stream>是不必要的,因为接收实体和初始化实体必须(MUST)确保原来的流在TLS握手成功之后被关闭) 。<br />
::# 在从初始化实体收到新的流头信息之后,接收实体必须(MUST)发送一个新的XML流头信息给初始化实体作为应答,其中应包含可用的特性但不包含STATRTTLS特性。<br />
<br />
===客户端-服务器 示例===<br />
<br />
:以下例子展示一个客户端使用STARTTLS保护数据流 (注意: 以下步骤举例说明协议中的失败案例;在这个例子中它们并不详尽并且也不是必须被数据传输触发的).<br />
<br />
:步骤 1: 客户端初始化流给服务器:<br />
<br />
<source lang="xml"><br />
<stream:stream xmlns='jabber:client' xmlns:stream='http://etherx.jabber.org/streams' to='example.com' version='1.0'><br />
</source><br />
<br />
:步骤 2: 服务器发送一个流标签给客户端作为应答:<br />
<br />
<source lang="xml"><br />
<stream:stream xmlns='jabber:client' xmlns:stream='http://etherx.jabber.org/streams' id='c2s_123' from='example.com' version='1.0'><br />
</source><br />
<br />
:步骤 3: 服务器发送 STARTTLS 范围给客户端(包括验证机制和任何其他流特性):<br />
<br />
<source lang="xml"><br />
<stream:features><br />
<starttls xmlns='urn:ietf:params:xml:ns:xmpp-tls'><br />
<required/><br />
</starttls><br />
<mechanisms xmlns='urn:ietf:params:xml:ns:xmpp-sasl'><br />
<mechanism>DIGEST-MD5</mechanism><br />
<mechanism>PLAIN</mechanism><br />
</mechanisms><br />
</stream:features><br />
</source><br />
<br />
:步骤 4: 客户端发送 STARTTLS 命令给服务器:<br />
<br />
<source lang="xml"><br />
<starttls xmlns='urn:ietf:params:xml:ns:xmpp-tls'/><br />
</source><br />
<br />
:步骤 5: 服务器通知客户端可以继续进行:<br />
<br />
<source lang="xml"><br />
<proceed xmlns='urn:ietf:params:xml:ns:xmpp-tls'/><br />
</source><br />
<br />
:步骤 5 (或者): 服务器通知客户端 TLS 握手失败并关闭流和TCP连接:<br />
<br />
<source lang="xml"><br />
<failure xmlns='urn:ietf:params:xml:ns:xmpp-tls'/><br />
</stream:stream><br />
</source><br />
<br />
:步骤 6: 客户端和服务器尝试通过已有的TCP连接完成 TLS 握手.<br />
<br />
:步骤 7: 如果 TLS 握手成功, 客户端初始化一个新的流给服务器:<br />
<br />
<source lang="xml"><br />
<stream:stream xmlns='jabber:client' xmlns:stream='http://etherx.jabber.org/streams' to='example.com' version='1.0'><br />
</source><br />
<br />
:步骤 7 (或者): 如果 TLS 握手不成功, 服务器关闭 TCP 连接.<br />
<br />
:步骤 8: 服务器发送一个流头信息应答客户端,其中包括任何可用的流特性:<br />
<br />
<source lang="xml"><br />
<stream:stream xmlns='jabber:client' xmlns:stream='http://etherx.jabber.org/streams' from='example.com' id='c2s_234' version='1.0'><br />
<stream:features><br />
<mechanisms xmlns='urn:ietf:params:xml:ns:xmpp-sasl'><br />
<mechanism>DIGEST-MD5</mechanism><br />
<mechanism>PLAIN</mechanism><br />
<mechanism>EXTERNAL</mechanism><br />
</mechanisms><br />
</stream:features><br />
</source><br />
<br />
:步骤 9: 客户端继续 SASL 握手 (第六章).<br />
<br />
===服务器-服务器示例===<br />
<br />
:以下例子展示两个服务器之间使用STARTTLS保护数据流 (注意: 以下步骤举例说明协议中的失败案例;在这个例子中它们并不详尽并且也不是必须被数据传输触发的).<br />
<br />
:步骤 1: Server1 初始化流给 Server2:<br />
<br />
<source lang="xml"><br />
<stream:stream xmlns='jabber:server' xmlns:stream='http://etherx.jabber.org/streams' to='example.com' version='1.0'><br />
</source><br />
<br />
:步骤 2: Server2 发送一个流标签给 Server1 作为应答:<br />
<br />
<source lang="xml"><br />
<stream:stream xmlns='jabber:server' xmlns:stream='http://etherx.jabber.org/streams' from='example.com' id='s2s_123' version='1.0'><br />
</source><br />
<br />
:步骤 3: Server2 发送 STARTTLS 范围给 Server1 ,包括验证机制和任何其他流特性:<br />
<br />
<source lang="xml"><br />
<stream:features><br />
<starttls xmlns='urn:ietf:params:xml:ns:xmpp-tls'><br />
<required/><br />
</starttls><br />
<mechanisms xmlns='urn:ietf:params:xml:ns:xmpp-sasl'><br />
<mechanism>DIGEST-MD5</mechanism><br />
<mechanism>KERBEROS_V4</mechanism><br />
</mechanisms><br />
</stream:features><br />
</source><br />
<br />
:步骤 4: Server1 发送 STARTTLS 命令给 Server2:<br />
<br />
<source lang="xml"><br />
<starttls xmlns='urn:ietf:params:xml:ns:xmpp-tls'/><br />
</source><br />
<br />
:步骤 5: Server2 通知 Server1 允许继续进行:<br />
<br />
<source lang="xml"><br />
<proceed xmlns='urn:ietf:params:xml:ns:xmpp-tls'/><br />
</source><br />
<br />
:步骤 5 (或者): Server2 通知 Server1 TLS握手失败并关闭流:<br />
<br />
<source lang="xml"><br />
<failure xmlns='urn:ietf:params:xml:ns:xmpp-tls'/><br />
</stream:stream><br />
</source><br />
<br />
:步骤 6: Server1 和 Server2 尝试通过 TCP 完成 TLS 握手.<br />
<br />
:步骤 7: 如果 TLS 握手成功, Server1 初始化一个新的流给 Server2:<br />
<br />
<source lang="xml"><br />
<stream:stream xmlns='jabber:server' xmlns:stream='http://etherx.jabber.org/streams' to='example.com' version='1.0'><br />
</source><br />
<br />
:步骤 7 (或者): 如果 TLS 握手不成功, Server2 关闭 TCP 连接.<br />
<br />
:步骤 8: Server2 发送一个包含任何可用流特性的流头信息给 Server1 :<br />
<br />
<source lang="xml"><br />
<stream:stream xmlns='jabber:server' xmlns:stream='http://etherx.jabber.org/streams' from='example.com' id='s2s_234' version='1.0'><br />
<stream:features><br />
<mechanisms xmlns='urn:ietf:params:xml:ns:xmpp-sasl'><br />
<mechanism>DIGEST-MD5</mechanism><br />
<mechanism>KERBEROS_V4</mechanism><br />
<mechanism>EXTERNAL</mechanism><br />
</mechanisms><br />
</stream:features><br />
</source><br />
<br />
:步骤 9: Server1 继续进行 SASL 握手(第六章).<br />
<br />
==SASL 的使用==<br />
<br />
===概览===<br />
<br />
:XMPP 有一个验证流的方法,即XMPP特定的SASL(简单验证和安全层)[SASL]。SASL提供了一个通用的方法为基于连接的协议增加验证支持,而XMPP使用了一个普通的XML名字空间来满足SASL的需要。<br />
<br />
:以下规则应用于:<br />
<br />
:# 如果SASL协商发生在两台服务器之间,除非服务器宣称的DNS主机名得到解析,否则不能(MUST NOT)进行通信。(参见 服务器间的通信(第十四章第四节)).<br />
:# 如果初始化实体有能力使用 SASL 协商, 它必须(MUST)在初始化流的头信息中包含一个值为"1.0"的属性'version'。<br />
:# 如果接收实体有能力使用 SASL 协商, 它必须(MUST)在应答从初始化实体收到的打开流标签时(如果打开的流标签包含一个值为"1.0"的'version'属性),通过'urn:ietf:params:xml:ns:xmpp-sasl'名字空间中的<mechanisms/>元素声明一个或多个验证机制.<br />
:# 当 SASL 协商时, 一个实体不能(MUST NOT)在流的根元素中发送任何空格符号(匹配 production [3] content of [XML])作为元素之间的分隔符(在以下的SASL例子中任何空格符号的出现仅仅是为了增加可读性); 这条禁令帮助确保安全层字节的精确度。<br />
:# 当SASL握手时,在XML元素中使用的任何 XML 字符数据必须被编码成 base64, 编码遵循 RFC 3548 第三章的规定。<br />
:# 如果一个 简单名字"simple username" 规范被选定的SASL机制所支持,(比如, 这被 DIGEST-MD5 和 CRAM-MD5 机制支持但不被 EXTERNAL 和 GSSAPI 机制支持), 验证的时候初始化实体应该(SHOULD)在服务器间通信时提供 简单名字 自身的发送域(IP地址或包含在一个域标识符中的域名全称),在客户端与服务器之间通信时提供注册用户名(包含在一个XMPP节点标识符中的用户或节点名)。<br />
:# 如果初始化实体希望以另一个实体的身份出现并且SASL机制支持授权ID的传输,初始化实体在SASL握手时必须(MUST)提供一个授权ID。如果初始化实体不希望以另一个实体的身份出现,初始化实体在SASL握手时不能(MUST NOT)提供一个授权ID。在 [SASL] 的定义中,除非授权ID不同于从验证ID(详见[SASL])中得到的缺省的授权ID,初始化实体不能(MUST NOT)提供授权ID。如果提供了,这个授权ID的值必须(MUST)是<domain>的格式(对于服务器来说)或<node@domain>的格式(对于客户端来说). <br />
:# 在成功进行包括安全层的SASL握手之后,接收实体必须(MUST)丢弃任何从初始化实体得到的而不是从SASL协商本身获得的信息。<br />
:# 在成功进行包括安全层的SASL握手之后,初始化实体必须(MUST)丢弃任何从接收实体得到的而不是从SASL协商本身获得的信息。<br />
:# 参看 强制执行的技术 (第十四章第七节) ,了解关于必须(MUST)支持的机制.<br />
<br />
===叙述===<br />
<br />
:一个初始化实体使用SASL和接收实体做验证的步骤如下:<br />
<br />
:# 初始化实体请求SASL验证,它发送一个打开的XML流头信息给接收实体,其'version'属性的值为"1.0".<br />
:# 在发送一个XML流头回复之后,接收实体声明一个可用的SASL验证机制清单;每个机制作为一个<mechanism/>元素,作为子元素包含在<mechanisms/>容器元素(其名字空间为'urn:ietf:params:xml:ns:xmpp-sasl')中,而<mechanisms/>则包含在流名字空间中的<features/>元素中。如果在使用任何验证机制之前需要使用TLS(见第五章),接收实体不能(MUST NOT)在TLS握手之前提供可用的SASL验证机制清单。如果初始化实体在优先的TLS协商过程中呈现了一个合法的证书,接收实体应该(SHOULD)在SASL握手中提出一个SASL外部机制给初始化实体,尽管这个外部机制可以(MAY)在其它环境下提供。<br />
:# 初始化实体发送一个符合'urn:ietf:params:xml:ns:xmpp-sasl'名字空间的<auth/>元素(其中包含了适当的'mechanism'属性值)给接收实体,以选择一个机制。如果这个机制支持或需要,这个元素可以(MAY)包含XML字符数据(在SASL术语中,即“初始化应答”);如果初始化实体需要发送一个零字节的初始化应答,它必须(MUST)传输一个单独的等号作为应答,这表示应答有效但不包含数据。<br />
:# 如果必要,接收实体向初始化实体发送一个符合'urn:ietf:params:xml:ns:xmpp-sasl'名字空间的<challenge/>元素来发出挑战;这个元素可以(MAY)包含XML字符数据(必须按照初始化实体选择的SASL机制进行一致性运算)。<br />
:# 初始化实体向接收实体发送符合'urn:ietf:params:xml:ns:xmpp-sasl'名字空间的<response/>元素作为应答;这个元素可以(MAY)包含XML字符数据(必须按照初始化实体选择的SASL机制进行一致性运算)。<br />
:# 如果必要,接收实体发送更多的挑战给初始化实体,初始化实体发送更多的回应。<br />
<br />
:这一系列的 挑战/应答 组,持续进行直到发生以下三件事中的一件为止:<br />
<br />
:# 初始化实体向接收实体发送符合'urn:ietf:params:xml:ns:xmpp-sasl'名字空间的<abort/>元素以中止握手。在接收到<abort/>元素之后,接收实体应该(SHOULD)允许一个可配置的但是合理的重试次数(至少2次),然后它必须(MUST)终止TCP连接;这使得初始化实体(如一个最终用户客户端)能够容忍可能不正确的credentials(如密码输入错误)而不用强制重新连接。<br />
:# 接收实体向初始化实体发送符合'urn:ietf:params:xml:ns:xmpp-sasl'名字空间的<failure/>元素以报告握手失败(详细的失败原因应该在<failure/>的一个适当的子元素中沟通,在第六章第四节中的SASL Errors中定义)。如果失败的情况发生了,接收实体应该(SHOULD)允许一个可配置的但是合理的重试次数(至少2次), 然后它必须(MUST)终止TCP连接;这使得初始化实体(如一个最终用户客户端)能够容忍可能不正确的credentials(如密码输入错误)而不用强制重新连接。<br />
:# 接收实体向初始化实体发送符合'urn:ietf:params:xml:ns:xmpp-sasl'名字空间的<success/>元素以报告握手成功;如果所选择的SASL机制要求,这个元素可以(MAY)包含XML字符数据(见SASL术语,“成功的额外数据”)。接收到<success/> 元素之后,初始化实体必须(MUST)发送一个打开的XML流头信息给接收实体以发起一个新的的流(不需要先发送一个 </stream>标签,因为在发送和接收到<success/>元素之后,接收实体和初始化实体必须确认原来的流被关闭了)。从初始化实体接收到新的流头信息之后,接收实体必须(MUST)发送一个新的流头信息给初始化实体作为回应,附上任何可用的特性(但不包括 STARTTLS 和 SASL 特性)或一个空的 <features/> 元素(这表示没有更多的特性可用);任何没有在本文定义的附加特性必须(MUST)在XMPP的相关扩展中定义。<br />
<br />
===SASL 定义===<br />
<br />
:[SASL]的必要条件要求通过协议定义来提供以下信息:<br />
<br />
::service name(服务名): "xmpp"<br />
<br />
::initiation sequence(开始序列): 当初始化实体提供一个打开的XML流头信息并且接收实体善意回应之后,接收实体提供一个可接受的验证方法清单。初始化实体从这个清单中选择一个方法,把它作为 <auth/> 元素的 'mechanism' 属性的值发送给接收实体,也可以选择发送一个初始化应答以避免循环。<br />
<br />
::exchange sequence(交换序列): 挑战和回应的交换,从接收实体发送给初始化实体的 <challenge/> 元素和从初始化实体发送给接收实体的 <response/> 元素信息。接收实体通过发送 <failure/>元素报告失败,发送<success/>元素报告成功;初始化实体通过发送<abort/> 元素中止交换。成功的协商之后,两边都认为原来的XML流已经关闭并且都开始发送新的流头信息。<br />
<br />
::security layer negotiation(安全层协商): 安全层在接收实体发送 <success/> 元素的关闭字符">"之后立刻生效,在初始化实体发送 <success/> 元素的关闭字符">"之后也立刻生效。层的顺序是 [TCP],[TLS],然后是 [SASL],然后是 [XMPP]。<br />
<br />
::use of the authorization identity(授权ID的使用): 授权ID可在xmpp中用于表示一个客户端的非缺省的<node@domain>,或一个服务器的<domain> 。<br />
<br />
===SASL 错误===<br />
<br />
:SASL相关的错误条件定义如下:<br />
<br />
::* <aborted/> -- 接收实体认可由初始化实体发送的<abort/>元素;在回应一个<abort/>元素时发送。<br />
<br />
::* <incorrect-encoding/> -- 由初始化实体提供的数据无法处理,因为[BASE64]编码不正确(例如,因为编码不符合[BASE64]的第三章); 在回应一个包含初始化响应数据的<response/> 元素或<auth/>元素时发送.<br />
<br />
::* <invalid-authzid/> -- 由初始化实体提供的授权id是非法的,因为它的格式不正确或初始化实体无权给那个ID授权;在回应一个包含初始化响应数据的<response/> 元素或<auth/>元素时发送。<br />
<br />
::* <invalid-mechanism/> -- 初始化实体不能提供一个机制活、或请求一个不被接受实体支持的机制;在回应一个<auth/>元素时发送。<br />
<br />
::* <mechanism-too-weak/> -- 初始化实体请求的机制比服务器策略对它的要求弱;在回应一个包含初始化响应数据的<response/> 元素或<auth/>元素时发送。<br />
<br />
::* <not-authorized/> -- 验证失败,因为初始化实体没有提供合法的credentials(这包括但不限于未知用户名等情形);在回应一个包含初始化响应数据的<response/> 元素或<auth/>元素时发送。<br />
<br />
::* <temporary-auth-failure/> -- 验证失败,因为接收实体出现了临时的错误;在回应一个<response/> 元素或<auth/>元素时发送。<br />
<br />
===客户端-服务器 示例===<br />
<br />
:以下例子展示了一个客户端和一个服务器使用SASL作验证的数据流,通常是在成功的TLS握手之后(注意:以下显示的替代步骤仅用于举例说明协议的失败情形;它们不够详尽也不需要由例子中的数据传送来触发)。<br />
<br />
:步骤 1: 客户端初始化流给服务器:<br />
<br />
<source lang="xml"><br />
<stream:stream xmlns='jabber:client' xmlns:stream='http://etherx.jabber.org/streams' to='example.com' version='1.0'><br />
</source><br />
<br />
:步骤 2: 服务器向客户端发送流标签作为应答:<br />
<br />
<source lang="xml"><br />
<stream:stream xmlns='jabber:client' xmlns:stream='http://etherx.jabber.org/streams' id='c2s_234' from='example.com' version='1.0'><br />
</source><br />
<br />
:步骤 3: 服务器通知客户端可用的验证机制:<br />
<br />
<source lang="xml"><br />
<stream:features><br />
<mechanisms xmlns='urn:ietf:params:xml:ns:xmpp-sasl'><br />
<mechanism>DIGEST-MD5</mechanism><br />
<mechanism>PLAIN</mechanism><br />
</mechanisms><br />
</stream:features><br />
</source><br />
<br />
:步骤 4: 客户端选择一个验证机制:<br />
<br />
<source lang="xml"><br />
<auth xmlns='urn:ietf:params:xml:ns:xmpp-sasl' mechanism='DIGEST-MD5'/><br />
</source><br />
<br />
:步骤 5: 服务器发送一个 [BASE64] 编码的挑战给客户端:<br />
<br />
<source lang="xml"><br />
<challenge xmlns='urn:ietf:params:xml:ns:xmpp-sasl'><br />
cmVhbG09InNvbWVyZWFsbSIsbm9uY2U9Ik9BNk1HOXRFUUdtMmhoIixxb3A9ImF1dGgi<br />
LGNoYXJzZXQ9dXRmLTgsYWxnb3JpdGhtPW1kNS1zZXNzCg==<br />
</challenge><br />
</source><br />
<br />
:解码后的挑战信息是:<br />
<br />
<source lang="xml"><br />
realm="somerealm",nonce="OA6MG9tEQGm2hh",\<br />
qop="auth",charset=utf-8,algorithm=md5-sess<br />
</source><br />
<br />
:步骤 5 (替代): 服务器返回一个错误给客户端:<br />
<br />
<source lang="xml"><br />
<failure xmlns='urn:ietf:params:xml:ns:xmpp-sasl'><br />
<incorrect-encoding/><br />
</failure><br />
</stream:stream><br />
</source><br />
<br />
:步骤 6: 客户端发送一个[BASE64]编码的回应这个挑战:<br />
<br />
<source lang="xml"><br />
<response xmlns='urn:ietf:params:xml:ns:xmpp-sasl'><br />
dXNlcm5hbWU9InNvbWVub2RlIixyZWFsbT0ic29tZXJlYWxtIixub25jZT0i<br />
T0E2TUc5dEVRR20yaGgiLGNub25jZT0iT0E2TUhYaDZWcVRyUmsiLG5jPTAw<br />
MDAwMDAxLHFvcD1hdXRoLGRpZ2VzdC11cmk9InhtcHAvZXhhbXBsZS5jb20i<br />
LHJlc3BvbnNlPWQzODhkYWQ5MGQ0YmJkNzYwYTE1MjMyMWYyMTQzYWY3LGNo<br />
YXJzZXQ9dXRmLTgK<br />
</response><br />
</source><br />
<br />
:解码后的回应信息是:<br />
<br />
<source lang="xml"><br />
username="somenode",realm="somerealm",\<br />
nonce="OA6MG9tEQGm2hh",cnonce="OA6MHXh6VqTrRk",\<br />
nc=00000001,qop=auth,digest-uri="xmpp/example.com",\<br />
response=d388dad90d4bbd760a152321f2143af7,charset=utf-8<br />
</source><br />
<br />
:步骤 7: 服务器发送另一个[BASE64]编码的挑战给客户端:<br />
<br />
<source lang="xml"><br />
<challenge xmlns='urn:ietf:params:xml:ns:xmpp-sasl'><br />
cnNwYXV0aD1lYTQwZjYwMzM1YzQyN2I1NTI3Yjg0ZGJhYmNkZmZmZAo=<br />
</challenge><br />
</source><br />
<br />
:解码后的挑战信息是:<br />
<br />
<source lang="xml"><br />
rspauth=ea40f60335c427b5527b84dbabcdfffd<br />
</source><br />
<br />
:步骤 7 (或者): 服务器返回一个错误给客户端:<br />
<br />
<source lang="xml"><br />
<failure xmlns='urn:ietf:params:xml:ns:xmpp-sasl'><br />
<temporary-auth-failure/><br />
</failure><br />
</stream:stream><br />
</source><br />
<br />
:步骤 8: 客户端应答这个挑战:<br />
<br />
<source lang="xml"><br />
<response xmlns='urn:ietf:params:xml:ns:xmpp-sasl'/><br />
</source><br />
<br />
:步骤 9: 服务器通知客户端验证成功:<br />
<br />
<source lang="xml"><br />
<success xmlns='urn:ietf:params:xml:ns:xmpp-sasl'/><br />
</source><br />
<br />
:步骤 9 (或者): 服务器通知客户端验证失败:<br />
<br />
<source lang="xml"><br />
<failure xmlns='urn:ietf:params:xml:ns:xmpp-sasl'><br />
<temporary-auth-failure/><br />
</failure><br />
</stream:stream><br />
</source><br />
<br />
:步骤 10: 客户端发起一个新的流给服务器:<br />
<br />
<source lang="xml"><br />
<stream:stream xmlns='jabber:client' xmlns:stream='http://etherx.jabber.org/streams' to='example.com' version='1.0'><br />
</source><br />
<br />
:步骤 11: 服务器发送一个流头信息回应客户端,并附上任何可用的特性(或空的features元素):<br />
<br />
<source lang="xml"><br />
<stream:stream xmlns='jabber:client' xmlns:stream='http://etherx.jabber.org/streams' id='c2s_345' from='example.com' version='1.0'><br />
<stream:features><br />
<bind xmlns='urn:ietf:params:xml:ns:xmpp-bind'/><br />
<session xmlns='urn:ietf:params:xml:ns:xmpp-session'/><br />
</stream:features><br />
</source><br />
<br />
===服务器-服务器 示例===<br />
<br />
:以下例子展示了一个服务器和另一个服务器使用SASL作验证的数据流,通常是在成功的TLS握手之后(注意:以下显示的替代步骤仅用于举例说明协议的失败情形;它们不够详尽也不需要由例子中的数据传送来触发)。<br />
<br />
:步骤 1: 服务器1 发起一个流给 服务器2 :<br />
<br />
<source lang="xml"><br />
<stream:stream xmlns='jabber:server' xmlns:stream='http://etherx.jabber.org/streams' to='example.com' version='1.0'><br />
</source><br />
<br />
:步骤 2: 服务器2 回应一个流标签给 服务器1:<br />
<br />
<source lang="xml"><br />
<stream:stream xmlns='jabber:server' xmlns:stream='http://etherx.jabber.org/streams' from='example.com' id='s2s_234' version='1.0'><br />
</source><br />
<br />
:步骤 3: 服务器2 通知 服务器1 可用的验证机制:<br />
<br />
<source lang="xml"><br />
<stream:features><br />
<mechanisms xmlns='urn:ietf:params:xml:ns:xmpp-sasl'><br />
<mechanism>DIGEST-MD5</mechanism><br />
<mechanism>KERBEROS_V4</mechanism><br />
</mechanisms><br />
</stream:features><br />
</source><br />
<br />
:步骤 4: 服务器1 选择一个验证机制:<br />
<br />
<source lang="xml"><br />
<auth xmlns='urn:ietf:params:xml:ns:xmpp-sasl' mechanism='DIGEST-MD5'/><br />
</source><br />
<br />
:步骤 5: 服务器2 发送一个[BASE64]编码的挑战给 服务器1:<br />
<br />
<source lang="xml"><br />
<challenge xmlns='urn:ietf:params:xml:ns:xmpp-sasl'><br />
cmVhbG09InNvbWVyZWFsbSIsbm9uY2U9Ik9BNk1HOXRFUUdtMmhoIixxb3A9<br />
ImF1dGgiLGNoYXJzZXQ9dXRmLTgsYWxnb3JpdGhtPW1kNS1zZXNz<br />
</challenge><br />
</source><br />
<br />
:解码后的挑战信息是:<br />
<br />
<source lang="xml"><br />
realm="somerealm",nonce="OA6MG9tEQGm2hh",\<br />
qop="auth",charset=utf-8,algorithm=md5-sess<br />
</source><br />
<br />
:步骤 5 (替代): 服务器2 返回一个错误给 服务器1:<br />
<br />
<source lang="xml"><br />
<failure xmlns='urn:ietf:params:xml:ns:xmpp-sasl'><br />
<incorrect-encoding/><br />
</failure><br />
</stream:stream><br />
</source><br />
<br />
:步骤 6: 服务器1 发送一个[BASE64]编码的回应这个挑战:<br />
<br />
<source lang="xml"><br />
<response xmlns='urn:ietf:params:xml:ns:xmpp-sasl'><br />
dXNlcm5hbWU9ImV4YW1wbGUub3JnIixyZWFsbT0ic29tZXJlYWxtIixub25j<br />
ZT0iT0E2TUc5dEVRR20yaGgiLGNub25jZT0iT0E2TUhYaDZWcVRyUmsiLG5j<br />
PTAwMDAwMDAxLHFvcD1hdXRoLGRpZ2VzdC11cmk9InhtcHAvZXhhbXBsZS5v<br />
cmciLHJlc3BvbnNlPWQzODhkYWQ5MGQ0YmJkNzYwYTE1MjMyMWYyMTQzYWY3<br />
LGNoYXJzZXQ9dXRmLTgK<br />
</response><br />
</source><br />
<br />
:解码后的应答信息是:<br />
<br />
<source lang="xml"><br />
username="example.org",realm="somerealm",\<br />
nonce="OA6MG9tEQGm2hh",cnonce="OA6MHXh6VqTrRk",\<br />
nc=00000001,qop=auth,digest-uri="xmpp/example.org",\<br />
response=d388dad90d4bbd760a152321f2143af7,charset=utf-8<br />
</source><br />
<br />
:步骤 7: 服务器2 发送另外一个[BASE64]编码的挑战给 服务器1:<br />
<br />
<source lang="xml"><br />
<challenge xmlns='urn:ietf:params:xml:ns:xmpp-sasl'><br />
cnNwYXV0aD1lYTQwZjYwMzM1YzQyN2I1NTI3Yjg0ZGJhYmNkZmZmZAo=<br />
</challenge><br />
</source><br />
<br />
:解码后的挑战信息是:<br />
<br />
<source lang="xml"><br />
rspauth=ea40f60335c427b5527b84dbabcdfffd<br />
</source><br />
<br />
:步骤 7 (或者): 服务器2 返回一个错误给 服务器1:<br />
<br />
<source lang="xml"><br />
<failure xmlns='urn:ietf:params:xml:ns:xmpp-sasl'><br />
<invalid-authzid/><br />
</failure><br />
</stream:stream><br />
</source><br />
<br />
:步骤 8: 服务器1 回应挑战:<br />
<br />
<source lang="xml"><br />
<response xmlns='urn:ietf:params:xml:ns:xmpp-sasl'/><br />
</source><br />
<br />
:步骤 8 (或者): 服务器1 中止协商:<br />
<br />
<source lang="xml"><br />
<abort xmlns='urn:ietf:params:xml:ns:xmpp-sasl'/><br />
</source><br />
<br />
:步骤 9: 服务器2 通知 服务器1 验证成功:<br />
<br />
<source lang="xml"><br />
<success xmlns='urn:ietf:params:xml:ns:xmpp-sasl'/><br />
</source><br />
<br />
:步骤 9 (或者): 服务器2 通知 服务器1 验证失败:<br />
<br />
<source lang="xml"><br />
<failure xmlns='urn:ietf:params:xml:ns:xmpp-sasl'><br />
<aborted/><br />
</failure><br />
</stream:stream><br />
</source><br />
<br />
:步骤 10: 服务器1 重新发起一个新的流给 服务器2:<br />
<br />
<source lang="xml"><br />
<stream:stream xmlns='jabber:server' xmlns:stream='http://etherx.jabber.org/streams' to='example.com' version='1.0'><br />
</source><br />
<br />
:步骤 11: 服务器2 发送一个流头信息应答 服务器1 ,并附上任何可用的特性(或一个空的features元素).:<br />
<br />
<source lang="xml"><br />
<stream:stream xmlns='jabber:client' xmlns:stream='http://etherx.jabber.org/streams' from='example.com' id='s2s_345' version='1.0'><br />
<stream:features/><br />
</source><br />
<br />
==资源绑定==<br />
<br />
:在和接收实体完成 SASL 协商(第六章)之后,初始化实体可能(MAY)想要或者需要绑定一个特定的资源到流上.通常这仅适用于客户端: 为了满足本文定义的寻址格式(第三章)和节传输规则(第十章),客户端<node@domain>必须(MUST)拥有一个相关的资源ID(由服务器生成或由客户端程序提供);以确保在流上使用的地址是一个“全JID”(<node@domain/resource>)。<br />
<br />
:接收到一个成功的SASL握手之后,客户端必须(MUST)发送一个新的流头信息给服务器,服务器必须(MUST)返回一个包含可用的流特性列表的头信息。特别是,在成功的SASL握手之后如果服务器需要客户端绑定一个资源,它必须(MUST)在握手成功之后(而不是之前)发送给客户端的应答流特性中包含一个空的符合'urn:ietf:params:xml:ns:xmpp-bind'名字空间的<bind/>元素。:<br />
<br />
:服务器向客户端声明资源绑定特性:<br />
<br />
<source lang="xml"><br />
<stream:stream xmlns='jabber:client' xmlns:stream='http://etherx.jabber.org/streams' id='c2s_345' from='example.com' version='1.0'><br />
<stream:features><br />
<bind xmlns='urn:ietf:params:xml:ns:xmpp-bind'/><br />
</stream:features><br />
</source><br />
<br />
:收到要求资源绑定的通知后,客户端必须(MUST)通过发送一个符合'urn:ietf:params:xml:ns:xmpp-bind'名字空间的“set”类型的IQ节(参见 IQ 语义 (第九章第二节第三小节))给服务器来绑定一个资源到流中。<br />
<br />
:如果客户端端希望允许服务器给自己生成一个资源ID,它可以发送一个包含空的<bind/>元素的“set”类型的IQ节。:<br />
<br />
:客户端请求服务器绑定资源:<br />
<br />
<source lang="xml"><br />
<iq type='set' id='bind_1'><br />
<bind xmlns='urn:ietf:params:xml:ns:xmpp-bind'/><br />
</iq><br />
</source><br />
<br />
:一个支持资源绑定的服务器必须(MUST)自动生成一个资源ID给客户端。一个由服务器生成的资源ID对于那个<node@domain>必须(MUST)是唯一的。<br />
<br />
:如果客户端希望指定资源ID,它发送一个包含期望资源ID的“set”类型的 IQ节,把资源ID作为<bind/>元素下的<resource/>子元素的XML字符数据:<br />
<br />
:客户端绑定一个资源:<br />
<br />
<source lang="xml"><br />
<iq type='set' id='bind_2'><br />
<bind xmlns='urn:ietf:params:xml:ns:xmpp-bind'><br />
<resource>someresource</resource><br />
</bind><br />
</iq><br />
</source><br />
<br />
:一旦服务器为客户端生成了一个资源ID或接受了客户端自己提供的资源ID,它必须(MUST)返回一个“result”类型的 IQ 节给客户端,这个节必须包含一个指明全JID的<jid/>子元素表示服务器决定连接的资源:<br />
<br />
:服务器通知客户端资源绑定成功:<br />
<br />
<source lang="xml"><br />
<iq type='result' id='bind_2'><br />
<bind xmlns='urn:ietf:params:xml:ns:xmpp-bind'><br />
<jid>somenode@example.com/someresource</jid><br />
</bind><br />
</iq><br />
</source><br />
<br />
:一个服务器应该(SHOULD)接受客户端提供的资源ID,但是可以(MAY)用服务器生成的资源ID覆盖它;在这种情况下,服务器不应该(SHOULD NOT)返回一个错误信息一个(如<forbidden/>)给客户端,而应该(SHOULD)在上文所述的 IQ result 中返回生成的资源ID。<br />
<br />
:当一个客户端自行提供资源ID时,可能发生以下的节错误(参见 Stanza Errors (第九章第三节)):<br />
<br />
::- 提供的资源ID服务器无法处理,因为不符合资源字符规范Resourceprep(附录B)。<br />
<br />
::- 客户端不被允许绑定一个资源(如节点或用户已经达到允许连接的资源数限制)。<br />
<br />
::- 提供的资源ID已经被使用但是服务器不允许以同一个资源ID绑定多个连接。<br />
<br />
:协议对这些错误条件规定如下.<br />
<br />
::资源ID不能处理:<br />
<br />
<source lang="xml"><br />
<iq type='error' id='bind_2'><br />
<bind xmlns='urn:ietf:params:xml:ns:xmpp-bind'><br />
<resource>someresource</resource><br />
</bind><br />
<error type='modify'><br />
<bad-request xmlns='urn:ietf:params:xml:ns:xmpp-stanzas'/><br />
</error><br />
</iq><br />
</source><br />
<br />
::客户端不允许绑定一个资源:<br />
<br />
<source lang="xml"><br />
<iq type='error' id='bind_2'><br />
<bind xmlns='urn:ietf:params:xml:ns:xmpp-bind'><br />
<resource>someresource</resource><br />
</bind><br />
<error type='cancel'><br />
<not-allowed xmlns='urn:ietf:params:xml:ns:xmpp-stanzas'/><br />
</error><br />
</iq><br />
</source><br />
<br />
::资源ID已经在使用:<br />
<br />
<source lang="xml"><br />
<iq type='error' id='bind_2'><br />
<bind xmlns='urn:ietf:params:xml:ns:xmpp-bind'><br />
<resource>someresource</resource><br />
</bind><br />
<error type='cancel'><br />
<conflict xmlns='urn:ietf:params:xml:ns:xmpp-stanzas'/><br />
</error><br />
</iq><br />
</source><br />
<br />
:如果,在完成资源绑定步骤之前,客户端试图以符合'urn:ietf:params:xml:ns:xmpp-bind'名字空间的<bind/>子元素发送一个非IQ类型的XML节,服务器不能(MUST NOT)处理这个节,而应该(SHOULD)返回一个<not-authorized/>节错误信息给客户端.<br />
<br />
==服务器回拨==<br />
<br />
===概览===<br />
<br />
:Jabber协议接受的来自XMPP的包括“服务器回拨”方法,用于防治域名欺骗,使得欺骗XML节更为困难。服务器回拨不是一个安全机制,并且它的服务器身份认证结果很弱(参见服务器之间的通信(第十四章第四节)中关于这个方法的安全特性)。需要健壮的安全性的域名应该(SHOULD)使用TLS或SASL;细节参见服务器间的通信(第十四章第四节)。如果SASL用于服务器间通信,回拨就不需要用了(SHOULD NOT)。本文描述回拨的好处在于向后兼容现存的实现和部署。<br />
<br />
:服务器回拨方法由现存的DNS系统的存在而成为可能,因为一个服务器(通常)可以查询给定域的授权服务器。由于服务器回拨依赖于DNS,除非服务器宣称的DNS主机得到解析,域之间的通信无法进行(参见服务器间的通信(第十四章第四节))。<br />
<br />
:服务器回拨是单向性的,可在单一方向上对一个流进行(微弱的)身份验证.因为服务器回拨不是一个验证机制,通过回拨获得相互的认证是不可能的.因此,为了使得服务器之间的双向通信,服务器回拨必须(MUST)在每个方向上完成。<br />
<br />
:在服务器回拨中生成和检验密钥的方法必须(MUST)考虑计算被使用的主机名,由接收服务器生成的流ID,和只有授权服务器网络才知道的秘密。在服务器回拨中流ID是安全性的关键所以必须(MUST)是不可预知的和不可重复的(见[RANDOM]中关于使用随机数获得安全性的建议).<br />
<br />
:任何回拨协商过程中发生的错误必须(MUST)被当成一个流错误,并导致流以及相关的TCP连接的终止.可能发生的错误情况协议中描述如下.<br />
<br />
:以下术语适用:<br />
<br />
:* 发起服务器 -- 尝试在两个域之间建立连接的那个服务器.<br />
<br />
:* 接收服务器 -- 尝试验证发起服务期声称的域名的那台服务器.<br />
<br />
:* 授权(权威?Authoritative) 服务器 -- 回答发起服务器声称的DNS主机名的服务器;基本上这应该是那台发起服务器,但是它也可能是一个在发起服务器网络中独立的服务器。<br />
<br />
===事件顺序===<br />
<br />
:以下是回拨中的事件顺序的简介:<br />
<br />
:# 发起服务器和接收服务器建立一个连接。<br />
:# 发起服务器通过到连接发送一个 'key' 值给接收服务期。<br />
:# 接收服务器建立一个连接到授权服务器。<br />
:# 接收服务器发送一个相同的 'key' 值给授权服务器。<br />
:# 授权服务器回答这个key是否合法。<br />
:# 接收服务器通知发起服务器是否被验证通过。<br />
<br />
:我们用用以下图形展示这个事件流程(见附件s2s.png):<br />
<br />
{image:img=s2s}<br />
<br />
发起服务器 接收服务器<br />
----------- ---------<br />
| |<br />
| 建立连接 |<br />
| ----------------------> |<br />
| |<br />
| 发stream头 |<br />
| ----------------------> |<br />
| |<br />
| 发stream头 |<br />
| <---------------------- |<br />
| | <br />
| 发回拨key | 授权服务器<br />
| ----------------------> | -------------<br />
| | |<br />
| 建立连接 |<br />
| ----------------------> |<br />
| |<br />
| 发stream头 |<br />
| ----------------------> |<br />
| |<br />
| 发stream头 |<br />
| <---------------------- |<br />
| |<br />
| 发验证请求 |<br />
| ----------------------> |<br />
| |<br />
| 发验证响应 |<br />
| <---------------------- |<br />
|<br />
| 报告回拨结果 |<br />
| <---------------------- |<br />
| |<br />
<br />
===协议===<br />
<br />
:服务器之间互动的细节协议如下:<br />
<br />
:1. 发起服务器和接受服务器建立TCP连接.<br />
<br />
:2. 发起服务器发送流头信息给接收服务器:<br />
<br />
<source lang="xml"><br />
<stream:stream xmlns:stream='http://etherx.jabber.org/streams' xmlns='jabber:server' xmlns:db='jabber:server:dialback'><br />
</source><br />
<br />
:注意: 'to'和'from'属性在流的根元素是可选的(OPTIONAL). 其中包含的xmlns:db名字空间向接收服务器声明了发起服务器支持回拨. 如果名字空间不正确,接收实体必须(MUST)生成一个<invalid-namespace/>流错误条件并且终止XML流和相应的TCP连接.<br />
<br />
:3. 接收服务器应该(SHOULD)回送一个流头信息给发起服务器,为这次交互生成一个唯一性的ID :<br />
<br />
<source lang="xml"><br />
<stream:stream xmlns:stream='http://etherx.jabber.org/streams' xmlns='jabber:server' xmlns:db='jabber:server:dialback' id='457F9224A0...'><br />
</source><br />
<br />
:注意: 'to'和'from'属性在流的根元素是可选的(OPTIONAL). 如果名字空间不正确,发起服务器必须生成一个<invalid-namespace/>流错误条件并且终止XML流和相应的TCP连接.也要注意,在这里接收服务器应该(SHOULD)应答但是可以(MAY)出于安全策略考虑只是悄悄地终止XML流和TCP连接;无论如何,如果接收服务器希望继续,它必须(MUST)回送一个流头信息给发起服务器.<br />
<br />
:4. 发起服务器发送一个回拨密钥给接收服务器:<br />
<br />
<source lang="xml"><br />
<db:result to='Receiving Server' from='Originating Server'><br />
98AF014EDC0...<br />
</db:result><br />
</source><br />
<br />
:注意: 这个密钥不由接收服务器检查,因为接收服务器在会话之间(between sessions)不保存发起服务器的信息. 这个由发起服务器生成的密钥必须(MUST)是基于接收服务器在上一步骤中提供的ID值,以及发起服务器与授权服务器共享的安全机制生成的。 如果 'to' 地址的值和接收服务器知道的主机名不匹配,接收服务器必须(MUST)生成一个<host-unknown/>流错误条件并且终止XML流和相应的TCP连接. 如果 'from' 地址和接收服务器已经建立的连接的域名相吻合,接收服务器必须(MUST)维护这个已经存在的连接,直到证明这个新的连接是合法的为止;另外,接收实体可以(MAY)选择生成一个<not-authorized/> 流错误条件给这个新的连接并且终止和新连接申请相关的XML流及相应的TCP连接.<br />
<br />
:5. 接收服务器向发起服务器声明的那个域建立一个 TCP 连接,作为结果它连接到授权服务器. (注意: 为了优化性能, 在这里一个实现可以(MAY)重用现有的连接.)<br />
<br />
:6. 接收服务器发送一个流头信息给授权服务器:<br />
<br />
<source lang="xml"><br />
<stream:stream xmlns:stream='http://etherx.jabber.org/streams' xmlns='jabber:server' xmlns:db='jabber:server:dialback'><br />
</source><br />
<br />
:注意: 'to'和'from'属性在流的根元素是可选的(OPTIONAL). 如果名字空间不正确,授权服务器必须生成一个<invalid-namespace/>流错误条件并且终止XML流和相应的TCP连接. <br />
<br />
:7. 授权服务器发送流头信息给接收服务器:<br />
<br />
<source lang="xml"><br />
<stream:stream xmlns:stream='http://etherx.jabber.org/streams' xmlns='jabber:server' xmlns:db='jabber:server:dialback' id='1251A342B...'><br />
</source><br />
<br />
:注意: 如果名字空间不正确,接收服务器必须生成一个<invalid-namespace/>流错误条件并且终止它和授权服务器之间的XML流和相应的TCP连接. 如果一个流错误发生在接收服务器和 '''授权服务器''' 之间,接收服务器必须(MUST)生成一个 <remote-connection-failed/> 流错误条件并且终止它和 '''发起服务器''' 之间的XML流和相应的TCP连接.<br />
<br />
:8. 接收服务器发送一个密钥检查请求给授权服务器:<br />
<br />
<source lang="xml"><br />
<db:verify from='Receiving Server' to='Originating Server' id='457F9224A0...'><br />
98AF014EDC0...<br />
</db:verify><br />
</source><br />
<br />
:注意: 现在这里已经有了主机名,第三步中接收服务器发送给发起服务器的ID,第四步中发起服务器发送给接收服务器的密钥. 基于这些信息, 加上授权服务器网络共享的安全信息, 这个密钥被证实了.任何可用于验证的办法都可以(MAY)用于生成密钥. 如果 'to' 地址的值和授权服务器知道的主机名不匹配,授权服务器必须(MUST)生成一个<host-unknown/>流错误条件并且终止XML流和相应的TCP连接. 打开这个连接时,如果 'from' 地址和接收服务器声明的主机名(或任何合法的域,如验证过的接收服务器的子域名或寄宿在接收服务器上的其他经过验证的域)不符,授权服务器必须(MUST)生成一个<invalid-from/>流错误条件并且终止XML流和相应的TCP连接.<br />
<br />
:9. 授权服务器检查密钥是否合法:<br />
<br />
<source lang="xml"><br />
<db:verify from='Originating Server' to='Receiving Server' type='valid' id='457F9224A0...'/><br />
</source><br />
<br />
::或<br />
<br />
<source lang="xml"><br />
<db:verify from='Originating Server' to='Receiving Server' type='invalid' id='457F9224A0...'/><br />
</source><br />
<br />
:注意: 如果 ID 和第三步中接收服务器提供的不符,接收服务器必须(MUST)生成一个<invalid-id/>流错误条件并且终止XML流和相应的TCP连接. 如果 'to' 地址的值和接收服务器知道的主机名不匹配,接收服务器必须(MUST)生成一个<host-unknown/>流错误条件并且终止XML流和相应的TCP连接. 打开这个连接时,如果 'from' 地址和发起服务器声明的主机名(或任何合法的域,如验证过的发起服务器的子域名或寄宿在发起服务器上的其他经过验证的域)不符,接收服务器必须(MUST)生成一个<invalid-from/>流错误条件并且终止XML流和相应的TCP连接. 在返回验证信息给接收服务器之后,授权服务器应该(SHOULD)终止它们之间的流.<br />
<br />
:10. 接收服务器通知发起服务器结果:<br />
<br />
<source lang="xml"><br />
<db:result from='Receiving Server'to='Originating Server' type='valid'/><br />
</source><br />
<br />
:注意: 在这一个点上, 连接已经由 type='valid' 确认验证是通过了,还是没通过. 如果连接是非法的,接收服务器必须(MUST)终止XML流和相应的TCP连接. 如果连接是合法的, 数据可以从发起服务器发送由接收服务器读取;在此之前,所有发送给接收服务器的XML节应该(SHOULD)被丢弃.<br />
<br />
:进一步的结果是,接收服务器已经验证了发起服务器的ID,所以通过初始化流("initial stream",例如从发起服务器到接收服务器的流)发起服务器可以发送,接收服务器可以接受XML节. 为了使用应答流("response stream",例如从接收服务器到发起服务器的流)验证实体ID,回拨必须(MUST)在相对的两个方向上都完成.<br />
<br />
:在成功的回拨协商之后, 接收服务器应该(SHOULD)接受接下来发起服务器通过当前的合法连接发送的 <db:result/> 包 (例如, 发送给子域或其他寄宿在接收服务器上的主机名的验证请求); 这在单一方向上激活了原始合法连接的 "piggybacking" .<br />
<br />
:即使回拨协商成功了, 服务器仍然必须(MUST)检查从其他服务器接收的所有XML节的'from'和'to'属性; 如果一个节不符合这些限定, 收到这些节的服务器必须(MUST)生成一个<improper-addressing/> 流错误条件并终止XML流和相应的TCP连接. 而且, 一个服务器也必须(MUST)检查从其他的有合法域名的服务器的流中收到的节的'from'属性; 如果一个节不符合这一限定, 接收节的服务器必须(MUST)生成一个 <invalid-from/> 流错误条件并终止XML流和相应的TCP连接. 所有这些检查都用来帮助防止特定的节伪造行为.<br />
<br />
==XML节==<br />
<br />
:在 TLS 协商(第五章) (如果想要), SASL 协商(第六章), 和资源绑定(第七章)(如果需要)之后, XML节就可以通过流发送了. 在'jabber:client'和'jabber:server'名字空间中定义了三种XML节: <message/>, <presence/>, 和 <iq/>. 另外, 这三种节有五种通用的属性. 这些通用属性, 加上三种节的术语,在这里定义; 更多关于和即时消息及出席信息应用相关的XML节语法详细信息在[XMPP-IM|XMPP文档列表/XMPP正式RFC标准/RFC3921]中提供.<br />
<br />
===通用属性===<br />
<br />
:以下五种属性通用于 message, presence, 和 IQ 节:<br />
<br />
====to====<br />
<br />
:'to' 属性表示节的预期接收者的JID.<br />
<br />
:在'jabber:client'名字空间中, 一个节应该(SHOULD)处理一个'to'属性, 尽管由服务器处理的从客户端发给服务器的节(如, 发送给服务器用于广播给其他实体的出席信息) 应该不(SHOULD NOT)处理'to'属性.<br />
<br />
:在'jabber:server'名字空间中, 一个节必须(MUST)处理一个'to'属性; 如果一个服务器收到一个不符合此限定的节, 它必须(MUST)生成一个<improper-addressing/>流错误条件并终止和这个非法服务器的XML流和相应的TCP连接.<br />
<br />
:如果'to'属性的值非法或无法联络, 发现这个事实的实体(通常是发送者或接收者的服务器)必须(MUST)返回一个适当的错误给发送者, 错误节的'from'属性设置成非法节的提供的'to'属性的值.<br />
<br />
====from====<br />
<br />
:'from' 属性表示发送者的 JID .<br />
<br />
:当一个服务器接收了一个符合'jabber:client'名字空间的合法流的XML节, 它必须(MUST)做以下步骤中的一步:<br />
<br />
:# 验证客户端提供的'from'属性值就是那个相关实体连接的资源<br />
:# 为生成这个节的已连接的资源增加一个'from'地址(由服务器决定是纯JID或全JID)(参见 地址的决定 Determination of Addresses (第三章第五节))<br />
:# 如果一个客户端试图发送一个XML节,而它的'from'属性和这个实体已连接的资源不符, 服务器应该(SHOULD)返回一个<invalid-from/>流错误条件给客户端. 如果一个客户端试图通过一个尚未验证的流发送一个XML节, 服务器应该(SHOULD)返回一个<not-authorized/>流错误条件给客户端. 如果生成了, 所有这些条件必须(MUST)导致流的关闭和相应的TCP连接的终止; 这有助于防止不诚实的客户的拒绝服务攻击.<br />
<br />
:当一个服务器从服务器自身生成一个节用于一个已连接的客户端的信息发布(例如, 在服务器为客户端提供数据存储服务的情况下), 这个节必须(MUST) (1) 不包含 'from' 属性 或 (2) 包含一个'from'属性,它的值是这个账号的纯 JID (<node@domain>) 或 客户端的全 JID (<node@domain/resource>). 如果节不是由服务器自身生成的,那么一个服务器不能(MUST NOT)发送不带'from'属性的节. 当一个客户端接收到一个不包含'from'属性的节, 它必须(MUST)认为这个节是从客户端连接的服务器发来的.<br />
<br />
:在'jabber:server'名字空间, 一个节必须(MUST)处理一个'from'属性; 如果一个服务器接收到一个不符合此限定的节, 它必须(MUST)生成一个<improper-addressing/>流错误条件. 而且, 'from'属性的 JID值的域名ID部分必须(MUST)和以SASL协商连接或以回拨协商连接的发送服务器的主机名(或任何合法的域,如发送服务器主机名的合法子域,或其他寄宿在发送服务器上的合法域)吻合; 如果一个服务器接收到的节不符合此限定, 它必须(MUST)生成一个<invalid-from/>流错误条件. 所有这些条件都必须(MUST)导致流的关闭和相应的TCP连接的终止; 这有助于防止不诚实的客户端发起的拒绝服务攻击.<br />
<br />
====id====<br />
<br />
:可选的'id' 属性可以(MAY)用于为节的内部跟踪发送实体,从IQ节 语义来讲,就是通过发送和接收这些节来跟踪“请求-应答”型的交互行为。这个可选的(OPTIONAL)'id'属性值在一个域或一个流中是全局唯一的。IQ节语义学中对此有附加限定;见IQ Semantics (第九章第二节第三小节)。<br />
<br />
====type====<br />
<br />
:'type' 属性指明消息、出席信息或IQ节的意图或上下文的详细信息。'type'属性所允许的值依据节的类型是消息、出席信息还是IQ而有很大不同; 用于消息和出席信息节的值定义在即时消息和出席信息应用中,所以在[XMPP-IM|XMPP文档列表/XMPP正式RFC标准/RFC3921]中定义,反之用于IQ节的值定义了在一个 请求-应答 的“会话”中IQ节的角色,所以定义在IQ语义学中(第九章第二节第三小节)。 所有三种节的通用'type'值是"error";见Stanza Errors (第九章第三节)。<br />
<br />
====xml:lang====<br />
<br />
:如果一个节包含用于显示给人human user看的XML字符数据(在RFC 2277中有所解释[CHARSET],"internationalization is for humans"),这个节应该(SHOULD)处理一个'xml:lang'属性(定义在第二章第十二节[XML])。 'xml:lang'属性的值指明任何一个人类可读的XML字符数据的缺省语言, 它可以(MAY)被特定的子元素的'xml:lang'值重载。 如果一个节不处理一个'xml:lang'属性,一个实现必须(MUST)认为缺省的语言就是流属性中定义的语言(第四章第四节). 'xml:lang'属性值必须(MUST)是一个 NMTOKEN 并且必须(MUST)遵守 RFC 3066 [LANGTAGS]中定义的格式. <br />
<br />
===基本语义学===<br />
<br />
====消息语义学====<br />
<br />
:<message/>节类型可以被看作是一个"push"机制用于一个实体推送信息给另一个实体,类似发生在email系统中的通信. 所有消息节应该(SHOULD)处理一个表明预定的消息接收者的'to'属性;接收了这样一个节之后,一个服务器应该(SHOULD)路由或递送它给预定的接收者(见 Server Rules for Handling XML Stanzas (第十章)的XML节相关的通用路由和递送规则).<br />
<br />
====出席信息语义学====<br />
<br />
:<presence/> 元素可以被看作一个基本的广播或“出版-订阅”机制,用于多个实体接收某个已订阅的实体的信息(在这里,是网络可用性信息). 通常,一个发行实体应该(SHOULD)不带'to'属性发送一个出席信息,这时这个实体所连接的服务器应该(SHOULD)广播或复用(multiplex)那个节给所有订阅的实体.无论如何,一个发行实体也可以(MAY)带'to'属性发送一个出席信息节,这时服务器应该(SHOULD)路由或递送这个节给预定的接收者.见 Server Rules for Handling XML Stanzas (第十章)的XML节相关的通用路由和递送规则,以及[XMPP-IM|XMPP文档列表/XMPP正式RFC标准/RFC3921]中即时消息和出席信息应用中出席信息的特定规则.<br />
<br />
====IQ语义学====<br />
<br />
:信息/查询(Info/Query),或曰IQ,是一个 请求-回应 机制,某些情况下类似[HTTP].IQ语义学使一个实体能够向另一个实体做出请求并做出应答. 请求和应答所包含的数据定义在IQ元素的一个直接的子元素的名字空间声明中, 并且由请求实体用'id'属性来跟踪这一交互行为. 因而,IQ交互伴随着一个结构化的数据交换的通用模式例如 get/result 或 set/result (尽管有时候会以一个错误信息应答某个请求):<br />
<br />
:以下是IQ的流程图,参见附件iq.png<br />
<br />
{image:img=iq}<br />
<br />
请求实体 响应实体<br />
---------- ----------<br />
| |<br />
| <iq type='get' id='1'> |<br />
| ------------------------> |<br />
| |<br />
| <iq type='result' id='1'> |<br />
| <------------------------ |<br />
| |<br />
| <iq type='set' id='2'> |<br />
| ------------------------> |<br />
| |<br />
| <iq type='error' id='2'> |<br />
| <------------------------ |<br />
| |<br />
<br />
:为了强制执行这些语义学,要应用以下规则:<br />
<br />
:1. 对于IQ节来说'id'属性是必需的(REQUIRED).<br />
:2. 对于IQ节来说'type'属性是必需的(REQUIRED). 它的值必须(MUST)是以下之一:<br />
::* get -- 这个节是一个对信息或需求的请求.<br />
::* set -- 这个节提供需要的数据, 设置新的值, 或取代现有的值.<br />
::* result -- 这个节是一个对一个成功的 get 或 set 请求的应答.<br />
::* error -- 发生了一个错误,关于处理或递送上次发送的 get 或 set的(参见 节错误 Stanza Errors(第九章第三节)).<br />
:3. 一个接收到"get" 或 "set" 类型的IQ请求的实体必须(MUST)回复一个"result"或"error"类型的IQ应答(这个应答必须(MUST)保留相关请求的'id'属性).<br />
:4. 一个接收到"result"或"error"类型的IQ节的实体不能(MUST NOT)再发送更多的"result"或"error"类型的IQ应答; 无论如何, 如上所述, 请求实体可以(MAY)发送另一个请求(如, 一个"set"类型的IQ,通过get/result对提供查询(discovery)所需的信息).<br />
:5. 一个"get" 或 "set" 类型的IQ节必须(MUST)包含并只包含一个子元素指明特定请求或应答的语义.<br />
:6. 一个"result"类型的IQ节必须(MUST)包含零或一个子元素.<br />
:7. 一个"error"类型的IQ节应该(SHOULD)包含和"get"或"set"相关联的那个子元素并且必须(MUST)包含一个<error/>子元素;详细信息,见Stanza Errors (第九章第三节).<br />
<br />
===节错误===<br />
<br />
:节相关的错误的处理方式类似流错误(第四章第七节). 无论如何, 不像流错误, 节错误是可恢复的;所以错误节包含了暗示原来的发送者可以采取什么行动来补救这个错误.<br />
<br />
====规则====<br />
<br />
:以下规则适用于节相关的错误:<br />
<br />
:* 接收或处理实体察觉到一个节相关的错误条件时应该(MUST)返回给发送实体一个同类型的节(消息,出席信息,或IQ),这个节的'type'属性值则设置为"error"(这里这样的节称之为"error stanza").<br />
<br />
:* 生成一个错误节的实体应该(SHOULD)包含原来发送的XML,这样发送者可以检查它,并且如果必要,在尝试重新发送之前纠正它.<br />
<br />
:* 一个错误节必须(MUST)包含一个<error/>子元素.<br />
<br />
:* 如果'type'属性值不是"error"(或没有"type"属性),节不能(MUST NOT)包含一个<error/>子元素.<br />
<br />
:* 接收到一个错误节的实体不能(MUST NOT)应答这个节更多的错误节; 这有助于防止死循环.<br />
<br />
====语法====<br />
<br />
:节相关错误的语法如下:<br />
<br />
<source lang="xml"><br />
<stanza-kind to='sender' type='error'><br />
[RECOMMENDED to include sender XML here]<br />
<error type='error-type'><br />
<defined-condition xmlns='urn:ietf:params:xml:ns:xmpp-stanzas'/><br />
<text xmlns='urn:ietf:params:xml:ns:xmpp-stanzas' xml:lang='langcode'><br />
OPTIONAL descriptive text<br />
</text><br />
[OPTIONAL application-specific condition element]<br />
</error><br />
</stanza-kind><br />
</source><br />
<br />
:stanza-kind 是 message, presence, 或 iq 中的一个.<br />
<br />
:<error/> 元素的'type'属性值必须(MUST)是以下之一:<br />
<br />
:* cancel -- 不重试(这个错误是不可恢复的)<br />
<br />
:* continue -- 继续进行(这个条件只是一个警告)<br />
<br />
:* modify -- 改变数据之后重试<br />
<br />
:* auth -- 提供证书之后重试<br />
<br />
:* wait -- 等待之后重试(错误是暂时的)<br />
<br />
:<error/>元素:<br />
<br />
:* 必须(MUST)包含一个子元素,符合以下定义的节错误条件之一;这个元素(MUST)符合'urn:ietf:params:xml:ns:xmpp-stanzas'名字空间.<br />
<br />
:* 可以(MAY)包含一个<text/>子元素容纳XML字符数据用来描述错误的更多细节;这个元素必须(MUST)符合'urn:ietf:params:xml:ns:xmpp-stanzas'名字空间并且应该(SHOULD)处理'xml:lang'属性.<br />
<br />
:* 可以(MAY)包含一个应用程序定义的错误条件子元素;这个元素必须(MUST)符合一个应用程序定义的名字空间,并且它的结构由这个名字空间定义.<br />
<br />
:<text/>元素是可选的(OPTIONAL).如果包含它,它应该(SHOULD)仅用于提供描述或诊断信息以补充一个已定义的条件或应用程序定义的条件. 它不应(SHOULD NOT)被应用程序认为是一个程序性的. 它不应(SHOULD NOT)被用作向一个使用者展示的错误信息,但是可以(MAY)展示除条件元素(或元素们)相关的错误信息之外的信息.<br />
<br />
:最后,为了维护向后兼容性, 这个schema (定义在[XMPP-IM|XMPP文档列表/XMPP正式RFC标准/RFC3921])允许可选的在<error/>元素中包含一个("code")属性.<br />
<br />
====已定义的条件====<br />
<br />
:以下条件定义用于节错误.<br />
<br />
:* <bad-request/> -- 发送者发送的XML是不规范的或不能被处理(例如 一个IQ节包含了一个未被承认的'type'属性值); 相关的错误类型应该(SHOULD)是"modify".<br />
<br />
:* <conflict/> -- 不同意访问,因为相同的名字或地址已存在一个资源或会话;相关的错误类型应该( SHOULD)是"cancel".<br />
<br />
:* <feature-not-implemented/> -- 请求的特性未被接收者或服务器实现所以不能处理;相关的错误类型应该(SHOULD)是"cancel".<br />
<br />
:* <forbidden/> -- 请求实体没有必需的许可来执行这一动作;相关的错误类型应该(SHOULD)是"auth".<br />
<br />
:* <gone/> -- 接收者或服务器无法再以这个地址进行联系(错误节可以(MAY)在<gone/>元素的XML字符数据中包含一个新的地址);相关的错误类型应该(SHOULD)是"modify".<br />
<br />
:* <internal-server-error/> -- 服务器不能处理节,因为错误的配置或其他未定义的内部服务器错误;相关的错误类型应该(SHOULD)是"wait".<br />
<br />
:* <item-not-found/> -- JID地址或申请的条目无法找到;相关的错误类型应该(SHOULD)是"cancel".<br />
<br />
:* <jid-malformed/> -- 发送的实体提供的XMPP地址或与之通信的某个XMPP地址(如一个'to'属性值)或这个XMPP地址中的一部分(如一个资源ID)不符合寻址方案的语法(第三章);相关的错误类型应该(SHOULD)是"modify".<br />
<br />
:* <not-acceptable/> -- 接收者或服务器理解这个请求但是拒绝处理,因为它不符合某些接收者或服务器定义的标准(例如,一个关于消息中可接收的单词的本地策略);相关错误类型应该(SHOULD)是"modify".<br />
<br />
:* <not-allowed/> -- 接收者或服务器不允许任何实体执行这个动作;相关错误类型应该(SHOULD)是"cancel".<br />
<br />
:* <not-authorized/> -- 在被允许执行某个动作之前发送者必须提供适当的证书,或已提供了不正确的证书;相关错误类型应该(SHOULD)是"auth".<br />
<br />
:* <payment-required/> -- 请求实体未被授权访问请求的服务,因为需要付费;相关错误类型应该(SHOULD)是"auth".<br />
<br />
:* <recipient-unavailable/> -- 预定的接收者暂时不可用;相关错误类型应该(SHOULD)是"wait"(注意: 如果这样做会导致泄露预定接收者的网络可用性给一个未被授权了解此信息的实体,应用程序不应该(MUST NOT)返回这个错误).<br />
<br />
:* <redirect/> -- 接收者或服务器重定向这个请求信息到另一个实体,通常是暂时的(这个错误节应该 (SHOULD)在<redirect/>元素的XML字符数据中包含一个预备的地址,它必须(MUST)是一个合法的JID); 相关的错误类型应该(SHOULD)是"modify".<br />
<br />
:* <registration-required/> -- 请求实体未被授权访问请求的服务,因为需要注册;相关错误类型应该(SHOULD)是"auth".<br />
<br />
:* <remote-server-not-found/> -- 在预定的接收者的全部或部分JID中的一个远程服务器或服务不存在;相关错误类型应该(SHOULD)是"cancel".<br />
<br />
:* <remote-server-timeout/> -- 在预定的接收者(或需要完成的一个申请)的全部或部分JID中的一个远程服务器或服务无法在合理的时间内联系到;相关错误类型应该(SHOULD)是"wait".<br />
<br />
:* <resource-constraint/> -- 服务器或接收者缺乏足够的系统资源来服务请求;相关错误类型应该(SHOULD)是"wait".<br />
<br />
:* <service-unavailable/> -- 服务器或接收者目前无法提供被请求的服务;相关错误类型应该(SHOULD)是"cancel".<br />
<br />
:* <subscription-required/> -- 请求实体未被授权访问能请求的服务,因为需要订阅;相关错误类型应该(SHOULD)是"auth".<br />
<br />
:* <undefined-condition/> -- 错误条件不是本列表中定于的其他条件之一;任何错误类型可能和这个条件有关,并且它应该(SHOULD)仅用于关联一个应用程序定义的条件.<br />
<br />
:* <unexpected-request/> -- 接收者或服务器理解这个请求但是不希望是在这个时间(比如,请求的顺序颠倒);相关错误类型应该(SHOULD)是"wait".<br />
<br />
====应用程序定义条件====<br />
<br />
:大家知道,一个应用程序可以(MAY)通过在错误元素里包含一个适当名字空间的字元素来提供应用程序定义的节错误信息. 应用程序定义的元素应该(SHOULD)补充或进一步限定一个已定义的元素. 因而,<error/>元素将包含两个或三个子元素:<br />
<br />
<source lang="xml"><br />
<iq type='error' id='some-id'><br />
<error type='modify'><br />
<bad-request xmlns='urn:ietf:params:xml:ns:xmpp-stanzas'/><br />
<too-many-parameters xmlns='application-ns'/><br />
</error><br />
</iq><br />
<message type='error' id='another-id'><br />
<error type='modify'><br />
<undefined-condition xmlns='urn:ietf:params:xml:ns:xmpp-stanzas'/><br />
<text xml:lang='en' xmlns='urn:ietf:params:xml:ns:xmpp-stanzas'><br />
Some special application diagnostic information...<br />
</text><br />
<special-application-condition xmlns='application-ns'/><br />
</error><br />
</message><br />
</source><br />
<br />
==服务器处理XML节的规则==<br />
<br />
:兼容的服务器实现必须(MUST)确保两个实体之间的XML节按次序处理.<br />
<br />
:在按次序处理的需求之外, 每个服务器实现将包含它自己的递送树"delivery tree"以处理它接收到的节.这个树决定一个节是否需要路由到其他域, 在内部处理, 还是递送到和一个已连接的节点相关的资源. 以下规则适用:<br />
<br />
===没有'to'地址===<br />
<br />
:如果这个节没有'to'属性, 服务器应该(SHOULD)为发送它的实体处理这个节. 因为所有从其他服务器收到的节必须(MUST)拥有'to'属性, 这个规则仅适用于从一个连接到这台服务器的已注册实体(如一个客户端)收到的节.如果这个服务器收到一个没有'to'属性的出席信息节, 服务器应该(SHOULD)向那些订阅了这个发送实体的出席信息的所有实体广播它, 如果可能的话(即时消息和出席信息应用程序中出席信息广播的语义定义在[XMPP-IM|XMPP文档列表/XMPP正式RFC标准/RFC3921]). 如果服务器接收到一个类型为"get" 或 "set" 的没有'to'属性的节并且它理解这个节的名字空间下的内容, 它必须(MUST)为这个发送实体处理节(在这里"process"的含义是由相关的名字空间的语义所决定的)或返回一个错误给发送实体.<br />
<br />
===外部域===<br />
<br />
:如果'to'属性中的JID的域ID部分的主机名和服务器自身或其子域配置的主机名不匹配, 服务器应该(SHOULD)路由这个节到外部域(取决于本地服务规定或安全策略关于域间通信的规定).有两种可能的情况:<br />
<br />
::- 一个服务器之间的流已经存在于两个域之间: 发送者的服务器通过这个已存在的流为这个外部域路由这个节到授权服务器<br />
<br />
::- 两个域之间不存在服务器间的流: 发送者服务器 (1) 解析这个外部域的主机名(定义在服务器间的通信Server-to-Server Communications (第十四章第四节)), (2) 在两个域之间进行服务器到服务器的流协商(定义在 Use of TLS (第五章) 和 Use of SASL (第六章)), 然后 (3) 通过这个新建的流为外部域路由这个节到授权服务器<br />
<br />
:如果路由到接收者的服务器不成功, 发送者的服务器必须(MUST)返回一个错误给发送者; 如果接收者的服务器联系上了但是从接收者的服务器递送到接收者不成功, 接收者服务器必须(MUST)通过发送者的服务器返回一个错误给发送者.<br />
<br />
===子域===<br />
<br />
:如果'to'属性中的JID的域ID部分的主机名和服务器自身配置的主机名的一个子域名匹配,服务器必须(MUST)自己处理这个节或路由这个节到专门负责这个子域的特定服务(如果子域被配置了),或者返回一个错误给发送者(如果子域没有配置).<br />
<br />
===纯粹的域或特定的资源===<br />
<br />
:如果'to'属性中的JID的域ID部分的主机名和服务器自身配置的主机名本身匹配,并且'to'属性中的JID类型是<domain> 或 <domain/resource>, 服务器(或其中定于的资源)必须(MUST)根据节的类型适当的处理这个节或返回一个错误节给发送者.<br />
<br />
===同一域中的节点===<br />
<br />
:如果'to'属性中的JID的域ID部分的主机名和服务器自身配置的主机名本身匹配,并且'to'属性中的JID类型是<node@domain> 或 <node@domain/resource>, 服务器应该(SHOULD)递送这个节到节的'to'属性中的JID所指明的预定的接收者. 以下规则适用:<br />
<br />
:# 如果这个JID包含一个资源ID(例如, 格式是<node@domain/resource>)并且存在一个连接的资源符合这个全JID, 接收者服务器应该(SHOULD)递送这个节给正确符合这个资源ID的流或会话.<br />
:# 如果这个JID包含一个资源ID(例如, 格式是<node@domain/resource>)并且不存在一个连接的资源符合这个全JID, 接收者服务器应该(SHOULD)返回一个<service-unavailable/> 节错误给发送者.<br />
:# 如果这个JID的格式是<node@domain>并且存在至少一个此节点的连接资源, 接收服务器应该( SHOULD)递送这个节给至少其中一个已连接的资源, 依据应用程序定义的规则(一系列即时消息和出席信息应用程序的递送规则定义在[XMPP-IM|XMPP文档列表/XMPP正式RFC标准/RFC3921]).<br />
<br />
==XMPP中的XML用法==<br />
<br />
===限制===<br />
<br />
:XMPP是一个简单的流式XML元素的专用协议用于接近实时地交换结构化信息. 因为XMPP不需要任意的解析和所有的XML文档, 所以XMPP不需要支持[XML]的所有功能. 特殊的, 适用以下限制.<br />
<br />
:关于XML生成, 一个XMPP实现不能(MUST NOT)在XML流中注入以下任何东西:<br />
<br />
:* 注释 (第二章第五节[XML])<br />
<br />
:* 处理指示(第二章第六节 同上)<br />
<br />
:* 内部或外部的 DTD 子集 (第二章第八节 同上)<br />
<br />
:* 内部或外部的实体参考 (第四章第二节 同上) 除了预定实体以外(第四章第六节 同上)<br />
<br />
:* 字符数据或属性值包含和预定实体列表中吻合的未逃逸的unescaped字符(第四章第六节 同上); 这些字符必须(MUST)逃逸<br />
<br />
:关于XML处理, 如果一个XMPP实现接收到这些受限的XML数据,它必须(MUST)忽略这些数据.<br />
<br />
===XML 名字空间的名字和前缀===<br />
<br />
:XML名字空间[XML-NAMES]为所有XMPP兼容的XML建立数据所有权的严格界限. 这个名字空间的基本功能是把结构上混合在一起的XML元素区分出不同的词汇. 确保XMPP兼容的XML有名字空间的感知能力使得任何允许的XML可以被结构化的混合到任何XMPP数据元素中. XML名字空间的名字和前缀的规则在下一小节中.<br />
<br />
====流名字空间====<br />
<br />
:在所有的XML流头中必须声明一个流名字空间. 流名字空间必须(MUST)是 'http://etherx.jabber.org/streams'. 元素名<stream/>和它的<features/>和<error/>子元素必须(MUST)在所有实例中符合这个流名字空间前缀. 一个实现应该(SHOULD)只为这些元素生成'stream:'前缀, 并且由于历史原因可以(MAY)只接受'stream:'前缀.<br />
<br />
====缺省名字空间====<br />
<br />
:在所有的XML流中必须声明一个缺省的流名字空间用于定义允许的流根元素的一级子元素. 这个名字空间声明对于初始化流和应答流必须(MUST)是相同的使得双方的流都是合格一致的. 缺省的名字空间声明适用于流和所有在流中发送的节(除非由流名字空间或回拨名字空间的前缀显式的符合另一个名字空间).<br />
<br />
:一个服务器实现必须(MUST)支持以下两个缺省名字空间(由于历史原因, 一些实现可能(MAY)只支持这两个缺省名字空间):<br />
<br />
:* jabber:client -- 当流用于客户端和服务器的通信时声明这个缺省名字空间<br />
<br />
:* jabber:server -- 当流用于两个服务器间的通信时声明这个缺省名字空间<br />
<br />
:一个客户端实现必须(MUST)支持'jabber:client'缺省名字空间,并且由于历史原因可以(MAY)只支持这个缺省名字空间.<br />
<br />
:如果缺省名字空间是'jabber:client'或'jabber:server',一个实施不能(MUST NOT)在这个名字空间下为元素生成名字空间前缀. 一个实现不应该(SHOULD NOT)按照元素的内容(可能和流相反)生成不同于'jabber:client'和'jabber:server'名字空间前缀.<br />
<br />
:注意: 'jabber:client' 和 'jabber:server' 名字空间接近于相同但是用于不同的上下文(客户端服务器通信用'jabber:client' 而服务器间通信用'jabber:server'). 这两者之间仅有的不同在于在'jabber:client'中被发送的节中'to'和'from'属性是可选的(OPTIONAL),而在'jabber:server'中被发送的节中它们是必需的(REQUIRED). 如果兼容的实施接受一个符合'jabber:client'或'jabber:server'名字空间的流, 它必须(MUST)支持通用属性(第九章第一节)和三个核心节类型(message, presence, 和IQ)的基本语义(第九章第二节).<br />
<br />
====回拨名字空间====<br />
<br />
:所有用于服务器回拨的(第八章)元素都必须声明一个回拨名字空间. 回拨名字空间的名字必须(MUST)是'jabber:server:dialback'. 所有符合此名字空间的元素必须(MUST)有前缀. 一个实现应该(SHOULD)只为这些元素生成'db:'前缀并且只可以(MAY)接受'db:'前缀.<br />
<br />
===确认===<br />
<br />
:除了注意'jabber:server'名字空间中关于节中'to'和'from'地址的规定,一个服务器不需要为转发到客户端或其他服务器负责检查XML元素;一个实现可以(MAY)选择仅提供有效数据元素但这是可选的(OPTIONAL)(尽管一个实现不能(MUST NOT)接受不规范的XML). 客户端不应该(SHOULD NOT)滥用发送不符合schema的数据的能力, 并且应该(SHOULD)忽略接收到的XML流中任何和schema不一致的元素或属性值. XML流和节的有效性确认是可选的(OPTIONAL),并且在这里提到的schemas仅用于描述的用途.<br />
<br />
===文本声明的包含===<br />
<br />
:实现应该(SHOULD)在发送一个流头信息之前发送一个文本声明. 应用程序必须(MUST)遵守[XML]中关于环境(那里对文本声明做了规定)的规则.<br />
<br />
===字符编码===<br />
<br />
:实现必须(MUST)支持通用字符集Universal Character Set (ISO/IEC 10646-1 [UCS2])字符到UTF-8(RFC 3629 [UTF-8])的转换, 必须符合 RFC 2277 [CHARSET]. 实现不能(MUST NOT)试图使用任何其他的编码.<br />
<br />
==核心的兼容性要求==<br />
<br />
:本章总结了可扩展的消息和出席信息协议中的某些方面,为了实施的兼容性,它们必须(MUST)被服务器和客户端支持,当然协议的其他方面也应该(SHOULD)被支持. 为了兼容的目的, 我们在核心协议(它必须(MUST)被任何服务器或客户端支持, 无论是什么特定的应用)和即时消息协议(仅仅是在核心协议之上的即时消息和出席信息应用必须(MUST)支持它)之间划了一个级别. 在本章中定义了所有服务器和客户端的兼容性要求; 即时消息服务器和客户端的兼容性要求在[XMPP-IM|XMPP文档列表/XMPP正式RFC标准/RFC3921]的相关章节中定义.<br />
<br />
===服务器===<br />
<br />
:除了所有已定义的关于安全, XML使用, 和国际化的要求之外, 一个服务器还必须(MUST)支持以下核心协议以保证兼容性:<br />
<br />
:* 在地址中应用[STRINGPREP] 的 [NAMEPREP], Nodeprep (附录 A),和 Resourceprep (附录 B) profiles (包括确保域ID是[IDNA]中定义的国际化域名)<br />
<br />
:* XML流(第四章), 包括Use of TLS(第五章), Use of SASL(第六章), 和Resource Binding (第七章)<br />
<br />
:* 三个在stanza semantics(第九章第二节)中已定义的节类型(即,<message/>, <presence/>, 和<iq/>)的基本语义<br />
<br />
:* 生成错误的语法及相关的流, TLS, SASL, 和 XML节的语义<br />
<br />
:另外, 一个服务器可以(MAY)支持以下核心协议:<br />
<br />
:* 服务器回拨 (第八章)<br />
<br />
===客户端===<br />
<br />
:一个客户端必须(MUST)支持以下核心协议以满足兼容性:<br />
<br />
:* XML流(第四章), 包括Use of TLS(第五章), Use of SASL(第六章), 和Resource Binding (第七章)<br />
<br />
:* 三个在stanza semantics(第九章第二节)中已定义的节类型(即,<message/>, <presence/>, 和<iq/>)的基本语义<br />
<br />
:* 处理(并且, 如果可能, 生成) 错误的语法及相关的流, TLS, SASL, 和 XML节的语义<br />
<br />
:另外, 一个客户端应该(SHOULD)支持以下核心协议:<br />
<br />
:* 地址的生成应用[STRINGPREP] 的 [NAMEPREP], Nodeprep (附录 A),和 Resourceprep (附录 B) profiles <br />
<br />
==国际化事项==<br />
<br />
:XML流在Character Encoding(第十一章第五节)中定义为必须(MUST)被编码成UTF-8. 在Stream Attributes(第四章第四节)中特别定义了, 一个XML流应该(SHOULD)包含一个'xml:lang'属性,它被认为是通过这个用于人类用户解读的流发送的任何XML字符数据的缺省语言. 在 xml:lang (第九章第一节第五小节)特别定义了, 如果一个XML节是用来给人类用户解读,这个节应该(SHOULD)包含一个'xml:lang'属性. 服务器在为连接的实体路由或递送节的时候应该(SHOULD)应用缺省的'xml:lang'属性, 并且不能(MUST NOT)修改或删除它从其他实体收到的节的'xml:lang'属性.<br />
<br />
==安全性事项==<br />
<br />
===高安全性===<br />
<br />
:为了XMPP通信的目的(客户端-服务器 和 服务器-服务器), "高安全性"条款谈的是相互验证和完整性检查安全性技术的使用; 特别是, 当使用基于证书的验证来提供高安全性, 应该( SHOULD)建立一个带外的信任链,尽管一个共享签名证书可能允许以前不知道的证书在带内建立信任关系. 参见以下第十四章第二节关于证书确认程序.<br />
<br />
:实施必须(MUST)支持高安全性. 服务提供者应该(SHOULD)基于本地安全策略使用高安全性.<br />
<br />
===证书确认===<br />
<br />
:当一个XMPP点和另一个XMPP点安全的地通信, 它必须(MUST)确认对方终端的证书.有三种可能的情况:<br />
<br />
:情形 #1: 点包含一个终端实体证书,以根证书的证书链中一环出现(见[X509]中的第六章第一节).<br />
<br />
:情形 #2: 点的证书由一个对方不知道的证书授权.<br />
<br />
:情形 #3: 点的证书由自己签名.<br />
<br />
:在情形#1, 确认方必须(MUST)做以下两条之一:<br />
<br />
:# 根据[X509]的规则确认对方证书.然后证书应该(SHOULD)被对方接下来在[HTTP-TLS]中描述的规则反向确认预期的身份。但如果"xmpp"是subjectAltName扩展类型,则必须(MUST)使用证书中的显示的身份。如果这两项检查之一失败,用户导向的客户端必须(MUST)通知用户(客户端可以(MAY)给用户机会继续连接)或以一个坏证书的错误终止连接。自动客户端应该(SHOULD)终止连接(以一个坏证书错误)并在适当的日志中记录这个错误。自动客户端可以(MAY)提供一个配置设置成禁止检查,但同时必须(MUST)提供一个激活检查的配置。<br />
:# 点应该(SHOULD)出示证书给一个用户用于批准,包括完整的证书链.点必须(MUST)缓存这个证书(或一些其他不会忘记的表达方式比如一个哈希值).在将来的连接中,点必须(MUST)展示相同的证书并且如果改变了证书必须(MUST)通知用户.<br />
<br />
:在情形#2 和情形#3, 实现应该(SHOULD)执行上述第二条.<br />
<br />
===客户端-服务器通信===<br />
<br />
:一个兼容的客户端实现必须(MUST)支持TLS和SASL用于连接到服务器.<br />
<br />
:用于加密XML流的TLS协议(在 Use of TLS(第五章)定义)提供可信的机制帮助确保机密性和实体之间数据交换的完整性.<br />
<br />
:用于验证XML流的SASL协议(在 Use of SASL(第六章)定义)提供可靠的机制用于确认一个连接到服务器的客户端确实是它自己所声明的那个客户端.<br />
<br />
:服务器宣称的DNS主机名被解析之前,客户端-服务器通信不能(MUST NOT)继续进行。应该首先尝试解析[SRV]记录,其服务名为"xmpp-client",协议名为"tcp",整个资源记录类似"_xmpp-client._tcp.example.com."(使用字符"xmpp-client"表示服务ID是经过IANA注册).如果SRV查找失败,退而求其次,将查找一个正规的IPv4/IPv6地址记录来决定IP地址,使用"xmpp-client"端口5222,这个端口是在IANA注册了的。<br />
<br />
:客户端的IP地址和访问方法不能(MUST NOT)被服务器公开, 也不能被被任何原始服务器之外的服务器索取。这帮助保护客户端的服务器避免受到直接攻击(译者注:似乎应该是客户避免受到直接攻击,但原文如此)或被第三方知道它的身份。<br />
<br />
===服务器-服务器通信===<br />
<br />
:一个兼容的服务器实现必须(MUST)支持TLS和SASL,用于域间的通信.因为历史原因,一个兼容的实施也应该(SHOULD)支持服务器回拨(第八章).<br />
<br />
:因为服务提供者是一个策略问题,对于任何给定域和其他域的通信中,它是可选的(OPTIONAL),服务器之间的通信可以(MAY)被任何特定部署的管理员禁止。如果一个特殊的域允许域间的通信,它应该(SHOULD)允许高安全性。<br />
<br />
:管理员可能想在服务器间使用SASL来通信,以确保双方的验证和保密性(比如在机构的私有网络).兼容实施应该(SHOULD)为这个目的支持SASL.<br />
<br />
:服务器宣称的DNS主机名被解析之前,服务器-服务器通信不能(MUST NOT)继续进行。应该首先尝试解析[SRV]记录,其服务名为"xmpp-server",协议名为"tcp",整个资源记录类似"_xmpp-server._tcp.example.com."(使用字符"xmpp-server"表示服务ID是经过IANA注册的,注意要用"xmpp-server"取代以前用的"jabber",因为以前的用法不符合[SRV]标准;希望保持向后兼容的实现可以继续查找或应答"jabber"服务ID).如果SRV查找失败,退而求其次,将查找一个正规的IPv4/IPv6地址记录来决定IP地址,使用"xmpp-server"端口5269,这个端口是在IANA注册了的。<br />
<br />
:服务器回拨防止域欺骗,从而使得伪造XML节更为困难.它和SASL和TLS不一样,它不是一个用于验证、安全或加密服务器之间的流的机制, 所以只是服务器身份的微弱确认而已。而且除非它使用了DNSSec [DNSSEC]否则它 容易受到DNS中毒攻击,即使DNS信息是正确的,如果攻击者劫持了远程域,回拨也不能防止它的攻击.需要健壮的安全性的域应该(SHOULD)使用TLS和SASL.如果服务器间的验证使用了SASL,回拨就不应该(SHOULD NOT)使用了,因为它是多余的.<br />
<br />
===层的次序===<br />
<br />
:协议中的层的次序必须(MUST)如下堆积:<br />
<br />
:# TCP<br />
:# TLS<br />
:# SASL<br />
:# XMPP<br />
<br />
:这个次序的原理是,[TCP]是基于连接的层,被所有使用,所以处于最上层, [TLS]经常是由操作系统层提供,[SASL]经常由应用程序层提供, XMPP则是应用程序本身.<br />
<br />
===缺乏绑定到TLS的SASL通道===<br />
<br />
:SASL构架不提供一个机制来绑定SASL验证到一个提供机密性和完整性保护的安全层。这一通道绑定"channel binding"的缺乏阻碍了SASL确认低层安全性所绑定的源和目标终端和SASL所验证的结果是否一致。如果终端不一致, 低层安全性不能被信任用来保护SASL验证的实体之间的数据传输。在这种情况下,一个SASL安全层进行握手的时候应该有效的忽略低层安全性的存在。<br />
<br />
===强制实现的技术===<br />
<br />
:最低要求, 所有实现必须(MUST)支持以下机制:<br />
<br />
::对于验证: SASL [DIGEST-MD5] 机制<br />
<br />
::对于机密性: TLS (使用 TLS_RSA_WITH_3DES_EDE_CBC_SHA 密码)<br />
<br />
::对于两者: TLS 加 SASL EXTERNAL(使用 TLS_RSA_WITH_3DES_EDE_CBC_SHA 密码支持客户端证书)<br />
<br />
===防火墙===<br />
<br />
:使用XMPP通信通常是通过[TCP]连接到5222端口(客户端-服务器)或5269端口(服务器-服务器), 正如在IANA注册的那样(见 IANA Considerations (第十五章)). 使用这些广为人知的端口允许管理员很容易的通过一般的防火墙来激活或禁止XMPP活动.<br />
<br />
===在SASL中使用base64===<br />
<br />
:客户端和服务器都必须(MUST)确认在SASL协商中收到的任何[BASE64]数据. 一个实现必须(MUST)拒绝(不是忽略)任何非显式允许base64字母的字符串; 这有助于预防建立隐蔽通道泄漏信息的行为。一个实现不能(MUST NOT)在非法输入处中断,如果那个('=')被包含在一些和最后的数据字符(如, "=AAA" or "BBBB=CCC")不同的东西里面,必须(MUST)拒绝接下来的任何包含('=')的base64字符;这有助于防止对这个实现的缓存溢出攻击和其他攻击。Base 64编码从外表看隐藏了容易辨认的信息,例如密码,但是不提供任何算法机密性。Base 64编码必须(MUST)按照RFC 3548[BASE64]第三章的定义执行。<br />
<br />
===Stringprep Profiles===<br />
<br />
:为了处理域ID,XMPP使用了[STRINGPREP]中的[NAMEPREP] profile; 和Nameprep有关的安全性考虑, 参考[NAMEPREP]中的相关章节.<br />
<br />
:另外, XMPP 定义了两个[STRINGPREP]的 profiles: 用于node identifiers的Nodeprep(附录 A)和用于resource identifiers的Resourceprep(附录 B).<br />
<br />
:Unicode 和 ISO/IEC 10646 集有许多字符看起来相似. 在许多时候, 安全协议的使用者可能看起来吻合,比如当比较信任的第三方的名字的时候. 因为没有很多上下文的时候不可能映射看起来相似的字符,比如知道所用的字符集, stringprep不匹配相似字符串,也不因为一些字符串象看起来象别的字符串而禁止它们.<br />
<br />
:一个节点ID可能被作为一个实体的XMPP地址的一部分. 一个通常的用途是作为一个即时消息用户的用户名;另一个用途是作为一个多用途聊天室的名字; 很多其他种类的实体可能使用节点ID作为他们的地址的一部分。 这些服务的安全性可能会受到国际化节点ID的不同表达的威胁;例如, 一个用户键入一个单独的国际化的节点ID可能访问了另一个用户的帐号信息, 或一个用户可能获得访问一个受限的聊天室或服务的访问权限.<br />
<br />
:一个资源ID可能被作为一个实体的XMPP地址的一部分。一个通常的用户是即时消息用户所连接的资源(激活的会话)的名字; 另一个是作为多用户聊天室的某用户的昵称; 许多其他种类的实体可能使用资源ID作为他们地址的一部分.这些服务的安全性可能会受到国际化资源ID的不同表达的威胁;例如, 一个用户可能尝试以同一个名字初始化多个会话,或一个用户可能发送一个消息给多用户聊天室的一个人但实际上发给了另外一个人.<br />
<br />
==IANA 事项==<br />
<br />
===用于TLS数据的XML名字空间名===<br />
<br />
:XMPP中用于TLS相关数据的 URN 子名字空间定义如下. (这个名字空间的名字遵守The IETF XML Registry [XML-REG]定义的格式.)<br />
<br />
::URI: urn:ietf:params:xml:ns:xmpp-tls<br />
<br />
::Specification: RFC 3920<br />
<br />
::Description: This is the XML namespace name for TLS-related data in the Extensible Messaging and Presence Protocol (XMPP) as defined by RFC 3920.<br />
<br />
::Registrant Contact: IETF, XMPP Working Group, <xmppwg@jabber.org><br />
<br />
===用于SASL数据的XML名字空间名===<br />
<br />
:XMPP中用于SASL相关数据的 URN 子名字空间定义如下. (这个名字空间的名字遵守The IETF XML Registry [XML-REG]定义的格式.)<br />
<br />
::URI: urn:ietf:params:xml:ns:xmpp-sasl<br />
<br />
::Specification: RFC 3920<br />
<br />
::Description: This is the XML namespace name for SASL-related data in the Extensible Messaging and Presence Protocol (XMPP) as defined by RFC 3920.<br />
<br />
::Registrant Contact: IETF, XMPP Working Group, <xmppwg@jabber.org><br />
<br />
===用于流错误的XML名字空间名===<br />
<br />
:XMPP中用于流相关错误的 URN 子名字空间定义如下. (这个名字空间的名字遵守The IETF XML Registry [XML-REG]定义的格式.)<br />
<br />
::URI: urn:ietf:params:xml:ns:xmpp-streams<br />
<br />
::Specification: RFC 3920<br />
<br />
:Description: This is the XML namespace name for stream-related error data in the Extensible Messaging and Presence Protocol (XMPP) as defined by RFC 3920.<br />
<br />
::Registrant Contact: IETF, XMPP Working Group, <xmppwg@jabber.org><br />
<br />
===用于资源绑定的XML名字空间名===<br />
<br />
:XMPP中用于资源绑定的 URN 子名字空间定义如下. (这个名字空间的名字遵守The IETF XML Registry [XML-REG]定义的格式.)<br />
<br />
::URI: urn:ietf:params:xml:ns:xmpp-bind<br />
<br />
::Specification: RFC 3920<br />
<br />
::Description: This is the XML namespace name for resource binding in the Extensible Messaging and Presence Protocol (XMPP) as defined by RFC 3920.<br />
<br />
::Registrant Contact: IETF, XMPP Working Group, <xmppwg@jabber.org><br />
<br />
===用于节错误的XML名字空间名===<br />
<br />
:XMPP中用于节相关错误数据的 URN 子名字空间定义如下. (这个名字空间的名字遵守The IETF XML Registry [XML-REG]定义的格式.)<br />
<br />
::URI: urn:ietf:params:xml:ns:xmpp-stanzas<br />
<br />
::Specification: RFC 3920<br />
<br />
::Description: This is the XML namespace name for stanza-related error data in the Extensible Messaging and Presence Protocol (XMPP) as defined by RFC 3920.<br />
<br />
::Registrant Contact: IETF, XMPP Working Group, <xmppwg@jabber.org><br />
<br />
===Nodeprep Profile of Stringprep===<br />
<br />
:The Nodeprep profile of stringprep是在Nodeprep(附录 A)定义的. IANA已经在stringprep profile registry中注册了 Nodeprep.<br />
<br />
::Name of this profile:<br />
<br />
:::Nodeprep<br />
<br />
::RFC in which the profile is defined:<br />
<br />
:::RFC 3920<br />
<br />
::Indicator whether or not this is the newest version of the profile:<br />
<br />
:::This is the first version of Nodeprep<br />
<br />
===Resourceprep Profile of Stringprep===<br />
<br />
:The Resourceprep profile of stringprep是在Resourceprep(附录 B)定义的. IANA已经在stringprep profile registry中注册了Resourceprep.<br />
<br />
::Name of this profile:<br />
<br />
:::Resourceprep<br />
<br />
::RFC in which the profile is defined:<br />
<br />
:::RFC 3920<br />
<br />
::Indicator whether or not this is the newest version of the profile:<br />
<br />
:::This is the first version of Resourceprep<br />
<br />
===GSSAPI 服务名===<br />
<br />
:IANA已经注册了 "xmpp" 作为一个 GSSAPI [GSS-API] 服务名, 在SASL Definition (第六章第三节)定义了.<br />
<br />
===端口号===<br />
<br />
:IANA已经注册了"xmpp-client" 和 "xmpp-server" 作为[TCP]端口号5222和5269的关键字.<br />
<br />
:这些端口应该(SHOULD)用于客户端-服务器 和 服务器-服务器通信,但它们的使用是可选的(OPTIONAL).<br />
<br />
==参考==<br />
<br />
===标准化参考===<br />
<br />
:[ABNF] Crocker, D. and P. Overell, "Augmented BNF for Syntax Specifications: ABNF", RFC 2234, November 1997.<br />
<br />
:[BASE64] Josefsson, S., "The Base16, Base32, and Base64 Data Encodings", RFC 3548, July 2003.<br />
<br />
:[CHARSET] Alvestrand, H., "IETF Policy on Character Sets and Languages", BCP 18, RFC 2277, January 1998.<br />
<br />
:[DIGEST-MD5] Leach, P. and C. Newman, "Using Digest Authentication as a SASL Mechanism", RFC 2831, May 2000.<br />
<br />
:[DNS] Mockapetris, P., "Domain names - implementation and specification", STD 13, RFC 1035, November 1987.<br />
<br />
:[GSS-API] Linn, J., "Generic Security Service Application Program Interface Version 2, Update 1", RFC 2743, January 2000.<br />
<br />
:[HTTP-TLS] Rescorla, E., "HTTP Over TLS", RFC 2818, May 2000.<br />
<br />
:[IDNA] Faltstrom, P., Hoffman, P., and A. Costello, "Internationalizing Domain Names in Applications (IDNA)", RFC 3490, March 2003.<br />
<br />
:[IPv6] Hinden, R. and S. Deering, "Internet Protocol Version 6 (IPv6) Addressing Architecture", RFC 3513, April 2003.<br />
<br />
:[LANGTAGS] Alvestrand, H., "Tags for the Identification of Languages", BCP 47, RFC 3066, January 2001.<br />
<br />
:[NAMEPREP] Hoffman, P. and M. Blanchet, "Nameprep: A Stringprep Profile for Internationalized Domain Names (IDN)", RFC 3491, March 2003.<br />
<br />
:[RANDOM] Eastlake 3rd, D., Crocker, S., and J. Schiller, "Randomness Recommendations for Security", RFC 1750, December 1994.<br />
<br />
:[SASL] Myers, J., "Simple Authentication and Security Layer (SASL)", RFC 2222, October 1997.<br />
<br />
:[SRV] Gulbrandsen, A., Vixie, P., and L. Esibov, "A DNS RR for specifying the location of services (DNS SRV)", RFC 2782, February 2000.<br />
<br />
:[STRINGPREP] Hoffman, P. and M. Blanchet, "Preparation of Internationalized Strings ("stringprep")", RFC 3454, December 2002.<br />
<br />
:[TCP] Postel, J., "Transmission Control Protocol", STD 7, RFC 793, September 1981.<br />
<br />
:[TERMS] Bradner, S., "Key words for use in RFCs to Indicate Requirement Levels", BCP 14, RFC 2119, March 1997.<br />
<br />
:[TLS] Dierks, T. and C. Allen, "The TLS Protocol Version 1.0", RFC 2246, January 1999.<br />
<br />
:[UCS2] International Organization for Standardization, "Information Technology - Universal Multiple-octet coded Character Set (UCS) - Amendment 2: UCS Transformation Format 8 (UTF-8)", ISO Standard 10646-1 Addendum 2, October 1996.<br />
<br />
:[UTF-8] Yergeau, F., "UTF-8, a transformation format of ISO 10646", STD 63, RFC 3629, November 2003.<br />
<br />
:[X509] Housley, R., Polk, W., Ford, W., and D. Solo, "Internet X.509 Public Key Infrastructure Certificate and Certificate Revocation List (CRL) Profile", RFC 3280, April 2002.<br />
<br />
:[XML] Bray, T., Paoli, J., Sperberg-McQueen, C., and E. Maler, "Extensible Markup Language (XML) 1.0 (2nd ed)", W3C REC-xml, October 2000, <http://www.w3.org/TR/REC-xml>.<br />
<br />
:[XML-NAMES] Bray, T., Hollander, D., and A. Layman, "Namespaces in XML", W3C REC-xml-names, January 1999, <http://www.w3.org/TR/REC-xml-names>.<br />
<br />
===信息参考===<br />
<br />
:[ACAP] Newman, C. and J. Myers, "ACAP -- Application Configuration Access Protocol", RFC 2244, November 1997.<br />
<br />
:[ASN.1] CCITT, "Recommendation X.208: Specification of Abstract Syntax Notation One (ASN.1)", 1988.<br />
<br />
<br />
:[DNSSEC] Eastlake 3rd, D., "Domain Name System Security Extensions", RFC 2535, March 1999.<br />
<br />
:[HTTP] Fielding, R., Gettys, J., Mogul, J., Frystyk, H., Masinter, L., Leach, P., and T. Berners-Lee, "Hypertext Transfer Protocol -- HTTP/1.1", RFC 2616, June 1999.<br />
<br />
:[IMAP] Crispin, M., "INTERNET MESSAGE ACCESS PROTOCOL - VERSION 4rev1", RFC 3501, March 2003.<br />
<br />
:[IMP-REQS] Day, M., Aggarwal, S., Mohr, G., and J. Vincent, "Instant Messaging \/ Presence Protocol Requirements", RFC 2779, February 2000.<br />
<br />
:[IRC] Oikarinen, J. and D. Reed, "Internet Relay Chat Protocol", RFC 1459, May 1993.<br />
<br />
:[JEP-0029] Kaes, C., "Definition of Jabber Identifiers (JIDs)", JSF JEP 0029, October 2003.<br />
<br />
:[JEP-0078] Saint-Andre, P., "Non-SASL Authentication", JSF JEP 0078, July 2004.<br />
<br />
[JEP-0086] Norris, R. and P. Saint-Andre, "Error Condition Mappings", JSF JEP 0086, February 2004.<br />
<br />
:[JSF] Jabber Software Foundation, "Jabber Software Foundation", <http://www.jabber.org/>.<br />
<br />
:[POP3] Myers, J. and M. Rose, "Post Office Protocol - Version 3", STD 53, RFC 1939, May 1996.<br />
<br />
:[SIMPLE] SIMPLE Working Group, "SIMPLE WG", <http://www.ietf.org/html.charters/simple-charter.html>.<br />
<br />
:[SMTP] Klensin, J., "Simple Mail Transfer Protocol", RFC 2821, April 2001.<br />
<br />
:[URI] Berners-Lee, T., Fielding, R., and L. Masinter, "Uniform Resource Identifiers (URI): Generic Syntax", RFC 2396, August 1998.<br />
<br />
:[USINGTLS] Newman, C., "Using TLS with IMAP, POP3 and ACAP", RFC 2595, June 1999.<br />
<br />
:[XML-REG] Mealling, M., "The IETF XML Registry", BCP 81, RFC 3688, January 2004.<br />
<br />
:[[RFC3921]] Saint-Andre, P., Ed., "Extensible Messaging and Presence Protocol (XMPP): Instant Messaging and Presence", RFC 3921, October 2004.<br />
<br />
<br />
==附录 A. Nodeprep==<br />
<br />
===A.1. 介绍===<br />
<br />
:这个附录定义了 "Nodeprep" profile of [STRINGPREP]. 它定义了处理规则让用户能够在XMPP中输入国际化节点标识符并尽可能正确的获取正确的字符内容. (一个XMPP节点标识符是XMPP地址的可选部分,它在域名标识符和那个'@'分隔符之前;它经常但不是专门用来关联一个即时消息用户名)这些处理规则仅仅适用于XMPP节点标识符但不适用于任意文本或任何XMPP的其他方面.<br />
<br />
:这个脚本定义了以下这些, 正如 [STRINGPREP]要求的:<br />
<br />
:* 脚本预期的适用性: XMPP的国际化节点标识符<br />
<br />
:* 用于stringprep的输入输出字符集: Unicode 3.2, 定义在本附录的第二章<br />
<br />
:* 使用的映射: 定义在第三章<br />
<br />
:* Unicode正规化使用: 定义在第四章<br />
<br />
:* 禁止输出的字符串: 定义在第五章<br />
<br />
:* 双字节字符处理: 定义在第六章<br />
<br />
===A.2. 字符集===<br />
<br />
:本脚本使用Unicode 3.2的未分配编码列表,指向 Table A.1, 也定义在 [STRINGPREP]的附录 A 中.<br />
<br />
===A.3. 映射===<br />
<br />
:本脚本指定使用[STRINGPREP]的以下表:<br />
<br />
::Table B.1<br />
<br />
::Table B.2<br />
<br />
===A.4. 正规化===<br />
<br />
:本脚本指定 Unicode正规化使用 form KC, 定义在 [STRINGPREP]中.<br />
<br />
===A.5. 禁止输出===<br />
<br />
:本脚本指定使用以下的[STRINGPREP]表禁止输出.<br />
<br />
::Table C.1.1<br />
<br />
::Table C.1.2<br />
<br />
::Table C.2.1<br />
<br />
::Table C.2.2<br />
<br />
::Table C.3<br />
<br />
::Table C.4<br />
<br />
::Table C.5<br />
<br />
::Table C.6<br />
<br />
::Table C.7<br />
<br />
::Table C.8<br />
<br />
::Table C.9<br />
<br />
:另外, 以下Unicode字符也被禁止:<br />
<br />
: #x22 (")<br />
<br />
: #x26 (&)<br />
<br />
: #x27 (')<br />
<br />
: #x2F (/)<br />
<br />
: #x3A (:)<br />
<br />
: #x3C (<)<br />
<br />
: #x3E (>)<br />
<br />
: #x40 (@)<br />
<br />
===A.6. 双字节===<br />
<br />
:本脚本指定按照[STRINGPREP]第六章检查双字节.<br />
<br />
==附录 B. Resourceprep==<br />
<br />
===B.1. 介绍===<br />
<br />
:这个附录定义了 "Resourceprep" profile of [STRINGPREP]. 它定义了处理规则让用户能够在XMPP中输入国际化资源标识符并尽可能正确的获取正确的字符内容. (一个XMPP资源标识符是XMPP地址的可选部分,它在域名标识符和'/'分隔符之后;它经常但不是专门用来关联一个即时消息会话名)这些处理规则仅仅适用于XMPP资源标识符但不适用于任意文本或任何XMPP的其他方面.<br />
<br />
:这个脚本定义了以下这些, 正如 [STRINGPREP]要求的:<br />
<br />
:* 脚本预期的适用性: XMPP的国际化节点标识符<br />
<br />
:* 用于stringprep的输入输出字符集: Unicode 3.2, 定义在本附录的第二章<br />
<br />
:* 使用的映射: 定义在第三章<br />
<br />
:* Unicode正规化使用: 定义在第四章<br />
<br />
:* 禁止输出的字符串: 定义在第五章<br />
<br />
:* 双字节字符处理: 定义在第六章<br />
<br />
===B.2. 字符集===<br />
<br />
:本脚本使用Unicode 3.2的未分配编码列表,指向 Table A.1, 也定义在 [STRINGPREP]的附录<br />
<br />
===B.3. 映射===<br />
<br />
:本脚本指定使用[STRINGPREP]的以下表:<br />
<br />
::Table B.1<br />
<br />
===B.4. 正规化===<br />
<br />
:本脚本指定使用 Unicode normalization form KC, 定义在 [STRINGPREP]中.<br />
<br />
===B.5. 禁止输出===<br />
<br />
:本脚本指定使用以下的[STRINGPREP]表禁止输出.<br />
<br />
::Table C.1.2<br />
<br />
::Table C.2.1<br />
<br />
::Table C.2.2<br />
<br />
::Table C.3<br />
<br />
::Table C.4<br />
<br />
::Table C.5<br />
<br />
::Table C.6<br />
<br />
::Table C.7<br />
<br />
::Table C.8<br />
<br />
::Table C.9<br />
<br />
===B.6. 双字节===<br />
<br />
:本脚本指定按照[STRINGPREP]第六章检查双字节.<br />
<br />
==附录 C. XML 规划==<br />
<br />
:以下 XML schemas 是描述性的, 不是标准的. 'jabber:client' 和 'jabber:server' 名字空间的标准定义, 参照 [[RFC3921]].<br />
<br />
===C.1. Streams namespace===<br />
<br />
<source lang="xml"><br />
<?xml version='1.0' encoding='UTF-8'?><br />
<br />
<xs:schema<br />
xmlns:xs='http://www.w3.org/2001/XMLSchema'<br />
targetNamespace='http://etherx.jabber.org/streams'<br />
xmlns='http://etherx.jabber.org/streams'<br />
elementFormDefault='unqualified'><br />
<br />
<xs:element name='stream'><br />
<xs:complexType><br />
<xs:sequence xmlns:client='jabber:client'<br />
xmlns:server='jabber:server'<br />
xmlns:db='jabber:server:dialback'><br />
<xs:element ref='features' minOccurs='0' maxOccurs='1'/><br />
<xs:any namespace='urn:ietf:params:xml:ns:xmpp-tls'<br />
minOccurs='0'<br />
maxOccurs='unbounded'/><br />
<xs:any namespace='urn:ietf:params:xml:ns:xmpp-sasl'<br />
minOccurs='0'<br />
maxOccurs='unbounded'/><br />
<xs:choice minOccurs='0' maxOccurs='1'><br />
<xs:choice minOccurs='0' maxOccurs='unbounded'><br />
<xs:element ref='client:message'/><br />
<xs:element ref='client:presence'/><br />
<xs:element ref='client:iq'/><br />
</xs:choice><br />
<xs:choice minOccurs='0' maxOccurs='unbounded'><br />
<xs:element ref='server:message'/><br />
<xs:element ref='server:presence'/><br />
<xs:element ref='server:iq'/><br />
<xs:element ref='db:result'/><br />
<xs:element ref='db:verify'/><br />
</xs:choice><br />
</xs:choice><br />
<xs:element ref='error' minOccurs='0' maxOccurs='1'/><br />
</xs:sequence><br />
<xs:attribute name='from' type='xs:string' use='optional'/><br />
<xs:attribute name='id' type='xs:NMTOKEN' use='optional'/><br />
<xs:attribute name='to' type='xs:string' use='optional'/><br />
<xs:attribute name='version' type='xs:decimal' use='optional'/><br />
<xs:attribute ref='xml:lang' use='optional'/><br />
</xs:complexType><br />
</xs:element><br />
<br />
<xs:element name='features'><br />
<xs:complexType><br />
<xs:all xmlns:tls='urn:ietf:params:xml:ns:xmpp-tls'<br />
xmlns:sasl='urn:ietf:params:xml:ns:xmpp-sasl'<br />
xmlns:bind='urn:ietf:params:xml:ns:xmpp-bind'<br />
xmlns:sess='urn:ietf:params:xml:ns:xmpp-session'><br />
<xs:element ref='tls:starttls' minOccurs='0'/><br />
<xs:element ref='sasl:mechanisms' minOccurs='0'/><br />
<xs:element ref='bind:bind' minOccurs='0'/><br />
<xs:elemnt ref='sess:session' minOccurs='0'/><br />
</xs:all><br />
</xs:complexType><br />
</xs:element><br />
<br />
<xs:element name='error'><br />
<xs:complexType><br />
<xs:sequence xmlns:err='urn:ietf:params:xml:ns:xmpp-streams'><br />
<xs:group ref='err:streamErrorGroup'/><br />
<xs:element ref='err:text'<br />
minOccurs='0'<br />
maxOccurs='1'/><br />
</xs:sequence><br />
</xs:complexType><br />
</xs:element><br />
<br />
</xs:schema><br />
</source><br />
<br />
===C.2. Stream error namespace===<br />
<br />
<source lang="xml"><br />
<?xml version='1.0' encoding='UTF-8'?><br />
<br />
<xs:schema<br />
xmlns:xs='http://www.w3.org/2001/XMLSchema'<br />
targetNamespace='urn:ietf:params:xml:ns:xmpp-streams'<br />
xmlns='urn:ietf:params:xml:ns:xmpp-streams'<br />
elementFormDefault='qualified'><br />
<br />
<xs:element name='bad-format' type='empty'/><br />
<xs:element name='bad-namespace-prefix' type='empty'/><br />
<xs:element name='conflict' type='empty'/><br />
<xs:element name='connection-timeout' type='empty'/><br />
<xs:element name='host-gone' type='empty'/><br />
<xs:element name='host-unknown' type='empty'/><br />
<xs:element name='improper-addressing' type='empty'/><br />
<xs:element name='internal-server-error' type='empty'/><br />
<xs:element name='invalid-from' type='empty'/><br />
<xs:element name='invalid-id' type='empty'/><br />
<xs:element name='invalid-namespace' type='empty'/><br />
<xs:element name='invalid-xml' type='empty'/><br />
<xs:element name='not-authorized' type='empty'/><br />
<xs:element name='policy-violation' type='empty'/><br />
<xs:element name='remote-connection-failed' type='empty'/><br />
<xs:element name='resource-constraint' type='empty'/><br />
<xs:element name='restricted-xml' type='empty'/><br />
<xs:element name='see-other-host' type='xs:string'/><br />
<xs:element name='system-shutdown' type='empty'/><br />
<xs:element name='undefined-condition' type='empty'/><br />
<xs:element name='unsupported-encoding' type='empty'/><br />
<xs:element name='unsupported-stanza-type' type='empty'/><br />
<xs:element name='unsupported-version' type='empty'/><br />
<xs:element name='xml-not-well-formed' type='empty'/><br />
<br />
<xs:group name='streamErrorGroup'><br />
<xs:choice><br />
<xs:element ref='bad-format'/><br />
<xs:element ref='bad-namespace-prefix'/><br />
<xs:element ref='conflict'/><br />
<xs:element ref='connection-timeout'/><br />
<xs:element ref='host-gone'/><br />
<xs:element ref='host-unknown'/><br />
<xs:element ref='improper-addressing'/><br />
<xs:element ref='internal-server-error'/><br />
<xs:element ref='invalid-from'/><br />
<xs:element ref='invalid-id'/><br />
<xs:element ref='invalid-namespace'/><br />
<xs:element ref='invalid-xml'/><br />
<xs:element ref='not-authorized'/><br />
<xs:element ref='policy-violation'/><br />
<xs:element ref='remote-connection-failed'/><br />
<xs:element ref='resource-constraint'/><br />
<xs:element ref='restricted-xml'/><br />
<xs:element ref='see-other-host'/><br />
<xs:element ref='system-shutdown'/><br />
<xs:element ref='undefined-condition'/><br />
<xs:element ref='unsupported-encoding'/><br />
<xs:element ref='unsupported-stanza-type'/><br />
<xs:element ref='unsupported-version'/><br />
<xs:element ref='xml-not-well-formed'/><br />
</xs:choice><br />
</xs:group><br />
<br />
<xs:element name='text'><br />
<xs:complexType><br />
<xs:simpleContent><br />
<xs:extension base='xs:string'><br />
<xs:attribute ref='xml:lang' use='optional'/><br />
</xs:extension><br />
</xs:simpleContent><br />
</xs:complexType><br />
</xs:element><br />
<br />
<xs:simpleType name='empty'><br />
<xs:restriction base='xs:string'><br />
<xs:enumeration value=''/><br />
</xs:restriction><br />
</xs:simpleType><br />
<br />
</xs:schema><br />
</source><br />
<br />
===C.3. TLS namespace===<br />
<br />
<source lang="xml"><br />
<?xml version='1.0' encoding='UTF-8'?><br />
<br />
<xs:schema<br />
xmlns:xs='http://www.w3.org/2001/XMLSchema'<br />
targetNamespace='urn:ietf:params:xml:ns:xmpp-tls'<br />
xmlns='urn:ietf:params:xml:ns:xmpp-tls'<br />
elementFormDefault='qualified'><br />
<br />
<xs:element name='starttls'><br />
<xs:complexType><br />
<xs:sequence><br />
<xs:element<br />
name='required'<br />
minOccurs='0'<br />
maxOccurs='1'<br />
type='empty'/><br />
</xs:sequence><br />
</xs:complexType><br />
</xs:element><br />
<br />
<xs:element name='proceed' type='empty'/><br />
<xs:element name='failure' type='empty'/><br />
<br />
<xs:simpleType name='empty'><br />
<xs:restriction base='xs:string'><br />
<xs:enumeration value=''/><br />
</xs:restriction><br />
</xs:simpleType><br />
<br />
</xs:schema><br />
</source><br />
<br />
===C.4. SASL namespace===<br />
<br />
<source lang="xml"><br />
<?xml version='1.0' encoding='UTF-8'?><br />
<br />
<xs:schema<br />
xmlns:xs='http://www.w3.org/2001/XMLSchema'<br />
targetNamespace='urn:ietf:params:xml:ns:xmpp-sasl'<br />
xmlns='urn:ietf:params:xml:ns:xmpp-sasl'<br />
elementFormDefault='qualified'><br />
<br />
<xs:element name='mechanisms'><br />
<xs:complexType><br />
<xs:sequence><br />
<xs:element name='mechanism'<br />
maxOccurs='unbounded'<br />
type='xs:string'/><br />
</xs:sequence><br />
</xs:complexType><br />
</xs:element><br />
<br />
<xs:element name='auth'><br />
<xs:complexType><br />
<xs:simpleContent><br />
<xs:extension base='empty'><br />
<xs:attribute name='mechanism'<br />
type='xs:string'<br />
use='optional'/><br />
</xs:extension><br />
</xs:simpleContent><br />
</xs:complexType><br />
</xs:element><br />
<br />
<xs:element name='challenge' type='xs:string'/><br />
<xs:element name='response' type='xs:string'/><br />
<xs:element name='abort' type='empty'/><br />
<xs:element name='success' type='empty'/><br />
<br />
<xs:element name='failure'><br />
<xs:complexType><br />
<xs:choice minOccurs='0'><br />
<xs:element name='aborted' type='empty'/><br />
<xs:element name='incorrect-encoding' type='empty'/><br />
<xs:element name='invalid-authzid' type='empty'/><br />
<xs:element name='invalid-mechanism' type='empty'/><br />
<xs:element name='mechanism-too-weak' type='empty'/><br />
<xs:element name='not-authorized' type='empty'/><br />
<xs:element name='temporary-auth-failure' type='empty'/><br />
</xs:choice><br />
</xs:complexType><br />
</xs:element><br />
<xs:simpleType name='empty'><br />
<xs:restriction base='xs:string'><br />
<xs:enumeration value=''/><br />
</xs:restriction><br />
</xs:simpleType><br />
<br />
</xs:schema><br />
</source><br />
<br />
===C.5. Resource binding namespace===<br />
<br />
<source lang="xml"><br />
<?xml version='1.0' encoding='UTF-8'?><br />
<br />
<xs:schema<br />
xmlns:xs='http://www.w3.org/2001/XMLSchema'<br />
targetNamespace='urn:ietf:params:xml:ns:xmpp-bind'<br />
xmlns='urn:ietf:params:xml:ns:xmpp-bind'<br />
elementFormDefault='qualified'><br />
<br />
<xs:element name='bind'><br />
<xs:complexType><br />
<xs:choice minOccurs='0' maxOccurs='1'><br />
<xs:element name='resource' type='xs:string'/><br />
<xs:element name='jid' type='xs:string'/><br />
</xs:choice><br />
</xs:complexType><br />
</xs:element><br />
<br />
</xs:schema><br />
</source><br />
<br />
===C.6. Dialback namespace===<br />
<br />
<source lang="xml"><br />
<?xml version='1.0' encoding='UTF-8'?><br />
<br />
<xs:schema<br />
xmlns:xs='http://www.w3.org/2001/XMLSchema'<br />
targetNamespace='jabber:server:dialback'<br />
xmlns='jabber:server:dialback'<br />
elementFormDefault='qualified'><br />
<br />
<xs:element name='result'><br />
<xs:complexType><br />
<xs:simpleContent><br />
<xs:extension base='xs:token'><br />
<xs:attribute name='from' type='xs:string' use='required'/><br />
<xs:attribute name='to' type='xs:string' use='required'/><br />
<xs:attribute name='type' use='optional'><br />
<xs:simpleType><br />
<xs:restriction base='xs:NCName'><br />
<xs:enumeration value='invalid'/><br />
<xs:enumeration value='valid'/><br />
</xs:restriction><br />
</xs:simpleType><br />
</xs:attribute><br />
</xs:extension><br />
</xs:simpleContent><br />
</xs:complexType><br />
</xs:element><br />
<br />
<xs:element name='verify'><br />
<xs:complexType><br />
<xs:simpleContent><br />
<xs:extension base='xs:token'><br />
<xs:attribute name='from' type='xs:string' use='required'/><br />
<xs:attribute name='id' type='xs:NMTOKEN' use='required'/><br />
<xs:attribute name='to' type='xs:string' use='required'/><br />
<xs:attribute name='type' use='optional'><br />
<xs:simpleType><br />
<xs:restriction base='xs:NCName'><br />
<xs:enumeration value='invalid'/><br />
<xs:enumeration value='valid'/><br />
</xs:restriction><br />
</xs:simpleType><br />
</xs:attribute><br />
</xs:extension><br />
</xs:simpleContent><br />
</xs:complexType><br />
</xs:element><br />
<br />
</xs:schema><br />
</source><br />
<br />
===C.7. Stanza error namespace===<br />
<br />
<source lang="xml"><br />
<?xml version='1.0' encoding='UTF-8'?><br />
<br />
<xs:schema<br />
xmlns:xs='http://www.w3.org/2001/XMLSchema'<br />
targetNamespace='urn:ietf:params:xml:ns:xmpp-stanzas'<br />
xmlns='urn:ietf:params:xml:ns:xmpp-stanzas'<br />
elementFormDefault='qualified'><br />
<br />
<xs:element name='bad-request' type='empty'/><br />
<xs:element name='conflict' type='empty'/><br />
<xs:element name='feature-not-implemented' type='empty'/><br />
<xs:element name='forbidden' type='empty'/><br />
<xs:element name='gone' type='xs:string'/><br />
<xs:element name='internal-server-error' type='empty'/><br />
<xs:element name='item-not-found' type='empty'/><br />
<xs:element name='jid-malformed' type='empty'/><br />
<xs:element name='not-acceptable' type='empty'/><br />
<xs:element name='not-allowed' type='empty'/><br />
<xs:element name='payment-required' type='empty'/><br />
<xs:element name='recipient-unavailable' type='empty'/><br />
<xs:element name='redirect' type='xs:string'/><br />
<xs:element name='registration-required' type='empty'/><br />
<xs:element name='remote-server-not-found' type='empty'/><br />
<xs:element name='remote-server-timeout' type='empty'/><br />
<xs:element name='resource-constraint' type='empty'/><br />
<xs:element name='service-unavailable' type='empty'/><br />
<xs:element name='subscription-required' type='empty'/><br />
<xs:element name='undefined-condition' type='empty'/><br />
<xs:element name='unexpected-request' type='empty'/><br />
<br />
<xs:group name='stanzaErrorGroup'><br />
<xs:choice><br />
<xs:element ref='bad-request'/><br />
<xs:element ref='conflict'/><br />
<xs:element ref='feature-not-implemented'/><br />
<xs:element ref='forbidden'/><br />
<xs:element ref='gone'/><br />
<xs:element ref='internal-server-error'/><br />
<xs:element ref='item-not-found'/><br />
<xs:element ref='jid-malformed'/><br />
<xs:element ref='not-acceptable'/><br />
<xs:element ref='not-allowed'/><br />
<xs:element ref='payment-required'/><br />
<xs:element ref='recipient-unavailable'/><br />
<xs:element ref='redirect'/><br />
<xs:element ref='registration-required'/><br />
<xs:element ref='remote-server-not-found'/><br />
<xs:element ref='remote-server-timeout'/><br />
<xs:element ref='resource-constraint'/><br />
<xs:element ref='service-unavailable'/><br />
<xs:element ref='subscription-required'/><br />
<xs:element ref='undefined-condition'/><br />
<xs:element ref='unexpected-request'/><br />
</xs:choice><br />
</xs:group><br />
<br />
<xs:element name='text'><br />
<xs:complexType><br />
<xs:simpleContent><br />
<xs:extension base='xs:string'><br />
<xs:attribute ref='xml:lang' use='optional'/><br />
</xs:extension><br />
</xs:simpleContent><br />
</xs:complexType><br />
</xs:element><br />
<br />
<xs:simpleType name='empty'><br />
<xs:restriction base='xs:string'><br />
<xs:enumeration value=''/><br />
</xs:restriction><br />
</xs:simpleType><br />
<br />
</xs:schema><br />
</source><br />
<br />
==附录 D. 核心Jabber协议和XMPP的不同==<br />
<br />
:本章是非标准的.<br />
<br />
::译者注:附录D对于新接触XMPP的人没有什么意义,就不翻译了,免得浪费时间。因为现在RFC公布已经很久了,以前的Jabber实现很多都进化到XMPP了。<br />
<br />
:XMPP has been adapted from the protocols originally developed in the Jabber open-source community, which can be thought of as "XMPP 0.9". Because there exists a large installed base of Jabber implementations and deployments, it may be helpful to specify the key differences between the relevant Jabber protocols and XMPP in order to expedite and encourage upgrades of those implementations and deployments to XMPP. This section summarizes the core differences, while the corresponding section of [[RFC3921]] summarizes the differences that relate specifically to instant messaging and presence applications.<br />
<br />
===D.1. Channel Encryption===<br />
<br />
:It was common practice in the Jabber community to use SSL for channel encryption on ports other than 5222 and 5269 (the convention is to use ports 5223 and 5270). XMPP uses TLS over the IANA-registered ports for channel encryption, as defined under Use of TLS (Section 5) herein.<br />
<br />
===D.2. Authentication===<br />
<br />
:The client-server authentication protocol developed in the Jabber community used a basic IQ interaction qualified by the 'jabber:iq:auth' namespace (documentation of this protocol is contained in [JEP-0078], published by the Jabber Software Foundation [JSF]). XMPP uses SASL for authentication, as defined under Use of SASL (Section 6) herein.<br />
<br />
:The Jabber community did not develop an authentication protocol for server-to-server communications, only the Server Dialback (Section 8) protocol to prevent server poofing. XMPP supersedes Server Dialback with a true server-to-server authentication protocol, as defined under Use of SASL (Section 6) herein.<br />
<br />
===D.3. Resource Binding===<br />
<br />
:Resource binding in the Jabber community was handled via the 'jabber:iq:auth' namespace (which was also used for client authentication with a server). XMPP defines a dedicated namespace for resource binding as well as the ability for a server to generate a resource identifier on behalf of a client, as defined under Resource Binding (Section 7).<br />
<br />
===D.4. JID Processing===<br />
<br />
:JID processing was somewhat loosely defined by the Jabber community (documentation of forbidden characters and case handling is contained in [JEP-0029], published by the Jabber Software Foundation [JSF]). XMPP specifies the use of [NAMEPREP] for domain identifiers and supplements Nameprep with two additional [STRINGPREP] profiles for JID processing: Nodeprep (Appendix A) for node identifiers and Resourceprep (Appendix B) for resource identifiers.<br />
<br />
===D.5. Error Handling===<br />
<br />
:Stream-related errors were handled in the Jabber community via XML character data text in a <stream:error/> element. In XMPP, stream-related errors are handled via an extensible mechanism defined under Stream Errors (Section 4.7) herein. Stanza-related errors were handled in the Jabber community via HTTP-style error codes. In XMPP, stanza-related errors are handled via an extensible mechanism defined under Stanza Errors (Section 9.3) herein. (Documentation of a mapping between Jabber and XMPP error handling mechanisms is contained in [JEP-0086], published by the Jabber Software Foundation [JSF].)<br />
<br />
===D.6. Internationalization===<br />
<br />
:Although use of UTF-8 has always been standard practice within the Jabber community, the community did not define mechanisms for specifying the language of human-readable text provided in XML character data. XMPP specifies the use of the 'xml:lang' attribute in such contexts, as defined under Stream Attributes (Section 4.4) and xml:lang (Section 9.1.5) herein.<br />
<br />
===D.7. Stream Version Attribute===<br />
<br />
:The Jabber community did not include a 'version' attribute in stream headers. XMPP specifies inclusion of that attribute as a way to signal support for the stream features (authentication, encryption, etc.) defined under Version Support (Section 4.4.1) herein.<br />
<br />
==贡献者==<br />
<br />
:XMPP的大部分核心方面是由1999年开始的Jabber开源社区开发的. 这个社区是由 Jeremie Miller建立的, 他于1999年1月发布了最初版的jabber server源代码. 主要的基础协议的早期贡献者还包括 Ryan Eatmon, Peter Millard, Thomas Muldowney,和 Dave Smith. XMPP工作组的工作主要集中在安全性和国际化方面; 在这些领域, 使用 TLS 和 SASL 的协议最初是由 Rob Norris贡献的, stringprep profiles 最初是由 Joe Hildebrand贡献的. The error code syntax 是由Lisa Dusseault建议的.<br />
<br />
==致谢==<br />
<br />
:感谢许多在贡献者名单之外的人们. 尽管很难提供一个完整的名单, 以下个人对于定义协议或评论标准提供了很多帮助:<br />
<br />
:Thomas Charron, Richard Dobson, Sam Hartman, Schuyler Heath, Jonathan Hogg, Cullen Jennings, Craig Kaes, Jacek Konieczny, Alexey Melnikov, Keith Minkler, Julian Missig, Pete Resnick, Marshall Rose, Alexey Shchepin, Jean-Louis Seguineau, Iain Shigeoka, Greg Troxel, and David Waite. <br />
<br />
:也感谢 XMPP工作组的成员和 IETF 社区在本文的成文过程中一直提供的评论和反馈。<br />
<br />
<br />
==作者地址==<br />
<br />
:Peter Saint-Andre (editor)<br />
<br />
:Jabber Software Foundation<br />
<br />
:EMail: stpeter@jabber.org<br />
<br />
==完整的版权声明==<br />
<br />
:Copyright (C) The Internet Society (2004).<br />
<br />
:This document is subject to the rights, licenses and restrictions contained in BCP 78, and except as set forth therein, the authors retain all their rights. This document and the information contained herein are provided on an "AS IS" basis and THE CONTRIBUTOR, THE ORGANIZATION HE/S HE REPRESENTS OR IS SPONSORED BY (IF ANY), THE INTERNET SOCIETY AND THE INTERNET ENGINEERING TASK FORCE DISCLAIM ALL WARRANTIES, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO ANY WARRANTY THAT THE USE OF THE INFORMATION HEREIN WILL NOT INFRINGE ANY RIGHTS OR ANY IMPLIED WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE.<br />
<br />
==Intellectual Property==<br />
<br />
:The IETF takes no position regarding the validity or scope of any Intellectual Property Rights or other rights that might be claimed to pertain to the implementation or use of the technology described in this document or the extent to which any license under such rights might or might not be available; nor does it represent that it has made any independent effort to identify any such rights. Information on the IETF's procedures with respect to rights in IETF Documents can be found in BCP 78 and BCP 79. Copies of IPR disclosures made to the IETF Secretariat and any assurances of licenses to be made available, or the result of an attempt made to obtain a general license or permission for the use of such proprietary rights by implementers or users of this specification can be obtained from the IETF on-line IPR repository at http://www.ietf.org/ipr. The IETF invites any interested party to bring to its attention any copyrights, patents or patent applications, or other proprietary rights that may cover technology that may be required to implement this standard. Please address the information to the IETF at ietf-ipr@ietf.org.<br />
<br />
==感谢==<br />
<br />
:目前为RFC编辑活动提供资金的Internet Society.</div>
Snowqiang
http://wiki.jabbercn.org/XEP-0124
XEP-0124
2011-05-19T01:36:47Z
<p>Snowqiang: 加附录CDEF的模板</p>
<hr />
<div>[[Category:XMPP扩展]]<br />
[[Category:翻译中]]<br />
<br />
'''本文的英文原文来自[http://www.xmpp.org/extensions/xep-0124.html XEP-0124]'''<br />
<br />
'''XEP-0124: Bidirectional-streams Over Synchronous HTTP (BOSH)'''<br />
<br />
{|<br />
!摘要:<br />
|This specification defines a transport protocol that emulates the semantics of a long-lived, bidirectional TCP connection between two entities (such as a client and a server) by efficiently using multiple synchronous HTTP request/response pairs without requiring the use of frequent polling or chunked responses.<br />
|-<br />
!作者:<br />
|Ian Paterson, Dave Smith, Peter Saint-Andre, Jack Moffitt<br />
|-<br />
!版权:<br />
|© 1999 - 2011 XMPP Standards Foundation. SEE LEGAL NOTICES.<br />
|-<br />
!状态:<br />
|草案<br />
|-<br />
!类型:<br />
|标准跟踪<br />
|-<br />
!版本:<br />
|2.0<br />
|-<br />
!最后更新日期:<br />
|2010-07-02<br />
|}<br />
<br />
NOTICE: The protocol defined herein is a Draft Standard of the XMPP Standards Foundation. Implementations are encouraged and the protocol is appropriate for deployment in production systems, but some changes to the protocol are possible before it becomes a Final Standard.<br />
<br />
==Introduction==<br />
<br />
The Transmission Control Protocol (TCP; RFC 793 [1]) is often used to establish a stream-oriented connection between two entities. Such connections can often be long-lived to enable an interactive "session" between the entities. However, sometimes the nature of the device or network can prevent an application from maintaining a long-lived TCP connection to a server or peer. In this case, it is desirable to use an alternative connection method that emulates the behavior of a long-lived TCP connection using a sequenced series of requests and responses that are exchanged over short-lived connections. The appropriate request-response semantics are widely available via the Hypertext Transfer Protocol (HTTP) as specified in RFC 1945 [2] and RFC 2616 [3].<br />
<br />
BOSH, the technology defined in this specification, essentially provides a "drop-in" alternative to a long-lived, bidirectional TCP connection. It is a mature, full-featured technology that has been widely implemented and deployed since 2004. To our knowledge it was the first of many similar technologies, which now include the Comet methodology formalized in the Bayeux Protocol [4] as well as The Web Socket Protocol [5] and Reverse HTTP [6].<br />
<br />
BOSH is designed to transport any data efficiently and with minimal latency in both directions. For applications that require both "push" and "pull" semantics, BOSH is significantly more bandwidth-efficient and responsive than most other bidirectional HTTP-based transport protocols and the techniques now commonly known as "Ajax". BOSH achieves this efficiency and low latency by using so-called "long polling" with multiple synchronous HTTP request/response pairs. Furthermore, BOSH can address the needs of constrained clients by employing fully-compliant HTTP 1.0 without the need for "cookies" (see RFC 2965 [7]) [8] or even access to HTTP headers.<br />
<br />
BOSH was originally developed in the Jabber/XMPP community as a replacement for an even earlier HTTP-based technology called Jabber HTTP Polling [9]. Although BOSH assumes that the "payload" of HTTP requests and responses will be XML, the payload formats are not limited to XMPP stanzas (see XMPP Core [10]) and could contain a mixture of elements qualified by namespaces defined by different protocols (e.g., both XMPP and JSON). This mix is necessary because some connection managers might 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 payload is qualified by the correct namespace.<br />
<br />
Note: XMPP Over BOSH [11] documents some XMPP-specific extensions of this protocol that were formerly included in this document.<br />
<br />
==Requirements==<br />
<br />
The following design requirements reflect the need to offer performance as close as possible to a standard TCP connection.<br />
<br />
1. Compatible with constrained runtime environments* (e.g., mobile and browser-based clients).<br />
2. Compatible with proxies that buffer partial HTTP responses.<br />
3. Efficient through proxies that limit the duration of HTTP responses.<br />
4. Fully compatible with HTTP/1.0.<br />
5. Compatible with restricted network connections (e.g., firewalls, proxies, and gateways).<br />
6. Fault tolerant (e.g., session recovers after an underlying TCP connection breaks at any stage during an HTTP request).<br />
7. Extensible.<br />
8. Consume significantly less bandwidth than polling-based protocols.<br />
9. Significantly more responsive (lower latency) than polling-based protocols.<br />
10. Support for polling (for clients that are limited to a single HTTP connection at a time).<br />
11. In-order delivery of data.<br />
12. Guard against unauthorized users injecting HTTP requests into a session.<br />
13. Protect against denial of service attacks.<br />
14. Multiplexing of data streams.<br />
<br />
*Note: Compatibility with constrained runtime environments implies the following restrictions:<br />
<br />
1. Clients are not required to have programmatic access to the headers of each HTTP request and response (e.g., cookies or status codes).<br />
2. The body of each HTTP request and response is parsable XML with a single root element.<br />
3. Clients can specify the Content-Type of the HTTP responses they receive.<br />
<br />
==Architectural Assumptions==<br />
<br />
This document assumes that most implementations will utilize a specialized connection manager ("CM") to handle HTTP connections rather than the native connection type for the relevant application (e.g., TCP connections in XMPP). Effectively, such a connection manager is a specialized HTTP server that translates between the HTTP requests and responses defined herein and the data streams (or API) implemented by the server with which it communicates, thus enabling a client to connect to a server via HTTP on port 80 or 443 instead of an application-specific port. We can illustrate this graphically as follows:<br />
<br />
Server<br />
|<br />
| [unwrapped data streams]<br />
|<br />
HTTP CM<br />
|<br />
| [HTTP + <body/> wrapper]<br />
|<br />
Client<br />
<br />
<br />
This specification covers communication only between a client and the connection manager. It does not cover communication between the connection manager and the server, since such communications are implementation-specific (e.g., the server might 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 might be an independent translating proxy such that the server might believe it is talking directly to the client over TCP; or the connection manager and the server might use a component protocol or an API defined by the server implementation).<br />
<br />
Furthermore, no aspect of this protocol limits its use to communication between a client and a server. For example, it could be used for communication between a server and a peer server if such communication can occur for the relevant application (e.g., in XMPP). 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 the native connection transport for the relevant application. (However, on some unreliable networks, BOSH might enable more stable communication between servers.)<br />
<br />
==The BOSH Technique==<br />
<br />
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).<br />
<br />
The technique employed by BOSH 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.<br />
<br />
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 so to make sure the client can send more data immediately if necessary. (The client SHOULD NOT open more than two HTTP connections to the connection manager at the same time, [12] so it would otherwise have to wait until the connection manager responds to one of the requests.)<br />
<br />
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 TCP 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.<br />
<br />
If there is no traffic in either direction for an agreed amount of time (typically several 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 so 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. [13]<br />
<br />
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. Thus 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. Therefore, 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 were being used.<br />
<br />
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.<br />
<br />
==HTTP Overview==<br />
<br />
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).<br />
<br />
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 permitted by RFC 1945 or RFC 2616. For example, 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 might buffer each partial HTTP request or response and only forward the full request or response once it is available.<br />
<br />
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.<br />
<br />
Requests and responses MAY include HTTP headers not specified herein. The receiver SHOULD ignore any such headers.<br />
<br />
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). However, the responses to requests that are not part of the session sent over the same connection using HTTP pipelining (or queued to be sent over the same connection) might be delayed if they were sent while a request that is part of the session is being held (since the connection manager MUST send its responses in the same order that the requests were received, and the connection manager typically delays its responses).<br />
<br />
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.<br />
<br />
==<body/> Wrapper Element==<br />
<br />
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 transferred. The <body/> element and its content together MUST conform to the specifications set out in XML 1.0 [14]. They SHOULD also conform to Namespaces in XML [15]. The content MUST NOT contain any of the following (all defined in XML 1.0):<br />
<br />
* Partial XML elements<br />
* XML comments<br />
* XML processing instructions<br />
* Internal or external DTD subsets<br />
* Internal or external entity references (with the exception of predefined entities)<br />
<br />
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 "payloads" in this document, e.g., XMPP stanzas as defined in RFC 6120 or elements containing XML character data that represents objects using the JSON data interchange format as defined in RFC 4627 [16]). Each <body/> wrapper MAY contain payloads qualified under a wide variety of different namespaces.<br />
<br />
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.<br />
<br />
==Initiating a BOSH Session==<br />
===Session Creation Request===<br />
<br />
The first request from the client to the connection manager requests a new session.<br />
<br />
The <body/> element of the first request SHOULD possess the following attributes (they SHOULD NOT be included in any other requests except as specified under Adding Streams To A Session):<br />
<br />
* '''<nowiki>'to'</nowiki>''' -- This attribute specifies the target domain of the first stream.<br />
* '''<nowiki>'xml:lang'</nowiki>''' -- This attribute (as defined in Section 2.12 of XML 1.0 [17]) specifies the default language of any human-readable XML character data sent or received during the session.<br />
* '''<nowiki>'ver'</nowiki>''' -- This attribute specifies the highest version of the BOSH protocol that the client supports. The numbering scheme is "<major>.<minor>" (where the minor number MAY be incremented higher than a single digit, so it MUST be treated as a separate integer). Note: The 'ver' attribute should not be confused with the version of any protocol being transported.<br />
* '''<nowiki>'wait'</nowiki>''' -- This attribute specifies the longest time (in seconds) that the connection manager is allowed to wait before responding to any request during the session. This enables the client to limit the delay before it discovers any network failure, and to prevent its HTTP/TCP connection from expiring due to inactivity.<br />
* '''<nowiki>'hold'</nowiki>''' -- This attribute specifies the maximum number of requests the connection manager is allowed to keep waiting at any one time during the session. If the client is not able to use HTTP Pipelining then this SHOULD be set to "1".<br />
<br />
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 both typically one or two orders of magnitude!<br />
<br />
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:example.com:9999"). [18] A connection manager that is configured to work only with a single server (or only with a defined list of domains and the associated list of hostnames and ports that are serving those domains) MAY ignore the 'route' attribute. (Note that the 'to' attribute specifies the domain being served, not the hostname of the machine that is serving the domain.)<br />
<br />
The <body/> element of the first request MAY also possess a 'from' attribute, which specifies the originator of the first stream and which enables the connection manager to forward the originating entity's identity to the application server (e.g., the JabberID of an entity that is connecting to an XMPP server; see XEP-0206).<br />
<br />
A client MAY include an 'ack' attribute (set to "1") to indicate that it will be using acknowledgements throughout the session and that the absence of an 'ack' attribute in any request is meaningful (see Acknowledgements).<br />
<br />
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".<br />
<br />
'''Example 1. Requesting a BOSH session'''<br />
<source lang="xml"><br />
POST /webclient HTTP/1.1<br />
Host: httpcm.example.com<br />
Accept-Encoding: gzip, deflate<br />
Content-Type: text/xml; charset=utf-8<br />
Content-Length: 104<br />
<br />
<body content='text/xml; charset=utf-8'<br />
from='user@example.com'<br />
hold='1'<br />
rid='1573741820'<br />
to='example.com'<br />
route='xmpp:example.com:9999'<br />
ver='1.6'<br />
wait='60'<br />
ack='1'<br />
xml:lang='en'<br />
xmlns='http://jabber.org/protocol/httpbind'/><br />
</source><br />
<br />
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.<br />
===Session Creation Response===<br />
<br />
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):<br />
<br />
* '''<nowiki>'sid'</nowiki>''' -- This attribute specifies the SID<br />
* '''<nowiki>'wait'</nowiki>''' -- This is the longest time (in seconds) that the connection manager will wait before responding to any request during the session. The time MUST be less than or equal to the value specified in the session request.<br />
<br />
The <body/> element SHOULD also include the following attributes (they SHOULD NOT be included in any other responses):<br />
<br />
* '''<nowiki>'ver'</nowiki>''' -- This attribute specifies the highest version of the BOSH protocol that the connection manager supports, or the version specified by the client in its request, whichever is lower.<br />
* '''<nowiki>'polling'</nowiki>''' -- This attribute specifies the shortest allowable polling interval (in seconds). This enables the client to not send empty request elements more often than desired (see Polling Sessions and Overactivity).<br />
* '''<nowiki>'inactivity'</nowiki>''' -- This attribute specifies the longest allowable inactivity period (in seconds). This enables the client to ensure that the periods with no requests pending are never too long (see Polling Sessions and Inactivity).<br />
* '''<nowiki>'requests'</nowiki>''' -- This attribute enables the connection manager to limit the number of simultaneous requests the client makes (see Overactivity and Polling Sessions). The RECOMMENDED values are either "2" or one more than the value of the 'hold' attribute specified in the session request.<br />
* '''<nowiki>'hold'</nowiki>''' -- This attribute informs the client about the maximum number of requests the connection manager will keep waiting at any one time during the session. This value MUST NOT be greater than the value specified by the client in the session request.<br />
* '''<nowiki>'to'</nowiki>''' -- This attribute communicates the identity of the backend server to which the client is attempting to connect.<br />
<br />
The connection manager MAY include an 'accept' attribute in the session creation response element, to specify a space-separated list of 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.<br />
<br />
A connection manager MAY include an 'ack' attribute (set to the value of the 'rid' attribute of the session creation request) to indicate that it will be using acknowledgements throughout the session and that the absence of an 'ack' attribute in any response is meaningful (see Acknowledgements).<br />
<br />
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 can request.<br />
<br />
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. [19]<br />
<br />
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 a BOSH Session), then in the same response the connection manager SHOULD also include the 'secure' attribute set to "true" or "1".<br />
<br />
'''Example 2. Session creation response'''<br />
<source lang="xml"><br />
HTTP/1.1 200 OK<br />
Content-Type: text/xml; charset=utf-8<br />
Content-Length: 128<br />
<br />
<body wait='60'<br />
inactivity='30'<br />
polling='5'<br />
requests='2'<br />
hold='1'<br />
ack='1573741820'<br />
accept='deflate,gzip'<br />
maxpause='120'<br />
sid='SomeSID'<br />
charsets='ISO_8859-1 ISO-2022-JP'<br />
ver='1.6'<br />
from='example.com'<br />
xmlns='http://jabber.org/protocol/httpbind'/><br />
</source><br />
<br />
'''Example 3. Subsequent response with 'from' and 'secure' attributes'''<br />
<source lang="xml"><br />
HTTP/1.1 200 OK<br />
Content-Type: text/xml; charset=utf-8<br />
Content-Length: 128<br />
<br />
<body from='example.com'<br />
xmlns='http://jabber.org/protocol/httpbind'/><br />
</source><br />
<br />
==Sending and Receiving XML Payloads==<br />
<br />
After the client has successfully completed all required preconditions, it can send and receive XML payloads via the HTTP binding.<br />
<br />
'''Example 4. Transmitting payloads'''<br />
<source lang="xml"><br />
POST /webclient HTTP/1.1<br />
Host: httpcm.example.com<br />
Accept-Encoding: gzip, deflate<br />
Content-Type: text/xml; charset=utf-8<br />
Content-Length: 188<br />
<br />
<body rid='1249243562'<br />
sid='SomeSID'<br />
xmlns='http://jabber.org/protocol/httpbind'><br />
<message to='contact@example.com'<br />
xmlns='jabber:client'><br />
<body>Good morning!</body><br />
</message><br />
<message to='friend@example.com'<br />
xmlns='jabber:client'><br />
<body>Hey, what&apos;s up?</body><br />
</message><br />
</body><br />
</source><br />
<br />
Upon receipt of a request, the connection manager SHOULD forward the content of the <body/> element to the server as soon as possible. In any case it MUST forward the content from different requests in the order specified by their 'rid' attributes.<br />
<br />
The connection manager MUST also return an HTTP 200 OK response with a <body/> element to the client. Note: This does not indicate that the payloads have been successfully delivered to the application server.<br />
<br />
It is RECOMMENDED that the connection manager not return an HTTP result until a payload has arrived from the application server for delivery to the client. However, the connection manager SHOULD NOT wait longer than the time specified by the client in the 'wait' attribute of its Session Creation Request, and it SHOULD NOT keep more HTTP requests waiting at a time than the number specified in the 'hold' attribute of the session creation request. In any case it MUST respond to requests in the order specified by their 'rid' attributes.<br />
<br />
If there are no payloads waiting or ready to be delivered within the waiting period, then the connection manager SHOULD include an empty <body/> element in the HTTP result:<br />
<br />
'''Example 5. Empty response'''<br />
<source lang="xml"><br />
HTTP/1.1 200 OK<br />
Content-Type: text/xml; charset=utf-8<br />
Content-Length: 64<br />
<br />
<body xmlns='http://jabber.org/protocol/httpbind'/><br />
</source><br />
<br />
If the connection manager has received one or more payloads from the application server for delivery to the client, then it SHOULD return the payloads in the body of its response as soon as possible after receiving them from the server. The example below includes payloads qualified by different namespaces:<br />
<br />
'''Example 6. Response with queued stanza'''<br />
<source lang="xml"><br />
HTTP/1.1 200 OK<br />
Content-Type: text/xml; charset=utf-8<br />
Content-Length: 185<br />
<br />
<body xmlns='http://jabber.org/protocol/httpbind'<br />
xmlns:json='http://json.org/'><br />
<message from='contact@example.com'<br />
to='user@example.com'<br />
xmlns='jabber:client'><br />
<body>Good morning to you!</body><br />
</message><br />
<message from='friend@example.com'<br />
to='user@example.com'<br />
xmlns='jabber:client'><br />
<body>Not much, how about with you?</body><br />
</message><br />
<json:json><br />
[<br />
{<br />
"precision": "zip",<br />
"Latitude": 37.7668,<br />
"Longitude": -122.3959,<br />
"Address": "",<br />
"City": "SAN FRANCISCO",<br />
"State": "CA",<br />
"Zip": "94107",<br />
"Country": "US"<br />
},<br />
{<br />
"precision": "zip",<br />
"Latitude": 37.371991,<br />
"Longitude": -122.026020,<br />
"Address": "",<br />
"City": "SUNNYVALE",<br />
"State": "CA",<br />
"Zip": "94085",<br />
"Country": "US"<br />
}<br />
]<br />
</json:json><br />
</body><br />
</source><br />
<br />
The client MAY poll the connection manager for incoming payloads by sending an empty <body/> element.<br />
<br />
'''Example 7. Requesting XML Payloads'''<br />
<source lang="xml"><br />
POST /webclient HTTP/1.1<br />
Host: httpcm.example.com<br />
Accept-Encoding: gzip, deflate<br />
Content-Type: text/xml; charset=utf-8<br />
Content-Length: 88<br />
<br />
<body rid='1249243563'<br />
sid='SomeSID'<br />
xmlns='http://jabber.org/protocol/httpbind'/><br />
</source><br />
<br />
The connection manager MUST wait and respond in the same way as it does after receiving payloads from the client.<br />
<br />
==Acknowledgements==<br />
===Request Acknowledgements===<br />
<br />
When responding to a request that it has been holding, if the connection manager finds it has already received another request with a higher 'rid' attribute (typically while it was holding the first request), then it MAY acknowledge the reception to the client. The connection manager MAY set the 'ack' attribute of any response to the value of the highest 'rid' attribute it has received in the case where it has also received all requests with lower 'rid' values.<br />
<br />
'''Example 8. Response with request acknowledgement'''<br />
<source lang="xml"><br />
HTTP/1.1 200 OK<br />
Content-Type: text/xml; charset=utf-8<br />
Content-Length: 64<br />
<br />
<body ack='1249243564'<br />
xmlns='http://jabber.org/protocol/httpbind'/><br />
</source><br />
<br />
If the connection manager will be including 'ack' attributes on responses during a session, then it MUST include an 'ack' attribute in its session creation response, and set the 'ack' attribute of responses throughout the session. The only exception is that, after its session creation response, the connection manager SHOULD NOT include an 'ack' attribute in any response if the value would be the 'rid' of the request being responded to.<br />
<br />
If the connection manager is permitted to hold more than one request at a time, then the reception of a lower-than-expected 'ack' value from the connection manager (or the unexpected abscence of an 'ack' attribute) can give the client an early warning that a network failure might have occurred (e.g., if the client believes the connection manager should have received another request by the time it responded).<br />
===Response Acknowledgements===<br />
<br />
The client MAY similarly inform the connection manager about the responses it has received by setting the 'ack' attribute of any request to the value of the highest 'rid' of a request for which it has already received a response in the case where it has also received all responses associated with lower 'rid' values. If the client will be including 'ack' attributes on requests during a session, then it MUST include an 'ack' attribute (set to '1') in its session creation request, and set the 'ack' attribute of requests throughout the session. The only exception is that, after its session creation request, the client SHOULD NOT include an 'ack' attribute in any request if it has received responses to all its previous requests.<br />
<br />
'''Example 9. Request with response acknowledgement'''<br />
<source lang="xml"><br />
POST /webclient HTTP/1.1<br />
Host: httpcm.example.com<br />
Accept-Encoding: gzip, deflate<br />
Content-Type: text/xml; charset=utf-8<br />
Content-Length: 88<br />
<br />
<body rid='1249243566'<br />
sid='SomeSID'<br />
ack='1249243564'<br />
xmlns='http://jabber.org/protocol/httpbind'/><br />
</source><br />
<br />
After receiving a request with an 'ack' value less than the 'rid' of the last request that it has already responded to, the connection manager MAY inform the client of the situation by sending its next response immediately instead of waiting until it has payloads to send to the client (e.g., if some time has passed since it responded). In this case it SHOULD include a 'report' attribute set to one greater than the 'ack' attribute it received from the client, and a 'time' attribute set to the number of milliseconds since it sent the response associated with the 'report' attribute.<br />
<br />
'''Example 10. Response with report'''<br />
<source lang="xml"><br />
HTTP/1.1 200 OK<br />
Content-Type: text/xml; charset=utf-8<br />
Content-Length: 64<br />
<br />
<body report='1249243565'<br />
time='852'<br />
xmlns='http://jabber.org/protocol/httpbind'/><br />
</source><br />
<br />
Upon reception of a response with 'report' and 'time' attributes, if the client has still not received the response associated with the request identifier specified by the 'report' attribute, then it MAY choose to resend the request associated with the missing response (see Broken Connections).<br />
<br />
==Inactivity==<br />
<br />
After receiving a response from the connection manager, if none of the client's requests are still being held by the connection manager (and if the session is not a Polling Session), the client SHOULD make a new request as soon as possible. In any case, if no requests are being held, the client MUST make a new request before the maximum inactivity period has expired. The length of this period (in seconds) is specified by the 'inactivity' attribute in the session creation response.<br />
<br />
If the connection manager has responded to all the requests it has received within a session and the time since its last response is longer than the maximum inactivity period, then it SHOULD assume the client has been disconnected and terminate the session without informing the client. If the client subsequently makes another request, then the connection manager SHOULD respond as if the session does not exist.<br />
<br />
If the connection manager did not specify a maximum inactivity period in the session creation response, then it SHOULD allow the client to be inactive for as long as it chooses.<br />
<br />
If the session is not a polling session then the connection manager SHOULD specify a relatively short inactivity period to ensure that disconnections are discovered as quickly as possible. The RECOMMENDED time would be a little more than the number of seconds for a comfortable network round trip between the connection manager and the client under difficult network conditions (since the client can be expected to make a new request immediately -- see above).<br />
<br />
If a client encounters an exceptional temporary situation during which it will be unable to send requests to the connection manager for a period of time greater than the maximum inactivity period (e.g., while a runtime environment changes from one web page to another), and if the connection manager included a 'maxpause' attribute in its Session Creation Response, then the client MAY request a temporary increase to the maximum inactivity period by including a 'pause' attribute in a request. Note: If the connection manager did not specify a 'maxpause' attribute at the start of the session then the client MUST NOT send a 'pause' attribute during the session.<br />
<br />
'''Example 11. Requesting a Session Pause'''<br />
<source lang="xml"><br />
POST /webclient HTTP/1.1<br />
Host: httpcm.example.com<br />
Accept-Encoding: gzip, deflate<br />
Content-Type: text/xml; charset=utf-8<br />
Content-Length: 98<br />
<br />
<body rid='1249243564'<br />
sid='SomeSID'<br />
pause='60'<br />
xmlns='http://jabber.org/protocol/httpbind'/><br />
</source><br />
<br />
Upon reception of a session pause request, if the requested period is not greater than the maximum permitted time, then the connection manager SHOULD respond immediately to all pending requests (including the pause request) and temporarily increase the maximum inactivity period to the requested time. Note: The response to the pause request MUST NOT contain any payloads.<br />
<br />
Note: If the client simply wants the connection manager to return all the requests it is holding then it MAY set the value of the 'pause' attribute to be the value of the 'inactivity' attribute in the connection manager's session creation response. (If the client believes it is in danger of becoming disconnected indefinitely then it MAY even request a temporary reduction of the maximum inactivity period by specifying a 'pause' value less than the 'inactivity' value, thus enabling the connection manager to discover any subsequent disconnection more quickly.)<br />
<br />
The connection manager SHOULD set the maximum inactivity period back to normal upon reception of the next request from the client (assuming the connection manager has not already terminated the session).<br />
<br />
==Overactivity==<br />
<br />
The client SHOULD NOT make more simultaneous requests than specified by the 'requests' attribute in the connection manager's Session Creation Response. However the client MAY make one additional request if it is to pause or terminate a session.<br />
<br />
If during any period the client sends a sequence of new requests (i.e. requests with incremented rid attributes, not repeat requests) longer than the number specified by the 'requests' attribute, and if the connection manager has not yet responded to any of the requests, and if the last request did not include either a 'pause' attribute or a 'type' attribute set to "terminate", then the connection manager SHOULD consider that the client is making too many simultaneous requests, and terminate the HTTP session with a 'policy-violation' terminal binding error to the client. Note: This behavior applies to equally to normal and polling sessions.<br />
<br />
'''Example 12. Too many simultaneous requests response'''<br />
<source lang="xml"><br />
HTTP/1.1 200 OK<br />
Content-Type: text/xml; charset=utf-8<br />
Content-Length: 68<br />
<br />
<body type='terminate'<br />
condition='policy-violation'<br />
xmlns='http://jabber.org/protocol/httpbind'/><br />
</source><br />
<br />
Note: If the connection manager did not specify a 'requests' attribute in the session creation response, then it MUST allow the client to send as many simultaneous requests as it chooses.<br />
<br />
If during any period the client sends a sequence of new requests equal in length to the number specified by the 'requests' attribute, and if the connection manager has not yet responded to any of the requests, and if the last request was empty and did not include either a 'pause' attribute or a 'type' attribute set to "terminate", and if the last two requests arrived within a period shorter than the number of seconds specified by the 'polling' attribute in the session creation response, then the connection manager SHOULD consider that the client is making requests more frequently than it was permitted and terminate the HTTP session and return a 'policy-violation' terminal binding error to the client. Note: the behavior for Polling Sessions is slightly different.<br />
<br />
'''Example 13. Too frequent requests response'''<br />
<source lang="xml"><br />
HTTP/1.1 200 OK<br />
Content-Type: text/xml; charset=utf-8<br />
Content-Length: 68<br />
<br />
<body type='terminate'<br />
condition='policy-violation'<br />
xmlns='http://jabber.org/protocol/httpbind'/><br />
</source><br />
<br />
Note: If the connection manager did not specify a 'polling' attribute in the session creation response, then it MUST allow the client to send requests as frequently as it chooses.<br />
<br />
==Polling Sessions==<br />
<br />
It is not always possible for a constrained client to either use HTTP Pipelining or open more than one HTTP connection with the connection manager at a time. In this case the client SHOULD inform the connection manager by setting the values of the 'wait' and/or 'hold' attributes in its session creation request to "0", and then "poll" the connection manager at regular intervals throughout the session for payloads it might have received from the server. Note: Even if the client does not request a polling session, the connection manager MAY require a client to use polling by setting the 'requests' attribute (which specifies the number of simultaneous requests the client can make) of its Session Creation Response to "1", however this is NOT RECOMMENDED.<br />
<br />
If a session will use polling, the connection manager SHOULD specify a higher than normal value for the 'inactivity' attribute (see Inactivity) in its session creation response. The increase SHOULD be greater than the value it specifies for the 'polling' attribute.<br />
<br />
If the client sends two consecutive empty new requests (i.e. requests with incremented rid attributes, not repeat requests) within a period shorter than the number of seconds specified by the 'polling' attribute (the shortest allowable polling interval) in the session creation response, and if the connection manager's response to the first request contained no payloads, then upon reception of the second request the connection manager SHOULD terminate the HTTP session and return a 'policy-violation' terminal binding error to the client.<br />
<br />
'''Example 14. Too frequent polling response'''<br />
<source lang="xml"><br />
HTTP/1.1 200 OK<br />
Content-Type: text/xml; charset=utf-8<br />
Content-Length: 68<br />
<br />
<body type='terminate'<br />
condition='policy-violation'<br />
xmlns='http://jabber.org/protocol/httpbind'/><br />
</source><br />
<br />
Note: If the connection manager did not specify a 'polling' attribute in the session creation response, then it MUST allow the client to poll as frequently as it chooses.<br />
<br />
==Terminating the HTTP Session==<br />
<br />
At any time, the client MAY gracefully terminate the session by sending a <body/> element with a 'type' attribute set to "terminate". The termination request MAY include one or more payloads that the connection manager MUST forward to the server to ensure graceful logoff.<br />
<br />
'''Example 15. Session termination by client'''<br />
<source lang="xml"><br />
POST /webclient HTTP/1.1<br />
Host: httpcm.example.com<br />
Accept-Encoding: gzip, deflate<br />
Content-Type: text/xml; charset=utf-8<br />
Content-Length: 153<br />
<br />
<body rid='1249243565'<br />
sid='SomeSID'<br />
type='terminate'<br />
xmlns='http://jabber.org/protocol/httpbind'><br />
<presence type='unavailable'<br />
xmlns='jabber:client'/><br />
</body><br />
</source><br />
<br />
The connection manager SHOULD respond to this request with an HTTP 200 OK containing an empty <body/> element.<br />
<br />
'''Example 16. Connection manager acknowledges termination'''<br />
<source lang="xml"><br />
HTTP/1.1 200 OK<br />
Content-Type: text/xml; charset=utf-8<br />
Content-Length: 72<br />
<br />
<body type='terminate'<br />
xmlns='http://jabber.org/protocol/httpbind'/><br />
</source><br />
<br />
Upon receiving the response, the client MUST consider the HTTP session to have been terminated.<br />
<br />
==Request IDs==<br />
===Generation===<br />
<br />
The client MUST generate a large, random, positive integer for the initial 'rid' (see Security Considerations) and then increment that value by one for each subsequent request. The client MUST take care to choose an initial 'rid' that will never be incremented above 9007199254740991 [21] within the session. In practice, a session would have to be extraordinarily long (or involve the exchange of an extraordinary number of packets) to exceed the defined limit.<br />
===In-Order Message Forwarding===<br />
<br />
When a client makes simultaneous requests, the connection manager might receive them out of order. The connection manager MUST forward the payloads to the server and respond to the client requests in the order specified by the 'rid' attributes. The client MUST process responses received from the connection manager in the order the requests were made.<br />
<br />
The connection manager SHOULD expect the 'rid' attribute to be within a window of values greater than the 'rid' of the previous request. The size of the window is equal to the maximum number of simultaneous requests allowed by the connection manager. If it receives a request with a 'rid' greater than the values in the window, then the connection manager MUST terminate the session with an error:<br />
<br />
'''Example 17. Unexpected rid error'''<br />
<source lang="xml"><br />
HTTP/1.1 200 OK<br />
Content-Type: text/xml; charset=utf-8<br />
Content-Length: 68<br />
<br />
<body type='terminate'<br />
condition='item-not-found'<br />
xmlns='http://jabber.org/protocol/httpbind'/><br />
</source><br />
<br />
===Broken Connections===<br />
<br />
Unreliable network communications or client constraints can result in broken connections. The connection manager SHOULD remember the 'rid' and the associated HTTP response body of the client's most recent requests which were not session pause requests (see Inactivity) and which did not result in an HTTP or binding error. The number of responses to non-pause requests kept in the buffer SHOULD be either the same as the maximum number of simultaneous requests allowed by the connection manager or, if Acknowledgements are being used, the number of responses that have not yet been acknowledged.<br />
<br />
If the network connection is broken or closed before the client receives a response to a request from the connection manager, then the client MAY resend an exact copy of the original request. Whenever the connection manager receives a request with a 'rid' that it has already received, it SHOULD return an HTTP 200 (OK) response that includes the buffered copy of the original XML response to the client (i.e., a <body/> wrapper possessing appropriate attributes and optionally containing one or more XML payloads). If the original response is not available (e.g., it is no longer in the buffer), then the connection manager MUST return an 'item-not-found' terminal binding error:<br />
<br />
'''Example 18. Response not in buffer error'''<br />
<source lang="xml"><br />
HTTP/1.1 200 OK<br />
Content-Type: text/xml; charset=utf-8<br />
Content-Length: 68<br />
<br />
<body type='terminate'<br />
condition='item-not-found'<br />
xmlns='http://jabber.org/protocol/httpbind'/><br />
</source><br />
<br />
Note: The error is the same whether the 'rid' is too large or too small. This makes it more difficult for an attacker to discover an acceptable value.<br />
<br />
==Protecting Insecure Sessions==<br />
===Applicability===<br />
<br />
The OPTIONAL key sequencing mechanism described here MAY be used if the client's session with the connection manager is not secure. The session SHOULD be considered secure only if all client requests are made via SSL (or TLS) HTTP connections and the connection manager generates an unpredictable session ID. If the session is secure, it is not necessary to use this key sequencing mechanism.<br />
<br />
Even if the session is not secure, the unpredictable session and request IDs specified in the preceding sections of this document already provide a level of protection similar to that provided by a connection bound to a single pair of persistent TCP/IP connections, and thus provide sufficient protection against a 'blind' attacker. However, in some circumstances, the key sequencing mechanism defined below helps to protect against a more determined and knowledgeable attacker.<br />
<br />
It is important to recognize that the key sequencing mechanism defined below helps to protect only against an attacker who is able to view the contents of all requests or responses in an insecure session but who is not able to alter the contents of those requests (in this case, the mechanism prevents the attacker from injecting HTTP requests into the session, e.g., termination requests or responses). However, the key sequencing mechanism does not provide any protection when the attacker is able to alter the contents of insecure requests or responses.<br />
===Introduction===<br />
<br />
The HTTP requests of each session MAY be spread across a series of different socket connections. This would enable an unauthorized user that obtains the session ID and request ID of a session to then use their own socket connection to inject <body/> request elements into the session and receive the corresponding responses.<br />
<br />
The key sequencing mechanism below protects against such attacks by enabling a connection manager to detect <body/> request elements injected by a third party.<br />
===Generating the Key Sequence===<br />
<br />
Prior to requesting a new session, the client MUST select an unpredictable counter ("n") and an unpredictable value ("seed"). The client then processes the "seed" through a cryptographic hash and converts the resulting 160 bits to a hexadecimal string K(1). It does this "n" times to arrive at the initial key K(n). The hashing algorithm MUST be SHA-1 as defined in RFC 3174 [22].<br />
<br />
'''Example 19. Creating the key sequence'''<br />
<br />
K(1) = hex(SHA-1(seed))<br />
K(2) = hex(SHA-1(K(1)))<br />
...<br />
K(n) = hex(SHA-1(K(n-1)))<br />
<br />
<br />
===Use of Keys===<br />
<br />
The client MUST set the 'newkey' attribute of the first request in the session to the value K(n).<br />
<br />
'''Example 20. Session Request with Initial Key'''<br />
<source lang="xml"><br />
POST /webclient HTTP/1.1<br />
Host: httpcm.example.com<br />
Accept-Encoding: gzip, deflate<br />
Content-Type: text/xml; charset=utf-8<br />
Content-Length: 104<br />
<br />
<body content='text/xml; charset=utf-8'<br />
hold='1'<br />
rid='1573741820'<br />
to='example.com'<br />
wait='60'<br />
xml:lang='en'<br />
newkey='ca393b51b682f61f98e7877d61146407f3d0a770'<br />
xmlns='http://jabber.org/protocol/httpbind'/><br />
</source><br />
<br />
The client MUST set the 'key' attribute of all subsequent requests to the value of the next key in the generated sequence (decrementing from K(n-1) towards K(1) with each request sent).<br />
<br />
'''Example 21. Request with Key'''<br />
<source lang="xml"><br />
POST /webclient HTTP/1.1<br />
Host: httpcm.example.com<br />
Accept-Encoding: gzip, deflate<br />
Content-Type: text/xml; charset=utf-8<br />
Content-Length: 88<br />
<br />
<body rid='1573741821'<br />
sid='SomeSID'<br />
key='bfb06a6f113cd6fd3838ab9d300fdb4fe3da2f7d'<br />
xmlns='http://jabber.org/protocol/httpbind'/><br />
</source><br />
<br />
The connection manager MAY verify the key by calculating the SHA-1 hash of the key and comparing it to the 'newkey' attribute of the previous request (or the 'key' attribute if the 'newkey' attribute was not set). If the values do not match (or if it receives a request without a 'key' attribute and the 'newkey' or 'key' attribute of the previous request was set), then the connection manager MUST NOT process the element, MUST terminate the session, and MUST return an 'item-not-found' terminal binding error.<br />
<br />
'''Example 22. Invalid Key Sequence Error'''<br />
<source lang="xml"><br />
HTTP/1.1 200 OK<br />
Content-Type: text/xml; charset=utf-8<br />
Content-Length: 68<br />
<br />
<body type='terminate'<br />
condition='item-not-found'<br />
xmlns='http://jabber.org/protocol/httpbind'/><br />
</source><br />
<br />
===Switching to Another Key Sequence===<br />
<br />
A client SHOULD choose a high value for "n" when generating the key sequence. However, if the session lasts long enough that the client arrives at the last key in the sequence K(1) then the client MUST switch to a new key sequence.<br />
<br />
The client MUST:<br />
<br />
1. Choose new values for "seed" and "n".<br />
2. Generate a new key sequence using the algorithm defined above.<br />
3. Set the 'key' attribute of the request to the next value in the old sequence (i.e. K(1), the last value).<br />
4. Set the 'newkey' attribute of the request to the value K(n) from the new sequence.<br />
<br />
'''Example 23. New Key Sequence'''<br />
<source lang="xml"><br />
POST /webclient HTTP/1.1<br />
Host: httpcm.example.com<br />
Accept-Encoding: gzip, deflate<br />
Content-Type: text/xml; charset=utf-8<br />
Content-Length: 188<br />
<br />
<body rid='1573741822'<br />
sid='SomeSID'<br />
key='6f825e81f4532b2c5fa2d12457d8a1f22e8f838e'<br />
newkey='113f58a37245ec9637266cf2fb6e48bfeaf7964e'<br />
xmlns='http://jabber.org/protocol/httpbind'><br />
<message to='contact@example.com'<br />
xmlns='jabber:client'><br />
<body>I said "Hi!"</body><br />
</message><br />
</body><br />
</source><br />
<br />
==Multiple Streams==<br />
===Introduction===<br />
<br />
The OPTIONAL feature described in this section enables multiple XML streams to be contained within a single HTTP session. This feature is essential in runtime environments that prevent HTTP Pipelining, thereby constraining the number of simultaneous HTTP requests a client can make to each connection manager, since clients running in such environments need multi-stream sessions if they are to connect using more than one account at the same time. This feature also reduces network traffic for any client that needs to establish parallel streams over HTTP.<br />
===Discovery===<br />
<br />
If a connection manager supports the multi-streams feature, it MUST include a 'stream' attribute in its Session Creation Response. If a client does not receive the 'stream' attribute then it MUST assume that the connection manager does not support the feature. [23]<br />
<br />
The 'stream' attribute identifies the first stream to be opened for the session. The value of each 'stream' attribute MUST be an opaque and unpredictable name that is unique within the context of the connection manager application.<br />
<br />
'''Example 24. Session creation response with stream name'''<br />
<source lang="xml"><br />
HTTP/1.1 200 OK<br />
Content-Type: text/xml; charset=utf-8<br />
Content-Length: 128<br />
<br />
<body wait='60'<br />
inactivity='30'<br />
polling='5'<br />
requests='2'<br />
hold='1'<br />
accept='deflate,gzip'<br />
stream='firstStreamName'<br />
maxpause='120'<br />
sid='SomeSID'<br />
charsets='ISO_8859-1 ISO-2022-JP'<br />
ver='1.6'<br />
from='example.com'<br />
xmlns='http://jabber.org/protocol/httpbind'/><br />
</source><br />
<br />
===Adding Streams To A Session===<br />
<br />
If the connection manager included a 'stream' attribute in its session creation response then the client MAY ask it to open another stream at any time by sending it an empty <body/> element with a 'to' attribute. The request MUST include valid 'sid' and 'rid' [24] attributes, and SHOULD also include an 'xml:lang' attribute. The request MAY include 'route', 'from' and 'secure' attributes (see Session Creation Request), but it SHOULD NOT include 'ver', 'content', 'hold' or 'wait' attributes (since a new session is not being created).<br />
<br />
'''Example 25. Requesting another stream'''<br />
<source lang="xml"><br />
POST /webclient HTTP/1.1<br />
Host: httpcm.example.com<br />
Accept-Encoding: gzip, deflate<br />
Content-Type: text/xml; charset=utf-8<br />
Content-Length: 104<br />
<br />
<body sid='SomeSID'<br />
rid='1573741820'<br />
to='example.com'<br />
route='xmpp:example.com:9999'<br />
xml:lang='en'<br />
xmlns='http://jabber.org/protocol/httpbind'/><br />
</source><br />
<br />
If the connection manager did not indicate its support for multiple streams at the start of the session, then it MUST ignore the extra attributes and treat the request as a normal empty request for payloads (see Sending and Receiving XML Payloads). [25] Otherwise it MUST open a new stream with the specified server (see Session Creation Response), generate a new stream name, and respond to the client with the name. The response MAY also include 'from' and 'secure' attributes, but it SHOULD NOT include 'sid', 'requests', 'polling', 'hold', 'inactivity', 'maxpause', 'accept', 'charsets', 'ver' or 'wait' attributes.<br />
<br />
'''Example 26. Add stream response'''<br />
<source lang="xml"><br />
HTTP/1.1 200 OK<br />
Content-Type: text/xml; charset=utf-8<br />
Content-Length: 128<br />
<br />
<body stream='secondStreamName'<br />
from='example.com'<br />
xmlns='http://jabber.org/protocol/httpbind'/><br />
</source><br />
<br />
Note: If the response did not include either 'from' or 'secure' attributes then they MAY be sent in a subsequent response instead (see Session Creation Response). In that case the 'stream' attribute MUST also be specified.<br />
===Transmitting Payloads===<br />
<br />
If more than one stream has been opened within a session, then all non-empty <body/> elements sent by the connection manager MUST include a 'stream' attribute that specifies which stream all the payloads it contains belong to. The client SHOULD include a 'stream' attribute for the same purpose. The client MAY omit the 'stream' attribute if it wants the connection manager to broadcast the payloads over all open streams. Note: A <body/> element MUST NOT contain different payloads for different streams.<br />
<br />
If a stream name does not correspond to one of the session's open streams, then the receiving connection manager SHOULD return an 'item-not-found' terminal binding error, or the receiving client SHOULD terminate the session. However, if the receiving entity has only just closed the stream (and the sender might not have been aware of that when it sent the payloads), then it MAY instead simply silently ignore any payloads the <body/> element contains.<br />
<br />
Note: Empty <body/> elements that do not include a 'from' or 'secure' attribute SHOULD NOT include a 'stream' attribute (since nothing is being transmitted for any stream). If such a <body/> element does include a 'stream' attribute then the receiving entity SHOULD ignore the attribute.<br />
<br />
'''Example 27. Client sends payload with a stream name'''<br />
<source lang="xml"><br />
POST /webclient HTTP/1.1<br />
Host: httpcm.example.com<br />
Accept-Encoding: gzip, deflate<br />
Content-Type: text/xml; charset=utf-8<br />
Content-Length: 188<br />
<br />
<body rid='1249243562'<br />
sid='SomeSID'<br />
stream='secondStreamName'<br />
xmlns='http://jabber.org/protocol/httpbind'><br />
<message to='contact@example.com'<br />
xmlns='jabber:client'><br />
<body>I said hello.</body><br />
</message><br />
</body><br />
</source><br />
<br />
Note: The value of the 'stream' attribute of the response MAY be different than the corresponding request. [26]<br />
<br />
'''Example 28. Connection manager responds with a different stream name'''<br />
<source lang="xml"><br />
HTTP/1.1 200 OK<br />
Content-Type: text/xml; charset=utf-8<br />
Content-Length: 185<br />
<br />
<body stream='firstStreamName'<br />
xmlns='http://jabber.org/protocol/httpbind'><br />
<message from='contact@example.com'<br />
to='user@example.com'<br />
xmlns='jabber:client'><br />
<body>Hi yourself!</body><br />
</message><br />
</body><br />
</source><br />
<br />
If no stream name is specified by the connection manager then the client MUST assume the payloads are associated with the first stream (even if the first stream has been closed).<br />
<br />
If no stream name is specified by the client then the connection manager MUST broadcast the payloads over all open streams. [27]<br />
<br />
'''Example 29. Client asks for a payload to be broadcast'''<br />
<source lang="xml"><br />
POST /webclient HTTP/1.1<br />
Host: httpcm.example.com<br />
Accept-Encoding: gzip, deflate<br />
Content-Type: text/xml; charset=utf-8<br />
Content-Length: 188<br />
<br />
<body rid='1249243562'<br />
sid='SomeSID'<br />
xmlns='http://jabber.org/protocol/httpbind'><br />
<presence xmlns='jabber:client'><br />
<show>away</show><br />
</presence><br />
</body><br />
</source><br />
<br />
===Closing a Stream===<br />
<br />
If more than one stream is open within a session, the client MAY close one open stream at any time using the procedure described in the section Terminating the HTTP Session above, taking care to specify the stream name with a 'stream' attribute. If the client closes the last stream the connection manager MUST terminate the session. If the client does not specify a stream name then the connection manager MUST close all open streams (sending any payloads the terminate request contains to all streams), and terminate the session.<br />
<br />
'''Example 30. Client closes one stream'''<br />
<source lang="xml"><br />
POST /webclient HTTP/1.1<br />
Host: httpcm.example.com<br />
Accept-Encoding: gzip, deflate<br />
Content-Type: text/xml; charset=utf-8<br />
Content-Length: 153<br />
<br />
<body rid='1249243564'<br />
sid='SomeSID'<br />
stream='secondStreamName'<br />
type='terminate'<br />
xmlns='http://jabber.org/protocol/httpbind'><br />
<presence type='unavailable'<br />
xmlns='jabber:client'/><br />
</body><br />
</source><br />
<br />
===Error Conditions===<br />
<br />
If more than one stream is open within a session, the connection manager MAY include a 'stream' attribute in a fatal binding error (see Terminal Binding Conditions). If a 'stream' attribute is specified then the stream MUST be closed by both entities but the session SHOULD NOT be terminated.<br />
<br />
'''Example 31. Fatal stream error'''<br />
<source lang="xml"><br />
HTTP/1.1 200 OK<br />
Content-Type: text/xml; charset=utf-8<br />
Content-Length: 68<br />
<br />
<body type='terminate'<br />
condition='remote-connection-failed'<br />
stream='secondStreamName'<br />
xmlns='http://jabber.org/protocol/httpbind'/><br />
</source><br />
<br />
Note: If the connection manager does not include a 'stream' attribute in a fatal binding error then all the session's open streams MUST be closed by both entities and the session MUST be terminated.<br />
<br />
==Error and Status Codes==<br />
<br />
There are four types of error and status reporting in HTTP responses:<br />
<br />
'''Table 1: Error Condition Types'''<br />
{| border="1"<br />
!Condition Type<br />
!Description<br />
|-<br />
|HTTP Conditions (Deprecated) <br />
|The connection manager responds to an invalid request from a legacy client with a standard HTTP error. These are used for binding syntax errors, possible attacks, etc. Note that constrained clients are unable to differentiate between HTTP errors.<br />
|-<br />
|Terminal Binding Conditions <br />
|These error conditions can be read by constrained clients. They are used for connection manager problems, abstracting stream errors, communication problems between the connection manager and the server, and invalid client requests (binding syntax errors, possible attacks, etc.)<br />
|-<br />
|Recoverable Binding Conditions <br />
|These report communication problems between the connection manager and the client. They do not terminate the session. Clients recover from these errors by resending all the preceding <body/> wrappers that have not received responses.<br />
|-<br />
|Transported Protocol Conditions <br />
|Errors relating to the XML payloads within <body/> wrappers are, in general, defined in the documentation of the protocol being transported. They do not terminate the session.<br />
|}<br />
<br />
Full descriptions are provided below.<br />
===HTTP Conditions===<br />
<br />
Note: All HTTP codes except 200 have been superseded by Terminal Binding Conditions to allow clients to determine whether the source of errors is the connection manager application or an HTTP intermediary.<br />
<br />
A legacy client (or connection manager) is a client (or connection manager) that did not include a 'ver' attribute in its session creation request (or response). A legacy client (or connection manager) will interpret (or respond with) HTTP error codes according to the table below. Non-legacy connection managers SHOULD NOT send HTTP error codes unless they are communicating with a legacy client. Upon receiving an HTTP error (400, 403, 404), a legacy client or any client that is communicating with a legacy connection manager MUST consider the HTTP session to be null and void. A non-legacy client that is communicating with a non-legacy connection manager MAY consider that the session is still active.<br />
<br />
'''Table 2: HTTP Error and Status Codes'''<br />
{| border="1"<br />
!Code<br />
!Name<br />
!Superseded by<br />
!Purpose<br />
|-<br />
|200 <br />
|OK <br />
|<nowiki>-</nowiki><br />
|Response to valid client request.<br />
|-<br />
|400 <br />
|Bad Request <br />
|bad-request <br />
|Inform client that the format of an HTTP header or binding element is unacceptable (e.g., syntax error).<br />
|-<br />
|403<br />
|Forbidden <br />
|policy-violation <br />
|Inform client that it has broken the session rules (polling too frequently, requesting too frequently, too many simultaneous requests).<br />
|-<br />
|404 <br />
|Not Found <br />
|item-not-found <br />
|Inform client that (1) 'sid' is not valid, (2) 'stream' is not valid, (3) 'rid' is larger than the upper limit of the expected window, (4) connection manager is unable to resend response, (5) 'key' sequence is invalid.<br />
|}<br />
<br />
Note: No other HTTP error and status codes were defined in the early versions of BOSH (e.g., Internal Server Error).<br />
<br />
===Terminal Binding Conditions===<br />
<br />
In any response it sends to the client, the connection manager MAY return a fatal error by setting a 'type' attribute of the <body/> element to "terminate". These binding errors imply that the HTTP session is terminated (unless a 'stream' attribute is specified -- see Multiple Stream Error Conditions).<br />
<br />
Note: Although many of these conditions are similar to the XMPP stream error conditions specified in RFC 6120, they are not to be confused with XMPP stream errors. In cases where BOSH is being used to transport XMPP, any fatal XMPP stream error conditions experienced between the connection manager and the XMPP server SHOULD only be reported using the "remote-stream-error" condition as described below.<br />
<br />
'''Example 32. Remote connection failed error'''<br />
<source lang="xml"><br />
HTTP/1.1 200 OK<br />
Content-Type: text/xml; charset=utf-8<br />
Content-Length: 68<br />
<br />
<body type='terminate'<br />
condition='remote-connection-failed'<br />
xmlns='http://jabber.org/protocol/httpbind'/><br />
</source><br />
<br />
The following values of the 'condition' attribute are defined:<br />
<br />
'''Table 3: Terminal Binding Error Conditions'''<br />
{| border="1"<br />
!Condition<br />
!Purpose<br />
|-<br />
|bad-request* <br />
|The format of an HTTP header or binding element received from the client is unacceptable (e.g., syntax error).<br />
|-<br />
|host-gone <br />
|The target domain specified in the 'to' attribute or the target host or port specified in the 'route' attribute is no longer serviced by the connection manager.<br />
|-<br />
|host-unknown <br />
|The target domain specified in the 'to' attribute or the target host or port specified in the 'route' attribute is unknown to the connection manager.<br />
|-<br />
|improper-addressing <br />
|The initialization element lacks a 'to' or 'route' attribute (or the attribute has no value) but the connection manager requires one.<br />
|-<br />
|internal-server-error <br />
|The connection manager has experienced an internal error that prevents it from servicing the request.<br />
|-<br />
|item-not-found* <br />
|(1) 'sid' is not valid, (2) 'stream' is not valid, (3) 'rid' is larger than the upper limit of the expected window, (4) connection manager is unable to resend response, (5) 'key' sequence is invalid.<br />
|-<br />
|other-request <br />
|Another request being processed at the same time as this request caused the session to terminate.<br />
|-<br />
|policy-violation* <br />
|The client has broken the session rules (polling too frequently, requesting too frequently, sending too many simultaneous requests).<br />
|-<br />
|remote-connection-failed <br />
|The connection manager was unable to connect to, or unable to connect securely to, or has lost its connection to, the server.<br />
|-<br />
|remote-stream-error <br />
|Encapsulates an error in the protocol being transported.<br />
|-<br />
|see-other-uri <br />
|The connection manager does not operate at this URI (e.g., the connection manager accepts only SSL or TLS connections at some https: URI rather than the http: URI requested by the client). The client can try POSTing to the URI in the content of the <uri/> child element.<br />
|-<br />
|system-shutdown <br />
|The connection manager is being shut down. All active HTTP sessions are being terminated. No new sessions can be created.<br />
|-<br />
|undefined-condition <br />
|The error is not one of those defined herein; the connection manager SHOULD include application-specific information in the content of the <body/> wrapper.<br />
|}<br />
<br />
* If the client did not include a 'ver' attribute in its session creation request then the connection manager SHOULD send a deprecated HTTP Error Condition instead of this terminal binding condition. If the connection manager did not include a 'ver' attribute in its session creation response then the client SHOULD expect it to send a deprecated HTTP Error Condition instead of this terminal binding condition.<br />
<br />
The following is an example of a "see-other-uri" condition:<br />
<br />
'''Example 33. See other URI error'''<br />
<source lang="xml"><br />
HTTP/1.1 200 OK<br />
Content-Type: text/xml; charset=utf-8<br />
Content-Length: 68<br />
<br />
<body condition='see-other-uri'<br />
type='terminate'<br />
xmlns='http://jabber.org/protocol/httpbind'><br />
<uri>https://secure.jabber.org/xmppcm</uri><br />
</body><br />
</source><br />
<br />
The following is an example including a "remote-stream-error" condition:<br />
<br />
'''Example 34. Remote error'''<br />
<source lang="xml"><br />
HTTP/1.1 200 OK<br />
Content-Type: text/xml; charset=utf-8<br />
Content-Length: 68<br />
<br />
<body condition='remote-stream-error'<br />
type='terminate'<br />
xmlns='http://jabber.org/protocol/httpbind'<br />
xmlns:stream='http://etherx.jabber.org/streams'><br />
<message from='contact@example.com'<br />
to='user@example.com'<br />
xmlns='jabber:client'><br />
<body>I said "Hi!"</body><br />
</message><br />
<stream:error><br />
<xml-not-well-formed xmlns='urn:ietf:params:xml:ns:xmpp-streams'/><br />
<text xmlns='urn:ietf:params:xml:ns:xmpp-streams'<br />
xml:lang='en'><br />
Some special application diagnostic information!<br />
</text><br />
<escape-your-data xmlns='application-ns'/><br />
</stream:error><br />
</body><br />
</source><br />
<br />
Naturally, the client MAY report binding errors to the connection manager as well, although this is unlikely.<br />
===Recoverable Binding Conditions===<br />
<br />
In any response it sends to the client, the connection manager MAY return a recoverable error by setting a 'type' attribute of the <body/> element to "error". These errors do not imply that the HTTP session is terminated.<br />
<br />
If it decides to recover from the error, then the client MUST repeat the HTTP request that resulted in the error, as well as all the preceding HTTP requests that have not received responses. The content of these requests MUST be identical to the <body/> elements of the original requests. This enables the connection manager to recover a session after the previous request was lost due to a communication failure.<br />
<br />
'''Example 35. Recoverable error'''<br />
<source lang="xml"><br />
HTTP/1.1 200 OK<br />
Content-Type: text/xml; charset=utf-8<br />
Content-Length: 68<br />
<br />
<body type='error'<br />
xmlns='http://jabber.org/protocol/httpbind'/><br />
</source><br />
<br />
===XML Payload Conditions===<br />
<br />
Application-level error conditions described in the documentation of the protocol being transported are routed to the client through the connection manager. They are transparent to the connection manager, and therefore out of scope for the transport binding defined herein.<br />
<br />
==Implementation Notes==<br />
===HTTP Pipelining===<br />
<br />
Even if the client requests HTTP Pipelining and the connection manager supports it, there is no guarantee that pipelining will succeed, because it might not be supported by intermediate proxies.<br />
<br />
The best the client can do is to request the use of HTTP Pipelining by setting the 'hold' attribute to a value of "1". If HTTP Pipelining does not work (because the server returns HTTP 1.0 or connection:close), then the client SHOULD degrade gracefully by using multiple connections.<br />
<br />
==Security Considerations==<br />
===Connection Between Client and BOSH Service===<br />
<br />
All communications between a client and a BOSH service SHOULD occur over encrypted HTTP connections. Negotiation of encryption between the client and the connection manager SHOULD occur at the transport layer or the HTTP layer, not the application layer; such negotiation SHOULD follow the HTTP/SSL protocol defined in SSL [28], although MAY follow the HTTP/TLS protocol defined in RFC 2818 [29] or the TLS Within HTTP protocol defined in RFC 2817 [30].<br />
<br />
If the HTTP connection used to send the initial session request is encrypted, then all the other HTTP connections used within the session MUST also be encrypted. Furthermore, if authentication certificates are exchanged when establishing the encrypted connection that is used to send the initial session request, then the client and/or connection manager SHOULD ensure that the same authentication certificates are employed for all subsequent connections used by the session. Once such a "secure session" has been established:<br />
<br />
* If the connection manager refuses to establish an encrypted connection or offers a different certificate, then the client SHOULD close the connection and terminate the session without sending any more requests.<br />
* If the client sends a wrapper element that is part of a "secure session" over a connection that either is not encrypted or uses a different certificate, then the connection manager SHOULD simply close the connection. The connection manager SHOULD NOT terminate the session since that would facilitate denial of service attacks.<br />
<br />
===Connection Between BOSH Service and Application===<br />
<br />
A BOSH service SHOULD encrypt its connection to the backend application using appropriate technologies such as Secure Sockets Layer (SSL), Transport Layer Security (TLS), and StartTLS if supported by the backend application. Alternatively, the BOSH service can be considered secure (1) if it is running on the same physical machine as the backend application or (2) if it running on the same private network as the backend application and the administrators are sure that unknown individuals or processes do not have access to that private network.<br />
<br />
If data privacy is desired, the client SHOULD encrypt its messages using an application-specific end-to-end encryption technology, because there is no way for the client to be sure that the BOSH service encrypts its connection to the application; methods for doing so are outside the scope of this specification.<br />
===Unpredictable SID and RID===<br />
<br />
The session identifier (SID) and initial request identifier (RID) are security-critical and therefore MUST be both unpredictable and nonrepeating (see RFC 1750 [31] for recommendations regarding randomness of SIDs and initial RIDs for security purposes).<br />
===Use of SHA-1===<br />
<br />
Recent research has shown that in select cases it is possible to compromise the hashes produced by the SHA-1 hashing algorithm (see RFC 4270 [32]). However, the use to which SHA-1 is put in BOSH will likely minimize the applicability of the attacks described in the literature. Furthermore, current estimates suggest that even with the recently-discovered attack, it would still take one year of computing by a government-sized entity to produce a collision.<br />
<br />
==IANA Considerations==<br />
<br />
TCP port 5280, conventially used for communication between BOSH clients and BOSH connection mangers, is registered with the Internet Assigned Numbers Authority (IANA) [33] in its port registry at IANA Port Numbers Registry [34], with a keyword of "xmpp-bosh". (Although use of this port is OPTIONAL, it is helpful to define this port in a standardized way so that BOSH clients can contact any given XMPP service via BOSH without the need either for DNS TXT records as described in Discovering Alternative XMPP Connection Methods [35] or for more advanced methods such as U-NAPTR.<br />
<br />
==XMPP Registrar Considerations==<br />
===Protocol Namespaces===<br />
<br />
The XMPP Registrar includes 'http://jabber.org/protocol/httpbind' in its registry of protocol namespaces.<br />
<br />
==XML Schema==<br />
<source lang="xml"><br />
<?xml version='1.0' encoding='UTF-8'?><br />
<br />
<xs:schema<br />
xmlns:xs='http://www.w3.org/2001/XMLSchema'<br />
xmlns:stream='http://etherx.jabber.org/streams'<br />
targetNamespace='http://jabber.org/protocol/httpbind'<br />
xmlns='http://jabber.org/protocol/httpbind'<br />
elementFormDefault='qualified'><br />
<br />
<xs:annotation><br />
<xs:documentation><br />
The protocol documented by this schema is defined in<br />
XEP-0124: http://www.xmpp.org/extensions/xep-0124.html<br />
</xs:documentation><br />
</xs:annotation><br />
<br />
<xs:import namespace='http://www.w3.org/XML/1998/namespace'<br />
schemaLocation='http://www.w3.org/2001/03/xml.xsd'/><br />
<br />
<xs:element name='body'><br />
<xs:complexType><br />
<xs:choice><br />
<xs:element name='uri'<br />
minOccurs='0'<br />
maxOccurs='1'<br />
type='xs:string'/><br />
<xs:any namespace='##other'<br />
minOccurs='0'<br />
maxOccurs='unbounded'<br />
processContents='lax'/><br />
</xs:choice><br />
<xs:attribute name='accept' type='xs:string' use='optional'/><br />
<xs:attribute name='ack' type='xs:positiveInteger' use='optional'/><br />
<xs:attribute name='authid' type='xs:string' use='optional'/><br />
<xs:attribute name='charsets' type='xs:NMTOKENS' use='optional'/><br />
<xs:attribute name='condition' use='optional'><br />
<xs:simpleType><br />
<xs:restriction base='xs:NCName'><br />
<xs:enumeration value='bad-request'/><br />
<xs:enumeration value='host-gone'/><br />
<xs:enumeration value='host-unknown'/><br />
<xs:enumeration value='improper-addressing'/><br />
<xs:enumeration value='internal-server-error'/><br />
<xs:enumeration value='item-not-found'/><br />
<xs:enumeration value='other-request'/><br />
<xs:enumeration value='policy-violation'/><br />
<xs:enumeration value='remote-connection-failed'/><br />
<xs:enumeration value='remote-stream-error'/><br />
<xs:enumeration value='see-other-uri'/><br />
<xs:enumeration value='system-shutdown'/><br />
<xs:enumeration value='undefined-condition'/><br />
</xs:restriction><br />
</xs:simpleType><br />
</xs:attribute><br />
<xs:attribute name='content' type='xs:string' use='optional'/><br />
<xs:attribute name='from' type='xs:string' use='optional'/><br />
<xs:attribute name='hold' type='xs:unsignedByte' use='optional'/><br />
<xs:attribute name='inactivity' type='xs:unsignedShort' use='optional'/><br />
<xs:attribute name='key' type='xs:string' use='optional'/><br />
<xs:attribute name='maxpause' type='xs:unsignedShort' use='optional'/><br />
<xs:attribute name='newkey' type='xs:string' use='optional'/><br />
<xs:attribute name='pause' type='xs:unsignedShort' use='optional'/><br />
<xs:attribute name='polling' type='xs:unsignedShort' use='optional'/><br />
<xs:attribute name='report' type='xs:positiveInteger' use='optional'/><br />
<xs:attribute name='requests' type='xs:unsignedByte' use='optional'/><br />
<xs:attribute name='rid' type='xs:positiveInteger' use='optional'/><br />
<xs:attribute name='route' type='xs:string' use='optional'/><br />
<xs:attribute name='sid' type='xs:string' use='optional'/><br />
<xs:attribute name='stream' type='xs:string' use='optional'/><br />
<xs:attribute name='time' type='xs:unsignedShort' use='optional'/><br />
<xs:attribute name='to' type='xs:string' use='optional'/><br />
<xs:attribute name='type' use='optional'><br />
<xs:simpleType><br />
<xs:restriction base='xs:NCName'><br />
<xs:enumeration value='error'/><br />
<xs:enumeration value='terminate'/><br />
</xs:restriction><br />
</xs:simpleType><br />
</xs:attribute><br />
<xs:attribute name='ver' type='xs:string' use='optional'/><br />
<xs:attribute name='wait' type='xs:unsignedShort' use='optional'/><br />
<xs:attribute ref='xml:lang' use='optional'/><br />
<xs:anyAttribute namespace='##other' processContents='lax'/><br />
</xs:complexType><br />
</xs:element><br />
<br />
</xs:schema><br />
</source><br />
<br />
==Acknowledgements==<br />
<br />
Thanks to Mike Cumings, Tomas Karasek, Tobias Markmann, Chris Seymour, Safa Sofuoğlu, Stefan Strigler, Matthew Wild, Kevin Winters, and Christopher Zorn for their feedback.<br />
<br />
==Appendices==<br />
===Appendix A: Document Information===<br />
<br />
Series: XEP<br />
Number: 0124<br />
Publisher: XMPP Standards Foundation<br />
Status: Draft<br />
Type: Standards Track<br />
Version: 1.10<br />
Last Updated: 2010-07-02<br />
Approving Body: XMPP Council<br />
Dependencies: RFC 1945, RFC 2616, RFC 3174<br />
Supersedes: None<br />
Superseded By: None<br />
Short Name: bosh<br />
Schema: <http://www.xmpp.org/schemas/httpbind.xsd><br />
Source Control: HTML RSS<br />
This document in other formats: XML PDF<br />
===Appendix B: Author Information===<br />
Ian Paterson<br />
<br />
Email: ian.paterson@clientside.co.uk<br />
JabberID: ian@zoofy.com<br />
Dave Smith<br />
<br />
Email: dizzyd@jabber.org<br />
JabberID: dizzyd@jabber.org<br />
Peter Saint-Andre<br />
<br />
Email: stpeter@jabber.org<br />
JabberID: stpeter@jabber.org<br />
URI: https://stpeter.im/<br />
Jack Moffitt<br />
<br />
Email: jack@chesspark.com<br />
JabberID: jack@chesspark.com<br />
===附录C:法律通告===<br />
*版权<br />
:XMPP扩展协议的版权(1999 - 2011)归XMPP标准化基金会(XSF)所有.<br />
*权限<br />
:特此授权,费用全免,对任何获得本协议副本的人,对使用本协议没有限制,包括不限制在软件程序中实现本协议,不限制在网络服务中布署本协议,不限制拷贝,修改,合并,发行,翻译,分发,转授,或销售本协议的副本,被允许使用本协议做了以上工作的人士,应接受前述的版权声明和本许可通知并且必须包含在所有的副本或实质性部分的规格中.除非单独的许可,被重新分发的修改工作,不得含有关于作者,标题,编号,或出版者的规格的误导性资料,并不得宣称修改工作是由本文的作者,作者所属的任何组织或项目,或XMPP标准基金会签注。<br />
*免责声明<br />
:'''<nowiki>##</nowiki>特别注意:本协议是提供的“原样”的基础,没有担保或任何形式的条件,明示或暗示,包括,但不限于任何担保或关于名称,非侵权性,适销性或适合作某一特定目的的条件. ##'''<br />
*责任限制<br />
:在任何情况下以及没有任何法律规定时,不论是侵权行为(包括疏忽),合同或其它方面,除非根据适用法律的要求(如蓄意和有严重疏忽行为)或以书面形式同意,XMPP标准基金会或任何作者不对本协议所造成的损失承担责任,包括任何直接,间接,特殊,偶发,或任何从本协议出,入,连接的字符产生的或实现,布署或其他对本协议的使用导致的相应的损害赔偿(包括但不限于善意的损失,停止作业,电脑失灵或故障,或任何和所有其他商业损害或损失) ,即使XMPP标准基金会或作者已被告知此类损害的可能性。<br />
*知识产权的一致性<br />
:XMPP扩展协议完全遵守XSF的知识产权策略(可在<http://www.xmpp.org/extensions/ipr-policy.shtml>找到副本或写信给XMPP标准基金会, 1899 Wynkoop Street, Suite 600, Denver, CO 80202 USA).<br />
===附录D:和XMPP的关系===<br />
<br />
可扩展的消息和出席信息协议 (XMPP) 定义于 XMPP Core (RFC 3920) 和 XMPP IM (RFC 3921) 规范里,由 XMPP标准基金会贡献到由依据RFC 2026成立的互联网工程人物组管理的互联网标准流程 Internet Standards Process. 本文定义的任何协议已在互联网标准流程之外开发,并且被理解为 XMPP 的扩展而不是一个XMPP本身的演化, 开发, 或修改.<br />
===附录E:讨论地点===<br />
<br />
主要的XMPP扩展协议讨论地点是 <standards@xmpp.org> 讨论列表.<br />
<br />
在 xmpp.org 的其它讨论列表中的讨论可能也有合适的; 所有的列表见 <http://xmpp.org/about/discuss.shtml> .<br />
<br />
Given that this XMPP Extension Protocol normatively references IETF technologies, discussion on the <xsf-ietf@xmpp.org> list might also be appropriate.<br />
<br />
勘误表可以发送邮件到 <editor@xmpp.org>.<br />
===附录F:需求一致性===<br />
<br />
以下用于本文的需求关键字的解释见于 [http://www.ietf.org/rfc/rfc2119.txt RFC 2119]: "MUST", "SHALL", "REQUIRED"; "MUST NOT", "SHALL NOT"; "SHOULD", "RECOMMENDED"; "SHOULD NOT", "NOT RECOMMENDED"; "MAY", "OPTIONAL".<br />
===Appendix G: Notes===<br />
<br />
1. RFC 793: Transmission Control Protocol <http://tools.ietf.org/html/rfc0793>.<br />
<br />
2. RFC 1945: Hypertext Transfer Protocol -- HTTP/1.0 <http://tools.ietf.org/html/rfc1945>.<br />
<br />
3. RFC 2616: Hypertext Transport Protocol -- HTTP/1.1 <http://tools.ietf.org/html/rfc2616>.<br />
<br />
4. Bayeux Protocol <http://svn.cometd.org/trunk/bayeux/bayeux.html>.<br />
<br />
5. The Web Socket Protocol <http://tools.ietf.org/html/draft-hixie-thewebsocketprotocol>.<br />
<br />
6. Reverse HTTP <http://tools.ietf.org/html/draft-lentczner-rhttp>.<br />
<br />
7. RFC 2965: HTTP State Management Mechanism <http://tools.ietf.org/html/rfc2965>.<br />
<br />
8. Requiring cookies is sub-optimal because several significant computing platforms provide only limited access to underlying HTTP requests/responses; worse, some platforms hide or remove cookie-related headers.<br />
<br />
9. XEP-0025: Jabber HTTP Polling <http://xmpp.org/extensions/xep-0025.html>.<br />
<br />
10. RFC 6120: Extensible Messaging and Presence Protocol (XMPP): Core <http://tools.ietf.org/html/rfc6120>.<br />
<br />
11. XEP-0206: XMPP Over BOSH <http://xmpp.org/extensions/xep-0206.html>.<br />
<br />
12. In order to reduce network congestion, RFC 2616 recommends that clients SHOULD NOT keep more than two HTTP connections to the same HTTP server open at the same time. Clients running in constrained enviroments typically have no choice but to abide by that recommendation.<br />
<br />
13. If there is no traffic other than the "pings" then bandwidth consumption will be double that of a TCP connection (although double nothing is still nothing). If data is sent in large packets then bandwidth consumption will be almost identical.<br />
<br />
14. Extensible Markup Language (XML) 1.0 (Fourth Edition) <http://www.w3.org/TR/REC-xml/>.<br />
<br />
15. Namespaces in XML <http://www.w3.org/TR/REC-xml-names/>.<br />
<br />
16. RFC 4627: The application/json Media Type for JavaScript Object Notation (JSON) <http://tools.ietf.org/html/rfc4627>.<br />
<br />
17. Extensible Markup Language (XML) 1.0 (Fourth Edition) <http://www.w3.org/TR/REC-xml/>.<br />
<br />
18. Although the syntax of the 'route' attribute bears a superficial resemblance to a URI or IRI, it is not a URI/IRI and MUST NOT be processed in accordance with the rules specified in RFC 3986, RFC 3987, or (for XMPP) RFC 5122.<br />
<br />
19. Each character set name (or character encoding name -- we use the terms interchangeably) SHOULD be of type NMTOKEN, where the names are separated by the white space character #x20, resulting in a tokenized attribute type of NMTOKENS (see Section 3.3.1 of XML 1.0 [20]). Strictly speaking, the Character Sets registry maintained by the Internet Assigned Numbers Authority (see <http://www.iana.org/assignments/character-sets>) allows a character set name to contain any printable US-ASCII character, which might include characters not allowed by the NMTOKEN construction of XML 1.0; however, the only existing character set name which includes such a character is "NF_Z_62-010_(1973)".<br />
<br />
20. Extensible Markup Language (XML) 1.0 (Fourth Edition) <http://www.w3.org/TR/REC-xml/>.<br />
<br />
21. 9007199254740991 is 253-1. Some weakly typed languages use IEEE Standard 754 Doubles to represent all numbers. These Doubles cannot represent integers above 253 accurately.<br />
<br />
22. RFC 3174: US Secure Hash Algorithm 1 (SHA1) <http://tools.ietf.org/html/rfc3174>.<br />
<br />
23. Therefore a client and a connection manager will be compatible even if one or the other offers no support for multi-stream sessions.<br />
<br />
24. The 'rid' attribute is always incremented normally without reference to any 'stream' attribute.<br />
<br />
25. This helps to ensure backwards-compatibility with older implementations.<br />
<br />
26. Each HTTP response MUST belong to the same session as the request that triggered it, but not necessarily to the same stream.<br />
<br />
27. The broadcast payloads can be of any type.<br />
<br />
28. SSL V3.0 <http://wp.netscape.com/eng/ssl3/draft302.txt>.<br />
<br />
29. RFC 2818: HTTP Over TLS <http://tools.ietf.org/html/rfc2818>.<br />
<br />
30. RFC 2817: Upgrading to TLS Within HTTP/1.1 <http://tools.ietf.org/html/rfc2817>.<br />
<br />
31. RFC 1750: Randomness Recommendations for Security <http://tools.ietf.org/html/rfc1750>.<br />
<br />
32. RFC 4270: Attacks on Cryptographic Hashes in Internet Protocols <http://tools.ietf.org/html/rfc4270>.<br />
<br />
33. The Internet Assigned Numbers Authority (IANA) is the central coordinator for the assignment of unique parameter values for Internet protocols, such as port numbers and URI schemes. For further information, see <http://www.iana.org/>.<br />
<br />
34. IANA registry of port numbers <http://www.iana.org/assignments/port-numbers>.<br />
<br />
35. XEP-0156: Discovering Alternative XMPP Connection Methods <http://xmpp.org/extensions/xep-0156.html>.<br />
===Appendix H: Revision History===<br />
<br />
Note: Older versions of this specification might be available at http://xmpp.org/extensions/attic/<br />
;Version 1.10 (2010-07-02)<br />
<br />
:Further clarified use of 'from' and 'to' attributes; added missing condition values to the schema.<br />
:(psa)<br />
;Version 1.9 (2009-11-06)<br />
<br />
:Added information for registration of port 5280 with IANA.<br />
:(psa)<br />
;Version 1.8 (2009-04-30)<br />
<br />
:Removed secure attribute because it did not solve the problem it was intended to solve; added security consideration regarding link between connection manager and application server; changed "stanza" to "payload" for disambiguation with XMPP; clarified design objectives and relationship to similar technologies; corrected several errors in the schema.<br />
:(psa/jm)<br />
;Version 1.7 (2008-10-29)<br />
<br />
:Moved alternative script syntax to historical specification; added implementation note about HTTP Pipelining; adjusted architectural description.<br />
:(psa)<br />
;Version 1.6 (2007-02-21)<br />
<br />
:Multiple clarifications and restructuring without changes to protocol itself; changed title to BOSH; added section that fully explains the technique underlying the protocol; separated XMPP-specific features into new XEP-0206; added optional new Script Syntax and session pauses; added Acknowledgements section; added from and ver attributes; added hold attribute to session creation response; clarified polling too-frequently error; recommended that clients use HTTP Pipelining.<br />
:(ip)<br />
;Version 1.5 (2006-04-28)<br />
<br />
:Added optional Multiple Streams section; added security considerations about encrypted HTTP connections; recommended use of SSL rather than HTTP over TLS; specified that request ID values must not exceed 9007199254740991; corrected datatypes of inactivity, polling, rid, and wait attributes in the schema; added <any/> and <anyAttribute/> elements to schema to optionally support non-XMPP XML elements and attributes; deprecated HTTP error codes in favor of new terminal binding conditions.<br />
:(ip/psa)<br />
;Version 1.4 (2005-12-14)<br />
<br />
:Modified syntax of route attribute to be proto:host:port rather than XMPP URI/IRI.<br />
:(psa)<br />
;Version 1.3 (2005-11-02)<br />
<br />
:Corrected stream:features namespace and the Recoverable Binding Conditions section; recommended that connection manager shall return secure attribute to client; recommended end-to-end encryption through proxy connection managers.<br />
:(ip)<br />
;Version 1.2 (2005-06-16)<br />
<br />
:Specified optional use of route and secure attributes in session request. Minor correction: the stream features element should be included in the response that contains the authid attribute (this is not necessarily the session creation response).<br />
:(ip)<br />
;Version 1.1 (2005-06-02)<br />
<br />
:Specified optional use of HTTP Accept-Encoding and Content-Encoding headers for compression at HTTP binding level.<br />
:(ip)<br />
;Version 1.0 (2005-03-03)<br />
<br />
:Per a vote of the Jabber Council, advanced status to Draft.<br />
:(psa)<br />
;Version 0.10 (2004-11-08)<br />
<br />
:Changed HTTP 401 errors to HTTP 404.<br />
:(ip)<br />
;Version 0.9 (2004-10-26)<br />
<br />
:Added charset attribute.<br />
:(ip/psa)<br />
;Version 0.8 (2004-10-26)<br />
<br />
:Specified that wait attribute must be included in the session creation response.<br />
:(ip)<br />
;Version 0.7 (2004-08-12)<br />
<br />
:Defined appropriate XMPP stanza error conditions.<br />
:(psa/ip)<br />
;Version 0.6 (2004-07-19)<br />
<br />
:Added xml:lang attribute to the session request; added recoverable binding error conditions.<br />
:(ip)<br />
;Version 0.5 (2004-05-07)<br />
<br />
:Protocol refactored to enable simultaneous requests (request identifier attribute, wait attribute, hold attribute, requests attribute) and recovery of broken connections; added content attribute; removed all wrapper types except 'terminate'; updated error handling; made key mechanism optional (should use SSL/TLS instead).<br />
:(ip/psa)<br />
;Version 0.4 (2004-02-23)<br />
<br />
:Fixed typos; removed "resource-constraint" binding error; added HTTP 403 error to table.<br />
:(psa/ip)<br />
;Version 0.3 (2004-02-19)<br />
<br />
:Added 'authid' attribute to enable communication of XMPP stream ID (used in digest authentication); specified that Content-Types other than "text/xml" are allowed to support older HTTP clients; specified business rule for connection manager queueing of client requests; changed <packet/> to <body/> to support older HTTP clients; changed 'to' attribute on initialization element from MAY to SHOULD; recommended inclusion of unavailable presence in termination element sent from client; described architectural assumptions; specified binding-specific error handling.<br />
:(psa/ip)<br />
;Version 0.2 (2004-01-13)<br />
<br />
:Added 'to' attribute on the initialization element; specified that 'text/html' is allowable for backwards-compatibility.<br />
:(dss/psa/ip)<br />
;Version 0.1 (2003-11-06)<br />
<br />
:Initial version.<br />
:(dss/psa)<br />
<br />
结束</div>
Snowqiang
http://wiki.jabbercn.org/XEP-0124
XEP-0124
2011-05-18T15:09:17Z
<p>Snowqiang: </p>
<hr />
<div>[[Category:XMPP扩展]]<br />
[[Category:翻译中]]<br />
<br />
'''本文的英文原文来自[http://www.xmpp.org/extensions/xep-0124.html XEP-0124]'''<br />
<br />
'''XEP-0124: Bidirectional-streams Over Synchronous HTTP (BOSH)'''<br />
<br />
{|<br />
!摘要:<br />
|This specification defines a transport protocol that emulates the semantics of a long-lived, bidirectional TCP connection between two entities (such as a client and a server) by efficiently using multiple synchronous HTTP request/response pairs without requiring the use of frequent polling or chunked responses.<br />
|-<br />
!作者:<br />
|Ian Paterson, Dave Smith, Peter Saint-Andre, Jack Moffitt<br />
|-<br />
!版权:<br />
|© 1999 - 2011 XMPP Standards Foundation. SEE LEGAL NOTICES.<br />
|-<br />
!状态:<br />
|草案<br />
|-<br />
!类型:<br />
|标准跟踪<br />
|-<br />
!版本:<br />
|2.0<br />
|-<br />
!最后更新日期:<br />
|2010-07-02<br />
|}<br />
<br />
NOTICE: The protocol defined herein is a Draft Standard of the XMPP Standards Foundation. Implementations are encouraged and the protocol is appropriate for deployment in production systems, but some changes to the protocol are possible before it becomes a Final Standard.<br />
<br />
==Introduction==<br />
<br />
The Transmission Control Protocol (TCP; RFC 793 [1]) is often used to establish a stream-oriented connection between two entities. Such connections can often be long-lived to enable an interactive "session" between the entities. However, sometimes the nature of the device or network can prevent an application from maintaining a long-lived TCP connection to a server or peer. In this case, it is desirable to use an alternative connection method that emulates the behavior of a long-lived TCP connection using a sequenced series of requests and responses that are exchanged over short-lived connections. The appropriate request-response semantics are widely available via the Hypertext Transfer Protocol (HTTP) as specified in RFC 1945 [2] and RFC 2616 [3].<br />
<br />
BOSH, the technology defined in this specification, essentially provides a "drop-in" alternative to a long-lived, bidirectional TCP connection. It is a mature, full-featured technology that has been widely implemented and deployed since 2004. To our knowledge it was the first of many similar technologies, which now include the Comet methodology formalized in the Bayeux Protocol [4] as well as The Web Socket Protocol [5] and Reverse HTTP [6].<br />
<br />
BOSH is designed to transport any data efficiently and with minimal latency in both directions. For applications that require both "push" and "pull" semantics, BOSH is significantly more bandwidth-efficient and responsive than most other bidirectional HTTP-based transport protocols and the techniques now commonly known as "Ajax". BOSH achieves this efficiency and low latency by using so-called "long polling" with multiple synchronous HTTP request/response pairs. Furthermore, BOSH can address the needs of constrained clients by employing fully-compliant HTTP 1.0 without the need for "cookies" (see RFC 2965 [7]) [8] or even access to HTTP headers.<br />
<br />
BOSH was originally developed in the Jabber/XMPP community as a replacement for an even earlier HTTP-based technology called Jabber HTTP Polling [9]. Although BOSH assumes that the "payload" of HTTP requests and responses will be XML, the payload formats are not limited to XMPP stanzas (see XMPP Core [10]) and could contain a mixture of elements qualified by namespaces defined by different protocols (e.g., both XMPP and JSON). This mix is necessary because some connection managers might 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 payload is qualified by the correct namespace.<br />
<br />
Note: XMPP Over BOSH [11] documents some XMPP-specific extensions of this protocol that were formerly included in this document.<br />
<br />
==Requirements==<br />
<br />
The following design requirements reflect the need to offer performance as close as possible to a standard TCP connection.<br />
<br />
1. Compatible with constrained runtime environments* (e.g., mobile and browser-based clients).<br />
2. Compatible with proxies that buffer partial HTTP responses.<br />
3. Efficient through proxies that limit the duration of HTTP responses.<br />
4. Fully compatible with HTTP/1.0.<br />
5. Compatible with restricted network connections (e.g., firewalls, proxies, and gateways).<br />
6. Fault tolerant (e.g., session recovers after an underlying TCP connection breaks at any stage during an HTTP request).<br />
7. Extensible.<br />
8. Consume significantly less bandwidth than polling-based protocols.<br />
9. Significantly more responsive (lower latency) than polling-based protocols.<br />
10. Support for polling (for clients that are limited to a single HTTP connection at a time).<br />
11. In-order delivery of data.<br />
12. Guard against unauthorized users injecting HTTP requests into a session.<br />
13. Protect against denial of service attacks.<br />
14. Multiplexing of data streams.<br />
<br />
*Note: Compatibility with constrained runtime environments implies the following restrictions:<br />
<br />
1. Clients are not required to have programmatic access to the headers of each HTTP request and response (e.g., cookies or status codes).<br />
2. The body of each HTTP request and response is parsable XML with a single root element.<br />
3. Clients can specify the Content-Type of the HTTP responses they receive.<br />
<br />
==Architectural Assumptions==<br />
<br />
This document assumes that most implementations will utilize a specialized connection manager ("CM") to handle HTTP connections rather than the native connection type for the relevant application (e.g., TCP connections in XMPP). Effectively, such a connection manager is a specialized HTTP server that translates between the HTTP requests and responses defined herein and the data streams (or API) implemented by the server with which it communicates, thus enabling a client to connect to a server via HTTP on port 80 or 443 instead of an application-specific port. We can illustrate this graphically as follows:<br />
<br />
Server<br />
|<br />
| [unwrapped data streams]<br />
|<br />
HTTP CM<br />
|<br />
| [HTTP + <body/> wrapper]<br />
|<br />
Client<br />
<br />
<br />
This specification covers communication only between a client and the connection manager. It does not cover communication between the connection manager and the server, since such communications are implementation-specific (e.g., the server might 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 might be an independent translating proxy such that the server might believe it is talking directly to the client over TCP; or the connection manager and the server might use a component protocol or an API defined by the server implementation).<br />
<br />
Furthermore, no aspect of this protocol limits its use to communication between a client and a server. For example, it could be used for communication between a server and a peer server if such communication can occur for the relevant application (e.g., in XMPP). 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 the native connection transport for the relevant application. (However, on some unreliable networks, BOSH might enable more stable communication between servers.)<br />
<br />
==The BOSH Technique==<br />
<br />
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).<br />
<br />
The technique employed by BOSH 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.<br />
<br />
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 so to make sure the client can send more data immediately if necessary. (The client SHOULD NOT open more than two HTTP connections to the connection manager at the same time, [12] so it would otherwise have to wait until the connection manager responds to one of the requests.)<br />
<br />
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 TCP 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.<br />
<br />
If there is no traffic in either direction for an agreed amount of time (typically several 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 so 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. [13]<br />
<br />
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. Thus 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. Therefore, 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 were being used.<br />
<br />
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.<br />
<br />
==HTTP Overview==<br />
<br />
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).<br />
<br />
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 permitted by RFC 1945 or RFC 2616. For example, 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 might buffer each partial HTTP request or response and only forward the full request or response once it is available.<br />
<br />
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.<br />
<br />
Requests and responses MAY include HTTP headers not specified herein. The receiver SHOULD ignore any such headers.<br />
<br />
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). However, the responses to requests that are not part of the session sent over the same connection using HTTP pipelining (or queued to be sent over the same connection) might be delayed if they were sent while a request that is part of the session is being held (since the connection manager MUST send its responses in the same order that the requests were received, and the connection manager typically delays its responses).<br />
<br />
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.<br />
<br />
==<body/> Wrapper Element==<br />
<br />
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 transferred. The <body/> element and its content together MUST conform to the specifications set out in XML 1.0 [14]. They SHOULD also conform to Namespaces in XML [15]. The content MUST NOT contain any of the following (all defined in XML 1.0):<br />
<br />
* Partial XML elements<br />
* XML comments<br />
* XML processing instructions<br />
* Internal or external DTD subsets<br />
* Internal or external entity references (with the exception of predefined entities)<br />
<br />
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 "payloads" in this document, e.g., XMPP stanzas as defined in RFC 6120 or elements containing XML character data that represents objects using the JSON data interchange format as defined in RFC 4627 [16]). Each <body/> wrapper MAY contain payloads qualified under a wide variety of different namespaces.<br />
<br />
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.<br />
<br />
==Initiating a BOSH Session==<br />
===Session Creation Request===<br />
<br />
The first request from the client to the connection manager requests a new session.<br />
<br />
The <body/> element of the first request SHOULD possess the following attributes (they SHOULD NOT be included in any other requests except as specified under Adding Streams To A Session):<br />
<br />
* '''<nowiki>'to'</nowiki>''' -- This attribute specifies the target domain of the first stream.<br />
* '''<nowiki>'xml:lang'</nowiki>''' -- This attribute (as defined in Section 2.12 of XML 1.0 [17]) specifies the default language of any human-readable XML character data sent or received during the session.<br />
* '''<nowiki>'ver'</nowiki>''' -- This attribute specifies the highest version of the BOSH protocol that the client supports. The numbering scheme is "<major>.<minor>" (where the minor number MAY be incremented higher than a single digit, so it MUST be treated as a separate integer). Note: The 'ver' attribute should not be confused with the version of any protocol being transported.<br />
* '''<nowiki>'wait'</nowiki>''' -- This attribute specifies the longest time (in seconds) that the connection manager is allowed to wait before responding to any request during the session. This enables the client to limit the delay before it discovers any network failure, and to prevent its HTTP/TCP connection from expiring due to inactivity.<br />
* '''<nowiki>'hold'</nowiki>''' -- This attribute specifies the maximum number of requests the connection manager is allowed to keep waiting at any one time during the session. If the client is not able to use HTTP Pipelining then this SHOULD be set to "1".<br />
<br />
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 both typically one or two orders of magnitude!<br />
<br />
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:example.com:9999"). [18] A connection manager that is configured to work only with a single server (or only with a defined list of domains and the associated list of hostnames and ports that are serving those domains) MAY ignore the 'route' attribute. (Note that the 'to' attribute specifies the domain being served, not the hostname of the machine that is serving the domain.)<br />
<br />
The <body/> element of the first request MAY also possess a 'from' attribute, which specifies the originator of the first stream and which enables the connection manager to forward the originating entity's identity to the application server (e.g., the JabberID of an entity that is connecting to an XMPP server; see XEP-0206).<br />
<br />
A client MAY include an 'ack' attribute (set to "1") to indicate that it will be using acknowledgements throughout the session and that the absence of an 'ack' attribute in any request is meaningful (see Acknowledgements).<br />
<br />
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".<br />
<br />
'''Example 1. Requesting a BOSH session'''<br />
<source lang="xml"><br />
POST /webclient HTTP/1.1<br />
Host: httpcm.example.com<br />
Accept-Encoding: gzip, deflate<br />
Content-Type: text/xml; charset=utf-8<br />
Content-Length: 104<br />
<br />
<body content='text/xml; charset=utf-8'<br />
from='user@example.com'<br />
hold='1'<br />
rid='1573741820'<br />
to='example.com'<br />
route='xmpp:example.com:9999'<br />
ver='1.6'<br />
wait='60'<br />
ack='1'<br />
xml:lang='en'<br />
xmlns='http://jabber.org/protocol/httpbind'/><br />
</source><br />
<br />
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.<br />
===Session Creation Response===<br />
<br />
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):<br />
<br />
* '''<nowiki>'sid'</nowiki>''' -- This attribute specifies the SID<br />
* '''<nowiki>'wait'</nowiki>''' -- This is the longest time (in seconds) that the connection manager will wait before responding to any request during the session. The time MUST be less than or equal to the value specified in the session request.<br />
<br />
The <body/> element SHOULD also include the following attributes (they SHOULD NOT be included in any other responses):<br />
<br />
* '''<nowiki>'ver'</nowiki>''' -- This attribute specifies the highest version of the BOSH protocol that the connection manager supports, or the version specified by the client in its request, whichever is lower.<br />
* '''<nowiki>'polling'</nowiki>''' -- This attribute specifies the shortest allowable polling interval (in seconds). This enables the client to not send empty request elements more often than desired (see Polling Sessions and Overactivity).<br />
* '''<nowiki>'inactivity'</nowiki>''' -- This attribute specifies the longest allowable inactivity period (in seconds). This enables the client to ensure that the periods with no requests pending are never too long (see Polling Sessions and Inactivity).<br />
* '''<nowiki>'requests'</nowiki>''' -- This attribute enables the connection manager to limit the number of simultaneous requests the client makes (see Overactivity and Polling Sessions). The RECOMMENDED values are either "2" or one more than the value of the 'hold' attribute specified in the session request.<br />
* '''<nowiki>'hold'</nowiki>''' -- This attribute informs the client about the maximum number of requests the connection manager will keep waiting at any one time during the session. This value MUST NOT be greater than the value specified by the client in the session request.<br />
* '''<nowiki>'to'</nowiki>''' -- This attribute communicates the identity of the backend server to which the client is attempting to connect.<br />
<br />
The connection manager MAY include an 'accept' attribute in the session creation response element, to specify a space-separated list of 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.<br />
<br />
A connection manager MAY include an 'ack' attribute (set to the value of the 'rid' attribute of the session creation request) to indicate that it will be using acknowledgements throughout the session and that the absence of an 'ack' attribute in any response is meaningful (see Acknowledgements).<br />
<br />
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 can request.<br />
<br />
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. [19]<br />
<br />
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 a BOSH Session), then in the same response the connection manager SHOULD also include the 'secure' attribute set to "true" or "1".<br />
<br />
'''Example 2. Session creation response'''<br />
<source lang="xml"><br />
HTTP/1.1 200 OK<br />
Content-Type: text/xml; charset=utf-8<br />
Content-Length: 128<br />
<br />
<body wait='60'<br />
inactivity='30'<br />
polling='5'<br />
requests='2'<br />
hold='1'<br />
ack='1573741820'<br />
accept='deflate,gzip'<br />
maxpause='120'<br />
sid='SomeSID'<br />
charsets='ISO_8859-1 ISO-2022-JP'<br />
ver='1.6'<br />
from='example.com'<br />
xmlns='http://jabber.org/protocol/httpbind'/><br />
</source><br />
<br />
'''Example 3. Subsequent response with 'from' and 'secure' attributes'''<br />
<source lang="xml"><br />
HTTP/1.1 200 OK<br />
Content-Type: text/xml; charset=utf-8<br />
Content-Length: 128<br />
<br />
<body from='example.com'<br />
xmlns='http://jabber.org/protocol/httpbind'/><br />
</source><br />
<br />
==Sending and Receiving XML Payloads==<br />
<br />
After the client has successfully completed all required preconditions, it can send and receive XML payloads via the HTTP binding.<br />
<br />
'''Example 4. Transmitting payloads'''<br />
<source lang="xml"><br />
POST /webclient HTTP/1.1<br />
Host: httpcm.example.com<br />
Accept-Encoding: gzip, deflate<br />
Content-Type: text/xml; charset=utf-8<br />
Content-Length: 188<br />
<br />
<body rid='1249243562'<br />
sid='SomeSID'<br />
xmlns='http://jabber.org/protocol/httpbind'><br />
<message to='contact@example.com'<br />
xmlns='jabber:client'><br />
<body>Good morning!</body><br />
</message><br />
<message to='friend@example.com'<br />
xmlns='jabber:client'><br />
<body>Hey, what&apos;s up?</body><br />
</message><br />
</body><br />
</source><br />
<br />
Upon receipt of a request, the connection manager SHOULD forward the content of the <body/> element to the server as soon as possible. In any case it MUST forward the content from different requests in the order specified by their 'rid' attributes.<br />
<br />
The connection manager MUST also return an HTTP 200 OK response with a <body/> element to the client. Note: This does not indicate that the payloads have been successfully delivered to the application server.<br />
<br />
It is RECOMMENDED that the connection manager not return an HTTP result until a payload has arrived from the application server for delivery to the client. However, the connection manager SHOULD NOT wait longer than the time specified by the client in the 'wait' attribute of its Session Creation Request, and it SHOULD NOT keep more HTTP requests waiting at a time than the number specified in the 'hold' attribute of the session creation request. In any case it MUST respond to requests in the order specified by their 'rid' attributes.<br />
<br />
If there are no payloads waiting or ready to be delivered within the waiting period, then the connection manager SHOULD include an empty <body/> element in the HTTP result:<br />
<br />
'''Example 5. Empty response'''<br />
<source lang="xml"><br />
HTTP/1.1 200 OK<br />
Content-Type: text/xml; charset=utf-8<br />
Content-Length: 64<br />
<br />
<body xmlns='http://jabber.org/protocol/httpbind'/><br />
</source><br />
<br />
If the connection manager has received one or more payloads from the application server for delivery to the client, then it SHOULD return the payloads in the body of its response as soon as possible after receiving them from the server. The example below includes payloads qualified by different namespaces:<br />
<br />
'''Example 6. Response with queued stanza'''<br />
<source lang="xml"><br />
HTTP/1.1 200 OK<br />
Content-Type: text/xml; charset=utf-8<br />
Content-Length: 185<br />
<br />
<body xmlns='http://jabber.org/protocol/httpbind'<br />
xmlns:json='http://json.org/'><br />
<message from='contact@example.com'<br />
to='user@example.com'<br />
xmlns='jabber:client'><br />
<body>Good morning to you!</body><br />
</message><br />
<message from='friend@example.com'<br />
to='user@example.com'<br />
xmlns='jabber:client'><br />
<body>Not much, how about with you?</body><br />
</message><br />
<json:json><br />
[<br />
{<br />
"precision": "zip",<br />
"Latitude": 37.7668,<br />
"Longitude": -122.3959,<br />
"Address": "",<br />
"City": "SAN FRANCISCO",<br />
"State": "CA",<br />
"Zip": "94107",<br />
"Country": "US"<br />
},<br />
{<br />
"precision": "zip",<br />
"Latitude": 37.371991,<br />
"Longitude": -122.026020,<br />
"Address": "",<br />
"City": "SUNNYVALE",<br />
"State": "CA",<br />
"Zip": "94085",<br />
"Country": "US"<br />
}<br />
]<br />
</json:json><br />
</body><br />
</source><br />
<br />
The client MAY poll the connection manager for incoming payloads by sending an empty <body/> element.<br />
<br />
'''Example 7. Requesting XML Payloads'''<br />
<source lang="xml"><br />
POST /webclient HTTP/1.1<br />
Host: httpcm.example.com<br />
Accept-Encoding: gzip, deflate<br />
Content-Type: text/xml; charset=utf-8<br />
Content-Length: 88<br />
<br />
<body rid='1249243563'<br />
sid='SomeSID'<br />
xmlns='http://jabber.org/protocol/httpbind'/><br />
</source><br />
<br />
The connection manager MUST wait and respond in the same way as it does after receiving payloads from the client.<br />
<br />
==Acknowledgements==<br />
===Request Acknowledgements===<br />
<br />
When responding to a request that it has been holding, if the connection manager finds it has already received another request with a higher 'rid' attribute (typically while it was holding the first request), then it MAY acknowledge the reception to the client. The connection manager MAY set the 'ack' attribute of any response to the value of the highest 'rid' attribute it has received in the case where it has also received all requests with lower 'rid' values.<br />
<br />
'''Example 8. Response with request acknowledgement'''<br />
<source lang="xml"><br />
HTTP/1.1 200 OK<br />
Content-Type: text/xml; charset=utf-8<br />
Content-Length: 64<br />
<br />
<body ack='1249243564'<br />
xmlns='http://jabber.org/protocol/httpbind'/><br />
</source><br />
<br />
If the connection manager will be including 'ack' attributes on responses during a session, then it MUST include an 'ack' attribute in its session creation response, and set the 'ack' attribute of responses throughout the session. The only exception is that, after its session creation response, the connection manager SHOULD NOT include an 'ack' attribute in any response if the value would be the 'rid' of the request being responded to.<br />
<br />
If the connection manager is permitted to hold more than one request at a time, then the reception of a lower-than-expected 'ack' value from the connection manager (or the unexpected abscence of an 'ack' attribute) can give the client an early warning that a network failure might have occurred (e.g., if the client believes the connection manager should have received another request by the time it responded).<br />
===Response Acknowledgements===<br />
<br />
The client MAY similarly inform the connection manager about the responses it has received by setting the 'ack' attribute of any request to the value of the highest 'rid' of a request for which it has already received a response in the case where it has also received all responses associated with lower 'rid' values. If the client will be including 'ack' attributes on requests during a session, then it MUST include an 'ack' attribute (set to '1') in its session creation request, and set the 'ack' attribute of requests throughout the session. The only exception is that, after its session creation request, the client SHOULD NOT include an 'ack' attribute in any request if it has received responses to all its previous requests.<br />
<br />
'''Example 9. Request with response acknowledgement'''<br />
<source lang="xml"><br />
POST /webclient HTTP/1.1<br />
Host: httpcm.example.com<br />
Accept-Encoding: gzip, deflate<br />
Content-Type: text/xml; charset=utf-8<br />
Content-Length: 88<br />
<br />
<body rid='1249243566'<br />
sid='SomeSID'<br />
ack='1249243564'<br />
xmlns='http://jabber.org/protocol/httpbind'/><br />
</source><br />
<br />
After receiving a request with an 'ack' value less than the 'rid' of the last request that it has already responded to, the connection manager MAY inform the client of the situation by sending its next response immediately instead of waiting until it has payloads to send to the client (e.g., if some time has passed since it responded). In this case it SHOULD include a 'report' attribute set to one greater than the 'ack' attribute it received from the client, and a 'time' attribute set to the number of milliseconds since it sent the response associated with the 'report' attribute.<br />
<br />
'''Example 10. Response with report'''<br />
<source lang="xml"><br />
HTTP/1.1 200 OK<br />
Content-Type: text/xml; charset=utf-8<br />
Content-Length: 64<br />
<br />
<body report='1249243565'<br />
time='852'<br />
xmlns='http://jabber.org/protocol/httpbind'/><br />
</source><br />
<br />
Upon reception of a response with 'report' and 'time' attributes, if the client has still not received the response associated with the request identifier specified by the 'report' attribute, then it MAY choose to resend the request associated with the missing response (see Broken Connections).<br />
<br />
==Inactivity==<br />
<br />
After receiving a response from the connection manager, if none of the client's requests are still being held by the connection manager (and if the session is not a Polling Session), the client SHOULD make a new request as soon as possible. In any case, if no requests are being held, the client MUST make a new request before the maximum inactivity period has expired. The length of this period (in seconds) is specified by the 'inactivity' attribute in the session creation response.<br />
<br />
If the connection manager has responded to all the requests it has received within a session and the time since its last response is longer than the maximum inactivity period, then it SHOULD assume the client has been disconnected and terminate the session without informing the client. If the client subsequently makes another request, then the connection manager SHOULD respond as if the session does not exist.<br />
<br />
If the connection manager did not specify a maximum inactivity period in the session creation response, then it SHOULD allow the client to be inactive for as long as it chooses.<br />
<br />
If the session is not a polling session then the connection manager SHOULD specify a relatively short inactivity period to ensure that disconnections are discovered as quickly as possible. The RECOMMENDED time would be a little more than the number of seconds for a comfortable network round trip between the connection manager and the client under difficult network conditions (since the client can be expected to make a new request immediately -- see above).<br />
<br />
If a client encounters an exceptional temporary situation during which it will be unable to send requests to the connection manager for a period of time greater than the maximum inactivity period (e.g., while a runtime environment changes from one web page to another), and if the connection manager included a 'maxpause' attribute in its Session Creation Response, then the client MAY request a temporary increase to the maximum inactivity period by including a 'pause' attribute in a request. Note: If the connection manager did not specify a 'maxpause' attribute at the start of the session then the client MUST NOT send a 'pause' attribute during the session.<br />
<br />
'''Example 11. Requesting a Session Pause'''<br />
<source lang="xml"><br />
POST /webclient HTTP/1.1<br />
Host: httpcm.example.com<br />
Accept-Encoding: gzip, deflate<br />
Content-Type: text/xml; charset=utf-8<br />
Content-Length: 98<br />
<br />
<body rid='1249243564'<br />
sid='SomeSID'<br />
pause='60'<br />
xmlns='http://jabber.org/protocol/httpbind'/><br />
</source><br />
<br />
Upon reception of a session pause request, if the requested period is not greater than the maximum permitted time, then the connection manager SHOULD respond immediately to all pending requests (including the pause request) and temporarily increase the maximum inactivity period to the requested time. Note: The response to the pause request MUST NOT contain any payloads.<br />
<br />
Note: If the client simply wants the connection manager to return all the requests it is holding then it MAY set the value of the 'pause' attribute to be the value of the 'inactivity' attribute in the connection manager's session creation response. (If the client believes it is in danger of becoming disconnected indefinitely then it MAY even request a temporary reduction of the maximum inactivity period by specifying a 'pause' value less than the 'inactivity' value, thus enabling the connection manager to discover any subsequent disconnection more quickly.)<br />
<br />
The connection manager SHOULD set the maximum inactivity period back to normal upon reception of the next request from the client (assuming the connection manager has not already terminated the session).<br />
<br />
==Overactivity==<br />
<br />
The client SHOULD NOT make more simultaneous requests than specified by the 'requests' attribute in the connection manager's Session Creation Response. However the client MAY make one additional request if it is to pause or terminate a session.<br />
<br />
If during any period the client sends a sequence of new requests (i.e. requests with incremented rid attributes, not repeat requests) longer than the number specified by the 'requests' attribute, and if the connection manager has not yet responded to any of the requests, and if the last request did not include either a 'pause' attribute or a 'type' attribute set to "terminate", then the connection manager SHOULD consider that the client is making too many simultaneous requests, and terminate the HTTP session with a 'policy-violation' terminal binding error to the client. Note: This behavior applies to equally to normal and polling sessions.<br />
<br />
'''Example 12. Too many simultaneous requests response'''<br />
<source lang="xml"><br />
HTTP/1.1 200 OK<br />
Content-Type: text/xml; charset=utf-8<br />
Content-Length: 68<br />
<br />
<body type='terminate'<br />
condition='policy-violation'<br />
xmlns='http://jabber.org/protocol/httpbind'/><br />
</source><br />
<br />
Note: If the connection manager did not specify a 'requests' attribute in the session creation response, then it MUST allow the client to send as many simultaneous requests as it chooses.<br />
<br />
If during any period the client sends a sequence of new requests equal in length to the number specified by the 'requests' attribute, and if the connection manager has not yet responded to any of the requests, and if the last request was empty and did not include either a 'pause' attribute or a 'type' attribute set to "terminate", and if the last two requests arrived within a period shorter than the number of seconds specified by the 'polling' attribute in the session creation response, then the connection manager SHOULD consider that the client is making requests more frequently than it was permitted and terminate the HTTP session and return a 'policy-violation' terminal binding error to the client. Note: the behavior for Polling Sessions is slightly different.<br />
<br />
'''Example 13. Too frequent requests response'''<br />
<source lang="xml"><br />
HTTP/1.1 200 OK<br />
Content-Type: text/xml; charset=utf-8<br />
Content-Length: 68<br />
<br />
<body type='terminate'<br />
condition='policy-violation'<br />
xmlns='http://jabber.org/protocol/httpbind'/><br />
</source><br />
<br />
Note: If the connection manager did not specify a 'polling' attribute in the session creation response, then it MUST allow the client to send requests as frequently as it chooses.<br />
<br />
==Polling Sessions==<br />
<br />
It is not always possible for a constrained client to either use HTTP Pipelining or open more than one HTTP connection with the connection manager at a time. In this case the client SHOULD inform the connection manager by setting the values of the 'wait' and/or 'hold' attributes in its session creation request to "0", and then "poll" the connection manager at regular intervals throughout the session for payloads it might have received from the server. Note: Even if the client does not request a polling session, the connection manager MAY require a client to use polling by setting the 'requests' attribute (which specifies the number of simultaneous requests the client can make) of its Session Creation Response to "1", however this is NOT RECOMMENDED.<br />
<br />
If a session will use polling, the connection manager SHOULD specify a higher than normal value for the 'inactivity' attribute (see Inactivity) in its session creation response. The increase SHOULD be greater than the value it specifies for the 'polling' attribute.<br />
<br />
If the client sends two consecutive empty new requests (i.e. requests with incremented rid attributes, not repeat requests) within a period shorter than the number of seconds specified by the 'polling' attribute (the shortest allowable polling interval) in the session creation response, and if the connection manager's response to the first request contained no payloads, then upon reception of the second request the connection manager SHOULD terminate the HTTP session and return a 'policy-violation' terminal binding error to the client.<br />
<br />
'''Example 14. Too frequent polling response'''<br />
<source lang="xml"><br />
HTTP/1.1 200 OK<br />
Content-Type: text/xml; charset=utf-8<br />
Content-Length: 68<br />
<br />
<body type='terminate'<br />
condition='policy-violation'<br />
xmlns='http://jabber.org/protocol/httpbind'/><br />
</source><br />
<br />
Note: If the connection manager did not specify a 'polling' attribute in the session creation response, then it MUST allow the client to poll as frequently as it chooses.<br />
<br />
==Terminating the HTTP Session==<br />
<br />
At any time, the client MAY gracefully terminate the session by sending a <body/> element with a 'type' attribute set to "terminate". The termination request MAY include one or more payloads that the connection manager MUST forward to the server to ensure graceful logoff.<br />
<br />
'''Example 15. Session termination by client'''<br />
<source lang="xml"><br />
POST /webclient HTTP/1.1<br />
Host: httpcm.example.com<br />
Accept-Encoding: gzip, deflate<br />
Content-Type: text/xml; charset=utf-8<br />
Content-Length: 153<br />
<br />
<body rid='1249243565'<br />
sid='SomeSID'<br />
type='terminate'<br />
xmlns='http://jabber.org/protocol/httpbind'><br />
<presence type='unavailable'<br />
xmlns='jabber:client'/><br />
</body><br />
</source><br />
<br />
The connection manager SHOULD respond to this request with an HTTP 200 OK containing an empty <body/> element.<br />
<br />
'''Example 16. Connection manager acknowledges termination'''<br />
<source lang="xml"><br />
HTTP/1.1 200 OK<br />
Content-Type: text/xml; charset=utf-8<br />
Content-Length: 72<br />
<br />
<body type='terminate'<br />
xmlns='http://jabber.org/protocol/httpbind'/><br />
</source><br />
<br />
Upon receiving the response, the client MUST consider the HTTP session to have been terminated.<br />
<br />
==Request IDs==<br />
===Generation===<br />
<br />
The client MUST generate a large, random, positive integer for the initial 'rid' (see Security Considerations) and then increment that value by one for each subsequent request. The client MUST take care to choose an initial 'rid' that will never be incremented above 9007199254740991 [21] within the session. In practice, a session would have to be extraordinarily long (or involve the exchange of an extraordinary number of packets) to exceed the defined limit.<br />
===In-Order Message Forwarding===<br />
<br />
When a client makes simultaneous requests, the connection manager might receive them out of order. The connection manager MUST forward the payloads to the server and respond to the client requests in the order specified by the 'rid' attributes. The client MUST process responses received from the connection manager in the order the requests were made.<br />
<br />
The connection manager SHOULD expect the 'rid' attribute to be within a window of values greater than the 'rid' of the previous request. The size of the window is equal to the maximum number of simultaneous requests allowed by the connection manager. If it receives a request with a 'rid' greater than the values in the window, then the connection manager MUST terminate the session with an error:<br />
<br />
'''Example 17. Unexpected rid error'''<br />
<source lang="xml"><br />
HTTP/1.1 200 OK<br />
Content-Type: text/xml; charset=utf-8<br />
Content-Length: 68<br />
<br />
<body type='terminate'<br />
condition='item-not-found'<br />
xmlns='http://jabber.org/protocol/httpbind'/><br />
</source><br />
<br />
===Broken Connections===<br />
<br />
Unreliable network communications or client constraints can result in broken connections. The connection manager SHOULD remember the 'rid' and the associated HTTP response body of the client's most recent requests which were not session pause requests (see Inactivity) and which did not result in an HTTP or binding error. The number of responses to non-pause requests kept in the buffer SHOULD be either the same as the maximum number of simultaneous requests allowed by the connection manager or, if Acknowledgements are being used, the number of responses that have not yet been acknowledged.<br />
<br />
If the network connection is broken or closed before the client receives a response to a request from the connection manager, then the client MAY resend an exact copy of the original request. Whenever the connection manager receives a request with a 'rid' that it has already received, it SHOULD return an HTTP 200 (OK) response that includes the buffered copy of the original XML response to the client (i.e., a <body/> wrapper possessing appropriate attributes and optionally containing one or more XML payloads). If the original response is not available (e.g., it is no longer in the buffer), then the connection manager MUST return an 'item-not-found' terminal binding error:<br />
<br />
'''Example 18. Response not in buffer error'''<br />
<source lang="xml"><br />
HTTP/1.1 200 OK<br />
Content-Type: text/xml; charset=utf-8<br />
Content-Length: 68<br />
<br />
<body type='terminate'<br />
condition='item-not-found'<br />
xmlns='http://jabber.org/protocol/httpbind'/><br />
</source><br />
<br />
Note: The error is the same whether the 'rid' is too large or too small. This makes it more difficult for an attacker to discover an acceptable value.<br />
<br />
==Protecting Insecure Sessions==<br />
===Applicability===<br />
<br />
The OPTIONAL key sequencing mechanism described here MAY be used if the client's session with the connection manager is not secure. The session SHOULD be considered secure only if all client requests are made via SSL (or TLS) HTTP connections and the connection manager generates an unpredictable session ID. If the session is secure, it is not necessary to use this key sequencing mechanism.<br />
<br />
Even if the session is not secure, the unpredictable session and request IDs specified in the preceding sections of this document already provide a level of protection similar to that provided by a connection bound to a single pair of persistent TCP/IP connections, and thus provide sufficient protection against a 'blind' attacker. However, in some circumstances, the key sequencing mechanism defined below helps to protect against a more determined and knowledgeable attacker.<br />
<br />
It is important to recognize that the key sequencing mechanism defined below helps to protect only against an attacker who is able to view the contents of all requests or responses in an insecure session but who is not able to alter the contents of those requests (in this case, the mechanism prevents the attacker from injecting HTTP requests into the session, e.g., termination requests or responses). However, the key sequencing mechanism does not provide any protection when the attacker is able to alter the contents of insecure requests or responses.<br />
===Introduction===<br />
<br />
The HTTP requests of each session MAY be spread across a series of different socket connections. This would enable an unauthorized user that obtains the session ID and request ID of a session to then use their own socket connection to inject <body/> request elements into the session and receive the corresponding responses.<br />
<br />
The key sequencing mechanism below protects against such attacks by enabling a connection manager to detect <body/> request elements injected by a third party.<br />
===Generating the Key Sequence===<br />
<br />
Prior to requesting a new session, the client MUST select an unpredictable counter ("n") and an unpredictable value ("seed"). The client then processes the "seed" through a cryptographic hash and converts the resulting 160 bits to a hexadecimal string K(1). It does this "n" times to arrive at the initial key K(n). The hashing algorithm MUST be SHA-1 as defined in RFC 3174 [22].<br />
<br />
'''Example 19. Creating the key sequence'''<br />
<br />
K(1) = hex(SHA-1(seed))<br />
K(2) = hex(SHA-1(K(1)))<br />
...<br />
K(n) = hex(SHA-1(K(n-1)))<br />
<br />
<br />
===Use of Keys===<br />
<br />
The client MUST set the 'newkey' attribute of the first request in the session to the value K(n).<br />
<br />
'''Example 20. Session Request with Initial Key'''<br />
<source lang="xml"><br />
POST /webclient HTTP/1.1<br />
Host: httpcm.example.com<br />
Accept-Encoding: gzip, deflate<br />
Content-Type: text/xml; charset=utf-8<br />
Content-Length: 104<br />
<br />
<body content='text/xml; charset=utf-8'<br />
hold='1'<br />
rid='1573741820'<br />
to='example.com'<br />
wait='60'<br />
xml:lang='en'<br />
newkey='ca393b51b682f61f98e7877d61146407f3d0a770'<br />
xmlns='http://jabber.org/protocol/httpbind'/><br />
</source><br />
<br />
The client MUST set the 'key' attribute of all subsequent requests to the value of the next key in the generated sequence (decrementing from K(n-1) towards K(1) with each request sent).<br />
<br />
'''Example 21. Request with Key'''<br />
<source lang="xml"><br />
POST /webclient HTTP/1.1<br />
Host: httpcm.example.com<br />
Accept-Encoding: gzip, deflate<br />
Content-Type: text/xml; charset=utf-8<br />
Content-Length: 88<br />
<br />
<body rid='1573741821'<br />
sid='SomeSID'<br />
key='bfb06a6f113cd6fd3838ab9d300fdb4fe3da2f7d'<br />
xmlns='http://jabber.org/protocol/httpbind'/><br />
</source><br />
<br />
The connection manager MAY verify the key by calculating the SHA-1 hash of the key and comparing it to the 'newkey' attribute of the previous request (or the 'key' attribute if the 'newkey' attribute was not set). If the values do not match (or if it receives a request without a 'key' attribute and the 'newkey' or 'key' attribute of the previous request was set), then the connection manager MUST NOT process the element, MUST terminate the session, and MUST return an 'item-not-found' terminal binding error.<br />
<br />
'''Example 22. Invalid Key Sequence Error'''<br />
<source lang="xml"><br />
HTTP/1.1 200 OK<br />
Content-Type: text/xml; charset=utf-8<br />
Content-Length: 68<br />
<br />
<body type='terminate'<br />
condition='item-not-found'<br />
xmlns='http://jabber.org/protocol/httpbind'/><br />
</source><br />
<br />
===Switching to Another Key Sequence===<br />
<br />
A client SHOULD choose a high value for "n" when generating the key sequence. However, if the session lasts long enough that the client arrives at the last key in the sequence K(1) then the client MUST switch to a new key sequence.<br />
<br />
The client MUST:<br />
<br />
1. Choose new values for "seed" and "n".<br />
2. Generate a new key sequence using the algorithm defined above.<br />
3. Set the 'key' attribute of the request to the next value in the old sequence (i.e. K(1), the last value).<br />
4. Set the 'newkey' attribute of the request to the value K(n) from the new sequence.<br />
<br />
'''Example 23. New Key Sequence'''<br />
<source lang="xml"><br />
POST /webclient HTTP/1.1<br />
Host: httpcm.example.com<br />
Accept-Encoding: gzip, deflate<br />
Content-Type: text/xml; charset=utf-8<br />
Content-Length: 188<br />
<br />
<body rid='1573741822'<br />
sid='SomeSID'<br />
key='6f825e81f4532b2c5fa2d12457d8a1f22e8f838e'<br />
newkey='113f58a37245ec9637266cf2fb6e48bfeaf7964e'<br />
xmlns='http://jabber.org/protocol/httpbind'><br />
<message to='contact@example.com'<br />
xmlns='jabber:client'><br />
<body>I said "Hi!"</body><br />
</message><br />
</body><br />
</source><br />
<br />
==Multiple Streams==<br />
===Introduction===<br />
<br />
The OPTIONAL feature described in this section enables multiple XML streams to be contained within a single HTTP session. This feature is essential in runtime environments that prevent HTTP Pipelining, thereby constraining the number of simultaneous HTTP requests a client can make to each connection manager, since clients running in such environments need multi-stream sessions if they are to connect using more than one account at the same time. This feature also reduces network traffic for any client that needs to establish parallel streams over HTTP.<br />
===Discovery===<br />
<br />
If a connection manager supports the multi-streams feature, it MUST include a 'stream' attribute in its Session Creation Response. If a client does not receive the 'stream' attribute then it MUST assume that the connection manager does not support the feature. [23]<br />
<br />
The 'stream' attribute identifies the first stream to be opened for the session. The value of each 'stream' attribute MUST be an opaque and unpredictable name that is unique within the context of the connection manager application.<br />
<br />
'''Example 24. Session creation response with stream name'''<br />
<source lang="xml"><br />
HTTP/1.1 200 OK<br />
Content-Type: text/xml; charset=utf-8<br />
Content-Length: 128<br />
<br />
<body wait='60'<br />
inactivity='30'<br />
polling='5'<br />
requests='2'<br />
hold='1'<br />
accept='deflate,gzip'<br />
stream='firstStreamName'<br />
maxpause='120'<br />
sid='SomeSID'<br />
charsets='ISO_8859-1 ISO-2022-JP'<br />
ver='1.6'<br />
from='example.com'<br />
xmlns='http://jabber.org/protocol/httpbind'/><br />
</source><br />
<br />
===Adding Streams To A Session===<br />
<br />
If the connection manager included a 'stream' attribute in its session creation response then the client MAY ask it to open another stream at any time by sending it an empty <body/> element with a 'to' attribute. The request MUST include valid 'sid' and 'rid' [24] attributes, and SHOULD also include an 'xml:lang' attribute. The request MAY include 'route', 'from' and 'secure' attributes (see Session Creation Request), but it SHOULD NOT include 'ver', 'content', 'hold' or 'wait' attributes (since a new session is not being created).<br />
<br />
'''Example 25. Requesting another stream'''<br />
<source lang="xml"><br />
POST /webclient HTTP/1.1<br />
Host: httpcm.example.com<br />
Accept-Encoding: gzip, deflate<br />
Content-Type: text/xml; charset=utf-8<br />
Content-Length: 104<br />
<br />
<body sid='SomeSID'<br />
rid='1573741820'<br />
to='example.com'<br />
route='xmpp:example.com:9999'<br />
xml:lang='en'<br />
xmlns='http://jabber.org/protocol/httpbind'/><br />
</source><br />
<br />
If the connection manager did not indicate its support for multiple streams at the start of the session, then it MUST ignore the extra attributes and treat the request as a normal empty request for payloads (see Sending and Receiving XML Payloads). [25] Otherwise it MUST open a new stream with the specified server (see Session Creation Response), generate a new stream name, and respond to the client with the name. The response MAY also include 'from' and 'secure' attributes, but it SHOULD NOT include 'sid', 'requests', 'polling', 'hold', 'inactivity', 'maxpause', 'accept', 'charsets', 'ver' or 'wait' attributes.<br />
<br />
'''Example 26. Add stream response'''<br />
<source lang="xml"><br />
HTTP/1.1 200 OK<br />
Content-Type: text/xml; charset=utf-8<br />
Content-Length: 128<br />
<br />
<body stream='secondStreamName'<br />
from='example.com'<br />
xmlns='http://jabber.org/protocol/httpbind'/><br />
</source><br />
<br />
Note: If the response did not include either 'from' or 'secure' attributes then they MAY be sent in a subsequent response instead (see Session Creation Response). In that case the 'stream' attribute MUST also be specified.<br />
===Transmitting Payloads===<br />
<br />
If more than one stream has been opened within a session, then all non-empty <body/> elements sent by the connection manager MUST include a 'stream' attribute that specifies which stream all the payloads it contains belong to. The client SHOULD include a 'stream' attribute for the same purpose. The client MAY omit the 'stream' attribute if it wants the connection manager to broadcast the payloads over all open streams. Note: A <body/> element MUST NOT contain different payloads for different streams.<br />
<br />
If a stream name does not correspond to one of the session's open streams, then the receiving connection manager SHOULD return an 'item-not-found' terminal binding error, or the receiving client SHOULD terminate the session. However, if the receiving entity has only just closed the stream (and the sender might not have been aware of that when it sent the payloads), then it MAY instead simply silently ignore any payloads the <body/> element contains.<br />
<br />
Note: Empty <body/> elements that do not include a 'from' or 'secure' attribute SHOULD NOT include a 'stream' attribute (since nothing is being transmitted for any stream). If such a <body/> element does include a 'stream' attribute then the receiving entity SHOULD ignore the attribute.<br />
<br />
'''Example 27. Client sends payload with a stream name'''<br />
<source lang="xml"><br />
POST /webclient HTTP/1.1<br />
Host: httpcm.example.com<br />
Accept-Encoding: gzip, deflate<br />
Content-Type: text/xml; charset=utf-8<br />
Content-Length: 188<br />
<br />
<body rid='1249243562'<br />
sid='SomeSID'<br />
stream='secondStreamName'<br />
xmlns='http://jabber.org/protocol/httpbind'><br />
<message to='contact@example.com'<br />
xmlns='jabber:client'><br />
<body>I said hello.</body><br />
</message><br />
</body><br />
</source><br />
<br />
Note: The value of the 'stream' attribute of the response MAY be different than the corresponding request. [26]<br />
<br />
'''Example 28. Connection manager responds with a different stream name'''<br />
<source lang="xml"><br />
HTTP/1.1 200 OK<br />
Content-Type: text/xml; charset=utf-8<br />
Content-Length: 185<br />
<br />
<body stream='firstStreamName'<br />
xmlns='http://jabber.org/protocol/httpbind'><br />
<message from='contact@example.com'<br />
to='user@example.com'<br />
xmlns='jabber:client'><br />
<body>Hi yourself!</body><br />
</message><br />
</body><br />
</source><br />
<br />
If no stream name is specified by the connection manager then the client MUST assume the payloads are associated with the first stream (even if the first stream has been closed).<br />
<br />
If no stream name is specified by the client then the connection manager MUST broadcast the payloads over all open streams. [27]<br />
<br />
'''Example 29. Client asks for a payload to be broadcast'''<br />
<source lang="xml"><br />
POST /webclient HTTP/1.1<br />
Host: httpcm.example.com<br />
Accept-Encoding: gzip, deflate<br />
Content-Type: text/xml; charset=utf-8<br />
Content-Length: 188<br />
<br />
<body rid='1249243562'<br />
sid='SomeSID'<br />
xmlns='http://jabber.org/protocol/httpbind'><br />
<presence xmlns='jabber:client'><br />
<show>away</show><br />
</presence><br />
</body><br />
</source><br />
<br />
===Closing a Stream===<br />
<br />
If more than one stream is open within a session, the client MAY close one open stream at any time using the procedure described in the section Terminating the HTTP Session above, taking care to specify the stream name with a 'stream' attribute. If the client closes the last stream the connection manager MUST terminate the session. If the client does not specify a stream name then the connection manager MUST close all open streams (sending any payloads the terminate request contains to all streams), and terminate the session.<br />
<br />
'''Example 30. Client closes one stream'''<br />
<source lang="xml"><br />
POST /webclient HTTP/1.1<br />
Host: httpcm.example.com<br />
Accept-Encoding: gzip, deflate<br />
Content-Type: text/xml; charset=utf-8<br />
Content-Length: 153<br />
<br />
<body rid='1249243564'<br />
sid='SomeSID'<br />
stream='secondStreamName'<br />
type='terminate'<br />
xmlns='http://jabber.org/protocol/httpbind'><br />
<presence type='unavailable'<br />
xmlns='jabber:client'/><br />
</body><br />
</source><br />
<br />
===Error Conditions===<br />
<br />
If more than one stream is open within a session, the connection manager MAY include a 'stream' attribute in a fatal binding error (see Terminal Binding Conditions). If a 'stream' attribute is specified then the stream MUST be closed by both entities but the session SHOULD NOT be terminated.<br />
<br />
'''Example 31. Fatal stream error'''<br />
<source lang="xml"><br />
HTTP/1.1 200 OK<br />
Content-Type: text/xml; charset=utf-8<br />
Content-Length: 68<br />
<br />
<body type='terminate'<br />
condition='remote-connection-failed'<br />
stream='secondStreamName'<br />
xmlns='http://jabber.org/protocol/httpbind'/><br />
</source><br />
<br />
Note: If the connection manager does not include a 'stream' attribute in a fatal binding error then all the session's open streams MUST be closed by both entities and the session MUST be terminated.<br />
<br />
==Error and Status Codes==<br />
<br />
There are four types of error and status reporting in HTTP responses:<br />
<br />
'''Table 1: Error Condition Types'''<br />
{| border="1"<br />
!Condition Type<br />
!Description<br />
|-<br />
|HTTP Conditions (Deprecated) <br />
|The connection manager responds to an invalid request from a legacy client with a standard HTTP error. These are used for binding syntax errors, possible attacks, etc. Note that constrained clients are unable to differentiate between HTTP errors.<br />
|-<br />
|Terminal Binding Conditions <br />
|These error conditions can be read by constrained clients. They are used for connection manager problems, abstracting stream errors, communication problems between the connection manager and the server, and invalid client requests (binding syntax errors, possible attacks, etc.)<br />
|-<br />
|Recoverable Binding Conditions <br />
|These report communication problems between the connection manager and the client. They do not terminate the session. Clients recover from these errors by resending all the preceding <body/> wrappers that have not received responses.<br />
|-<br />
|Transported Protocol Conditions <br />
|Errors relating to the XML payloads within <body/> wrappers are, in general, defined in the documentation of the protocol being transported. They do not terminate the session.<br />
|}<br />
<br />
Full descriptions are provided below.<br />
===HTTP Conditions===<br />
<br />
Note: All HTTP codes except 200 have been superseded by Terminal Binding Conditions to allow clients to determine whether the source of errors is the connection manager application or an HTTP intermediary.<br />
<br />
A legacy client (or connection manager) is a client (or connection manager) that did not include a 'ver' attribute in its session creation request (or response). A legacy client (or connection manager) will interpret (or respond with) HTTP error codes according to the table below. Non-legacy connection managers SHOULD NOT send HTTP error codes unless they are communicating with a legacy client. Upon receiving an HTTP error (400, 403, 404), a legacy client or any client that is communicating with a legacy connection manager MUST consider the HTTP session to be null and void. A non-legacy client that is communicating with a non-legacy connection manager MAY consider that the session is still active.<br />
<br />
'''Table 2: HTTP Error and Status Codes'''<br />
{| border="1"<br />
!Code<br />
!Name<br />
!Superseded by<br />
!Purpose<br />
|-<br />
|200 <br />
|OK <br />
|<nowiki>-</nowiki><br />
|Response to valid client request.<br />
|-<br />
|400 <br />
|Bad Request <br />
|bad-request <br />
|Inform client that the format of an HTTP header or binding element is unacceptable (e.g., syntax error).<br />
|-<br />
|403<br />
|Forbidden <br />
|policy-violation <br />
|Inform client that it has broken the session rules (polling too frequently, requesting too frequently, too many simultaneous requests).<br />
|-<br />
|404 <br />
|Not Found <br />
|item-not-found <br />
|Inform client that (1) 'sid' is not valid, (2) 'stream' is not valid, (3) 'rid' is larger than the upper limit of the expected window, (4) connection manager is unable to resend response, (5) 'key' sequence is invalid.<br />
|}<br />
<br />
Note: No other HTTP error and status codes were defined in the early versions of BOSH (e.g., Internal Server Error).<br />
<br />
===Terminal Binding Conditions===<br />
<br />
In any response it sends to the client, the connection manager MAY return a fatal error by setting a 'type' attribute of the <body/> element to "terminate". These binding errors imply that the HTTP session is terminated (unless a 'stream' attribute is specified -- see Multiple Stream Error Conditions).<br />
<br />
Note: Although many of these conditions are similar to the XMPP stream error conditions specified in RFC 6120, they are not to be confused with XMPP stream errors. In cases where BOSH is being used to transport XMPP, any fatal XMPP stream error conditions experienced between the connection manager and the XMPP server SHOULD only be reported using the "remote-stream-error" condition as described below.<br />
<br />
'''Example 32. Remote connection failed error'''<br />
<source lang="xml"><br />
HTTP/1.1 200 OK<br />
Content-Type: text/xml; charset=utf-8<br />
Content-Length: 68<br />
<br />
<body type='terminate'<br />
condition='remote-connection-failed'<br />
xmlns='http://jabber.org/protocol/httpbind'/><br />
</source><br />
<br />
The following values of the 'condition' attribute are defined:<br />
<br />
'''Table 3: Terminal Binding Error Conditions'''<br />
{| border="1"<br />
!Condition<br />
!Purpose<br />
|-<br />
|bad-request* <br />
|The format of an HTTP header or binding element received from the client is unacceptable (e.g., syntax error).<br />
|-<br />
|host-gone <br />
|The target domain specified in the 'to' attribute or the target host or port specified in the 'route' attribute is no longer serviced by the connection manager.<br />
|-<br />
|host-unknown <br />
|The target domain specified in the 'to' attribute or the target host or port specified in the 'route' attribute is unknown to the connection manager.<br />
|-<br />
|improper-addressing <br />
|The initialization element lacks a 'to' or 'route' attribute (or the attribute has no value) but the connection manager requires one.<br />
|-<br />
|internal-server-error <br />
|The connection manager has experienced an internal error that prevents it from servicing the request.<br />
|-<br />
|item-not-found* <br />
|(1) 'sid' is not valid, (2) 'stream' is not valid, (3) 'rid' is larger than the upper limit of the expected window, (4) connection manager is unable to resend response, (5) 'key' sequence is invalid.<br />
|-<br />
|other-request <br />
|Another request being processed at the same time as this request caused the session to terminate.<br />
|-<br />
|policy-violation* <br />
|The client has broken the session rules (polling too frequently, requesting too frequently, sending too many simultaneous requests).<br />
|-<br />
|remote-connection-failed <br />
|The connection manager was unable to connect to, or unable to connect securely to, or has lost its connection to, the server.<br />
|-<br />
|remote-stream-error <br />
|Encapsulates an error in the protocol being transported.<br />
|-<br />
|see-other-uri <br />
|The connection manager does not operate at this URI (e.g., the connection manager accepts only SSL or TLS connections at some https: URI rather than the http: URI requested by the client). The client can try POSTing to the URI in the content of the <uri/> child element.<br />
|-<br />
|system-shutdown <br />
|The connection manager is being shut down. All active HTTP sessions are being terminated. No new sessions can be created.<br />
|-<br />
|undefined-condition <br />
|The error is not one of those defined herein; the connection manager SHOULD include application-specific information in the content of the <body/> wrapper.<br />
|}<br />
<br />
* If the client did not include a 'ver' attribute in its session creation request then the connection manager SHOULD send a deprecated HTTP Error Condition instead of this terminal binding condition. If the connection manager did not include a 'ver' attribute in its session creation response then the client SHOULD expect it to send a deprecated HTTP Error Condition instead of this terminal binding condition.<br />
<br />
The following is an example of a "see-other-uri" condition:<br />
<br />
'''Example 33. See other URI error'''<br />
<source lang="xml"><br />
HTTP/1.1 200 OK<br />
Content-Type: text/xml; charset=utf-8<br />
Content-Length: 68<br />
<br />
<body condition='see-other-uri'<br />
type='terminate'<br />
xmlns='http://jabber.org/protocol/httpbind'><br />
<uri>https://secure.jabber.org/xmppcm</uri><br />
</body><br />
</source><br />
<br />
The following is an example including a "remote-stream-error" condition:<br />
<br />
'''Example 34. Remote error'''<br />
<source lang="xml"><br />
HTTP/1.1 200 OK<br />
Content-Type: text/xml; charset=utf-8<br />
Content-Length: 68<br />
<br />
<body condition='remote-stream-error'<br />
type='terminate'<br />
xmlns='http://jabber.org/protocol/httpbind'<br />
xmlns:stream='http://etherx.jabber.org/streams'><br />
<message from='contact@example.com'<br />
to='user@example.com'<br />
xmlns='jabber:client'><br />
<body>I said "Hi!"</body><br />
</message><br />
<stream:error><br />
<xml-not-well-formed xmlns='urn:ietf:params:xml:ns:xmpp-streams'/><br />
<text xmlns='urn:ietf:params:xml:ns:xmpp-streams'<br />
xml:lang='en'><br />
Some special application diagnostic information!<br />
</text><br />
<escape-your-data xmlns='application-ns'/><br />
</stream:error><br />
</body><br />
</source><br />
<br />
Naturally, the client MAY report binding errors to the connection manager as well, although this is unlikely.<br />
===Recoverable Binding Conditions===<br />
<br />
In any response it sends to the client, the connection manager MAY return a recoverable error by setting a 'type' attribute of the <body/> element to "error". These errors do not imply that the HTTP session is terminated.<br />
<br />
If it decides to recover from the error, then the client MUST repeat the HTTP request that resulted in the error, as well as all the preceding HTTP requests that have not received responses. The content of these requests MUST be identical to the <body/> elements of the original requests. This enables the connection manager to recover a session after the previous request was lost due to a communication failure.<br />
<br />
'''Example 35. Recoverable error'''<br />
<source lang="xml"><br />
HTTP/1.1 200 OK<br />
Content-Type: text/xml; charset=utf-8<br />
Content-Length: 68<br />
<br />
<body type='error'<br />
xmlns='http://jabber.org/protocol/httpbind'/><br />
</source><br />
<br />
===XML Payload Conditions===<br />
<br />
Application-level error conditions described in the documentation of the protocol being transported are routed to the client through the connection manager. They are transparent to the connection manager, and therefore out of scope for the transport binding defined herein.<br />
<br />
==Implementation Notes==<br />
===HTTP Pipelining===<br />
<br />
Even if the client requests HTTP Pipelining and the connection manager supports it, there is no guarantee that pipelining will succeed, because it might not be supported by intermediate proxies.<br />
<br />
The best the client can do is to request the use of HTTP Pipelining by setting the 'hold' attribute to a value of "1". If HTTP Pipelining does not work (because the server returns HTTP 1.0 or connection:close), then the client SHOULD degrade gracefully by using multiple connections.<br />
<br />
==Security Considerations==<br />
===Connection Between Client and BOSH Service===<br />
<br />
All communications between a client and a BOSH service SHOULD occur over encrypted HTTP connections. Negotiation of encryption between the client and the connection manager SHOULD occur at the transport layer or the HTTP layer, not the application layer; such negotiation SHOULD follow the HTTP/SSL protocol defined in SSL [28], although MAY follow the HTTP/TLS protocol defined in RFC 2818 [29] or the TLS Within HTTP protocol defined in RFC 2817 [30].<br />
<br />
If the HTTP connection used to send the initial session request is encrypted, then all the other HTTP connections used within the session MUST also be encrypted. Furthermore, if authentication certificates are exchanged when establishing the encrypted connection that is used to send the initial session request, then the client and/or connection manager SHOULD ensure that the same authentication certificates are employed for all subsequent connections used by the session. Once such a "secure session" has been established:<br />
<br />
* If the connection manager refuses to establish an encrypted connection or offers a different certificate, then the client SHOULD close the connection and terminate the session without sending any more requests.<br />
* If the client sends a wrapper element that is part of a "secure session" over a connection that either is not encrypted or uses a different certificate, then the connection manager SHOULD simply close the connection. The connection manager SHOULD NOT terminate the session since that would facilitate denial of service attacks.<br />
<br />
===Connection Between BOSH Service and Application===<br />
<br />
A BOSH service SHOULD encrypt its connection to the backend application using appropriate technologies such as Secure Sockets Layer (SSL), Transport Layer Security (TLS), and StartTLS if supported by the backend application. Alternatively, the BOSH service can be considered secure (1) if it is running on the same physical machine as the backend application or (2) if it running on the same private network as the backend application and the administrators are sure that unknown individuals or processes do not have access to that private network.<br />
<br />
If data privacy is desired, the client SHOULD encrypt its messages using an application-specific end-to-end encryption technology, because there is no way for the client to be sure that the BOSH service encrypts its connection to the application; methods for doing so are outside the scope of this specification.<br />
===Unpredictable SID and RID===<br />
<br />
The session identifier (SID) and initial request identifier (RID) are security-critical and therefore MUST be both unpredictable and nonrepeating (see RFC 1750 [31] for recommendations regarding randomness of SIDs and initial RIDs for security purposes).<br />
===Use of SHA-1===<br />
<br />
Recent research has shown that in select cases it is possible to compromise the hashes produced by the SHA-1 hashing algorithm (see RFC 4270 [32]). However, the use to which SHA-1 is put in BOSH will likely minimize the applicability of the attacks described in the literature. Furthermore, current estimates suggest that even with the recently-discovered attack, it would still take one year of computing by a government-sized entity to produce a collision.<br />
<br />
==IANA Considerations==<br />
<br />
TCP port 5280, conventially used for communication between BOSH clients and BOSH connection mangers, is registered with the Internet Assigned Numbers Authority (IANA) [33] in its port registry at IANA Port Numbers Registry [34], with a keyword of "xmpp-bosh". (Although use of this port is OPTIONAL, it is helpful to define this port in a standardized way so that BOSH clients can contact any given XMPP service via BOSH without the need either for DNS TXT records as described in Discovering Alternative XMPP Connection Methods [35] or for more advanced methods such as U-NAPTR.<br />
<br />
==XMPP Registrar Considerations==<br />
===Protocol Namespaces===<br />
<br />
The XMPP Registrar includes 'http://jabber.org/protocol/httpbind' in its registry of protocol namespaces.<br />
<br />
==XML Schema==<br />
<source lang="xml"><br />
<?xml version='1.0' encoding='UTF-8'?><br />
<br />
<xs:schema<br />
xmlns:xs='http://www.w3.org/2001/XMLSchema'<br />
xmlns:stream='http://etherx.jabber.org/streams'<br />
targetNamespace='http://jabber.org/protocol/httpbind'<br />
xmlns='http://jabber.org/protocol/httpbind'<br />
elementFormDefault='qualified'><br />
<br />
<xs:annotation><br />
<xs:documentation><br />
The protocol documented by this schema is defined in<br />
XEP-0124: http://www.xmpp.org/extensions/xep-0124.html<br />
</xs:documentation><br />
</xs:annotation><br />
<br />
<xs:import namespace='http://www.w3.org/XML/1998/namespace'<br />
schemaLocation='http://www.w3.org/2001/03/xml.xsd'/><br />
<br />
<xs:element name='body'><br />
<xs:complexType><br />
<xs:choice><br />
<xs:element name='uri'<br />
minOccurs='0'<br />
maxOccurs='1'<br />
type='xs:string'/><br />
<xs:any namespace='##other'<br />
minOccurs='0'<br />
maxOccurs='unbounded'<br />
processContents='lax'/><br />
</xs:choice><br />
<xs:attribute name='accept' type='xs:string' use='optional'/><br />
<xs:attribute name='ack' type='xs:positiveInteger' use='optional'/><br />
<xs:attribute name='authid' type='xs:string' use='optional'/><br />
<xs:attribute name='charsets' type='xs:NMTOKENS' use='optional'/><br />
<xs:attribute name='condition' use='optional'><br />
<xs:simpleType><br />
<xs:restriction base='xs:NCName'><br />
<xs:enumeration value='bad-request'/><br />
<xs:enumeration value='host-gone'/><br />
<xs:enumeration value='host-unknown'/><br />
<xs:enumeration value='improper-addressing'/><br />
<xs:enumeration value='internal-server-error'/><br />
<xs:enumeration value='item-not-found'/><br />
<xs:enumeration value='other-request'/><br />
<xs:enumeration value='policy-violation'/><br />
<xs:enumeration value='remote-connection-failed'/><br />
<xs:enumeration value='remote-stream-error'/><br />
<xs:enumeration value='see-other-uri'/><br />
<xs:enumeration value='system-shutdown'/><br />
<xs:enumeration value='undefined-condition'/><br />
</xs:restriction><br />
</xs:simpleType><br />
</xs:attribute><br />
<xs:attribute name='content' type='xs:string' use='optional'/><br />
<xs:attribute name='from' type='xs:string' use='optional'/><br />
<xs:attribute name='hold' type='xs:unsignedByte' use='optional'/><br />
<xs:attribute name='inactivity' type='xs:unsignedShort' use='optional'/><br />
<xs:attribute name='key' type='xs:string' use='optional'/><br />
<xs:attribute name='maxpause' type='xs:unsignedShort' use='optional'/><br />
<xs:attribute name='newkey' type='xs:string' use='optional'/><br />
<xs:attribute name='pause' type='xs:unsignedShort' use='optional'/><br />
<xs:attribute name='polling' type='xs:unsignedShort' use='optional'/><br />
<xs:attribute name='report' type='xs:positiveInteger' use='optional'/><br />
<xs:attribute name='requests' type='xs:unsignedByte' use='optional'/><br />
<xs:attribute name='rid' type='xs:positiveInteger' use='optional'/><br />
<xs:attribute name='route' type='xs:string' use='optional'/><br />
<xs:attribute name='sid' type='xs:string' use='optional'/><br />
<xs:attribute name='stream' type='xs:string' use='optional'/><br />
<xs:attribute name='time' type='xs:unsignedShort' use='optional'/><br />
<xs:attribute name='to' type='xs:string' use='optional'/><br />
<xs:attribute name='type' use='optional'><br />
<xs:simpleType><br />
<xs:restriction base='xs:NCName'><br />
<xs:enumeration value='error'/><br />
<xs:enumeration value='terminate'/><br />
</xs:restriction><br />
</xs:simpleType><br />
</xs:attribute><br />
<xs:attribute name='ver' type='xs:string' use='optional'/><br />
<xs:attribute name='wait' type='xs:unsignedShort' use='optional'/><br />
<xs:attribute ref='xml:lang' use='optional'/><br />
<xs:anyAttribute namespace='##other' processContents='lax'/><br />
</xs:complexType><br />
</xs:element><br />
<br />
</xs:schema><br />
</source><br />
<br />
==Acknowledgements==<br />
<br />
Thanks to Mike Cumings, Tomas Karasek, Tobias Markmann, Chris Seymour, Safa Sofuoğlu, Stefan Strigler, Matthew Wild, Kevin Winters, and Christopher Zorn for their feedback.<br />
<br />
==Appendices==<br />
===Appendix A: Document Information===<br />
<br />
Series: XEP<br />
Number: 0124<br />
Publisher: XMPP Standards Foundation<br />
Status: Draft<br />
Type: Standards Track<br />
Version: 1.10<br />
Last Updated: 2010-07-02<br />
Approving Body: XMPP Council<br />
Dependencies: RFC 1945, RFC 2616, RFC 3174<br />
Supersedes: None<br />
Superseded By: None<br />
Short Name: bosh<br />
Schema: <http://www.xmpp.org/schemas/httpbind.xsd><br />
Source Control: HTML RSS<br />
This document in other formats: XML PDF<br />
===Appendix B: Author Information===<br />
Ian Paterson<br />
<br />
Email: ian.paterson@clientside.co.uk<br />
JabberID: ian@zoofy.com<br />
Dave Smith<br />
<br />
Email: dizzyd@jabber.org<br />
JabberID: dizzyd@jabber.org<br />
Peter Saint-Andre<br />
<br />
Email: stpeter@jabber.org<br />
JabberID: stpeter@jabber.org<br />
URI: https://stpeter.im/<br />
Jack Moffitt<br />
<br />
Email: jack@chesspark.com<br />
JabberID: jack@chesspark.com<br />
===Appendix C: Legal Notices===<br />
*Copyright<br />
:This XMPP Extension Protocol is copyright © 1999 - 2011 by the XMPP Standards Foundation (XSF).<br />
*Permissions<br />
:Permission is hereby granted, free of charge, to any person obtaining a copy of this specification (the "Specification"), to make use of the Specification without restriction, including without limitation the rights to implement the Specification in a software program, deploy the Specification in a network service, and copy, modify, merge, publish, translate, distribute, sublicense, or sell copies of the Specification, and to permit persons to whom the Specification is furnished to do so, subject to the condition that the foregoing copyright notice and this permission notice shall be included in all copies or substantial portions of the Specification. Unless separate permission is granted, modified works that are redistributed shall not contain misleading information regarding the authors, title, number, or publisher of the Specification, and shall not claim endorsement of the modified works by the authors, any organization or project to which the authors belong, or the XMPP Standards Foundation.<br />
*Disclaimer of Warranty<br />
:'''<nowiki>##</nowiki> NOTE WELL: This Specification is provided on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, express or implied, including, without limitation, any warranties or conditions of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A PARTICULAR PURPOSE. ##'''<br />
*Limitation of Liability<br />
:In no event and under no legal theory, whether in tort (including negligence), contract, or otherwise, unless required by applicable law (such as deliberate and grossly negligent acts) or agreed to in writing, shall the XMPP Standards Foundation or any author of this Specification be liable for damages, including any direct, indirect, special, incidental, or consequential damages of any character arising from, out of, or in connection with the Specification or the implementation, deployment, or other use of the Specification (including but not limited to damages for loss of goodwill, work stoppage, computer failure or malfunction, or any and all other commercial damages or losses), even if the XMPP Standards Foundation or such author has been advised of the possibility of such damages.<br />
*IPR Conformance<br />
:This XMPP Extension Protocol has been contributed in full conformance with the XSF's Intellectual Property Rights Policy (a copy of which can be found at <http://xmpp.org/extensions/ipr-policy.shtml> or obtained by writing to XMPP Standards Foundation, 1899 Wynkoop Street, Suite 600, Denver, CO 80202 USA).<br />
===Appendix D: Relation to XMPP===<br />
<br />
The Extensible Messaging and Presence Protocol (XMPP) is defined in the XMPP Core (RFC 3920) and XMPP IM (RFC 3921) specifications contributed by the XMPP Standards Foundation to the Internet Standards Process, which is managed by the Internet Engineering Task Force in accordance with RFC 2026. Any protocol defined in this document has been developed outside the Internet Standards Process and is to be understood as an extension to XMPP rather than as an evolution, development, or modification of XMPP itself.<br />
===Appendix E: Discussion Venue===<br />
<br />
The primary venue for discussion of XMPP Extension Protocols is the <standards@xmpp.org> discussion list.<br />
<br />
Discussion on other xmpp.org discussion lists might also be appropriate; see <http://xmpp.org/about/discuss.shtml> for a complete list.<br />
<br />
Given that this XMPP Extension Protocol normatively references IETF technologies, discussion on the <xsf-ietf@xmpp.org> list might also be appropriate.<br />
<br />
Errata can be sent to <editor@xmpp.org>.<br />
===Appendix F: Requirements Conformance===<br />
<br />
The following requirements keywords as used in this document are to be interpreted as described in RFC 2119: "MUST", "SHALL", "REQUIRED"; "MUST NOT", "SHALL NOT"; "SHOULD", "RECOMMENDED"; "SHOULD NOT", "NOT RECOMMENDED"; "MAY", "OPTIONAL".<br />
===Appendix G: Notes===<br />
<br />
1. RFC 793: Transmission Control Protocol <http://tools.ietf.org/html/rfc0793>.<br />
<br />
2. RFC 1945: Hypertext Transfer Protocol -- HTTP/1.0 <http://tools.ietf.org/html/rfc1945>.<br />
<br />
3. RFC 2616: Hypertext Transport Protocol -- HTTP/1.1 <http://tools.ietf.org/html/rfc2616>.<br />
<br />
4. Bayeux Protocol <http://svn.cometd.org/trunk/bayeux/bayeux.html>.<br />
<br />
5. The Web Socket Protocol <http://tools.ietf.org/html/draft-hixie-thewebsocketprotocol>.<br />
<br />
6. Reverse HTTP <http://tools.ietf.org/html/draft-lentczner-rhttp>.<br />
<br />
7. RFC 2965: HTTP State Management Mechanism <http://tools.ietf.org/html/rfc2965>.<br />
<br />
8. Requiring cookies is sub-optimal because several significant computing platforms provide only limited access to underlying HTTP requests/responses; worse, some platforms hide or remove cookie-related headers.<br />
<br />
9. XEP-0025: Jabber HTTP Polling <http://xmpp.org/extensions/xep-0025.html>.<br />
<br />
10. RFC 6120: Extensible Messaging and Presence Protocol (XMPP): Core <http://tools.ietf.org/html/rfc6120>.<br />
<br />
11. XEP-0206: XMPP Over BOSH <http://xmpp.org/extensions/xep-0206.html>.<br />
<br />
12. In order to reduce network congestion, RFC 2616 recommends that clients SHOULD NOT keep more than two HTTP connections to the same HTTP server open at the same time. Clients running in constrained enviroments typically have no choice but to abide by that recommendation.<br />
<br />
13. If there is no traffic other than the "pings" then bandwidth consumption will be double that of a TCP connection (although double nothing is still nothing). If data is sent in large packets then bandwidth consumption will be almost identical.<br />
<br />
14. Extensible Markup Language (XML) 1.0 (Fourth Edition) <http://www.w3.org/TR/REC-xml/>.<br />
<br />
15. Namespaces in XML <http://www.w3.org/TR/REC-xml-names/>.<br />
<br />
16. RFC 4627: The application/json Media Type for JavaScript Object Notation (JSON) <http://tools.ietf.org/html/rfc4627>.<br />
<br />
17. Extensible Markup Language (XML) 1.0 (Fourth Edition) <http://www.w3.org/TR/REC-xml/>.<br />
<br />
18. Although the syntax of the 'route' attribute bears a superficial resemblance to a URI or IRI, it is not a URI/IRI and MUST NOT be processed in accordance with the rules specified in RFC 3986, RFC 3987, or (for XMPP) RFC 5122.<br />
<br />
19. Each character set name (or character encoding name -- we use the terms interchangeably) SHOULD be of type NMTOKEN, where the names are separated by the white space character #x20, resulting in a tokenized attribute type of NMTOKENS (see Section 3.3.1 of XML 1.0 [20]). Strictly speaking, the Character Sets registry maintained by the Internet Assigned Numbers Authority (see <http://www.iana.org/assignments/character-sets>) allows a character set name to contain any printable US-ASCII character, which might include characters not allowed by the NMTOKEN construction of XML 1.0; however, the only existing character set name which includes such a character is "NF_Z_62-010_(1973)".<br />
<br />
20. Extensible Markup Language (XML) 1.0 (Fourth Edition) <http://www.w3.org/TR/REC-xml/>.<br />
<br />
21. 9007199254740991 is 253-1. Some weakly typed languages use IEEE Standard 754 Doubles to represent all numbers. These Doubles cannot represent integers above 253 accurately.<br />
<br />
22. RFC 3174: US Secure Hash Algorithm 1 (SHA1) <http://tools.ietf.org/html/rfc3174>.<br />
<br />
23. Therefore a client and a connection manager will be compatible even if one or the other offers no support for multi-stream sessions.<br />
<br />
24. The 'rid' attribute is always incremented normally without reference to any 'stream' attribute.<br />
<br />
25. This helps to ensure backwards-compatibility with older implementations.<br />
<br />
26. Each HTTP response MUST belong to the same session as the request that triggered it, but not necessarily to the same stream.<br />
<br />
27. The broadcast payloads can be of any type.<br />
<br />
28. SSL V3.0 <http://wp.netscape.com/eng/ssl3/draft302.txt>.<br />
<br />
29. RFC 2818: HTTP Over TLS <http://tools.ietf.org/html/rfc2818>.<br />
<br />
30. RFC 2817: Upgrading to TLS Within HTTP/1.1 <http://tools.ietf.org/html/rfc2817>.<br />
<br />
31. RFC 1750: Randomness Recommendations for Security <http://tools.ietf.org/html/rfc1750>.<br />
<br />
32. RFC 4270: Attacks on Cryptographic Hashes in Internet Protocols <http://tools.ietf.org/html/rfc4270>.<br />
<br />
33. The Internet Assigned Numbers Authority (IANA) is the central coordinator for the assignment of unique parameter values for Internet protocols, such as port numbers and URI schemes. For further information, see <http://www.iana.org/>.<br />
<br />
34. IANA registry of port numbers <http://www.iana.org/assignments/port-numbers>.<br />
<br />
35. XEP-0156: Discovering Alternative XMPP Connection Methods <http://xmpp.org/extensions/xep-0156.html>.<br />
===Appendix H: Revision History===<br />
<br />
Note: Older versions of this specification might be available at http://xmpp.org/extensions/attic/<br />
;Version 1.10 (2010-07-02)<br />
<br />
:Further clarified use of 'from' and 'to' attributes; added missing condition values to the schema.<br />
:(psa)<br />
;Version 1.9 (2009-11-06)<br />
<br />
:Added information for registration of port 5280 with IANA.<br />
:(psa)<br />
;Version 1.8 (2009-04-30)<br />
<br />
:Removed secure attribute because it did not solve the problem it was intended to solve; added security consideration regarding link between connection manager and application server; changed "stanza" to "payload" for disambiguation with XMPP; clarified design objectives and relationship to similar technologies; corrected several errors in the schema.<br />
:(psa/jm)<br />
;Version 1.7 (2008-10-29)<br />
<br />
:Moved alternative script syntax to historical specification; added implementation note about HTTP Pipelining; adjusted architectural description.<br />
:(psa)<br />
;Version 1.6 (2007-02-21)<br />
<br />
:Multiple clarifications and restructuring without changes to protocol itself; changed title to BOSH; added section that fully explains the technique underlying the protocol; separated XMPP-specific features into new XEP-0206; added optional new Script Syntax and session pauses; added Acknowledgements section; added from and ver attributes; added hold attribute to session creation response; clarified polling too-frequently error; recommended that clients use HTTP Pipelining.<br />
:(ip)<br />
;Version 1.5 (2006-04-28)<br />
<br />
:Added optional Multiple Streams section; added security considerations about encrypted HTTP connections; recommended use of SSL rather than HTTP over TLS; specified that request ID values must not exceed 9007199254740991; corrected datatypes of inactivity, polling, rid, and wait attributes in the schema; added <any/> and <anyAttribute/> elements to schema to optionally support non-XMPP XML elements and attributes; deprecated HTTP error codes in favor of new terminal binding conditions.<br />
:(ip/psa)<br />
;Version 1.4 (2005-12-14)<br />
<br />
:Modified syntax of route attribute to be proto:host:port rather than XMPP URI/IRI.<br />
:(psa)<br />
;Version 1.3 (2005-11-02)<br />
<br />
:Corrected stream:features namespace and the Recoverable Binding Conditions section; recommended that connection manager shall return secure attribute to client; recommended end-to-end encryption through proxy connection managers.<br />
:(ip)<br />
;Version 1.2 (2005-06-16)<br />
<br />
:Specified optional use of route and secure attributes in session request. Minor correction: the stream features element should be included in the response that contains the authid attribute (this is not necessarily the session creation response).<br />
:(ip)<br />
;Version 1.1 (2005-06-02)<br />
<br />
:Specified optional use of HTTP Accept-Encoding and Content-Encoding headers for compression at HTTP binding level.<br />
:(ip)<br />
;Version 1.0 (2005-03-03)<br />
<br />
:Per a vote of the Jabber Council, advanced status to Draft.<br />
:(psa)<br />
;Version 0.10 (2004-11-08)<br />
<br />
:Changed HTTP 401 errors to HTTP 404.<br />
:(ip)<br />
;Version 0.9 (2004-10-26)<br />
<br />
:Added charset attribute.<br />
:(ip/psa)<br />
;Version 0.8 (2004-10-26)<br />
<br />
:Specified that wait attribute must be included in the session creation response.<br />
:(ip)<br />
;Version 0.7 (2004-08-12)<br />
<br />
:Defined appropriate XMPP stanza error conditions.<br />
:(psa/ip)<br />
;Version 0.6 (2004-07-19)<br />
<br />
:Added xml:lang attribute to the session request; added recoverable binding error conditions.<br />
:(ip)<br />
;Version 0.5 (2004-05-07)<br />
<br />
:Protocol refactored to enable simultaneous requests (request identifier attribute, wait attribute, hold attribute, requests attribute) and recovery of broken connections; added content attribute; removed all wrapper types except 'terminate'; updated error handling; made key mechanism optional (should use SSL/TLS instead).<br />
:(ip/psa)<br />
;Version 0.4 (2004-02-23)<br />
<br />
:Fixed typos; removed "resource-constraint" binding error; added HTTP 403 error to table.<br />
:(psa/ip)<br />
;Version 0.3 (2004-02-19)<br />
<br />
:Added 'authid' attribute to enable communication of XMPP stream ID (used in digest authentication); specified that Content-Types other than "text/xml" are allowed to support older HTTP clients; specified business rule for connection manager queueing of client requests; changed <packet/> to <body/> to support older HTTP clients; changed 'to' attribute on initialization element from MAY to SHOULD; recommended inclusion of unavailable presence in termination element sent from client; described architectural assumptions; specified binding-specific error handling.<br />
:(psa/ip)<br />
;Version 0.2 (2004-01-13)<br />
<br />
:Added 'to' attribute on the initialization element; specified that 'text/html' is allowable for backwards-compatibility.<br />
:(dss/psa/ip)<br />
;Version 0.1 (2003-11-06)<br />
<br />
:Initial version.<br />
:(dss/psa)<br />
<br />
结束</div>
Snowqiang
http://wiki.jabbercn.org/XEP-0124
XEP-0124
2011-05-18T14:55:54Z
<p>Snowqiang: /* HTTP Conditions */</p>
<hr />
<div>[[Category:XMPP扩展]]<br />
[[Category:翻译中]]<br />
<br />
'''本文的英文原文来自[http://www.xmpp.org/extensions/xep-0124.html XEP-0124]'''<br />
<br />
'''XEP-0124: Bidirectional-streams Over Synchronous HTTP (BOSH)'''<br />
<br />
摘要: This specification defines a transport protocol that emulates the semantics of a long-lived, bidirectional TCP connection between two entities (such as a client and a server) by efficiently using multiple synchronous HTTP request/response pairs without requiring the use of frequent polling or chunked responses.<br />
<br />
作者: Ian Paterson, Dave Smith, Peter Saint-Andre, Jack Moffitt<br />
<br />
版权: © 1999 - 2011 XMPP Standards Foundation. SEE LEGAL NOTICES.<br />
<br />
状态: 草案<br />
<br />
类型: 标准跟踪<br />
<br />
版本: 2.0<br />
<br />
最后更新日期: 2010-07-02<br />
<br />
NOTICE: The protocol defined herein is a Draft Standard of the XMPP Standards Foundation. Implementations are encouraged and the protocol is appropriate for deployment in production systems, but some changes to the protocol are possible before it becomes a Final Standard.<br />
<br />
==Introduction==<br />
<br />
The Transmission Control Protocol (TCP; RFC 793 [1]) is often used to establish a stream-oriented connection between two entities. Such connections can often be long-lived to enable an interactive "session" between the entities. However, sometimes the nature of the device or network can prevent an application from maintaining a long-lived TCP connection to a server or peer. In this case, it is desirable to use an alternative connection method that emulates the behavior of a long-lived TCP connection using a sequenced series of requests and responses that are exchanged over short-lived connections. The appropriate request-response semantics are widely available via the Hypertext Transfer Protocol (HTTP) as specified in RFC 1945 [2] and RFC 2616 [3].<br />
<br />
BOSH, the technology defined in this specification, essentially provides a "drop-in" alternative to a long-lived, bidirectional TCP connection. It is a mature, full-featured technology that has been widely implemented and deployed since 2004. To our knowledge it was the first of many similar technologies, which now include the Comet methodology formalized in the Bayeux Protocol [4] as well as The Web Socket Protocol [5] and Reverse HTTP [6].<br />
<br />
BOSH is designed to transport any data efficiently and with minimal latency in both directions. For applications that require both "push" and "pull" semantics, BOSH is significantly more bandwidth-efficient and responsive than most other bidirectional HTTP-based transport protocols and the techniques now commonly known as "Ajax". BOSH achieves this efficiency and low latency by using so-called "long polling" with multiple synchronous HTTP request/response pairs. Furthermore, BOSH can address the needs of constrained clients by employing fully-compliant HTTP 1.0 without the need for "cookies" (see RFC 2965 [7]) [8] or even access to HTTP headers.<br />
<br />
BOSH was originally developed in the Jabber/XMPP community as a replacement for an even earlier HTTP-based technology called Jabber HTTP Polling [9]. Although BOSH assumes that the "payload" of HTTP requests and responses will be XML, the payload formats are not limited to XMPP stanzas (see XMPP Core [10]) and could contain a mixture of elements qualified by namespaces defined by different protocols (e.g., both XMPP and JSON). This mix is necessary because some connection managers might 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 payload is qualified by the correct namespace.<br />
<br />
Note: XMPP Over BOSH [11] documents some XMPP-specific extensions of this protocol that were formerly included in this document.<br />
<br />
==Requirements==<br />
<br />
The following design requirements reflect the need to offer performance as close as possible to a standard TCP connection.<br />
<br />
1. Compatible with constrained runtime environments* (e.g., mobile and browser-based clients).<br />
2. Compatible with proxies that buffer partial HTTP responses.<br />
3. Efficient through proxies that limit the duration of HTTP responses.<br />
4. Fully compatible with HTTP/1.0.<br />
5. Compatible with restricted network connections (e.g., firewalls, proxies, and gateways).<br />
6. Fault tolerant (e.g., session recovers after an underlying TCP connection breaks at any stage during an HTTP request).<br />
7. Extensible.<br />
8. Consume significantly less bandwidth than polling-based protocols.<br />
9. Significantly more responsive (lower latency) than polling-based protocols.<br />
10. Support for polling (for clients that are limited to a single HTTP connection at a time).<br />
11. In-order delivery of data.<br />
12. Guard against unauthorized users injecting HTTP requests into a session.<br />
13. Protect against denial of service attacks.<br />
14. Multiplexing of data streams.<br />
<br />
*Note: Compatibility with constrained runtime environments implies the following restrictions:<br />
<br />
1. Clients are not required to have programmatic access to the headers of each HTTP request and response (e.g., cookies or status codes).<br />
2. The body of each HTTP request and response is parsable XML with a single root element.<br />
3. Clients can specify the Content-Type of the HTTP responses they receive.<br />
<br />
==Architectural Assumptions==<br />
<br />
This document assumes that most implementations will utilize a specialized connection manager ("CM") to handle HTTP connections rather than the native connection type for the relevant application (e.g., TCP connections in XMPP). Effectively, such a connection manager is a specialized HTTP server that translates between the HTTP requests and responses defined herein and the data streams (or API) implemented by the server with which it communicates, thus enabling a client to connect to a server via HTTP on port 80 or 443 instead of an application-specific port. We can illustrate this graphically as follows:<br />
<br />
Server<br />
|<br />
| [unwrapped data streams]<br />
|<br />
HTTP CM<br />
|<br />
| [HTTP + <body/> wrapper]<br />
|<br />
Client<br />
<br />
<br />
This specification covers communication only between a client and the connection manager. It does not cover communication between the connection manager and the server, since such communications are implementation-specific (e.g., the server might 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 might be an independent translating proxy such that the server might believe it is talking directly to the client over TCP; or the connection manager and the server might use a component protocol or an API defined by the server implementation).<br />
<br />
Furthermore, no aspect of this protocol limits its use to communication between a client and a server. For example, it could be used for communication between a server and a peer server if such communication can occur for the relevant application (e.g., in XMPP). 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 the native connection transport for the relevant application. (However, on some unreliable networks, BOSH might enable more stable communication between servers.)<br />
<br />
==The BOSH Technique==<br />
<br />
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).<br />
<br />
The technique employed by BOSH 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.<br />
<br />
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 so to make sure the client can send more data immediately if necessary. (The client SHOULD NOT open more than two HTTP connections to the connection manager at the same time, [12] so it would otherwise have to wait until the connection manager responds to one of the requests.)<br />
<br />
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 TCP 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.<br />
<br />
If there is no traffic in either direction for an agreed amount of time (typically several 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 so 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. [13]<br />
<br />
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. Thus 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. Therefore, 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 were being used.<br />
<br />
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.<br />
<br />
==HTTP Overview==<br />
<br />
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).<br />
<br />
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 permitted by RFC 1945 or RFC 2616. For example, 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 might buffer each partial HTTP request or response and only forward the full request or response once it is available.<br />
<br />
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.<br />
<br />
Requests and responses MAY include HTTP headers not specified herein. The receiver SHOULD ignore any such headers.<br />
<br />
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). However, the responses to requests that are not part of the session sent over the same connection using HTTP pipelining (or queued to be sent over the same connection) might be delayed if they were sent while a request that is part of the session is being held (since the connection manager MUST send its responses in the same order that the requests were received, and the connection manager typically delays its responses).<br />
<br />
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.<br />
<br />
==<body/> Wrapper Element==<br />
<br />
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 transferred. The <body/> element and its content together MUST conform to the specifications set out in XML 1.0 [14]. They SHOULD also conform to Namespaces in XML [15]. The content MUST NOT contain any of the following (all defined in XML 1.0):<br />
<br />
* Partial XML elements<br />
* XML comments<br />
* XML processing instructions<br />
* Internal or external DTD subsets<br />
* Internal or external entity references (with the exception of predefined entities)<br />
<br />
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 "payloads" in this document, e.g., XMPP stanzas as defined in RFC 6120 or elements containing XML character data that represents objects using the JSON data interchange format as defined in RFC 4627 [16]). Each <body/> wrapper MAY contain payloads qualified under a wide variety of different namespaces.<br />
<br />
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.<br />
<br />
==Initiating a BOSH Session==<br />
===Session Creation Request===<br />
<br />
The first request from the client to the connection manager requests a new session.<br />
<br />
The <body/> element of the first request SHOULD possess the following attributes (they SHOULD NOT be included in any other requests except as specified under Adding Streams To A Session):<br />
<br />
* '''<nowiki>'to'</nowiki>''' -- This attribute specifies the target domain of the first stream.<br />
* '''<nowiki>'xml:lang'</nowiki>''' -- This attribute (as defined in Section 2.12 of XML 1.0 [17]) specifies the default language of any human-readable XML character data sent or received during the session.<br />
* '''<nowiki>'ver'</nowiki>''' -- This attribute specifies the highest version of the BOSH protocol that the client supports. The numbering scheme is "<major>.<minor>" (where the minor number MAY be incremented higher than a single digit, so it MUST be treated as a separate integer). Note: The 'ver' attribute should not be confused with the version of any protocol being transported.<br />
* '''<nowiki>'wait'</nowiki>''' -- This attribute specifies the longest time (in seconds) that the connection manager is allowed to wait before responding to any request during the session. This enables the client to limit the delay before it discovers any network failure, and to prevent its HTTP/TCP connection from expiring due to inactivity.<br />
* '''<nowiki>'hold'</nowiki>''' -- This attribute specifies the maximum number of requests the connection manager is allowed to keep waiting at any one time during the session. If the client is not able to use HTTP Pipelining then this SHOULD be set to "1".<br />
<br />
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 both typically one or two orders of magnitude!<br />
<br />
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:example.com:9999"). [18] A connection manager that is configured to work only with a single server (or only with a defined list of domains and the associated list of hostnames and ports that are serving those domains) MAY ignore the 'route' attribute. (Note that the 'to' attribute specifies the domain being served, not the hostname of the machine that is serving the domain.)<br />
<br />
The <body/> element of the first request MAY also possess a 'from' attribute, which specifies the originator of the first stream and which enables the connection manager to forward the originating entity's identity to the application server (e.g., the JabberID of an entity that is connecting to an XMPP server; see XEP-0206).<br />
<br />
A client MAY include an 'ack' attribute (set to "1") to indicate that it will be using acknowledgements throughout the session and that the absence of an 'ack' attribute in any request is meaningful (see Acknowledgements).<br />
<br />
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".<br />
<br />
'''Example 1. Requesting a BOSH session'''<br />
<source lang="xml"><br />
POST /webclient HTTP/1.1<br />
Host: httpcm.example.com<br />
Accept-Encoding: gzip, deflate<br />
Content-Type: text/xml; charset=utf-8<br />
Content-Length: 104<br />
<br />
<body content='text/xml; charset=utf-8'<br />
from='user@example.com'<br />
hold='1'<br />
rid='1573741820'<br />
to='example.com'<br />
route='xmpp:example.com:9999'<br />
ver='1.6'<br />
wait='60'<br />
ack='1'<br />
xml:lang='en'<br />
xmlns='http://jabber.org/protocol/httpbind'/><br />
</source><br />
<br />
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.<br />
===Session Creation Response===<br />
<br />
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):<br />
<br />
* '''<nowiki>'sid'</nowiki>''' -- This attribute specifies the SID<br />
* '''<nowiki>'wait'</nowiki>''' -- This is the longest time (in seconds) that the connection manager will wait before responding to any request during the session. The time MUST be less than or equal to the value specified in the session request.<br />
<br />
The <body/> element SHOULD also include the following attributes (they SHOULD NOT be included in any other responses):<br />
<br />
* '''<nowiki>'ver'</nowiki>''' -- This attribute specifies the highest version of the BOSH protocol that the connection manager supports, or the version specified by the client in its request, whichever is lower.<br />
* '''<nowiki>'polling'</nowiki>''' -- This attribute specifies the shortest allowable polling interval (in seconds). This enables the client to not send empty request elements more often than desired (see Polling Sessions and Overactivity).<br />
* '''<nowiki>'inactivity'</nowiki>''' -- This attribute specifies the longest allowable inactivity period (in seconds). This enables the client to ensure that the periods with no requests pending are never too long (see Polling Sessions and Inactivity).<br />
* '''<nowiki>'requests'</nowiki>''' -- This attribute enables the connection manager to limit the number of simultaneous requests the client makes (see Overactivity and Polling Sessions). The RECOMMENDED values are either "2" or one more than the value of the 'hold' attribute specified in the session request.<br />
* '''<nowiki>'hold'</nowiki>''' -- This attribute informs the client about the maximum number of requests the connection manager will keep waiting at any one time during the session. This value MUST NOT be greater than the value specified by the client in the session request.<br />
* '''<nowiki>'to'</nowiki>''' -- This attribute communicates the identity of the backend server to which the client is attempting to connect.<br />
<br />
The connection manager MAY include an 'accept' attribute in the session creation response element, to specify a space-separated list of 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.<br />
<br />
A connection manager MAY include an 'ack' attribute (set to the value of the 'rid' attribute of the session creation request) to indicate that it will be using acknowledgements throughout the session and that the absence of an 'ack' attribute in any response is meaningful (see Acknowledgements).<br />
<br />
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 can request.<br />
<br />
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. [19]<br />
<br />
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 a BOSH Session), then in the same response the connection manager SHOULD also include the 'secure' attribute set to "true" or "1".<br />
<br />
'''Example 2. Session creation response'''<br />
<source lang="xml"><br />
HTTP/1.1 200 OK<br />
Content-Type: text/xml; charset=utf-8<br />
Content-Length: 128<br />
<br />
<body wait='60'<br />
inactivity='30'<br />
polling='5'<br />
requests='2'<br />
hold='1'<br />
ack='1573741820'<br />
accept='deflate,gzip'<br />
maxpause='120'<br />
sid='SomeSID'<br />
charsets='ISO_8859-1 ISO-2022-JP'<br />
ver='1.6'<br />
from='example.com'<br />
xmlns='http://jabber.org/protocol/httpbind'/><br />
</source><br />
<br />
'''Example 3. Subsequent response with 'from' and 'secure' attributes'''<br />
<source lang="xml"><br />
HTTP/1.1 200 OK<br />
Content-Type: text/xml; charset=utf-8<br />
Content-Length: 128<br />
<br />
<body from='example.com'<br />
xmlns='http://jabber.org/protocol/httpbind'/><br />
</source><br />
<br />
==Sending and Receiving XML Payloads==<br />
<br />
After the client has successfully completed all required preconditions, it can send and receive XML payloads via the HTTP binding.<br />
<br />
'''Example 4. Transmitting payloads'''<br />
<source lang="xml"><br />
POST /webclient HTTP/1.1<br />
Host: httpcm.example.com<br />
Accept-Encoding: gzip, deflate<br />
Content-Type: text/xml; charset=utf-8<br />
Content-Length: 188<br />
<br />
<body rid='1249243562'<br />
sid='SomeSID'<br />
xmlns='http://jabber.org/protocol/httpbind'><br />
<message to='contact@example.com'<br />
xmlns='jabber:client'><br />
<body>Good morning!</body><br />
</message><br />
<message to='friend@example.com'<br />
xmlns='jabber:client'><br />
<body>Hey, what&apos;s up?</body><br />
</message><br />
</body><br />
</source><br />
<br />
Upon receipt of a request, the connection manager SHOULD forward the content of the <body/> element to the server as soon as possible. In any case it MUST forward the content from different requests in the order specified by their 'rid' attributes.<br />
<br />
The connection manager MUST also return an HTTP 200 OK response with a <body/> element to the client. Note: This does not indicate that the payloads have been successfully delivered to the application server.<br />
<br />
It is RECOMMENDED that the connection manager not return an HTTP result until a payload has arrived from the application server for delivery to the client. However, the connection manager SHOULD NOT wait longer than the time specified by the client in the 'wait' attribute of its Session Creation Request, and it SHOULD NOT keep more HTTP requests waiting at a time than the number specified in the 'hold' attribute of the session creation request. In any case it MUST respond to requests in the order specified by their 'rid' attributes.<br />
<br />
If there are no payloads waiting or ready to be delivered within the waiting period, then the connection manager SHOULD include an empty <body/> element in the HTTP result:<br />
<br />
'''Example 5. Empty response'''<br />
<source lang="xml"><br />
HTTP/1.1 200 OK<br />
Content-Type: text/xml; charset=utf-8<br />
Content-Length: 64<br />
<br />
<body xmlns='http://jabber.org/protocol/httpbind'/><br />
</source><br />
<br />
If the connection manager has received one or more payloads from the application server for delivery to the client, then it SHOULD return the payloads in the body of its response as soon as possible after receiving them from the server. The example below includes payloads qualified by different namespaces:<br />
<br />
'''Example 6. Response with queued stanza'''<br />
<source lang="xml"><br />
HTTP/1.1 200 OK<br />
Content-Type: text/xml; charset=utf-8<br />
Content-Length: 185<br />
<br />
<body xmlns='http://jabber.org/protocol/httpbind'<br />
xmlns:json='http://json.org/'><br />
<message from='contact@example.com'<br />
to='user@example.com'<br />
xmlns='jabber:client'><br />
<body>Good morning to you!</body><br />
</message><br />
<message from='friend@example.com'<br />
to='user@example.com'<br />
xmlns='jabber:client'><br />
<body>Not much, how about with you?</body><br />
</message><br />
<json:json><br />
[<br />
{<br />
"precision": "zip",<br />
"Latitude": 37.7668,<br />
"Longitude": -122.3959,<br />
"Address": "",<br />
"City": "SAN FRANCISCO",<br />
"State": "CA",<br />
"Zip": "94107",<br />
"Country": "US"<br />
},<br />
{<br />
"precision": "zip",<br />
"Latitude": 37.371991,<br />
"Longitude": -122.026020,<br />
"Address": "",<br />
"City": "SUNNYVALE",<br />
"State": "CA",<br />
"Zip": "94085",<br />
"Country": "US"<br />
}<br />
]<br />
</json:json><br />
</body><br />
</source><br />
<br />
The client MAY poll the connection manager for incoming payloads by sending an empty <body/> element.<br />
<br />
'''Example 7. Requesting XML Payloads'''<br />
<source lang="xml"><br />
POST /webclient HTTP/1.1<br />
Host: httpcm.example.com<br />
Accept-Encoding: gzip, deflate<br />
Content-Type: text/xml; charset=utf-8<br />
Content-Length: 88<br />
<br />
<body rid='1249243563'<br />
sid='SomeSID'<br />
xmlns='http://jabber.org/protocol/httpbind'/><br />
</source><br />
<br />
The connection manager MUST wait and respond in the same way as it does after receiving payloads from the client.<br />
<br />
==Acknowledgements==<br />
===Request Acknowledgements===<br />
<br />
When responding to a request that it has been holding, if the connection manager finds it has already received another request with a higher 'rid' attribute (typically while it was holding the first request), then it MAY acknowledge the reception to the client. The connection manager MAY set the 'ack' attribute of any response to the value of the highest 'rid' attribute it has received in the case where it has also received all requests with lower 'rid' values.<br />
<br />
'''Example 8. Response with request acknowledgement'''<br />
<source lang="xml"><br />
HTTP/1.1 200 OK<br />
Content-Type: text/xml; charset=utf-8<br />
Content-Length: 64<br />
<br />
<body ack='1249243564'<br />
xmlns='http://jabber.org/protocol/httpbind'/><br />
</source><br />
<br />
If the connection manager will be including 'ack' attributes on responses during a session, then it MUST include an 'ack' attribute in its session creation response, and set the 'ack' attribute of responses throughout the session. The only exception is that, after its session creation response, the connection manager SHOULD NOT include an 'ack' attribute in any response if the value would be the 'rid' of the request being responded to.<br />
<br />
If the connection manager is permitted to hold more than one request at a time, then the reception of a lower-than-expected 'ack' value from the connection manager (or the unexpected abscence of an 'ack' attribute) can give the client an early warning that a network failure might have occurred (e.g., if the client believes the connection manager should have received another request by the time it responded).<br />
===Response Acknowledgements===<br />
<br />
The client MAY similarly inform the connection manager about the responses it has received by setting the 'ack' attribute of any request to the value of the highest 'rid' of a request for which it has already received a response in the case where it has also received all responses associated with lower 'rid' values. If the client will be including 'ack' attributes on requests during a session, then it MUST include an 'ack' attribute (set to '1') in its session creation request, and set the 'ack' attribute of requests throughout the session. The only exception is that, after its session creation request, the client SHOULD NOT include an 'ack' attribute in any request if it has received responses to all its previous requests.<br />
<br />
'''Example 9. Request with response acknowledgement'''<br />
<source lang="xml"><br />
POST /webclient HTTP/1.1<br />
Host: httpcm.example.com<br />
Accept-Encoding: gzip, deflate<br />
Content-Type: text/xml; charset=utf-8<br />
Content-Length: 88<br />
<br />
<body rid='1249243566'<br />
sid='SomeSID'<br />
ack='1249243564'<br />
xmlns='http://jabber.org/protocol/httpbind'/><br />
</source><br />
<br />
After receiving a request with an 'ack' value less than the 'rid' of the last request that it has already responded to, the connection manager MAY inform the client of the situation by sending its next response immediately instead of waiting until it has payloads to send to the client (e.g., if some time has passed since it responded). In this case it SHOULD include a 'report' attribute set to one greater than the 'ack' attribute it received from the client, and a 'time' attribute set to the number of milliseconds since it sent the response associated with the 'report' attribute.<br />
<br />
'''Example 10. Response with report'''<br />
<source lang="xml"><br />
HTTP/1.1 200 OK<br />
Content-Type: text/xml; charset=utf-8<br />
Content-Length: 64<br />
<br />
<body report='1249243565'<br />
time='852'<br />
xmlns='http://jabber.org/protocol/httpbind'/><br />
</source><br />
<br />
Upon reception of a response with 'report' and 'time' attributes, if the client has still not received the response associated with the request identifier specified by the 'report' attribute, then it MAY choose to resend the request associated with the missing response (see Broken Connections).<br />
<br />
==Inactivity==<br />
<br />
After receiving a response from the connection manager, if none of the client's requests are still being held by the connection manager (and if the session is not a Polling Session), the client SHOULD make a new request as soon as possible. In any case, if no requests are being held, the client MUST make a new request before the maximum inactivity period has expired. The length of this period (in seconds) is specified by the 'inactivity' attribute in the session creation response.<br />
<br />
If the connection manager has responded to all the requests it has received within a session and the time since its last response is longer than the maximum inactivity period, then it SHOULD assume the client has been disconnected and terminate the session without informing the client. If the client subsequently makes another request, then the connection manager SHOULD respond as if the session does not exist.<br />
<br />
If the connection manager did not specify a maximum inactivity period in the session creation response, then it SHOULD allow the client to be inactive for as long as it chooses.<br />
<br />
If the session is not a polling session then the connection manager SHOULD specify a relatively short inactivity period to ensure that disconnections are discovered as quickly as possible. The RECOMMENDED time would be a little more than the number of seconds for a comfortable network round trip between the connection manager and the client under difficult network conditions (since the client can be expected to make a new request immediately -- see above).<br />
<br />
If a client encounters an exceptional temporary situation during which it will be unable to send requests to the connection manager for a period of time greater than the maximum inactivity period (e.g., while a runtime environment changes from one web page to another), and if the connection manager included a 'maxpause' attribute in its Session Creation Response, then the client MAY request a temporary increase to the maximum inactivity period by including a 'pause' attribute in a request. Note: If the connection manager did not specify a 'maxpause' attribute at the start of the session then the client MUST NOT send a 'pause' attribute during the session.<br />
<br />
'''Example 11. Requesting a Session Pause'''<br />
<source lang="xml"><br />
POST /webclient HTTP/1.1<br />
Host: httpcm.example.com<br />
Accept-Encoding: gzip, deflate<br />
Content-Type: text/xml; charset=utf-8<br />
Content-Length: 98<br />
<br />
<body rid='1249243564'<br />
sid='SomeSID'<br />
pause='60'<br />
xmlns='http://jabber.org/protocol/httpbind'/><br />
</source><br />
<br />
Upon reception of a session pause request, if the requested period is not greater than the maximum permitted time, then the connection manager SHOULD respond immediately to all pending requests (including the pause request) and temporarily increase the maximum inactivity period to the requested time. Note: The response to the pause request MUST NOT contain any payloads.<br />
<br />
Note: If the client simply wants the connection manager to return all the requests it is holding then it MAY set the value of the 'pause' attribute to be the value of the 'inactivity' attribute in the connection manager's session creation response. (If the client believes it is in danger of becoming disconnected indefinitely then it MAY even request a temporary reduction of the maximum inactivity period by specifying a 'pause' value less than the 'inactivity' value, thus enabling the connection manager to discover any subsequent disconnection more quickly.)<br />
<br />
The connection manager SHOULD set the maximum inactivity period back to normal upon reception of the next request from the client (assuming the connection manager has not already terminated the session).<br />
<br />
==Overactivity==<br />
<br />
The client SHOULD NOT make more simultaneous requests than specified by the 'requests' attribute in the connection manager's Session Creation Response. However the client MAY make one additional request if it is to pause or terminate a session.<br />
<br />
If during any period the client sends a sequence of new requests (i.e. requests with incremented rid attributes, not repeat requests) longer than the number specified by the 'requests' attribute, and if the connection manager has not yet responded to any of the requests, and if the last request did not include either a 'pause' attribute or a 'type' attribute set to "terminate", then the connection manager SHOULD consider that the client is making too many simultaneous requests, and terminate the HTTP session with a 'policy-violation' terminal binding error to the client. Note: This behavior applies to equally to normal and polling sessions.<br />
<br />
'''Example 12. Too many simultaneous requests response'''<br />
<source lang="xml"><br />
HTTP/1.1 200 OK<br />
Content-Type: text/xml; charset=utf-8<br />
Content-Length: 68<br />
<br />
<body type='terminate'<br />
condition='policy-violation'<br />
xmlns='http://jabber.org/protocol/httpbind'/><br />
</source><br />
<br />
Note: If the connection manager did not specify a 'requests' attribute in the session creation response, then it MUST allow the client to send as many simultaneous requests as it chooses.<br />
<br />
If during any period the client sends a sequence of new requests equal in length to the number specified by the 'requests' attribute, and if the connection manager has not yet responded to any of the requests, and if the last request was empty and did not include either a 'pause' attribute or a 'type' attribute set to "terminate", and if the last two requests arrived within a period shorter than the number of seconds specified by the 'polling' attribute in the session creation response, then the connection manager SHOULD consider that the client is making requests more frequently than it was permitted and terminate the HTTP session and return a 'policy-violation' terminal binding error to the client. Note: the behavior for Polling Sessions is slightly different.<br />
<br />
'''Example 13. Too frequent requests response'''<br />
<source lang="xml"><br />
HTTP/1.1 200 OK<br />
Content-Type: text/xml; charset=utf-8<br />
Content-Length: 68<br />
<br />
<body type='terminate'<br />
condition='policy-violation'<br />
xmlns='http://jabber.org/protocol/httpbind'/><br />
</source><br />
<br />
Note: If the connection manager did not specify a 'polling' attribute in the session creation response, then it MUST allow the client to send requests as frequently as it chooses.<br />
<br />
==Polling Sessions==<br />
<br />
It is not always possible for a constrained client to either use HTTP Pipelining or open more than one HTTP connection with the connection manager at a time. In this case the client SHOULD inform the connection manager by setting the values of the 'wait' and/or 'hold' attributes in its session creation request to "0", and then "poll" the connection manager at regular intervals throughout the session for payloads it might have received from the server. Note: Even if the client does not request a polling session, the connection manager MAY require a client to use polling by setting the 'requests' attribute (which specifies the number of simultaneous requests the client can make) of its Session Creation Response to "1", however this is NOT RECOMMENDED.<br />
<br />
If a session will use polling, the connection manager SHOULD specify a higher than normal value for the 'inactivity' attribute (see Inactivity) in its session creation response. The increase SHOULD be greater than the value it specifies for the 'polling' attribute.<br />
<br />
If the client sends two consecutive empty new requests (i.e. requests with incremented rid attributes, not repeat requests) within a period shorter than the number of seconds specified by the 'polling' attribute (the shortest allowable polling interval) in the session creation response, and if the connection manager's response to the first request contained no payloads, then upon reception of the second request the connection manager SHOULD terminate the HTTP session and return a 'policy-violation' terminal binding error to the client.<br />
<br />
'''Example 14. Too frequent polling response'''<br />
<source lang="xml"><br />
HTTP/1.1 200 OK<br />
Content-Type: text/xml; charset=utf-8<br />
Content-Length: 68<br />
<br />
<body type='terminate'<br />
condition='policy-violation'<br />
xmlns='http://jabber.org/protocol/httpbind'/><br />
</source><br />
<br />
Note: If the connection manager did not specify a 'polling' attribute in the session creation response, then it MUST allow the client to poll as frequently as it chooses.<br />
<br />
==Terminating the HTTP Session==<br />
<br />
At any time, the client MAY gracefully terminate the session by sending a <body/> element with a 'type' attribute set to "terminate". The termination request MAY include one or more payloads that the connection manager MUST forward to the server to ensure graceful logoff.<br />
<br />
'''Example 15. Session termination by client'''<br />
<source lang="xml"><br />
POST /webclient HTTP/1.1<br />
Host: httpcm.example.com<br />
Accept-Encoding: gzip, deflate<br />
Content-Type: text/xml; charset=utf-8<br />
Content-Length: 153<br />
<br />
<body rid='1249243565'<br />
sid='SomeSID'<br />
type='terminate'<br />
xmlns='http://jabber.org/protocol/httpbind'><br />
<presence type='unavailable'<br />
xmlns='jabber:client'/><br />
</body><br />
</source><br />
<br />
The connection manager SHOULD respond to this request with an HTTP 200 OK containing an empty <body/> element.<br />
<br />
'''Example 16. Connection manager acknowledges termination'''<br />
<source lang="xml"><br />
HTTP/1.1 200 OK<br />
Content-Type: text/xml; charset=utf-8<br />
Content-Length: 72<br />
<br />
<body type='terminate'<br />
xmlns='http://jabber.org/protocol/httpbind'/><br />
</source><br />
<br />
Upon receiving the response, the client MUST consider the HTTP session to have been terminated.<br />
<br />
==Request IDs==<br />
===Generation===<br />
<br />
The client MUST generate a large, random, positive integer for the initial 'rid' (see Security Considerations) and then increment that value by one for each subsequent request. The client MUST take care to choose an initial 'rid' that will never be incremented above 9007199254740991 [21] within the session. In practice, a session would have to be extraordinarily long (or involve the exchange of an extraordinary number of packets) to exceed the defined limit.<br />
===In-Order Message Forwarding===<br />
<br />
When a client makes simultaneous requests, the connection manager might receive them out of order. The connection manager MUST forward the payloads to the server and respond to the client requests in the order specified by the 'rid' attributes. The client MUST process responses received from the connection manager in the order the requests were made.<br />
<br />
The connection manager SHOULD expect the 'rid' attribute to be within a window of values greater than the 'rid' of the previous request. The size of the window is equal to the maximum number of simultaneous requests allowed by the connection manager. If it receives a request with a 'rid' greater than the values in the window, then the connection manager MUST terminate the session with an error:<br />
<br />
'''Example 17. Unexpected rid error'''<br />
<source lang="xml"><br />
HTTP/1.1 200 OK<br />
Content-Type: text/xml; charset=utf-8<br />
Content-Length: 68<br />
<br />
<body type='terminate'<br />
condition='item-not-found'<br />
xmlns='http://jabber.org/protocol/httpbind'/><br />
</source><br />
<br />
===Broken Connections===<br />
<br />
Unreliable network communications or client constraints can result in broken connections. The connection manager SHOULD remember the 'rid' and the associated HTTP response body of the client's most recent requests which were not session pause requests (see Inactivity) and which did not result in an HTTP or binding error. The number of responses to non-pause requests kept in the buffer SHOULD be either the same as the maximum number of simultaneous requests allowed by the connection manager or, if Acknowledgements are being used, the number of responses that have not yet been acknowledged.<br />
<br />
If the network connection is broken or closed before the client receives a response to a request from the connection manager, then the client MAY resend an exact copy of the original request. Whenever the connection manager receives a request with a 'rid' that it has already received, it SHOULD return an HTTP 200 (OK) response that includes the buffered copy of the original XML response to the client (i.e., a <body/> wrapper possessing appropriate attributes and optionally containing one or more XML payloads). If the original response is not available (e.g., it is no longer in the buffer), then the connection manager MUST return an 'item-not-found' terminal binding error:<br />
<br />
'''Example 18. Response not in buffer error'''<br />
<source lang="xml"><br />
HTTP/1.1 200 OK<br />
Content-Type: text/xml; charset=utf-8<br />
Content-Length: 68<br />
<br />
<body type='terminate'<br />
condition='item-not-found'<br />
xmlns='http://jabber.org/protocol/httpbind'/><br />
</source><br />
<br />
Note: The error is the same whether the 'rid' is too large or too small. This makes it more difficult for an attacker to discover an acceptable value.<br />
<br />
==Protecting Insecure Sessions==<br />
===Applicability===<br />
<br />
The OPTIONAL key sequencing mechanism described here MAY be used if the client's session with the connection manager is not secure. The session SHOULD be considered secure only if all client requests are made via SSL (or TLS) HTTP connections and the connection manager generates an unpredictable session ID. If the session is secure, it is not necessary to use this key sequencing mechanism.<br />
<br />
Even if the session is not secure, the unpredictable session and request IDs specified in the preceding sections of this document already provide a level of protection similar to that provided by a connection bound to a single pair of persistent TCP/IP connections, and thus provide sufficient protection against a 'blind' attacker. However, in some circumstances, the key sequencing mechanism defined below helps to protect against a more determined and knowledgeable attacker.<br />
<br />
It is important to recognize that the key sequencing mechanism defined below helps to protect only against an attacker who is able to view the contents of all requests or responses in an insecure session but who is not able to alter the contents of those requests (in this case, the mechanism prevents the attacker from injecting HTTP requests into the session, e.g., termination requests or responses). However, the key sequencing mechanism does not provide any protection when the attacker is able to alter the contents of insecure requests or responses.<br />
===Introduction===<br />
<br />
The HTTP requests of each session MAY be spread across a series of different socket connections. This would enable an unauthorized user that obtains the session ID and request ID of a session to then use their own socket connection to inject <body/> request elements into the session and receive the corresponding responses.<br />
<br />
The key sequencing mechanism below protects against such attacks by enabling a connection manager to detect <body/> request elements injected by a third party.<br />
===Generating the Key Sequence===<br />
<br />
Prior to requesting a new session, the client MUST select an unpredictable counter ("n") and an unpredictable value ("seed"). The client then processes the "seed" through a cryptographic hash and converts the resulting 160 bits to a hexadecimal string K(1). It does this "n" times to arrive at the initial key K(n). The hashing algorithm MUST be SHA-1 as defined in RFC 3174 [22].<br />
<br />
'''Example 19. Creating the key sequence'''<br />
<br />
K(1) = hex(SHA-1(seed))<br />
K(2) = hex(SHA-1(K(1)))<br />
...<br />
K(n) = hex(SHA-1(K(n-1)))<br />
<br />
<br />
===Use of Keys===<br />
<br />
The client MUST set the 'newkey' attribute of the first request in the session to the value K(n).<br />
<br />
'''Example 20. Session Request with Initial Key'''<br />
<source lang="xml"><br />
POST /webclient HTTP/1.1<br />
Host: httpcm.example.com<br />
Accept-Encoding: gzip, deflate<br />
Content-Type: text/xml; charset=utf-8<br />
Content-Length: 104<br />
<br />
<body content='text/xml; charset=utf-8'<br />
hold='1'<br />
rid='1573741820'<br />
to='example.com'<br />
wait='60'<br />
xml:lang='en'<br />
newkey='ca393b51b682f61f98e7877d61146407f3d0a770'<br />
xmlns='http://jabber.org/protocol/httpbind'/><br />
</source><br />
<br />
The client MUST set the 'key' attribute of all subsequent requests to the value of the next key in the generated sequence (decrementing from K(n-1) towards K(1) with each request sent).<br />
<br />
'''Example 21. Request with Key'''<br />
<source lang="xml"><br />
POST /webclient HTTP/1.1<br />
Host: httpcm.example.com<br />
Accept-Encoding: gzip, deflate<br />
Content-Type: text/xml; charset=utf-8<br />
Content-Length: 88<br />
<br />
<body rid='1573741821'<br />
sid='SomeSID'<br />
key='bfb06a6f113cd6fd3838ab9d300fdb4fe3da2f7d'<br />
xmlns='http://jabber.org/protocol/httpbind'/><br />
</source><br />
<br />
The connection manager MAY verify the key by calculating the SHA-1 hash of the key and comparing it to the 'newkey' attribute of the previous request (or the 'key' attribute if the 'newkey' attribute was not set). If the values do not match (or if it receives a request without a 'key' attribute and the 'newkey' or 'key' attribute of the previous request was set), then the connection manager MUST NOT process the element, MUST terminate the session, and MUST return an 'item-not-found' terminal binding error.<br />
<br />
'''Example 22. Invalid Key Sequence Error'''<br />
<source lang="xml"><br />
HTTP/1.1 200 OK<br />
Content-Type: text/xml; charset=utf-8<br />
Content-Length: 68<br />
<br />
<body type='terminate'<br />
condition='item-not-found'<br />
xmlns='http://jabber.org/protocol/httpbind'/><br />
</source><br />
<br />
===Switching to Another Key Sequence===<br />
<br />
A client SHOULD choose a high value for "n" when generating the key sequence. However, if the session lasts long enough that the client arrives at the last key in the sequence K(1) then the client MUST switch to a new key sequence.<br />
<br />
The client MUST:<br />
<br />
1. Choose new values for "seed" and "n".<br />
2. Generate a new key sequence using the algorithm defined above.<br />
3. Set the 'key' attribute of the request to the next value in the old sequence (i.e. K(1), the last value).<br />
4. Set the 'newkey' attribute of the request to the value K(n) from the new sequence.<br />
<br />
'''Example 23. New Key Sequence'''<br />
<source lang="xml"><br />
POST /webclient HTTP/1.1<br />
Host: httpcm.example.com<br />
Accept-Encoding: gzip, deflate<br />
Content-Type: text/xml; charset=utf-8<br />
Content-Length: 188<br />
<br />
<body rid='1573741822'<br />
sid='SomeSID'<br />
key='6f825e81f4532b2c5fa2d12457d8a1f22e8f838e'<br />
newkey='113f58a37245ec9637266cf2fb6e48bfeaf7964e'<br />
xmlns='http://jabber.org/protocol/httpbind'><br />
<message to='contact@example.com'<br />
xmlns='jabber:client'><br />
<body>I said "Hi!"</body><br />
</message><br />
</body><br />
</source><br />
<br />
==Multiple Streams==<br />
===Introduction===<br />
<br />
The OPTIONAL feature described in this section enables multiple XML streams to be contained within a single HTTP session. This feature is essential in runtime environments that prevent HTTP Pipelining, thereby constraining the number of simultaneous HTTP requests a client can make to each connection manager, since clients running in such environments need multi-stream sessions if they are to connect using more than one account at the same time. This feature also reduces network traffic for any client that needs to establish parallel streams over HTTP.<br />
===Discovery===<br />
<br />
If a connection manager supports the multi-streams feature, it MUST include a 'stream' attribute in its Session Creation Response. If a client does not receive the 'stream' attribute then it MUST assume that the connection manager does not support the feature. [23]<br />
<br />
The 'stream' attribute identifies the first stream to be opened for the session. The value of each 'stream' attribute MUST be an opaque and unpredictable name that is unique within the context of the connection manager application.<br />
<br />
'''Example 24. Session creation response with stream name'''<br />
<source lang="xml"><br />
HTTP/1.1 200 OK<br />
Content-Type: text/xml; charset=utf-8<br />
Content-Length: 128<br />
<br />
<body wait='60'<br />
inactivity='30'<br />
polling='5'<br />
requests='2'<br />
hold='1'<br />
accept='deflate,gzip'<br />
stream='firstStreamName'<br />
maxpause='120'<br />
sid='SomeSID'<br />
charsets='ISO_8859-1 ISO-2022-JP'<br />
ver='1.6'<br />
from='example.com'<br />
xmlns='http://jabber.org/protocol/httpbind'/><br />
</source><br />
<br />
===Adding Streams To A Session===<br />
<br />
If the connection manager included a 'stream' attribute in its session creation response then the client MAY ask it to open another stream at any time by sending it an empty <body/> element with a 'to' attribute. The request MUST include valid 'sid' and 'rid' [24] attributes, and SHOULD also include an 'xml:lang' attribute. The request MAY include 'route', 'from' and 'secure' attributes (see Session Creation Request), but it SHOULD NOT include 'ver', 'content', 'hold' or 'wait' attributes (since a new session is not being created).<br />
<br />
'''Example 25. Requesting another stream'''<br />
<source lang="xml"><br />
POST /webclient HTTP/1.1<br />
Host: httpcm.example.com<br />
Accept-Encoding: gzip, deflate<br />
Content-Type: text/xml; charset=utf-8<br />
Content-Length: 104<br />
<br />
<body sid='SomeSID'<br />
rid='1573741820'<br />
to='example.com'<br />
route='xmpp:example.com:9999'<br />
xml:lang='en'<br />
xmlns='http://jabber.org/protocol/httpbind'/><br />
</source><br />
<br />
If the connection manager did not indicate its support for multiple streams at the start of the session, then it MUST ignore the extra attributes and treat the request as a normal empty request for payloads (see Sending and Receiving XML Payloads). [25] Otherwise it MUST open a new stream with the specified server (see Session Creation Response), generate a new stream name, and respond to the client with the name. The response MAY also include 'from' and 'secure' attributes, but it SHOULD NOT include 'sid', 'requests', 'polling', 'hold', 'inactivity', 'maxpause', 'accept', 'charsets', 'ver' or 'wait' attributes.<br />
<br />
'''Example 26. Add stream response'''<br />
<source lang="xml"><br />
HTTP/1.1 200 OK<br />
Content-Type: text/xml; charset=utf-8<br />
Content-Length: 128<br />
<br />
<body stream='secondStreamName'<br />
from='example.com'<br />
xmlns='http://jabber.org/protocol/httpbind'/><br />
</source><br />
<br />
Note: If the response did not include either 'from' or 'secure' attributes then they MAY be sent in a subsequent response instead (see Session Creation Response). In that case the 'stream' attribute MUST also be specified.<br />
===Transmitting Payloads===<br />
<br />
If more than one stream has been opened within a session, then all non-empty <body/> elements sent by the connection manager MUST include a 'stream' attribute that specifies which stream all the payloads it contains belong to. The client SHOULD include a 'stream' attribute for the same purpose. The client MAY omit the 'stream' attribute if it wants the connection manager to broadcast the payloads over all open streams. Note: A <body/> element MUST NOT contain different payloads for different streams.<br />
<br />
If a stream name does not correspond to one of the session's open streams, then the receiving connection manager SHOULD return an 'item-not-found' terminal binding error, or the receiving client SHOULD terminate the session. However, if the receiving entity has only just closed the stream (and the sender might not have been aware of that when it sent the payloads), then it MAY instead simply silently ignore any payloads the <body/> element contains.<br />
<br />
Note: Empty <body/> elements that do not include a 'from' or 'secure' attribute SHOULD NOT include a 'stream' attribute (since nothing is being transmitted for any stream). If such a <body/> element does include a 'stream' attribute then the receiving entity SHOULD ignore the attribute.<br />
<br />
'''Example 27. Client sends payload with a stream name'''<br />
<source lang="xml"><br />
POST /webclient HTTP/1.1<br />
Host: httpcm.example.com<br />
Accept-Encoding: gzip, deflate<br />
Content-Type: text/xml; charset=utf-8<br />
Content-Length: 188<br />
<br />
<body rid='1249243562'<br />
sid='SomeSID'<br />
stream='secondStreamName'<br />
xmlns='http://jabber.org/protocol/httpbind'><br />
<message to='contact@example.com'<br />
xmlns='jabber:client'><br />
<body>I said hello.</body><br />
</message><br />
</body><br />
</source><br />
<br />
Note: The value of the 'stream' attribute of the response MAY be different than the corresponding request. [26]<br />
<br />
'''Example 28. Connection manager responds with a different stream name'''<br />
<source lang="xml"><br />
HTTP/1.1 200 OK<br />
Content-Type: text/xml; charset=utf-8<br />
Content-Length: 185<br />
<br />
<body stream='firstStreamName'<br />
xmlns='http://jabber.org/protocol/httpbind'><br />
<message from='contact@example.com'<br />
to='user@example.com'<br />
xmlns='jabber:client'><br />
<body>Hi yourself!</body><br />
</message><br />
</body><br />
</source><br />
<br />
If no stream name is specified by the connection manager then the client MUST assume the payloads are associated with the first stream (even if the first stream has been closed).<br />
<br />
If no stream name is specified by the client then the connection manager MUST broadcast the payloads over all open streams. [27]<br />
<br />
'''Example 29. Client asks for a payload to be broadcast'''<br />
<source lang="xml"><br />
POST /webclient HTTP/1.1<br />
Host: httpcm.example.com<br />
Accept-Encoding: gzip, deflate<br />
Content-Type: text/xml; charset=utf-8<br />
Content-Length: 188<br />
<br />
<body rid='1249243562'<br />
sid='SomeSID'<br />
xmlns='http://jabber.org/protocol/httpbind'><br />
<presence xmlns='jabber:client'><br />
<show>away</show><br />
</presence><br />
</body><br />
</source><br />
<br />
===Closing a Stream===<br />
<br />
If more than one stream is open within a session, the client MAY close one open stream at any time using the procedure described in the section Terminating the HTTP Session above, taking care to specify the stream name with a 'stream' attribute. If the client closes the last stream the connection manager MUST terminate the session. If the client does not specify a stream name then the connection manager MUST close all open streams (sending any payloads the terminate request contains to all streams), and terminate the session.<br />
<br />
'''Example 30. Client closes one stream'''<br />
<source lang="xml"><br />
POST /webclient HTTP/1.1<br />
Host: httpcm.example.com<br />
Accept-Encoding: gzip, deflate<br />
Content-Type: text/xml; charset=utf-8<br />
Content-Length: 153<br />
<br />
<body rid='1249243564'<br />
sid='SomeSID'<br />
stream='secondStreamName'<br />
type='terminate'<br />
xmlns='http://jabber.org/protocol/httpbind'><br />
<presence type='unavailable'<br />
xmlns='jabber:client'/><br />
</body><br />
</source><br />
<br />
===Error Conditions===<br />
<br />
If more than one stream is open within a session, the connection manager MAY include a 'stream' attribute in a fatal binding error (see Terminal Binding Conditions). If a 'stream' attribute is specified then the stream MUST be closed by both entities but the session SHOULD NOT be terminated.<br />
<br />
'''Example 31. Fatal stream error'''<br />
<source lang="xml"><br />
HTTP/1.1 200 OK<br />
Content-Type: text/xml; charset=utf-8<br />
Content-Length: 68<br />
<br />
<body type='terminate'<br />
condition='remote-connection-failed'<br />
stream='secondStreamName'<br />
xmlns='http://jabber.org/protocol/httpbind'/><br />
</source><br />
<br />
Note: If the connection manager does not include a 'stream' attribute in a fatal binding error then all the session's open streams MUST be closed by both entities and the session MUST be terminated.<br />
<br />
==Error and Status Codes==<br />
<br />
There are four types of error and status reporting in HTTP responses:<br />
<br />
'''Table 1: Error Condition Types'''<br />
{| border="1"<br />
|'''Condition Type''' <br />
|'''Description'''<br />
|-<br />
|HTTP Conditions (Deprecated) <br />
|The connection manager responds to an invalid request from a legacy client with a standard HTTP error. These are used for binding syntax errors, possible attacks, etc. Note that constrained clients are unable to differentiate between HTTP errors.<br />
|-<br />
|Terminal Binding Conditions <br />
|These error conditions can be read by constrained clients. They are used for connection manager problems, abstracting stream errors, communication problems between the connection manager and the server, and invalid client requests (binding syntax errors, possible attacks, etc.)<br />
|-<br />
|Recoverable Binding Conditions <br />
|These report communication problems between the connection manager and the client. They do not terminate the session. Clients recover from these errors by resending all the preceding <body/> wrappers that have not received responses.<br />
|-<br />
|Transported Protocol Conditions <br />
|Errors relating to the XML payloads within <body/> wrappers are, in general, defined in the documentation of the protocol being transported. They do not terminate the session.<br />
|}<br />
<br />
Full descriptions are provided below.<br />
===HTTP Conditions===<br />
<br />
Note: All HTTP codes except 200 have been superseded by Terminal Binding Conditions to allow clients to determine whether the source of errors is the connection manager application or an HTTP intermediary.<br />
<br />
A legacy client (or connection manager) is a client (or connection manager) that did not include a 'ver' attribute in its session creation request (or response). A legacy client (or connection manager) will interpret (or respond with) HTTP error codes according to the table below. Non-legacy connection managers SHOULD NOT send HTTP error codes unless they are communicating with a legacy client. Upon receiving an HTTP error (400, 403, 404), a legacy client or any client that is communicating with a legacy connection manager MUST consider the HTTP session to be null and void. A non-legacy client that is communicating with a non-legacy connection manager MAY consider that the session is still active.<br />
<br />
'''Table 2: HTTP Error and Status Codes'''<br />
{| border="1"<br />
|'''Code'''<br />
|'''Name'''<br />
|'''Superseded by''' <br />
|'''Purpose'''<br />
|-<br />
|200 <br />
|OK <br />
|<nowiki>-</nowiki><br />
|Response to valid client request.<br />
|-<br />
|400 <br />
|Bad Request <br />
|bad-request <br />
|Inform client that the format of an HTTP header or binding element is unacceptable (e.g., syntax error).<br />
|-<br />
|403<br />
|Forbidden <br />
|policy-violation <br />
|Inform client that it has broken the session rules (polling too frequently, requesting too frequently, too many simultaneous requests).<br />
|-<br />
|404 <br />
|Not Found <br />
|item-not-found <br />
|Inform client that (1) 'sid' is not valid, (2) 'stream' is not valid, (3) 'rid' is larger than the upper limit of the expected window, (4) connection manager is unable to resend response, (5) 'key' sequence is invalid.<br />
|}<br />
<br />
Note: No other HTTP error and status codes were defined in the early versions of BOSH (e.g., Internal Server Error).<br />
<br />
===Terminal Binding Conditions===<br />
<br />
In any response it sends to the client, the connection manager MAY return a fatal error by setting a 'type' attribute of the <body/> element to "terminate". These binding errors imply that the HTTP session is terminated (unless a 'stream' attribute is specified -- see Multiple Stream Error Conditions).<br />
<br />
Note: Although many of these conditions are similar to the XMPP stream error conditions specified in RFC 6120, they are not to be confused with XMPP stream errors. In cases where BOSH is being used to transport XMPP, any fatal XMPP stream error conditions experienced between the connection manager and the XMPP server SHOULD only be reported using the "remote-stream-error" condition as described below.<br />
<br />
'''Example 32. Remote connection failed error'''<br />
<source lang="xml"><br />
HTTP/1.1 200 OK<br />
Content-Type: text/xml; charset=utf-8<br />
Content-Length: 68<br />
<br />
<body type='terminate'<br />
condition='remote-connection-failed'<br />
xmlns='http://jabber.org/protocol/httpbind'/><br />
</source><br />
<br />
The following values of the 'condition' attribute are defined:<br />
<br />
'''Table 3: Terminal Binding Error Conditions'''<br />
{| border="1"<br />
|'''Condition'''<br />
|'''Purpose'''<br />
|-<br />
|bad-request* <br />
|The format of an HTTP header or binding element received from the client is unacceptable (e.g., syntax error).<br />
|-<br />
|host-gone <br />
|The target domain specified in the 'to' attribute or the target host or port specified in the 'route' attribute is no longer serviced by the connection manager.<br />
|-<br />
|host-unknown <br />
|The target domain specified in the 'to' attribute or the target host or port specified in the 'route' attribute is unknown to the connection manager.<br />
|-<br />
|improper-addressing <br />
|The initialization element lacks a 'to' or 'route' attribute (or the attribute has no value) but the connection manager requires one.<br />
|-<br />
|internal-server-error <br />
|The connection manager has experienced an internal error that prevents it from servicing the request.<br />
|-<br />
|item-not-found* <br />
|(1) 'sid' is not valid, (2) 'stream' is not valid, (3) 'rid' is larger than the upper limit of the expected window, (4) connection manager is unable to resend response, (5) 'key' sequence is invalid.<br />
|-<br />
|other-request <br />
|Another request being processed at the same time as this request caused the session to terminate.<br />
|-<br />
|policy-violation* <br />
|The client has broken the session rules (polling too frequently, requesting too frequently, sending too many simultaneous requests).<br />
|-<br />
|remote-connection-failed <br />
|The connection manager was unable to connect to, or unable to connect securely to, or has lost its connection to, the server.<br />
|-<br />
|remote-stream-error <br />
|Encapsulates an error in the protocol being transported.<br />
|-<br />
|see-other-uri <br />
|The connection manager does not operate at this URI (e.g., the connection manager accepts only SSL or TLS connections at some https: URI rather than the http: URI requested by the client). The client can try POSTing to the URI in the content of the <uri/> child element.<br />
|-<br />
|system-shutdown <br />
|The connection manager is being shut down. All active HTTP sessions are being terminated. No new sessions can be created.<br />
|-<br />
|undefined-condition <br />
|The error is not one of those defined herein; the connection manager SHOULD include application-specific information in the content of the <body/> wrapper.<br />
|}<br />
<br />
* If the client did not include a 'ver' attribute in its session creation request then the connection manager SHOULD send a deprecated HTTP Error Condition instead of this terminal binding condition. If the connection manager did not include a 'ver' attribute in its session creation response then the client SHOULD expect it to send a deprecated HTTP Error Condition instead of this terminal binding condition.<br />
<br />
The following is an example of a "see-other-uri" condition:<br />
<br />
'''Example 33. See other URI error'''<br />
<source lang="xml"><br />
HTTP/1.1 200 OK<br />
Content-Type: text/xml; charset=utf-8<br />
Content-Length: 68<br />
<br />
<body condition='see-other-uri'<br />
type='terminate'<br />
xmlns='http://jabber.org/protocol/httpbind'><br />
<uri>https://secure.jabber.org/xmppcm</uri><br />
</body><br />
</source><br />
<br />
The following is an example including a "remote-stream-error" condition:<br />
<br />
'''Example 34. Remote error'''<br />
<source lang="xml"><br />
HTTP/1.1 200 OK<br />
Content-Type: text/xml; charset=utf-8<br />
Content-Length: 68<br />
<br />
<body condition='remote-stream-error'<br />
type='terminate'<br />
xmlns='http://jabber.org/protocol/httpbind'<br />
xmlns:stream='http://etherx.jabber.org/streams'><br />
<message from='contact@example.com'<br />
to='user@example.com'<br />
xmlns='jabber:client'><br />
<body>I said "Hi!"</body><br />
</message><br />
<stream:error><br />
<xml-not-well-formed xmlns='urn:ietf:params:xml:ns:xmpp-streams'/><br />
<text xmlns='urn:ietf:params:xml:ns:xmpp-streams'<br />
xml:lang='en'><br />
Some special application diagnostic information!<br />
</text><br />
<escape-your-data xmlns='application-ns'/><br />
</stream:error><br />
</body><br />
</source><br />
<br />
Naturally, the client MAY report binding errors to the connection manager as well, although this is unlikely.<br />
===Recoverable Binding Conditions===<br />
<br />
In any response it sends to the client, the connection manager MAY return a recoverable error by setting a 'type' attribute of the <body/> element to "error". These errors do not imply that the HTTP session is terminated.<br />
<br />
If it decides to recover from the error, then the client MUST repeat the HTTP request that resulted in the error, as well as all the preceding HTTP requests that have not received responses. The content of these requests MUST be identical to the <body/> elements of the original requests. This enables the connection manager to recover a session after the previous request was lost due to a communication failure.<br />
<br />
'''Example 35. Recoverable error'''<br />
<source lang="xml"><br />
HTTP/1.1 200 OK<br />
Content-Type: text/xml; charset=utf-8<br />
Content-Length: 68<br />
<br />
<body type='error'<br />
xmlns='http://jabber.org/protocol/httpbind'/><br />
</source><br />
<br />
===XML Payload Conditions===<br />
<br />
Application-level error conditions described in the documentation of the protocol being transported are routed to the client through the connection manager. They are transparent to the connection manager, and therefore out of scope for the transport binding defined herein.<br />
<br />
==Implementation Notes==<br />
===HTTP Pipelining===<br />
<br />
Even if the client requests HTTP Pipelining and the connection manager supports it, there is no guarantee that pipelining will succeed, because it might not be supported by intermediate proxies.<br />
<br />
The best the client can do is to request the use of HTTP Pipelining by setting the 'hold' attribute to a value of "1". If HTTP Pipelining does not work (because the server returns HTTP 1.0 or connection:close), then the client SHOULD degrade gracefully by using multiple connections.<br />
<br />
==Security Considerations==<br />
===Connection Between Client and BOSH Service===<br />
<br />
All communications between a client and a BOSH service SHOULD occur over encrypted HTTP connections. Negotiation of encryption between the client and the connection manager SHOULD occur at the transport layer or the HTTP layer, not the application layer; such negotiation SHOULD follow the HTTP/SSL protocol defined in SSL [28], although MAY follow the HTTP/TLS protocol defined in RFC 2818 [29] or the TLS Within HTTP protocol defined in RFC 2817 [30].<br />
<br />
If the HTTP connection used to send the initial session request is encrypted, then all the other HTTP connections used within the session MUST also be encrypted. Furthermore, if authentication certificates are exchanged when establishing the encrypted connection that is used to send the initial session request, then the client and/or connection manager SHOULD ensure that the same authentication certificates are employed for all subsequent connections used by the session. Once such a "secure session" has been established:<br />
<br />
* If the connection manager refuses to establish an encrypted connection or offers a different certificate, then the client SHOULD close the connection and terminate the session without sending any more requests.<br />
* If the client sends a wrapper element that is part of a "secure session" over a connection that either is not encrypted or uses a different certificate, then the connection manager SHOULD simply close the connection. The connection manager SHOULD NOT terminate the session since that would facilitate denial of service attacks.<br />
<br />
===Connection Between BOSH Service and Application===<br />
<br />
A BOSH service SHOULD encrypt its connection to the backend application using appropriate technologies such as Secure Sockets Layer (SSL), Transport Layer Security (TLS), and StartTLS if supported by the backend application. Alternatively, the BOSH service can be considered secure (1) if it is running on the same physical machine as the backend application or (2) if it running on the same private network as the backend application and the administrators are sure that unknown individuals or processes do not have access to that private network.<br />
<br />
If data privacy is desired, the client SHOULD encrypt its messages using an application-specific end-to-end encryption technology, because there is no way for the client to be sure that the BOSH service encrypts its connection to the application; methods for doing so are outside the scope of this specification.<br />
===Unpredictable SID and RID===<br />
<br />
The session identifier (SID) and initial request identifier (RID) are security-critical and therefore MUST be both unpredictable and nonrepeating (see RFC 1750 [31] for recommendations regarding randomness of SIDs and initial RIDs for security purposes).<br />
===Use of SHA-1===<br />
<br />
Recent research has shown that in select cases it is possible to compromise the hashes produced by the SHA-1 hashing algorithm (see RFC 4270 [32]). However, the use to which SHA-1 is put in BOSH will likely minimize the applicability of the attacks described in the literature. Furthermore, current estimates suggest that even with the recently-discovered attack, it would still take one year of computing by a government-sized entity to produce a collision.<br />
<br />
==IANA Considerations==<br />
<br />
TCP port 5280, conventially used for communication between BOSH clients and BOSH connection mangers, is registered with the Internet Assigned Numbers Authority (IANA) [33] in its port registry at IANA Port Numbers Registry [34], with a keyword of "xmpp-bosh". (Although use of this port is OPTIONAL, it is helpful to define this port in a standardized way so that BOSH clients can contact any given XMPP service via BOSH without the need either for DNS TXT records as described in Discovering Alternative XMPP Connection Methods [35] or for more advanced methods such as U-NAPTR.<br />
<br />
==XMPP Registrar Considerations==<br />
===Protocol Namespaces===<br />
<br />
The XMPP Registrar includes 'http://jabber.org/protocol/httpbind' in its registry of protocol namespaces.<br />
<br />
==XML Schema==<br />
<source lang="xml"><br />
<?xml version='1.0' encoding='UTF-8'?><br />
<br />
<xs:schema<br />
xmlns:xs='http://www.w3.org/2001/XMLSchema'<br />
xmlns:stream='http://etherx.jabber.org/streams'<br />
targetNamespace='http://jabber.org/protocol/httpbind'<br />
xmlns='http://jabber.org/protocol/httpbind'<br />
elementFormDefault='qualified'><br />
<br />
<xs:annotation><br />
<xs:documentation><br />
The protocol documented by this schema is defined in<br />
XEP-0124: http://www.xmpp.org/extensions/xep-0124.html<br />
</xs:documentation><br />
</xs:annotation><br />
<br />
<xs:import namespace='http://www.w3.org/XML/1998/namespace'<br />
schemaLocation='http://www.w3.org/2001/03/xml.xsd'/><br />
<br />
<xs:element name='body'><br />
<xs:complexType><br />
<xs:choice><br />
<xs:element name='uri'<br />
minOccurs='0'<br />
maxOccurs='1'<br />
type='xs:string'/><br />
<xs:any namespace='##other'<br />
minOccurs='0'<br />
maxOccurs='unbounded'<br />
processContents='lax'/><br />
</xs:choice><br />
<xs:attribute name='accept' type='xs:string' use='optional'/><br />
<xs:attribute name='ack' type='xs:positiveInteger' use='optional'/><br />
<xs:attribute name='authid' type='xs:string' use='optional'/><br />
<xs:attribute name='charsets' type='xs:NMTOKENS' use='optional'/><br />
<xs:attribute name='condition' use='optional'><br />
<xs:simpleType><br />
<xs:restriction base='xs:NCName'><br />
<xs:enumeration value='bad-request'/><br />
<xs:enumeration value='host-gone'/><br />
<xs:enumeration value='host-unknown'/><br />
<xs:enumeration value='improper-addressing'/><br />
<xs:enumeration value='internal-server-error'/><br />
<xs:enumeration value='item-not-found'/><br />
<xs:enumeration value='other-request'/><br />
<xs:enumeration value='policy-violation'/><br />
<xs:enumeration value='remote-connection-failed'/><br />
<xs:enumeration value='remote-stream-error'/><br />
<xs:enumeration value='see-other-uri'/><br />
<xs:enumeration value='system-shutdown'/><br />
<xs:enumeration value='undefined-condition'/><br />
</xs:restriction><br />
</xs:simpleType><br />
</xs:attribute><br />
<xs:attribute name='content' type='xs:string' use='optional'/><br />
<xs:attribute name='from' type='xs:string' use='optional'/><br />
<xs:attribute name='hold' type='xs:unsignedByte' use='optional'/><br />
<xs:attribute name='inactivity' type='xs:unsignedShort' use='optional'/><br />
<xs:attribute name='key' type='xs:string' use='optional'/><br />
<xs:attribute name='maxpause' type='xs:unsignedShort' use='optional'/><br />
<xs:attribute name='newkey' type='xs:string' use='optional'/><br />
<xs:attribute name='pause' type='xs:unsignedShort' use='optional'/><br />
<xs:attribute name='polling' type='xs:unsignedShort' use='optional'/><br />
<xs:attribute name='report' type='xs:positiveInteger' use='optional'/><br />
<xs:attribute name='requests' type='xs:unsignedByte' use='optional'/><br />
<xs:attribute name='rid' type='xs:positiveInteger' use='optional'/><br />
<xs:attribute name='route' type='xs:string' use='optional'/><br />
<xs:attribute name='sid' type='xs:string' use='optional'/><br />
<xs:attribute name='stream' type='xs:string' use='optional'/><br />
<xs:attribute name='time' type='xs:unsignedShort' use='optional'/><br />
<xs:attribute name='to' type='xs:string' use='optional'/><br />
<xs:attribute name='type' use='optional'><br />
<xs:simpleType><br />
<xs:restriction base='xs:NCName'><br />
<xs:enumeration value='error'/><br />
<xs:enumeration value='terminate'/><br />
</xs:restriction><br />
</xs:simpleType><br />
</xs:attribute><br />
<xs:attribute name='ver' type='xs:string' use='optional'/><br />
<xs:attribute name='wait' type='xs:unsignedShort' use='optional'/><br />
<xs:attribute ref='xml:lang' use='optional'/><br />
<xs:anyAttribute namespace='##other' processContents='lax'/><br />
</xs:complexType><br />
</xs:element><br />
<br />
</xs:schema><br />
</source><br />
<br />
==Acknowledgements==<br />
<br />
Thanks to Mike Cumings, Tomas Karasek, Tobias Markmann, Chris Seymour, Safa Sofuoğlu, Stefan Strigler, Matthew Wild, Kevin Winters, and Christopher Zorn for their feedback.<br />
<br />
==Appendices==<br />
===Appendix A: Document Information===<br />
<br />
Series: XEP<br />
Number: 0124<br />
Publisher: XMPP Standards Foundation<br />
Status: Draft<br />
Type: Standards Track<br />
Version: 1.10<br />
Last Updated: 2010-07-02<br />
Approving Body: XMPP Council<br />
Dependencies: RFC 1945, RFC 2616, RFC 3174<br />
Supersedes: None<br />
Superseded By: None<br />
Short Name: bosh<br />
Schema: <http://www.xmpp.org/schemas/httpbind.xsd><br />
Source Control: HTML RSS<br />
This document in other formats: XML PDF<br />
===Appendix B: Author Information===<br />
Ian Paterson<br />
<br />
Email: ian.paterson@clientside.co.uk<br />
JabberID: ian@zoofy.com<br />
Dave Smith<br />
<br />
Email: dizzyd@jabber.org<br />
JabberID: dizzyd@jabber.org<br />
Peter Saint-Andre<br />
<br />
Email: stpeter@jabber.org<br />
JabberID: stpeter@jabber.org<br />
URI: https://stpeter.im/<br />
Jack Moffitt<br />
<br />
Email: jack@chesspark.com<br />
JabberID: jack@chesspark.com<br />
===Appendix C: Legal Notices===<br />
*Copyright<br />
:This XMPP Extension Protocol is copyright © 1999 - 2011 by the XMPP Standards Foundation (XSF).<br />
*Permissions<br />
:Permission is hereby granted, free of charge, to any person obtaining a copy of this specification (the "Specification"), to make use of the Specification without restriction, including without limitation the rights to implement the Specification in a software program, deploy the Specification in a network service, and copy, modify, merge, publish, translate, distribute, sublicense, or sell copies of the Specification, and to permit persons to whom the Specification is furnished to do so, subject to the condition that the foregoing copyright notice and this permission notice shall be included in all copies or substantial portions of the Specification. Unless separate permission is granted, modified works that are redistributed shall not contain misleading information regarding the authors, title, number, or publisher of the Specification, and shall not claim endorsement of the modified works by the authors, any organization or project to which the authors belong, or the XMPP Standards Foundation.<br />
*Disclaimer of Warranty<br />
:'''<nowiki>##</nowiki> NOTE WELL: This Specification is provided on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, express or implied, including, without limitation, any warranties or conditions of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A PARTICULAR PURPOSE. ##'''<br />
*Limitation of Liability<br />
:In no event and under no legal theory, whether in tort (including negligence), contract, or otherwise, unless required by applicable law (such as deliberate and grossly negligent acts) or agreed to in writing, shall the XMPP Standards Foundation or any author of this Specification be liable for damages, including any direct, indirect, special, incidental, or consequential damages of any character arising from, out of, or in connection with the Specification or the implementation, deployment, or other use of the Specification (including but not limited to damages for loss of goodwill, work stoppage, computer failure or malfunction, or any and all other commercial damages or losses), even if the XMPP Standards Foundation or such author has been advised of the possibility of such damages.<br />
*IPR Conformance<br />
:This XMPP Extension Protocol has been contributed in full conformance with the XSF's Intellectual Property Rights Policy (a copy of which can be found at <http://xmpp.org/extensions/ipr-policy.shtml> or obtained by writing to XMPP Standards Foundation, 1899 Wynkoop Street, Suite 600, Denver, CO 80202 USA).<br />
===Appendix D: Relation to XMPP===<br />
<br />
The Extensible Messaging and Presence Protocol (XMPP) is defined in the XMPP Core (RFC 3920) and XMPP IM (RFC 3921) specifications contributed by the XMPP Standards Foundation to the Internet Standards Process, which is managed by the Internet Engineering Task Force in accordance with RFC 2026. Any protocol defined in this document has been developed outside the Internet Standards Process and is to be understood as an extension to XMPP rather than as an evolution, development, or modification of XMPP itself.<br />
===Appendix E: Discussion Venue===<br />
<br />
The primary venue for discussion of XMPP Extension Protocols is the <standards@xmpp.org> discussion list.<br />
<br />
Discussion on other xmpp.org discussion lists might also be appropriate; see <http://xmpp.org/about/discuss.shtml> for a complete list.<br />
<br />
Given that this XMPP Extension Protocol normatively references IETF technologies, discussion on the <xsf-ietf@xmpp.org> list might also be appropriate.<br />
<br />
Errata can be sent to <editor@xmpp.org>.<br />
===Appendix F: Requirements Conformance===<br />
<br />
The following requirements keywords as used in this document are to be interpreted as described in RFC 2119: "MUST", "SHALL", "REQUIRED"; "MUST NOT", "SHALL NOT"; "SHOULD", "RECOMMENDED"; "SHOULD NOT", "NOT RECOMMENDED"; "MAY", "OPTIONAL".<br />
===Appendix G: Notes===<br />
<br />
1. RFC 793: Transmission Control Protocol <http://tools.ietf.org/html/rfc0793>.<br />
<br />
2. RFC 1945: Hypertext Transfer Protocol -- HTTP/1.0 <http://tools.ietf.org/html/rfc1945>.<br />
<br />
3. RFC 2616: Hypertext Transport Protocol -- HTTP/1.1 <http://tools.ietf.org/html/rfc2616>.<br />
<br />
4. Bayeux Protocol <http://svn.cometd.org/trunk/bayeux/bayeux.html>.<br />
<br />
5. The Web Socket Protocol <http://tools.ietf.org/html/draft-hixie-thewebsocketprotocol>.<br />
<br />
6. Reverse HTTP <http://tools.ietf.org/html/draft-lentczner-rhttp>.<br />
<br />
7. RFC 2965: HTTP State Management Mechanism <http://tools.ietf.org/html/rfc2965>.<br />
<br />
8. Requiring cookies is sub-optimal because several significant computing platforms provide only limited access to underlying HTTP requests/responses; worse, some platforms hide or remove cookie-related headers.<br />
<br />
9. XEP-0025: Jabber HTTP Polling <http://xmpp.org/extensions/xep-0025.html>.<br />
<br />
10. RFC 6120: Extensible Messaging and Presence Protocol (XMPP): Core <http://tools.ietf.org/html/rfc6120>.<br />
<br />
11. XEP-0206: XMPP Over BOSH <http://xmpp.org/extensions/xep-0206.html>.<br />
<br />
12. In order to reduce network congestion, RFC 2616 recommends that clients SHOULD NOT keep more than two HTTP connections to the same HTTP server open at the same time. Clients running in constrained enviroments typically have no choice but to abide by that recommendation.<br />
<br />
13. If there is no traffic other than the "pings" then bandwidth consumption will be double that of a TCP connection (although double nothing is still nothing). If data is sent in large packets then bandwidth consumption will be almost identical.<br />
<br />
14. Extensible Markup Language (XML) 1.0 (Fourth Edition) <http://www.w3.org/TR/REC-xml/>.<br />
<br />
15. Namespaces in XML <http://www.w3.org/TR/REC-xml-names/>.<br />
<br />
16. RFC 4627: The application/json Media Type for JavaScript Object Notation (JSON) <http://tools.ietf.org/html/rfc4627>.<br />
<br />
17. Extensible Markup Language (XML) 1.0 (Fourth Edition) <http://www.w3.org/TR/REC-xml/>.<br />
<br />
18. Although the syntax of the 'route' attribute bears a superficial resemblance to a URI or IRI, it is not a URI/IRI and MUST NOT be processed in accordance with the rules specified in RFC 3986, RFC 3987, or (for XMPP) RFC 5122.<br />
<br />
19. Each character set name (or character encoding name -- we use the terms interchangeably) SHOULD be of type NMTOKEN, where the names are separated by the white space character #x20, resulting in a tokenized attribute type of NMTOKENS (see Section 3.3.1 of XML 1.0 [20]). Strictly speaking, the Character Sets registry maintained by the Internet Assigned Numbers Authority (see <http://www.iana.org/assignments/character-sets>) allows a character set name to contain any printable US-ASCII character, which might include characters not allowed by the NMTOKEN construction of XML 1.0; however, the only existing character set name which includes such a character is "NF_Z_62-010_(1973)".<br />
<br />
20. Extensible Markup Language (XML) 1.0 (Fourth Edition) <http://www.w3.org/TR/REC-xml/>.<br />
<br />
21. 9007199254740991 is 253-1. Some weakly typed languages use IEEE Standard 754 Doubles to represent all numbers. These Doubles cannot represent integers above 253 accurately.<br />
<br />
22. RFC 3174: US Secure Hash Algorithm 1 (SHA1) <http://tools.ietf.org/html/rfc3174>.<br />
<br />
23. Therefore a client and a connection manager will be compatible even if one or the other offers no support for multi-stream sessions.<br />
<br />
24. The 'rid' attribute is always incremented normally without reference to any 'stream' attribute.<br />
<br />
25. This helps to ensure backwards-compatibility with older implementations.<br />
<br />
26. Each HTTP response MUST belong to the same session as the request that triggered it, but not necessarily to the same stream.<br />
<br />
27. The broadcast payloads can be of any type.<br />
<br />
28. SSL V3.0 <http://wp.netscape.com/eng/ssl3/draft302.txt>.<br />
<br />
29. RFC 2818: HTTP Over TLS <http://tools.ietf.org/html/rfc2818>.<br />
<br />
30. RFC 2817: Upgrading to TLS Within HTTP/1.1 <http://tools.ietf.org/html/rfc2817>.<br />
<br />
31. RFC 1750: Randomness Recommendations for Security <http://tools.ietf.org/html/rfc1750>.<br />
<br />
32. RFC 4270: Attacks on Cryptographic Hashes in Internet Protocols <http://tools.ietf.org/html/rfc4270>.<br />
<br />
33. The Internet Assigned Numbers Authority (IANA) is the central coordinator for the assignment of unique parameter values for Internet protocols, such as port numbers and URI schemes. For further information, see <http://www.iana.org/>.<br />
<br />
34. IANA registry of port numbers <http://www.iana.org/assignments/port-numbers>.<br />
<br />
35. XEP-0156: Discovering Alternative XMPP Connection Methods <http://xmpp.org/extensions/xep-0156.html>.<br />
===Appendix H: Revision History===<br />
<br />
Note: Older versions of this specification might be available at http://xmpp.org/extensions/attic/<br />
;Version 1.10 (2010-07-02)<br />
<br />
:Further clarified use of 'from' and 'to' attributes; added missing condition values to the schema.<br />
:(psa)<br />
;Version 1.9 (2009-11-06)<br />
<br />
:Added information for registration of port 5280 with IANA.<br />
:(psa)<br />
;Version 1.8 (2009-04-30)<br />
<br />
:Removed secure attribute because it did not solve the problem it was intended to solve; added security consideration regarding link between connection manager and application server; changed "stanza" to "payload" for disambiguation with XMPP; clarified design objectives and relationship to similar technologies; corrected several errors in the schema.<br />
:(psa/jm)<br />
;Version 1.7 (2008-10-29)<br />
<br />
:Moved alternative script syntax to historical specification; added implementation note about HTTP Pipelining; adjusted architectural description.<br />
:(psa)<br />
;Version 1.6 (2007-02-21)<br />
<br />
:Multiple clarifications and restructuring without changes to protocol itself; changed title to BOSH; added section that fully explains the technique underlying the protocol; separated XMPP-specific features into new XEP-0206; added optional new Script Syntax and session pauses; added Acknowledgements section; added from and ver attributes; added hold attribute to session creation response; clarified polling too-frequently error; recommended that clients use HTTP Pipelining.<br />
:(ip)<br />
;Version 1.5 (2006-04-28)<br />
<br />
:Added optional Multiple Streams section; added security considerations about encrypted HTTP connections; recommended use of SSL rather than HTTP over TLS; specified that request ID values must not exceed 9007199254740991; corrected datatypes of inactivity, polling, rid, and wait attributes in the schema; added <any/> and <anyAttribute/> elements to schema to optionally support non-XMPP XML elements and attributes; deprecated HTTP error codes in favor of new terminal binding conditions.<br />
:(ip/psa)<br />
;Version 1.4 (2005-12-14)<br />
<br />
:Modified syntax of route attribute to be proto:host:port rather than XMPP URI/IRI.<br />
:(psa)<br />
;Version 1.3 (2005-11-02)<br />
<br />
:Corrected stream:features namespace and the Recoverable Binding Conditions section; recommended that connection manager shall return secure attribute to client; recommended end-to-end encryption through proxy connection managers.<br />
:(ip)<br />
;Version 1.2 (2005-06-16)<br />
<br />
:Specified optional use of route and secure attributes in session request. Minor correction: the stream features element should be included in the response that contains the authid attribute (this is not necessarily the session creation response).<br />
:(ip)<br />
;Version 1.1 (2005-06-02)<br />
<br />
:Specified optional use of HTTP Accept-Encoding and Content-Encoding headers for compression at HTTP binding level.<br />
:(ip)<br />
;Version 1.0 (2005-03-03)<br />
<br />
:Per a vote of the Jabber Council, advanced status to Draft.<br />
:(psa)<br />
;Version 0.10 (2004-11-08)<br />
<br />
:Changed HTTP 401 errors to HTTP 404.<br />
:(ip)<br />
;Version 0.9 (2004-10-26)<br />
<br />
:Added charset attribute.<br />
:(ip/psa)<br />
;Version 0.8 (2004-10-26)<br />
<br />
:Specified that wait attribute must be included in the session creation response.<br />
:(ip)<br />
;Version 0.7 (2004-08-12)<br />
<br />
:Defined appropriate XMPP stanza error conditions.<br />
:(psa/ip)<br />
;Version 0.6 (2004-07-19)<br />
<br />
:Added xml:lang attribute to the session request; added recoverable binding error conditions.<br />
:(ip)<br />
;Version 0.5 (2004-05-07)<br />
<br />
:Protocol refactored to enable simultaneous requests (request identifier attribute, wait attribute, hold attribute, requests attribute) and recovery of broken connections; added content attribute; removed all wrapper types except 'terminate'; updated error handling; made key mechanism optional (should use SSL/TLS instead).<br />
:(ip/psa)<br />
;Version 0.4 (2004-02-23)<br />
<br />
:Fixed typos; removed "resource-constraint" binding error; added HTTP 403 error to table.<br />
:(psa/ip)<br />
;Version 0.3 (2004-02-19)<br />
<br />
:Added 'authid' attribute to enable communication of XMPP stream ID (used in digest authentication); specified that Content-Types other than "text/xml" are allowed to support older HTTP clients; specified business rule for connection manager queueing of client requests; changed <packet/> to <body/> to support older HTTP clients; changed 'to' attribute on initialization element from MAY to SHOULD; recommended inclusion of unavailable presence in termination element sent from client; described architectural assumptions; specified binding-specific error handling.<br />
:(psa/ip)<br />
;Version 0.2 (2004-01-13)<br />
<br />
:Added 'to' attribute on the initialization element; specified that 'text/html' is allowable for backwards-compatibility.<br />
:(dss/psa/ip)<br />
;Version 0.1 (2003-11-06)<br />
<br />
:Initial version.<br />
:(dss/psa)<br />
<br />
结束</div>
Snowqiang
http://wiki.jabbercn.org/XEP-0124
XEP-0124
2011-05-18T14:55:17Z
<p>Snowqiang: </p>
<hr />
<div>[[Category:XMPP扩展]]<br />
[[Category:翻译中]]<br />
<br />
'''本文的英文原文来自[http://www.xmpp.org/extensions/xep-0124.html XEP-0124]'''<br />
<br />
'''XEP-0124: Bidirectional-streams Over Synchronous HTTP (BOSH)'''<br />
<br />
摘要: This specification defines a transport protocol that emulates the semantics of a long-lived, bidirectional TCP connection between two entities (such as a client and a server) by efficiently using multiple synchronous HTTP request/response pairs without requiring the use of frequent polling or chunked responses.<br />
<br />
作者: Ian Paterson, Dave Smith, Peter Saint-Andre, Jack Moffitt<br />
<br />
版权: © 1999 - 2011 XMPP Standards Foundation. SEE LEGAL NOTICES.<br />
<br />
状态: 草案<br />
<br />
类型: 标准跟踪<br />
<br />
版本: 2.0<br />
<br />
最后更新日期: 2010-07-02<br />
<br />
NOTICE: The protocol defined herein is a Draft Standard of the XMPP Standards Foundation. Implementations are encouraged and the protocol is appropriate for deployment in production systems, but some changes to the protocol are possible before it becomes a Final Standard.<br />
<br />
==Introduction==<br />
<br />
The Transmission Control Protocol (TCP; RFC 793 [1]) is often used to establish a stream-oriented connection between two entities. Such connections can often be long-lived to enable an interactive "session" between the entities. However, sometimes the nature of the device or network can prevent an application from maintaining a long-lived TCP connection to a server or peer. In this case, it is desirable to use an alternative connection method that emulates the behavior of a long-lived TCP connection using a sequenced series of requests and responses that are exchanged over short-lived connections. The appropriate request-response semantics are widely available via the Hypertext Transfer Protocol (HTTP) as specified in RFC 1945 [2] and RFC 2616 [3].<br />
<br />
BOSH, the technology defined in this specification, essentially provides a "drop-in" alternative to a long-lived, bidirectional TCP connection. It is a mature, full-featured technology that has been widely implemented and deployed since 2004. To our knowledge it was the first of many similar technologies, which now include the Comet methodology formalized in the Bayeux Protocol [4] as well as The Web Socket Protocol [5] and Reverse HTTP [6].<br />
<br />
BOSH is designed to transport any data efficiently and with minimal latency in both directions. For applications that require both "push" and "pull" semantics, BOSH is significantly more bandwidth-efficient and responsive than most other bidirectional HTTP-based transport protocols and the techniques now commonly known as "Ajax". BOSH achieves this efficiency and low latency by using so-called "long polling" with multiple synchronous HTTP request/response pairs. Furthermore, BOSH can address the needs of constrained clients by employing fully-compliant HTTP 1.0 without the need for "cookies" (see RFC 2965 [7]) [8] or even access to HTTP headers.<br />
<br />
BOSH was originally developed in the Jabber/XMPP community as a replacement for an even earlier HTTP-based technology called Jabber HTTP Polling [9]. Although BOSH assumes that the "payload" of HTTP requests and responses will be XML, the payload formats are not limited to XMPP stanzas (see XMPP Core [10]) and could contain a mixture of elements qualified by namespaces defined by different protocols (e.g., both XMPP and JSON). This mix is necessary because some connection managers might 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 payload is qualified by the correct namespace.<br />
<br />
Note: XMPP Over BOSH [11] documents some XMPP-specific extensions of this protocol that were formerly included in this document.<br />
<br />
==Requirements==<br />
<br />
The following design requirements reflect the need to offer performance as close as possible to a standard TCP connection.<br />
<br />
1. Compatible with constrained runtime environments* (e.g., mobile and browser-based clients).<br />
2. Compatible with proxies that buffer partial HTTP responses.<br />
3. Efficient through proxies that limit the duration of HTTP responses.<br />
4. Fully compatible with HTTP/1.0.<br />
5. Compatible with restricted network connections (e.g., firewalls, proxies, and gateways).<br />
6. Fault tolerant (e.g., session recovers after an underlying TCP connection breaks at any stage during an HTTP request).<br />
7. Extensible.<br />
8. Consume significantly less bandwidth than polling-based protocols.<br />
9. Significantly more responsive (lower latency) than polling-based protocols.<br />
10. Support for polling (for clients that are limited to a single HTTP connection at a time).<br />
11. In-order delivery of data.<br />
12. Guard against unauthorized users injecting HTTP requests into a session.<br />
13. Protect against denial of service attacks.<br />
14. Multiplexing of data streams.<br />
<br />
*Note: Compatibility with constrained runtime environments implies the following restrictions:<br />
<br />
1. Clients are not required to have programmatic access to the headers of each HTTP request and response (e.g., cookies or status codes).<br />
2. The body of each HTTP request and response is parsable XML with a single root element.<br />
3. Clients can specify the Content-Type of the HTTP responses they receive.<br />
<br />
==Architectural Assumptions==<br />
<br />
This document assumes that most implementations will utilize a specialized connection manager ("CM") to handle HTTP connections rather than the native connection type for the relevant application (e.g., TCP connections in XMPP). Effectively, such a connection manager is a specialized HTTP server that translates between the HTTP requests and responses defined herein and the data streams (or API) implemented by the server with which it communicates, thus enabling a client to connect to a server via HTTP on port 80 or 443 instead of an application-specific port. We can illustrate this graphically as follows:<br />
<br />
Server<br />
|<br />
| [unwrapped data streams]<br />
|<br />
HTTP CM<br />
|<br />
| [HTTP + <body/> wrapper]<br />
|<br />
Client<br />
<br />
<br />
This specification covers communication only between a client and the connection manager. It does not cover communication between the connection manager and the server, since such communications are implementation-specific (e.g., the server might 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 might be an independent translating proxy such that the server might believe it is talking directly to the client over TCP; or the connection manager and the server might use a component protocol or an API defined by the server implementation).<br />
<br />
Furthermore, no aspect of this protocol limits its use to communication between a client and a server. For example, it could be used for communication between a server and a peer server if such communication can occur for the relevant application (e.g., in XMPP). 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 the native connection transport for the relevant application. (However, on some unreliable networks, BOSH might enable more stable communication between servers.)<br />
<br />
==The BOSH Technique==<br />
<br />
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).<br />
<br />
The technique employed by BOSH 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.<br />
<br />
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 so to make sure the client can send more data immediately if necessary. (The client SHOULD NOT open more than two HTTP connections to the connection manager at the same time, [12] so it would otherwise have to wait until the connection manager responds to one of the requests.)<br />
<br />
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 TCP 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.<br />
<br />
If there is no traffic in either direction for an agreed amount of time (typically several 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 so 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. [13]<br />
<br />
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. Thus 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. Therefore, 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 were being used.<br />
<br />
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.<br />
<br />
==HTTP Overview==<br />
<br />
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).<br />
<br />
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 permitted by RFC 1945 or RFC 2616. For example, 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 might buffer each partial HTTP request or response and only forward the full request or response once it is available.<br />
<br />
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.<br />
<br />
Requests and responses MAY include HTTP headers not specified herein. The receiver SHOULD ignore any such headers.<br />
<br />
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). However, the responses to requests that are not part of the session sent over the same connection using HTTP pipelining (or queued to be sent over the same connection) might be delayed if they were sent while a request that is part of the session is being held (since the connection manager MUST send its responses in the same order that the requests were received, and the connection manager typically delays its responses).<br />
<br />
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.<br />
<br />
==<body/> Wrapper Element==<br />
<br />
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 transferred. The <body/> element and its content together MUST conform to the specifications set out in XML 1.0 [14]. They SHOULD also conform to Namespaces in XML [15]. The content MUST NOT contain any of the following (all defined in XML 1.0):<br />
<br />
* Partial XML elements<br />
* XML comments<br />
* XML processing instructions<br />
* Internal or external DTD subsets<br />
* Internal or external entity references (with the exception of predefined entities)<br />
<br />
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 "payloads" in this document, e.g., XMPP stanzas as defined in RFC 6120 or elements containing XML character data that represents objects using the JSON data interchange format as defined in RFC 4627 [16]). Each <body/> wrapper MAY contain payloads qualified under a wide variety of different namespaces.<br />
<br />
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.<br />
<br />
==Initiating a BOSH Session==<br />
===Session Creation Request===<br />
<br />
The first request from the client to the connection manager requests a new session.<br />
<br />
The <body/> element of the first request SHOULD possess the following attributes (they SHOULD NOT be included in any other requests except as specified under Adding Streams To A Session):<br />
<br />
* '''<nowiki>'to'</nowiki>''' -- This attribute specifies the target domain of the first stream.<br />
* '''<nowiki>'xml:lang'</nowiki>''' -- This attribute (as defined in Section 2.12 of XML 1.0 [17]) specifies the default language of any human-readable XML character data sent or received during the session.<br />
* '''<nowiki>'ver'</nowiki>''' -- This attribute specifies the highest version of the BOSH protocol that the client supports. The numbering scheme is "<major>.<minor>" (where the minor number MAY be incremented higher than a single digit, so it MUST be treated as a separate integer). Note: The 'ver' attribute should not be confused with the version of any protocol being transported.<br />
* '''<nowiki>'wait'</nowiki>''' -- This attribute specifies the longest time (in seconds) that the connection manager is allowed to wait before responding to any request during the session. This enables the client to limit the delay before it discovers any network failure, and to prevent its HTTP/TCP connection from expiring due to inactivity.<br />
* '''<nowiki>'hold'</nowiki>''' -- This attribute specifies the maximum number of requests the connection manager is allowed to keep waiting at any one time during the session. If the client is not able to use HTTP Pipelining then this SHOULD be set to "1".<br />
<br />
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 both typically one or two orders of magnitude!<br />
<br />
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:example.com:9999"). [18] A connection manager that is configured to work only with a single server (or only with a defined list of domains and the associated list of hostnames and ports that are serving those domains) MAY ignore the 'route' attribute. (Note that the 'to' attribute specifies the domain being served, not the hostname of the machine that is serving the domain.)<br />
<br />
The <body/> element of the first request MAY also possess a 'from' attribute, which specifies the originator of the first stream and which enables the connection manager to forward the originating entity's identity to the application server (e.g., the JabberID of an entity that is connecting to an XMPP server; see XEP-0206).<br />
<br />
A client MAY include an 'ack' attribute (set to "1") to indicate that it will be using acknowledgements throughout the session and that the absence of an 'ack' attribute in any request is meaningful (see Acknowledgements).<br />
<br />
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".<br />
<br />
'''Example 1. Requesting a BOSH session'''<br />
<source lang="xml"><br />
POST /webclient HTTP/1.1<br />
Host: httpcm.example.com<br />
Accept-Encoding: gzip, deflate<br />
Content-Type: text/xml; charset=utf-8<br />
Content-Length: 104<br />
<br />
<body content='text/xml; charset=utf-8'<br />
from='user@example.com'<br />
hold='1'<br />
rid='1573741820'<br />
to='example.com'<br />
route='xmpp:example.com:9999'<br />
ver='1.6'<br />
wait='60'<br />
ack='1'<br />
xml:lang='en'<br />
xmlns='http://jabber.org/protocol/httpbind'/><br />
</source><br />
<br />
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.<br />
===Session Creation Response===<br />
<br />
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):<br />
<br />
* '''<nowiki>'sid'</nowiki>''' -- This attribute specifies the SID<br />
* '''<nowiki>'wait'</nowiki>''' -- This is the longest time (in seconds) that the connection manager will wait before responding to any request during the session. The time MUST be less than or equal to the value specified in the session request.<br />
<br />
The <body/> element SHOULD also include the following attributes (they SHOULD NOT be included in any other responses):<br />
<br />
* '''<nowiki>'ver'</nowiki>''' -- This attribute specifies the highest version of the BOSH protocol that the connection manager supports, or the version specified by the client in its request, whichever is lower.<br />
* '''<nowiki>'polling'</nowiki>''' -- This attribute specifies the shortest allowable polling interval (in seconds). This enables the client to not send empty request elements more often than desired (see Polling Sessions and Overactivity).<br />
* '''<nowiki>'inactivity'</nowiki>''' -- This attribute specifies the longest allowable inactivity period (in seconds). This enables the client to ensure that the periods with no requests pending are never too long (see Polling Sessions and Inactivity).<br />
* '''<nowiki>'requests'</nowiki>''' -- This attribute enables the connection manager to limit the number of simultaneous requests the client makes (see Overactivity and Polling Sessions). The RECOMMENDED values are either "2" or one more than the value of the 'hold' attribute specified in the session request.<br />
* '''<nowiki>'hold'</nowiki>''' -- This attribute informs the client about the maximum number of requests the connection manager will keep waiting at any one time during the session. This value MUST NOT be greater than the value specified by the client in the session request.<br />
* '''<nowiki>'to'</nowiki>''' -- This attribute communicates the identity of the backend server to which the client is attempting to connect.<br />
<br />
The connection manager MAY include an 'accept' attribute in the session creation response element, to specify a space-separated list of 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.<br />
<br />
A connection manager MAY include an 'ack' attribute (set to the value of the 'rid' attribute of the session creation request) to indicate that it will be using acknowledgements throughout the session and that the absence of an 'ack' attribute in any response is meaningful (see Acknowledgements).<br />
<br />
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 can request.<br />
<br />
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. [19]<br />
<br />
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 a BOSH Session), then in the same response the connection manager SHOULD also include the 'secure' attribute set to "true" or "1".<br />
<br />
'''Example 2. Session creation response'''<br />
<source lang="xml"><br />
HTTP/1.1 200 OK<br />
Content-Type: text/xml; charset=utf-8<br />
Content-Length: 128<br />
<br />
<body wait='60'<br />
inactivity='30'<br />
polling='5'<br />
requests='2'<br />
hold='1'<br />
ack='1573741820'<br />
accept='deflate,gzip'<br />
maxpause='120'<br />
sid='SomeSID'<br />
charsets='ISO_8859-1 ISO-2022-JP'<br />
ver='1.6'<br />
from='example.com'<br />
xmlns='http://jabber.org/protocol/httpbind'/><br />
</source><br />
<br />
'''Example 3. Subsequent response with 'from' and 'secure' attributes'''<br />
<source lang="xml"><br />
HTTP/1.1 200 OK<br />
Content-Type: text/xml; charset=utf-8<br />
Content-Length: 128<br />
<br />
<body from='example.com'<br />
xmlns='http://jabber.org/protocol/httpbind'/><br />
</source><br />
<br />
==Sending and Receiving XML Payloads==<br />
<br />
After the client has successfully completed all required preconditions, it can send and receive XML payloads via the HTTP binding.<br />
<br />
'''Example 4. Transmitting payloads'''<br />
<source lang="xml"><br />
POST /webclient HTTP/1.1<br />
Host: httpcm.example.com<br />
Accept-Encoding: gzip, deflate<br />
Content-Type: text/xml; charset=utf-8<br />
Content-Length: 188<br />
<br />
<body rid='1249243562'<br />
sid='SomeSID'<br />
xmlns='http://jabber.org/protocol/httpbind'><br />
<message to='contact@example.com'<br />
xmlns='jabber:client'><br />
<body>Good morning!</body><br />
</message><br />
<message to='friend@example.com'<br />
xmlns='jabber:client'><br />
<body>Hey, what&apos;s up?</body><br />
</message><br />
</body><br />
</source><br />
<br />
Upon receipt of a request, the connection manager SHOULD forward the content of the <body/> element to the server as soon as possible. In any case it MUST forward the content from different requests in the order specified by their 'rid' attributes.<br />
<br />
The connection manager MUST also return an HTTP 200 OK response with a <body/> element to the client. Note: This does not indicate that the payloads have been successfully delivered to the application server.<br />
<br />
It is RECOMMENDED that the connection manager not return an HTTP result until a payload has arrived from the application server for delivery to the client. However, the connection manager SHOULD NOT wait longer than the time specified by the client in the 'wait' attribute of its Session Creation Request, and it SHOULD NOT keep more HTTP requests waiting at a time than the number specified in the 'hold' attribute of the session creation request. In any case it MUST respond to requests in the order specified by their 'rid' attributes.<br />
<br />
If there are no payloads waiting or ready to be delivered within the waiting period, then the connection manager SHOULD include an empty <body/> element in the HTTP result:<br />
<br />
'''Example 5. Empty response'''<br />
<source lang="xml"><br />
HTTP/1.1 200 OK<br />
Content-Type: text/xml; charset=utf-8<br />
Content-Length: 64<br />
<br />
<body xmlns='http://jabber.org/protocol/httpbind'/><br />
</source><br />
<br />
If the connection manager has received one or more payloads from the application server for delivery to the client, then it SHOULD return the payloads in the body of its response as soon as possible after receiving them from the server. The example below includes payloads qualified by different namespaces:<br />
<br />
'''Example 6. Response with queued stanza'''<br />
<source lang="xml"><br />
HTTP/1.1 200 OK<br />
Content-Type: text/xml; charset=utf-8<br />
Content-Length: 185<br />
<br />
<body xmlns='http://jabber.org/protocol/httpbind'<br />
xmlns:json='http://json.org/'><br />
<message from='contact@example.com'<br />
to='user@example.com'<br />
xmlns='jabber:client'><br />
<body>Good morning to you!</body><br />
</message><br />
<message from='friend@example.com'<br />
to='user@example.com'<br />
xmlns='jabber:client'><br />
<body>Not much, how about with you?</body><br />
</message><br />
<json:json><br />
[<br />
{<br />
"precision": "zip",<br />
"Latitude": 37.7668,<br />
"Longitude": -122.3959,<br />
"Address": "",<br />
"City": "SAN FRANCISCO",<br />
"State": "CA",<br />
"Zip": "94107",<br />
"Country": "US"<br />
},<br />
{<br />
"precision": "zip",<br />
"Latitude": 37.371991,<br />
"Longitude": -122.026020,<br />
"Address": "",<br />
"City": "SUNNYVALE",<br />
"State": "CA",<br />
"Zip": "94085",<br />
"Country": "US"<br />
}<br />
]<br />
</json:json><br />
</body><br />
</source><br />
<br />
The client MAY poll the connection manager for incoming payloads by sending an empty <body/> element.<br />
<br />
'''Example 7. Requesting XML Payloads'''<br />
<source lang="xml"><br />
POST /webclient HTTP/1.1<br />
Host: httpcm.example.com<br />
Accept-Encoding: gzip, deflate<br />
Content-Type: text/xml; charset=utf-8<br />
Content-Length: 88<br />
<br />
<body rid='1249243563'<br />
sid='SomeSID'<br />
xmlns='http://jabber.org/protocol/httpbind'/><br />
</source><br />
<br />
The connection manager MUST wait and respond in the same way as it does after receiving payloads from the client.<br />
<br />
==Acknowledgements==<br />
===Request Acknowledgements===<br />
<br />
When responding to a request that it has been holding, if the connection manager finds it has already received another request with a higher 'rid' attribute (typically while it was holding the first request), then it MAY acknowledge the reception to the client. The connection manager MAY set the 'ack' attribute of any response to the value of the highest 'rid' attribute it has received in the case where it has also received all requests with lower 'rid' values.<br />
<br />
'''Example 8. Response with request acknowledgement'''<br />
<source lang="xml"><br />
HTTP/1.1 200 OK<br />
Content-Type: text/xml; charset=utf-8<br />
Content-Length: 64<br />
<br />
<body ack='1249243564'<br />
xmlns='http://jabber.org/protocol/httpbind'/><br />
</source><br />
<br />
If the connection manager will be including 'ack' attributes on responses during a session, then it MUST include an 'ack' attribute in its session creation response, and set the 'ack' attribute of responses throughout the session. The only exception is that, after its session creation response, the connection manager SHOULD NOT include an 'ack' attribute in any response if the value would be the 'rid' of the request being responded to.<br />
<br />
If the connection manager is permitted to hold more than one request at a time, then the reception of a lower-than-expected 'ack' value from the connection manager (or the unexpected abscence of an 'ack' attribute) can give the client an early warning that a network failure might have occurred (e.g., if the client believes the connection manager should have received another request by the time it responded).<br />
===Response Acknowledgements===<br />
<br />
The client MAY similarly inform the connection manager about the responses it has received by setting the 'ack' attribute of any request to the value of the highest 'rid' of a request for which it has already received a response in the case where it has also received all responses associated with lower 'rid' values. If the client will be including 'ack' attributes on requests during a session, then it MUST include an 'ack' attribute (set to '1') in its session creation request, and set the 'ack' attribute of requests throughout the session. The only exception is that, after its session creation request, the client SHOULD NOT include an 'ack' attribute in any request if it has received responses to all its previous requests.<br />
<br />
'''Example 9. Request with response acknowledgement'''<br />
<source lang="xml"><br />
POST /webclient HTTP/1.1<br />
Host: httpcm.example.com<br />
Accept-Encoding: gzip, deflate<br />
Content-Type: text/xml; charset=utf-8<br />
Content-Length: 88<br />
<br />
<body rid='1249243566'<br />
sid='SomeSID'<br />
ack='1249243564'<br />
xmlns='http://jabber.org/protocol/httpbind'/><br />
</source><br />
<br />
After receiving a request with an 'ack' value less than the 'rid' of the last request that it has already responded to, the connection manager MAY inform the client of the situation by sending its next response immediately instead of waiting until it has payloads to send to the client (e.g., if some time has passed since it responded). In this case it SHOULD include a 'report' attribute set to one greater than the 'ack' attribute it received from the client, and a 'time' attribute set to the number of milliseconds since it sent the response associated with the 'report' attribute.<br />
<br />
'''Example 10. Response with report'''<br />
<source lang="xml"><br />
HTTP/1.1 200 OK<br />
Content-Type: text/xml; charset=utf-8<br />
Content-Length: 64<br />
<br />
<body report='1249243565'<br />
time='852'<br />
xmlns='http://jabber.org/protocol/httpbind'/><br />
</source><br />
<br />
Upon reception of a response with 'report' and 'time' attributes, if the client has still not received the response associated with the request identifier specified by the 'report' attribute, then it MAY choose to resend the request associated with the missing response (see Broken Connections).<br />
<br />
==Inactivity==<br />
<br />
After receiving a response from the connection manager, if none of the client's requests are still being held by the connection manager (and if the session is not a Polling Session), the client SHOULD make a new request as soon as possible. In any case, if no requests are being held, the client MUST make a new request before the maximum inactivity period has expired. The length of this period (in seconds) is specified by the 'inactivity' attribute in the session creation response.<br />
<br />
If the connection manager has responded to all the requests it has received within a session and the time since its last response is longer than the maximum inactivity period, then it SHOULD assume the client has been disconnected and terminate the session without informing the client. If the client subsequently makes another request, then the connection manager SHOULD respond as if the session does not exist.<br />
<br />
If the connection manager did not specify a maximum inactivity period in the session creation response, then it SHOULD allow the client to be inactive for as long as it chooses.<br />
<br />
If the session is not a polling session then the connection manager SHOULD specify a relatively short inactivity period to ensure that disconnections are discovered as quickly as possible. The RECOMMENDED time would be a little more than the number of seconds for a comfortable network round trip between the connection manager and the client under difficult network conditions (since the client can be expected to make a new request immediately -- see above).<br />
<br />
If a client encounters an exceptional temporary situation during which it will be unable to send requests to the connection manager for a period of time greater than the maximum inactivity period (e.g., while a runtime environment changes from one web page to another), and if the connection manager included a 'maxpause' attribute in its Session Creation Response, then the client MAY request a temporary increase to the maximum inactivity period by including a 'pause' attribute in a request. Note: If the connection manager did not specify a 'maxpause' attribute at the start of the session then the client MUST NOT send a 'pause' attribute during the session.<br />
<br />
'''Example 11. Requesting a Session Pause'''<br />
<source lang="xml"><br />
POST /webclient HTTP/1.1<br />
Host: httpcm.example.com<br />
Accept-Encoding: gzip, deflate<br />
Content-Type: text/xml; charset=utf-8<br />
Content-Length: 98<br />
<br />
<body rid='1249243564'<br />
sid='SomeSID'<br />
pause='60'<br />
xmlns='http://jabber.org/protocol/httpbind'/><br />
</source><br />
<br />
Upon reception of a session pause request, if the requested period is not greater than the maximum permitted time, then the connection manager SHOULD respond immediately to all pending requests (including the pause request) and temporarily increase the maximum inactivity period to the requested time. Note: The response to the pause request MUST NOT contain any payloads.<br />
<br />
Note: If the client simply wants the connection manager to return all the requests it is holding then it MAY set the value of the 'pause' attribute to be the value of the 'inactivity' attribute in the connection manager's session creation response. (If the client believes it is in danger of becoming disconnected indefinitely then it MAY even request a temporary reduction of the maximum inactivity period by specifying a 'pause' value less than the 'inactivity' value, thus enabling the connection manager to discover any subsequent disconnection more quickly.)<br />
<br />
The connection manager SHOULD set the maximum inactivity period back to normal upon reception of the next request from the client (assuming the connection manager has not already terminated the session).<br />
<br />
==Overactivity==<br />
<br />
The client SHOULD NOT make more simultaneous requests than specified by the 'requests' attribute in the connection manager's Session Creation Response. However the client MAY make one additional request if it is to pause or terminate a session.<br />
<br />
If during any period the client sends a sequence of new requests (i.e. requests with incremented rid attributes, not repeat requests) longer than the number specified by the 'requests' attribute, and if the connection manager has not yet responded to any of the requests, and if the last request did not include either a 'pause' attribute or a 'type' attribute set to "terminate", then the connection manager SHOULD consider that the client is making too many simultaneous requests, and terminate the HTTP session with a 'policy-violation' terminal binding error to the client. Note: This behavior applies to equally to normal and polling sessions.<br />
<br />
'''Example 12. Too many simultaneous requests response'''<br />
<source lang="xml"><br />
HTTP/1.1 200 OK<br />
Content-Type: text/xml; charset=utf-8<br />
Content-Length: 68<br />
<br />
<body type='terminate'<br />
condition='policy-violation'<br />
xmlns='http://jabber.org/protocol/httpbind'/><br />
</source><br />
<br />
Note: If the connection manager did not specify a 'requests' attribute in the session creation response, then it MUST allow the client to send as many simultaneous requests as it chooses.<br />
<br />
If during any period the client sends a sequence of new requests equal in length to the number specified by the 'requests' attribute, and if the connection manager has not yet responded to any of the requests, and if the last request was empty and did not include either a 'pause' attribute or a 'type' attribute set to "terminate", and if the last two requests arrived within a period shorter than the number of seconds specified by the 'polling' attribute in the session creation response, then the connection manager SHOULD consider that the client is making requests more frequently than it was permitted and terminate the HTTP session and return a 'policy-violation' terminal binding error to the client. Note: the behavior for Polling Sessions is slightly different.<br />
<br />
'''Example 13. Too frequent requests response'''<br />
<source lang="xml"><br />
HTTP/1.1 200 OK<br />
Content-Type: text/xml; charset=utf-8<br />
Content-Length: 68<br />
<br />
<body type='terminate'<br />
condition='policy-violation'<br />
xmlns='http://jabber.org/protocol/httpbind'/><br />
</source><br />
<br />
Note: If the connection manager did not specify a 'polling' attribute in the session creation response, then it MUST allow the client to send requests as frequently as it chooses.<br />
<br />
==Polling Sessions==<br />
<br />
It is not always possible for a constrained client to either use HTTP Pipelining or open more than one HTTP connection with the connection manager at a time. In this case the client SHOULD inform the connection manager by setting the values of the 'wait' and/or 'hold' attributes in its session creation request to "0", and then "poll" the connection manager at regular intervals throughout the session for payloads it might have received from the server. Note: Even if the client does not request a polling session, the connection manager MAY require a client to use polling by setting the 'requests' attribute (which specifies the number of simultaneous requests the client can make) of its Session Creation Response to "1", however this is NOT RECOMMENDED.<br />
<br />
If a session will use polling, the connection manager SHOULD specify a higher than normal value for the 'inactivity' attribute (see Inactivity) in its session creation response. The increase SHOULD be greater than the value it specifies for the 'polling' attribute.<br />
<br />
If the client sends two consecutive empty new requests (i.e. requests with incremented rid attributes, not repeat requests) within a period shorter than the number of seconds specified by the 'polling' attribute (the shortest allowable polling interval) in the session creation response, and if the connection manager's response to the first request contained no payloads, then upon reception of the second request the connection manager SHOULD terminate the HTTP session and return a 'policy-violation' terminal binding error to the client.<br />
<br />
'''Example 14. Too frequent polling response'''<br />
<source lang="xml"><br />
HTTP/1.1 200 OK<br />
Content-Type: text/xml; charset=utf-8<br />
Content-Length: 68<br />
<br />
<body type='terminate'<br />
condition='policy-violation'<br />
xmlns='http://jabber.org/protocol/httpbind'/><br />
</source><br />
<br />
Note: If the connection manager did not specify a 'polling' attribute in the session creation response, then it MUST allow the client to poll as frequently as it chooses.<br />
<br />
==Terminating the HTTP Session==<br />
<br />
At any time, the client MAY gracefully terminate the session by sending a <body/> element with a 'type' attribute set to "terminate". The termination request MAY include one or more payloads that the connection manager MUST forward to the server to ensure graceful logoff.<br />
<br />
'''Example 15. Session termination by client'''<br />
<source lang="xml"><br />
POST /webclient HTTP/1.1<br />
Host: httpcm.example.com<br />
Accept-Encoding: gzip, deflate<br />
Content-Type: text/xml; charset=utf-8<br />
Content-Length: 153<br />
<br />
<body rid='1249243565'<br />
sid='SomeSID'<br />
type='terminate'<br />
xmlns='http://jabber.org/protocol/httpbind'><br />
<presence type='unavailable'<br />
xmlns='jabber:client'/><br />
</body><br />
</source><br />
<br />
The connection manager SHOULD respond to this request with an HTTP 200 OK containing an empty <body/> element.<br />
<br />
'''Example 16. Connection manager acknowledges termination'''<br />
<source lang="xml"><br />
HTTP/1.1 200 OK<br />
Content-Type: text/xml; charset=utf-8<br />
Content-Length: 72<br />
<br />
<body type='terminate'<br />
xmlns='http://jabber.org/protocol/httpbind'/><br />
</source><br />
<br />
Upon receiving the response, the client MUST consider the HTTP session to have been terminated.<br />
<br />
==Request IDs==<br />
===Generation===<br />
<br />
The client MUST generate a large, random, positive integer for the initial 'rid' (see Security Considerations) and then increment that value by one for each subsequent request. The client MUST take care to choose an initial 'rid' that will never be incremented above 9007199254740991 [21] within the session. In practice, a session would have to be extraordinarily long (or involve the exchange of an extraordinary number of packets) to exceed the defined limit.<br />
===In-Order Message Forwarding===<br />
<br />
When a client makes simultaneous requests, the connection manager might receive them out of order. The connection manager MUST forward the payloads to the server and respond to the client requests in the order specified by the 'rid' attributes. The client MUST process responses received from the connection manager in the order the requests were made.<br />
<br />
The connection manager SHOULD expect the 'rid' attribute to be within a window of values greater than the 'rid' of the previous request. The size of the window is equal to the maximum number of simultaneous requests allowed by the connection manager. If it receives a request with a 'rid' greater than the values in the window, then the connection manager MUST terminate the session with an error:<br />
<br />
'''Example 17. Unexpected rid error'''<br />
<source lang="xml"><br />
HTTP/1.1 200 OK<br />
Content-Type: text/xml; charset=utf-8<br />
Content-Length: 68<br />
<br />
<body type='terminate'<br />
condition='item-not-found'<br />
xmlns='http://jabber.org/protocol/httpbind'/><br />
</source><br />
<br />
===Broken Connections===<br />
<br />
Unreliable network communications or client constraints can result in broken connections. The connection manager SHOULD remember the 'rid' and the associated HTTP response body of the client's most recent requests which were not session pause requests (see Inactivity) and which did not result in an HTTP or binding error. The number of responses to non-pause requests kept in the buffer SHOULD be either the same as the maximum number of simultaneous requests allowed by the connection manager or, if Acknowledgements are being used, the number of responses that have not yet been acknowledged.<br />
<br />
If the network connection is broken or closed before the client receives a response to a request from the connection manager, then the client MAY resend an exact copy of the original request. Whenever the connection manager receives a request with a 'rid' that it has already received, it SHOULD return an HTTP 200 (OK) response that includes the buffered copy of the original XML response to the client (i.e., a <body/> wrapper possessing appropriate attributes and optionally containing one or more XML payloads). If the original response is not available (e.g., it is no longer in the buffer), then the connection manager MUST return an 'item-not-found' terminal binding error:<br />
<br />
'''Example 18. Response not in buffer error'''<br />
<source lang="xml"><br />
HTTP/1.1 200 OK<br />
Content-Type: text/xml; charset=utf-8<br />
Content-Length: 68<br />
<br />
<body type='terminate'<br />
condition='item-not-found'<br />
xmlns='http://jabber.org/protocol/httpbind'/><br />
</source><br />
<br />
Note: The error is the same whether the 'rid' is too large or too small. This makes it more difficult for an attacker to discover an acceptable value.<br />
<br />
==Protecting Insecure Sessions==<br />
===Applicability===<br />
<br />
The OPTIONAL key sequencing mechanism described here MAY be used if the client's session with the connection manager is not secure. The session SHOULD be considered secure only if all client requests are made via SSL (or TLS) HTTP connections and the connection manager generates an unpredictable session ID. If the session is secure, it is not necessary to use this key sequencing mechanism.<br />
<br />
Even if the session is not secure, the unpredictable session and request IDs specified in the preceding sections of this document already provide a level of protection similar to that provided by a connection bound to a single pair of persistent TCP/IP connections, and thus provide sufficient protection against a 'blind' attacker. However, in some circumstances, the key sequencing mechanism defined below helps to protect against a more determined and knowledgeable attacker.<br />
<br />
It is important to recognize that the key sequencing mechanism defined below helps to protect only against an attacker who is able to view the contents of all requests or responses in an insecure session but who is not able to alter the contents of those requests (in this case, the mechanism prevents the attacker from injecting HTTP requests into the session, e.g., termination requests or responses). However, the key sequencing mechanism does not provide any protection when the attacker is able to alter the contents of insecure requests or responses.<br />
===Introduction===<br />
<br />
The HTTP requests of each session MAY be spread across a series of different socket connections. This would enable an unauthorized user that obtains the session ID and request ID of a session to then use their own socket connection to inject <body/> request elements into the session and receive the corresponding responses.<br />
<br />
The key sequencing mechanism below protects against such attacks by enabling a connection manager to detect <body/> request elements injected by a third party.<br />
===Generating the Key Sequence===<br />
<br />
Prior to requesting a new session, the client MUST select an unpredictable counter ("n") and an unpredictable value ("seed"). The client then processes the "seed" through a cryptographic hash and converts the resulting 160 bits to a hexadecimal string K(1). It does this "n" times to arrive at the initial key K(n). The hashing algorithm MUST be SHA-1 as defined in RFC 3174 [22].<br />
<br />
'''Example 19. Creating the key sequence'''<br />
<br />
K(1) = hex(SHA-1(seed))<br />
K(2) = hex(SHA-1(K(1)))<br />
...<br />
K(n) = hex(SHA-1(K(n-1)))<br />
<br />
<br />
===Use of Keys===<br />
<br />
The client MUST set the 'newkey' attribute of the first request in the session to the value K(n).<br />
<br />
'''Example 20. Session Request with Initial Key'''<br />
<source lang="xml"><br />
POST /webclient HTTP/1.1<br />
Host: httpcm.example.com<br />
Accept-Encoding: gzip, deflate<br />
Content-Type: text/xml; charset=utf-8<br />
Content-Length: 104<br />
<br />
<body content='text/xml; charset=utf-8'<br />
hold='1'<br />
rid='1573741820'<br />
to='example.com'<br />
wait='60'<br />
xml:lang='en'<br />
newkey='ca393b51b682f61f98e7877d61146407f3d0a770'<br />
xmlns='http://jabber.org/protocol/httpbind'/><br />
</source><br />
<br />
The client MUST set the 'key' attribute of all subsequent requests to the value of the next key in the generated sequence (decrementing from K(n-1) towards K(1) with each request sent).<br />
<br />
'''Example 21. Request with Key'''<br />
<source lang="xml"><br />
POST /webclient HTTP/1.1<br />
Host: httpcm.example.com<br />
Accept-Encoding: gzip, deflate<br />
Content-Type: text/xml; charset=utf-8<br />
Content-Length: 88<br />
<br />
<body rid='1573741821'<br />
sid='SomeSID'<br />
key='bfb06a6f113cd6fd3838ab9d300fdb4fe3da2f7d'<br />
xmlns='http://jabber.org/protocol/httpbind'/><br />
</source><br />
<br />
The connection manager MAY verify the key by calculating the SHA-1 hash of the key and comparing it to the 'newkey' attribute of the previous request (or the 'key' attribute if the 'newkey' attribute was not set). If the values do not match (or if it receives a request without a 'key' attribute and the 'newkey' or 'key' attribute of the previous request was set), then the connection manager MUST NOT process the element, MUST terminate the session, and MUST return an 'item-not-found' terminal binding error.<br />
<br />
'''Example 22. Invalid Key Sequence Error'''<br />
<source lang="xml"><br />
HTTP/1.1 200 OK<br />
Content-Type: text/xml; charset=utf-8<br />
Content-Length: 68<br />
<br />
<body type='terminate'<br />
condition='item-not-found'<br />
xmlns='http://jabber.org/protocol/httpbind'/><br />
</source><br />
<br />
===Switching to Another Key Sequence===<br />
<br />
A client SHOULD choose a high value for "n" when generating the key sequence. However, if the session lasts long enough that the client arrives at the last key in the sequence K(1) then the client MUST switch to a new key sequence.<br />
<br />
The client MUST:<br />
<br />
1. Choose new values for "seed" and "n".<br />
2. Generate a new key sequence using the algorithm defined above.<br />
3. Set the 'key' attribute of the request to the next value in the old sequence (i.e. K(1), the last value).<br />
4. Set the 'newkey' attribute of the request to the value K(n) from the new sequence.<br />
<br />
'''Example 23. New Key Sequence'''<br />
<source lang="xml"><br />
POST /webclient HTTP/1.1<br />
Host: httpcm.example.com<br />
Accept-Encoding: gzip, deflate<br />
Content-Type: text/xml; charset=utf-8<br />
Content-Length: 188<br />
<br />
<body rid='1573741822'<br />
sid='SomeSID'<br />
key='6f825e81f4532b2c5fa2d12457d8a1f22e8f838e'<br />
newkey='113f58a37245ec9637266cf2fb6e48bfeaf7964e'<br />
xmlns='http://jabber.org/protocol/httpbind'><br />
<message to='contact@example.com'<br />
xmlns='jabber:client'><br />
<body>I said "Hi!"</body><br />
</message><br />
</body><br />
</source><br />
<br />
==Multiple Streams==<br />
===Introduction===<br />
<br />
The OPTIONAL feature described in this section enables multiple XML streams to be contained within a single HTTP session. This feature is essential in runtime environments that prevent HTTP Pipelining, thereby constraining the number of simultaneous HTTP requests a client can make to each connection manager, since clients running in such environments need multi-stream sessions if they are to connect using more than one account at the same time. This feature also reduces network traffic for any client that needs to establish parallel streams over HTTP.<br />
===Discovery===<br />
<br />
If a connection manager supports the multi-streams feature, it MUST include a 'stream' attribute in its Session Creation Response. If a client does not receive the 'stream' attribute then it MUST assume that the connection manager does not support the feature. [23]<br />
<br />
The 'stream' attribute identifies the first stream to be opened for the session. The value of each 'stream' attribute MUST be an opaque and unpredictable name that is unique within the context of the connection manager application.<br />
<br />
'''Example 24. Session creation response with stream name'''<br />
<source lang="xml"><br />
HTTP/1.1 200 OK<br />
Content-Type: text/xml; charset=utf-8<br />
Content-Length: 128<br />
<br />
<body wait='60'<br />
inactivity='30'<br />
polling='5'<br />
requests='2'<br />
hold='1'<br />
accept='deflate,gzip'<br />
stream='firstStreamName'<br />
maxpause='120'<br />
sid='SomeSID'<br />
charsets='ISO_8859-1 ISO-2022-JP'<br />
ver='1.6'<br />
from='example.com'<br />
xmlns='http://jabber.org/protocol/httpbind'/><br />
</source><br />
<br />
===Adding Streams To A Session===<br />
<br />
If the connection manager included a 'stream' attribute in its session creation response then the client MAY ask it to open another stream at any time by sending it an empty <body/> element with a 'to' attribute. The request MUST include valid 'sid' and 'rid' [24] attributes, and SHOULD also include an 'xml:lang' attribute. The request MAY include 'route', 'from' and 'secure' attributes (see Session Creation Request), but it SHOULD NOT include 'ver', 'content', 'hold' or 'wait' attributes (since a new session is not being created).<br />
<br />
'''Example 25. Requesting another stream'''<br />
<source lang="xml"><br />
POST /webclient HTTP/1.1<br />
Host: httpcm.example.com<br />
Accept-Encoding: gzip, deflate<br />
Content-Type: text/xml; charset=utf-8<br />
Content-Length: 104<br />
<br />
<body sid='SomeSID'<br />
rid='1573741820'<br />
to='example.com'<br />
route='xmpp:example.com:9999'<br />
xml:lang='en'<br />
xmlns='http://jabber.org/protocol/httpbind'/><br />
</source><br />
<br />
If the connection manager did not indicate its support for multiple streams at the start of the session, then it MUST ignore the extra attributes and treat the request as a normal empty request for payloads (see Sending and Receiving XML Payloads). [25] Otherwise it MUST open a new stream with the specified server (see Session Creation Response), generate a new stream name, and respond to the client with the name. The response MAY also include 'from' and 'secure' attributes, but it SHOULD NOT include 'sid', 'requests', 'polling', 'hold', 'inactivity', 'maxpause', 'accept', 'charsets', 'ver' or 'wait' attributes.<br />
<br />
'''Example 26. Add stream response'''<br />
<source lang="xml"><br />
HTTP/1.1 200 OK<br />
Content-Type: text/xml; charset=utf-8<br />
Content-Length: 128<br />
<br />
<body stream='secondStreamName'<br />
from='example.com'<br />
xmlns='http://jabber.org/protocol/httpbind'/><br />
</source><br />
<br />
Note: If the response did not include either 'from' or 'secure' attributes then they MAY be sent in a subsequent response instead (see Session Creation Response). In that case the 'stream' attribute MUST also be specified.<br />
===Transmitting Payloads===<br />
<br />
If more than one stream has been opened within a session, then all non-empty <body/> elements sent by the connection manager MUST include a 'stream' attribute that specifies which stream all the payloads it contains belong to. The client SHOULD include a 'stream' attribute for the same purpose. The client MAY omit the 'stream' attribute if it wants the connection manager to broadcast the payloads over all open streams. Note: A <body/> element MUST NOT contain different payloads for different streams.<br />
<br />
If a stream name does not correspond to one of the session's open streams, then the receiving connection manager SHOULD return an 'item-not-found' terminal binding error, or the receiving client SHOULD terminate the session. However, if the receiving entity has only just closed the stream (and the sender might not have been aware of that when it sent the payloads), then it MAY instead simply silently ignore any payloads the <body/> element contains.<br />
<br />
Note: Empty <body/> elements that do not include a 'from' or 'secure' attribute SHOULD NOT include a 'stream' attribute (since nothing is being transmitted for any stream). If such a <body/> element does include a 'stream' attribute then the receiving entity SHOULD ignore the attribute.<br />
<br />
'''Example 27. Client sends payload with a stream name'''<br />
<source lang="xml"><br />
POST /webclient HTTP/1.1<br />
Host: httpcm.example.com<br />
Accept-Encoding: gzip, deflate<br />
Content-Type: text/xml; charset=utf-8<br />
Content-Length: 188<br />
<br />
<body rid='1249243562'<br />
sid='SomeSID'<br />
stream='secondStreamName'<br />
xmlns='http://jabber.org/protocol/httpbind'><br />
<message to='contact@example.com'<br />
xmlns='jabber:client'><br />
<body>I said hello.</body><br />
</message><br />
</body><br />
</source><br />
<br />
Note: The value of the 'stream' attribute of the response MAY be different than the corresponding request. [26]<br />
<br />
'''Example 28. Connection manager responds with a different stream name'''<br />
<source lang="xml"><br />
HTTP/1.1 200 OK<br />
Content-Type: text/xml; charset=utf-8<br />
Content-Length: 185<br />
<br />
<body stream='firstStreamName'<br />
xmlns='http://jabber.org/protocol/httpbind'><br />
<message from='contact@example.com'<br />
to='user@example.com'<br />
xmlns='jabber:client'><br />
<body>Hi yourself!</body><br />
</message><br />
</body><br />
</source><br />
<br />
If no stream name is specified by the connection manager then the client MUST assume the payloads are associated with the first stream (even if the first stream has been closed).<br />
<br />
If no stream name is specified by the client then the connection manager MUST broadcast the payloads over all open streams. [27]<br />
<br />
'''Example 29. Client asks for a payload to be broadcast'''<br />
<source lang="xml"><br />
POST /webclient HTTP/1.1<br />
Host: httpcm.example.com<br />
Accept-Encoding: gzip, deflate<br />
Content-Type: text/xml; charset=utf-8<br />
Content-Length: 188<br />
<br />
<body rid='1249243562'<br />
sid='SomeSID'<br />
xmlns='http://jabber.org/protocol/httpbind'><br />
<presence xmlns='jabber:client'><br />
<show>away</show><br />
</presence><br />
</body><br />
</source><br />
<br />
===Closing a Stream===<br />
<br />
If more than one stream is open within a session, the client MAY close one open stream at any time using the procedure described in the section Terminating the HTTP Session above, taking care to specify the stream name with a 'stream' attribute. If the client closes the last stream the connection manager MUST terminate the session. If the client does not specify a stream name then the connection manager MUST close all open streams (sending any payloads the terminate request contains to all streams), and terminate the session.<br />
<br />
'''Example 30. Client closes one stream'''<br />
<source lang="xml"><br />
POST /webclient HTTP/1.1<br />
Host: httpcm.example.com<br />
Accept-Encoding: gzip, deflate<br />
Content-Type: text/xml; charset=utf-8<br />
Content-Length: 153<br />
<br />
<body rid='1249243564'<br />
sid='SomeSID'<br />
stream='secondStreamName'<br />
type='terminate'<br />
xmlns='http://jabber.org/protocol/httpbind'><br />
<presence type='unavailable'<br />
xmlns='jabber:client'/><br />
</body><br />
</source><br />
<br />
===Error Conditions===<br />
<br />
If more than one stream is open within a session, the connection manager MAY include a 'stream' attribute in a fatal binding error (see Terminal Binding Conditions). If a 'stream' attribute is specified then the stream MUST be closed by both entities but the session SHOULD NOT be terminated.<br />
<br />
'''Example 31. Fatal stream error'''<br />
<source lang="xml"><br />
HTTP/1.1 200 OK<br />
Content-Type: text/xml; charset=utf-8<br />
Content-Length: 68<br />
<br />
<body type='terminate'<br />
condition='remote-connection-failed'<br />
stream='secondStreamName'<br />
xmlns='http://jabber.org/protocol/httpbind'/><br />
</source><br />
<br />
Note: If the connection manager does not include a 'stream' attribute in a fatal binding error then all the session's open streams MUST be closed by both entities and the session MUST be terminated.<br />
<br />
==Error and Status Codes==<br />
<br />
There are four types of error and status reporting in HTTP responses:<br />
<br />
'''Table 1: Error Condition Types'''<br />
{| border="1"<br />
|'''Condition Type''' <br />
|'''Description'''<br />
|-<br />
|HTTP Conditions (Deprecated) <br />
|The connection manager responds to an invalid request from a legacy client with a standard HTTP error. These are used for binding syntax errors, possible attacks, etc. Note that constrained clients are unable to differentiate between HTTP errors.<br />
|-<br />
|Terminal Binding Conditions <br />
|These error conditions can be read by constrained clients. They are used for connection manager problems, abstracting stream errors, communication problems between the connection manager and the server, and invalid client requests (binding syntax errors, possible attacks, etc.)<br />
|-<br />
|Recoverable Binding Conditions <br />
|These report communication problems between the connection manager and the client. They do not terminate the session. Clients recover from these errors by resending all the preceding <body/> wrappers that have not received responses.<br />
|-<br />
|Transported Protocol Conditions <br />
|Errors relating to the XML payloads within <body/> wrappers are, in general, defined in the documentation of the protocol being transported. They do not terminate the session.<br />
|}<br />
<br />
Full descriptions are provided below.<br />
===HTTP Conditions===<br />
<br />
Note: All HTTP codes except 200 have been superseded by Terminal Binding Conditions to allow clients to determine whether the source of errors is the connection manager application or an HTTP intermediary.<br />
<br />
A legacy client (or connection manager) is a client (or connection manager) that did not include a 'ver' attribute in its session creation request (or response). A legacy client (or connection manager) will interpret (or respond with) HTTP error codes according to the table below. Non-legacy connection managers SHOULD NOT send HTTP error codes unless they are communicating with a legacy client. Upon receiving an HTTP error (400, 403, 404), a legacy client or any client that is communicating with a legacy connection manager MUST consider the HTTP session to be null and void. A non-legacy client that is communicating with a non-legacy connection manager MAY consider that the session is still active.<br />
<br />
'''Table 2: HTTP Error and Status Codes'''<br />
{| border="1"<br />
|'''Code'''<br />
|'''Name'''<br />
|'''Superseded by'' <br />
|'''Purpose'''<br />
|-<br />
|200 <br />
|OK <br />
|<nowiki>-</nowiki><br />
|Response to valid client request.<br />
|-<br />
|400 <br />
|Bad Request <br />
|bad-request <br />
|Inform client that the format of an HTTP header or binding element is unacceptable (e.g., syntax error).<br />
|-<br />
|403<br />
|Forbidden <br />
|policy-violation <br />
|Inform client that it has broken the session rules (polling too frequently, requesting too frequently, too many simultaneous requests).<br />
|-<br />
|404 <br />
|Not Found <br />
|item-not-found <br />
|Inform client that (1) 'sid' is not valid, (2) 'stream' is not valid, (3) 'rid' is larger than the upper limit of the expected window, (4) connection manager is unable to resend response, (5) 'key' sequence is invalid.<br />
|}<br />
<br />
Note: No other HTTP error and status codes were defined in the early versions of BOSH (e.g., Internal Server Error).<br />
===Terminal Binding Conditions===<br />
<br />
In any response it sends to the client, the connection manager MAY return a fatal error by setting a 'type' attribute of the <body/> element to "terminate". These binding errors imply that the HTTP session is terminated (unless a 'stream' attribute is specified -- see Multiple Stream Error Conditions).<br />
<br />
Note: Although many of these conditions are similar to the XMPP stream error conditions specified in RFC 6120, they are not to be confused with XMPP stream errors. In cases where BOSH is being used to transport XMPP, any fatal XMPP stream error conditions experienced between the connection manager and the XMPP server SHOULD only be reported using the "remote-stream-error" condition as described below.<br />
<br />
'''Example 32. Remote connection failed error'''<br />
<source lang="xml"><br />
HTTP/1.1 200 OK<br />
Content-Type: text/xml; charset=utf-8<br />
Content-Length: 68<br />
<br />
<body type='terminate'<br />
condition='remote-connection-failed'<br />
xmlns='http://jabber.org/protocol/httpbind'/><br />
</source><br />
<br />
The following values of the 'condition' attribute are defined:<br />
<br />
'''Table 3: Terminal Binding Error Conditions'''<br />
{| border="1"<br />
|'''Condition'''<br />
|'''Purpose'''<br />
|-<br />
|bad-request* <br />
|The format of an HTTP header or binding element received from the client is unacceptable (e.g., syntax error).<br />
|-<br />
|host-gone <br />
|The target domain specified in the 'to' attribute or the target host or port specified in the 'route' attribute is no longer serviced by the connection manager.<br />
|-<br />
|host-unknown <br />
|The target domain specified in the 'to' attribute or the target host or port specified in the 'route' attribute is unknown to the connection manager.<br />
|-<br />
|improper-addressing <br />
|The initialization element lacks a 'to' or 'route' attribute (or the attribute has no value) but the connection manager requires one.<br />
|-<br />
|internal-server-error <br />
|The connection manager has experienced an internal error that prevents it from servicing the request.<br />
|-<br />
|item-not-found* <br />
|(1) 'sid' is not valid, (2) 'stream' is not valid, (3) 'rid' is larger than the upper limit of the expected window, (4) connection manager is unable to resend response, (5) 'key' sequence is invalid.<br />
|-<br />
|other-request <br />
|Another request being processed at the same time as this request caused the session to terminate.<br />
|-<br />
|policy-violation* <br />
|The client has broken the session rules (polling too frequently, requesting too frequently, sending too many simultaneous requests).<br />
|-<br />
|remote-connection-failed <br />
|The connection manager was unable to connect to, or unable to connect securely to, or has lost its connection to, the server.<br />
|-<br />
|remote-stream-error <br />
|Encapsulates an error in the protocol being transported.<br />
|-<br />
|see-other-uri <br />
|The connection manager does not operate at this URI (e.g., the connection manager accepts only SSL or TLS connections at some https: URI rather than the http: URI requested by the client). The client can try POSTing to the URI in the content of the <uri/> child element.<br />
|-<br />
|system-shutdown <br />
|The connection manager is being shut down. All active HTTP sessions are being terminated. No new sessions can be created.<br />
|-<br />
|undefined-condition <br />
|The error is not one of those defined herein; the connection manager SHOULD include application-specific information in the content of the <body/> wrapper.<br />
|}<br />
<br />
* If the client did not include a 'ver' attribute in its session creation request then the connection manager SHOULD send a deprecated HTTP Error Condition instead of this terminal binding condition. If the connection manager did not include a 'ver' attribute in its session creation response then the client SHOULD expect it to send a deprecated HTTP Error Condition instead of this terminal binding condition.<br />
<br />
The following is an example of a "see-other-uri" condition:<br />
<br />
'''Example 33. See other URI error'''<br />
<source lang="xml"><br />
HTTP/1.1 200 OK<br />
Content-Type: text/xml; charset=utf-8<br />
Content-Length: 68<br />
<br />
<body condition='see-other-uri'<br />
type='terminate'<br />
xmlns='http://jabber.org/protocol/httpbind'><br />
<uri>https://secure.jabber.org/xmppcm</uri><br />
</body><br />
</source><br />
<br />
The following is an example including a "remote-stream-error" condition:<br />
<br />
'''Example 34. Remote error'''<br />
<source lang="xml"><br />
HTTP/1.1 200 OK<br />
Content-Type: text/xml; charset=utf-8<br />
Content-Length: 68<br />
<br />
<body condition='remote-stream-error'<br />
type='terminate'<br />
xmlns='http://jabber.org/protocol/httpbind'<br />
xmlns:stream='http://etherx.jabber.org/streams'><br />
<message from='contact@example.com'<br />
to='user@example.com'<br />
xmlns='jabber:client'><br />
<body>I said "Hi!"</body><br />
</message><br />
<stream:error><br />
<xml-not-well-formed xmlns='urn:ietf:params:xml:ns:xmpp-streams'/><br />
<text xmlns='urn:ietf:params:xml:ns:xmpp-streams'<br />
xml:lang='en'><br />
Some special application diagnostic information!<br />
</text><br />
<escape-your-data xmlns='application-ns'/><br />
</stream:error><br />
</body><br />
</source><br />
<br />
Naturally, the client MAY report binding errors to the connection manager as well, although this is unlikely.<br />
===Recoverable Binding Conditions===<br />
<br />
In any response it sends to the client, the connection manager MAY return a recoverable error by setting a 'type' attribute of the <body/> element to "error". These errors do not imply that the HTTP session is terminated.<br />
<br />
If it decides to recover from the error, then the client MUST repeat the HTTP request that resulted in the error, as well as all the preceding HTTP requests that have not received responses. The content of these requests MUST be identical to the <body/> elements of the original requests. This enables the connection manager to recover a session after the previous request was lost due to a communication failure.<br />
<br />
'''Example 35. Recoverable error'''<br />
<source lang="xml"><br />
HTTP/1.1 200 OK<br />
Content-Type: text/xml; charset=utf-8<br />
Content-Length: 68<br />
<br />
<body type='error'<br />
xmlns='http://jabber.org/protocol/httpbind'/><br />
</source><br />
<br />
===XML Payload Conditions===<br />
<br />
Application-level error conditions described in the documentation of the protocol being transported are routed to the client through the connection manager. They are transparent to the connection manager, and therefore out of scope for the transport binding defined herein.<br />
<br />
==Implementation Notes==<br />
===HTTP Pipelining===<br />
<br />
Even if the client requests HTTP Pipelining and the connection manager supports it, there is no guarantee that pipelining will succeed, because it might not be supported by intermediate proxies.<br />
<br />
The best the client can do is to request the use of HTTP Pipelining by setting the 'hold' attribute to a value of "1". If HTTP Pipelining does not work (because the server returns HTTP 1.0 or connection:close), then the client SHOULD degrade gracefully by using multiple connections.<br />
<br />
==Security Considerations==<br />
===Connection Between Client and BOSH Service===<br />
<br />
All communications between a client and a BOSH service SHOULD occur over encrypted HTTP connections. Negotiation of encryption between the client and the connection manager SHOULD occur at the transport layer or the HTTP layer, not the application layer; such negotiation SHOULD follow the HTTP/SSL protocol defined in SSL [28], although MAY follow the HTTP/TLS protocol defined in RFC 2818 [29] or the TLS Within HTTP protocol defined in RFC 2817 [30].<br />
<br />
If the HTTP connection used to send the initial session request is encrypted, then all the other HTTP connections used within the session MUST also be encrypted. Furthermore, if authentication certificates are exchanged when establishing the encrypted connection that is used to send the initial session request, then the client and/or connection manager SHOULD ensure that the same authentication certificates are employed for all subsequent connections used by the session. Once such a "secure session" has been established:<br />
<br />
* If the connection manager refuses to establish an encrypted connection or offers a different certificate, then the client SHOULD close the connection and terminate the session without sending any more requests.<br />
* If the client sends a wrapper element that is part of a "secure session" over a connection that either is not encrypted or uses a different certificate, then the connection manager SHOULD simply close the connection. The connection manager SHOULD NOT terminate the session since that would facilitate denial of service attacks.<br />
<br />
===Connection Between BOSH Service and Application===<br />
<br />
A BOSH service SHOULD encrypt its connection to the backend application using appropriate technologies such as Secure Sockets Layer (SSL), Transport Layer Security (TLS), and StartTLS if supported by the backend application. Alternatively, the BOSH service can be considered secure (1) if it is running on the same physical machine as the backend application or (2) if it running on the same private network as the backend application and the administrators are sure that unknown individuals or processes do not have access to that private network.<br />
<br />
If data privacy is desired, the client SHOULD encrypt its messages using an application-specific end-to-end encryption technology, because there is no way for the client to be sure that the BOSH service encrypts its connection to the application; methods for doing so are outside the scope of this specification.<br />
===Unpredictable SID and RID===<br />
<br />
The session identifier (SID) and initial request identifier (RID) are security-critical and therefore MUST be both unpredictable and nonrepeating (see RFC 1750 [31] for recommendations regarding randomness of SIDs and initial RIDs for security purposes).<br />
===Use of SHA-1===<br />
<br />
Recent research has shown that in select cases it is possible to compromise the hashes produced by the SHA-1 hashing algorithm (see RFC 4270 [32]). However, the use to which SHA-1 is put in BOSH will likely minimize the applicability of the attacks described in the literature. Furthermore, current estimates suggest that even with the recently-discovered attack, it would still take one year of computing by a government-sized entity to produce a collision.<br />
<br />
==IANA Considerations==<br />
<br />
TCP port 5280, conventially used for communication between BOSH clients and BOSH connection mangers, is registered with the Internet Assigned Numbers Authority (IANA) [33] in its port registry at IANA Port Numbers Registry [34], with a keyword of "xmpp-bosh". (Although use of this port is OPTIONAL, it is helpful to define this port in a standardized way so that BOSH clients can contact any given XMPP service via BOSH without the need either for DNS TXT records as described in Discovering Alternative XMPP Connection Methods [35] or for more advanced methods such as U-NAPTR.<br />
<br />
==XMPP Registrar Considerations==<br />
===Protocol Namespaces===<br />
<br />
The XMPP Registrar includes 'http://jabber.org/protocol/httpbind' in its registry of protocol namespaces.<br />
<br />
==XML Schema==<br />
<source lang="xml"><br />
<?xml version='1.0' encoding='UTF-8'?><br />
<br />
<xs:schema<br />
xmlns:xs='http://www.w3.org/2001/XMLSchema'<br />
xmlns:stream='http://etherx.jabber.org/streams'<br />
targetNamespace='http://jabber.org/protocol/httpbind'<br />
xmlns='http://jabber.org/protocol/httpbind'<br />
elementFormDefault='qualified'><br />
<br />
<xs:annotation><br />
<xs:documentation><br />
The protocol documented by this schema is defined in<br />
XEP-0124: http://www.xmpp.org/extensions/xep-0124.html<br />
</xs:documentation><br />
</xs:annotation><br />
<br />
<xs:import namespace='http://www.w3.org/XML/1998/namespace'<br />
schemaLocation='http://www.w3.org/2001/03/xml.xsd'/><br />
<br />
<xs:element name='body'><br />
<xs:complexType><br />
<xs:choice><br />
<xs:element name='uri'<br />
minOccurs='0'<br />
maxOccurs='1'<br />
type='xs:string'/><br />
<xs:any namespace='##other'<br />
minOccurs='0'<br />
maxOccurs='unbounded'<br />
processContents='lax'/><br />
</xs:choice><br />
<xs:attribute name='accept' type='xs:string' use='optional'/><br />
<xs:attribute name='ack' type='xs:positiveInteger' use='optional'/><br />
<xs:attribute name='authid' type='xs:string' use='optional'/><br />
<xs:attribute name='charsets' type='xs:NMTOKENS' use='optional'/><br />
<xs:attribute name='condition' use='optional'><br />
<xs:simpleType><br />
<xs:restriction base='xs:NCName'><br />
<xs:enumeration value='bad-request'/><br />
<xs:enumeration value='host-gone'/><br />
<xs:enumeration value='host-unknown'/><br />
<xs:enumeration value='improper-addressing'/><br />
<xs:enumeration value='internal-server-error'/><br />
<xs:enumeration value='item-not-found'/><br />
<xs:enumeration value='other-request'/><br />
<xs:enumeration value='policy-violation'/><br />
<xs:enumeration value='remote-connection-failed'/><br />
<xs:enumeration value='remote-stream-error'/><br />
<xs:enumeration value='see-other-uri'/><br />
<xs:enumeration value='system-shutdown'/><br />
<xs:enumeration value='undefined-condition'/><br />
</xs:restriction><br />
</xs:simpleType><br />
</xs:attribute><br />
<xs:attribute name='content' type='xs:string' use='optional'/><br />
<xs:attribute name='from' type='xs:string' use='optional'/><br />
<xs:attribute name='hold' type='xs:unsignedByte' use='optional'/><br />
<xs:attribute name='inactivity' type='xs:unsignedShort' use='optional'/><br />
<xs:attribute name='key' type='xs:string' use='optional'/><br />
<xs:attribute name='maxpause' type='xs:unsignedShort' use='optional'/><br />
<xs:attribute name='newkey' type='xs:string' use='optional'/><br />
<xs:attribute name='pause' type='xs:unsignedShort' use='optional'/><br />
<xs:attribute name='polling' type='xs:unsignedShort' use='optional'/><br />
<xs:attribute name='report' type='xs:positiveInteger' use='optional'/><br />
<xs:attribute name='requests' type='xs:unsignedByte' use='optional'/><br />
<xs:attribute name='rid' type='xs:positiveInteger' use='optional'/><br />
<xs:attribute name='route' type='xs:string' use='optional'/><br />
<xs:attribute name='sid' type='xs:string' use='optional'/><br />
<xs:attribute name='stream' type='xs:string' use='optional'/><br />
<xs:attribute name='time' type='xs:unsignedShort' use='optional'/><br />
<xs:attribute name='to' type='xs:string' use='optional'/><br />
<xs:attribute name='type' use='optional'><br />
<xs:simpleType><br />
<xs:restriction base='xs:NCName'><br />
<xs:enumeration value='error'/><br />
<xs:enumeration value='terminate'/><br />
</xs:restriction><br />
</xs:simpleType><br />
</xs:attribute><br />
<xs:attribute name='ver' type='xs:string' use='optional'/><br />
<xs:attribute name='wait' type='xs:unsignedShort' use='optional'/><br />
<xs:attribute ref='xml:lang' use='optional'/><br />
<xs:anyAttribute namespace='##other' processContents='lax'/><br />
</xs:complexType><br />
</xs:element><br />
<br />
</xs:schema><br />
</source><br />
<br />
==Acknowledgements==<br />
<br />
Thanks to Mike Cumings, Tomas Karasek, Tobias Markmann, Chris Seymour, Safa Sofuoğlu, Stefan Strigler, Matthew Wild, Kevin Winters, and Christopher Zorn for their feedback.<br />
<br />
==Appendices==<br />
===Appendix A: Document Information===<br />
<br />
Series: XEP<br />
Number: 0124<br />
Publisher: XMPP Standards Foundation<br />
Status: Draft<br />
Type: Standards Track<br />
Version: 1.10<br />
Last Updated: 2010-07-02<br />
Approving Body: XMPP Council<br />
Dependencies: RFC 1945, RFC 2616, RFC 3174<br />
Supersedes: None<br />
Superseded By: None<br />
Short Name: bosh<br />
Schema: <http://www.xmpp.org/schemas/httpbind.xsd><br />
Source Control: HTML RSS<br />
This document in other formats: XML PDF<br />
===Appendix B: Author Information===<br />
Ian Paterson<br />
<br />
Email: ian.paterson@clientside.co.uk<br />
JabberID: ian@zoofy.com<br />
Dave Smith<br />
<br />
Email: dizzyd@jabber.org<br />
JabberID: dizzyd@jabber.org<br />
Peter Saint-Andre<br />
<br />
Email: stpeter@jabber.org<br />
JabberID: stpeter@jabber.org<br />
URI: https://stpeter.im/<br />
Jack Moffitt<br />
<br />
Email: jack@chesspark.com<br />
JabberID: jack@chesspark.com<br />
===Appendix C: Legal Notices===<br />
*Copyright<br />
:This XMPP Extension Protocol is copyright © 1999 - 2011 by the XMPP Standards Foundation (XSF).<br />
*Permissions<br />
:Permission is hereby granted, free of charge, to any person obtaining a copy of this specification (the "Specification"), to make use of the Specification without restriction, including without limitation the rights to implement the Specification in a software program, deploy the Specification in a network service, and copy, modify, merge, publish, translate, distribute, sublicense, or sell copies of the Specification, and to permit persons to whom the Specification is furnished to do so, subject to the condition that the foregoing copyright notice and this permission notice shall be included in all copies or substantial portions of the Specification. Unless separate permission is granted, modified works that are redistributed shall not contain misleading information regarding the authors, title, number, or publisher of the Specification, and shall not claim endorsement of the modified works by the authors, any organization or project to which the authors belong, or the XMPP Standards Foundation.<br />
*Disclaimer of Warranty<br />
:'''<nowiki>##</nowiki> NOTE WELL: This Specification is provided on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, express or implied, including, without limitation, any warranties or conditions of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A PARTICULAR PURPOSE. ##'''<br />
*Limitation of Liability<br />
:In no event and under no legal theory, whether in tort (including negligence), contract, or otherwise, unless required by applicable law (such as deliberate and grossly negligent acts) or agreed to in writing, shall the XMPP Standards Foundation or any author of this Specification be liable for damages, including any direct, indirect, special, incidental, or consequential damages of any character arising from, out of, or in connection with the Specification or the implementation, deployment, or other use of the Specification (including but not limited to damages for loss of goodwill, work stoppage, computer failure or malfunction, or any and all other commercial damages or losses), even if the XMPP Standards Foundation or such author has been advised of the possibility of such damages.<br />
*IPR Conformance<br />
:This XMPP Extension Protocol has been contributed in full conformance with the XSF's Intellectual Property Rights Policy (a copy of which can be found at <http://xmpp.org/extensions/ipr-policy.shtml> or obtained by writing to XMPP Standards Foundation, 1899 Wynkoop Street, Suite 600, Denver, CO 80202 USA).<br />
===Appendix D: Relation to XMPP===<br />
<br />
The Extensible Messaging and Presence Protocol (XMPP) is defined in the XMPP Core (RFC 3920) and XMPP IM (RFC 3921) specifications contributed by the XMPP Standards Foundation to the Internet Standards Process, which is managed by the Internet Engineering Task Force in accordance with RFC 2026. Any protocol defined in this document has been developed outside the Internet Standards Process and is to be understood as an extension to XMPP rather than as an evolution, development, or modification of XMPP itself.<br />
===Appendix E: Discussion Venue===<br />
<br />
The primary venue for discussion of XMPP Extension Protocols is the <standards@xmpp.org> discussion list.<br />
<br />
Discussion on other xmpp.org discussion lists might also be appropriate; see <http://xmpp.org/about/discuss.shtml> for a complete list.<br />
<br />
Given that this XMPP Extension Protocol normatively references IETF technologies, discussion on the <xsf-ietf@xmpp.org> list might also be appropriate.<br />
<br />
Errata can be sent to <editor@xmpp.org>.<br />
===Appendix F: Requirements Conformance===<br />
<br />
The following requirements keywords as used in this document are to be interpreted as described in RFC 2119: "MUST", "SHALL", "REQUIRED"; "MUST NOT", "SHALL NOT"; "SHOULD", "RECOMMENDED"; "SHOULD NOT", "NOT RECOMMENDED"; "MAY", "OPTIONAL".<br />
===Appendix G: Notes===<br />
<br />
1. RFC 793: Transmission Control Protocol <http://tools.ietf.org/html/rfc0793>.<br />
<br />
2. RFC 1945: Hypertext Transfer Protocol -- HTTP/1.0 <http://tools.ietf.org/html/rfc1945>.<br />
<br />
3. RFC 2616: Hypertext Transport Protocol -- HTTP/1.1 <http://tools.ietf.org/html/rfc2616>.<br />
<br />
4. Bayeux Protocol <http://svn.cometd.org/trunk/bayeux/bayeux.html>.<br />
<br />
5. The Web Socket Protocol <http://tools.ietf.org/html/draft-hixie-thewebsocketprotocol>.<br />
<br />
6. Reverse HTTP <http://tools.ietf.org/html/draft-lentczner-rhttp>.<br />
<br />
7. RFC 2965: HTTP State Management Mechanism <http://tools.ietf.org/html/rfc2965>.<br />
<br />
8. Requiring cookies is sub-optimal because several significant computing platforms provide only limited access to underlying HTTP requests/responses; worse, some platforms hide or remove cookie-related headers.<br />
<br />
9. XEP-0025: Jabber HTTP Polling <http://xmpp.org/extensions/xep-0025.html>.<br />
<br />
10. RFC 6120: Extensible Messaging and Presence Protocol (XMPP): Core <http://tools.ietf.org/html/rfc6120>.<br />
<br />
11. XEP-0206: XMPP Over BOSH <http://xmpp.org/extensions/xep-0206.html>.<br />
<br />
12. In order to reduce network congestion, RFC 2616 recommends that clients SHOULD NOT keep more than two HTTP connections to the same HTTP server open at the same time. Clients running in constrained enviroments typically have no choice but to abide by that recommendation.<br />
<br />
13. If there is no traffic other than the "pings" then bandwidth consumption will be double that of a TCP connection (although double nothing is still nothing). If data is sent in large packets then bandwidth consumption will be almost identical.<br />
<br />
14. Extensible Markup Language (XML) 1.0 (Fourth Edition) <http://www.w3.org/TR/REC-xml/>.<br />
<br />
15. Namespaces in XML <http://www.w3.org/TR/REC-xml-names/>.<br />
<br />
16. RFC 4627: The application/json Media Type for JavaScript Object Notation (JSON) <http://tools.ietf.org/html/rfc4627>.<br />
<br />
17. Extensible Markup Language (XML) 1.0 (Fourth Edition) <http://www.w3.org/TR/REC-xml/>.<br />
<br />
18. Although the syntax of the 'route' attribute bears a superficial resemblance to a URI or IRI, it is not a URI/IRI and MUST NOT be processed in accordance with the rules specified in RFC 3986, RFC 3987, or (for XMPP) RFC 5122.<br />
<br />
19. Each character set name (or character encoding name -- we use the terms interchangeably) SHOULD be of type NMTOKEN, where the names are separated by the white space character #x20, resulting in a tokenized attribute type of NMTOKENS (see Section 3.3.1 of XML 1.0 [20]). Strictly speaking, the Character Sets registry maintained by the Internet Assigned Numbers Authority (see <http://www.iana.org/assignments/character-sets>) allows a character set name to contain any printable US-ASCII character, which might include characters not allowed by the NMTOKEN construction of XML 1.0; however, the only existing character set name which includes such a character is "NF_Z_62-010_(1973)".<br />
<br />
20. Extensible Markup Language (XML) 1.0 (Fourth Edition) <http://www.w3.org/TR/REC-xml/>.<br />
<br />
21. 9007199254740991 is 253-1. Some weakly typed languages use IEEE Standard 754 Doubles to represent all numbers. These Doubles cannot represent integers above 253 accurately.<br />
<br />
22. RFC 3174: US Secure Hash Algorithm 1 (SHA1) <http://tools.ietf.org/html/rfc3174>.<br />
<br />
23. Therefore a client and a connection manager will be compatible even if one or the other offers no support for multi-stream sessions.<br />
<br />
24. The 'rid' attribute is always incremented normally without reference to any 'stream' attribute.<br />
<br />
25. This helps to ensure backwards-compatibility with older implementations.<br />
<br />
26. Each HTTP response MUST belong to the same session as the request that triggered it, but not necessarily to the same stream.<br />
<br />
27. The broadcast payloads can be of any type.<br />
<br />
28. SSL V3.0 <http://wp.netscape.com/eng/ssl3/draft302.txt>.<br />
<br />
29. RFC 2818: HTTP Over TLS <http://tools.ietf.org/html/rfc2818>.<br />
<br />
30. RFC 2817: Upgrading to TLS Within HTTP/1.1 <http://tools.ietf.org/html/rfc2817>.<br />
<br />
31. RFC 1750: Randomness Recommendations for Security <http://tools.ietf.org/html/rfc1750>.<br />
<br />
32. RFC 4270: Attacks on Cryptographic Hashes in Internet Protocols <http://tools.ietf.org/html/rfc4270>.<br />
<br />
33. The Internet Assigned Numbers Authority (IANA) is the central coordinator for the assignment of unique parameter values for Internet protocols, such as port numbers and URI schemes. For further information, see <http://www.iana.org/>.<br />
<br />
34. IANA registry of port numbers <http://www.iana.org/assignments/port-numbers>.<br />
<br />
35. XEP-0156: Discovering Alternative XMPP Connection Methods <http://xmpp.org/extensions/xep-0156.html>.<br />
===Appendix H: Revision History===<br />
<br />
Note: Older versions of this specification might be available at http://xmpp.org/extensions/attic/<br />
;Version 1.10 (2010-07-02)<br />
<br />
:Further clarified use of 'from' and 'to' attributes; added missing condition values to the schema.<br />
:(psa)<br />
;Version 1.9 (2009-11-06)<br />
<br />
:Added information for registration of port 5280 with IANA.<br />
:(psa)<br />
;Version 1.8 (2009-04-30)<br />
<br />
:Removed secure attribute because it did not solve the problem it was intended to solve; added security consideration regarding link between connection manager and application server; changed "stanza" to "payload" for disambiguation with XMPP; clarified design objectives and relationship to similar technologies; corrected several errors in the schema.<br />
:(psa/jm)<br />
;Version 1.7 (2008-10-29)<br />
<br />
:Moved alternative script syntax to historical specification; added implementation note about HTTP Pipelining; adjusted architectural description.<br />
:(psa)<br />
;Version 1.6 (2007-02-21)<br />
<br />
:Multiple clarifications and restructuring without changes to protocol itself; changed title to BOSH; added section that fully explains the technique underlying the protocol; separated XMPP-specific features into new XEP-0206; added optional new Script Syntax and session pauses; added Acknowledgements section; added from and ver attributes; added hold attribute to session creation response; clarified polling too-frequently error; recommended that clients use HTTP Pipelining.<br />
:(ip)<br />
;Version 1.5 (2006-04-28)<br />
<br />
:Added optional Multiple Streams section; added security considerations about encrypted HTTP connections; recommended use of SSL rather than HTTP over TLS; specified that request ID values must not exceed 9007199254740991; corrected datatypes of inactivity, polling, rid, and wait attributes in the schema; added <any/> and <anyAttribute/> elements to schema to optionally support non-XMPP XML elements and attributes; deprecated HTTP error codes in favor of new terminal binding conditions.<br />
:(ip/psa)<br />
;Version 1.4 (2005-12-14)<br />
<br />
:Modified syntax of route attribute to be proto:host:port rather than XMPP URI/IRI.<br />
:(psa)<br />
;Version 1.3 (2005-11-02)<br />
<br />
:Corrected stream:features namespace and the Recoverable Binding Conditions section; recommended that connection manager shall return secure attribute to client; recommended end-to-end encryption through proxy connection managers.<br />
:(ip)<br />
;Version 1.2 (2005-06-16)<br />
<br />
:Specified optional use of route and secure attributes in session request. Minor correction: the stream features element should be included in the response that contains the authid attribute (this is not necessarily the session creation response).<br />
:(ip)<br />
;Version 1.1 (2005-06-02)<br />
<br />
:Specified optional use of HTTP Accept-Encoding and Content-Encoding headers for compression at HTTP binding level.<br />
:(ip)<br />
;Version 1.0 (2005-03-03)<br />
<br />
:Per a vote of the Jabber Council, advanced status to Draft.<br />
:(psa)<br />
;Version 0.10 (2004-11-08)<br />
<br />
:Changed HTTP 401 errors to HTTP 404.<br />
:(ip)<br />
;Version 0.9 (2004-10-26)<br />
<br />
:Added charset attribute.<br />
:(ip/psa)<br />
;Version 0.8 (2004-10-26)<br />
<br />
:Specified that wait attribute must be included in the session creation response.<br />
:(ip)<br />
;Version 0.7 (2004-08-12)<br />
<br />
:Defined appropriate XMPP stanza error conditions.<br />
:(psa/ip)<br />
;Version 0.6 (2004-07-19)<br />
<br />
:Added xml:lang attribute to the session request; added recoverable binding error conditions.<br />
:(ip)<br />
;Version 0.5 (2004-05-07)<br />
<br />
:Protocol refactored to enable simultaneous requests (request identifier attribute, wait attribute, hold attribute, requests attribute) and recovery of broken connections; added content attribute; removed all wrapper types except 'terminate'; updated error handling; made key mechanism optional (should use SSL/TLS instead).<br />
:(ip/psa)<br />
;Version 0.4 (2004-02-23)<br />
<br />
:Fixed typos; removed "resource-constraint" binding error; added HTTP 403 error to table.<br />
:(psa/ip)<br />
;Version 0.3 (2004-02-19)<br />
<br />
:Added 'authid' attribute to enable communication of XMPP stream ID (used in digest authentication); specified that Content-Types other than "text/xml" are allowed to support older HTTP clients; specified business rule for connection manager queueing of client requests; changed <packet/> to <body/> to support older HTTP clients; changed 'to' attribute on initialization element from MAY to SHOULD; recommended inclusion of unavailable presence in termination element sent from client; described architectural assumptions; specified binding-specific error handling.<br />
:(psa/ip)<br />
;Version 0.2 (2004-01-13)<br />
<br />
:Added 'to' attribute on the initialization element; specified that 'text/html' is allowable for backwards-compatibility.<br />
:(dss/psa/ip)<br />
;Version 0.1 (2003-11-06)<br />
<br />
:Initial version.<br />
:(dss/psa)<br />
<br />
结束</div>
Snowqiang
http://wiki.jabbercn.org/XEP-0124
XEP-0124
2011-05-18T14:35:44Z
<p>Snowqiang: </p>
<hr />
<div>[[Category:XMPP扩展]]<br />
[[Category:翻译中]]<br />
<br />
'''本文的英文原文来自[http://www.xmpp.org/extensions/xep-0124.html XEP-0124]'''<br />
<br />
'''XEP-0124: Bidirectional-streams Over Synchronous HTTP (BOSH)'''<br />
<br />
摘要: This specification defines a transport protocol that emulates the semantics of a long-lived, bidirectional TCP connection between two entities (such as a client and a server) by efficiently using multiple synchronous HTTP request/response pairs without requiring the use of frequent polling or chunked responses.<br />
<br />
作者: Ian Paterson, Dave Smith, Peter Saint-Andre, Jack Moffitt<br />
<br />
版权: © 1999 - 2011 XMPP Standards Foundation. SEE LEGAL NOTICES.<br />
<br />
状态: 草案<br />
<br />
类型: 标准跟踪<br />
<br />
版本: 2.0<br />
<br />
最后更新日期: 2010-07-02<br />
<br />
NOTICE: The protocol defined herein is a Draft Standard of the XMPP Standards Foundation. Implementations are encouraged and the protocol is appropriate for deployment in production systems, but some changes to the protocol are possible before it becomes a Final Standard.<br />
<br />
==Introduction==<br />
<br />
The Transmission Control Protocol (TCP; RFC 793 [1]) is often used to establish a stream-oriented connection between two entities. Such connections can often be long-lived to enable an interactive "session" between the entities. However, sometimes the nature of the device or network can prevent an application from maintaining a long-lived TCP connection to a server or peer. In this case, it is desirable to use an alternative connection method that emulates the behavior of a long-lived TCP connection using a sequenced series of requests and responses that are exchanged over short-lived connections. The appropriate request-response semantics are widely available via the Hypertext Transfer Protocol (HTTP) as specified in RFC 1945 [2] and RFC 2616 [3].<br />
<br />
BOSH, the technology defined in this specification, essentially provides a "drop-in" alternative to a long-lived, bidirectional TCP connection. It is a mature, full-featured technology that has been widely implemented and deployed since 2004. To our knowledge it was the first of many similar technologies, which now include the Comet methodology formalized in the Bayeux Protocol [4] as well as The Web Socket Protocol [5] and Reverse HTTP [6].<br />
<br />
BOSH is designed to transport any data efficiently and with minimal latency in both directions. For applications that require both "push" and "pull" semantics, BOSH is significantly more bandwidth-efficient and responsive than most other bidirectional HTTP-based transport protocols and the techniques now commonly known as "Ajax". BOSH achieves this efficiency and low latency by using so-called "long polling" with multiple synchronous HTTP request/response pairs. Furthermore, BOSH can address the needs of constrained clients by employing fully-compliant HTTP 1.0 without the need for "cookies" (see RFC 2965 [7]) [8] or even access to HTTP headers.<br />
<br />
BOSH was originally developed in the Jabber/XMPP community as a replacement for an even earlier HTTP-based technology called Jabber HTTP Polling [9]. Although BOSH assumes that the "payload" of HTTP requests and responses will be XML, the payload formats are not limited to XMPP stanzas (see XMPP Core [10]) and could contain a mixture of elements qualified by namespaces defined by different protocols (e.g., both XMPP and JSON). This mix is necessary because some connection managers might 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 payload is qualified by the correct namespace.<br />
<br />
Note: XMPP Over BOSH [11] documents some XMPP-specific extensions of this protocol that were formerly included in this document.<br />
<br />
==Requirements==<br />
<br />
The following design requirements reflect the need to offer performance as close as possible to a standard TCP connection.<br />
<br />
1. Compatible with constrained runtime environments* (e.g., mobile and browser-based clients).<br />
2. Compatible with proxies that buffer partial HTTP responses.<br />
3. Efficient through proxies that limit the duration of HTTP responses.<br />
4. Fully compatible with HTTP/1.0.<br />
5. Compatible with restricted network connections (e.g., firewalls, proxies, and gateways).<br />
6. Fault tolerant (e.g., session recovers after an underlying TCP connection breaks at any stage during an HTTP request).<br />
7. Extensible.<br />
8. Consume significantly less bandwidth than polling-based protocols.<br />
9. Significantly more responsive (lower latency) than polling-based protocols.<br />
10. Support for polling (for clients that are limited to a single HTTP connection at a time).<br />
11. In-order delivery of data.<br />
12. Guard against unauthorized users injecting HTTP requests into a session.<br />
13. Protect against denial of service attacks.<br />
14. Multiplexing of data streams.<br />
<br />
*Note: Compatibility with constrained runtime environments implies the following restrictions:<br />
<br />
1. Clients are not required to have programmatic access to the headers of each HTTP request and response (e.g., cookies or status codes).<br />
2. The body of each HTTP request and response is parsable XML with a single root element.<br />
3. Clients can specify the Content-Type of the HTTP responses they receive.<br />
<br />
==Architectural Assumptions==<br />
<br />
This document assumes that most implementations will utilize a specialized connection manager ("CM") to handle HTTP connections rather than the native connection type for the relevant application (e.g., TCP connections in XMPP). Effectively, such a connection manager is a specialized HTTP server that translates between the HTTP requests and responses defined herein and the data streams (or API) implemented by the server with which it communicates, thus enabling a client to connect to a server via HTTP on port 80 or 443 instead of an application-specific port. We can illustrate this graphically as follows:<br />
<br />
Server<br />
|<br />
| [unwrapped data streams]<br />
|<br />
HTTP CM<br />
|<br />
| [HTTP + <body/> wrapper]<br />
|<br />
Client<br />
<br />
<br />
This specification covers communication only between a client and the connection manager. It does not cover communication between the connection manager and the server, since such communications are implementation-specific (e.g., the server might 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 might be an independent translating proxy such that the server might believe it is talking directly to the client over TCP; or the connection manager and the server might use a component protocol or an API defined by the server implementation).<br />
<br />
Furthermore, no aspect of this protocol limits its use to communication between a client and a server. For example, it could be used for communication between a server and a peer server if such communication can occur for the relevant application (e.g., in XMPP). 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 the native connection transport for the relevant application. (However, on some unreliable networks, BOSH might enable more stable communication between servers.)<br />
<br />
==The BOSH Technique==<br />
<br />
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).<br />
<br />
The technique employed by BOSH 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.<br />
<br />
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 so to make sure the client can send more data immediately if necessary. (The client SHOULD NOT open more than two HTTP connections to the connection manager at the same time, [12] so it would otherwise have to wait until the connection manager responds to one of the requests.)<br />
<br />
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 TCP 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.<br />
<br />
If there is no traffic in either direction for an agreed amount of time (typically several 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 so 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. [13]<br />
<br />
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. Thus 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. Therefore, 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 were being used.<br />
<br />
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.<br />
<br />
==HTTP Overview==<br />
<br />
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).<br />
<br />
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 permitted by RFC 1945 or RFC 2616. For example, 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 might buffer each partial HTTP request or response and only forward the full request or response once it is available.<br />
<br />
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.<br />
<br />
Requests and responses MAY include HTTP headers not specified herein. The receiver SHOULD ignore any such headers.<br />
<br />
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). However, the responses to requests that are not part of the session sent over the same connection using HTTP pipelining (or queued to be sent over the same connection) might be delayed if they were sent while a request that is part of the session is being held (since the connection manager MUST send its responses in the same order that the requests were received, and the connection manager typically delays its responses).<br />
<br />
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.<br />
<br />
==<body/> Wrapper Element==<br />
<br />
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 transferred. The <body/> element and its content together MUST conform to the specifications set out in XML 1.0 [14]. They SHOULD also conform to Namespaces in XML [15]. The content MUST NOT contain any of the following (all defined in XML 1.0):<br />
<br />
* Partial XML elements<br />
* XML comments<br />
* XML processing instructions<br />
* Internal or external DTD subsets<br />
* Internal or external entity references (with the exception of predefined entities)<br />
<br />
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 "payloads" in this document, e.g., XMPP stanzas as defined in RFC 6120 or elements containing XML character data that represents objects using the JSON data interchange format as defined in RFC 4627 [16]). Each <body/> wrapper MAY contain payloads qualified under a wide variety of different namespaces.<br />
<br />
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.<br />
<br />
==Initiating a BOSH Session==<br />
===Session Creation Request===<br />
<br />
The first request from the client to the connection manager requests a new session.<br />
<br />
The <body/> element of the first request SHOULD possess the following attributes (they SHOULD NOT be included in any other requests except as specified under Adding Streams To A Session):<br />
<br />
* '''<nowiki>'to'</nowiki>''' -- This attribute specifies the target domain of the first stream.<br />
* '''<nowiki>'xml:lang'</nowiki>''' -- This attribute (as defined in Section 2.12 of XML 1.0 [17]) specifies the default language of any human-readable XML character data sent or received during the session.<br />
* '''<nowiki>'ver'</nowiki>''' -- This attribute specifies the highest version of the BOSH protocol that the client supports. The numbering scheme is "<major>.<minor>" (where the minor number MAY be incremented higher than a single digit, so it MUST be treated as a separate integer). Note: The 'ver' attribute should not be confused with the version of any protocol being transported.<br />
* '''<nowiki>'wait'</nowiki>''' -- This attribute specifies the longest time (in seconds) that the connection manager is allowed to wait before responding to any request during the session. This enables the client to limit the delay before it discovers any network failure, and to prevent its HTTP/TCP connection from expiring due to inactivity.<br />
* '''<nowiki>'hold'</nowiki>''' -- This attribute specifies the maximum number of requests the connection manager is allowed to keep waiting at any one time during the session. If the client is not able to use HTTP Pipelining then this SHOULD be set to "1".<br />
<br />
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 both typically one or two orders of magnitude!<br />
<br />
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:example.com:9999"). [18] A connection manager that is configured to work only with a single server (or only with a defined list of domains and the associated list of hostnames and ports that are serving those domains) MAY ignore the 'route' attribute. (Note that the 'to' attribute specifies the domain being served, not the hostname of the machine that is serving the domain.)<br />
<br />
The <body/> element of the first request MAY also possess a 'from' attribute, which specifies the originator of the first stream and which enables the connection manager to forward the originating entity's identity to the application server (e.g., the JabberID of an entity that is connecting to an XMPP server; see XEP-0206).<br />
<br />
A client MAY include an 'ack' attribute (set to "1") to indicate that it will be using acknowledgements throughout the session and that the absence of an 'ack' attribute in any request is meaningful (see Acknowledgements).<br />
<br />
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".<br />
<br />
'''Example 1. Requesting a BOSH session'''<br />
<source lang="xml"><br />
POST /webclient HTTP/1.1<br />
Host: httpcm.example.com<br />
Accept-Encoding: gzip, deflate<br />
Content-Type: text/xml; charset=utf-8<br />
Content-Length: 104<br />
<br />
<body content='text/xml; charset=utf-8'<br />
from='user@example.com'<br />
hold='1'<br />
rid='1573741820'<br />
to='example.com'<br />
route='xmpp:example.com:9999'<br />
ver='1.6'<br />
wait='60'<br />
ack='1'<br />
xml:lang='en'<br />
xmlns='http://jabber.org/protocol/httpbind'/><br />
</source><br />
<br />
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.<br />
===Session Creation Response===<br />
<br />
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):<br />
<br />
* '''<nowiki>'sid'</nowiki>''' -- This attribute specifies the SID<br />
* '''<nowiki>'wait'</nowiki>''' -- This is the longest time (in seconds) that the connection manager will wait before responding to any request during the session. The time MUST be less than or equal to the value specified in the session request.<br />
<br />
The <body/> element SHOULD also include the following attributes (they SHOULD NOT be included in any other responses):<br />
<br />
* '''<nowiki>'ver'</nowiki>''' -- This attribute specifies the highest version of the BOSH protocol that the connection manager supports, or the version specified by the client in its request, whichever is lower.<br />
* '''<nowiki>'polling'</nowiki>''' -- This attribute specifies the shortest allowable polling interval (in seconds). This enables the client to not send empty request elements more often than desired (see Polling Sessions and Overactivity).<br />
* '''<nowiki>'inactivity'</nowiki>''' -- This attribute specifies the longest allowable inactivity period (in seconds). This enables the client to ensure that the periods with no requests pending are never too long (see Polling Sessions and Inactivity).<br />
* '''<nowiki>'requests'</nowiki>''' -- This attribute enables the connection manager to limit the number of simultaneous requests the client makes (see Overactivity and Polling Sessions). The RECOMMENDED values are either "2" or one more than the value of the 'hold' attribute specified in the session request.<br />
* '''<nowiki>'hold'</nowiki>''' -- This attribute informs the client about the maximum number of requests the connection manager will keep waiting at any one time during the session. This value MUST NOT be greater than the value specified by the client in the session request.<br />
* '''<nowiki>'to'</nowiki>''' -- This attribute communicates the identity of the backend server to which the client is attempting to connect.<br />
<br />
The connection manager MAY include an 'accept' attribute in the session creation response element, to specify a space-separated list of 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.<br />
<br />
A connection manager MAY include an 'ack' attribute (set to the value of the 'rid' attribute of the session creation request) to indicate that it will be using acknowledgements throughout the session and that the absence of an 'ack' attribute in any response is meaningful (see Acknowledgements).<br />
<br />
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 can request.<br />
<br />
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. [19]<br />
<br />
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 a BOSH Session), then in the same response the connection manager SHOULD also include the 'secure' attribute set to "true" or "1".<br />
<br />
'''Example 2. Session creation response'''<br />
<source lang="xml"><br />
HTTP/1.1 200 OK<br />
Content-Type: text/xml; charset=utf-8<br />
Content-Length: 128<br />
<br />
<body wait='60'<br />
inactivity='30'<br />
polling='5'<br />
requests='2'<br />
hold='1'<br />
ack='1573741820'<br />
accept='deflate,gzip'<br />
maxpause='120'<br />
sid='SomeSID'<br />
charsets='ISO_8859-1 ISO-2022-JP'<br />
ver='1.6'<br />
from='example.com'<br />
xmlns='http://jabber.org/protocol/httpbind'/><br />
</source><br />
<br />
'''Example 3. Subsequent response with 'from' and 'secure' attributes'''<br />
<source lang="xml"><br />
HTTP/1.1 200 OK<br />
Content-Type: text/xml; charset=utf-8<br />
Content-Length: 128<br />
<br />
<body from='example.com'<br />
xmlns='http://jabber.org/protocol/httpbind'/><br />
</source><br />
<br />
==Sending and Receiving XML Payloads==<br />
<br />
After the client has successfully completed all required preconditions, it can send and receive XML payloads via the HTTP binding.<br />
<br />
'''Example 4. Transmitting payloads'''<br />
<source lang="xml"><br />
POST /webclient HTTP/1.1<br />
Host: httpcm.example.com<br />
Accept-Encoding: gzip, deflate<br />
Content-Type: text/xml; charset=utf-8<br />
Content-Length: 188<br />
<br />
<body rid='1249243562'<br />
sid='SomeSID'<br />
xmlns='http://jabber.org/protocol/httpbind'><br />
<message to='contact@example.com'<br />
xmlns='jabber:client'><br />
<body>Good morning!</body><br />
</message><br />
<message to='friend@example.com'<br />
xmlns='jabber:client'><br />
<body>Hey, what&apos;s up?</body><br />
</message><br />
</body><br />
</source><br />
<br />
Upon receipt of a request, the connection manager SHOULD forward the content of the <body/> element to the server as soon as possible. In any case it MUST forward the content from different requests in the order specified by their 'rid' attributes.<br />
<br />
The connection manager MUST also return an HTTP 200 OK response with a <body/> element to the client. Note: This does not indicate that the payloads have been successfully delivered to the application server.<br />
<br />
It is RECOMMENDED that the connection manager not return an HTTP result until a payload has arrived from the application server for delivery to the client. However, the connection manager SHOULD NOT wait longer than the time specified by the client in the 'wait' attribute of its Session Creation Request, and it SHOULD NOT keep more HTTP requests waiting at a time than the number specified in the 'hold' attribute of the session creation request. In any case it MUST respond to requests in the order specified by their 'rid' attributes.<br />
<br />
If there are no payloads waiting or ready to be delivered within the waiting period, then the connection manager SHOULD include an empty <body/> element in the HTTP result:<br />
<br />
'''Example 5. Empty response'''<br />
<source lang="xml"><br />
HTTP/1.1 200 OK<br />
Content-Type: text/xml; charset=utf-8<br />
Content-Length: 64<br />
<br />
<body xmlns='http://jabber.org/protocol/httpbind'/><br />
</source><br />
<br />
If the connection manager has received one or more payloads from the application server for delivery to the client, then it SHOULD return the payloads in the body of its response as soon as possible after receiving them from the server. The example below includes payloads qualified by different namespaces:<br />
<br />
'''Example 6. Response with queued stanza'''<br />
<source lang="xml"><br />
HTTP/1.1 200 OK<br />
Content-Type: text/xml; charset=utf-8<br />
Content-Length: 185<br />
<br />
<body xmlns='http://jabber.org/protocol/httpbind'<br />
xmlns:json='http://json.org/'><br />
<message from='contact@example.com'<br />
to='user@example.com'<br />
xmlns='jabber:client'><br />
<body>Good morning to you!</body><br />
</message><br />
<message from='friend@example.com'<br />
to='user@example.com'<br />
xmlns='jabber:client'><br />
<body>Not much, how about with you?</body><br />
</message><br />
<json:json><br />
[<br />
{<br />
"precision": "zip",<br />
"Latitude": 37.7668,<br />
"Longitude": -122.3959,<br />
"Address": "",<br />
"City": "SAN FRANCISCO",<br />
"State": "CA",<br />
"Zip": "94107",<br />
"Country": "US"<br />
},<br />
{<br />
"precision": "zip",<br />
"Latitude": 37.371991,<br />
"Longitude": -122.026020,<br />
"Address": "",<br />
"City": "SUNNYVALE",<br />
"State": "CA",<br />
"Zip": "94085",<br />
"Country": "US"<br />
}<br />
]<br />
</json:json><br />
</body><br />
</source><br />
<br />
The client MAY poll the connection manager for incoming payloads by sending an empty <body/> element.<br />
<br />
'''Example 7. Requesting XML Payloads'''<br />
<source lang="xml"><br />
POST /webclient HTTP/1.1<br />
Host: httpcm.example.com<br />
Accept-Encoding: gzip, deflate<br />
Content-Type: text/xml; charset=utf-8<br />
Content-Length: 88<br />
<br />
<body rid='1249243563'<br />
sid='SomeSID'<br />
xmlns='http://jabber.org/protocol/httpbind'/><br />
</source><br />
<br />
The connection manager MUST wait and respond in the same way as it does after receiving payloads from the client.<br />
<br />
==Acknowledgements==<br />
===Request Acknowledgements===<br />
<br />
When responding to a request that it has been holding, if the connection manager finds it has already received another request with a higher 'rid' attribute (typically while it was holding the first request), then it MAY acknowledge the reception to the client. The connection manager MAY set the 'ack' attribute of any response to the value of the highest 'rid' attribute it has received in the case where it has also received all requests with lower 'rid' values.<br />
<br />
'''Example 8. Response with request acknowledgement'''<br />
<source lang="xml"><br />
HTTP/1.1 200 OK<br />
Content-Type: text/xml; charset=utf-8<br />
Content-Length: 64<br />
<br />
<body ack='1249243564'<br />
xmlns='http://jabber.org/protocol/httpbind'/><br />
</source><br />
<br />
If the connection manager will be including 'ack' attributes on responses during a session, then it MUST include an 'ack' attribute in its session creation response, and set the 'ack' attribute of responses throughout the session. The only exception is that, after its session creation response, the connection manager SHOULD NOT include an 'ack' attribute in any response if the value would be the 'rid' of the request being responded to.<br />
<br />
If the connection manager is permitted to hold more than one request at a time, then the reception of a lower-than-expected 'ack' value from the connection manager (or the unexpected abscence of an 'ack' attribute) can give the client an early warning that a network failure might have occurred (e.g., if the client believes the connection manager should have received another request by the time it responded).<br />
===Response Acknowledgements===<br />
<br />
The client MAY similarly inform the connection manager about the responses it has received by setting the 'ack' attribute of any request to the value of the highest 'rid' of a request for which it has already received a response in the case where it has also received all responses associated with lower 'rid' values. If the client will be including 'ack' attributes on requests during a session, then it MUST include an 'ack' attribute (set to '1') in its session creation request, and set the 'ack' attribute of requests throughout the session. The only exception is that, after its session creation request, the client SHOULD NOT include an 'ack' attribute in any request if it has received responses to all its previous requests.<br />
<br />
'''Example 9. Request with response acknowledgement'''<br />
<source lang="xml"><br />
POST /webclient HTTP/1.1<br />
Host: httpcm.example.com<br />
Accept-Encoding: gzip, deflate<br />
Content-Type: text/xml; charset=utf-8<br />
Content-Length: 88<br />
<br />
<body rid='1249243566'<br />
sid='SomeSID'<br />
ack='1249243564'<br />
xmlns='http://jabber.org/protocol/httpbind'/><br />
</source><br />
<br />
After receiving a request with an 'ack' value less than the 'rid' of the last request that it has already responded to, the connection manager MAY inform the client of the situation by sending its next response immediately instead of waiting until it has payloads to send to the client (e.g., if some time has passed since it responded). In this case it SHOULD include a 'report' attribute set to one greater than the 'ack' attribute it received from the client, and a 'time' attribute set to the number of milliseconds since it sent the response associated with the 'report' attribute.<br />
<br />
'''Example 10. Response with report'''<br />
<source lang="xml"><br />
HTTP/1.1 200 OK<br />
Content-Type: text/xml; charset=utf-8<br />
Content-Length: 64<br />
<br />
<body report='1249243565'<br />
time='852'<br />
xmlns='http://jabber.org/protocol/httpbind'/><br />
</source><br />
<br />
Upon reception of a response with 'report' and 'time' attributes, if the client has still not received the response associated with the request identifier specified by the 'report' attribute, then it MAY choose to resend the request associated with the missing response (see Broken Connections).<br />
<br />
==Inactivity==<br />
<br />
After receiving a response from the connection manager, if none of the client's requests are still being held by the connection manager (and if the session is not a Polling Session), the client SHOULD make a new request as soon as possible. In any case, if no requests are being held, the client MUST make a new request before the maximum inactivity period has expired. The length of this period (in seconds) is specified by the 'inactivity' attribute in the session creation response.<br />
<br />
If the connection manager has responded to all the requests it has received within a session and the time since its last response is longer than the maximum inactivity period, then it SHOULD assume the client has been disconnected and terminate the session without informing the client. If the client subsequently makes another request, then the connection manager SHOULD respond as if the session does not exist.<br />
<br />
If the connection manager did not specify a maximum inactivity period in the session creation response, then it SHOULD allow the client to be inactive for as long as it chooses.<br />
<br />
If the session is not a polling session then the connection manager SHOULD specify a relatively short inactivity period to ensure that disconnections are discovered as quickly as possible. The RECOMMENDED time would be a little more than the number of seconds for a comfortable network round trip between the connection manager and the client under difficult network conditions (since the client can be expected to make a new request immediately -- see above).<br />
<br />
If a client encounters an exceptional temporary situation during which it will be unable to send requests to the connection manager for a period of time greater than the maximum inactivity period (e.g., while a runtime environment changes from one web page to another), and if the connection manager included a 'maxpause' attribute in its Session Creation Response, then the client MAY request a temporary increase to the maximum inactivity period by including a 'pause' attribute in a request. Note: If the connection manager did not specify a 'maxpause' attribute at the start of the session then the client MUST NOT send a 'pause' attribute during the session.<br />
<br />
'''Example 11. Requesting a Session Pause'''<br />
<source lang="xml"><br />
POST /webclient HTTP/1.1<br />
Host: httpcm.example.com<br />
Accept-Encoding: gzip, deflate<br />
Content-Type: text/xml; charset=utf-8<br />
Content-Length: 98<br />
<br />
<body rid='1249243564'<br />
sid='SomeSID'<br />
pause='60'<br />
xmlns='http://jabber.org/protocol/httpbind'/><br />
</source><br />
<br />
Upon reception of a session pause request, if the requested period is not greater than the maximum permitted time, then the connection manager SHOULD respond immediately to all pending requests (including the pause request) and temporarily increase the maximum inactivity period to the requested time. Note: The response to the pause request MUST NOT contain any payloads.<br />
<br />
Note: If the client simply wants the connection manager to return all the requests it is holding then it MAY set the value of the 'pause' attribute to be the value of the 'inactivity' attribute in the connection manager's session creation response. (If the client believes it is in danger of becoming disconnected indefinitely then it MAY even request a temporary reduction of the maximum inactivity period by specifying a 'pause' value less than the 'inactivity' value, thus enabling the connection manager to discover any subsequent disconnection more quickly.)<br />
<br />
The connection manager SHOULD set the maximum inactivity period back to normal upon reception of the next request from the client (assuming the connection manager has not already terminated the session).<br />
<br />
==Overactivity==<br />
<br />
The client SHOULD NOT make more simultaneous requests than specified by the 'requests' attribute in the connection manager's Session Creation Response. However the client MAY make one additional request if it is to pause or terminate a session.<br />
<br />
If during any period the client sends a sequence of new requests (i.e. requests with incremented rid attributes, not repeat requests) longer than the number specified by the 'requests' attribute, and if the connection manager has not yet responded to any of the requests, and if the last request did not include either a 'pause' attribute or a 'type' attribute set to "terminate", then the connection manager SHOULD consider that the client is making too many simultaneous requests, and terminate the HTTP session with a 'policy-violation' terminal binding error to the client. Note: This behavior applies to equally to normal and polling sessions.<br />
<br />
'''Example 12. Too many simultaneous requests response'''<br />
<source lang="xml"><br />
HTTP/1.1 200 OK<br />
Content-Type: text/xml; charset=utf-8<br />
Content-Length: 68<br />
<br />
<body type='terminate'<br />
condition='policy-violation'<br />
xmlns='http://jabber.org/protocol/httpbind'/><br />
</source><br />
<br />
Note: If the connection manager did not specify a 'requests' attribute in the session creation response, then it MUST allow the client to send as many simultaneous requests as it chooses.<br />
<br />
If during any period the client sends a sequence of new requests equal in length to the number specified by the 'requests' attribute, and if the connection manager has not yet responded to any of the requests, and if the last request was empty and did not include either a 'pause' attribute or a 'type' attribute set to "terminate", and if the last two requests arrived within a period shorter than the number of seconds specified by the 'polling' attribute in the session creation response, then the connection manager SHOULD consider that the client is making requests more frequently than it was permitted and terminate the HTTP session and return a 'policy-violation' terminal binding error to the client. Note: the behavior for Polling Sessions is slightly different.<br />
<br />
'''Example 13. Too frequent requests response'''<br />
<source lang="xml"><br />
HTTP/1.1 200 OK<br />
Content-Type: text/xml; charset=utf-8<br />
Content-Length: 68<br />
<br />
<body type='terminate'<br />
condition='policy-violation'<br />
xmlns='http://jabber.org/protocol/httpbind'/><br />
</source><br />
<br />
Note: If the connection manager did not specify a 'polling' attribute in the session creation response, then it MUST allow the client to send requests as frequently as it chooses.<br />
<br />
==Polling Sessions==<br />
<br />
It is not always possible for a constrained client to either use HTTP Pipelining or open more than one HTTP connection with the connection manager at a time. In this case the client SHOULD inform the connection manager by setting the values of the 'wait' and/or 'hold' attributes in its session creation request to "0", and then "poll" the connection manager at regular intervals throughout the session for payloads it might have received from the server. Note: Even if the client does not request a polling session, the connection manager MAY require a client to use polling by setting the 'requests' attribute (which specifies the number of simultaneous requests the client can make) of its Session Creation Response to "1", however this is NOT RECOMMENDED.<br />
<br />
If a session will use polling, the connection manager SHOULD specify a higher than normal value for the 'inactivity' attribute (see Inactivity) in its session creation response. The increase SHOULD be greater than the value it specifies for the 'polling' attribute.<br />
<br />
If the client sends two consecutive empty new requests (i.e. requests with incremented rid attributes, not repeat requests) within a period shorter than the number of seconds specified by the 'polling' attribute (the shortest allowable polling interval) in the session creation response, and if the connection manager's response to the first request contained no payloads, then upon reception of the second request the connection manager SHOULD terminate the HTTP session and return a 'policy-violation' terminal binding error to the client.<br />
<br />
'''Example 14. Too frequent polling response'''<br />
<source lang="xml"><br />
HTTP/1.1 200 OK<br />
Content-Type: text/xml; charset=utf-8<br />
Content-Length: 68<br />
<br />
<body type='terminate'<br />
condition='policy-violation'<br />
xmlns='http://jabber.org/protocol/httpbind'/><br />
</source><br />
<br />
Note: If the connection manager did not specify a 'polling' attribute in the session creation response, then it MUST allow the client to poll as frequently as it chooses.<br />
<br />
==Terminating the HTTP Session==<br />
<br />
At any time, the client MAY gracefully terminate the session by sending a <body/> element with a 'type' attribute set to "terminate". The termination request MAY include one or more payloads that the connection manager MUST forward to the server to ensure graceful logoff.<br />
<br />
'''Example 15. Session termination by client'''<br />
<source lang="xml"><br />
POST /webclient HTTP/1.1<br />
Host: httpcm.example.com<br />
Accept-Encoding: gzip, deflate<br />
Content-Type: text/xml; charset=utf-8<br />
Content-Length: 153<br />
<br />
<body rid='1249243565'<br />
sid='SomeSID'<br />
type='terminate'<br />
xmlns='http://jabber.org/protocol/httpbind'><br />
<presence type='unavailable'<br />
xmlns='jabber:client'/><br />
</body><br />
</source><br />
<br />
The connection manager SHOULD respond to this request with an HTTP 200 OK containing an empty <body/> element.<br />
<br />
'''Example 16. Connection manager acknowledges termination'''<br />
<source lang="xml"><br />
HTTP/1.1 200 OK<br />
Content-Type: text/xml; charset=utf-8<br />
Content-Length: 72<br />
<br />
<body type='terminate'<br />
xmlns='http://jabber.org/protocol/httpbind'/><br />
</source><br />
<br />
Upon receiving the response, the client MUST consider the HTTP session to have been terminated.<br />
<br />
==Request IDs==<br />
===Generation===<br />
<br />
The client MUST generate a large, random, positive integer for the initial 'rid' (see Security Considerations) and then increment that value by one for each subsequent request. The client MUST take care to choose an initial 'rid' that will never be incremented above 9007199254740991 [21] within the session. In practice, a session would have to be extraordinarily long (or involve the exchange of an extraordinary number of packets) to exceed the defined limit.<br />
===In-Order Message Forwarding===<br />
<br />
When a client makes simultaneous requests, the connection manager might receive them out of order. The connection manager MUST forward the payloads to the server and respond to the client requests in the order specified by the 'rid' attributes. The client MUST process responses received from the connection manager in the order the requests were made.<br />
<br />
The connection manager SHOULD expect the 'rid' attribute to be within a window of values greater than the 'rid' of the previous request. The size of the window is equal to the maximum number of simultaneous requests allowed by the connection manager. If it receives a request with a 'rid' greater than the values in the window, then the connection manager MUST terminate the session with an error:<br />
<br />
'''Example 17. Unexpected rid error'''<br />
<source lang="xml"><br />
HTTP/1.1 200 OK<br />
Content-Type: text/xml; charset=utf-8<br />
Content-Length: 68<br />
<br />
<body type='terminate'<br />
condition='item-not-found'<br />
xmlns='http://jabber.org/protocol/httpbind'/><br />
</source><br />
<br />
===Broken Connections===<br />
<br />
Unreliable network communications or client constraints can result in broken connections. The connection manager SHOULD remember the 'rid' and the associated HTTP response body of the client's most recent requests which were not session pause requests (see Inactivity) and which did not result in an HTTP or binding error. The number of responses to non-pause requests kept in the buffer SHOULD be either the same as the maximum number of simultaneous requests allowed by the connection manager or, if Acknowledgements are being used, the number of responses that have not yet been acknowledged.<br />
<br />
If the network connection is broken or closed before the client receives a response to a request from the connection manager, then the client MAY resend an exact copy of the original request. Whenever the connection manager receives a request with a 'rid' that it has already received, it SHOULD return an HTTP 200 (OK) response that includes the buffered copy of the original XML response to the client (i.e., a <body/> wrapper possessing appropriate attributes and optionally containing one or more XML payloads). If the original response is not available (e.g., it is no longer in the buffer), then the connection manager MUST return an 'item-not-found' terminal binding error:<br />
<br />
'''Example 18. Response not in buffer error'''<br />
<source lang="xml"><br />
HTTP/1.1 200 OK<br />
Content-Type: text/xml; charset=utf-8<br />
Content-Length: 68<br />
<br />
<body type='terminate'<br />
condition='item-not-found'<br />
xmlns='http://jabber.org/protocol/httpbind'/><br />
</source><br />
<br />
Note: The error is the same whether the 'rid' is too large or too small. This makes it more difficult for an attacker to discover an acceptable value.<br />
<br />
==Protecting Insecure Sessions==<br />
===Applicability===<br />
<br />
The OPTIONAL key sequencing mechanism described here MAY be used if the client's session with the connection manager is not secure. The session SHOULD be considered secure only if all client requests are made via SSL (or TLS) HTTP connections and the connection manager generates an unpredictable session ID. If the session is secure, it is not necessary to use this key sequencing mechanism.<br />
<br />
Even if the session is not secure, the unpredictable session and request IDs specified in the preceding sections of this document already provide a level of protection similar to that provided by a connection bound to a single pair of persistent TCP/IP connections, and thus provide sufficient protection against a 'blind' attacker. However, in some circumstances, the key sequencing mechanism defined below helps to protect against a more determined and knowledgeable attacker.<br />
<br />
It is important to recognize that the key sequencing mechanism defined below helps to protect only against an attacker who is able to view the contents of all requests or responses in an insecure session but who is not able to alter the contents of those requests (in this case, the mechanism prevents the attacker from injecting HTTP requests into the session, e.g., termination requests or responses). However, the key sequencing mechanism does not provide any protection when the attacker is able to alter the contents of insecure requests or responses.<br />
===Introduction===<br />
<br />
The HTTP requests of each session MAY be spread across a series of different socket connections. This would enable an unauthorized user that obtains the session ID and request ID of a session to then use their own socket connection to inject <body/> request elements into the session and receive the corresponding responses.<br />
<br />
The key sequencing mechanism below protects against such attacks by enabling a connection manager to detect <body/> request elements injected by a third party.<br />
===Generating the Key Sequence===<br />
<br />
Prior to requesting a new session, the client MUST select an unpredictable counter ("n") and an unpredictable value ("seed"). The client then processes the "seed" through a cryptographic hash and converts the resulting 160 bits to a hexadecimal string K(1). It does this "n" times to arrive at the initial key K(n). The hashing algorithm MUST be SHA-1 as defined in RFC 3174 [22].<br />
<br />
'''Example 19. Creating the key sequence'''<br />
<br />
K(1) = hex(SHA-1(seed))<br />
K(2) = hex(SHA-1(K(1)))<br />
...<br />
K(n) = hex(SHA-1(K(n-1)))<br />
<br />
<br />
===Use of Keys===<br />
<br />
The client MUST set the 'newkey' attribute of the first request in the session to the value K(n).<br />
<br />
'''Example 20. Session Request with Initial Key'''<br />
<source lang="xml"><br />
POST /webclient HTTP/1.1<br />
Host: httpcm.example.com<br />
Accept-Encoding: gzip, deflate<br />
Content-Type: text/xml; charset=utf-8<br />
Content-Length: 104<br />
<br />
<body content='text/xml; charset=utf-8'<br />
hold='1'<br />
rid='1573741820'<br />
to='example.com'<br />
wait='60'<br />
xml:lang='en'<br />
newkey='ca393b51b682f61f98e7877d61146407f3d0a770'<br />
xmlns='http://jabber.org/protocol/httpbind'/><br />
</source><br />
<br />
The client MUST set the 'key' attribute of all subsequent requests to the value of the next key in the generated sequence (decrementing from K(n-1) towards K(1) with each request sent).<br />
<br />
'''Example 21. Request with Key'''<br />
<source lang="xml"><br />
POST /webclient HTTP/1.1<br />
Host: httpcm.example.com<br />
Accept-Encoding: gzip, deflate<br />
Content-Type: text/xml; charset=utf-8<br />
Content-Length: 88<br />
<br />
<body rid='1573741821'<br />
sid='SomeSID'<br />
key='bfb06a6f113cd6fd3838ab9d300fdb4fe3da2f7d'<br />
xmlns='http://jabber.org/protocol/httpbind'/><br />
</source><br />
<br />
The connection manager MAY verify the key by calculating the SHA-1 hash of the key and comparing it to the 'newkey' attribute of the previous request (or the 'key' attribute if the 'newkey' attribute was not set). If the values do not match (or if it receives a request without a 'key' attribute and the 'newkey' or 'key' attribute of the previous request was set), then the connection manager MUST NOT process the element, MUST terminate the session, and MUST return an 'item-not-found' terminal binding error.<br />
<br />
'''Example 22. Invalid Key Sequence Error'''<br />
<source lang="xml"><br />
HTTP/1.1 200 OK<br />
Content-Type: text/xml; charset=utf-8<br />
Content-Length: 68<br />
<br />
<body type='terminate'<br />
condition='item-not-found'<br />
xmlns='http://jabber.org/protocol/httpbind'/><br />
</source><br />
<br />
===Switching to Another Key Sequence===<br />
<br />
A client SHOULD choose a high value for "n" when generating the key sequence. However, if the session lasts long enough that the client arrives at the last key in the sequence K(1) then the client MUST switch to a new key sequence.<br />
<br />
The client MUST:<br />
<br />
1. Choose new values for "seed" and "n".<br />
2. Generate a new key sequence using the algorithm defined above.<br />
3. Set the 'key' attribute of the request to the next value in the old sequence (i.e. K(1), the last value).<br />
4. Set the 'newkey' attribute of the request to the value K(n) from the new sequence.<br />
<br />
'''Example 23. New Key Sequence'''<br />
<source lang="xml"><br />
POST /webclient HTTP/1.1<br />
Host: httpcm.example.com<br />
Accept-Encoding: gzip, deflate<br />
Content-Type: text/xml; charset=utf-8<br />
Content-Length: 188<br />
<br />
<body rid='1573741822'<br />
sid='SomeSID'<br />
key='6f825e81f4532b2c5fa2d12457d8a1f22e8f838e'<br />
newkey='113f58a37245ec9637266cf2fb6e48bfeaf7964e'<br />
xmlns='http://jabber.org/protocol/httpbind'><br />
<message to='contact@example.com'<br />
xmlns='jabber:client'><br />
<body>I said "Hi!"</body><br />
</message><br />
</body><br />
</source><br />
<br />
==Multiple Streams==<br />
===Introduction===<br />
<br />
The OPTIONAL feature described in this section enables multiple XML streams to be contained within a single HTTP session. This feature is essential in runtime environments that prevent HTTP Pipelining, thereby constraining the number of simultaneous HTTP requests a client can make to each connection manager, since clients running in such environments need multi-stream sessions if they are to connect using more than one account at the same time. This feature also reduces network traffic for any client that needs to establish parallel streams over HTTP.<br />
===Discovery===<br />
<br />
If a connection manager supports the multi-streams feature, it MUST include a 'stream' attribute in its Session Creation Response. If a client does not receive the 'stream' attribute then it MUST assume that the connection manager does not support the feature. [23]<br />
<br />
The 'stream' attribute identifies the first stream to be opened for the session. The value of each 'stream' attribute MUST be an opaque and unpredictable name that is unique within the context of the connection manager application.<br />
<br />
'''Example 24. Session creation response with stream name'''<br />
<source lang="xml"><br />
HTTP/1.1 200 OK<br />
Content-Type: text/xml; charset=utf-8<br />
Content-Length: 128<br />
<br />
<body wait='60'<br />
inactivity='30'<br />
polling='5'<br />
requests='2'<br />
hold='1'<br />
accept='deflate,gzip'<br />
stream='firstStreamName'<br />
maxpause='120'<br />
sid='SomeSID'<br />
charsets='ISO_8859-1 ISO-2022-JP'<br />
ver='1.6'<br />
from='example.com'<br />
xmlns='http://jabber.org/protocol/httpbind'/><br />
</source><br />
<br />
===Adding Streams To A Session===<br />
<br />
If the connection manager included a 'stream' attribute in its session creation response then the client MAY ask it to open another stream at any time by sending it an empty <body/> element with a 'to' attribute. The request MUST include valid 'sid' and 'rid' [24] attributes, and SHOULD also include an 'xml:lang' attribute. The request MAY include 'route', 'from' and 'secure' attributes (see Session Creation Request), but it SHOULD NOT include 'ver', 'content', 'hold' or 'wait' attributes (since a new session is not being created).<br />
<br />
'''Example 25. Requesting another stream'''<br />
<source lang="xml"><br />
POST /webclient HTTP/1.1<br />
Host: httpcm.example.com<br />
Accept-Encoding: gzip, deflate<br />
Content-Type: text/xml; charset=utf-8<br />
Content-Length: 104<br />
<br />
<body sid='SomeSID'<br />
rid='1573741820'<br />
to='example.com'<br />
route='xmpp:example.com:9999'<br />
xml:lang='en'<br />
xmlns='http://jabber.org/protocol/httpbind'/><br />
</source><br />
<br />
If the connection manager did not indicate its support for multiple streams at the start of the session, then it MUST ignore the extra attributes and treat the request as a normal empty request for payloads (see Sending and Receiving XML Payloads). [25] Otherwise it MUST open a new stream with the specified server (see Session Creation Response), generate a new stream name, and respond to the client with the name. The response MAY also include 'from' and 'secure' attributes, but it SHOULD NOT include 'sid', 'requests', 'polling', 'hold', 'inactivity', 'maxpause', 'accept', 'charsets', 'ver' or 'wait' attributes.<br />
<br />
'''Example 26. Add stream response'''<br />
<source lang="xml"><br />
HTTP/1.1 200 OK<br />
Content-Type: text/xml; charset=utf-8<br />
Content-Length: 128<br />
<br />
<body stream='secondStreamName'<br />
from='example.com'<br />
xmlns='http://jabber.org/protocol/httpbind'/><br />
</source><br />
<br />
Note: If the response did not include either 'from' or 'secure' attributes then they MAY be sent in a subsequent response instead (see Session Creation Response). In that case the 'stream' attribute MUST also be specified.<br />
===Transmitting Payloads===<br />
<br />
If more than one stream has been opened within a session, then all non-empty <body/> elements sent by the connection manager MUST include a 'stream' attribute that specifies which stream all the payloads it contains belong to. The client SHOULD include a 'stream' attribute for the same purpose. The client MAY omit the 'stream' attribute if it wants the connection manager to broadcast the payloads over all open streams. Note: A <body/> element MUST NOT contain different payloads for different streams.<br />
<br />
If a stream name does not correspond to one of the session's open streams, then the receiving connection manager SHOULD return an 'item-not-found' terminal binding error, or the receiving client SHOULD terminate the session. However, if the receiving entity has only just closed the stream (and the sender might not have been aware of that when it sent the payloads), then it MAY instead simply silently ignore any payloads the <body/> element contains.<br />
<br />
Note: Empty <body/> elements that do not include a 'from' or 'secure' attribute SHOULD NOT include a 'stream' attribute (since nothing is being transmitted for any stream). If such a <body/> element does include a 'stream' attribute then the receiving entity SHOULD ignore the attribute.<br />
<br />
'''Example 27. Client sends payload with a stream name'''<br />
<source lang="xml"><br />
POST /webclient HTTP/1.1<br />
Host: httpcm.example.com<br />
Accept-Encoding: gzip, deflate<br />
Content-Type: text/xml; charset=utf-8<br />
Content-Length: 188<br />
<br />
<body rid='1249243562'<br />
sid='SomeSID'<br />
stream='secondStreamName'<br />
xmlns='http://jabber.org/protocol/httpbind'><br />
<message to='contact@example.com'<br />
xmlns='jabber:client'><br />
<body>I said hello.</body><br />
</message><br />
</body><br />
</source><br />
<br />
Note: The value of the 'stream' attribute of the response MAY be different than the corresponding request. [26]<br />
<br />
'''Example 28. Connection manager responds with a different stream name'''<br />
<source lang="xml"><br />
HTTP/1.1 200 OK<br />
Content-Type: text/xml; charset=utf-8<br />
Content-Length: 185<br />
<br />
<body stream='firstStreamName'<br />
xmlns='http://jabber.org/protocol/httpbind'><br />
<message from='contact@example.com'<br />
to='user@example.com'<br />
xmlns='jabber:client'><br />
<body>Hi yourself!</body><br />
</message><br />
</body><br />
</source><br />
<br />
If no stream name is specified by the connection manager then the client MUST assume the payloads are associated with the first stream (even if the first stream has been closed).<br />
<br />
If no stream name is specified by the client then the connection manager MUST broadcast the payloads over all open streams. [27]<br />
<br />
'''Example 29. Client asks for a payload to be broadcast'''<br />
<source lang="xml"><br />
POST /webclient HTTP/1.1<br />
Host: httpcm.example.com<br />
Accept-Encoding: gzip, deflate<br />
Content-Type: text/xml; charset=utf-8<br />
Content-Length: 188<br />
<br />
<body rid='1249243562'<br />
sid='SomeSID'<br />
xmlns='http://jabber.org/protocol/httpbind'><br />
<presence xmlns='jabber:client'><br />
<show>away</show><br />
</presence><br />
</body><br />
</source><br />
<br />
===Closing a Stream===<br />
<br />
If more than one stream is open within a session, the client MAY close one open stream at any time using the procedure described in the section Terminating the HTTP Session above, taking care to specify the stream name with a 'stream' attribute. If the client closes the last stream the connection manager MUST terminate the session. If the client does not specify a stream name then the connection manager MUST close all open streams (sending any payloads the terminate request contains to all streams), and terminate the session.<br />
<br />
'''Example 30. Client closes one stream'''<br />
<source lang="xml"><br />
POST /webclient HTTP/1.1<br />
Host: httpcm.example.com<br />
Accept-Encoding: gzip, deflate<br />
Content-Type: text/xml; charset=utf-8<br />
Content-Length: 153<br />
<br />
<body rid='1249243564'<br />
sid='SomeSID'<br />
stream='secondStreamName'<br />
type='terminate'<br />
xmlns='http://jabber.org/protocol/httpbind'><br />
<presence type='unavailable'<br />
xmlns='jabber:client'/><br />
</body><br />
</source><br />
<br />
===Error Conditions===<br />
<br />
If more than one stream is open within a session, the connection manager MAY include a 'stream' attribute in a fatal binding error (see Terminal Binding Conditions). If a 'stream' attribute is specified then the stream MUST be closed by both entities but the session SHOULD NOT be terminated.<br />
<br />
'''Example 31. Fatal stream error'''<br />
<source lang="xml"><br />
HTTP/1.1 200 OK<br />
Content-Type: text/xml; charset=utf-8<br />
Content-Length: 68<br />
<br />
<body type='terminate'<br />
condition='remote-connection-failed'<br />
stream='secondStreamName'<br />
xmlns='http://jabber.org/protocol/httpbind'/><br />
</source><br />
<br />
Note: If the connection manager does not include a 'stream' attribute in a fatal binding error then all the session's open streams MUST be closed by both entities and the session MUST be terminated.<br />
<br />
==Error and Status Codes==<br />
<br />
There are four types of error and status reporting in HTTP responses:<br />
<br />
'''Table 1: Error Condition Types'''<br />
{| border="1"<br />
|Condition Type <br />
|Description<br />
|-<br />
|HTTP Conditions (Deprecated) <br />
|The connection manager responds to an invalid request from a legacy client with a standard HTTP error. These are used for binding syntax errors, possible attacks, etc. Note that constrained clients are unable to differentiate between HTTP errors.<br />
|-<br />
|Terminal Binding Conditions <br />
|These error conditions can be read by constrained clients. They are used for connection manager problems, abstracting stream errors, communication problems between the connection manager and the server, and invalid client requests (binding syntax errors, possible attacks, etc.)<br />
|-<br />
|Recoverable Binding Conditions <br />
|These report communication problems between the connection manager and the client. They do not terminate the session. Clients recover from these errors by resending all the preceding <body/> wrappers that have not received responses.<br />
|-<br />
|Transported Protocol Conditions <br />
|Errors relating to the XML payloads within <body/> wrappers are, in general, defined in the documentation of the protocol being transported. They do not terminate the session.<br />
|}<br />
<br />
Full descriptions are provided below.<br />
===HTTP Conditions===<br />
<br />
Note: All HTTP codes except 200 have been superseded by Terminal Binding Conditions to allow clients to determine whether the source of errors is the connection manager application or an HTTP intermediary.<br />
<br />
A legacy client (or connection manager) is a client (or connection manager) that did not include a 'ver' attribute in its session creation request (or response). A legacy client (or connection manager) will interpret (or respond with) HTTP error codes according to the table below. Non-legacy connection managers SHOULD NOT send HTTP error codes unless they are communicating with a legacy client. Upon receiving an HTTP error (400, 403, 404), a legacy client or any client that is communicating with a legacy connection manager MUST consider the HTTP session to be null and void. A non-legacy client that is communicating with a non-legacy connection manager MAY consider that the session is still active.<br />
<br />
'''Table 2: HTTP Error and Status Codes'''<br />
{| border="1"<br />
|Code<br />
|Name<br />
|Superseded by <br />
|Purpose<br />
|-<br />
|200 <br />
|OK <br />
|<nowiki>-</nowiki><br />
|Response to valid client request.<br />
|-<br />
|400 <br />
|Bad Request <br />
|bad-request <br />
|Inform client that the format of an HTTP header or binding element is unacceptable (e.g., syntax error).<br />
|-<br />
|403<br />
|Forbidden <br />
|policy-violation <br />
|Inform client that it has broken the session rules (polling too frequently, requesting too frequently, too many simultaneous requests).<br />
|-<br />
|404 <br />
|Not Found <br />
|item-not-found <br />
|Inform client that (1) 'sid' is not valid, (2) 'stream' is not valid, (3) 'rid' is larger than the upper limit of the expected window, (4) connection manager is unable to resend response, (5) 'key' sequence is invalid.<br />
|}<br />
<br />
Note: No other HTTP error and status codes were defined in the early versions of BOSH (e.g., Internal Server Error).<br />
===Terminal Binding Conditions===<br />
<br />
In any response it sends to the client, the connection manager MAY return a fatal error by setting a 'type' attribute of the <body/> element to "terminate". These binding errors imply that the HTTP session is terminated (unless a 'stream' attribute is specified -- see Multiple Stream Error Conditions).<br />
<br />
Note: Although many of these conditions are similar to the XMPP stream error conditions specified in RFC 6120, they are not to be confused with XMPP stream errors. In cases where BOSH is being used to transport XMPP, any fatal XMPP stream error conditions experienced between the connection manager and the XMPP server SHOULD only be reported using the "remote-stream-error" condition as described below.<br />
<br />
'''Example 32. Remote connection failed error'''<br />
<source lang="xml"><br />
HTTP/1.1 200 OK<br />
Content-Type: text/xml; charset=utf-8<br />
Content-Length: 68<br />
<br />
<body type='terminate'<br />
condition='remote-connection-failed'<br />
xmlns='http://jabber.org/protocol/httpbind'/><br />
</source><br />
<br />
The following values of the 'condition' attribute are defined:<br />
<br />
Table 3: Terminal Binding Error Conditions<br />
Condition Purpose<br />
bad-request* The format of an HTTP header or binding element received from the client is unacceptable (e.g., syntax error).<br />
host-gone The target domain specified in the 'to' attribute or the target host or port specified in the 'route' attribute is no longer serviced by the connection manager.<br />
host-unknown The target domain specified in the 'to' attribute or the target host or port specified in the 'route' attribute is unknown to the connection manager.<br />
improper-addressing The initialization element lacks a 'to' or 'route' attribute (or the attribute has no value) but the connection manager requires one.<br />
internal-server-error The connection manager has experienced an internal error that prevents it from servicing the request.<br />
item-not-found* (1) 'sid' is not valid, (2) 'stream' is not valid, (3) 'rid' is larger than the upper limit of the expected window, (4) connection manager is unable to resend response, (5) 'key' sequence is invalid.<br />
other-request Another request being processed at the same time as this request caused the session to terminate.<br />
policy-violation* The client has broken the session rules (polling too frequently, requesting too frequently, sending too many simultaneous requests).<br />
remote-connection-failed The connection manager was unable to connect to, or unable to connect securely to, or has lost its connection to, the server.<br />
remote-stream-error Encapsulates an error in the protocol being transported.<br />
see-other-uri The connection manager does not operate at this URI (e.g., the connection manager accepts only SSL or TLS connections at some https: URI rather than the http: URI requested by the client). The client can try POSTing to the URI in the content of the <uri/> child element.<br />
system-shutdown The connection manager is being shut down. All active HTTP sessions are being terminated. No new sessions can be created.<br />
undefined-condition The error is not one of those defined herein; the connection manager SHOULD include application-specific information in the content of the <body/> wrapper.<br />
<br />
* If the client did not include a 'ver' attribute in its session creation request then the connection manager SHOULD send a deprecated HTTP Error Condition instead of this terminal binding condition. If the connection manager did not include a 'ver' attribute in its session creation response then the client SHOULD expect it to send a deprecated HTTP Error Condition instead of this terminal binding condition.<br />
<br />
The following is an example of a "see-other-uri" condition:<br />
<br />
'''Example 33. See other URI error'''<br />
<source lang="xml"><br />
HTTP/1.1 200 OK<br />
Content-Type: text/xml; charset=utf-8<br />
Content-Length: 68<br />
<br />
<body condition='see-other-uri'<br />
type='terminate'<br />
xmlns='http://jabber.org/protocol/httpbind'><br />
<uri>https://secure.jabber.org/xmppcm</uri><br />
</body><br />
</source><br />
<br />
The following is an example including a "remote-stream-error" condition:<br />
<br />
'''Example 34. Remote error'''<br />
<source lang="xml"><br />
HTTP/1.1 200 OK<br />
Content-Type: text/xml; charset=utf-8<br />
Content-Length: 68<br />
<br />
<body condition='remote-stream-error'<br />
type='terminate'<br />
xmlns='http://jabber.org/protocol/httpbind'<br />
xmlns:stream='http://etherx.jabber.org/streams'><br />
<message from='contact@example.com'<br />
to='user@example.com'<br />
xmlns='jabber:client'><br />
<body>I said "Hi!"</body><br />
</message><br />
<stream:error><br />
<xml-not-well-formed xmlns='urn:ietf:params:xml:ns:xmpp-streams'/><br />
<text xmlns='urn:ietf:params:xml:ns:xmpp-streams'<br />
xml:lang='en'><br />
Some special application diagnostic information!<br />
</text><br />
<escape-your-data xmlns='application-ns'/><br />
</stream:error><br />
</body><br />
</source><br />
<br />
Naturally, the client MAY report binding errors to the connection manager as well, although this is unlikely.<br />
===Recoverable Binding Conditions===<br />
<br />
In any response it sends to the client, the connection manager MAY return a recoverable error by setting a 'type' attribute of the <body/> element to "error". These errors do not imply that the HTTP session is terminated.<br />
<br />
If it decides to recover from the error, then the client MUST repeat the HTTP request that resulted in the error, as well as all the preceding HTTP requests that have not received responses. The content of these requests MUST be identical to the <body/> elements of the original requests. This enables the connection manager to recover a session after the previous request was lost due to a communication failure.<br />
<br />
'''Example 35. Recoverable error'''<br />
<source lang="xml"><br />
HTTP/1.1 200 OK<br />
Content-Type: text/xml; charset=utf-8<br />
Content-Length: 68<br />
<br />
<body type='error'<br />
xmlns='http://jabber.org/protocol/httpbind'/><br />
</source><br />
<br />
===XML Payload Conditions===<br />
<br />
Application-level error conditions described in the documentation of the protocol being transported are routed to the client through the connection manager. They are transparent to the connection manager, and therefore out of scope for the transport binding defined herein.<br />
<br />
==Implementation Notes==<br />
===HTTP Pipelining===<br />
<br />
Even if the client requests HTTP Pipelining and the connection manager supports it, there is no guarantee that pipelining will succeed, because it might not be supported by intermediate proxies.<br />
<br />
The best the client can do is to request the use of HTTP Pipelining by setting the 'hold' attribute to a value of "1". If HTTP Pipelining does not work (because the server returns HTTP 1.0 or connection:close), then the client SHOULD degrade gracefully by using multiple connections.<br />
<br />
==Security Considerations==<br />
===Connection Between Client and BOSH Service===<br />
<br />
All communications between a client and a BOSH service SHOULD occur over encrypted HTTP connections. Negotiation of encryption between the client and the connection manager SHOULD occur at the transport layer or the HTTP layer, not the application layer; such negotiation SHOULD follow the HTTP/SSL protocol defined in SSL [28], although MAY follow the HTTP/TLS protocol defined in RFC 2818 [29] or the TLS Within HTTP protocol defined in RFC 2817 [30].<br />
<br />
If the HTTP connection used to send the initial session request is encrypted, then all the other HTTP connections used within the session MUST also be encrypted. Furthermore, if authentication certificates are exchanged when establishing the encrypted connection that is used to send the initial session request, then the client and/or connection manager SHOULD ensure that the same authentication certificates are employed for all subsequent connections used by the session. Once such a "secure session" has been established:<br />
<br />
* If the connection manager refuses to establish an encrypted connection or offers a different certificate, then the client SHOULD close the connection and terminate the session without sending any more requests.<br />
* If the client sends a wrapper element that is part of a "secure session" over a connection that either is not encrypted or uses a different certificate, then the connection manager SHOULD simply close the connection. The connection manager SHOULD NOT terminate the session since that would facilitate denial of service attacks.<br />
<br />
===Connection Between BOSH Service and Application===<br />
<br />
A BOSH service SHOULD encrypt its connection to the backend application using appropriate technologies such as Secure Sockets Layer (SSL), Transport Layer Security (TLS), and StartTLS if supported by the backend application. Alternatively, the BOSH service can be considered secure (1) if it is running on the same physical machine as the backend application or (2) if it running on the same private network as the backend application and the administrators are sure that unknown individuals or processes do not have access to that private network.<br />
<br />
If data privacy is desired, the client SHOULD encrypt its messages using an application-specific end-to-end encryption technology, because there is no way for the client to be sure that the BOSH service encrypts its connection to the application; methods for doing so are outside the scope of this specification.<br />
===Unpredictable SID and RID===<br />
<br />
The session identifier (SID) and initial request identifier (RID) are security-critical and therefore MUST be both unpredictable and nonrepeating (see RFC 1750 [31] for recommendations regarding randomness of SIDs and initial RIDs for security purposes).<br />
===Use of SHA-1===<br />
<br />
Recent research has shown that in select cases it is possible to compromise the hashes produced by the SHA-1 hashing algorithm (see RFC 4270 [32]). However, the use to which SHA-1 is put in BOSH will likely minimize the applicability of the attacks described in the literature. Furthermore, current estimates suggest that even with the recently-discovered attack, it would still take one year of computing by a government-sized entity to produce a collision.<br />
<br />
==IANA Considerations==<br />
<br />
TCP port 5280, conventially used for communication between BOSH clients and BOSH connection mangers, is registered with the Internet Assigned Numbers Authority (IANA) [33] in its port registry at IANA Port Numbers Registry [34], with a keyword of "xmpp-bosh". (Although use of this port is OPTIONAL, it is helpful to define this port in a standardized way so that BOSH clients can contact any given XMPP service via BOSH without the need either for DNS TXT records as described in Discovering Alternative XMPP Connection Methods [35] or for more advanced methods such as U-NAPTR.<br />
<br />
==XMPP Registrar Considerations==<br />
===Protocol Namespaces===<br />
<br />
The XMPP Registrar includes 'http://jabber.org/protocol/httpbind' in its registry of protocol namespaces.<br />
<br />
==XML Schema==<br />
<source lang="xml"><br />
<?xml version='1.0' encoding='UTF-8'?><br />
<br />
<xs:schema<br />
xmlns:xs='http://www.w3.org/2001/XMLSchema'<br />
xmlns:stream='http://etherx.jabber.org/streams'<br />
targetNamespace='http://jabber.org/protocol/httpbind'<br />
xmlns='http://jabber.org/protocol/httpbind'<br />
elementFormDefault='qualified'><br />
<br />
<xs:annotation><br />
<xs:documentation><br />
The protocol documented by this schema is defined in<br />
XEP-0124: http://www.xmpp.org/extensions/xep-0124.html<br />
</xs:documentation><br />
</xs:annotation><br />
<br />
<xs:import namespace='http://www.w3.org/XML/1998/namespace'<br />
schemaLocation='http://www.w3.org/2001/03/xml.xsd'/><br />
<br />
<xs:element name='body'><br />
<xs:complexType><br />
<xs:choice><br />
<xs:element name='uri'<br />
minOccurs='0'<br />
maxOccurs='1'<br />
type='xs:string'/><br />
<xs:any namespace='##other'<br />
minOccurs='0'<br />
maxOccurs='unbounded'<br />
processContents='lax'/><br />
</xs:choice><br />
<xs:attribute name='accept' type='xs:string' use='optional'/><br />
<xs:attribute name='ack' type='xs:positiveInteger' use='optional'/><br />
<xs:attribute name='authid' type='xs:string' use='optional'/><br />
<xs:attribute name='charsets' type='xs:NMTOKENS' use='optional'/><br />
<xs:attribute name='condition' use='optional'><br />
<xs:simpleType><br />
<xs:restriction base='xs:NCName'><br />
<xs:enumeration value='bad-request'/><br />
<xs:enumeration value='host-gone'/><br />
<xs:enumeration value='host-unknown'/><br />
<xs:enumeration value='improper-addressing'/><br />
<xs:enumeration value='internal-server-error'/><br />
<xs:enumeration value='item-not-found'/><br />
<xs:enumeration value='other-request'/><br />
<xs:enumeration value='policy-violation'/><br />
<xs:enumeration value='remote-connection-failed'/><br />
<xs:enumeration value='remote-stream-error'/><br />
<xs:enumeration value='see-other-uri'/><br />
<xs:enumeration value='system-shutdown'/><br />
<xs:enumeration value='undefined-condition'/><br />
</xs:restriction><br />
</xs:simpleType><br />
</xs:attribute><br />
<xs:attribute name='content' type='xs:string' use='optional'/><br />
<xs:attribute name='from' type='xs:string' use='optional'/><br />
<xs:attribute name='hold' type='xs:unsignedByte' use='optional'/><br />
<xs:attribute name='inactivity' type='xs:unsignedShort' use='optional'/><br />
<xs:attribute name='key' type='xs:string' use='optional'/><br />
<xs:attribute name='maxpause' type='xs:unsignedShort' use='optional'/><br />
<xs:attribute name='newkey' type='xs:string' use='optional'/><br />
<xs:attribute name='pause' type='xs:unsignedShort' use='optional'/><br />
<xs:attribute name='polling' type='xs:unsignedShort' use='optional'/><br />
<xs:attribute name='report' type='xs:positiveInteger' use='optional'/><br />
<xs:attribute name='requests' type='xs:unsignedByte' use='optional'/><br />
<xs:attribute name='rid' type='xs:positiveInteger' use='optional'/><br />
<xs:attribute name='route' type='xs:string' use='optional'/><br />
<xs:attribute name='sid' type='xs:string' use='optional'/><br />
<xs:attribute name='stream' type='xs:string' use='optional'/><br />
<xs:attribute name='time' type='xs:unsignedShort' use='optional'/><br />
<xs:attribute name='to' type='xs:string' use='optional'/><br />
<xs:attribute name='type' use='optional'><br />
<xs:simpleType><br />
<xs:restriction base='xs:NCName'><br />
<xs:enumeration value='error'/><br />
<xs:enumeration value='terminate'/><br />
</xs:restriction><br />
</xs:simpleType><br />
</xs:attribute><br />
<xs:attribute name='ver' type='xs:string' use='optional'/><br />
<xs:attribute name='wait' type='xs:unsignedShort' use='optional'/><br />
<xs:attribute ref='xml:lang' use='optional'/><br />
<xs:anyAttribute namespace='##other' processContents='lax'/><br />
</xs:complexType><br />
</xs:element><br />
<br />
</xs:schema><br />
</source><br />
<br />
==Acknowledgements==<br />
<br />
Thanks to Mike Cumings, Tomas Karasek, Tobias Markmann, Chris Seymour, Safa Sofuoğlu, Stefan Strigler, Matthew Wild, Kevin Winters, and Christopher Zorn for their feedback.<br />
<br />
==Appendices==<br />
===Appendix A: Document Information===<br />
<br />
Series: XEP<br />
Number: 0124<br />
Publisher: XMPP Standards Foundation<br />
Status: Draft<br />
Type: Standards Track<br />
Version: 1.10<br />
Last Updated: 2010-07-02<br />
Approving Body: XMPP Council<br />
Dependencies: RFC 1945, RFC 2616, RFC 3174<br />
Supersedes: None<br />
Superseded By: None<br />
Short Name: bosh<br />
Schema: <http://www.xmpp.org/schemas/httpbind.xsd><br />
Source Control: HTML RSS<br />
This document in other formats: XML PDF<br />
===Appendix B: Author Information===<br />
Ian Paterson<br />
<br />
Email: ian.paterson@clientside.co.uk<br />
JabberID: ian@zoofy.com<br />
Dave Smith<br />
<br />
Email: dizzyd@jabber.org<br />
JabberID: dizzyd@jabber.org<br />
Peter Saint-Andre<br />
<br />
Email: stpeter@jabber.org<br />
JabberID: stpeter@jabber.org<br />
URI: https://stpeter.im/<br />
Jack Moffitt<br />
<br />
Email: jack@chesspark.com<br />
JabberID: jack@chesspark.com<br />
===Appendix C: Legal Notices===<br />
Copyright<br />
This XMPP Extension Protocol is copyright © 1999 - 2011 by the XMPP Standards Foundation (XSF).<br />
Permissions<br />
Permission is hereby granted, free of charge, to any person obtaining a copy of this specification (the "Specification"), to make use of the Specification without restriction, including without limitation the rights to implement the Specification in a software program, deploy the Specification in a network service, and copy, modify, merge, publish, translate, distribute, sublicense, or sell copies of the Specification, and to permit persons to whom the Specification is furnished to do so, subject to the condition that the foregoing copyright notice and this permission notice shall be included in all copies or substantial portions of the Specification. Unless separate permission is granted, modified works that are redistributed shall not contain misleading information regarding the authors, title, number, or publisher of the Specification, and shall not claim endorsement of the modified works by the authors, any organization or project to which the authors belong, or the XMPP Standards Foundation.<br />
Disclaimer of Warranty<br />
## NOTE WELL: This Specification is provided on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, express or implied, including, without limitation, any warranties or conditions of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A PARTICULAR PURPOSE. ##<br />
Limitation of Liability<br />
In no event and under no legal theory, whether in tort (including negligence), contract, or otherwise, unless required by applicable law (such as deliberate and grossly negligent acts) or agreed to in writing, shall the XMPP Standards Foundation or any author of this Specification be liable for damages, including any direct, indirect, special, incidental, or consequential damages of any character arising from, out of, or in connection with the Specification or the implementation, deployment, or other use of the Specification (including but not limited to damages for loss of goodwill, work stoppage, computer failure or malfunction, or any and all other commercial damages or losses), even if the XMPP Standards Foundation or such author has been advised of the possibility of such damages.<br />
IPR Conformance<br />
This XMPP Extension Protocol has been contributed in full conformance with the XSF's Intellectual Property Rights Policy (a copy of which can be found at <http://xmpp.org/extensions/ipr-policy.shtml> or obtained by writing to XMPP Standards Foundation, 1899 Wynkoop Street, Suite 600, Denver, CO 80202 USA).<br />
===Appendix D: Relation to XMPP===<br />
<br />
The Extensible Messaging and Presence Protocol (XMPP) is defined in the XMPP Core (RFC 3920) and XMPP IM (RFC 3921) specifications contributed by the XMPP Standards Foundation to the Internet Standards Process, which is managed by the Internet Engineering Task Force in accordance with RFC 2026. Any protocol defined in this document has been developed outside the Internet Standards Process and is to be understood as an extension to XMPP rather than as an evolution, development, or modification of XMPP itself.<br />
===Appendix E: Discussion Venue===<br />
<br />
The primary venue for discussion of XMPP Extension Protocols is the <standards@xmpp.org> discussion list.<br />
<br />
Discussion on other xmpp.org discussion lists might also be appropriate; see <http://xmpp.org/about/discuss.shtml> for a complete list.<br />
<br />
Given that this XMPP Extension Protocol normatively references IETF technologies, discussion on the <xsf-ietf@xmpp.org> list might also be appropriate.<br />
<br />
Errata can be sent to <editor@xmpp.org>.<br />
===Appendix F: Requirements Conformance===<br />
<br />
The following requirements keywords as used in this document are to be interpreted as described in RFC 2119: "MUST", "SHALL", "REQUIRED"; "MUST NOT", "SHALL NOT"; "SHOULD", "RECOMMENDED"; "SHOULD NOT", "NOT RECOMMENDED"; "MAY", "OPTIONAL".<br />
===Appendix G: Notes===<br />
<br />
1. RFC 793: Transmission Control Protocol <http://tools.ietf.org/html/rfc0793>.<br />
<br />
2. RFC 1945: Hypertext Transfer Protocol -- HTTP/1.0 <http://tools.ietf.org/html/rfc1945>.<br />
<br />
3. RFC 2616: Hypertext Transport Protocol -- HTTP/1.1 <http://tools.ietf.org/html/rfc2616>.<br />
<br />
4. Bayeux Protocol <http://svn.cometd.org/trunk/bayeux/bayeux.html>.<br />
<br />
5. The Web Socket Protocol <http://tools.ietf.org/html/draft-hixie-thewebsocketprotocol>.<br />
<br />
6. Reverse HTTP <http://tools.ietf.org/html/draft-lentczner-rhttp>.<br />
<br />
7. RFC 2965: HTTP State Management Mechanism <http://tools.ietf.org/html/rfc2965>.<br />
<br />
8. Requiring cookies is sub-optimal because several significant computing platforms provide only limited access to underlying HTTP requests/responses; worse, some platforms hide or remove cookie-related headers.<br />
<br />
9. XEP-0025: Jabber HTTP Polling <http://xmpp.org/extensions/xep-0025.html>.<br />
<br />
10. RFC 6120: Extensible Messaging and Presence Protocol (XMPP): Core <http://tools.ietf.org/html/rfc6120>.<br />
<br />
11. XEP-0206: XMPP Over BOSH <http://xmpp.org/extensions/xep-0206.html>.<br />
<br />
12. In order to reduce network congestion, RFC 2616 recommends that clients SHOULD NOT keep more than two HTTP connections to the same HTTP server open at the same time. Clients running in constrained enviroments typically have no choice but to abide by that recommendation.<br />
<br />
13. If there is no traffic other than the "pings" then bandwidth consumption will be double that of a TCP connection (although double nothing is still nothing). If data is sent in large packets then bandwidth consumption will be almost identical.<br />
<br />
14. Extensible Markup Language (XML) 1.0 (Fourth Edition) <http://www.w3.org/TR/REC-xml/>.<br />
<br />
15. Namespaces in XML <http://www.w3.org/TR/REC-xml-names/>.<br />
<br />
16. RFC 4627: The application/json Media Type for JavaScript Object Notation (JSON) <http://tools.ietf.org/html/rfc4627>.<br />
<br />
17. Extensible Markup Language (XML) 1.0 (Fourth Edition) <http://www.w3.org/TR/REC-xml/>.<br />
<br />
18. Although the syntax of the 'route' attribute bears a superficial resemblance to a URI or IRI, it is not a URI/IRI and MUST NOT be processed in accordance with the rules specified in RFC 3986, RFC 3987, or (for XMPP) RFC 5122.<br />
<br />
19. Each character set name (or character encoding name -- we use the terms interchangeably) SHOULD be of type NMTOKEN, where the names are separated by the white space character #x20, resulting in a tokenized attribute type of NMTOKENS (see Section 3.3.1 of XML 1.0 [20]). Strictly speaking, the Character Sets registry maintained by the Internet Assigned Numbers Authority (see <http://www.iana.org/assignments/character-sets>) allows a character set name to contain any printable US-ASCII character, which might include characters not allowed by the NMTOKEN construction of XML 1.0; however, the only existing character set name which includes such a character is "NF_Z_62-010_(1973)".<br />
<br />
20. Extensible Markup Language (XML) 1.0 (Fourth Edition) <http://www.w3.org/TR/REC-xml/>.<br />
<br />
21. 9007199254740991 is 253-1. Some weakly typed languages use IEEE Standard 754 Doubles to represent all numbers. These Doubles cannot represent integers above 253 accurately.<br />
<br />
22. RFC 3174: US Secure Hash Algorithm 1 (SHA1) <http://tools.ietf.org/html/rfc3174>.<br />
<br />
23. Therefore a client and a connection manager will be compatible even if one or the other offers no support for multi-stream sessions.<br />
<br />
24. The 'rid' attribute is always incremented normally without reference to any 'stream' attribute.<br />
<br />
25. This helps to ensure backwards-compatibility with older implementations.<br />
<br />
26. Each HTTP response MUST belong to the same session as the request that triggered it, but not necessarily to the same stream.<br />
<br />
27. The broadcast payloads can be of any type.<br />
<br />
28. SSL V3.0 <http://wp.netscape.com/eng/ssl3/draft302.txt>.<br />
<br />
29. RFC 2818: HTTP Over TLS <http://tools.ietf.org/html/rfc2818>.<br />
<br />
30. RFC 2817: Upgrading to TLS Within HTTP/1.1 <http://tools.ietf.org/html/rfc2817>.<br />
<br />
31. RFC 1750: Randomness Recommendations for Security <http://tools.ietf.org/html/rfc1750>.<br />
<br />
32. RFC 4270: Attacks on Cryptographic Hashes in Internet Protocols <http://tools.ietf.org/html/rfc4270>.<br />
<br />
33. The Internet Assigned Numbers Authority (IANA) is the central coordinator for the assignment of unique parameter values for Internet protocols, such as port numbers and URI schemes. For further information, see <http://www.iana.org/>.<br />
<br />
34. IANA registry of port numbers <http://www.iana.org/assignments/port-numbers>.<br />
<br />
35. XEP-0156: Discovering Alternative XMPP Connection Methods <http://xmpp.org/extensions/xep-0156.html>.<br />
===Appendix H: Revision History===<br />
<br />
Note: Older versions of this specification might be available at http://xmpp.org/extensions/attic/<br />
Version 1.10 (2010-07-02)<br />
<br />
Further clarified use of 'from' and 'to' attributes; added missing condition values to the schema.<br />
(psa)<br />
Version 1.9 (2009-11-06)<br />
<br />
Added information for registration of port 5280 with IANA.<br />
(psa)<br />
Version 1.8 (2009-04-30)<br />
<br />
Removed secure attribute because it did not solve the problem it was intended to solve; added security consideration regarding link between connection manager and application server; changed "stanza" to "payload" for disambiguation with XMPP; clarified design objectives and relationship to similar technologies; corrected several errors in the schema.<br />
(psa/jm)<br />
Version 1.7 (2008-10-29)<br />
<br />
Moved alternative script syntax to historical specification; added implementation note about HTTP Pipelining; adjusted architectural description.<br />
(psa)<br />
Version 1.6 (2007-02-21)<br />
<br />
Multiple clarifications and restructuring without changes to protocol itself; changed title to BOSH; added section that fully explains the technique underlying the protocol; separated XMPP-specific features into new XEP-0206; added optional new Script Syntax and session pauses; added Acknowledgements section; added from and ver attributes; added hold attribute to session creation response; clarified polling too-frequently error; recommended that clients use HTTP Pipelining.<br />
(ip)<br />
Version 1.5 (2006-04-28)<br />
<br />
Added optional Multiple Streams section; added security considerations about encrypted HTTP connections; recommended use of SSL rather than HTTP over TLS; specified that request ID values must not exceed 9007199254740991; corrected datatypes of inactivity, polling, rid, and wait attributes in the schema; added <any/> and <anyAttribute/> elements to schema to optionally support non-XMPP XML elements and attributes; deprecated HTTP error codes in favor of new terminal binding conditions.<br />
(ip/psa)<br />
Version 1.4 (2005-12-14)<br />
<br />
Modified syntax of route attribute to be proto:host:port rather than XMPP URI/IRI.<br />
(psa)<br />
Version 1.3 (2005-11-02)<br />
<br />
Corrected stream:features namespace and the Recoverable Binding Conditions section; recommended that connection manager shall return secure attribute to client; recommended end-to-end encryption through proxy connection managers.<br />
(ip)<br />
Version 1.2 (2005-06-16)<br />
<br />
Specified optional use of route and secure attributes in session request. Minor correction: the stream features element should be included in the response that contains the authid attribute (this is not necessarily the session creation response).<br />
(ip)<br />
Version 1.1 (2005-06-02)<br />
<br />
Specified optional use of HTTP Accept-Encoding and Content-Encoding headers for compression at HTTP binding level.<br />
(ip)<br />
Version 1.0 (2005-03-03)<br />
<br />
Per a vote of the Jabber Council, advanced status to Draft.<br />
(psa)<br />
Version 0.10 (2004-11-08)<br />
<br />
Changed HTTP 401 errors to HTTP 404.<br />
(ip)<br />
Version 0.9 (2004-10-26)<br />
<br />
Added charset attribute.<br />
(ip/psa)<br />
Version 0.8 (2004-10-26)<br />
<br />
Specified that wait attribute must be included in the session creation response.<br />
(ip)<br />
Version 0.7 (2004-08-12)<br />
<br />
Defined appropriate XMPP stanza error conditions.<br />
(psa/ip)<br />
Version 0.6 (2004-07-19)<br />
<br />
Added xml:lang attribute to the session request; added recoverable binding error conditions.<br />
(ip)<br />
Version 0.5 (2004-05-07)<br />
<br />
Protocol refactored to enable simultaneous requests (request identifier attribute, wait attribute, hold attribute, requests attribute) and recovery of broken connections; added content attribute; removed all wrapper types except 'terminate'; updated error handling; made key mechanism optional (should use SSL/TLS instead).<br />
(ip/psa)<br />
Version 0.4 (2004-02-23)<br />
<br />
Fixed typos; removed "resource-constraint" binding error; added HTTP 403 error to table.<br />
(psa/ip)<br />
Version 0.3 (2004-02-19)<br />
<br />
Added 'authid' attribute to enable communication of XMPP stream ID (used in digest authentication); specified that Content-Types other than "text/xml" are allowed to support older HTTP clients; specified business rule for connection manager queueing of client requests; changed <packet/> to <body/> to support older HTTP clients; changed 'to' attribute on initialization element from MAY to SHOULD; recommended inclusion of unavailable presence in termination element sent from client; described architectural assumptions; specified binding-specific error handling.<br />
(psa/ip)<br />
Version 0.2 (2004-01-13)<br />
<br />
Added 'to' attribute on the initialization element; specified that 'text/html' is allowable for backwards-compatibility.<br />
(dss/psa/ip)<br />
Version 0.1 (2003-11-06)<br />
<br />
Initial version.<br />
(dss/psa)<br />
<br />
结束</div>
Snowqiang
http://wiki.jabbercn.org/XEP-0124
XEP-0124
2011-05-18T14:16:31Z
<p>Snowqiang: 基本格式</p>
<hr />
<div>[[Category:XMPP扩展]]<br />
[[Category:翻译中]]<br />
<br />
'''本文的英文原文来自[http://www.xmpp.org/extensions/xep-0124.html XEP-0124]'''<br />
<br />
'''XEP-0124: Bidirectional-streams Over Synchronous HTTP (BOSH)'''<br />
<br />
摘要: This specification defines a transport protocol that emulates the semantics of a long-lived, bidirectional TCP connection between two entities (such as a client and a server) by efficiently using multiple synchronous HTTP request/response pairs without requiring the use of frequent polling or chunked responses.<br />
作者: Ian Paterson, Dave Smith, Peter Saint-Andre, Jack Moffitt<br />
版权: © 1999 - 2011 XMPP Standards Foundation. SEE LEGAL NOTICES.<br />
状态: 草案<br />
类型: 标准跟踪<br />
版本: 2.0<br />
最后更新日期: 2010-07-02<br />
<br />
NOTICE: The protocol defined herein is a Draft Standard of the XMPP Standards Foundation. Implementations are encouraged and the protocol is appropriate for deployment in production systems, but some changes to the protocol are possible before it becomes a Final Standard.<br />
<br />
==Introduction==<br />
<br />
The Transmission Control Protocol (TCP; RFC 793 [1]) is often used to establish a stream-oriented connection between two entities. Such connections can often be long-lived to enable an interactive "session" between the entities. However, sometimes the nature of the device or network can prevent an application from maintaining a long-lived TCP connection to a server or peer. In this case, it is desirable to use an alternative connection method that emulates the behavior of a long-lived TCP connection using a sequenced series of requests and responses that are exchanged over short-lived connections. The appropriate request-response semantics are widely available via the Hypertext Transfer Protocol (HTTP) as specified in RFC 1945 [2] and RFC 2616 [3].<br />
<br />
BOSH, the technology defined in this specification, essentially provides a "drop-in" alternative to a long-lived, bidirectional TCP connection. It is a mature, full-featured technology that has been widely implemented and deployed since 2004. To our knowledge it was the first of many similar technologies, which now include the Comet methodology formalized in the Bayeux Protocol [4] as well as The Web Socket Protocol [5] and Reverse HTTP [6].<br />
<br />
BOSH is designed to transport any data efficiently and with minimal latency in both directions. For applications that require both "push" and "pull" semantics, BOSH is significantly more bandwidth-efficient and responsive than most other bidirectional HTTP-based transport protocols and the techniques now commonly known as "Ajax". BOSH achieves this efficiency and low latency by using so-called "long polling" with multiple synchronous HTTP request/response pairs. Furthermore, BOSH can address the needs of constrained clients by employing fully-compliant HTTP 1.0 without the need for "cookies" (see RFC 2965 [7]) [8] or even access to HTTP headers.<br />
<br />
BOSH was originally developed in the Jabber/XMPP community as a replacement for an even earlier HTTP-based technology called Jabber HTTP Polling [9]. Although BOSH assumes that the "payload" of HTTP requests and responses will be XML, the payload formats are not limited to XMPP stanzas (see XMPP Core [10]) and could contain a mixture of elements qualified by namespaces defined by different protocols (e.g., both XMPP and JSON). This mix is necessary because some connection managers might 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 payload is qualified by the correct namespace.<br />
<br />
Note: XMPP Over BOSH [11] documents some XMPP-specific extensions of this protocol that were formerly included in this document.<br />
<br />
==Requirements==<br />
<br />
The following design requirements reflect the need to offer performance as close as possible to a standard TCP connection.<br />
<br />
1. Compatible with constrained runtime environments* (e.g., mobile and browser-based clients).<br />
2. Compatible with proxies that buffer partial HTTP responses.<br />
3. Efficient through proxies that limit the duration of HTTP responses.<br />
4. Fully compatible with HTTP/1.0.<br />
5. Compatible with restricted network connections (e.g., firewalls, proxies, and gateways).<br />
6. Fault tolerant (e.g., session recovers after an underlying TCP connection breaks at any stage during an HTTP request).<br />
7. Extensible.<br />
8. Consume significantly less bandwidth than polling-based protocols.<br />
9. Significantly more responsive (lower latency) than polling-based protocols.<br />
10. Support for polling (for clients that are limited to a single HTTP connection at a time).<br />
11. In-order delivery of data.<br />
12. Guard against unauthorized users injecting HTTP requests into a session.<br />
13. Protect against denial of service attacks.<br />
14. Multiplexing of data streams.<br />
<br />
*Note: Compatibility with constrained runtime environments implies the following restrictions:<br />
<br />
1. Clients are not required to have programmatic access to the headers of each HTTP request and response (e.g., cookies or status codes).<br />
2. The body of each HTTP request and response is parsable XML with a single root element.<br />
3. Clients can specify the Content-Type of the HTTP responses they receive.<br />
<br />
==Architectural Assumptions==<br />
<br />
This document assumes that most implementations will utilize a specialized connection manager ("CM") to handle HTTP connections rather than the native connection type for the relevant application (e.g., TCP connections in XMPP). Effectively, such a connection manager is a specialized HTTP server that translates between the HTTP requests and responses defined herein and the data streams (or API) implemented by the server with which it communicates, thus enabling a client to connect to a server via HTTP on port 80 or 443 instead of an application-specific port. We can illustrate this graphically as follows:<br />
<br />
Server<br />
|<br />
| [unwrapped data streams]<br />
|<br />
HTTP CM<br />
|<br />
| [HTTP + <body/> wrapper]<br />
|<br />
Client<br />
<br />
<br />
This specification covers communication only between a client and the connection manager. It does not cover communication between the connection manager and the server, since such communications are implementation-specific (e.g., the server might 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 might be an independent translating proxy such that the server might believe it is talking directly to the client over TCP; or the connection manager and the server might use a component protocol or an API defined by the server implementation).<br />
<br />
Furthermore, no aspect of this protocol limits its use to communication between a client and a server. For example, it could be used for communication between a server and a peer server if such communication can occur for the relevant application (e.g., in XMPP). 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 the native connection transport for the relevant application. (However, on some unreliable networks, BOSH might enable more stable communication between servers.)<br />
<br />
==The BOSH Technique==<br />
<br />
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).<br />
<br />
The technique employed by BOSH 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.<br />
<br />
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 so to make sure the client can send more data immediately if necessary. (The client SHOULD NOT open more than two HTTP connections to the connection manager at the same time, [12] so it would otherwise have to wait until the connection manager responds to one of the requests.)<br />
<br />
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 TCP 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.<br />
<br />
If there is no traffic in either direction for an agreed amount of time (typically several 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 so 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. [13]<br />
<br />
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. Thus 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. Therefore, 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 were being used.<br />
<br />
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.<br />
<br />
==HTTP Overview==<br />
<br />
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).<br />
<br />
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 permitted by RFC 1945 or RFC 2616. For example, 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 might buffer each partial HTTP request or response and only forward the full request or response once it is available.<br />
<br />
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.<br />
<br />
Requests and responses MAY include HTTP headers not specified herein. The receiver SHOULD ignore any such headers.<br />
<br />
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). However, the responses to requests that are not part of the session sent over the same connection using HTTP pipelining (or queued to be sent over the same connection) might be delayed if they were sent while a request that is part of the session is being held (since the connection manager MUST send its responses in the same order that the requests were received, and the connection manager typically delays its responses).<br />
<br />
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.<br />
<br />
==<body/> Wrapper Element==<br />
<br />
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 transferred. The <body/> element and its content together MUST conform to the specifications set out in XML 1.0 [14]. They SHOULD also conform to Namespaces in XML [15]. The content MUST NOT contain any of the following (all defined in XML 1.0):<br />
<br />
* Partial XML elements<br />
* XML comments<br />
* XML processing instructions<br />
* Internal or external DTD subsets<br />
* Internal or external entity references (with the exception of predefined entities)<br />
<br />
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 "payloads" in this document, e.g., XMPP stanzas as defined in RFC 6120 or elements containing XML character data that represents objects using the JSON data interchange format as defined in RFC 4627 [16]). Each <body/> wrapper MAY contain payloads qualified under a wide variety of different namespaces.<br />
<br />
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.<br />
<br />
==Initiating a BOSH Session==<br />
===Session Creation Request===<br />
<br />
The first request from the client to the connection manager requests a new session.<br />
<br />
The <body/> element of the first request SHOULD possess the following attributes (they SHOULD NOT be included in any other requests except as specified under Adding Streams To A Session):<br />
<br />
* '''<nowiki>'to'</nowiki>''' -- This attribute specifies the target domain of the first stream.<br />
* '''<nowiki>'xml:lang'</nowiki>''' -- This attribute (as defined in Section 2.12 of XML 1.0 [17]) specifies the default language of any human-readable XML character data sent or received during the session.<br />
* '''<nowiki>'ver'</nowiki>''' -- This attribute specifies the highest version of the BOSH protocol that the client supports. The numbering scheme is "<major>.<minor>" (where the minor number MAY be incremented higher than a single digit, so it MUST be treated as a separate integer). Note: The 'ver' attribute should not be confused with the version of any protocol being transported.<br />
* '''<nowiki>'wait'</nowiki>''' -- This attribute specifies the longest time (in seconds) that the connection manager is allowed to wait before responding to any request during the session. This enables the client to limit the delay before it discovers any network failure, and to prevent its HTTP/TCP connection from expiring due to inactivity.<br />
* '''<nowiki>'hold'</nowiki>''' -- This attribute specifies the maximum number of requests the connection manager is allowed to keep waiting at any one time during the session. If the client is not able to use HTTP Pipelining then this SHOULD be set to "1".<br />
<br />
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 both typically one or two orders of magnitude!<br />
<br />
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:example.com:9999"). [18] A connection manager that is configured to work only with a single server (or only with a defined list of domains and the associated list of hostnames and ports that are serving those domains) MAY ignore the 'route' attribute. (Note that the 'to' attribute specifies the domain being served, not the hostname of the machine that is serving the domain.)<br />
<br />
The <body/> element of the first request MAY also possess a 'from' attribute, which specifies the originator of the first stream and which enables the connection manager to forward the originating entity's identity to the application server (e.g., the JabberID of an entity that is connecting to an XMPP server; see XEP-0206).<br />
<br />
A client MAY include an 'ack' attribute (set to "1") to indicate that it will be using acknowledgements throughout the session and that the absence of an 'ack' attribute in any request is meaningful (see Acknowledgements).<br />
<br />
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".<br />
<br />
'''Example 1. Requesting a BOSH session'''<br />
<source lang="xml"><br />
POST /webclient HTTP/1.1<br />
Host: httpcm.example.com<br />
Accept-Encoding: gzip, deflate<br />
Content-Type: text/xml; charset=utf-8<br />
Content-Length: 104<br />
<br />
<body content='text/xml; charset=utf-8'<br />
from='user@example.com'<br />
hold='1'<br />
rid='1573741820'<br />
to='example.com'<br />
route='xmpp:example.com:9999'<br />
ver='1.6'<br />
wait='60'<br />
ack='1'<br />
xml:lang='en'<br />
xmlns='http://jabber.org/protocol/httpbind'/><br />
</source><br />
<br />
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.<br />
===Session Creation Response===<br />
<br />
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):<br />
<br />
* '''<nowiki>'sid'</nowiki>''' -- This attribute specifies the SID<br />
* '''<nowiki>'wait'</nowiki>''' -- This is the longest time (in seconds) that the connection manager will wait before responding to any request during the session. The time MUST be less than or equal to the value specified in the session request.<br />
<br />
The <body/> element SHOULD also include the following attributes (they SHOULD NOT be included in any other responses):<br />
<br />
* '''<nowiki>'ver'</nowiki>''' -- This attribute specifies the highest version of the BOSH protocol that the connection manager supports, or the version specified by the client in its request, whichever is lower.<br />
* '''<nowiki>'polling'</nowiki>''' -- This attribute specifies the shortest allowable polling interval (in seconds). This enables the client to not send empty request elements more often than desired (see Polling Sessions and Overactivity).<br />
* '''<nowiki>'inactivity'</nowiki>''' -- This attribute specifies the longest allowable inactivity period (in seconds). This enables the client to ensure that the periods with no requests pending are never too long (see Polling Sessions and Inactivity).<br />
* '''<nowiki>'requests'</nowiki>''' -- This attribute enables the connection manager to limit the number of simultaneous requests the client makes (see Overactivity and Polling Sessions). The RECOMMENDED values are either "2" or one more than the value of the 'hold' attribute specified in the session request.<br />
* '''<nowiki>'hold'</nowiki>''' -- This attribute informs the client about the maximum number of requests the connection manager will keep waiting at any one time during the session. This value MUST NOT be greater than the value specified by the client in the session request.<br />
* '''<nowiki>'to'</nowiki>''' -- This attribute communicates the identity of the backend server to which the client is attempting to connect.<br />
<br />
The connection manager MAY include an 'accept' attribute in the session creation response element, to specify a space-separated list of 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.<br />
<br />
A connection manager MAY include an 'ack' attribute (set to the value of the 'rid' attribute of the session creation request) to indicate that it will be using acknowledgements throughout the session and that the absence of an 'ack' attribute in any response is meaningful (see Acknowledgements).<br />
<br />
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 can request.<br />
<br />
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. [19]<br />
<br />
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 a BOSH Session), then in the same response the connection manager SHOULD also include the 'secure' attribute set to "true" or "1".<br />
<br />
'''Example 2. Session creation response'''<br />
<source lang="xml"><br />
HTTP/1.1 200 OK<br />
Content-Type: text/xml; charset=utf-8<br />
Content-Length: 128<br />
<br />
<body wait='60'<br />
inactivity='30'<br />
polling='5'<br />
requests='2'<br />
hold='1'<br />
ack='1573741820'<br />
accept='deflate,gzip'<br />
maxpause='120'<br />
sid='SomeSID'<br />
charsets='ISO_8859-1 ISO-2022-JP'<br />
ver='1.6'<br />
from='example.com'<br />
xmlns='http://jabber.org/protocol/httpbind'/><br />
</source><br />
<br />
'''Example 3. Subsequent response with 'from' and 'secure' attributes'''<br />
<source lang="xml"><br />
HTTP/1.1 200 OK<br />
Content-Type: text/xml; charset=utf-8<br />
Content-Length: 128<br />
<br />
<body from='example.com'<br />
xmlns='http://jabber.org/protocol/httpbind'/><br />
</source><br />
<br />
==Sending and Receiving XML Payloads==<br />
<br />
After the client has successfully completed all required preconditions, it can send and receive XML payloads via the HTTP binding.<br />
<br />
'''Example 4. Transmitting payloads'''<br />
<source lang="xml"><br />
POST /webclient HTTP/1.1<br />
Host: httpcm.example.com<br />
Accept-Encoding: gzip, deflate<br />
Content-Type: text/xml; charset=utf-8<br />
Content-Length: 188<br />
<br />
<body rid='1249243562'<br />
sid='SomeSID'<br />
xmlns='http://jabber.org/protocol/httpbind'><br />
<message to='contact@example.com'<br />
xmlns='jabber:client'><br />
<body>Good morning!</body><br />
</message><br />
<message to='friend@example.com'<br />
xmlns='jabber:client'><br />
<body>Hey, what&apos;s up?</body><br />
</message><br />
</body><br />
</source><br />
<br />
Upon receipt of a request, the connection manager SHOULD forward the content of the <body/> element to the server as soon as possible. In any case it MUST forward the content from different requests in the order specified by their 'rid' attributes.<br />
<br />
The connection manager MUST also return an HTTP 200 OK response with a <body/> element to the client. Note: This does not indicate that the payloads have been successfully delivered to the application server.<br />
<br />
It is RECOMMENDED that the connection manager not return an HTTP result until a payload has arrived from the application server for delivery to the client. However, the connection manager SHOULD NOT wait longer than the time specified by the client in the 'wait' attribute of its Session Creation Request, and it SHOULD NOT keep more HTTP requests waiting at a time than the number specified in the 'hold' attribute of the session creation request. In any case it MUST respond to requests in the order specified by their 'rid' attributes.<br />
<br />
If there are no payloads waiting or ready to be delivered within the waiting period, then the connection manager SHOULD include an empty <body/> element in the HTTP result:<br />
<br />
'''Example 5. Empty response'''<br />
<source lang="xml"><br />
HTTP/1.1 200 OK<br />
Content-Type: text/xml; charset=utf-8<br />
Content-Length: 64<br />
<br />
<body xmlns='http://jabber.org/protocol/httpbind'/><br />
</source><br />
<br />
If the connection manager has received one or more payloads from the application server for delivery to the client, then it SHOULD return the payloads in the body of its response as soon as possible after receiving them from the server. The example below includes payloads qualified by different namespaces:<br />
<br />
'''Example 6. Response with queued stanza'''<br />
<source lang="xml"><br />
HTTP/1.1 200 OK<br />
Content-Type: text/xml; charset=utf-8<br />
Content-Length: 185<br />
<br />
<body xmlns='http://jabber.org/protocol/httpbind'<br />
xmlns:json='http://json.org/'><br />
<message from='contact@example.com'<br />
to='user@example.com'<br />
xmlns='jabber:client'><br />
<body>Good morning to you!</body><br />
</message><br />
<message from='friend@example.com'<br />
to='user@example.com'<br />
xmlns='jabber:client'><br />
<body>Not much, how about with you?</body><br />
</message><br />
<json:json><br />
[<br />
{<br />
"precision": "zip",<br />
"Latitude": 37.7668,<br />
"Longitude": -122.3959,<br />
"Address": "",<br />
"City": "SAN FRANCISCO",<br />
"State": "CA",<br />
"Zip": "94107",<br />
"Country": "US"<br />
},<br />
{<br />
"precision": "zip",<br />
"Latitude": 37.371991,<br />
"Longitude": -122.026020,<br />
"Address": "",<br />
"City": "SUNNYVALE",<br />
"State": "CA",<br />
"Zip": "94085",<br />
"Country": "US"<br />
}<br />
]<br />
</json:json><br />
</body><br />
</source><br />
<br />
The client MAY poll the connection manager for incoming payloads by sending an empty <body/> element.<br />
<br />
'''Example 7. Requesting XML Payloads'''<br />
<source lang="xml"><br />
POST /webclient HTTP/1.1<br />
Host: httpcm.example.com<br />
Accept-Encoding: gzip, deflate<br />
Content-Type: text/xml; charset=utf-8<br />
Content-Length: 88<br />
<br />
<body rid='1249243563'<br />
sid='SomeSID'<br />
xmlns='http://jabber.org/protocol/httpbind'/><br />
</source><br />
<br />
The connection manager MUST wait and respond in the same way as it does after receiving payloads from the client.<br />
<br />
==Acknowledgements==<br />
===Request Acknowledgements===<br />
<br />
When responding to a request that it has been holding, if the connection manager finds it has already received another request with a higher 'rid' attribute (typically while it was holding the first request), then it MAY acknowledge the reception to the client. The connection manager MAY set the 'ack' attribute of any response to the value of the highest 'rid' attribute it has received in the case where it has also received all requests with lower 'rid' values.<br />
<br />
'''Example 8. Response with request acknowledgement'''<br />
<source lang="xml"><br />
HTTP/1.1 200 OK<br />
Content-Type: text/xml; charset=utf-8<br />
Content-Length: 64<br />
<br />
<body ack='1249243564'<br />
xmlns='http://jabber.org/protocol/httpbind'/><br />
</source><br />
<br />
If the connection manager will be including 'ack' attributes on responses during a session, then it MUST include an 'ack' attribute in its session creation response, and set the 'ack' attribute of responses throughout the session. The only exception is that, after its session creation response, the connection manager SHOULD NOT include an 'ack' attribute in any response if the value would be the 'rid' of the request being responded to.<br />
<br />
If the connection manager is permitted to hold more than one request at a time, then the reception of a lower-than-expected 'ack' value from the connection manager (or the unexpected abscence of an 'ack' attribute) can give the client an early warning that a network failure might have occurred (e.g., if the client believes the connection manager should have received another request by the time it responded).<br />
===Response Acknowledgements===<br />
<br />
The client MAY similarly inform the connection manager about the responses it has received by setting the 'ack' attribute of any request to the value of the highest 'rid' of a request for which it has already received a response in the case where it has also received all responses associated with lower 'rid' values. If the client will be including 'ack' attributes on requests during a session, then it MUST include an 'ack' attribute (set to '1') in its session creation request, and set the 'ack' attribute of requests throughout the session. The only exception is that, after its session creation request, the client SHOULD NOT include an 'ack' attribute in any request if it has received responses to all its previous requests.<br />
<br />
'''Example 9. Request with response acknowledgement'''<br />
<source lang="xml"><br />
POST /webclient HTTP/1.1<br />
Host: httpcm.example.com<br />
Accept-Encoding: gzip, deflate<br />
Content-Type: text/xml; charset=utf-8<br />
Content-Length: 88<br />
<br />
<body rid='1249243566'<br />
sid='SomeSID'<br />
ack='1249243564'<br />
xmlns='http://jabber.org/protocol/httpbind'/><br />
</source><br />
<br />
After receiving a request with an 'ack' value less than the 'rid' of the last request that it has already responded to, the connection manager MAY inform the client of the situation by sending its next response immediately instead of waiting until it has payloads to send to the client (e.g., if some time has passed since it responded). In this case it SHOULD include a 'report' attribute set to one greater than the 'ack' attribute it received from the client, and a 'time' attribute set to the number of milliseconds since it sent the response associated with the 'report' attribute.<br />
<br />
'''Example 10. Response with report'''<br />
<source lang="xml"><br />
HTTP/1.1 200 OK<br />
Content-Type: text/xml; charset=utf-8<br />
Content-Length: 64<br />
<br />
<body report='1249243565'<br />
time='852'<br />
xmlns='http://jabber.org/protocol/httpbind'/><br />
</source><br />
<br />
Upon reception of a response with 'report' and 'time' attributes, if the client has still not received the response associated with the request identifier specified by the 'report' attribute, then it MAY choose to resend the request associated with the missing response (see Broken Connections).<br />
<br />
==Inactivity==<br />
<br />
After receiving a response from the connection manager, if none of the client's requests are still being held by the connection manager (and if the session is not a Polling Session), the client SHOULD make a new request as soon as possible. In any case, if no requests are being held, the client MUST make a new request before the maximum inactivity period has expired. The length of this period (in seconds) is specified by the 'inactivity' attribute in the session creation response.<br />
<br />
If the connection manager has responded to all the requests it has received within a session and the time since its last response is longer than the maximum inactivity period, then it SHOULD assume the client has been disconnected and terminate the session without informing the client. If the client subsequently makes another request, then the connection manager SHOULD respond as if the session does not exist.<br />
<br />
If the connection manager did not specify a maximum inactivity period in the session creation response, then it SHOULD allow the client to be inactive for as long as it chooses.<br />
<br />
If the session is not a polling session then the connection manager SHOULD specify a relatively short inactivity period to ensure that disconnections are discovered as quickly as possible. The RECOMMENDED time would be a little more than the number of seconds for a comfortable network round trip between the connection manager and the client under difficult network conditions (since the client can be expected to make a new request immediately -- see above).<br />
<br />
If a client encounters an exceptional temporary situation during which it will be unable to send requests to the connection manager for a period of time greater than the maximum inactivity period (e.g., while a runtime environment changes from one web page to another), and if the connection manager included a 'maxpause' attribute in its Session Creation Response, then the client MAY request a temporary increase to the maximum inactivity period by including a 'pause' attribute in a request. Note: If the connection manager did not specify a 'maxpause' attribute at the start of the session then the client MUST NOT send a 'pause' attribute during the session.<br />
<br />
'''Example 11. Requesting a Session Pause'''<br />
<source lang="xml"><br />
POST /webclient HTTP/1.1<br />
Host: httpcm.example.com<br />
Accept-Encoding: gzip, deflate<br />
Content-Type: text/xml; charset=utf-8<br />
Content-Length: 98<br />
<br />
<body rid='1249243564'<br />
sid='SomeSID'<br />
pause='60'<br />
xmlns='http://jabber.org/protocol/httpbind'/><br />
</source><br />
<br />
Upon reception of a session pause request, if the requested period is not greater than the maximum permitted time, then the connection manager SHOULD respond immediately to all pending requests (including the pause request) and temporarily increase the maximum inactivity period to the requested time. Note: The response to the pause request MUST NOT contain any payloads.<br />
<br />
Note: If the client simply wants the connection manager to return all the requests it is holding then it MAY set the value of the 'pause' attribute to be the value of the 'inactivity' attribute in the connection manager's session creation response. (If the client believes it is in danger of becoming disconnected indefinitely then it MAY even request a temporary reduction of the maximum inactivity period by specifying a 'pause' value less than the 'inactivity' value, thus enabling the connection manager to discover any subsequent disconnection more quickly.)<br />
<br />
The connection manager SHOULD set the maximum inactivity period back to normal upon reception of the next request from the client (assuming the connection manager has not already terminated the session).<br />
11. Overactivity<br />
<br />
The client SHOULD NOT make more simultaneous requests than specified by the 'requests' attribute in the connection manager's Session Creation Response. However the client MAY make one additional request if it is to pause or terminate a session.<br />
<br />
If during any period the client sends a sequence of new requests (i.e. requests with incremented rid attributes, not repeat requests) longer than the number specified by the 'requests' attribute, and if the connection manager has not yet responded to any of the requests, and if the last request did not include either a 'pause' attribute or a 'type' attribute set to "terminate", then the connection manager SHOULD consider that the client is making too many simultaneous requests, and terminate the HTTP session with a 'policy-violation' terminal binding error to the client. Note: This behavior applies to equally to normal and polling sessions.<br />
<br />
'''Example 12. Too many simultaneous requests response'''<br />
<source lang="xml"><br />
HTTP/1.1 200 OK<br />
Content-Type: text/xml; charset=utf-8<br />
Content-Length: 68<br />
<br />
<body type='terminate'<br />
condition='policy-violation'<br />
xmlns='http://jabber.org/protocol/httpbind'/><br />
</source><br />
<br />
Note: If the connection manager did not specify a 'requests' attribute in the session creation response, then it MUST allow the client to send as many simultaneous requests as it chooses.<br />
<br />
If during any period the client sends a sequence of new requests equal in length to the number specified by the 'requests' attribute, and if the connection manager has not yet responded to any of the requests, and if the last request was empty and did not include either a 'pause' attribute or a 'type' attribute set to "terminate", and if the last two requests arrived within a period shorter than the number of seconds specified by the 'polling' attribute in the session creation response, then the connection manager SHOULD consider that the client is making requests more frequently than it was permitted and terminate the HTTP session and return a 'policy-violation' terminal binding error to the client. Note: the behavior for Polling Sessions is slightly different.<br />
<br />
'''Example 13. Too frequent requests response'''<br />
<source lang="xml"><br />
HTTP/1.1 200 OK<br />
Content-Type: text/xml; charset=utf-8<br />
Content-Length: 68<br />
<br />
<body type='terminate'<br />
condition='policy-violation'<br />
xmlns='http://jabber.org/protocol/httpbind'/><br />
</source><br />
<br />
Note: If the connection manager did not specify a 'polling' attribute in the session creation response, then it MUST allow the client to send requests as frequently as it chooses.<br />
<br />
==Polling Sessions==<br />
<br />
It is not always possible for a constrained client to either use HTTP Pipelining or open more than one HTTP connection with the connection manager at a time. In this case the client SHOULD inform the connection manager by setting the values of the 'wait' and/or 'hold' attributes in its session creation request to "0", and then "poll" the connection manager at regular intervals throughout the session for payloads it might have received from the server. Note: Even if the client does not request a polling session, the connection manager MAY require a client to use polling by setting the 'requests' attribute (which specifies the number of simultaneous requests the client can make) of its Session Creation Response to "1", however this is NOT RECOMMENDED.<br />
<br />
If a session will use polling, the connection manager SHOULD specify a higher than normal value for the 'inactivity' attribute (see Inactivity) in its session creation response. The increase SHOULD be greater than the value it specifies for the 'polling' attribute.<br />
<br />
If the client sends two consecutive empty new requests (i.e. requests with incremented rid attributes, not repeat requests) within a period shorter than the number of seconds specified by the 'polling' attribute (the shortest allowable polling interval) in the session creation response, and if the connection manager's response to the first request contained no payloads, then upon reception of the second request the connection manager SHOULD terminate the HTTP session and return a 'policy-violation' terminal binding error to the client.<br />
<br />
'''Example 14. Too frequent polling response'''<br />
<source lang="xml"><br />
HTTP/1.1 200 OK<br />
Content-Type: text/xml; charset=utf-8<br />
Content-Length: 68<br />
<br />
<body type='terminate'<br />
condition='policy-violation'<br />
xmlns='http://jabber.org/protocol/httpbind'/><br />
</source><br />
<br />
Note: If the connection manager did not specify a 'polling' attribute in the session creation response, then it MUST allow the client to poll as frequently as it chooses.<br />
<br />
==Terminating the HTTP Session==<br />
<br />
At any time, the client MAY gracefully terminate the session by sending a <body/> element with a 'type' attribute set to "terminate". The termination request MAY include one or more payloads that the connection manager MUST forward to the server to ensure graceful logoff.<br />
<br />
'''Example 15. Session termination by client'''<br />
<source lang="xml"><br />
POST /webclient HTTP/1.1<br />
Host: httpcm.example.com<br />
Accept-Encoding: gzip, deflate<br />
Content-Type: text/xml; charset=utf-8<br />
Content-Length: 153<br />
<br />
<body rid='1249243565'<br />
sid='SomeSID'<br />
type='terminate'<br />
xmlns='http://jabber.org/protocol/httpbind'><br />
<presence type='unavailable'<br />
xmlns='jabber:client'/><br />
</body><br />
</source><br />
<br />
The connection manager SHOULD respond to this request with an HTTP 200 OK containing an empty <body/> element.<br />
<br />
'''Example 16. Connection manager acknowledges termination'''<br />
<source lang="xml"><br />
HTTP/1.1 200 OK<br />
Content-Type: text/xml; charset=utf-8<br />
Content-Length: 72<br />
<br />
<body type='terminate'<br />
xmlns='http://jabber.org/protocol/httpbind'/><br />
</source><br />
<br />
Upon receiving the response, the client MUST consider the HTTP session to have been terminated.<br />
<br />
==Request IDs==<br />
===Generation===<br />
<br />
The client MUST generate a large, random, positive integer for the initial 'rid' (see Security Considerations) and then increment that value by one for each subsequent request. The client MUST take care to choose an initial 'rid' that will never be incremented above 9007199254740991 [21] within the session. In practice, a session would have to be extraordinarily long (or involve the exchange of an extraordinary number of packets) to exceed the defined limit.<br />
===In-Order Message Forwarding===<br />
<br />
When a client makes simultaneous requests, the connection manager might receive them out of order. The connection manager MUST forward the payloads to the server and respond to the client requests in the order specified by the 'rid' attributes. The client MUST process responses received from the connection manager in the order the requests were made.<br />
<br />
The connection manager SHOULD expect the 'rid' attribute to be within a window of values greater than the 'rid' of the previous request. The size of the window is equal to the maximum number of simultaneous requests allowed by the connection manager. If it receives a request with a 'rid' greater than the values in the window, then the connection manager MUST terminate the session with an error:<br />
<br />
'''Example 17. Unexpected rid error'''<br />
<source lang="xml"><br />
HTTP/1.1 200 OK<br />
Content-Type: text/xml; charset=utf-8<br />
Content-Length: 68<br />
<br />
<body type='terminate'<br />
condition='item-not-found'<br />
xmlns='http://jabber.org/protocol/httpbind'/><br />
</source><br />
<br />
===Broken Connections===<br />
<br />
Unreliable network communications or client constraints can result in broken connections. The connection manager SHOULD remember the 'rid' and the associated HTTP response body of the client's most recent requests which were not session pause requests (see Inactivity) and which did not result in an HTTP or binding error. The number of responses to non-pause requests kept in the buffer SHOULD be either the same as the maximum number of simultaneous requests allowed by the connection manager or, if Acknowledgements are being used, the number of responses that have not yet been acknowledged.<br />
<br />
If the network connection is broken or closed before the client receives a response to a request from the connection manager, then the client MAY resend an exact copy of the original request. Whenever the connection manager receives a request with a 'rid' that it has already received, it SHOULD return an HTTP 200 (OK) response that includes the buffered copy of the original XML response to the client (i.e., a <body/> wrapper possessing appropriate attributes and optionally containing one or more XML payloads). If the original response is not available (e.g., it is no longer in the buffer), then the connection manager MUST return an 'item-not-found' terminal binding error:<br />
<br />
'''Example 18. Response not in buffer error'''<br />
<source lang="xml"><br />
HTTP/1.1 200 OK<br />
Content-Type: text/xml; charset=utf-8<br />
Content-Length: 68<br />
<br />
<body type='terminate'<br />
condition='item-not-found'<br />
xmlns='http://jabber.org/protocol/httpbind'/><br />
</source><br />
<br />
Note: The error is the same whether the 'rid' is too large or too small. This makes it more difficult for an attacker to discover an acceptable value.<br />
<br />
==Protecting Insecure Sessions==<br />
===Applicability===<br />
<br />
The OPTIONAL key sequencing mechanism described here MAY be used if the client's session with the connection manager is not secure. The session SHOULD be considered secure only if all client requests are made via SSL (or TLS) HTTP connections and the connection manager generates an unpredictable session ID. If the session is secure, it is not necessary to use this key sequencing mechanism.<br />
<br />
Even if the session is not secure, the unpredictable session and request IDs specified in the preceding sections of this document already provide a level of protection similar to that provided by a connection bound to a single pair of persistent TCP/IP connections, and thus provide sufficient protection against a 'blind' attacker. However, in some circumstances, the key sequencing mechanism defined below helps to protect against a more determined and knowledgeable attacker.<br />
<br />
It is important to recognize that the key sequencing mechanism defined below helps to protect only against an attacker who is able to view the contents of all requests or responses in an insecure session but who is not able to alter the contents of those requests (in this case, the mechanism prevents the attacker from injecting HTTP requests into the session, e.g., termination requests or responses). However, the key sequencing mechanism does not provide any protection when the attacker is able to alter the contents of insecure requests or responses.<br />
===Introduction===<br />
<br />
The HTTP requests of each session MAY be spread across a series of different socket connections. This would enable an unauthorized user that obtains the session ID and request ID of a session to then use their own socket connection to inject <body/> request elements into the session and receive the corresponding responses.<br />
<br />
The key sequencing mechanism below protects against such attacks by enabling a connection manager to detect <body/> request elements injected by a third party.<br />
===Generating the Key Sequence===<br />
<br />
Prior to requesting a new session, the client MUST select an unpredictable counter ("n") and an unpredictable value ("seed"). The client then processes the "seed" through a cryptographic hash and converts the resulting 160 bits to a hexadecimal string K(1). It does this "n" times to arrive at the initial key K(n). The hashing algorithm MUST be SHA-1 as defined in RFC 3174 [22].<br />
<br />
'''Example 19. Creating the key sequence'''<br />
<br />
K(1) = hex(SHA-1(seed))<br />
K(2) = hex(SHA-1(K(1)))<br />
...<br />
K(n) = hex(SHA-1(K(n-1)))<br />
<br />
<br />
===Use of Keys===<br />
<br />
The client MUST set the 'newkey' attribute of the first request in the session to the value K(n).<br />
<br />
'''Example 20. Session Request with Initial Key'''<br />
<source lang="xml"><br />
POST /webclient HTTP/1.1<br />
Host: httpcm.example.com<br />
Accept-Encoding: gzip, deflate<br />
Content-Type: text/xml; charset=utf-8<br />
Content-Length: 104<br />
<br />
<body content='text/xml; charset=utf-8'<br />
hold='1'<br />
rid='1573741820'<br />
to='example.com'<br />
wait='60'<br />
xml:lang='en'<br />
newkey='ca393b51b682f61f98e7877d61146407f3d0a770'<br />
xmlns='http://jabber.org/protocol/httpbind'/><br />
</source><br />
<br />
The client MUST set the 'key' attribute of all subsequent requests to the value of the next key in the generated sequence (decrementing from K(n-1) towards K(1) with each request sent).<br />
<br />
'''Example 21. Request with Key'''<br />
<source lang="xml"><br />
POST /webclient HTTP/1.1<br />
Host: httpcm.example.com<br />
Accept-Encoding: gzip, deflate<br />
Content-Type: text/xml; charset=utf-8<br />
Content-Length: 88<br />
<br />
<body rid='1573741821'<br />
sid='SomeSID'<br />
key='bfb06a6f113cd6fd3838ab9d300fdb4fe3da2f7d'<br />
xmlns='http://jabber.org/protocol/httpbind'/><br />
</source><br />
<br />
The connection manager MAY verify the key by calculating the SHA-1 hash of the key and comparing it to the 'newkey' attribute of the previous request (or the 'key' attribute if the 'newkey' attribute was not set). If the values do not match (or if it receives a request without a 'key' attribute and the 'newkey' or 'key' attribute of the previous request was set), then the connection manager MUST NOT process the element, MUST terminate the session, and MUST return an 'item-not-found' terminal binding error.<br />
<br />
'''Example 22. Invalid Key Sequence Error'''<br />
<source lang="xml"><br />
HTTP/1.1 200 OK<br />
Content-Type: text/xml; charset=utf-8<br />
Content-Length: 68<br />
<br />
<body type='terminate'<br />
condition='item-not-found'<br />
xmlns='http://jabber.org/protocol/httpbind'/><br />
</source><br />
<br />
===Switching to Another Key Sequence===<br />
<br />
A client SHOULD choose a high value for "n" when generating the key sequence. However, if the session lasts long enough that the client arrives at the last key in the sequence K(1) then the client MUST switch to a new key sequence.<br />
<br />
The client MUST:<br />
<br />
1. Choose new values for "seed" and "n".<br />
2. Generate a new key sequence using the algorithm defined above.<br />
3. Set the 'key' attribute of the request to the next value in the old sequence (i.e. K(1), the last value).<br />
4. Set the 'newkey' attribute of the request to the value K(n) from the new sequence.<br />
<br />
'''Example 23. New Key Sequence'''<br />
<source lang="xml"><br />
POST /webclient HTTP/1.1<br />
Host: httpcm.example.com<br />
Accept-Encoding: gzip, deflate<br />
Content-Type: text/xml; charset=utf-8<br />
Content-Length: 188<br />
<br />
<body rid='1573741822'<br />
sid='SomeSID'<br />
key='6f825e81f4532b2c5fa2d12457d8a1f22e8f838e'<br />
newkey='113f58a37245ec9637266cf2fb6e48bfeaf7964e'<br />
xmlns='http://jabber.org/protocol/httpbind'><br />
<message to='contact@example.com'<br />
xmlns='jabber:client'><br />
<body>I said "Hi!"</body><br />
</message><br />
</body><br />
</source><br />
<br />
==Multiple Streams==<br />
===Introduction===<br />
<br />
The OPTIONAL feature described in this section enables multiple XML streams to be contained within a single HTTP session. This feature is essential in runtime environments that prevent HTTP Pipelining, thereby constraining the number of simultaneous HTTP requests a client can make to each connection manager, since clients running in such environments need multi-stream sessions if they are to connect using more than one account at the same time. This feature also reduces network traffic for any client that needs to establish parallel streams over HTTP.<br />
===Discovery===<br />
<br />
If a connection manager supports the multi-streams feature, it MUST include a 'stream' attribute in its Session Creation Response. If a client does not receive the 'stream' attribute then it MUST assume that the connection manager does not support the feature. [23]<br />
<br />
The 'stream' attribute identifies the first stream to be opened for the session. The value of each 'stream' attribute MUST be an opaque and unpredictable name that is unique within the context of the connection manager application.<br />
<br />
'''Example 24. Session creation response with stream name'''<br />
<source lang="xml"><br />
HTTP/1.1 200 OK<br />
Content-Type: text/xml; charset=utf-8<br />
Content-Length: 128<br />
<br />
<body wait='60'<br />
inactivity='30'<br />
polling='5'<br />
requests='2'<br />
hold='1'<br />
accept='deflate,gzip'<br />
stream='firstStreamName'<br />
maxpause='120'<br />
sid='SomeSID'<br />
charsets='ISO_8859-1 ISO-2022-JP'<br />
ver='1.6'<br />
from='example.com'<br />
xmlns='http://jabber.org/protocol/httpbind'/><br />
</source><br />
<br />
===Adding Streams To A Session===<br />
<br />
If the connection manager included a 'stream' attribute in its session creation response then the client MAY ask it to open another stream at any time by sending it an empty <body/> element with a 'to' attribute. The request MUST include valid 'sid' and 'rid' [24] attributes, and SHOULD also include an 'xml:lang' attribute. The request MAY include 'route', 'from' and 'secure' attributes (see Session Creation Request), but it SHOULD NOT include 'ver', 'content', 'hold' or 'wait' attributes (since a new session is not being created).<br />
<br />
'''Example 25. Requesting another stream'''<br />
<source lang="xml"><br />
POST /webclient HTTP/1.1<br />
Host: httpcm.example.com<br />
Accept-Encoding: gzip, deflate<br />
Content-Type: text/xml; charset=utf-8<br />
Content-Length: 104<br />
<br />
<body sid='SomeSID'<br />
rid='1573741820'<br />
to='example.com'<br />
route='xmpp:example.com:9999'<br />
xml:lang='en'<br />
xmlns='http://jabber.org/protocol/httpbind'/><br />
</source><br />
<br />
If the connection manager did not indicate its support for multiple streams at the start of the session, then it MUST ignore the extra attributes and treat the request as a normal empty request for payloads (see Sending and Receiving XML Payloads). [25] Otherwise it MUST open a new stream with the specified server (see Session Creation Response), generate a new stream name, and respond to the client with the name. The response MAY also include 'from' and 'secure' attributes, but it SHOULD NOT include 'sid', 'requests', 'polling', 'hold', 'inactivity', 'maxpause', 'accept', 'charsets', 'ver' or 'wait' attributes.<br />
<br />
'''Example 26. Add stream response'''<br />
<source lang="xml"><br />
HTTP/1.1 200 OK<br />
Content-Type: text/xml; charset=utf-8<br />
Content-Length: 128<br />
<br />
<body stream='secondStreamName'<br />
from='example.com'<br />
xmlns='http://jabber.org/protocol/httpbind'/><br />
</source><br />
<br />
Note: If the response did not include either 'from' or 'secure' attributes then they MAY be sent in a subsequent response instead (see Session Creation Response). In that case the 'stream' attribute MUST also be specified.<br />
===Transmitting Payloads===<br />
<br />
If more than one stream has been opened within a session, then all non-empty <body/> elements sent by the connection manager MUST include a 'stream' attribute that specifies which stream all the payloads it contains belong to. The client SHOULD include a 'stream' attribute for the same purpose. The client MAY omit the 'stream' attribute if it wants the connection manager to broadcast the payloads over all open streams. Note: A <body/> element MUST NOT contain different payloads for different streams.<br />
<br />
If a stream name does not correspond to one of the session's open streams, then the receiving connection manager SHOULD return an 'item-not-found' terminal binding error, or the receiving client SHOULD terminate the session. However, if the receiving entity has only just closed the stream (and the sender might not have been aware of that when it sent the payloads), then it MAY instead simply silently ignore any payloads the <body/> element contains.<br />
<br />
Note: Empty <body/> elements that do not include a 'from' or 'secure' attribute SHOULD NOT include a 'stream' attribute (since nothing is being transmitted for any stream). If such a <body/> element does include a 'stream' attribute then the receiving entity SHOULD ignore the attribute.<br />
<br />
'''Example 27. Client sends payload with a stream name'''<br />
<source lang="xml"><br />
POST /webclient HTTP/1.1<br />
Host: httpcm.example.com<br />
Accept-Encoding: gzip, deflate<br />
Content-Type: text/xml; charset=utf-8<br />
Content-Length: 188<br />
<br />
<body rid='1249243562'<br />
sid='SomeSID'<br />
stream='secondStreamName'<br />
xmlns='http://jabber.org/protocol/httpbind'><br />
<message to='contact@example.com'<br />
xmlns='jabber:client'><br />
<body>I said hello.</body><br />
</message><br />
</body><br />
</source><br />
<br />
Note: The value of the 'stream' attribute of the response MAY be different than the corresponding request. [26]<br />
<br />
'''Example 28. Connection manager responds with a different stream name'''<br />
<source lang="xml"><br />
HTTP/1.1 200 OK<br />
Content-Type: text/xml; charset=utf-8<br />
Content-Length: 185<br />
<br />
<body stream='firstStreamName'<br />
xmlns='http://jabber.org/protocol/httpbind'><br />
<message from='contact@example.com'<br />
to='user@example.com'<br />
xmlns='jabber:client'><br />
<body>Hi yourself!</body><br />
</message><br />
</body><br />
</source><br />
<br />
If no stream name is specified by the connection manager then the client MUST assume the payloads are associated with the first stream (even if the first stream has been closed).<br />
<br />
If no stream name is specified by the client then the connection manager MUST broadcast the payloads over all open streams. [27]<br />
<br />
'''Example 29. Client asks for a payload to be broadcast'''<br />
<source lang="xml"><br />
POST /webclient HTTP/1.1<br />
Host: httpcm.example.com<br />
Accept-Encoding: gzip, deflate<br />
Content-Type: text/xml; charset=utf-8<br />
Content-Length: 188<br />
<br />
<body rid='1249243562'<br />
sid='SomeSID'<br />
xmlns='http://jabber.org/protocol/httpbind'><br />
<presence xmlns='jabber:client'><br />
<show>away</show><br />
</presence><br />
</body><br />
</source><br />
<br />
===Closing a Stream===<br />
<br />
If more than one stream is open within a session, the client MAY close one open stream at any time using the procedure described in the section Terminating the HTTP Session above, taking care to specify the stream name with a 'stream' attribute. If the client closes the last stream the connection manager MUST terminate the session. If the client does not specify a stream name then the connection manager MUST close all open streams (sending any payloads the terminate request contains to all streams), and terminate the session.<br />
<br />
'''Example 30. Client closes one stream'''<br />
<source lang="xml"><br />
POST /webclient HTTP/1.1<br />
Host: httpcm.example.com<br />
Accept-Encoding: gzip, deflate<br />
Content-Type: text/xml; charset=utf-8<br />
Content-Length: 153<br />
<br />
<body rid='1249243564'<br />
sid='SomeSID'<br />
stream='secondStreamName'<br />
type='terminate'<br />
xmlns='http://jabber.org/protocol/httpbind'><br />
<presence type='unavailable'<br />
xmlns='jabber:client'/><br />
</body><br />
</source><br />
<br />
===Error Conditions===<br />
<br />
If more than one stream is open within a session, the connection manager MAY include a 'stream' attribute in a fatal binding error (see Terminal Binding Conditions). If a 'stream' attribute is specified then the stream MUST be closed by both entities but the session SHOULD NOT be terminated.<br />
<br />
'''Example 31. Fatal stream error'''<br />
<source lang="xml"><br />
HTTP/1.1 200 OK<br />
Content-Type: text/xml; charset=utf-8<br />
Content-Length: 68<br />
<br />
<body type='terminate'<br />
condition='remote-connection-failed'<br />
stream='secondStreamName'<br />
xmlns='http://jabber.org/protocol/httpbind'/><br />
</source><br />
<br />
Note: If the connection manager does not include a 'stream' attribute in a fatal binding error then all the session's open streams MUST be closed by both entities and the session MUST be terminated.<br />
<br />
==Error and Status Codes==<br />
<br />
There are four types of error and status reporting in HTTP responses:<br />
<br />
Table 1: Error Condition Types<br />
Condition Type Description<br />
HTTP Conditions (Deprecated) The connection manager responds to an invalid request from a legacy client with a standard HTTP error. These are used for binding syntax errors, possible attacks, etc. Note that constrained clients are unable to differentiate between HTTP errors.<br />
Terminal Binding Conditions These error conditions can be read by constrained clients. They are used for connection manager problems, abstracting stream errors, communication problems between the connection manager and the server, and invalid client requests (binding syntax errors, possible attacks, etc.)<br />
Recoverable Binding Conditions These report communication problems between the connection manager and the client. They do not terminate the session. Clients recover from these errors by resending all the preceding <body/> wrappers that have not received responses.<br />
Transported Protocol Conditions Errors relating to the XML payloads within <body/> wrappers are, in general, defined in the documentation of the protocol being transported. They do not terminate the session.<br />
<br />
Full descriptions are provided below.<br />
===HTTP Conditions===<br />
<br />
Note: All HTTP codes except 200 have been superseded by Terminal Binding Conditions to allow clients to determine whether the source of errors is the connection manager application or an HTTP intermediary.<br />
<br />
A legacy client (or connection manager) is a client (or connection manager) that did not include a 'ver' attribute in its session creation request (or response). A legacy client (or connection manager) will interpret (or respond with) HTTP error codes according to the table below. Non-legacy connection managers SHOULD NOT send HTTP error codes unless they are communicating with a legacy client. Upon receiving an HTTP error (400, 403, 404), a legacy client or any client that is communicating with a legacy connection manager MUST consider the HTTP session to be null and void. A non-legacy client that is communicating with a non-legacy connection manager MAY consider that the session is still active.<br />
<br />
Table 2: HTTP Error and Status Codes<br />
Code Name Superseded by Purpose<br />
200 OK - Response to valid client request.<br />
400 Bad Request bad-request Inform client that the format of an HTTP header or binding element is unacceptable (e.g., syntax error).<br />
403 Forbidden policy-violation Inform client that it has broken the session rules (polling too frequently, requesting too frequently, too many simultaneous requests).<br />
404 Not Found item-not-found Inform client that (1) 'sid' is not valid, (2) 'stream' is not valid, (3) 'rid' is larger than the upper limit of the expected window, (4) connection manager is unable to resend response, (5) 'key' sequence is invalid.<br />
<br />
Note: No other HTTP error and status codes were defined in the early versions of BOSH (e.g., Internal Server Error).<br />
===Terminal Binding Conditions===<br />
<br />
In any response it sends to the client, the connection manager MAY return a fatal error by setting a 'type' attribute of the <body/> element to "terminate". These binding errors imply that the HTTP session is terminated (unless a 'stream' attribute is specified -- see Multiple Stream Error Conditions).<br />
<br />
Note: Although many of these conditions are similar to the XMPP stream error conditions specified in RFC 6120, they are not to be confused with XMPP stream errors. In cases where BOSH is being used to transport XMPP, any fatal XMPP stream error conditions experienced between the connection manager and the XMPP server SHOULD only be reported using the "remote-stream-error" condition as described below.<br />
<br />
'''Example 32. Remote connection failed error'''<br />
<source lang="xml"><br />
HTTP/1.1 200 OK<br />
Content-Type: text/xml; charset=utf-8<br />
Content-Length: 68<br />
<br />
<body type='terminate'<br />
condition='remote-connection-failed'<br />
xmlns='http://jabber.org/protocol/httpbind'/><br />
</source><br />
<br />
The following values of the 'condition' attribute are defined:<br />
<br />
Table 3: Terminal Binding Error Conditions<br />
Condition Purpose<br />
bad-request* The format of an HTTP header or binding element received from the client is unacceptable (e.g., syntax error).<br />
host-gone The target domain specified in the 'to' attribute or the target host or port specified in the 'route' attribute is no longer serviced by the connection manager.<br />
host-unknown The target domain specified in the 'to' attribute or the target host or port specified in the 'route' attribute is unknown to the connection manager.<br />
improper-addressing The initialization element lacks a 'to' or 'route' attribute (or the attribute has no value) but the connection manager requires one.<br />
internal-server-error The connection manager has experienced an internal error that prevents it from servicing the request.<br />
item-not-found* (1) 'sid' is not valid, (2) 'stream' is not valid, (3) 'rid' is larger than the upper limit of the expected window, (4) connection manager is unable to resend response, (5) 'key' sequence is invalid.<br />
other-request Another request being processed at the same time as this request caused the session to terminate.<br />
policy-violation* The client has broken the session rules (polling too frequently, requesting too frequently, sending too many simultaneous requests).<br />
remote-connection-failed The connection manager was unable to connect to, or unable to connect securely to, or has lost its connection to, the server.<br />
remote-stream-error Encapsulates an error in the protocol being transported.<br />
see-other-uri The connection manager does not operate at this URI (e.g., the connection manager accepts only SSL or TLS connections at some https: URI rather than the http: URI requested by the client). The client can try POSTing to the URI in the content of the <uri/> child element.<br />
system-shutdown The connection manager is being shut down. All active HTTP sessions are being terminated. No new sessions can be created.<br />
undefined-condition The error is not one of those defined herein; the connection manager SHOULD include application-specific information in the content of the <body/> wrapper.<br />
<br />
* If the client did not include a 'ver' attribute in its session creation request then the connection manager SHOULD send a deprecated HTTP Error Condition instead of this terminal binding condition. If the connection manager did not include a 'ver' attribute in its session creation response then the client SHOULD expect it to send a deprecated HTTP Error Condition instead of this terminal binding condition.<br />
<br />
The following is an example of a "see-other-uri" condition:<br />
<br />
'''Example 33. See other URI error'''<br />
<source lang="xml"><br />
HTTP/1.1 200 OK<br />
Content-Type: text/xml; charset=utf-8<br />
Content-Length: 68<br />
<br />
<body condition='see-other-uri'<br />
type='terminate'<br />
xmlns='http://jabber.org/protocol/httpbind'><br />
<uri>https://secure.jabber.org/xmppcm</uri><br />
</body><br />
</source><br />
<br />
The following is an example including a "remote-stream-error" condition:<br />
<br />
'''Example 34. Remote error'''<br />
<source lang="xml"><br />
HTTP/1.1 200 OK<br />
Content-Type: text/xml; charset=utf-8<br />
Content-Length: 68<br />
<br />
<body condition='remote-stream-error'<br />
type='terminate'<br />
xmlns='http://jabber.org/protocol/httpbind'<br />
xmlns:stream='http://etherx.jabber.org/streams'><br />
<message from='contact@example.com'<br />
to='user@example.com'<br />
xmlns='jabber:client'><br />
<body>I said "Hi!"</body><br />
</message><br />
<stream:error><br />
<xml-not-well-formed xmlns='urn:ietf:params:xml:ns:xmpp-streams'/><br />
<text xmlns='urn:ietf:params:xml:ns:xmpp-streams'<br />
xml:lang='en'><br />
Some special application diagnostic information!<br />
</text><br />
<escape-your-data xmlns='application-ns'/><br />
</stream:error><br />
</body><br />
</source><br />
<br />
Naturally, the client MAY report binding errors to the connection manager as well, although this is unlikely.<br />
===Recoverable Binding Conditions===<br />
<br />
In any response it sends to the client, the connection manager MAY return a recoverable error by setting a 'type' attribute of the <body/> element to "error". These errors do not imply that the HTTP session is terminated.<br />
<br />
If it decides to recover from the error, then the client MUST repeat the HTTP request that resulted in the error, as well as all the preceding HTTP requests that have not received responses. The content of these requests MUST be identical to the <body/> elements of the original requests. This enables the connection manager to recover a session after the previous request was lost due to a communication failure.<br />
<br />
'''Example 35. Recoverable error'''<br />
<source lang="xml"><br />
HTTP/1.1 200 OK<br />
Content-Type: text/xml; charset=utf-8<br />
Content-Length: 68<br />
<br />
<body type='error'<br />
xmlns='http://jabber.org/protocol/httpbind'/><br />
</source><br />
<br />
===XML Payload Conditions===<br />
<br />
Application-level error conditions described in the documentation of the protocol being transported are routed to the client through the connection manager. They are transparent to the connection manager, and therefore out of scope for the transport binding defined herein.<br />
<br />
==Implementation Notes==<br />
===HTTP Pipelining===<br />
<br />
Even if the client requests HTTP Pipelining and the connection manager supports it, there is no guarantee that pipelining will succeed, because it might not be supported by intermediate proxies.<br />
<br />
The best the client can do is to request the use of HTTP Pipelining by setting the 'hold' attribute to a value of "1". If HTTP Pipelining does not work (because the server returns HTTP 1.0 or connection:close), then the client SHOULD degrade gracefully by using multiple connections.<br />
<br />
==Security Considerations==<br />
===Connection Between Client and BOSH Service===<br />
<br />
All communications between a client and a BOSH service SHOULD occur over encrypted HTTP connections. Negotiation of encryption between the client and the connection manager SHOULD occur at the transport layer or the HTTP layer, not the application layer; such negotiation SHOULD follow the HTTP/SSL protocol defined in SSL [28], although MAY follow the HTTP/TLS protocol defined in RFC 2818 [29] or the TLS Within HTTP protocol defined in RFC 2817 [30].<br />
<br />
If the HTTP connection used to send the initial session request is encrypted, then all the other HTTP connections used within the session MUST also be encrypted. Furthermore, if authentication certificates are exchanged when establishing the encrypted connection that is used to send the initial session request, then the client and/or connection manager SHOULD ensure that the same authentication certificates are employed for all subsequent connections used by the session. Once such a "secure session" has been established:<br />
<br />
* If the connection manager refuses to establish an encrypted connection or offers a different certificate, then the client SHOULD close the connection and terminate the session without sending any more requests.<br />
* If the client sends a wrapper element that is part of a "secure session" over a connection that either is not encrypted or uses a different certificate, then the connection manager SHOULD simply close the connection. The connection manager SHOULD NOT terminate the session since that would facilitate denial of service attacks.<br />
<br />
===Connection Between BOSH Service and Application===<br />
<br />
A BOSH service SHOULD encrypt its connection to the backend application using appropriate technologies such as Secure Sockets Layer (SSL), Transport Layer Security (TLS), and StartTLS if supported by the backend application. Alternatively, the BOSH service can be considered secure (1) if it is running on the same physical machine as the backend application or (2) if it running on the same private network as the backend application and the administrators are sure that unknown individuals or processes do not have access to that private network.<br />
<br />
If data privacy is desired, the client SHOULD encrypt its messages using an application-specific end-to-end encryption technology, because there is no way for the client to be sure that the BOSH service encrypts its connection to the application; methods for doing so are outside the scope of this specification.<br />
===Unpredictable SID and RID===<br />
<br />
The session identifier (SID) and initial request identifier (RID) are security-critical and therefore MUST be both unpredictable and nonrepeating (see RFC 1750 [31] for recommendations regarding randomness of SIDs and initial RIDs for security purposes).<br />
===Use of SHA-1===<br />
<br />
Recent research has shown that in select cases it is possible to compromise the hashes produced by the SHA-1 hashing algorithm (see RFC 4270 [32]). However, the use to which SHA-1 is put in BOSH will likely minimize the applicability of the attacks described in the literature. Furthermore, current estimates suggest that even with the recently-discovered attack, it would still take one year of computing by a government-sized entity to produce a collision.<br />
<br />
==IANA Considerations==<br />
<br />
TCP port 5280, conventially used for communication between BOSH clients and BOSH connection mangers, is registered with the Internet Assigned Numbers Authority (IANA) [33] in its port registry at IANA Port Numbers Registry [34], with a keyword of "xmpp-bosh". (Although use of this port is OPTIONAL, it is helpful to define this port in a standardized way so that BOSH clients can contact any given XMPP service via BOSH without the need either for DNS TXT records as described in Discovering Alternative XMPP Connection Methods [35] or for more advanced methods such as U-NAPTR.<br />
<br />
==XMPP Registrar Considerations==<br />
===Protocol Namespaces===<br />
<br />
The XMPP Registrar includes 'http://jabber.org/protocol/httpbind' in its registry of protocol namespaces.<br />
<br />
==XML Schema==<br />
<source lang="xml"><br />
<?xml version='1.0' encoding='UTF-8'?><br />
<br />
<xs:schema<br />
xmlns:xs='http://www.w3.org/2001/XMLSchema'<br />
xmlns:stream='http://etherx.jabber.org/streams'<br />
targetNamespace='http://jabber.org/protocol/httpbind'<br />
xmlns='http://jabber.org/protocol/httpbind'<br />
elementFormDefault='qualified'><br />
<br />
<xs:annotation><br />
<xs:documentation><br />
The protocol documented by this schema is defined in<br />
XEP-0124: http://www.xmpp.org/extensions/xep-0124.html<br />
</xs:documentation><br />
</xs:annotation><br />
<br />
<xs:import namespace='http://www.w3.org/XML/1998/namespace'<br />
schemaLocation='http://www.w3.org/2001/03/xml.xsd'/><br />
<br />
<xs:element name='body'><br />
<xs:complexType><br />
<xs:choice><br />
<xs:element name='uri'<br />
minOccurs='0'<br />
maxOccurs='1'<br />
type='xs:string'/><br />
<xs:any namespace='##other'<br />
minOccurs='0'<br />
maxOccurs='unbounded'<br />
processContents='lax'/><br />
</xs:choice><br />
<xs:attribute name='accept' type='xs:string' use='optional'/><br />
<xs:attribute name='ack' type='xs:positiveInteger' use='optional'/><br />
<xs:attribute name='authid' type='xs:string' use='optional'/><br />
<xs:attribute name='charsets' type='xs:NMTOKENS' use='optional'/><br />
<xs:attribute name='condition' use='optional'><br />
<xs:simpleType><br />
<xs:restriction base='xs:NCName'><br />
<xs:enumeration value='bad-request'/><br />
<xs:enumeration value='host-gone'/><br />
<xs:enumeration value='host-unknown'/><br />
<xs:enumeration value='improper-addressing'/><br />
<xs:enumeration value='internal-server-error'/><br />
<xs:enumeration value='item-not-found'/><br />
<xs:enumeration value='other-request'/><br />
<xs:enumeration value='policy-violation'/><br />
<xs:enumeration value='remote-connection-failed'/><br />
<xs:enumeration value='remote-stream-error'/><br />
<xs:enumeration value='see-other-uri'/><br />
<xs:enumeration value='system-shutdown'/><br />
<xs:enumeration value='undefined-condition'/><br />
</xs:restriction><br />
</xs:simpleType><br />
</xs:attribute><br />
<xs:attribute name='content' type='xs:string' use='optional'/><br />
<xs:attribute name='from' type='xs:string' use='optional'/><br />
<xs:attribute name='hold' type='xs:unsignedByte' use='optional'/><br />
<xs:attribute name='inactivity' type='xs:unsignedShort' use='optional'/><br />
<xs:attribute name='key' type='xs:string' use='optional'/><br />
<xs:attribute name='maxpause' type='xs:unsignedShort' use='optional'/><br />
<xs:attribute name='newkey' type='xs:string' use='optional'/><br />
<xs:attribute name='pause' type='xs:unsignedShort' use='optional'/><br />
<xs:attribute name='polling' type='xs:unsignedShort' use='optional'/><br />
<xs:attribute name='report' type='xs:positiveInteger' use='optional'/><br />
<xs:attribute name='requests' type='xs:unsignedByte' use='optional'/><br />
<xs:attribute name='rid' type='xs:positiveInteger' use='optional'/><br />
<xs:attribute name='route' type='xs:string' use='optional'/><br />
<xs:attribute name='sid' type='xs:string' use='optional'/><br />
<xs:attribute name='stream' type='xs:string' use='optional'/><br />
<xs:attribute name='time' type='xs:unsignedShort' use='optional'/><br />
<xs:attribute name='to' type='xs:string' use='optional'/><br />
<xs:attribute name='type' use='optional'><br />
<xs:simpleType><br />
<xs:restriction base='xs:NCName'><br />
<xs:enumeration value='error'/><br />
<xs:enumeration value='terminate'/><br />
</xs:restriction><br />
</xs:simpleType><br />
</xs:attribute><br />
<xs:attribute name='ver' type='xs:string' use='optional'/><br />
<xs:attribute name='wait' type='xs:unsignedShort' use='optional'/><br />
<xs:attribute ref='xml:lang' use='optional'/><br />
<xs:anyAttribute namespace='##other' processContents='lax'/><br />
</xs:complexType><br />
</xs:element><br />
<br />
</xs:schema><br />
</source><br />
<br />
==Acknowledgements==<br />
<br />
Thanks to Mike Cumings, Tomas Karasek, Tobias Markmann, Chris Seymour, Safa Sofuoğlu, Stefan Strigler, Matthew Wild, Kevin Winters, and Christopher Zorn for their feedback.<br />
<br />
==Appendices==<br />
===Appendix A: Document Information===<br />
<br />
Series: XEP<br />
Number: 0124<br />
Publisher: XMPP Standards Foundation<br />
Status: Draft<br />
Type: Standards Track<br />
Version: 1.10<br />
Last Updated: 2010-07-02<br />
Approving Body: XMPP Council<br />
Dependencies: RFC 1945, RFC 2616, RFC 3174<br />
Supersedes: None<br />
Superseded By: None<br />
Short Name: bosh<br />
Schema: <http://www.xmpp.org/schemas/httpbind.xsd><br />
Source Control: HTML RSS<br />
This document in other formats: XML PDF<br />
===Appendix B: Author Information===<br />
Ian Paterson<br />
<br />
Email: ian.paterson@clientside.co.uk<br />
JabberID: ian@zoofy.com<br />
Dave Smith<br />
<br />
Email: dizzyd@jabber.org<br />
JabberID: dizzyd@jabber.org<br />
Peter Saint-Andre<br />
<br />
Email: stpeter@jabber.org<br />
JabberID: stpeter@jabber.org<br />
URI: https://stpeter.im/<br />
Jack Moffitt<br />
<br />
Email: jack@chesspark.com<br />
JabberID: jack@chesspark.com<br />
===Appendix C: Legal Notices===<br />
Copyright<br />
This XMPP Extension Protocol is copyright © 1999 - 2011 by the XMPP Standards Foundation (XSF).<br />
Permissions<br />
Permission is hereby granted, free of charge, to any person obtaining a copy of this specification (the "Specification"), to make use of the Specification without restriction, including without limitation the rights to implement the Specification in a software program, deploy the Specification in a network service, and copy, modify, merge, publish, translate, distribute, sublicense, or sell copies of the Specification, and to permit persons to whom the Specification is furnished to do so, subject to the condition that the foregoing copyright notice and this permission notice shall be included in all copies or substantial portions of the Specification. Unless separate permission is granted, modified works that are redistributed shall not contain misleading information regarding the authors, title, number, or publisher of the Specification, and shall not claim endorsement of the modified works by the authors, any organization or project to which the authors belong, or the XMPP Standards Foundation.<br />
Disclaimer of Warranty<br />
## NOTE WELL: This Specification is provided on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, express or implied, including, without limitation, any warranties or conditions of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A PARTICULAR PURPOSE. ##<br />
Limitation of Liability<br />
In no event and under no legal theory, whether in tort (including negligence), contract, or otherwise, unless required by applicable law (such as deliberate and grossly negligent acts) or agreed to in writing, shall the XMPP Standards Foundation or any author of this Specification be liable for damages, including any direct, indirect, special, incidental, or consequential damages of any character arising from, out of, or in connection with the Specification or the implementation, deployment, or other use of the Specification (including but not limited to damages for loss of goodwill, work stoppage, computer failure or malfunction, or any and all other commercial damages or losses), even if the XMPP Standards Foundation or such author has been advised of the possibility of such damages.<br />
IPR Conformance<br />
This XMPP Extension Protocol has been contributed in full conformance with the XSF's Intellectual Property Rights Policy (a copy of which can be found at <http://xmpp.org/extensions/ipr-policy.shtml> or obtained by writing to XMPP Standards Foundation, 1899 Wynkoop Street, Suite 600, Denver, CO 80202 USA).<br />
===Appendix D: Relation to XMPP===<br />
<br />
The Extensible Messaging and Presence Protocol (XMPP) is defined in the XMPP Core (RFC 3920) and XMPP IM (RFC 3921) specifications contributed by the XMPP Standards Foundation to the Internet Standards Process, which is managed by the Internet Engineering Task Force in accordance with RFC 2026. Any protocol defined in this document has been developed outside the Internet Standards Process and is to be understood as an extension to XMPP rather than as an evolution, development, or modification of XMPP itself.<br />
===Appendix E: Discussion Venue===<br />
<br />
The primary venue for discussion of XMPP Extension Protocols is the <standards@xmpp.org> discussion list.<br />
<br />
Discussion on other xmpp.org discussion lists might also be appropriate; see <http://xmpp.org/about/discuss.shtml> for a complete list.<br />
<br />
Given that this XMPP Extension Protocol normatively references IETF technologies, discussion on the <xsf-ietf@xmpp.org> list might also be appropriate.<br />
<br />
Errata can be sent to <editor@xmpp.org>.<br />
===Appendix F: Requirements Conformance===<br />
<br />
The following requirements keywords as used in this document are to be interpreted as described in RFC 2119: "MUST", "SHALL", "REQUIRED"; "MUST NOT", "SHALL NOT"; "SHOULD", "RECOMMENDED"; "SHOULD NOT", "NOT RECOMMENDED"; "MAY", "OPTIONAL".<br />
===Appendix G: Notes===<br />
<br />
1. RFC 793: Transmission Control Protocol <http://tools.ietf.org/html/rfc0793>.<br />
<br />
2. RFC 1945: Hypertext Transfer Protocol -- HTTP/1.0 <http://tools.ietf.org/html/rfc1945>.<br />
<br />
3. RFC 2616: Hypertext Transport Protocol -- HTTP/1.1 <http://tools.ietf.org/html/rfc2616>.<br />
<br />
4. Bayeux Protocol <http://svn.cometd.org/trunk/bayeux/bayeux.html>.<br />
<br />
5. The Web Socket Protocol <http://tools.ietf.org/html/draft-hixie-thewebsocketprotocol>.<br />
<br />
6. Reverse HTTP <http://tools.ietf.org/html/draft-lentczner-rhttp>.<br />
<br />
7. RFC 2965: HTTP State Management Mechanism <http://tools.ietf.org/html/rfc2965>.<br />
<br />
8. Requiring cookies is sub-optimal because several significant computing platforms provide only limited access to underlying HTTP requests/responses; worse, some platforms hide or remove cookie-related headers.<br />
<br />
9. XEP-0025: Jabber HTTP Polling <http://xmpp.org/extensions/xep-0025.html>.<br />
<br />
10. RFC 6120: Extensible Messaging and Presence Protocol (XMPP): Core <http://tools.ietf.org/html/rfc6120>.<br />
<br />
11. XEP-0206: XMPP Over BOSH <http://xmpp.org/extensions/xep-0206.html>.<br />
<br />
12. In order to reduce network congestion, RFC 2616 recommends that clients SHOULD NOT keep more than two HTTP connections to the same HTTP server open at the same time. Clients running in constrained enviroments typically have no choice but to abide by that recommendation.<br />
<br />
13. If there is no traffic other than the "pings" then bandwidth consumption will be double that of a TCP connection (although double nothing is still nothing). If data is sent in large packets then bandwidth consumption will be almost identical.<br />
<br />
14. Extensible Markup Language (XML) 1.0 (Fourth Edition) <http://www.w3.org/TR/REC-xml/>.<br />
<br />
15. Namespaces in XML <http://www.w3.org/TR/REC-xml-names/>.<br />
<br />
16. RFC 4627: The application/json Media Type for JavaScript Object Notation (JSON) <http://tools.ietf.org/html/rfc4627>.<br />
<br />
17. Extensible Markup Language (XML) 1.0 (Fourth Edition) <http://www.w3.org/TR/REC-xml/>.<br />
<br />
18. Although the syntax of the 'route' attribute bears a superficial resemblance to a URI or IRI, it is not a URI/IRI and MUST NOT be processed in accordance with the rules specified in RFC 3986, RFC 3987, or (for XMPP) RFC 5122.<br />
<br />
19. Each character set name (or character encoding name -- we use the terms interchangeably) SHOULD be of type NMTOKEN, where the names are separated by the white space character #x20, resulting in a tokenized attribute type of NMTOKENS (see Section 3.3.1 of XML 1.0 [20]). Strictly speaking, the Character Sets registry maintained by the Internet Assigned Numbers Authority (see <http://www.iana.org/assignments/character-sets>) allows a character set name to contain any printable US-ASCII character, which might include characters not allowed by the NMTOKEN construction of XML 1.0; however, the only existing character set name which includes such a character is "NF_Z_62-010_(1973)".<br />
<br />
20. Extensible Markup Language (XML) 1.0 (Fourth Edition) <http://www.w3.org/TR/REC-xml/>.<br />
<br />
21. 9007199254740991 is 253-1. Some weakly typed languages use IEEE Standard 754 Doubles to represent all numbers. These Doubles cannot represent integers above 253 accurately.<br />
<br />
22. RFC 3174: US Secure Hash Algorithm 1 (SHA1) <http://tools.ietf.org/html/rfc3174>.<br />
<br />
23. Therefore a client and a connection manager will be compatible even if one or the other offers no support for multi-stream sessions.<br />
<br />
24. The 'rid' attribute is always incremented normally without reference to any 'stream' attribute.<br />
<br />
25. This helps to ensure backwards-compatibility with older implementations.<br />
<br />
26. Each HTTP response MUST belong to the same session as the request that triggered it, but not necessarily to the same stream.<br />
<br />
27. The broadcast payloads can be of any type.<br />
<br />
28. SSL V3.0 <http://wp.netscape.com/eng/ssl3/draft302.txt>.<br />
<br />
29. RFC 2818: HTTP Over TLS <http://tools.ietf.org/html/rfc2818>.<br />
<br />
30. RFC 2817: Upgrading to TLS Within HTTP/1.1 <http://tools.ietf.org/html/rfc2817>.<br />
<br />
31. RFC 1750: Randomness Recommendations for Security <http://tools.ietf.org/html/rfc1750>.<br />
<br />
32. RFC 4270: Attacks on Cryptographic Hashes in Internet Protocols <http://tools.ietf.org/html/rfc4270>.<br />
<br />
33. The Internet Assigned Numbers Authority (IANA) is the central coordinator for the assignment of unique parameter values for Internet protocols, such as port numbers and URI schemes. For further information, see <http://www.iana.org/>.<br />
<br />
34. IANA registry of port numbers <http://www.iana.org/assignments/port-numbers>.<br />
<br />
35. XEP-0156: Discovering Alternative XMPP Connection Methods <http://xmpp.org/extensions/xep-0156.html>.<br />
===Appendix H: Revision History===<br />
<br />
Note: Older versions of this specification might be available at http://xmpp.org/extensions/attic/<br />
Version 1.10 (2010-07-02)<br />
<br />
Further clarified use of 'from' and 'to' attributes; added missing condition values to the schema.<br />
(psa)<br />
Version 1.9 (2009-11-06)<br />
<br />
Added information for registration of port 5280 with IANA.<br />
(psa)<br />
Version 1.8 (2009-04-30)<br />
<br />
Removed secure attribute because it did not solve the problem it was intended to solve; added security consideration regarding link between connection manager and application server; changed "stanza" to "payload" for disambiguation with XMPP; clarified design objectives and relationship to similar technologies; corrected several errors in the schema.<br />
(psa/jm)<br />
Version 1.7 (2008-10-29)<br />
<br />
Moved alternative script syntax to historical specification; added implementation note about HTTP Pipelining; adjusted architectural description.<br />
(psa)<br />
Version 1.6 (2007-02-21)<br />
<br />
Multiple clarifications and restructuring without changes to protocol itself; changed title to BOSH; added section that fully explains the technique underlying the protocol; separated XMPP-specific features into new XEP-0206; added optional new Script Syntax and session pauses; added Acknowledgements section; added from and ver attributes; added hold attribute to session creation response; clarified polling too-frequently error; recommended that clients use HTTP Pipelining.<br />
(ip)<br />
Version 1.5 (2006-04-28)<br />
<br />
Added optional Multiple Streams section; added security considerations about encrypted HTTP connections; recommended use of SSL rather than HTTP over TLS; specified that request ID values must not exceed 9007199254740991; corrected datatypes of inactivity, polling, rid, and wait attributes in the schema; added <any/> and <anyAttribute/> elements to schema to optionally support non-XMPP XML elements and attributes; deprecated HTTP error codes in favor of new terminal binding conditions.<br />
(ip/psa)<br />
Version 1.4 (2005-12-14)<br />
<br />
Modified syntax of route attribute to be proto:host:port rather than XMPP URI/IRI.<br />
(psa)<br />
Version 1.3 (2005-11-02)<br />
<br />
Corrected stream:features namespace and the Recoverable Binding Conditions section; recommended that connection manager shall return secure attribute to client; recommended end-to-end encryption through proxy connection managers.<br />
(ip)<br />
Version 1.2 (2005-06-16)<br />
<br />
Specified optional use of route and secure attributes in session request. Minor correction: the stream features element should be included in the response that contains the authid attribute (this is not necessarily the session creation response).<br />
(ip)<br />
Version 1.1 (2005-06-02)<br />
<br />
Specified optional use of HTTP Accept-Encoding and Content-Encoding headers for compression at HTTP binding level.<br />
(ip)<br />
Version 1.0 (2005-03-03)<br />
<br />
Per a vote of the Jabber Council, advanced status to Draft.<br />
(psa)<br />
Version 0.10 (2004-11-08)<br />
<br />
Changed HTTP 401 errors to HTTP 404.<br />
(ip)<br />
Version 0.9 (2004-10-26)<br />
<br />
Added charset attribute.<br />
(ip/psa)<br />
Version 0.8 (2004-10-26)<br />
<br />
Specified that wait attribute must be included in the session creation response.<br />
(ip)<br />
Version 0.7 (2004-08-12)<br />
<br />
Defined appropriate XMPP stanza error conditions.<br />
(psa/ip)<br />
Version 0.6 (2004-07-19)<br />
<br />
Added xml:lang attribute to the session request; added recoverable binding error conditions.<br />
(ip)<br />
Version 0.5 (2004-05-07)<br />
<br />
Protocol refactored to enable simultaneous requests (request identifier attribute, wait attribute, hold attribute, requests attribute) and recovery of broken connections; added content attribute; removed all wrapper types except 'terminate'; updated error handling; made key mechanism optional (should use SSL/TLS instead).<br />
(ip/psa)<br />
Version 0.4 (2004-02-23)<br />
<br />
Fixed typos; removed "resource-constraint" binding error; added HTTP 403 error to table.<br />
(psa/ip)<br />
Version 0.3 (2004-02-19)<br />
<br />
Added 'authid' attribute to enable communication of XMPP stream ID (used in digest authentication); specified that Content-Types other than "text/xml" are allowed to support older HTTP clients; specified business rule for connection manager queueing of client requests; changed <packet/> to <body/> to support older HTTP clients; changed 'to' attribute on initialization element from MAY to SHOULD; recommended inclusion of unavailable presence in termination element sent from client; described architectural assumptions; specified binding-specific error handling.<br />
(psa/ip)<br />
Version 0.2 (2004-01-13)<br />
<br />
Added 'to' attribute on the initialization element; specified that 'text/html' is allowable for backwards-compatibility.<br />
(dss/psa/ip)<br />
Version 0.1 (2003-11-06)<br />
<br />
Initial version.<br />
(dss/psa)<br />
<br />
结束</div>
Snowqiang
http://wiki.jabbercn.org/XEP-0124
XEP-0124
2011-05-18T13:59:38Z
<p>Snowqiang: /* =Request Acknowledgements */</p>
<hr />
<div>[[Category:XMPP扩展]]<br />
[[Category:翻译中]]<br />
<br />
'''本文的英文原文来自[http://www.xmpp.org/extensions/xep-0124.html XEP-0124]'''<br />
<br />
'''XEP-0124: Bidirectional-streams Over Synchronous HTTP (BOSH)'''<br />
<br />
摘要: This specification defines a transport protocol that emulates the semantics of a long-lived, bidirectional TCP connection between two entities (such as a client and a server) by efficiently using multiple synchronous HTTP request/response pairs without requiring the use of frequent polling or chunked responses.<br />
作者: Ian Paterson, Dave Smith, Peter Saint-Andre, Jack Moffitt<br />
版权: © 1999 - 2011 XMPP Standards Foundation. SEE LEGAL NOTICES.<br />
状态: 草案<br />
类型: 标准跟踪<br />
版本: 2.0<br />
最后更新日期: 2010-07-02<br />
<br />
NOTICE: The protocol defined herein is a Draft Standard of the XMPP Standards Foundation. Implementations are encouraged and the protocol is appropriate for deployment in production systems, but some changes to the protocol are possible before it becomes a Final Standard.<br />
<br />
==Introduction==<br />
<br />
The Transmission Control Protocol (TCP; RFC 793 [1]) is often used to establish a stream-oriented connection between two entities. Such connections can often be long-lived to enable an interactive "session" between the entities. However, sometimes the nature of the device or network can prevent an application from maintaining a long-lived TCP connection to a server or peer. In this case, it is desirable to use an alternative connection method that emulates the behavior of a long-lived TCP connection using a sequenced series of requests and responses that are exchanged over short-lived connections. The appropriate request-response semantics are widely available via the Hypertext Transfer Protocol (HTTP) as specified in RFC 1945 [2] and RFC 2616 [3].<br />
<br />
BOSH, the technology defined in this specification, essentially provides a "drop-in" alternative to a long-lived, bidirectional TCP connection. It is a mature, full-featured technology that has been widely implemented and deployed since 2004. To our knowledge it was the first of many similar technologies, which now include the Comet methodology formalized in the Bayeux Protocol [4] as well as The Web Socket Protocol [5] and Reverse HTTP [6].<br />
<br />
BOSH is designed to transport any data efficiently and with minimal latency in both directions. For applications that require both "push" and "pull" semantics, BOSH is significantly more bandwidth-efficient and responsive than most other bidirectional HTTP-based transport protocols and the techniques now commonly known as "Ajax". BOSH achieves this efficiency and low latency by using so-called "long polling" with multiple synchronous HTTP request/response pairs. Furthermore, BOSH can address the needs of constrained clients by employing fully-compliant HTTP 1.0 without the need for "cookies" (see RFC 2965 [7]) [8] or even access to HTTP headers.<br />
<br />
BOSH was originally developed in the Jabber/XMPP community as a replacement for an even earlier HTTP-based technology called Jabber HTTP Polling [9]. Although BOSH assumes that the "payload" of HTTP requests and responses will be XML, the payload formats are not limited to XMPP stanzas (see XMPP Core [10]) and could contain a mixture of elements qualified by namespaces defined by different protocols (e.g., both XMPP and JSON). This mix is necessary because some connection managers might 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 payload is qualified by the correct namespace.<br />
<br />
Note: XMPP Over BOSH [11] documents some XMPP-specific extensions of this protocol that were formerly included in this document.<br />
<br />
==Requirements==<br />
<br />
The following design requirements reflect the need to offer performance as close as possible to a standard TCP connection.<br />
<br />
1. Compatible with constrained runtime environments* (e.g., mobile and browser-based clients).<br />
2. Compatible with proxies that buffer partial HTTP responses.<br />
3. Efficient through proxies that limit the duration of HTTP responses.<br />
4. Fully compatible with HTTP/1.0.<br />
5. Compatible with restricted network connections (e.g., firewalls, proxies, and gateways).<br />
6. Fault tolerant (e.g., session recovers after an underlying TCP connection breaks at any stage during an HTTP request).<br />
7. Extensible.<br />
8. Consume significantly less bandwidth than polling-based protocols.<br />
9. Significantly more responsive (lower latency) than polling-based protocols.<br />
10. Support for polling (for clients that are limited to a single HTTP connection at a time).<br />
11. In-order delivery of data.<br />
12. Guard against unauthorized users injecting HTTP requests into a session.<br />
13. Protect against denial of service attacks.<br />
14. Multiplexing of data streams.<br />
<br />
*Note: Compatibility with constrained runtime environments implies the following restrictions:<br />
<br />
1. Clients are not required to have programmatic access to the headers of each HTTP request and response (e.g., cookies or status codes).<br />
2. The body of each HTTP request and response is parsable XML with a single root element.<br />
3. Clients can specify the Content-Type of the HTTP responses they receive.<br />
<br />
==Architectural Assumptions==<br />
<br />
This document assumes that most implementations will utilize a specialized connection manager ("CM") to handle HTTP connections rather than the native connection type for the relevant application (e.g., TCP connections in XMPP). Effectively, such a connection manager is a specialized HTTP server that translates between the HTTP requests and responses defined herein and the data streams (or API) implemented by the server with which it communicates, thus enabling a client to connect to a server via HTTP on port 80 or 443 instead of an application-specific port. We can illustrate this graphically as follows:<br />
<br />
Server<br />
|<br />
| [unwrapped data streams]<br />
|<br />
HTTP CM<br />
|<br />
| [HTTP + <body/> wrapper]<br />
|<br />
Client<br />
<br />
<br />
This specification covers communication only between a client and the connection manager. It does not cover communication between the connection manager and the server, since such communications are implementation-specific (e.g., the server might 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 might be an independent translating proxy such that the server might believe it is talking directly to the client over TCP; or the connection manager and the server might use a component protocol or an API defined by the server implementation).<br />
<br />
Furthermore, no aspect of this protocol limits its use to communication between a client and a server. For example, it could be used for communication between a server and a peer server if such communication can occur for the relevant application (e.g., in XMPP). 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 the native connection transport for the relevant application. (However, on some unreliable networks, BOSH might enable more stable communication between servers.)<br />
<br />
==The BOSH Technique==<br />
<br />
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).<br />
<br />
The technique employed by BOSH 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.<br />
<br />
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 so to make sure the client can send more data immediately if necessary. (The client SHOULD NOT open more than two HTTP connections to the connection manager at the same time, [12] so it would otherwise have to wait until the connection manager responds to one of the requests.)<br />
<br />
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 TCP 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.<br />
<br />
If there is no traffic in either direction for an agreed amount of time (typically several 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 so 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. [13]<br />
<br />
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. Thus 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. Therefore, 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 were being used.<br />
<br />
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.<br />
<br />
==HTTP Overview==<br />
<br />
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).<br />
<br />
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 permitted by RFC 1945 or RFC 2616. For example, 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 might buffer each partial HTTP request or response and only forward the full request or response once it is available.<br />
<br />
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.<br />
<br />
Requests and responses MAY include HTTP headers not specified herein. The receiver SHOULD ignore any such headers.<br />
<br />
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). However, the responses to requests that are not part of the session sent over the same connection using HTTP pipelining (or queued to be sent over the same connection) might be delayed if they were sent while a request that is part of the session is being held (since the connection manager MUST send its responses in the same order that the requests were received, and the connection manager typically delays its responses).<br />
<br />
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.<br />
<br />
==<body/> Wrapper Element==<br />
<br />
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 transferred. The <body/> element and its content together MUST conform to the specifications set out in XML 1.0 [14]. They SHOULD also conform to Namespaces in XML [15]. The content MUST NOT contain any of the following (all defined in XML 1.0):<br />
<br />
*<br />
<br />
Partial XML elements<br />
*<br />
<br />
XML comments<br />
*<br />
<br />
XML processing instructions<br />
*<br />
<br />
Internal or external DTD subsets<br />
*<br />
<br />
Internal or external entity references (with the exception of predefined entities)<br />
<br />
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 "payloads" in this document, e.g., XMPP stanzas as defined in RFC 6120 or elements containing XML character data that represents objects using the JSON data interchange format as defined in RFC 4627 [16]). Each <body/> wrapper MAY contain payloads qualified under a wide variety of different namespaces.<br />
<br />
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.<br />
<br />
==Initiating a BOSH Session==<br />
===Session Creation Request===<br />
<br />
The first request from the client to the connection manager requests a new session.<br />
<br />
The <body/> element of the first request SHOULD possess the following attributes (they SHOULD NOT be included in any other requests except as specified under Adding Streams To A Session):<br />
<br />
* 'to' -- This attribute specifies the target domain of the first stream.<br />
* 'xml:lang' -- This attribute (as defined in Section 2.12 of XML 1.0 [17]) specifies the default language of any human-readable XML character data sent or received during the session.<br />
* 'ver' -- This attribute specifies the highest version of the BOSH protocol that the client supports. The numbering scheme is "<major>.<minor>" (where the minor number MAY be incremented higher than a single digit, so it MUST be treated as a separate integer). Note: The 'ver' attribute should not be confused with the version of any protocol being transported.<br />
* 'wait' -- This attribute specifies the longest time (in seconds) that the connection manager is allowed to wait before responding to any request during the session. This enables the client to limit the delay before it discovers any network failure, and to prevent its HTTP/TCP connection from expiring due to inactivity.<br />
* 'hold' -- This attribute specifies the maximum number of requests the connection manager is allowed to keep waiting at any one time during the session. If the client is not able to use HTTP Pipelining then this SHOULD be set to "1".<br />
<br />
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 both typically one or two orders of magnitude!<br />
<br />
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:example.com:9999"). [18] A connection manager that is configured to work only with a single server (or only with a defined list of domains and the associated list of hostnames and ports that are serving those domains) MAY ignore the 'route' attribute. (Note that the 'to' attribute specifies the domain being served, not the hostname of the machine that is serving the domain.)<br />
<br />
The <body/> element of the first request MAY also possess a 'from' attribute, which specifies the originator of the first stream and which enables the connection manager to forward the originating entity's identity to the application server (e.g., the JabberID of an entity that is connecting to an XMPP server; see XEP-0206).<br />
<br />
A client MAY include an 'ack' attribute (set to "1") to indicate that it will be using acknowledgements throughout the session and that the absence of an 'ack' attribute in any request is meaningful (see Acknowledgements).<br />
<br />
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".<br />
<br />
'''Example 1. Requesting a BOSH session'''<br />
<source lang="xml"><br />
POST /webclient HTTP/1.1<br />
Host: httpcm.example.com<br />
Accept-Encoding: gzip, deflate<br />
Content-Type: text/xml; charset=utf-8<br />
Content-Length: 104<br />
<br />
<body content='text/xml; charset=utf-8'<br />
from='user@example.com'<br />
hold='1'<br />
rid='1573741820'<br />
to='example.com'<br />
route='xmpp:example.com:9999'<br />
ver='1.6'<br />
wait='60'<br />
ack='1'<br />
xml:lang='en'<br />
xmlns='http://jabber.org/protocol/httpbind'/><br />
</source><br />
<br />
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.<br />
===Session Creation Response===<br />
<br />
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):<br />
<br />
* 'sid' -- This attribute specifies the SID<br />
* 'wait' -- This is the longest time (in seconds) that the connection manager will wait before responding to any request during the session. The time MUST be less than or equal to the value specified in the session request.<br />
<br />
The <body/> element SHOULD also include the following attributes (they SHOULD NOT be included in any other responses):<br />
<br />
* 'ver' -- This attribute specifies the highest version of the BOSH protocol that the connection manager supports, or the version specified by the client in its request, whichever is lower.<br />
* 'polling' -- This attribute specifies the shortest allowable polling interval (in seconds). This enables the client to not send empty request elements more often than desired (see Polling Sessions and Overactivity).<br />
* 'inactivity' -- This attribute specifies the longest allowable inactivity period (in seconds). This enables the client to ensure that the periods with no requests pending are never too long (see Polling Sessions and Inactivity).<br />
* 'requests' -- This attribute enables the connection manager to limit the number of simultaneous requests the client makes (see Overactivity and Polling Sessions). The RECOMMENDED values are either "2" or one more than the value of the 'hold' attribute specified in the session request.<br />
* 'hold' -- This attribute informs the client about the maximum number of requests the connection manager will keep waiting at any one time during the session. This value MUST NOT be greater than the value specified by the client in the session request.<br />
* 'to' -- This attribute communicates the identity of the backend server to which the client is attempting to connect.<br />
<br />
The connection manager MAY include an 'accept' attribute in the session creation response element, to specify a space-separated list of 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.<br />
<br />
A connection manager MAY include an 'ack' attribute (set to the value of the 'rid' attribute of the session creation request) to indicate that it will be using acknowledgements throughout the session and that the absence of an 'ack' attribute in any response is meaningful (see Acknowledgements).<br />
<br />
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 can request.<br />
<br />
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. [19]<br />
<br />
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 a BOSH Session), then in the same response the connection manager SHOULD also include the 'secure' attribute set to "true" or "1".<br />
<br />
'''Example 2. Session creation response'''<br />
<source lang="xml"><br />
HTTP/1.1 200 OK<br />
Content-Type: text/xml; charset=utf-8<br />
Content-Length: 128<br />
<br />
<body wait='60'<br />
inactivity='30'<br />
polling='5'<br />
requests='2'<br />
hold='1'<br />
ack='1573741820'<br />
accept='deflate,gzip'<br />
maxpause='120'<br />
sid='SomeSID'<br />
charsets='ISO_8859-1 ISO-2022-JP'<br />
ver='1.6'<br />
from='example.com'<br />
xmlns='http://jabber.org/protocol/httpbind'/><br />
</source><br />
<br />
'''Example 3. Subsequent response with 'from' and 'secure' attributes'''<br />
<source lang="xml"><br />
HTTP/1.1 200 OK<br />
Content-Type: text/xml; charset=utf-8<br />
Content-Length: 128<br />
<br />
<body from='example.com'<br />
xmlns='http://jabber.org/protocol/httpbind'/><br />
</source><br />
<br />
==Sending and Receiving XML Payloads==<br />
<br />
After the client has successfully completed all required preconditions, it can send and receive XML payloads via the HTTP binding.<br />
<br />
'''Example 4. Transmitting payloads'''<br />
<source lang="xml"><br />
POST /webclient HTTP/1.1<br />
Host: httpcm.example.com<br />
Accept-Encoding: gzip, deflate<br />
Content-Type: text/xml; charset=utf-8<br />
Content-Length: 188<br />
<br />
<body rid='1249243562'<br />
sid='SomeSID'<br />
xmlns='http://jabber.org/protocol/httpbind'><br />
<message to='contact@example.com'<br />
xmlns='jabber:client'><br />
<body>Good morning!</body><br />
</message><br />
<message to='friend@example.com'<br />
xmlns='jabber:client'><br />
<body>Hey, what&apos;s up?</body><br />
</message><br />
</body><br />
</source><br />
<br />
Upon receipt of a request, the connection manager SHOULD forward the content of the <body/> element to the server as soon as possible. In any case it MUST forward the content from different requests in the order specified by their 'rid' attributes.<br />
<br />
The connection manager MUST also return an HTTP 200 OK response with a <body/> element to the client. Note: This does not indicate that the payloads have been successfully delivered to the application server.<br />
<br />
It is RECOMMENDED that the connection manager not return an HTTP result until a payload has arrived from the application server for delivery to the client. However, the connection manager SHOULD NOT wait longer than the time specified by the client in the 'wait' attribute of its Session Creation Request, and it SHOULD NOT keep more HTTP requests waiting at a time than the number specified in the 'hold' attribute of the session creation request. In any case it MUST respond to requests in the order specified by their 'rid' attributes.<br />
<br />
If there are no payloads waiting or ready to be delivered within the waiting period, then the connection manager SHOULD include an empty <body/> element in the HTTP result:<br />
<br />
'''Example 5. Empty response'''<br />
<source lang="xml"><br />
HTTP/1.1 200 OK<br />
Content-Type: text/xml; charset=utf-8<br />
Content-Length: 64<br />
<br />
<body xmlns='http://jabber.org/protocol/httpbind'/><br />
</source><br />
<br />
If the connection manager has received one or more payloads from the application server for delivery to the client, then it SHOULD return the payloads in the body of its response as soon as possible after receiving them from the server. The example below includes payloads qualified by different namespaces:<br />
<br />
'''Example 6. Response with queued stanza'''<br />
<source lang="xml"><br />
HTTP/1.1 200 OK<br />
Content-Type: text/xml; charset=utf-8<br />
Content-Length: 185<br />
<br />
<body xmlns='http://jabber.org/protocol/httpbind'<br />
xmlns:json='http://json.org/'><br />
<message from='contact@example.com'<br />
to='user@example.com'<br />
xmlns='jabber:client'><br />
<body>Good morning to you!</body><br />
</message><br />
<message from='friend@example.com'<br />
to='user@example.com'<br />
xmlns='jabber:client'><br />
<body>Not much, how about with you?</body><br />
</message><br />
<json:json><br />
[<br />
{<br />
"precision": "zip",<br />
"Latitude": 37.7668,<br />
"Longitude": -122.3959,<br />
"Address": "",<br />
"City": "SAN FRANCISCO",<br />
"State": "CA",<br />
"Zip": "94107",<br />
"Country": "US"<br />
},<br />
{<br />
"precision": "zip",<br />
"Latitude": 37.371991,<br />
"Longitude": -122.026020,<br />
"Address": "",<br />
"City": "SUNNYVALE",<br />
"State": "CA",<br />
"Zip": "94085",<br />
"Country": "US"<br />
}<br />
]<br />
</json:json><br />
</body><br />
</source><br />
<br />
The client MAY poll the connection manager for incoming payloads by sending an empty <body/> element.<br />
<br />
'''Example 7. Requesting XML Payloads'''<br />
<source lang="xml"><br />
POST /webclient HTTP/1.1<br />
Host: httpcm.example.com<br />
Accept-Encoding: gzip, deflate<br />
Content-Type: text/xml; charset=utf-8<br />
Content-Length: 88<br />
<br />
<body rid='1249243563'<br />
sid='SomeSID'<br />
xmlns='http://jabber.org/protocol/httpbind'/><br />
</source><br />
<br />
The connection manager MUST wait and respond in the same way as it does after receiving payloads from the client.<br />
<br />
==Acknowledgements==<br />
===Request Acknowledgements===<br />
<br />
When responding to a request that it has been holding, if the connection manager finds it has already received another request with a higher 'rid' attribute (typically while it was holding the first request), then it MAY acknowledge the reception to the client. The connection manager MAY set the 'ack' attribute of any response to the value of the highest 'rid' attribute it has received in the case where it has also received all requests with lower 'rid' values.<br />
<br />
'''Example 8. Response with request acknowledgement'''<br />
<source lang="xml"><br />
HTTP/1.1 200 OK<br />
Content-Type: text/xml; charset=utf-8<br />
Content-Length: 64<br />
<br />
<body ack='1249243564'<br />
xmlns='http://jabber.org/protocol/httpbind'/><br />
</source><br />
<br />
If the connection manager will be including 'ack' attributes on responses during a session, then it MUST include an 'ack' attribute in its session creation response, and set the 'ack' attribute of responses throughout the session. The only exception is that, after its session creation response, the connection manager SHOULD NOT include an 'ack' attribute in any response if the value would be the 'rid' of the request being responded to.<br />
<br />
If the connection manager is permitted to hold more than one request at a time, then the reception of a lower-than-expected 'ack' value from the connection manager (or the unexpected abscence of an 'ack' attribute) can give the client an early warning that a network failure might have occurred (e.g., if the client believes the connection manager should have received another request by the time it responded).<br />
===Response Acknowledgements===<br />
<br />
The client MAY similarly inform the connection manager about the responses it has received by setting the 'ack' attribute of any request to the value of the highest 'rid' of a request for which it has already received a response in the case where it has also received all responses associated with lower 'rid' values. If the client will be including 'ack' attributes on requests during a session, then it MUST include an 'ack' attribute (set to '1') in its session creation request, and set the 'ack' attribute of requests throughout the session. The only exception is that, after its session creation request, the client SHOULD NOT include an 'ack' attribute in any request if it has received responses to all its previous requests.<br />
<br />
'''Example 9. Request with response acknowledgement'''<br />
<source lang="xml"><br />
POST /webclient HTTP/1.1<br />
Host: httpcm.example.com<br />
Accept-Encoding: gzip, deflate<br />
Content-Type: text/xml; charset=utf-8<br />
Content-Length: 88<br />
<br />
<body rid='1249243566'<br />
sid='SomeSID'<br />
ack='1249243564'<br />
xmlns='http://jabber.org/protocol/httpbind'/><br />
</source><br />
<br />
After receiving a request with an 'ack' value less than the 'rid' of the last request that it has already responded to, the connection manager MAY inform the client of the situation by sending its next response immediately instead of waiting until it has payloads to send to the client (e.g., if some time has passed since it responded). In this case it SHOULD include a 'report' attribute set to one greater than the 'ack' attribute it received from the client, and a 'time' attribute set to the number of milliseconds since it sent the response associated with the 'report' attribute.<br />
<br />
'''Example 10. Response with report'''<br />
<source lang="xml"><br />
HTTP/1.1 200 OK<br />
Content-Type: text/xml; charset=utf-8<br />
Content-Length: 64<br />
<br />
<body report='1249243565'<br />
time='852'<br />
xmlns='http://jabber.org/protocol/httpbind'/><br />
</source><br />
<br />
Upon reception of a response with 'report' and 'time' attributes, if the client has still not received the response associated with the request identifier specified by the 'report' attribute, then it MAY choose to resend the request associated with the missing response (see Broken Connections).<br />
<br />
==Inactivity==<br />
<br />
After receiving a response from the connection manager, if none of the client's requests are still being held by the connection manager (and if the session is not a Polling Session), the client SHOULD make a new request as soon as possible. In any case, if no requests are being held, the client MUST make a new request before the maximum inactivity period has expired. The length of this period (in seconds) is specified by the 'inactivity' attribute in the session creation response.<br />
<br />
If the connection manager has responded to all the requests it has received within a session and the time since its last response is longer than the maximum inactivity period, then it SHOULD assume the client has been disconnected and terminate the session without informing the client. If the client subsequently makes another request, then the connection manager SHOULD respond as if the session does not exist.<br />
<br />
If the connection manager did not specify a maximum inactivity period in the session creation response, then it SHOULD allow the client to be inactive for as long as it chooses.<br />
<br />
If the session is not a polling session then the connection manager SHOULD specify a relatively short inactivity period to ensure that disconnections are discovered as quickly as possible. The RECOMMENDED time would be a little more than the number of seconds for a comfortable network round trip between the connection manager and the client under difficult network conditions (since the client can be expected to make a new request immediately -- see above).<br />
<br />
If a client encounters an exceptional temporary situation during which it will be unable to send requests to the connection manager for a period of time greater than the maximum inactivity period (e.g., while a runtime environment changes from one web page to another), and if the connection manager included a 'maxpause' attribute in its Session Creation Response, then the client MAY request a temporary increase to the maximum inactivity period by including a 'pause' attribute in a request. Note: If the connection manager did not specify a 'maxpause' attribute at the start of the session then the client MUST NOT send a 'pause' attribute during the session.<br />
<br />
'''Example 11. Requesting a Session Pause'''<br />
<source lang="xml"><br />
POST /webclient HTTP/1.1<br />
Host: httpcm.example.com<br />
Accept-Encoding: gzip, deflate<br />
Content-Type: text/xml; charset=utf-8<br />
Content-Length: 98<br />
<br />
<body rid='1249243564'<br />
sid='SomeSID'<br />
pause='60'<br />
xmlns='http://jabber.org/protocol/httpbind'/><br />
</source><br />
<br />
Upon reception of a session pause request, if the requested period is not greater than the maximum permitted time, then the connection manager SHOULD respond immediately to all pending requests (including the pause request) and temporarily increase the maximum inactivity period to the requested time. Note: The response to the pause request MUST NOT contain any payloads.<br />
<br />
Note: If the client simply wants the connection manager to return all the requests it is holding then it MAY set the value of the 'pause' attribute to be the value of the 'inactivity' attribute in the connection manager's session creation response. (If the client believes it is in danger of becoming disconnected indefinitely then it MAY even request a temporary reduction of the maximum inactivity period by specifying a 'pause' value less than the 'inactivity' value, thus enabling the connection manager to discover any subsequent disconnection more quickly.)<br />
<br />
The connection manager SHOULD set the maximum inactivity period back to normal upon reception of the next request from the client (assuming the connection manager has not already terminated the session).<br />
11. Overactivity<br />
<br />
The client SHOULD NOT make more simultaneous requests than specified by the 'requests' attribute in the connection manager's Session Creation Response. However the client MAY make one additional request if it is to pause or terminate a session.<br />
<br />
If during any period the client sends a sequence of new requests (i.e. requests with incremented rid attributes, not repeat requests) longer than the number specified by the 'requests' attribute, and if the connection manager has not yet responded to any of the requests, and if the last request did not include either a 'pause' attribute or a 'type' attribute set to "terminate", then the connection manager SHOULD consider that the client is making too many simultaneous requests, and terminate the HTTP session with a 'policy-violation' terminal binding error to the client. Note: This behavior applies to equally to normal and polling sessions.<br />
<br />
'''Example 12. Too many simultaneous requests response'''<br />
<source lang="xml"><br />
HTTP/1.1 200 OK<br />
Content-Type: text/xml; charset=utf-8<br />
Content-Length: 68<br />
<br />
<body type='terminate'<br />
condition='policy-violation'<br />
xmlns='http://jabber.org/protocol/httpbind'/><br />
</source><br />
<br />
Note: If the connection manager did not specify a 'requests' attribute in the session creation response, then it MUST allow the client to send as many simultaneous requests as it chooses.<br />
<br />
If during any period the client sends a sequence of new requests equal in length to the number specified by the 'requests' attribute, and if the connection manager has not yet responded to any of the requests, and if the last request was empty and did not include either a 'pause' attribute or a 'type' attribute set to "terminate", and if the last two requests arrived within a period shorter than the number of seconds specified by the 'polling' attribute in the session creation response, then the connection manager SHOULD consider that the client is making requests more frequently than it was permitted and terminate the HTTP session and return a 'policy-violation' terminal binding error to the client. Note: the behavior for Polling Sessions is slightly different.<br />
<br />
'''Example 13. Too frequent requests response'''<br />
<source lang="xml"><br />
HTTP/1.1 200 OK<br />
Content-Type: text/xml; charset=utf-8<br />
Content-Length: 68<br />
<br />
<body type='terminate'<br />
condition='policy-violation'<br />
xmlns='http://jabber.org/protocol/httpbind'/><br />
</source><br />
<br />
Note: If the connection manager did not specify a 'polling' attribute in the session creation response, then it MUST allow the client to send requests as frequently as it chooses.<br />
<br />
==Polling Sessions==<br />
<br />
It is not always possible for a constrained client to either use HTTP Pipelining or open more than one HTTP connection with the connection manager at a time. In this case the client SHOULD inform the connection manager by setting the values of the 'wait' and/or 'hold' attributes in its session creation request to "0", and then "poll" the connection manager at regular intervals throughout the session for payloads it might have received from the server. Note: Even if the client does not request a polling session, the connection manager MAY require a client to use polling by setting the 'requests' attribute (which specifies the number of simultaneous requests the client can make) of its Session Creation Response to "1", however this is NOT RECOMMENDED.<br />
<br />
If a session will use polling, the connection manager SHOULD specify a higher than normal value for the 'inactivity' attribute (see Inactivity) in its session creation response. The increase SHOULD be greater than the value it specifies for the 'polling' attribute.<br />
<br />
If the client sends two consecutive empty new requests (i.e. requests with incremented rid attributes, not repeat requests) within a period shorter than the number of seconds specified by the 'polling' attribute (the shortest allowable polling interval) in the session creation response, and if the connection manager's response to the first request contained no payloads, then upon reception of the second request the connection manager SHOULD terminate the HTTP session and return a 'policy-violation' terminal binding error to the client.<br />
<br />
'''Example 14. Too frequent polling response'''<br />
<source lang="xml"><br />
HTTP/1.1 200 OK<br />
Content-Type: text/xml; charset=utf-8<br />
Content-Length: 68<br />
<br />
<body type='terminate'<br />
condition='policy-violation'<br />
xmlns='http://jabber.org/protocol/httpbind'/><br />
</source><br />
<br />
Note: If the connection manager did not specify a 'polling' attribute in the session creation response, then it MUST allow the client to poll as frequently as it chooses.<br />
<br />
==Terminating the HTTP Session==<br />
<br />
At any time, the client MAY gracefully terminate the session by sending a <body/> element with a 'type' attribute set to "terminate". The termination request MAY include one or more payloads that the connection manager MUST forward to the server to ensure graceful logoff.<br />
<br />
'''Example 15. Session termination by client'''<br />
<source lang="xml"><br />
POST /webclient HTTP/1.1<br />
Host: httpcm.example.com<br />
Accept-Encoding: gzip, deflate<br />
Content-Type: text/xml; charset=utf-8<br />
Content-Length: 153<br />
<br />
<body rid='1249243565'<br />
sid='SomeSID'<br />
type='terminate'<br />
xmlns='http://jabber.org/protocol/httpbind'><br />
<presence type='unavailable'<br />
xmlns='jabber:client'/><br />
</body><br />
</source><br />
<br />
The connection manager SHOULD respond to this request with an HTTP 200 OK containing an empty <body/> element.<br />
<br />
'''Example 16. Connection manager acknowledges termination'''<br />
<source lang="xml"><br />
HTTP/1.1 200 OK<br />
Content-Type: text/xml; charset=utf-8<br />
Content-Length: 72<br />
<br />
<body type='terminate'<br />
xmlns='http://jabber.org/protocol/httpbind'/><br />
</source><br />
<br />
Upon receiving the response, the client MUST consider the HTTP session to have been terminated.<br />
<br />
==Request IDs==<br />
===Generation===<br />
<br />
The client MUST generate a large, random, positive integer for the initial 'rid' (see Security Considerations) and then increment that value by one for each subsequent request. The client MUST take care to choose an initial 'rid' that will never be incremented above 9007199254740991 [21] within the session. In practice, a session would have to be extraordinarily long (or involve the exchange of an extraordinary number of packets) to exceed the defined limit.<br />
===In-Order Message Forwarding===<br />
<br />
When a client makes simultaneous requests, the connection manager might receive them out of order. The connection manager MUST forward the payloads to the server and respond to the client requests in the order specified by the 'rid' attributes. The client MUST process responses received from the connection manager in the order the requests were made.<br />
<br />
The connection manager SHOULD expect the 'rid' attribute to be within a window of values greater than the 'rid' of the previous request. The size of the window is equal to the maximum number of simultaneous requests allowed by the connection manager. If it receives a request with a 'rid' greater than the values in the window, then the connection manager MUST terminate the session with an error:<br />
<br />
'''Example 17. Unexpected rid error'''<br />
<source lang="xml"><br />
HTTP/1.1 200 OK<br />
Content-Type: text/xml; charset=utf-8<br />
Content-Length: 68<br />
<br />
<body type='terminate'<br />
condition='item-not-found'<br />
xmlns='http://jabber.org/protocol/httpbind'/><br />
</source><br />
<br />
===Broken Connections===<br />
<br />
Unreliable network communications or client constraints can result in broken connections. The connection manager SHOULD remember the 'rid' and the associated HTTP response body of the client's most recent requests which were not session pause requests (see Inactivity) and which did not result in an HTTP or binding error. The number of responses to non-pause requests kept in the buffer SHOULD be either the same as the maximum number of simultaneous requests allowed by the connection manager or, if Acknowledgements are being used, the number of responses that have not yet been acknowledged.<br />
<br />
If the network connection is broken or closed before the client receives a response to a request from the connection manager, then the client MAY resend an exact copy of the original request. Whenever the connection manager receives a request with a 'rid' that it has already received, it SHOULD return an HTTP 200 (OK) response that includes the buffered copy of the original XML response to the client (i.e., a <body/> wrapper possessing appropriate attributes and optionally containing one or more XML payloads). If the original response is not available (e.g., it is no longer in the buffer), then the connection manager MUST return an 'item-not-found' terminal binding error:<br />
<br />
'''Example 18. Response not in buffer error'''<br />
<source lang="xml"><br />
HTTP/1.1 200 OK<br />
Content-Type: text/xml; charset=utf-8<br />
Content-Length: 68<br />
<br />
<body type='terminate'<br />
condition='item-not-found'<br />
xmlns='http://jabber.org/protocol/httpbind'/><br />
</source><br />
<br />
Note: The error is the same whether the 'rid' is too large or too small. This makes it more difficult for an attacker to discover an acceptable value.<br />
<br />
==Protecting Insecure Sessions==<br />
===Applicability===<br />
<br />
The OPTIONAL key sequencing mechanism described here MAY be used if the client's session with the connection manager is not secure. The session SHOULD be considered secure only if all client requests are made via SSL (or TLS) HTTP connections and the connection manager generates an unpredictable session ID. If the session is secure, it is not necessary to use this key sequencing mechanism.<br />
<br />
Even if the session is not secure, the unpredictable session and request IDs specified in the preceding sections of this document already provide a level of protection similar to that provided by a connection bound to a single pair of persistent TCP/IP connections, and thus provide sufficient protection against a 'blind' attacker. However, in some circumstances, the key sequencing mechanism defined below helps to protect against a more determined and knowledgeable attacker.<br />
<br />
It is important to recognize that the key sequencing mechanism defined below helps to protect only against an attacker who is able to view the contents of all requests or responses in an insecure session but who is not able to alter the contents of those requests (in this case, the mechanism prevents the attacker from injecting HTTP requests into the session, e.g., termination requests or responses). However, the key sequencing mechanism does not provide any protection when the attacker is able to alter the contents of insecure requests or responses.<br />
===Introduction===<br />
<br />
The HTTP requests of each session MAY be spread across a series of different socket connections. This would enable an unauthorized user that obtains the session ID and request ID of a session to then use their own socket connection to inject <body/> request elements into the session and receive the corresponding responses.<br />
<br />
The key sequencing mechanism below protects against such attacks by enabling a connection manager to detect <body/> request elements injected by a third party.<br />
===Generating the Key Sequence===<br />
<br />
Prior to requesting a new session, the client MUST select an unpredictable counter ("n") and an unpredictable value ("seed"). The client then processes the "seed" through a cryptographic hash and converts the resulting 160 bits to a hexadecimal string K(1). It does this "n" times to arrive at the initial key K(n). The hashing algorithm MUST be SHA-1 as defined in RFC 3174 [22].<br />
<br />
'''Example 19. Creating the key sequence'''<br />
<br />
K(1) = hex(SHA-1(seed))<br />
K(2) = hex(SHA-1(K(1)))<br />
...<br />
K(n) = hex(SHA-1(K(n-1)))<br />
<br />
<br />
===Use of Keys===<br />
<br />
The client MUST set the 'newkey' attribute of the first request in the session to the value K(n).<br />
<br />
'''Example 20. Session Request with Initial Key'''<br />
<source lang="xml"><br />
POST /webclient HTTP/1.1<br />
Host: httpcm.example.com<br />
Accept-Encoding: gzip, deflate<br />
Content-Type: text/xml; charset=utf-8<br />
Content-Length: 104<br />
<br />
<body content='text/xml; charset=utf-8'<br />
hold='1'<br />
rid='1573741820'<br />
to='example.com'<br />
wait='60'<br />
xml:lang='en'<br />
newkey='ca393b51b682f61f98e7877d61146407f3d0a770'<br />
xmlns='http://jabber.org/protocol/httpbind'/><br />
</source><br />
<br />
The client MUST set the 'key' attribute of all subsequent requests to the value of the next key in the generated sequence (decrementing from K(n-1) towards K(1) with each request sent).<br />
<br />
'''Example 21. Request with Key'''<br />
<source lang="xml"><br />
POST /webclient HTTP/1.1<br />
Host: httpcm.example.com<br />
Accept-Encoding: gzip, deflate<br />
Content-Type: text/xml; charset=utf-8<br />
Content-Length: 88<br />
<br />
<body rid='1573741821'<br />
sid='SomeSID'<br />
key='bfb06a6f113cd6fd3838ab9d300fdb4fe3da2f7d'<br />
xmlns='http://jabber.org/protocol/httpbind'/><br />
</source><br />
<br />
The connection manager MAY verify the key by calculating the SHA-1 hash of the key and comparing it to the 'newkey' attribute of the previous request (or the 'key' attribute if the 'newkey' attribute was not set). If the values do not match (or if it receives a request without a 'key' attribute and the 'newkey' or 'key' attribute of the previous request was set), then the connection manager MUST NOT process the element, MUST terminate the session, and MUST return an 'item-not-found' terminal binding error.<br />
<br />
'''Example 22. Invalid Key Sequence Error'''<br />
<source lang="xml"><br />
HTTP/1.1 200 OK<br />
Content-Type: text/xml; charset=utf-8<br />
Content-Length: 68<br />
<br />
<body type='terminate'<br />
condition='item-not-found'<br />
xmlns='http://jabber.org/protocol/httpbind'/><br />
</source><br />
<br />
===Switching to Another Key Sequence===<br />
<br />
A client SHOULD choose a high value for "n" when generating the key sequence. However, if the session lasts long enough that the client arrives at the last key in the sequence K(1) then the client MUST switch to a new key sequence.<br />
<br />
The client MUST:<br />
<br />
1. Choose new values for "seed" and "n".<br />
2. Generate a new key sequence using the algorithm defined above.<br />
3. Set the 'key' attribute of the request to the next value in the old sequence (i.e. K(1), the last value).<br />
4. Set the 'newkey' attribute of the request to the value K(n) from the new sequence.<br />
<br />
'''Example 23. New Key Sequence'''<br />
<source lang="xml"><br />
POST /webclient HTTP/1.1<br />
Host: httpcm.example.com<br />
Accept-Encoding: gzip, deflate<br />
Content-Type: text/xml; charset=utf-8<br />
Content-Length: 188<br />
<br />
<body rid='1573741822'<br />
sid='SomeSID'<br />
key='6f825e81f4532b2c5fa2d12457d8a1f22e8f838e'<br />
newkey='113f58a37245ec9637266cf2fb6e48bfeaf7964e'<br />
xmlns='http://jabber.org/protocol/httpbind'><br />
<message to='contact@example.com'<br />
xmlns='jabber:client'><br />
<body>I said "Hi!"</body><br />
</message><br />
</body><br />
</source><br />
<br />
==Multiple Streams==<br />
===Introduction===<br />
<br />
The OPTIONAL feature described in this section enables multiple XML streams to be contained within a single HTTP session. This feature is essential in runtime environments that prevent HTTP Pipelining, thereby constraining the number of simultaneous HTTP requests a client can make to each connection manager, since clients running in such environments need multi-stream sessions if they are to connect using more than one account at the same time. This feature also reduces network traffic for any client that needs to establish parallel streams over HTTP.<br />
===Discovery===<br />
<br />
If a connection manager supports the multi-streams feature, it MUST include a 'stream' attribute in its Session Creation Response. If a client does not receive the 'stream' attribute then it MUST assume that the connection manager does not support the feature. [23]<br />
<br />
The 'stream' attribute identifies the first stream to be opened for the session. The value of each 'stream' attribute MUST be an opaque and unpredictable name that is unique within the context of the connection manager application.<br />
<br />
'''Example 24. Session creation response with stream name'''<br />
<source lang="xml"><br />
HTTP/1.1 200 OK<br />
Content-Type: text/xml; charset=utf-8<br />
Content-Length: 128<br />
<br />
<body wait='60'<br />
inactivity='30'<br />
polling='5'<br />
requests='2'<br />
hold='1'<br />
accept='deflate,gzip'<br />
stream='firstStreamName'<br />
maxpause='120'<br />
sid='SomeSID'<br />
charsets='ISO_8859-1 ISO-2022-JP'<br />
ver='1.6'<br />
from='example.com'<br />
xmlns='http://jabber.org/protocol/httpbind'/><br />
</source><br />
<br />
===Adding Streams To A Session===<br />
<br />
If the connection manager included a 'stream' attribute in its session creation response then the client MAY ask it to open another stream at any time by sending it an empty <body/> element with a 'to' attribute. The request MUST include valid 'sid' and 'rid' [24] attributes, and SHOULD also include an 'xml:lang' attribute. The request MAY include 'route', 'from' and 'secure' attributes (see Session Creation Request), but it SHOULD NOT include 'ver', 'content', 'hold' or 'wait' attributes (since a new session is not being created).<br />
<br />
'''Example 25. Requesting another stream'''<br />
<source lang="xml"><br />
POST /webclient HTTP/1.1<br />
Host: httpcm.example.com<br />
Accept-Encoding: gzip, deflate<br />
Content-Type: text/xml; charset=utf-8<br />
Content-Length: 104<br />
<br />
<body sid='SomeSID'<br />
rid='1573741820'<br />
to='example.com'<br />
route='xmpp:example.com:9999'<br />
xml:lang='en'<br />
xmlns='http://jabber.org/protocol/httpbind'/><br />
</source><br />
<br />
If the connection manager did not indicate its support for multiple streams at the start of the session, then it MUST ignore the extra attributes and treat the request as a normal empty request for payloads (see Sending and Receiving XML Payloads). [25] Otherwise it MUST open a new stream with the specified server (see Session Creation Response), generate a new stream name, and respond to the client with the name. The response MAY also include 'from' and 'secure' attributes, but it SHOULD NOT include 'sid', 'requests', 'polling', 'hold', 'inactivity', 'maxpause', 'accept', 'charsets', 'ver' or 'wait' attributes.<br />
<br />
'''Example 26. Add stream response'''<br />
<source lang="xml"><br />
HTTP/1.1 200 OK<br />
Content-Type: text/xml; charset=utf-8<br />
Content-Length: 128<br />
<br />
<body stream='secondStreamName'<br />
from='example.com'<br />
xmlns='http://jabber.org/protocol/httpbind'/><br />
</source><br />
<br />
Note: If the response did not include either 'from' or 'secure' attributes then they MAY be sent in a subsequent response instead (see Session Creation Response). In that case the 'stream' attribute MUST also be specified.<br />
===Transmitting Payloads===<br />
<br />
If more than one stream has been opened within a session, then all non-empty <body/> elements sent by the connection manager MUST include a 'stream' attribute that specifies which stream all the payloads it contains belong to. The client SHOULD include a 'stream' attribute for the same purpose. The client MAY omit the 'stream' attribute if it wants the connection manager to broadcast the payloads over all open streams. Note: A <body/> element MUST NOT contain different payloads for different streams.<br />
<br />
If a stream name does not correspond to one of the session's open streams, then the receiving connection manager SHOULD return an 'item-not-found' terminal binding error, or the receiving client SHOULD terminate the session. However, if the receiving entity has only just closed the stream (and the sender might not have been aware of that when it sent the payloads), then it MAY instead simply silently ignore any payloads the <body/> element contains.<br />
<br />
Note: Empty <body/> elements that do not include a 'from' or 'secure' attribute SHOULD NOT include a 'stream' attribute (since nothing is being transmitted for any stream). If such a <body/> element does include a 'stream' attribute then the receiving entity SHOULD ignore the attribute.<br />
<br />
'''Example 27. Client sends payload with a stream name'''<br />
<source lang="xml"><br />
POST /webclient HTTP/1.1<br />
Host: httpcm.example.com<br />
Accept-Encoding: gzip, deflate<br />
Content-Type: text/xml; charset=utf-8<br />
Content-Length: 188<br />
<br />
<body rid='1249243562'<br />
sid='SomeSID'<br />
stream='secondStreamName'<br />
xmlns='http://jabber.org/protocol/httpbind'><br />
<message to='contact@example.com'<br />
xmlns='jabber:client'><br />
<body>I said hello.</body><br />
</message><br />
</body><br />
</source><br />
<br />
Note: The value of the 'stream' attribute of the response MAY be different than the corresponding request. [26]<br />
<br />
'''Example 28. Connection manager responds with a different stream name'''<br />
<source lang="xml"><br />
HTTP/1.1 200 OK<br />
Content-Type: text/xml; charset=utf-8<br />
Content-Length: 185<br />
<br />
<body stream='firstStreamName'<br />
xmlns='http://jabber.org/protocol/httpbind'><br />
<message from='contact@example.com'<br />
to='user@example.com'<br />
xmlns='jabber:client'><br />
<body>Hi yourself!</body><br />
</message><br />
</body><br />
</source><br />
<br />
If no stream name is specified by the connection manager then the client MUST assume the payloads are associated with the first stream (even if the first stream has been closed).<br />
<br />
If no stream name is specified by the client then the connection manager MUST broadcast the payloads over all open streams. [27]<br />
<br />
'''Example 29. Client asks for a payload to be broadcast'''<br />
<source lang="xml"><br />
POST /webclient HTTP/1.1<br />
Host: httpcm.example.com<br />
Accept-Encoding: gzip, deflate<br />
Content-Type: text/xml; charset=utf-8<br />
Content-Length: 188<br />
<br />
<body rid='1249243562'<br />
sid='SomeSID'<br />
xmlns='http://jabber.org/protocol/httpbind'><br />
<presence xmlns='jabber:client'><br />
<show>away</show><br />
</presence><br />
</body><br />
</source><br />
<br />
===Closing a Stream===<br />
<br />
If more than one stream is open within a session, the client MAY close one open stream at any time using the procedure described in the section Terminating the HTTP Session above, taking care to specify the stream name with a 'stream' attribute. If the client closes the last stream the connection manager MUST terminate the session. If the client does not specify a stream name then the connection manager MUST close all open streams (sending any payloads the terminate request contains to all streams), and terminate the session.<br />
<br />
'''Example 30. Client closes one stream'''<br />
<source lang="xml"><br />
POST /webclient HTTP/1.1<br />
Host: httpcm.example.com<br />
Accept-Encoding: gzip, deflate<br />
Content-Type: text/xml; charset=utf-8<br />
Content-Length: 153<br />
<br />
<body rid='1249243564'<br />
sid='SomeSID'<br />
stream='secondStreamName'<br />
type='terminate'<br />
xmlns='http://jabber.org/protocol/httpbind'><br />
<presence type='unavailable'<br />
xmlns='jabber:client'/><br />
</body><br />
</source><br />
<br />
===Error Conditions===<br />
<br />
If more than one stream is open within a session, the connection manager MAY include a 'stream' attribute in a fatal binding error (see Terminal Binding Conditions). If a 'stream' attribute is specified then the stream MUST be closed by both entities but the session SHOULD NOT be terminated.<br />
<br />
'''Example 31. Fatal stream error'''<br />
<source lang="xml"><br />
HTTP/1.1 200 OK<br />
Content-Type: text/xml; charset=utf-8<br />
Content-Length: 68<br />
<br />
<body type='terminate'<br />
condition='remote-connection-failed'<br />
stream='secondStreamName'<br />
xmlns='http://jabber.org/protocol/httpbind'/><br />
</source><br />
<br />
Note: If the connection manager does not include a 'stream' attribute in a fatal binding error then all the session's open streams MUST be closed by both entities and the session MUST be terminated.<br />
<br />
==Error and Status Codes==<br />
<br />
There are four types of error and status reporting in HTTP responses:<br />
<br />
Table 1: Error Condition Types<br />
Condition Type Description<br />
HTTP Conditions (Deprecated) The connection manager responds to an invalid request from a legacy client with a standard HTTP error. These are used for binding syntax errors, possible attacks, etc. Note that constrained clients are unable to differentiate between HTTP errors.<br />
Terminal Binding Conditions These error conditions can be read by constrained clients. They are used for connection manager problems, abstracting stream errors, communication problems between the connection manager and the server, and invalid client requests (binding syntax errors, possible attacks, etc.)<br />
Recoverable Binding Conditions These report communication problems between the connection manager and the client. They do not terminate the session. Clients recover from these errors by resending all the preceding <body/> wrappers that have not received responses.<br />
Transported Protocol Conditions Errors relating to the XML payloads within <body/> wrappers are, in general, defined in the documentation of the protocol being transported. They do not terminate the session.<br />
<br />
Full descriptions are provided below.<br />
===HTTP Conditions===<br />
<br />
Note: All HTTP codes except 200 have been superseded by Terminal Binding Conditions to allow clients to determine whether the source of errors is the connection manager application or an HTTP intermediary.<br />
<br />
A legacy client (or connection manager) is a client (or connection manager) that did not include a 'ver' attribute in its session creation request (or response). A legacy client (or connection manager) will interpret (or respond with) HTTP error codes according to the table below. Non-legacy connection managers SHOULD NOT send HTTP error codes unless they are communicating with a legacy client. Upon receiving an HTTP error (400, 403, 404), a legacy client or any client that is communicating with a legacy connection manager MUST consider the HTTP session to be null and void. A non-legacy client that is communicating with a non-legacy connection manager MAY consider that the session is still active.<br />
<br />
Table 2: HTTP Error and Status Codes<br />
Code Name Superseded by Purpose<br />
200 OK - Response to valid client request.<br />
400 Bad Request bad-request Inform client that the format of an HTTP header or binding element is unacceptable (e.g., syntax error).<br />
403 Forbidden policy-violation Inform client that it has broken the session rules (polling too frequently, requesting too frequently, too many simultaneous requests).<br />
404 Not Found item-not-found Inform client that (1) 'sid' is not valid, (2) 'stream' is not valid, (3) 'rid' is larger than the upper limit of the expected window, (4) connection manager is unable to resend response, (5) 'key' sequence is invalid.<br />
<br />
Note: No other HTTP error and status codes were defined in the early versions of BOSH (e.g., Internal Server Error).<br />
===Terminal Binding Conditions===<br />
<br />
In any response it sends to the client, the connection manager MAY return a fatal error by setting a 'type' attribute of the <body/> element to "terminate". These binding errors imply that the HTTP session is terminated (unless a 'stream' attribute is specified -- see Multiple Stream Error Conditions).<br />
<br />
Note: Although many of these conditions are similar to the XMPP stream error conditions specified in RFC 6120, they are not to be confused with XMPP stream errors. In cases where BOSH is being used to transport XMPP, any fatal XMPP stream error conditions experienced between the connection manager and the XMPP server SHOULD only be reported using the "remote-stream-error" condition as described below.<br />
<br />
'''Example 32. Remote connection failed error'''<br />
<source lang="xml"><br />
HTTP/1.1 200 OK<br />
Content-Type: text/xml; charset=utf-8<br />
Content-Length: 68<br />
<br />
<body type='terminate'<br />
condition='remote-connection-failed'<br />
xmlns='http://jabber.org/protocol/httpbind'/><br />
</source><br />
<br />
The following values of the 'condition' attribute are defined:<br />
<br />
Table 3: Terminal Binding Error Conditions<br />
Condition Purpose<br />
bad-request* The format of an HTTP header or binding element received from the client is unacceptable (e.g., syntax error).<br />
host-gone The target domain specified in the 'to' attribute or the target host or port specified in the 'route' attribute is no longer serviced by the connection manager.<br />
host-unknown The target domain specified in the 'to' attribute or the target host or port specified in the 'route' attribute is unknown to the connection manager.<br />
improper-addressing The initialization element lacks a 'to' or 'route' attribute (or the attribute has no value) but the connection manager requires one.<br />
internal-server-error The connection manager has experienced an internal error that prevents it from servicing the request.<br />
item-not-found* (1) 'sid' is not valid, (2) 'stream' is not valid, (3) 'rid' is larger than the upper limit of the expected window, (4) connection manager is unable to resend response, (5) 'key' sequence is invalid.<br />
other-request Another request being processed at the same time as this request caused the session to terminate.<br />
policy-violation* The client has broken the session rules (polling too frequently, requesting too frequently, sending too many simultaneous requests).<br />
remote-connection-failed The connection manager was unable to connect to, or unable to connect securely to, or has lost its connection to, the server.<br />
remote-stream-error Encapsulates an error in the protocol being transported.<br />
see-other-uri The connection manager does not operate at this URI (e.g., the connection manager accepts only SSL or TLS connections at some https: URI rather than the http: URI requested by the client). The client can try POSTing to the URI in the content of the <uri/> child element.<br />
system-shutdown The connection manager is being shut down. All active HTTP sessions are being terminated. No new sessions can be created.<br />
undefined-condition The error is not one of those defined herein; the connection manager SHOULD include application-specific information in the content of the <body/> wrapper.<br />
<br />
* If the client did not include a 'ver' attribute in its session creation request then the connection manager SHOULD send a deprecated HTTP Error Condition instead of this terminal binding condition. If the connection manager did not include a 'ver' attribute in its session creation response then the client SHOULD expect it to send a deprecated HTTP Error Condition instead of this terminal binding condition.<br />
<br />
The following is an example of a "see-other-uri" condition:<br />
<br />
'''Example 33. See other URI error'''<br />
<source lang="xml"><br />
HTTP/1.1 200 OK<br />
Content-Type: text/xml; charset=utf-8<br />
Content-Length: 68<br />
<br />
<body condition='see-other-uri'<br />
type='terminate'<br />
xmlns='http://jabber.org/protocol/httpbind'><br />
<uri>https://secure.jabber.org/xmppcm</uri><br />
</body><br />
</source><br />
<br />
The following is an example including a "remote-stream-error" condition:<br />
<br />
'''Example 34. Remote error'''<br />
<source lang="xml"><br />
HTTP/1.1 200 OK<br />
Content-Type: text/xml; charset=utf-8<br />
Content-Length: 68<br />
<br />
<body condition='remote-stream-error'<br />
type='terminate'<br />
xmlns='http://jabber.org/protocol/httpbind'<br />
xmlns:stream='http://etherx.jabber.org/streams'><br />
<message from='contact@example.com'<br />
to='user@example.com'<br />
xmlns='jabber:client'><br />
<body>I said "Hi!"</body><br />
</message><br />
<stream:error><br />
<xml-not-well-formed xmlns='urn:ietf:params:xml:ns:xmpp-streams'/><br />
<text xmlns='urn:ietf:params:xml:ns:xmpp-streams'<br />
xml:lang='en'><br />
Some special application diagnostic information!<br />
</text><br />
<escape-your-data xmlns='application-ns'/><br />
</stream:error><br />
</body><br />
</source><br />
<br />
Naturally, the client MAY report binding errors to the connection manager as well, although this is unlikely.<br />
===Recoverable Binding Conditions===<br />
<br />
In any response it sends to the client, the connection manager MAY return a recoverable error by setting a 'type' attribute of the <body/> element to "error". These errors do not imply that the HTTP session is terminated.<br />
<br />
If it decides to recover from the error, then the client MUST repeat the HTTP request that resulted in the error, as well as all the preceding HTTP requests that have not received responses. The content of these requests MUST be identical to the <body/> elements of the original requests. This enables the connection manager to recover a session after the previous request was lost due to a communication failure.<br />
<br />
'''Example 35. Recoverable error'''<br />
<source lang="xml"><br />
HTTP/1.1 200 OK<br />
Content-Type: text/xml; charset=utf-8<br />
Content-Length: 68<br />
<br />
<body type='error'<br />
xmlns='http://jabber.org/protocol/httpbind'/><br />
</source><br />
<br />
===XML Payload Conditions===<br />
<br />
Application-level error conditions described in the documentation of the protocol being transported are routed to the client through the connection manager. They are transparent to the connection manager, and therefore out of scope for the transport binding defined herein.<br />
<br />
==Implementation Notes==<br />
===HTTP Pipelining===<br />
<br />
Even if the client requests HTTP Pipelining and the connection manager supports it, there is no guarantee that pipelining will succeed, because it might not be supported by intermediate proxies.<br />
<br />
The best the client can do is to request the use of HTTP Pipelining by setting the 'hold' attribute to a value of "1". If HTTP Pipelining does not work (because the server returns HTTP 1.0 or connection:close), then the client SHOULD degrade gracefully by using multiple connections.<br />
<br />
==Security Considerations==<br />
===Connection Between Client and BOSH Service===<br />
<br />
All communications between a client and a BOSH service SHOULD occur over encrypted HTTP connections. Negotiation of encryption between the client and the connection manager SHOULD occur at the transport layer or the HTTP layer, not the application layer; such negotiation SHOULD follow the HTTP/SSL protocol defined in SSL [28], although MAY follow the HTTP/TLS protocol defined in RFC 2818 [29] or the TLS Within HTTP protocol defined in RFC 2817 [30].<br />
<br />
If the HTTP connection used to send the initial session request is encrypted, then all the other HTTP connections used within the session MUST also be encrypted. Furthermore, if authentication certificates are exchanged when establishing the encrypted connection that is used to send the initial session request, then the client and/or connection manager SHOULD ensure that the same authentication certificates are employed for all subsequent connections used by the session. Once such a "secure session" has been established:<br />
<br />
* If the connection manager refuses to establish an encrypted connection or offers a different certificate, then the client SHOULD close the connection and terminate the session without sending any more requests.<br />
* If the client sends a wrapper element that is part of a "secure session" over a connection that either is not encrypted or uses a different certificate, then the connection manager SHOULD simply close the connection. The connection manager SHOULD NOT terminate the session since that would facilitate denial of service attacks.<br />
<br />
===Connection Between BOSH Service and Application===<br />
<br />
A BOSH service SHOULD encrypt its connection to the backend application using appropriate technologies such as Secure Sockets Layer (SSL), Transport Layer Security (TLS), and StartTLS if supported by the backend application. Alternatively, the BOSH service can be considered secure (1) if it is running on the same physical machine as the backend application or (2) if it running on the same private network as the backend application and the administrators are sure that unknown individuals or processes do not have access to that private network.<br />
<br />
If data privacy is desired, the client SHOULD encrypt its messages using an application-specific end-to-end encryption technology, because there is no way for the client to be sure that the BOSH service encrypts its connection to the application; methods for doing so are outside the scope of this specification.<br />
===Unpredictable SID and RID===<br />
<br />
The session identifier (SID) and initial request identifier (RID) are security-critical and therefore MUST be both unpredictable and nonrepeating (see RFC 1750 [31] for recommendations regarding randomness of SIDs and initial RIDs for security purposes).<br />
===Use of SHA-1===<br />
<br />
Recent research has shown that in select cases it is possible to compromise the hashes produced by the SHA-1 hashing algorithm (see RFC 4270 [32]). However, the use to which SHA-1 is put in BOSH will likely minimize the applicability of the attacks described in the literature. Furthermore, current estimates suggest that even with the recently-discovered attack, it would still take one year of computing by a government-sized entity to produce a collision.<br />
<br />
==IANA Considerations==<br />
<br />
TCP port 5280, conventially used for communication between BOSH clients and BOSH connection mangers, is registered with the Internet Assigned Numbers Authority (IANA) [33] in its port registry at IANA Port Numbers Registry [34], with a keyword of "xmpp-bosh". (Although use of this port is OPTIONAL, it is helpful to define this port in a standardized way so that BOSH clients can contact any given XMPP service via BOSH without the need either for DNS TXT records as described in Discovering Alternative XMPP Connection Methods [35] or for more advanced methods such as U-NAPTR.<br />
<br />
==XMPP Registrar Considerations==<br />
===Protocol Namespaces===<br />
<br />
The XMPP Registrar includes 'http://jabber.org/protocol/httpbind' in its registry of protocol namespaces.<br />
<br />
==XML Schema==<br />
<source lang="xml"><br />
<?xml version='1.0' encoding='UTF-8'?><br />
<br />
<xs:schema<br />
xmlns:xs='http://www.w3.org/2001/XMLSchema'<br />
xmlns:stream='http://etherx.jabber.org/streams'<br />
targetNamespace='http://jabber.org/protocol/httpbind'<br />
xmlns='http://jabber.org/protocol/httpbind'<br />
elementFormDefault='qualified'><br />
<br />
<xs:annotation><br />
<xs:documentation><br />
The protocol documented by this schema is defined in<br />
XEP-0124: http://www.xmpp.org/extensions/xep-0124.html<br />
</xs:documentation><br />
</xs:annotation><br />
<br />
<xs:import namespace='http://www.w3.org/XML/1998/namespace'<br />
schemaLocation='http://www.w3.org/2001/03/xml.xsd'/><br />
<br />
<xs:element name='body'><br />
<xs:complexType><br />
<xs:choice><br />
<xs:element name='uri'<br />
minOccurs='0'<br />
maxOccurs='1'<br />
type='xs:string'/><br />
<xs:any namespace='##other'<br />
minOccurs='0'<br />
maxOccurs='unbounded'<br />
processContents='lax'/><br />
</xs:choice><br />
<xs:attribute name='accept' type='xs:string' use='optional'/><br />
<xs:attribute name='ack' type='xs:positiveInteger' use='optional'/><br />
<xs:attribute name='authid' type='xs:string' use='optional'/><br />
<xs:attribute name='charsets' type='xs:NMTOKENS' use='optional'/><br />
<xs:attribute name='condition' use='optional'><br />
<xs:simpleType><br />
<xs:restriction base='xs:NCName'><br />
<xs:enumeration value='bad-request'/><br />
<xs:enumeration value='host-gone'/><br />
<xs:enumeration value='host-unknown'/><br />
<xs:enumeration value='improper-addressing'/><br />
<xs:enumeration value='internal-server-error'/><br />
<xs:enumeration value='item-not-found'/><br />
<xs:enumeration value='other-request'/><br />
<xs:enumeration value='policy-violation'/><br />
<xs:enumeration value='remote-connection-failed'/><br />
<xs:enumeration value='remote-stream-error'/><br />
<xs:enumeration value='see-other-uri'/><br />
<xs:enumeration value='system-shutdown'/><br />
<xs:enumeration value='undefined-condition'/><br />
</xs:restriction><br />
</xs:simpleType><br />
</xs:attribute><br />
<xs:attribute name='content' type='xs:string' use='optional'/><br />
<xs:attribute name='from' type='xs:string' use='optional'/><br />
<xs:attribute name='hold' type='xs:unsignedByte' use='optional'/><br />
<xs:attribute name='inactivity' type='xs:unsignedShort' use='optional'/><br />
<xs:attribute name='key' type='xs:string' use='optional'/><br />
<xs:attribute name='maxpause' type='xs:unsignedShort' use='optional'/><br />
<xs:attribute name='newkey' type='xs:string' use='optional'/><br />
<xs:attribute name='pause' type='xs:unsignedShort' use='optional'/><br />
<xs:attribute name='polling' type='xs:unsignedShort' use='optional'/><br />
<xs:attribute name='report' type='xs:positiveInteger' use='optional'/><br />
<xs:attribute name='requests' type='xs:unsignedByte' use='optional'/><br />
<xs:attribute name='rid' type='xs:positiveInteger' use='optional'/><br />
<xs:attribute name='route' type='xs:string' use='optional'/><br />
<xs:attribute name='sid' type='xs:string' use='optional'/><br />
<xs:attribute name='stream' type='xs:string' use='optional'/><br />
<xs:attribute name='time' type='xs:unsignedShort' use='optional'/><br />
<xs:attribute name='to' type='xs:string' use='optional'/><br />
<xs:attribute name='type' use='optional'><br />
<xs:simpleType><br />
<xs:restriction base='xs:NCName'><br />
<xs:enumeration value='error'/><br />
<xs:enumeration value='terminate'/><br />
</xs:restriction><br />
</xs:simpleType><br />
</xs:attribute><br />
<xs:attribute name='ver' type='xs:string' use='optional'/><br />
<xs:attribute name='wait' type='xs:unsignedShort' use='optional'/><br />
<xs:attribute ref='xml:lang' use='optional'/><br />
<xs:anyAttribute namespace='##other' processContents='lax'/><br />
</xs:complexType><br />
</xs:element><br />
<br />
</xs:schema><br />
</source><br />
<br />
==Acknowledgements==<br />
<br />
Thanks to Mike Cumings, Tomas Karasek, Tobias Markmann, Chris Seymour, Safa Sofuoğlu, Stefan Strigler, Matthew Wild, Kevin Winters, and Christopher Zorn for their feedback.<br />
<br />
==Appendices==<br />
===Appendix A: Document Information===<br />
<br />
Series: XEP<br />
Number: 0124<br />
Publisher: XMPP Standards Foundation<br />
Status: Draft<br />
Type: Standards Track<br />
Version: 1.10<br />
Last Updated: 2010-07-02<br />
Approving Body: XMPP Council<br />
Dependencies: RFC 1945, RFC 2616, RFC 3174<br />
Supersedes: None<br />
Superseded By: None<br />
Short Name: bosh<br />
Schema: <http://www.xmpp.org/schemas/httpbind.xsd><br />
Source Control: HTML RSS<br />
This document in other formats: XML PDF<br />
===Appendix B: Author Information===<br />
Ian Paterson<br />
<br />
Email: ian.paterson@clientside.co.uk<br />
JabberID: ian@zoofy.com<br />
Dave Smith<br />
<br />
Email: dizzyd@jabber.org<br />
JabberID: dizzyd@jabber.org<br />
Peter Saint-Andre<br />
<br />
Email: stpeter@jabber.org<br />
JabberID: stpeter@jabber.org<br />
URI: https://stpeter.im/<br />
Jack Moffitt<br />
<br />
Email: jack@chesspark.com<br />
JabberID: jack@chesspark.com<br />
===Appendix C: Legal Notices===<br />
Copyright<br />
This XMPP Extension Protocol is copyright © 1999 - 2011 by the XMPP Standards Foundation (XSF).<br />
Permissions<br />
Permission is hereby granted, free of charge, to any person obtaining a copy of this specification (the "Specification"), to make use of the Specification without restriction, including without limitation the rights to implement the Specification in a software program, deploy the Specification in a network service, and copy, modify, merge, publish, translate, distribute, sublicense, or sell copies of the Specification, and to permit persons to whom the Specification is furnished to do so, subject to the condition that the foregoing copyright notice and this permission notice shall be included in all copies or substantial portions of the Specification. Unless separate permission is granted, modified works that are redistributed shall not contain misleading information regarding the authors, title, number, or publisher of the Specification, and shall not claim endorsement of the modified works by the authors, any organization or project to which the authors belong, or the XMPP Standards Foundation.<br />
Disclaimer of Warranty<br />
## NOTE WELL: This Specification is provided on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, express or implied, including, without limitation, any warranties or conditions of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A PARTICULAR PURPOSE. ##<br />
Limitation of Liability<br />
In no event and under no legal theory, whether in tort (including negligence), contract, or otherwise, unless required by applicable law (such as deliberate and grossly negligent acts) or agreed to in writing, shall the XMPP Standards Foundation or any author of this Specification be liable for damages, including any direct, indirect, special, incidental, or consequential damages of any character arising from, out of, or in connection with the Specification or the implementation, deployment, or other use of the Specification (including but not limited to damages for loss of goodwill, work stoppage, computer failure or malfunction, or any and all other commercial damages or losses), even if the XMPP Standards Foundation or such author has been advised of the possibility of such damages.<br />
IPR Conformance<br />
This XMPP Extension Protocol has been contributed in full conformance with the XSF's Intellectual Property Rights Policy (a copy of which can be found at <http://xmpp.org/extensions/ipr-policy.shtml> or obtained by writing to XMPP Standards Foundation, 1899 Wynkoop Street, Suite 600, Denver, CO 80202 USA).<br />
===Appendix D: Relation to XMPP===<br />
<br />
The Extensible Messaging and Presence Protocol (XMPP) is defined in the XMPP Core (RFC 3920) and XMPP IM (RFC 3921) specifications contributed by the XMPP Standards Foundation to the Internet Standards Process, which is managed by the Internet Engineering Task Force in accordance with RFC 2026. Any protocol defined in this document has been developed outside the Internet Standards Process and is to be understood as an extension to XMPP rather than as an evolution, development, or modification of XMPP itself.<br />
===Appendix E: Discussion Venue===<br />
<br />
The primary venue for discussion of XMPP Extension Protocols is the <standards@xmpp.org> discussion list.<br />
<br />
Discussion on other xmpp.org discussion lists might also be appropriate; see <http://xmpp.org/about/discuss.shtml> for a complete list.<br />
<br />
Given that this XMPP Extension Protocol normatively references IETF technologies, discussion on the <xsf-ietf@xmpp.org> list might also be appropriate.<br />
<br />
Errata can be sent to <editor@xmpp.org>.<br />
===Appendix F: Requirements Conformance===<br />
<br />
The following requirements keywords as used in this document are to be interpreted as described in RFC 2119: "MUST", "SHALL", "REQUIRED"; "MUST NOT", "SHALL NOT"; "SHOULD", "RECOMMENDED"; "SHOULD NOT", "NOT RECOMMENDED"; "MAY", "OPTIONAL".<br />
===Appendix G: Notes===<br />
<br />
1. RFC 793: Transmission Control Protocol <http://tools.ietf.org/html/rfc0793>.<br />
<br />
2. RFC 1945: Hypertext Transfer Protocol -- HTTP/1.0 <http://tools.ietf.org/html/rfc1945>.<br />
<br />
3. RFC 2616: Hypertext Transport Protocol -- HTTP/1.1 <http://tools.ietf.org/html/rfc2616>.<br />
<br />
4. Bayeux Protocol <http://svn.cometd.org/trunk/bayeux/bayeux.html>.<br />
<br />
5. The Web Socket Protocol <http://tools.ietf.org/html/draft-hixie-thewebsocketprotocol>.<br />
<br />
6. Reverse HTTP <http://tools.ietf.org/html/draft-lentczner-rhttp>.<br />
<br />
7. RFC 2965: HTTP State Management Mechanism <http://tools.ietf.org/html/rfc2965>.<br />
<br />
8. Requiring cookies is sub-optimal because several significant computing platforms provide only limited access to underlying HTTP requests/responses; worse, some platforms hide or remove cookie-related headers.<br />
<br />
9. XEP-0025: Jabber HTTP Polling <http://xmpp.org/extensions/xep-0025.html>.<br />
<br />
10. RFC 6120: Extensible Messaging and Presence Protocol (XMPP): Core <http://tools.ietf.org/html/rfc6120>.<br />
<br />
11. XEP-0206: XMPP Over BOSH <http://xmpp.org/extensions/xep-0206.html>.<br />
<br />
12. In order to reduce network congestion, RFC 2616 recommends that clients SHOULD NOT keep more than two HTTP connections to the same HTTP server open at the same time. Clients running in constrained enviroments typically have no choice but to abide by that recommendation.<br />
<br />
13. If there is no traffic other than the "pings" then bandwidth consumption will be double that of a TCP connection (although double nothing is still nothing). If data is sent in large packets then bandwidth consumption will be almost identical.<br />
<br />
14. Extensible Markup Language (XML) 1.0 (Fourth Edition) <http://www.w3.org/TR/REC-xml/>.<br />
<br />
15. Namespaces in XML <http://www.w3.org/TR/REC-xml-names/>.<br />
<br />
16. RFC 4627: The application/json Media Type for JavaScript Object Notation (JSON) <http://tools.ietf.org/html/rfc4627>.<br />
<br />
17. Extensible Markup Language (XML) 1.0 (Fourth Edition) <http://www.w3.org/TR/REC-xml/>.<br />
<br />
18. Although the syntax of the 'route' attribute bears a superficial resemblance to a URI or IRI, it is not a URI/IRI and MUST NOT be processed in accordance with the rules specified in RFC 3986, RFC 3987, or (for XMPP) RFC 5122.<br />
<br />
19. Each character set name (or character encoding name -- we use the terms interchangeably) SHOULD be of type NMTOKEN, where the names are separated by the white space character #x20, resulting in a tokenized attribute type of NMTOKENS (see Section 3.3.1 of XML 1.0 [20]). Strictly speaking, the Character Sets registry maintained by the Internet Assigned Numbers Authority (see <http://www.iana.org/assignments/character-sets>) allows a character set name to contain any printable US-ASCII character, which might include characters not allowed by the NMTOKEN construction of XML 1.0; however, the only existing character set name which includes such a character is "NF_Z_62-010_(1973)".<br />
<br />
20. Extensible Markup Language (XML) 1.0 (Fourth Edition) <http://www.w3.org/TR/REC-xml/>.<br />
<br />
21. 9007199254740991 is 253-1. Some weakly typed languages use IEEE Standard 754 Doubles to represent all numbers. These Doubles cannot represent integers above 253 accurately.<br />
<br />
22. RFC 3174: US Secure Hash Algorithm 1 (SHA1) <http://tools.ietf.org/html/rfc3174>.<br />
<br />
23. Therefore a client and a connection manager will be compatible even if one or the other offers no support for multi-stream sessions.<br />
<br />
24. The 'rid' attribute is always incremented normally without reference to any 'stream' attribute.<br />
<br />
25. This helps to ensure backwards-compatibility with older implementations.<br />
<br />
26. Each HTTP response MUST belong to the same session as the request that triggered it, but not necessarily to the same stream.<br />
<br />
27. The broadcast payloads can be of any type.<br />
<br />
28. SSL V3.0 <http://wp.netscape.com/eng/ssl3/draft302.txt>.<br />
<br />
29. RFC 2818: HTTP Over TLS <http://tools.ietf.org/html/rfc2818>.<br />
<br />
30. RFC 2817: Upgrading to TLS Within HTTP/1.1 <http://tools.ietf.org/html/rfc2817>.<br />
<br />
31. RFC 1750: Randomness Recommendations for Security <http://tools.ietf.org/html/rfc1750>.<br />
<br />
32. RFC 4270: Attacks on Cryptographic Hashes in Internet Protocols <http://tools.ietf.org/html/rfc4270>.<br />
<br />
33. The Internet Assigned Numbers Authority (IANA) is the central coordinator for the assignment of unique parameter values for Internet protocols, such as port numbers and URI schemes. For further information, see <http://www.iana.org/>.<br />
<br />
34. IANA registry of port numbers <http://www.iana.org/assignments/port-numbers>.<br />
<br />
35. XEP-0156: Discovering Alternative XMPP Connection Methods <http://xmpp.org/extensions/xep-0156.html>.<br />
===Appendix H: Revision History===<br />
<br />
Note: Older versions of this specification might be available at http://xmpp.org/extensions/attic/<br />
Version 1.10 (2010-07-02)<br />
<br />
Further clarified use of 'from' and 'to' attributes; added missing condition values to the schema.<br />
(psa)<br />
Version 1.9 (2009-11-06)<br />
<br />
Added information for registration of port 5280 with IANA.<br />
(psa)<br />
Version 1.8 (2009-04-30)<br />
<br />
Removed secure attribute because it did not solve the problem it was intended to solve; added security consideration regarding link between connection manager and application server; changed "stanza" to "payload" for disambiguation with XMPP; clarified design objectives and relationship to similar technologies; corrected several errors in the schema.<br />
(psa/jm)<br />
Version 1.7 (2008-10-29)<br />
<br />
Moved alternative script syntax to historical specification; added implementation note about HTTP Pipelining; adjusted architectural description.<br />
(psa)<br />
Version 1.6 (2007-02-21)<br />
<br />
Multiple clarifications and restructuring without changes to protocol itself; changed title to BOSH; added section that fully explains the technique underlying the protocol; separated XMPP-specific features into new XEP-0206; added optional new Script Syntax and session pauses; added Acknowledgements section; added from and ver attributes; added hold attribute to session creation response; clarified polling too-frequently error; recommended that clients use HTTP Pipelining.<br />
(ip)<br />
Version 1.5 (2006-04-28)<br />
<br />
Added optional Multiple Streams section; added security considerations about encrypted HTTP connections; recommended use of SSL rather than HTTP over TLS; specified that request ID values must not exceed 9007199254740991; corrected datatypes of inactivity, polling, rid, and wait attributes in the schema; added <any/> and <anyAttribute/> elements to schema to optionally support non-XMPP XML elements and attributes; deprecated HTTP error codes in favor of new terminal binding conditions.<br />
(ip/psa)<br />
Version 1.4 (2005-12-14)<br />
<br />
Modified syntax of route attribute to be proto:host:port rather than XMPP URI/IRI.<br />
(psa)<br />
Version 1.3 (2005-11-02)<br />
<br />
Corrected stream:features namespace and the Recoverable Binding Conditions section; recommended that connection manager shall return secure attribute to client; recommended end-to-end encryption through proxy connection managers.<br />
(ip)<br />
Version 1.2 (2005-06-16)<br />
<br />
Specified optional use of route and secure attributes in session request. Minor correction: the stream features element should be included in the response that contains the authid attribute (this is not necessarily the session creation response).<br />
(ip)<br />
Version 1.1 (2005-06-02)<br />
<br />
Specified optional use of HTTP Accept-Encoding and Content-Encoding headers for compression at HTTP binding level.<br />
(ip)<br />
Version 1.0 (2005-03-03)<br />
<br />
Per a vote of the Jabber Council, advanced status to Draft.<br />
(psa)<br />
Version 0.10 (2004-11-08)<br />
<br />
Changed HTTP 401 errors to HTTP 404.<br />
(ip)<br />
Version 0.9 (2004-10-26)<br />
<br />
Added charset attribute.<br />
(ip/psa)<br />
Version 0.8 (2004-10-26)<br />
<br />
Specified that wait attribute must be included in the session creation response.<br />
(ip)<br />
Version 0.7 (2004-08-12)<br />
<br />
Defined appropriate XMPP stanza error conditions.<br />
(psa/ip)<br />
Version 0.6 (2004-07-19)<br />
<br />
Added xml:lang attribute to the session request; added recoverable binding error conditions.<br />
(ip)<br />
Version 0.5 (2004-05-07)<br />
<br />
Protocol refactored to enable simultaneous requests (request identifier attribute, wait attribute, hold attribute, requests attribute) and recovery of broken connections; added content attribute; removed all wrapper types except 'terminate'; updated error handling; made key mechanism optional (should use SSL/TLS instead).<br />
(ip/psa)<br />
Version 0.4 (2004-02-23)<br />
<br />
Fixed typos; removed "resource-constraint" binding error; added HTTP 403 error to table.<br />
(psa/ip)<br />
Version 0.3 (2004-02-19)<br />
<br />
Added 'authid' attribute to enable communication of XMPP stream ID (used in digest authentication); specified that Content-Types other than "text/xml" are allowed to support older HTTP clients; specified business rule for connection manager queueing of client requests; changed <packet/> to <body/> to support older HTTP clients; changed 'to' attribute on initialization element from MAY to SHOULD; recommended inclusion of unavailable presence in termination element sent from client; described architectural assumptions; specified binding-specific error handling.<br />
(psa/ip)<br />
Version 0.2 (2004-01-13)<br />
<br />
Added 'to' attribute on the initialization element; specified that 'text/html' is allowable for backwards-compatibility.<br />
(dss/psa/ip)<br />
Version 0.1 (2003-11-06)<br />
<br />
Initial version.<br />
(dss/psa)<br />
<br />
结束</div>
Snowqiang
http://wiki.jabbercn.org/XEP-0124
XEP-0124
2011-05-18T13:58:33Z
<p>Snowqiang: 添加基本格式</p>
<hr />
<div>[[Category:XMPP扩展]]<br />
[[Category:翻译中]]<br />
<br />
'''本文的英文原文来自[http://www.xmpp.org/extensions/xep-0124.html XEP-0124]'''<br />
<br />
'''XEP-0124: Bidirectional-streams Over Synchronous HTTP (BOSH)'''<br />
<br />
摘要: This specification defines a transport protocol that emulates the semantics of a long-lived, bidirectional TCP connection between two entities (such as a client and a server) by efficiently using multiple synchronous HTTP request/response pairs without requiring the use of frequent polling or chunked responses.<br />
作者: Ian Paterson, Dave Smith, Peter Saint-Andre, Jack Moffitt<br />
版权: © 1999 - 2011 XMPP Standards Foundation. SEE LEGAL NOTICES.<br />
状态: 草案<br />
类型: 标准跟踪<br />
版本: 2.0<br />
最后更新日期: 2010-07-02<br />
<br />
NOTICE: The protocol defined herein is a Draft Standard of the XMPP Standards Foundation. Implementations are encouraged and the protocol is appropriate for deployment in production systems, but some changes to the protocol are possible before it becomes a Final Standard.<br />
<br />
==Introduction==<br />
<br />
The Transmission Control Protocol (TCP; RFC 793 [1]) is often used to establish a stream-oriented connection between two entities. Such connections can often be long-lived to enable an interactive "session" between the entities. However, sometimes the nature of the device or network can prevent an application from maintaining a long-lived TCP connection to a server or peer. In this case, it is desirable to use an alternative connection method that emulates the behavior of a long-lived TCP connection using a sequenced series of requests and responses that are exchanged over short-lived connections. The appropriate request-response semantics are widely available via the Hypertext Transfer Protocol (HTTP) as specified in RFC 1945 [2] and RFC 2616 [3].<br />
<br />
BOSH, the technology defined in this specification, essentially provides a "drop-in" alternative to a long-lived, bidirectional TCP connection. It is a mature, full-featured technology that has been widely implemented and deployed since 2004. To our knowledge it was the first of many similar technologies, which now include the Comet methodology formalized in the Bayeux Protocol [4] as well as The Web Socket Protocol [5] and Reverse HTTP [6].<br />
<br />
BOSH is designed to transport any data efficiently and with minimal latency in both directions. For applications that require both "push" and "pull" semantics, BOSH is significantly more bandwidth-efficient and responsive than most other bidirectional HTTP-based transport protocols and the techniques now commonly known as "Ajax". BOSH achieves this efficiency and low latency by using so-called "long polling" with multiple synchronous HTTP request/response pairs. Furthermore, BOSH can address the needs of constrained clients by employing fully-compliant HTTP 1.0 without the need for "cookies" (see RFC 2965 [7]) [8] or even access to HTTP headers.<br />
<br />
BOSH was originally developed in the Jabber/XMPP community as a replacement for an even earlier HTTP-based technology called Jabber HTTP Polling [9]. Although BOSH assumes that the "payload" of HTTP requests and responses will be XML, the payload formats are not limited to XMPP stanzas (see XMPP Core [10]) and could contain a mixture of elements qualified by namespaces defined by different protocols (e.g., both XMPP and JSON). This mix is necessary because some connection managers might 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 payload is qualified by the correct namespace.<br />
<br />
Note: XMPP Over BOSH [11] documents some XMPP-specific extensions of this protocol that were formerly included in this document.<br />
<br />
==Requirements==<br />
<br />
The following design requirements reflect the need to offer performance as close as possible to a standard TCP connection.<br />
<br />
1. Compatible with constrained runtime environments* (e.g., mobile and browser-based clients).<br />
2. Compatible with proxies that buffer partial HTTP responses.<br />
3. Efficient through proxies that limit the duration of HTTP responses.<br />
4. Fully compatible with HTTP/1.0.<br />
5. Compatible with restricted network connections (e.g., firewalls, proxies, and gateways).<br />
6. Fault tolerant (e.g., session recovers after an underlying TCP connection breaks at any stage during an HTTP request).<br />
7. Extensible.<br />
8. Consume significantly less bandwidth than polling-based protocols.<br />
9. Significantly more responsive (lower latency) than polling-based protocols.<br />
10. Support for polling (for clients that are limited to a single HTTP connection at a time).<br />
11. In-order delivery of data.<br />
12. Guard against unauthorized users injecting HTTP requests into a session.<br />
13. Protect against denial of service attacks.<br />
14. Multiplexing of data streams.<br />
<br />
*Note: Compatibility with constrained runtime environments implies the following restrictions:<br />
<br />
1. Clients are not required to have programmatic access to the headers of each HTTP request and response (e.g., cookies or status codes).<br />
2. The body of each HTTP request and response is parsable XML with a single root element.<br />
3. Clients can specify the Content-Type of the HTTP responses they receive.<br />
<br />
==Architectural Assumptions==<br />
<br />
This document assumes that most implementations will utilize a specialized connection manager ("CM") to handle HTTP connections rather than the native connection type for the relevant application (e.g., TCP connections in XMPP). Effectively, such a connection manager is a specialized HTTP server that translates between the HTTP requests and responses defined herein and the data streams (or API) implemented by the server with which it communicates, thus enabling a client to connect to a server via HTTP on port 80 or 443 instead of an application-specific port. We can illustrate this graphically as follows:<br />
<br />
Server<br />
|<br />
| [unwrapped data streams]<br />
|<br />
HTTP CM<br />
|<br />
| [HTTP + <body/> wrapper]<br />
|<br />
Client<br />
<br />
<br />
This specification covers communication only between a client and the connection manager. It does not cover communication between the connection manager and the server, since such communications are implementation-specific (e.g., the server might 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 might be an independent translating proxy such that the server might believe it is talking directly to the client over TCP; or the connection manager and the server might use a component protocol or an API defined by the server implementation).<br />
<br />
Furthermore, no aspect of this protocol limits its use to communication between a client and a server. For example, it could be used for communication between a server and a peer server if such communication can occur for the relevant application (e.g., in XMPP). 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 the native connection transport for the relevant application. (However, on some unreliable networks, BOSH might enable more stable communication between servers.)<br />
<br />
==The BOSH Technique==<br />
<br />
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).<br />
<br />
The technique employed by BOSH 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.<br />
<br />
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 so to make sure the client can send more data immediately if necessary. (The client SHOULD NOT open more than two HTTP connections to the connection manager at the same time, [12] so it would otherwise have to wait until the connection manager responds to one of the requests.)<br />
<br />
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 TCP 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.<br />
<br />
If there is no traffic in either direction for an agreed amount of time (typically several 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 so 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. [13]<br />
<br />
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. Thus 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. Therefore, 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 were being used.<br />
<br />
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.<br />
<br />
==HTTP Overview==<br />
<br />
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).<br />
<br />
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 permitted by RFC 1945 or RFC 2616. For example, 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 might buffer each partial HTTP request or response and only forward the full request or response once it is available.<br />
<br />
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.<br />
<br />
Requests and responses MAY include HTTP headers not specified herein. The receiver SHOULD ignore any such headers.<br />
<br />
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). However, the responses to requests that are not part of the session sent over the same connection using HTTP pipelining (or queued to be sent over the same connection) might be delayed if they were sent while a request that is part of the session is being held (since the connection manager MUST send its responses in the same order that the requests were received, and the connection manager typically delays its responses).<br />
<br />
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.<br />
<br />
==<body/> Wrapper Element==<br />
<br />
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 transferred. The <body/> element and its content together MUST conform to the specifications set out in XML 1.0 [14]. They SHOULD also conform to Namespaces in XML [15]. The content MUST NOT contain any of the following (all defined in XML 1.0):<br />
<br />
*<br />
<br />
Partial XML elements<br />
*<br />
<br />
XML comments<br />
*<br />
<br />
XML processing instructions<br />
*<br />
<br />
Internal or external DTD subsets<br />
*<br />
<br />
Internal or external entity references (with the exception of predefined entities)<br />
<br />
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 "payloads" in this document, e.g., XMPP stanzas as defined in RFC 6120 or elements containing XML character data that represents objects using the JSON data interchange format as defined in RFC 4627 [16]). Each <body/> wrapper MAY contain payloads qualified under a wide variety of different namespaces.<br />
<br />
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.<br />
<br />
==Initiating a BOSH Session==<br />
===Session Creation Request===<br />
<br />
The first request from the client to the connection manager requests a new session.<br />
<br />
The <body/> element of the first request SHOULD possess the following attributes (they SHOULD NOT be included in any other requests except as specified under Adding Streams To A Session):<br />
<br />
* 'to' -- This attribute specifies the target domain of the first stream.<br />
* 'xml:lang' -- This attribute (as defined in Section 2.12 of XML 1.0 [17]) specifies the default language of any human-readable XML character data sent or received during the session.<br />
* 'ver' -- This attribute specifies the highest version of the BOSH protocol that the client supports. The numbering scheme is "<major>.<minor>" (where the minor number MAY be incremented higher than a single digit, so it MUST be treated as a separate integer). Note: The 'ver' attribute should not be confused with the version of any protocol being transported.<br />
* 'wait' -- This attribute specifies the longest time (in seconds) that the connection manager is allowed to wait before responding to any request during the session. This enables the client to limit the delay before it discovers any network failure, and to prevent its HTTP/TCP connection from expiring due to inactivity.<br />
* 'hold' -- This attribute specifies the maximum number of requests the connection manager is allowed to keep waiting at any one time during the session. If the client is not able to use HTTP Pipelining then this SHOULD be set to "1".<br />
<br />
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 both typically one or two orders of magnitude!<br />
<br />
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:example.com:9999"). [18] A connection manager that is configured to work only with a single server (or only with a defined list of domains and the associated list of hostnames and ports that are serving those domains) MAY ignore the 'route' attribute. (Note that the 'to' attribute specifies the domain being served, not the hostname of the machine that is serving the domain.)<br />
<br />
The <body/> element of the first request MAY also possess a 'from' attribute, which specifies the originator of the first stream and which enables the connection manager to forward the originating entity's identity to the application server (e.g., the JabberID of an entity that is connecting to an XMPP server; see XEP-0206).<br />
<br />
A client MAY include an 'ack' attribute (set to "1") to indicate that it will be using acknowledgements throughout the session and that the absence of an 'ack' attribute in any request is meaningful (see Acknowledgements).<br />
<br />
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".<br />
<br />
'''Example 1. Requesting a BOSH session'''<br />
<source lang="xml"><br />
POST /webclient HTTP/1.1<br />
Host: httpcm.example.com<br />
Accept-Encoding: gzip, deflate<br />
Content-Type: text/xml; charset=utf-8<br />
Content-Length: 104<br />
<br />
<body content='text/xml; charset=utf-8'<br />
from='user@example.com'<br />
hold='1'<br />
rid='1573741820'<br />
to='example.com'<br />
route='xmpp:example.com:9999'<br />
ver='1.6'<br />
wait='60'<br />
ack='1'<br />
xml:lang='en'<br />
xmlns='http://jabber.org/protocol/httpbind'/><br />
</source><br />
<br />
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.<br />
===Session Creation Response===<br />
<br />
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):<br />
<br />
* 'sid' -- This attribute specifies the SID<br />
* 'wait' -- This is the longest time (in seconds) that the connection manager will wait before responding to any request during the session. The time MUST be less than or equal to the value specified in the session request.<br />
<br />
The <body/> element SHOULD also include the following attributes (they SHOULD NOT be included in any other responses):<br />
<br />
* 'ver' -- This attribute specifies the highest version of the BOSH protocol that the connection manager supports, or the version specified by the client in its request, whichever is lower.<br />
* 'polling' -- This attribute specifies the shortest allowable polling interval (in seconds). This enables the client to not send empty request elements more often than desired (see Polling Sessions and Overactivity).<br />
* 'inactivity' -- This attribute specifies the longest allowable inactivity period (in seconds). This enables the client to ensure that the periods with no requests pending are never too long (see Polling Sessions and Inactivity).<br />
* 'requests' -- This attribute enables the connection manager to limit the number of simultaneous requests the client makes (see Overactivity and Polling Sessions). The RECOMMENDED values are either "2" or one more than the value of the 'hold' attribute specified in the session request.<br />
* 'hold' -- This attribute informs the client about the maximum number of requests the connection manager will keep waiting at any one time during the session. This value MUST NOT be greater than the value specified by the client in the session request.<br />
* 'to' -- This attribute communicates the identity of the backend server to which the client is attempting to connect.<br />
<br />
The connection manager MAY include an 'accept' attribute in the session creation response element, to specify a space-separated list of 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.<br />
<br />
A connection manager MAY include an 'ack' attribute (set to the value of the 'rid' attribute of the session creation request) to indicate that it will be using acknowledgements throughout the session and that the absence of an 'ack' attribute in any response is meaningful (see Acknowledgements).<br />
<br />
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 can request.<br />
<br />
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. [19]<br />
<br />
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 a BOSH Session), then in the same response the connection manager SHOULD also include the 'secure' attribute set to "true" or "1".<br />
<br />
'''Example 2. Session creation response'''<br />
<source lang="xml"><br />
HTTP/1.1 200 OK<br />
Content-Type: text/xml; charset=utf-8<br />
Content-Length: 128<br />
<br />
<body wait='60'<br />
inactivity='30'<br />
polling='5'<br />
requests='2'<br />
hold='1'<br />
ack='1573741820'<br />
accept='deflate,gzip'<br />
maxpause='120'<br />
sid='SomeSID'<br />
charsets='ISO_8859-1 ISO-2022-JP'<br />
ver='1.6'<br />
from='example.com'<br />
xmlns='http://jabber.org/protocol/httpbind'/><br />
</source><br />
<br />
'''Example 3. Subsequent response with 'from' and 'secure' attributes'''<br />
<source lang="xml"><br />
HTTP/1.1 200 OK<br />
Content-Type: text/xml; charset=utf-8<br />
Content-Length: 128<br />
<br />
<body from='example.com'<br />
xmlns='http://jabber.org/protocol/httpbind'/><br />
</source><br />
<br />
==Sending and Receiving XML Payloads==<br />
<br />
After the client has successfully completed all required preconditions, it can send and receive XML payloads via the HTTP binding.<br />
<br />
'''Example 4. Transmitting payloads'''<br />
<source lang="xml"><br />
POST /webclient HTTP/1.1<br />
Host: httpcm.example.com<br />
Accept-Encoding: gzip, deflate<br />
Content-Type: text/xml; charset=utf-8<br />
Content-Length: 188<br />
<br />
<body rid='1249243562'<br />
sid='SomeSID'<br />
xmlns='http://jabber.org/protocol/httpbind'><br />
<message to='contact@example.com'<br />
xmlns='jabber:client'><br />
<body>Good morning!</body><br />
</message><br />
<message to='friend@example.com'<br />
xmlns='jabber:client'><br />
<body>Hey, what&apos;s up?</body><br />
</message><br />
</body><br />
</source><br />
<br />
Upon receipt of a request, the connection manager SHOULD forward the content of the <body/> element to the server as soon as possible. In any case it MUST forward the content from different requests in the order specified by their 'rid' attributes.<br />
<br />
The connection manager MUST also return an HTTP 200 OK response with a <body/> element to the client. Note: This does not indicate that the payloads have been successfully delivered to the application server.<br />
<br />
It is RECOMMENDED that the connection manager not return an HTTP result until a payload has arrived from the application server for delivery to the client. However, the connection manager SHOULD NOT wait longer than the time specified by the client in the 'wait' attribute of its Session Creation Request, and it SHOULD NOT keep more HTTP requests waiting at a time than the number specified in the 'hold' attribute of the session creation request. In any case it MUST respond to requests in the order specified by their 'rid' attributes.<br />
<br />
If there are no payloads waiting or ready to be delivered within the waiting period, then the connection manager SHOULD include an empty <body/> element in the HTTP result:<br />
<br />
'''Example 5. Empty response'''<br />
<source lang="xml"><br />
HTTP/1.1 200 OK<br />
Content-Type: text/xml; charset=utf-8<br />
Content-Length: 64<br />
<br />
<body xmlns='http://jabber.org/protocol/httpbind'/><br />
</source><br />
<br />
If the connection manager has received one or more payloads from the application server for delivery to the client, then it SHOULD return the payloads in the body of its response as soon as possible after receiving them from the server. The example below includes payloads qualified by different namespaces:<br />
<br />
'''Example 6. Response with queued stanza'''<br />
<source lang="xml"><br />
HTTP/1.1 200 OK<br />
Content-Type: text/xml; charset=utf-8<br />
Content-Length: 185<br />
<br />
<body xmlns='http://jabber.org/protocol/httpbind'<br />
xmlns:json='http://json.org/'><br />
<message from='contact@example.com'<br />
to='user@example.com'<br />
xmlns='jabber:client'><br />
<body>Good morning to you!</body><br />
</message><br />
<message from='friend@example.com'<br />
to='user@example.com'<br />
xmlns='jabber:client'><br />
<body>Not much, how about with you?</body><br />
</message><br />
<json:json><br />
[<br />
{<br />
"precision": "zip",<br />
"Latitude": 37.7668,<br />
"Longitude": -122.3959,<br />
"Address": "",<br />
"City": "SAN FRANCISCO",<br />
"State": "CA",<br />
"Zip": "94107",<br />
"Country": "US"<br />
},<br />
{<br />
"precision": "zip",<br />
"Latitude": 37.371991,<br />
"Longitude": -122.026020,<br />
"Address": "",<br />
"City": "SUNNYVALE",<br />
"State": "CA",<br />
"Zip": "94085",<br />
"Country": "US"<br />
}<br />
]<br />
</json:json><br />
</body><br />
</source><br />
<br />
The client MAY poll the connection manager for incoming payloads by sending an empty <body/> element.<br />
<br />
'''Example 7. Requesting XML Payloads'''<br />
<source lang="xml"><br />
POST /webclient HTTP/1.1<br />
Host: httpcm.example.com<br />
Accept-Encoding: gzip, deflate<br />
Content-Type: text/xml; charset=utf-8<br />
Content-Length: 88<br />
<br />
<body rid='1249243563'<br />
sid='SomeSID'<br />
xmlns='http://jabber.org/protocol/httpbind'/><br />
</source><br />
<br />
The connection manager MUST wait and respond in the same way as it does after receiving payloads from the client.<br />
<br />
==Acknowledgements==<br />
===Request Acknowledgements==<br />
<br />
When responding to a request that it has been holding, if the connection manager finds it has already received another request with a higher 'rid' attribute (typically while it was holding the first request), then it MAY acknowledge the reception to the client. The connection manager MAY set the 'ack' attribute of any response to the value of the highest 'rid' attribute it has received in the case where it has also received all requests with lower 'rid' values.<br />
<br />
'''Example 8. Response with request acknowledgement'''<br />
<source lang="xml"><br />
HTTP/1.1 200 OK<br />
Content-Type: text/xml; charset=utf-8<br />
Content-Length: 64<br />
<br />
<body ack='1249243564'<br />
xmlns='http://jabber.org/protocol/httpbind'/><br />
</source><br />
<br />
If the connection manager will be including 'ack' attributes on responses during a session, then it MUST include an 'ack' attribute in its session creation response, and set the 'ack' attribute of responses throughout the session. The only exception is that, after its session creation response, the connection manager SHOULD NOT include an 'ack' attribute in any response if the value would be the 'rid' of the request being responded to.<br />
<br />
If the connection manager is permitted to hold more than one request at a time, then the reception of a lower-than-expected 'ack' value from the connection manager (or the unexpected abscence of an 'ack' attribute) can give the client an early warning that a network failure might have occurred (e.g., if the client believes the connection manager should have received another request by the time it responded).<br />
===Response Acknowledgements===<br />
<br />
The client MAY similarly inform the connection manager about the responses it has received by setting the 'ack' attribute of any request to the value of the highest 'rid' of a request for which it has already received a response in the case where it has also received all responses associated with lower 'rid' values. If the client will be including 'ack' attributes on requests during a session, then it MUST include an 'ack' attribute (set to '1') in its session creation request, and set the 'ack' attribute of requests throughout the session. The only exception is that, after its session creation request, the client SHOULD NOT include an 'ack' attribute in any request if it has received responses to all its previous requests.<br />
<br />
'''Example 9. Request with response acknowledgement'''<br />
<source lang="xml"><br />
POST /webclient HTTP/1.1<br />
Host: httpcm.example.com<br />
Accept-Encoding: gzip, deflate<br />
Content-Type: text/xml; charset=utf-8<br />
Content-Length: 88<br />
<br />
<body rid='1249243566'<br />
sid='SomeSID'<br />
ack='1249243564'<br />
xmlns='http://jabber.org/protocol/httpbind'/><br />
</source><br />
<br />
After receiving a request with an 'ack' value less than the 'rid' of the last request that it has already responded to, the connection manager MAY inform the client of the situation by sending its next response immediately instead of waiting until it has payloads to send to the client (e.g., if some time has passed since it responded). In this case it SHOULD include a 'report' attribute set to one greater than the 'ack' attribute it received from the client, and a 'time' attribute set to the number of milliseconds since it sent the response associated with the 'report' attribute.<br />
<br />
'''Example 10. Response with report'''<br />
<source lang="xml"><br />
HTTP/1.1 200 OK<br />
Content-Type: text/xml; charset=utf-8<br />
Content-Length: 64<br />
<br />
<body report='1249243565'<br />
time='852'<br />
xmlns='http://jabber.org/protocol/httpbind'/><br />
</source><br />
<br />
Upon reception of a response with 'report' and 'time' attributes, if the client has still not received the response associated with the request identifier specified by the 'report' attribute, then it MAY choose to resend the request associated with the missing response (see Broken Connections).<br />
<br />
==Inactivity==<br />
<br />
After receiving a response from the connection manager, if none of the client's requests are still being held by the connection manager (and if the session is not a Polling Session), the client SHOULD make a new request as soon as possible. In any case, if no requests are being held, the client MUST make a new request before the maximum inactivity period has expired. The length of this period (in seconds) is specified by the 'inactivity' attribute in the session creation response.<br />
<br />
If the connection manager has responded to all the requests it has received within a session and the time since its last response is longer than the maximum inactivity period, then it SHOULD assume the client has been disconnected and terminate the session without informing the client. If the client subsequently makes another request, then the connection manager SHOULD respond as if the session does not exist.<br />
<br />
If the connection manager did not specify a maximum inactivity period in the session creation response, then it SHOULD allow the client to be inactive for as long as it chooses.<br />
<br />
If the session is not a polling session then the connection manager SHOULD specify a relatively short inactivity period to ensure that disconnections are discovered as quickly as possible. The RECOMMENDED time would be a little more than the number of seconds for a comfortable network round trip between the connection manager and the client under difficult network conditions (since the client can be expected to make a new request immediately -- see above).<br />
<br />
If a client encounters an exceptional temporary situation during which it will be unable to send requests to the connection manager for a period of time greater than the maximum inactivity period (e.g., while a runtime environment changes from one web page to another), and if the connection manager included a 'maxpause' attribute in its Session Creation Response, then the client MAY request a temporary increase to the maximum inactivity period by including a 'pause' attribute in a request. Note: If the connection manager did not specify a 'maxpause' attribute at the start of the session then the client MUST NOT send a 'pause' attribute during the session.<br />
<br />
'''Example 11. Requesting a Session Pause'''<br />
<source lang="xml"><br />
POST /webclient HTTP/1.1<br />
Host: httpcm.example.com<br />
Accept-Encoding: gzip, deflate<br />
Content-Type: text/xml; charset=utf-8<br />
Content-Length: 98<br />
<br />
<body rid='1249243564'<br />
sid='SomeSID'<br />
pause='60'<br />
xmlns='http://jabber.org/protocol/httpbind'/><br />
</source><br />
<br />
Upon reception of a session pause request, if the requested period is not greater than the maximum permitted time, then the connection manager SHOULD respond immediately to all pending requests (including the pause request) and temporarily increase the maximum inactivity period to the requested time. Note: The response to the pause request MUST NOT contain any payloads.<br />
<br />
Note: If the client simply wants the connection manager to return all the requests it is holding then it MAY set the value of the 'pause' attribute to be the value of the 'inactivity' attribute in the connection manager's session creation response. (If the client believes it is in danger of becoming disconnected indefinitely then it MAY even request a temporary reduction of the maximum inactivity period by specifying a 'pause' value less than the 'inactivity' value, thus enabling the connection manager to discover any subsequent disconnection more quickly.)<br />
<br />
The connection manager SHOULD set the maximum inactivity period back to normal upon reception of the next request from the client (assuming the connection manager has not already terminated the session).<br />
11. Overactivity<br />
<br />
The client SHOULD NOT make more simultaneous requests than specified by the 'requests' attribute in the connection manager's Session Creation Response. However the client MAY make one additional request if it is to pause or terminate a session.<br />
<br />
If during any period the client sends a sequence of new requests (i.e. requests with incremented rid attributes, not repeat requests) longer than the number specified by the 'requests' attribute, and if the connection manager has not yet responded to any of the requests, and if the last request did not include either a 'pause' attribute or a 'type' attribute set to "terminate", then the connection manager SHOULD consider that the client is making too many simultaneous requests, and terminate the HTTP session with a 'policy-violation' terminal binding error to the client. Note: This behavior applies to equally to normal and polling sessions.<br />
<br />
'''Example 12. Too many simultaneous requests response'''<br />
<source lang="xml"><br />
HTTP/1.1 200 OK<br />
Content-Type: text/xml; charset=utf-8<br />
Content-Length: 68<br />
<br />
<body type='terminate'<br />
condition='policy-violation'<br />
xmlns='http://jabber.org/protocol/httpbind'/><br />
</source><br />
<br />
Note: If the connection manager did not specify a 'requests' attribute in the session creation response, then it MUST allow the client to send as many simultaneous requests as it chooses.<br />
<br />
If during any period the client sends a sequence of new requests equal in length to the number specified by the 'requests' attribute, and if the connection manager has not yet responded to any of the requests, and if the last request was empty and did not include either a 'pause' attribute or a 'type' attribute set to "terminate", and if the last two requests arrived within a period shorter than the number of seconds specified by the 'polling' attribute in the session creation response, then the connection manager SHOULD consider that the client is making requests more frequently than it was permitted and terminate the HTTP session and return a 'policy-violation' terminal binding error to the client. Note: the behavior for Polling Sessions is slightly different.<br />
<br />
'''Example 13. Too frequent requests response'''<br />
<source lang="xml"><br />
HTTP/1.1 200 OK<br />
Content-Type: text/xml; charset=utf-8<br />
Content-Length: 68<br />
<br />
<body type='terminate'<br />
condition='policy-violation'<br />
xmlns='http://jabber.org/protocol/httpbind'/><br />
</source><br />
<br />
Note: If the connection manager did not specify a 'polling' attribute in the session creation response, then it MUST allow the client to send requests as frequently as it chooses.<br />
<br />
==Polling Sessions==<br />
<br />
It is not always possible for a constrained client to either use HTTP Pipelining or open more than one HTTP connection with the connection manager at a time. In this case the client SHOULD inform the connection manager by setting the values of the 'wait' and/or 'hold' attributes in its session creation request to "0", and then "poll" the connection manager at regular intervals throughout the session for payloads it might have received from the server. Note: Even if the client does not request a polling session, the connection manager MAY require a client to use polling by setting the 'requests' attribute (which specifies the number of simultaneous requests the client can make) of its Session Creation Response to "1", however this is NOT RECOMMENDED.<br />
<br />
If a session will use polling, the connection manager SHOULD specify a higher than normal value for the 'inactivity' attribute (see Inactivity) in its session creation response. The increase SHOULD be greater than the value it specifies for the 'polling' attribute.<br />
<br />
If the client sends two consecutive empty new requests (i.e. requests with incremented rid attributes, not repeat requests) within a period shorter than the number of seconds specified by the 'polling' attribute (the shortest allowable polling interval) in the session creation response, and if the connection manager's response to the first request contained no payloads, then upon reception of the second request the connection manager SHOULD terminate the HTTP session and return a 'policy-violation' terminal binding error to the client.<br />
<br />
'''Example 14. Too frequent polling response'''<br />
<source lang="xml"><br />
HTTP/1.1 200 OK<br />
Content-Type: text/xml; charset=utf-8<br />
Content-Length: 68<br />
<br />
<body type='terminate'<br />
condition='policy-violation'<br />
xmlns='http://jabber.org/protocol/httpbind'/><br />
</source><br />
<br />
Note: If the connection manager did not specify a 'polling' attribute in the session creation response, then it MUST allow the client to poll as frequently as it chooses.<br />
<br />
==Terminating the HTTP Session==<br />
<br />
At any time, the client MAY gracefully terminate the session by sending a <body/> element with a 'type' attribute set to "terminate". The termination request MAY include one or more payloads that the connection manager MUST forward to the server to ensure graceful logoff.<br />
<br />
'''Example 15. Session termination by client'''<br />
<source lang="xml"><br />
POST /webclient HTTP/1.1<br />
Host: httpcm.example.com<br />
Accept-Encoding: gzip, deflate<br />
Content-Type: text/xml; charset=utf-8<br />
Content-Length: 153<br />
<br />
<body rid='1249243565'<br />
sid='SomeSID'<br />
type='terminate'<br />
xmlns='http://jabber.org/protocol/httpbind'><br />
<presence type='unavailable'<br />
xmlns='jabber:client'/><br />
</body><br />
</source><br />
<br />
The connection manager SHOULD respond to this request with an HTTP 200 OK containing an empty <body/> element.<br />
<br />
'''Example 16. Connection manager acknowledges termination'''<br />
<source lang="xml"><br />
HTTP/1.1 200 OK<br />
Content-Type: text/xml; charset=utf-8<br />
Content-Length: 72<br />
<br />
<body type='terminate'<br />
xmlns='http://jabber.org/protocol/httpbind'/><br />
</source><br />
<br />
Upon receiving the response, the client MUST consider the HTTP session to have been terminated.<br />
<br />
==Request IDs==<br />
===Generation===<br />
<br />
The client MUST generate a large, random, positive integer for the initial 'rid' (see Security Considerations) and then increment that value by one for each subsequent request. The client MUST take care to choose an initial 'rid' that will never be incremented above 9007199254740991 [21] within the session. In practice, a session would have to be extraordinarily long (or involve the exchange of an extraordinary number of packets) to exceed the defined limit.<br />
===In-Order Message Forwarding===<br />
<br />
When a client makes simultaneous requests, the connection manager might receive them out of order. The connection manager MUST forward the payloads to the server and respond to the client requests in the order specified by the 'rid' attributes. The client MUST process responses received from the connection manager in the order the requests were made.<br />
<br />
The connection manager SHOULD expect the 'rid' attribute to be within a window of values greater than the 'rid' of the previous request. The size of the window is equal to the maximum number of simultaneous requests allowed by the connection manager. If it receives a request with a 'rid' greater than the values in the window, then the connection manager MUST terminate the session with an error:<br />
<br />
'''Example 17. Unexpected rid error'''<br />
<source lang="xml"><br />
HTTP/1.1 200 OK<br />
Content-Type: text/xml; charset=utf-8<br />
Content-Length: 68<br />
<br />
<body type='terminate'<br />
condition='item-not-found'<br />
xmlns='http://jabber.org/protocol/httpbind'/><br />
</source><br />
<br />
===Broken Connections===<br />
<br />
Unreliable network communications or client constraints can result in broken connections. The connection manager SHOULD remember the 'rid' and the associated HTTP response body of the client's most recent requests which were not session pause requests (see Inactivity) and which did not result in an HTTP or binding error. The number of responses to non-pause requests kept in the buffer SHOULD be either the same as the maximum number of simultaneous requests allowed by the connection manager or, if Acknowledgements are being used, the number of responses that have not yet been acknowledged.<br />
<br />
If the network connection is broken or closed before the client receives a response to a request from the connection manager, then the client MAY resend an exact copy of the original request. Whenever the connection manager receives a request with a 'rid' that it has already received, it SHOULD return an HTTP 200 (OK) response that includes the buffered copy of the original XML response to the client (i.e., a <body/> wrapper possessing appropriate attributes and optionally containing one or more XML payloads). If the original response is not available (e.g., it is no longer in the buffer), then the connection manager MUST return an 'item-not-found' terminal binding error:<br />
<br />
'''Example 18. Response not in buffer error'''<br />
<source lang="xml"><br />
HTTP/1.1 200 OK<br />
Content-Type: text/xml; charset=utf-8<br />
Content-Length: 68<br />
<br />
<body type='terminate'<br />
condition='item-not-found'<br />
xmlns='http://jabber.org/protocol/httpbind'/><br />
</source><br />
<br />
Note: The error is the same whether the 'rid' is too large or too small. This makes it more difficult for an attacker to discover an acceptable value.<br />
<br />
==Protecting Insecure Sessions==<br />
===Applicability===<br />
<br />
The OPTIONAL key sequencing mechanism described here MAY be used if the client's session with the connection manager is not secure. The session SHOULD be considered secure only if all client requests are made via SSL (or TLS) HTTP connections and the connection manager generates an unpredictable session ID. If the session is secure, it is not necessary to use this key sequencing mechanism.<br />
<br />
Even if the session is not secure, the unpredictable session and request IDs specified in the preceding sections of this document already provide a level of protection similar to that provided by a connection bound to a single pair of persistent TCP/IP connections, and thus provide sufficient protection against a 'blind' attacker. However, in some circumstances, the key sequencing mechanism defined below helps to protect against a more determined and knowledgeable attacker.<br />
<br />
It is important to recognize that the key sequencing mechanism defined below helps to protect only against an attacker who is able to view the contents of all requests or responses in an insecure session but who is not able to alter the contents of those requests (in this case, the mechanism prevents the attacker from injecting HTTP requests into the session, e.g., termination requests or responses). However, the key sequencing mechanism does not provide any protection when the attacker is able to alter the contents of insecure requests or responses.<br />
===Introduction===<br />
<br />
The HTTP requests of each session MAY be spread across a series of different socket connections. This would enable an unauthorized user that obtains the session ID and request ID of a session to then use their own socket connection to inject <body/> request elements into the session and receive the corresponding responses.<br />
<br />
The key sequencing mechanism below protects against such attacks by enabling a connection manager to detect <body/> request elements injected by a third party.<br />
===Generating the Key Sequence===<br />
<br />
Prior to requesting a new session, the client MUST select an unpredictable counter ("n") and an unpredictable value ("seed"). The client then processes the "seed" through a cryptographic hash and converts the resulting 160 bits to a hexadecimal string K(1). It does this "n" times to arrive at the initial key K(n). The hashing algorithm MUST be SHA-1 as defined in RFC 3174 [22].<br />
<br />
'''Example 19. Creating the key sequence'''<br />
<br />
K(1) = hex(SHA-1(seed))<br />
K(2) = hex(SHA-1(K(1)))<br />
...<br />
K(n) = hex(SHA-1(K(n-1)))<br />
<br />
<br />
===Use of Keys===<br />
<br />
The client MUST set the 'newkey' attribute of the first request in the session to the value K(n).<br />
<br />
'''Example 20. Session Request with Initial Key'''<br />
<source lang="xml"><br />
POST /webclient HTTP/1.1<br />
Host: httpcm.example.com<br />
Accept-Encoding: gzip, deflate<br />
Content-Type: text/xml; charset=utf-8<br />
Content-Length: 104<br />
<br />
<body content='text/xml; charset=utf-8'<br />
hold='1'<br />
rid='1573741820'<br />
to='example.com'<br />
wait='60'<br />
xml:lang='en'<br />
newkey='ca393b51b682f61f98e7877d61146407f3d0a770'<br />
xmlns='http://jabber.org/protocol/httpbind'/><br />
</source><br />
<br />
The client MUST set the 'key' attribute of all subsequent requests to the value of the next key in the generated sequence (decrementing from K(n-1) towards K(1) with each request sent).<br />
<br />
'''Example 21. Request with Key'''<br />
<source lang="xml"><br />
POST /webclient HTTP/1.1<br />
Host: httpcm.example.com<br />
Accept-Encoding: gzip, deflate<br />
Content-Type: text/xml; charset=utf-8<br />
Content-Length: 88<br />
<br />
<body rid='1573741821'<br />
sid='SomeSID'<br />
key='bfb06a6f113cd6fd3838ab9d300fdb4fe3da2f7d'<br />
xmlns='http://jabber.org/protocol/httpbind'/><br />
</source><br />
<br />
The connection manager MAY verify the key by calculating the SHA-1 hash of the key and comparing it to the 'newkey' attribute of the previous request (or the 'key' attribute if the 'newkey' attribute was not set). If the values do not match (or if it receives a request without a 'key' attribute and the 'newkey' or 'key' attribute of the previous request was set), then the connection manager MUST NOT process the element, MUST terminate the session, and MUST return an 'item-not-found' terminal binding error.<br />
<br />
'''Example 22. Invalid Key Sequence Error'''<br />
<source lang="xml"><br />
HTTP/1.1 200 OK<br />
Content-Type: text/xml; charset=utf-8<br />
Content-Length: 68<br />
<br />
<body type='terminate'<br />
condition='item-not-found'<br />
xmlns='http://jabber.org/protocol/httpbind'/><br />
</source><br />
<br />
===Switching to Another Key Sequence===<br />
<br />
A client SHOULD choose a high value for "n" when generating the key sequence. However, if the session lasts long enough that the client arrives at the last key in the sequence K(1) then the client MUST switch to a new key sequence.<br />
<br />
The client MUST:<br />
<br />
1. Choose new values for "seed" and "n".<br />
2. Generate a new key sequence using the algorithm defined above.<br />
3. Set the 'key' attribute of the request to the next value in the old sequence (i.e. K(1), the last value).<br />
4. Set the 'newkey' attribute of the request to the value K(n) from the new sequence.<br />
<br />
'''Example 23. New Key Sequence'''<br />
<source lang="xml"><br />
POST /webclient HTTP/1.1<br />
Host: httpcm.example.com<br />
Accept-Encoding: gzip, deflate<br />
Content-Type: text/xml; charset=utf-8<br />
Content-Length: 188<br />
<br />
<body rid='1573741822'<br />
sid='SomeSID'<br />
key='6f825e81f4532b2c5fa2d12457d8a1f22e8f838e'<br />
newkey='113f58a37245ec9637266cf2fb6e48bfeaf7964e'<br />
xmlns='http://jabber.org/protocol/httpbind'><br />
<message to='contact@example.com'<br />
xmlns='jabber:client'><br />
<body>I said "Hi!"</body><br />
</message><br />
</body><br />
</source><br />
<br />
==Multiple Streams==<br />
===Introduction===<br />
<br />
The OPTIONAL feature described in this section enables multiple XML streams to be contained within a single HTTP session. This feature is essential in runtime environments that prevent HTTP Pipelining, thereby constraining the number of simultaneous HTTP requests a client can make to each connection manager, since clients running in such environments need multi-stream sessions if they are to connect using more than one account at the same time. This feature also reduces network traffic for any client that needs to establish parallel streams over HTTP.<br />
===Discovery===<br />
<br />
If a connection manager supports the multi-streams feature, it MUST include a 'stream' attribute in its Session Creation Response. If a client does not receive the 'stream' attribute then it MUST assume that the connection manager does not support the feature. [23]<br />
<br />
The 'stream' attribute identifies the first stream to be opened for the session. The value of each 'stream' attribute MUST be an opaque and unpredictable name that is unique within the context of the connection manager application.<br />
<br />
'''Example 24. Session creation response with stream name'''<br />
<source lang="xml"><br />
HTTP/1.1 200 OK<br />
Content-Type: text/xml; charset=utf-8<br />
Content-Length: 128<br />
<br />
<body wait='60'<br />
inactivity='30'<br />
polling='5'<br />
requests='2'<br />
hold='1'<br />
accept='deflate,gzip'<br />
stream='firstStreamName'<br />
maxpause='120'<br />
sid='SomeSID'<br />
charsets='ISO_8859-1 ISO-2022-JP'<br />
ver='1.6'<br />
from='example.com'<br />
xmlns='http://jabber.org/protocol/httpbind'/><br />
</source><br />
<br />
===Adding Streams To A Session===<br />
<br />
If the connection manager included a 'stream' attribute in its session creation response then the client MAY ask it to open another stream at any time by sending it an empty <body/> element with a 'to' attribute. The request MUST include valid 'sid' and 'rid' [24] attributes, and SHOULD also include an 'xml:lang' attribute. The request MAY include 'route', 'from' and 'secure' attributes (see Session Creation Request), but it SHOULD NOT include 'ver', 'content', 'hold' or 'wait' attributes (since a new session is not being created).<br />
<br />
'''Example 25. Requesting another stream'''<br />
<source lang="xml"><br />
POST /webclient HTTP/1.1<br />
Host: httpcm.example.com<br />
Accept-Encoding: gzip, deflate<br />
Content-Type: text/xml; charset=utf-8<br />
Content-Length: 104<br />
<br />
<body sid='SomeSID'<br />
rid='1573741820'<br />
to='example.com'<br />
route='xmpp:example.com:9999'<br />
xml:lang='en'<br />
xmlns='http://jabber.org/protocol/httpbind'/><br />
</source><br />
<br />
If the connection manager did not indicate its support for multiple streams at the start of the session, then it MUST ignore the extra attributes and treat the request as a normal empty request for payloads (see Sending and Receiving XML Payloads). [25] Otherwise it MUST open a new stream with the specified server (see Session Creation Response), generate a new stream name, and respond to the client with the name. The response MAY also include 'from' and 'secure' attributes, but it SHOULD NOT include 'sid', 'requests', 'polling', 'hold', 'inactivity', 'maxpause', 'accept', 'charsets', 'ver' or 'wait' attributes.<br />
<br />
'''Example 26. Add stream response'''<br />
<source lang="xml"><br />
HTTP/1.1 200 OK<br />
Content-Type: text/xml; charset=utf-8<br />
Content-Length: 128<br />
<br />
<body stream='secondStreamName'<br />
from='example.com'<br />
xmlns='http://jabber.org/protocol/httpbind'/><br />
</source><br />
<br />
Note: If the response did not include either 'from' or 'secure' attributes then they MAY be sent in a subsequent response instead (see Session Creation Response). In that case the 'stream' attribute MUST also be specified.<br />
===Transmitting Payloads===<br />
<br />
If more than one stream has been opened within a session, then all non-empty <body/> elements sent by the connection manager MUST include a 'stream' attribute that specifies which stream all the payloads it contains belong to. The client SHOULD include a 'stream' attribute for the same purpose. The client MAY omit the 'stream' attribute if it wants the connection manager to broadcast the payloads over all open streams. Note: A <body/> element MUST NOT contain different payloads for different streams.<br />
<br />
If a stream name does not correspond to one of the session's open streams, then the receiving connection manager SHOULD return an 'item-not-found' terminal binding error, or the receiving client SHOULD terminate the session. However, if the receiving entity has only just closed the stream (and the sender might not have been aware of that when it sent the payloads), then it MAY instead simply silently ignore any payloads the <body/> element contains.<br />
<br />
Note: Empty <body/> elements that do not include a 'from' or 'secure' attribute SHOULD NOT include a 'stream' attribute (since nothing is being transmitted for any stream). If such a <body/> element does include a 'stream' attribute then the receiving entity SHOULD ignore the attribute.<br />
<br />
'''Example 27. Client sends payload with a stream name'''<br />
<source lang="xml"><br />
POST /webclient HTTP/1.1<br />
Host: httpcm.example.com<br />
Accept-Encoding: gzip, deflate<br />
Content-Type: text/xml; charset=utf-8<br />
Content-Length: 188<br />
<br />
<body rid='1249243562'<br />
sid='SomeSID'<br />
stream='secondStreamName'<br />
xmlns='http://jabber.org/protocol/httpbind'><br />
<message to='contact@example.com'<br />
xmlns='jabber:client'><br />
<body>I said hello.</body><br />
</message><br />
</body><br />
</source><br />
<br />
Note: The value of the 'stream' attribute of the response MAY be different than the corresponding request. [26]<br />
<br />
'''Example 28. Connection manager responds with a different stream name'''<br />
<source lang="xml"><br />
HTTP/1.1 200 OK<br />
Content-Type: text/xml; charset=utf-8<br />
Content-Length: 185<br />
<br />
<body stream='firstStreamName'<br />
xmlns='http://jabber.org/protocol/httpbind'><br />
<message from='contact@example.com'<br />
to='user@example.com'<br />
xmlns='jabber:client'><br />
<body>Hi yourself!</body><br />
</message><br />
</body><br />
</source><br />
<br />
If no stream name is specified by the connection manager then the client MUST assume the payloads are associated with the first stream (even if the first stream has been closed).<br />
<br />
If no stream name is specified by the client then the connection manager MUST broadcast the payloads over all open streams. [27]<br />
<br />
'''Example 29. Client asks for a payload to be broadcast'''<br />
<source lang="xml"><br />
POST /webclient HTTP/1.1<br />
Host: httpcm.example.com<br />
Accept-Encoding: gzip, deflate<br />
Content-Type: text/xml; charset=utf-8<br />
Content-Length: 188<br />
<br />
<body rid='1249243562'<br />
sid='SomeSID'<br />
xmlns='http://jabber.org/protocol/httpbind'><br />
<presence xmlns='jabber:client'><br />
<show>away</show><br />
</presence><br />
</body><br />
</source><br />
<br />
===Closing a Stream===<br />
<br />
If more than one stream is open within a session, the client MAY close one open stream at any time using the procedure described in the section Terminating the HTTP Session above, taking care to specify the stream name with a 'stream' attribute. If the client closes the last stream the connection manager MUST terminate the session. If the client does not specify a stream name then the connection manager MUST close all open streams (sending any payloads the terminate request contains to all streams), and terminate the session.<br />
<br />
'''Example 30. Client closes one stream'''<br />
<source lang="xml"><br />
POST /webclient HTTP/1.1<br />
Host: httpcm.example.com<br />
Accept-Encoding: gzip, deflate<br />
Content-Type: text/xml; charset=utf-8<br />
Content-Length: 153<br />
<br />
<body rid='1249243564'<br />
sid='SomeSID'<br />
stream='secondStreamName'<br />
type='terminate'<br />
xmlns='http://jabber.org/protocol/httpbind'><br />
<presence type='unavailable'<br />
xmlns='jabber:client'/><br />
</body><br />
</source><br />
<br />
===Error Conditions===<br />
<br />
If more than one stream is open within a session, the connection manager MAY include a 'stream' attribute in a fatal binding error (see Terminal Binding Conditions). If a 'stream' attribute is specified then the stream MUST be closed by both entities but the session SHOULD NOT be terminated.<br />
<br />
'''Example 31. Fatal stream error'''<br />
<source lang="xml"><br />
HTTP/1.1 200 OK<br />
Content-Type: text/xml; charset=utf-8<br />
Content-Length: 68<br />
<br />
<body type='terminate'<br />
condition='remote-connection-failed'<br />
stream='secondStreamName'<br />
xmlns='http://jabber.org/protocol/httpbind'/><br />
</source><br />
<br />
Note: If the connection manager does not include a 'stream' attribute in a fatal binding error then all the session's open streams MUST be closed by both entities and the session MUST be terminated.<br />
<br />
==Error and Status Codes==<br />
<br />
There are four types of error and status reporting in HTTP responses:<br />
<br />
Table 1: Error Condition Types<br />
Condition Type Description<br />
HTTP Conditions (Deprecated) The connection manager responds to an invalid request from a legacy client with a standard HTTP error. These are used for binding syntax errors, possible attacks, etc. Note that constrained clients are unable to differentiate between HTTP errors.<br />
Terminal Binding Conditions These error conditions can be read by constrained clients. They are used for connection manager problems, abstracting stream errors, communication problems between the connection manager and the server, and invalid client requests (binding syntax errors, possible attacks, etc.)<br />
Recoverable Binding Conditions These report communication problems between the connection manager and the client. They do not terminate the session. Clients recover from these errors by resending all the preceding <body/> wrappers that have not received responses.<br />
Transported Protocol Conditions Errors relating to the XML payloads within <body/> wrappers are, in general, defined in the documentation of the protocol being transported. They do not terminate the session.<br />
<br />
Full descriptions are provided below.<br />
===HTTP Conditions===<br />
<br />
Note: All HTTP codes except 200 have been superseded by Terminal Binding Conditions to allow clients to determine whether the source of errors is the connection manager application or an HTTP intermediary.<br />
<br />
A legacy client (or connection manager) is a client (or connection manager) that did not include a 'ver' attribute in its session creation request (or response). A legacy client (or connection manager) will interpret (or respond with) HTTP error codes according to the table below. Non-legacy connection managers SHOULD NOT send HTTP error codes unless they are communicating with a legacy client. Upon receiving an HTTP error (400, 403, 404), a legacy client or any client that is communicating with a legacy connection manager MUST consider the HTTP session to be null and void. A non-legacy client that is communicating with a non-legacy connection manager MAY consider that the session is still active.<br />
<br />
Table 2: HTTP Error and Status Codes<br />
Code Name Superseded by Purpose<br />
200 OK - Response to valid client request.<br />
400 Bad Request bad-request Inform client that the format of an HTTP header or binding element is unacceptable (e.g., syntax error).<br />
403 Forbidden policy-violation Inform client that it has broken the session rules (polling too frequently, requesting too frequently, too many simultaneous requests).<br />
404 Not Found item-not-found Inform client that (1) 'sid' is not valid, (2) 'stream' is not valid, (3) 'rid' is larger than the upper limit of the expected window, (4) connection manager is unable to resend response, (5) 'key' sequence is invalid.<br />
<br />
Note: No other HTTP error and status codes were defined in the early versions of BOSH (e.g., Internal Server Error).<br />
===Terminal Binding Conditions===<br />
<br />
In any response it sends to the client, the connection manager MAY return a fatal error by setting a 'type' attribute of the <body/> element to "terminate". These binding errors imply that the HTTP session is terminated (unless a 'stream' attribute is specified -- see Multiple Stream Error Conditions).<br />
<br />
Note: Although many of these conditions are similar to the XMPP stream error conditions specified in RFC 6120, they are not to be confused with XMPP stream errors. In cases where BOSH is being used to transport XMPP, any fatal XMPP stream error conditions experienced between the connection manager and the XMPP server SHOULD only be reported using the "remote-stream-error" condition as described below.<br />
<br />
'''Example 32. Remote connection failed error'''<br />
<source lang="xml"><br />
HTTP/1.1 200 OK<br />
Content-Type: text/xml; charset=utf-8<br />
Content-Length: 68<br />
<br />
<body type='terminate'<br />
condition='remote-connection-failed'<br />
xmlns='http://jabber.org/protocol/httpbind'/><br />
</source><br />
<br />
The following values of the 'condition' attribute are defined:<br />
<br />
Table 3: Terminal Binding Error Conditions<br />
Condition Purpose<br />
bad-request* The format of an HTTP header or binding element received from the client is unacceptable (e.g., syntax error).<br />
host-gone The target domain specified in the 'to' attribute or the target host or port specified in the 'route' attribute is no longer serviced by the connection manager.<br />
host-unknown The target domain specified in the 'to' attribute or the target host or port specified in the 'route' attribute is unknown to the connection manager.<br />
improper-addressing The initialization element lacks a 'to' or 'route' attribute (or the attribute has no value) but the connection manager requires one.<br />
internal-server-error The connection manager has experienced an internal error that prevents it from servicing the request.<br />
item-not-found* (1) 'sid' is not valid, (2) 'stream' is not valid, (3) 'rid' is larger than the upper limit of the expected window, (4) connection manager is unable to resend response, (5) 'key' sequence is invalid.<br />
other-request Another request being processed at the same time as this request caused the session to terminate.<br />
policy-violation* The client has broken the session rules (polling too frequently, requesting too frequently, sending too many simultaneous requests).<br />
remote-connection-failed The connection manager was unable to connect to, or unable to connect securely to, or has lost its connection to, the server.<br />
remote-stream-error Encapsulates an error in the protocol being transported.<br />
see-other-uri The connection manager does not operate at this URI (e.g., the connection manager accepts only SSL or TLS connections at some https: URI rather than the http: URI requested by the client). The client can try POSTing to the URI in the content of the <uri/> child element.<br />
system-shutdown The connection manager is being shut down. All active HTTP sessions are being terminated. No new sessions can be created.<br />
undefined-condition The error is not one of those defined herein; the connection manager SHOULD include application-specific information in the content of the <body/> wrapper.<br />
<br />
* If the client did not include a 'ver' attribute in its session creation request then the connection manager SHOULD send a deprecated HTTP Error Condition instead of this terminal binding condition. If the connection manager did not include a 'ver' attribute in its session creation response then the client SHOULD expect it to send a deprecated HTTP Error Condition instead of this terminal binding condition.<br />
<br />
The following is an example of a "see-other-uri" condition:<br />
<br />
'''Example 33. See other URI error'''<br />
<source lang="xml"><br />
HTTP/1.1 200 OK<br />
Content-Type: text/xml; charset=utf-8<br />
Content-Length: 68<br />
<br />
<body condition='see-other-uri'<br />
type='terminate'<br />
xmlns='http://jabber.org/protocol/httpbind'><br />
<uri>https://secure.jabber.org/xmppcm</uri><br />
</body><br />
</source><br />
<br />
The following is an example including a "remote-stream-error" condition:<br />
<br />
'''Example 34. Remote error'''<br />
<source lang="xml"><br />
HTTP/1.1 200 OK<br />
Content-Type: text/xml; charset=utf-8<br />
Content-Length: 68<br />
<br />
<body condition='remote-stream-error'<br />
type='terminate'<br />
xmlns='http://jabber.org/protocol/httpbind'<br />
xmlns:stream='http://etherx.jabber.org/streams'><br />
<message from='contact@example.com'<br />
to='user@example.com'<br />
xmlns='jabber:client'><br />
<body>I said "Hi!"</body><br />
</message><br />
<stream:error><br />
<xml-not-well-formed xmlns='urn:ietf:params:xml:ns:xmpp-streams'/><br />
<text xmlns='urn:ietf:params:xml:ns:xmpp-streams'<br />
xml:lang='en'><br />
Some special application diagnostic information!<br />
</text><br />
<escape-your-data xmlns='application-ns'/><br />
</stream:error><br />
</body><br />
</source><br />
<br />
Naturally, the client MAY report binding errors to the connection manager as well, although this is unlikely.<br />
===Recoverable Binding Conditions===<br />
<br />
In any response it sends to the client, the connection manager MAY return a recoverable error by setting a 'type' attribute of the <body/> element to "error". These errors do not imply that the HTTP session is terminated.<br />
<br />
If it decides to recover from the error, then the client MUST repeat the HTTP request that resulted in the error, as well as all the preceding HTTP requests that have not received responses. The content of these requests MUST be identical to the <body/> elements of the original requests. This enables the connection manager to recover a session after the previous request was lost due to a communication failure.<br />
<br />
'''Example 35. Recoverable error'''<br />
<source lang="xml"><br />
HTTP/1.1 200 OK<br />
Content-Type: text/xml; charset=utf-8<br />
Content-Length: 68<br />
<br />
<body type='error'<br />
xmlns='http://jabber.org/protocol/httpbind'/><br />
</source><br />
<br />
===XML Payload Conditions===<br />
<br />
Application-level error conditions described in the documentation of the protocol being transported are routed to the client through the connection manager. They are transparent to the connection manager, and therefore out of scope for the transport binding defined herein.<br />
<br />
==Implementation Notes==<br />
===HTTP Pipelining===<br />
<br />
Even if the client requests HTTP Pipelining and the connection manager supports it, there is no guarantee that pipelining will succeed, because it might not be supported by intermediate proxies.<br />
<br />
The best the client can do is to request the use of HTTP Pipelining by setting the 'hold' attribute to a value of "1". If HTTP Pipelining does not work (because the server returns HTTP 1.0 or connection:close), then the client SHOULD degrade gracefully by using multiple connections.<br />
<br />
==Security Considerations==<br />
===Connection Between Client and BOSH Service===<br />
<br />
All communications between a client and a BOSH service SHOULD occur over encrypted HTTP connections. Negotiation of encryption between the client and the connection manager SHOULD occur at the transport layer or the HTTP layer, not the application layer; such negotiation SHOULD follow the HTTP/SSL protocol defined in SSL [28], although MAY follow the HTTP/TLS protocol defined in RFC 2818 [29] or the TLS Within HTTP protocol defined in RFC 2817 [30].<br />
<br />
If the HTTP connection used to send the initial session request is encrypted, then all the other HTTP connections used within the session MUST also be encrypted. Furthermore, if authentication certificates are exchanged when establishing the encrypted connection that is used to send the initial session request, then the client and/or connection manager SHOULD ensure that the same authentication certificates are employed for all subsequent connections used by the session. Once such a "secure session" has been established:<br />
<br />
* If the connection manager refuses to establish an encrypted connection or offers a different certificate, then the client SHOULD close the connection and terminate the session without sending any more requests.<br />
* If the client sends a wrapper element that is part of a "secure session" over a connection that either is not encrypted or uses a different certificate, then the connection manager SHOULD simply close the connection. The connection manager SHOULD NOT terminate the session since that would facilitate denial of service attacks.<br />
<br />
===Connection Between BOSH Service and Application===<br />
<br />
A BOSH service SHOULD encrypt its connection to the backend application using appropriate technologies such as Secure Sockets Layer (SSL), Transport Layer Security (TLS), and StartTLS if supported by the backend application. Alternatively, the BOSH service can be considered secure (1) if it is running on the same physical machine as the backend application or (2) if it running on the same private network as the backend application and the administrators are sure that unknown individuals or processes do not have access to that private network.<br />
<br />
If data privacy is desired, the client SHOULD encrypt its messages using an application-specific end-to-end encryption technology, because there is no way for the client to be sure that the BOSH service encrypts its connection to the application; methods for doing so are outside the scope of this specification.<br />
===Unpredictable SID and RID===<br />
<br />
The session identifier (SID) and initial request identifier (RID) are security-critical and therefore MUST be both unpredictable and nonrepeating (see RFC 1750 [31] for recommendations regarding randomness of SIDs and initial RIDs for security purposes).<br />
===Use of SHA-1===<br />
<br />
Recent research has shown that in select cases it is possible to compromise the hashes produced by the SHA-1 hashing algorithm (see RFC 4270 [32]). However, the use to which SHA-1 is put in BOSH will likely minimize the applicability of the attacks described in the literature. Furthermore, current estimates suggest that even with the recently-discovered attack, it would still take one year of computing by a government-sized entity to produce a collision.<br />
<br />
==IANA Considerations==<br />
<br />
TCP port 5280, conventially used for communication between BOSH clients and BOSH connection mangers, is registered with the Internet Assigned Numbers Authority (IANA) [33] in its port registry at IANA Port Numbers Registry [34], with a keyword of "xmpp-bosh". (Although use of this port is OPTIONAL, it is helpful to define this port in a standardized way so that BOSH clients can contact any given XMPP service via BOSH without the need either for DNS TXT records as described in Discovering Alternative XMPP Connection Methods [35] or for more advanced methods such as U-NAPTR.<br />
<br />
==XMPP Registrar Considerations==<br />
===Protocol Namespaces===<br />
<br />
The XMPP Registrar includes 'http://jabber.org/protocol/httpbind' in its registry of protocol namespaces.<br />
<br />
==XML Schema==<br />
<source lang="xml"><br />
<?xml version='1.0' encoding='UTF-8'?><br />
<br />
<xs:schema<br />
xmlns:xs='http://www.w3.org/2001/XMLSchema'<br />
xmlns:stream='http://etherx.jabber.org/streams'<br />
targetNamespace='http://jabber.org/protocol/httpbind'<br />
xmlns='http://jabber.org/protocol/httpbind'<br />
elementFormDefault='qualified'><br />
<br />
<xs:annotation><br />
<xs:documentation><br />
The protocol documented by this schema is defined in<br />
XEP-0124: http://www.xmpp.org/extensions/xep-0124.html<br />
</xs:documentation><br />
</xs:annotation><br />
<br />
<xs:import namespace='http://www.w3.org/XML/1998/namespace'<br />
schemaLocation='http://www.w3.org/2001/03/xml.xsd'/><br />
<br />
<xs:element name='body'><br />
<xs:complexType><br />
<xs:choice><br />
<xs:element name='uri'<br />
minOccurs='0'<br />
maxOccurs='1'<br />
type='xs:string'/><br />
<xs:any namespace='##other'<br />
minOccurs='0'<br />
maxOccurs='unbounded'<br />
processContents='lax'/><br />
</xs:choice><br />
<xs:attribute name='accept' type='xs:string' use='optional'/><br />
<xs:attribute name='ack' type='xs:positiveInteger' use='optional'/><br />
<xs:attribute name='authid' type='xs:string' use='optional'/><br />
<xs:attribute name='charsets' type='xs:NMTOKENS' use='optional'/><br />
<xs:attribute name='condition' use='optional'><br />
<xs:simpleType><br />
<xs:restriction base='xs:NCName'><br />
<xs:enumeration value='bad-request'/><br />
<xs:enumeration value='host-gone'/><br />
<xs:enumeration value='host-unknown'/><br />
<xs:enumeration value='improper-addressing'/><br />
<xs:enumeration value='internal-server-error'/><br />
<xs:enumeration value='item-not-found'/><br />
<xs:enumeration value='other-request'/><br />
<xs:enumeration value='policy-violation'/><br />
<xs:enumeration value='remote-connection-failed'/><br />
<xs:enumeration value='remote-stream-error'/><br />
<xs:enumeration value='see-other-uri'/><br />
<xs:enumeration value='system-shutdown'/><br />
<xs:enumeration value='undefined-condition'/><br />
</xs:restriction><br />
</xs:simpleType><br />
</xs:attribute><br />
<xs:attribute name='content' type='xs:string' use='optional'/><br />
<xs:attribute name='from' type='xs:string' use='optional'/><br />
<xs:attribute name='hold' type='xs:unsignedByte' use='optional'/><br />
<xs:attribute name='inactivity' type='xs:unsignedShort' use='optional'/><br />
<xs:attribute name='key' type='xs:string' use='optional'/><br />
<xs:attribute name='maxpause' type='xs:unsignedShort' use='optional'/><br />
<xs:attribute name='newkey' type='xs:string' use='optional'/><br />
<xs:attribute name='pause' type='xs:unsignedShort' use='optional'/><br />
<xs:attribute name='polling' type='xs:unsignedShort' use='optional'/><br />
<xs:attribute name='report' type='xs:positiveInteger' use='optional'/><br />
<xs:attribute name='requests' type='xs:unsignedByte' use='optional'/><br />
<xs:attribute name='rid' type='xs:positiveInteger' use='optional'/><br />
<xs:attribute name='route' type='xs:string' use='optional'/><br />
<xs:attribute name='sid' type='xs:string' use='optional'/><br />
<xs:attribute name='stream' type='xs:string' use='optional'/><br />
<xs:attribute name='time' type='xs:unsignedShort' use='optional'/><br />
<xs:attribute name='to' type='xs:string' use='optional'/><br />
<xs:attribute name='type' use='optional'><br />
<xs:simpleType><br />
<xs:restriction base='xs:NCName'><br />
<xs:enumeration value='error'/><br />
<xs:enumeration value='terminate'/><br />
</xs:restriction><br />
</xs:simpleType><br />
</xs:attribute><br />
<xs:attribute name='ver' type='xs:string' use='optional'/><br />
<xs:attribute name='wait' type='xs:unsignedShort' use='optional'/><br />
<xs:attribute ref='xml:lang' use='optional'/><br />
<xs:anyAttribute namespace='##other' processContents='lax'/><br />
</xs:complexType><br />
</xs:element><br />
<br />
</xs:schema><br />
</source><br />
<br />
==Acknowledgements==<br />
<br />
Thanks to Mike Cumings, Tomas Karasek, Tobias Markmann, Chris Seymour, Safa Sofuoğlu, Stefan Strigler, Matthew Wild, Kevin Winters, and Christopher Zorn for their feedback.<br />
<br />
==Appendices==<br />
===Appendix A: Document Information===<br />
<br />
Series: XEP<br />
Number: 0124<br />
Publisher: XMPP Standards Foundation<br />
Status: Draft<br />
Type: Standards Track<br />
Version: 1.10<br />
Last Updated: 2010-07-02<br />
Approving Body: XMPP Council<br />
Dependencies: RFC 1945, RFC 2616, RFC 3174<br />
Supersedes: None<br />
Superseded By: None<br />
Short Name: bosh<br />
Schema: <http://www.xmpp.org/schemas/httpbind.xsd><br />
Source Control: HTML RSS<br />
This document in other formats: XML PDF<br />
===Appendix B: Author Information===<br />
Ian Paterson<br />
<br />
Email: ian.paterson@clientside.co.uk<br />
JabberID: ian@zoofy.com<br />
Dave Smith<br />
<br />
Email: dizzyd@jabber.org<br />
JabberID: dizzyd@jabber.org<br />
Peter Saint-Andre<br />
<br />
Email: stpeter@jabber.org<br />
JabberID: stpeter@jabber.org<br />
URI: https://stpeter.im/<br />
Jack Moffitt<br />
<br />
Email: jack@chesspark.com<br />
JabberID: jack@chesspark.com<br />
===Appendix C: Legal Notices===<br />
Copyright<br />
This XMPP Extension Protocol is copyright © 1999 - 2011 by the XMPP Standards Foundation (XSF).<br />
Permissions<br />
Permission is hereby granted, free of charge, to any person obtaining a copy of this specification (the "Specification"), to make use of the Specification without restriction, including without limitation the rights to implement the Specification in a software program, deploy the Specification in a network service, and copy, modify, merge, publish, translate, distribute, sublicense, or sell copies of the Specification, and to permit persons to whom the Specification is furnished to do so, subject to the condition that the foregoing copyright notice and this permission notice shall be included in all copies or substantial portions of the Specification. Unless separate permission is granted, modified works that are redistributed shall not contain misleading information regarding the authors, title, number, or publisher of the Specification, and shall not claim endorsement of the modified works by the authors, any organization or project to which the authors belong, or the XMPP Standards Foundation.<br />
Disclaimer of Warranty<br />
## NOTE WELL: This Specification is provided on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, express or implied, including, without limitation, any warranties or conditions of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A PARTICULAR PURPOSE. ##<br />
Limitation of Liability<br />
In no event and under no legal theory, whether in tort (including negligence), contract, or otherwise, unless required by applicable law (such as deliberate and grossly negligent acts) or agreed to in writing, shall the XMPP Standards Foundation or any author of this Specification be liable for damages, including any direct, indirect, special, incidental, or consequential damages of any character arising from, out of, or in connection with the Specification or the implementation, deployment, or other use of the Specification (including but not limited to damages for loss of goodwill, work stoppage, computer failure or malfunction, or any and all other commercial damages or losses), even if the XMPP Standards Foundation or such author has been advised of the possibility of such damages.<br />
IPR Conformance<br />
This XMPP Extension Protocol has been contributed in full conformance with the XSF's Intellectual Property Rights Policy (a copy of which can be found at <http://xmpp.org/extensions/ipr-policy.shtml> or obtained by writing to XMPP Standards Foundation, 1899 Wynkoop Street, Suite 600, Denver, CO 80202 USA).<br />
===Appendix D: Relation to XMPP===<br />
<br />
The Extensible Messaging and Presence Protocol (XMPP) is defined in the XMPP Core (RFC 3920) and XMPP IM (RFC 3921) specifications contributed by the XMPP Standards Foundation to the Internet Standards Process, which is managed by the Internet Engineering Task Force in accordance with RFC 2026. Any protocol defined in this document has been developed outside the Internet Standards Process and is to be understood as an extension to XMPP rather than as an evolution, development, or modification of XMPP itself.<br />
===Appendix E: Discussion Venue===<br />
<br />
The primary venue for discussion of XMPP Extension Protocols is the <standards@xmpp.org> discussion list.<br />
<br />
Discussion on other xmpp.org discussion lists might also be appropriate; see <http://xmpp.org/about/discuss.shtml> for a complete list.<br />
<br />
Given that this XMPP Extension Protocol normatively references IETF technologies, discussion on the <xsf-ietf@xmpp.org> list might also be appropriate.<br />
<br />
Errata can be sent to <editor@xmpp.org>.<br />
===Appendix F: Requirements Conformance===<br />
<br />
The following requirements keywords as used in this document are to be interpreted as described in RFC 2119: "MUST", "SHALL", "REQUIRED"; "MUST NOT", "SHALL NOT"; "SHOULD", "RECOMMENDED"; "SHOULD NOT", "NOT RECOMMENDED"; "MAY", "OPTIONAL".<br />
===Appendix G: Notes===<br />
<br />
1. RFC 793: Transmission Control Protocol <http://tools.ietf.org/html/rfc0793>.<br />
<br />
2. RFC 1945: Hypertext Transfer Protocol -- HTTP/1.0 <http://tools.ietf.org/html/rfc1945>.<br />
<br />
3. RFC 2616: Hypertext Transport Protocol -- HTTP/1.1 <http://tools.ietf.org/html/rfc2616>.<br />
<br />
4. Bayeux Protocol <http://svn.cometd.org/trunk/bayeux/bayeux.html>.<br />
<br />
5. The Web Socket Protocol <http://tools.ietf.org/html/draft-hixie-thewebsocketprotocol>.<br />
<br />
6. Reverse HTTP <http://tools.ietf.org/html/draft-lentczner-rhttp>.<br />
<br />
7. RFC 2965: HTTP State Management Mechanism <http://tools.ietf.org/html/rfc2965>.<br />
<br />
8. Requiring cookies is sub-optimal because several significant computing platforms provide only limited access to underlying HTTP requests/responses; worse, some platforms hide or remove cookie-related headers.<br />
<br />
9. XEP-0025: Jabber HTTP Polling <http://xmpp.org/extensions/xep-0025.html>.<br />
<br />
10. RFC 6120: Extensible Messaging and Presence Protocol (XMPP): Core <http://tools.ietf.org/html/rfc6120>.<br />
<br />
11. XEP-0206: XMPP Over BOSH <http://xmpp.org/extensions/xep-0206.html>.<br />
<br />
12. In order to reduce network congestion, RFC 2616 recommends that clients SHOULD NOT keep more than two HTTP connections to the same HTTP server open at the same time. Clients running in constrained enviroments typically have no choice but to abide by that recommendation.<br />
<br />
13. If there is no traffic other than the "pings" then bandwidth consumption will be double that of a TCP connection (although double nothing is still nothing). If data is sent in large packets then bandwidth consumption will be almost identical.<br />
<br />
14. Extensible Markup Language (XML) 1.0 (Fourth Edition) <http://www.w3.org/TR/REC-xml/>.<br />
<br />
15. Namespaces in XML <http://www.w3.org/TR/REC-xml-names/>.<br />
<br />
16. RFC 4627: The application/json Media Type for JavaScript Object Notation (JSON) <http://tools.ietf.org/html/rfc4627>.<br />
<br />
17. Extensible Markup Language (XML) 1.0 (Fourth Edition) <http://www.w3.org/TR/REC-xml/>.<br />
<br />
18. Although the syntax of the 'route' attribute bears a superficial resemblance to a URI or IRI, it is not a URI/IRI and MUST NOT be processed in accordance with the rules specified in RFC 3986, RFC 3987, or (for XMPP) RFC 5122.<br />
<br />
19. Each character set name (or character encoding name -- we use the terms interchangeably) SHOULD be of type NMTOKEN, where the names are separated by the white space character #x20, resulting in a tokenized attribute type of NMTOKENS (see Section 3.3.1 of XML 1.0 [20]). Strictly speaking, the Character Sets registry maintained by the Internet Assigned Numbers Authority (see <http://www.iana.org/assignments/character-sets>) allows a character set name to contain any printable US-ASCII character, which might include characters not allowed by the NMTOKEN construction of XML 1.0; however, the only existing character set name which includes such a character is "NF_Z_62-010_(1973)".<br />
<br />
20. Extensible Markup Language (XML) 1.0 (Fourth Edition) <http://www.w3.org/TR/REC-xml/>.<br />
<br />
21. 9007199254740991 is 253-1. Some weakly typed languages use IEEE Standard 754 Doubles to represent all numbers. These Doubles cannot represent integers above 253 accurately.<br />
<br />
22. RFC 3174: US Secure Hash Algorithm 1 (SHA1) <http://tools.ietf.org/html/rfc3174>.<br />
<br />
23. Therefore a client and a connection manager will be compatible even if one or the other offers no support for multi-stream sessions.<br />
<br />
24. The 'rid' attribute is always incremented normally without reference to any 'stream' attribute.<br />
<br />
25. This helps to ensure backwards-compatibility with older implementations.<br />
<br />
26. Each HTTP response MUST belong to the same session as the request that triggered it, but not necessarily to the same stream.<br />
<br />
27. The broadcast payloads can be of any type.<br />
<br />
28. SSL V3.0 <http://wp.netscape.com/eng/ssl3/draft302.txt>.<br />
<br />
29. RFC 2818: HTTP Over TLS <http://tools.ietf.org/html/rfc2818>.<br />
<br />
30. RFC 2817: Upgrading to TLS Within HTTP/1.1 <http://tools.ietf.org/html/rfc2817>.<br />
<br />
31. RFC 1750: Randomness Recommendations for Security <http://tools.ietf.org/html/rfc1750>.<br />
<br />
32. RFC 4270: Attacks on Cryptographic Hashes in Internet Protocols <http://tools.ietf.org/html/rfc4270>.<br />
<br />
33. The Internet Assigned Numbers Authority (IANA) is the central coordinator for the assignment of unique parameter values for Internet protocols, such as port numbers and URI schemes. For further information, see <http://www.iana.org/>.<br />
<br />
34. IANA registry of port numbers <http://www.iana.org/assignments/port-numbers>.<br />
<br />
35. XEP-0156: Discovering Alternative XMPP Connection Methods <http://xmpp.org/extensions/xep-0156.html>.<br />
===Appendix H: Revision History===<br />
<br />
Note: Older versions of this specification might be available at http://xmpp.org/extensions/attic/<br />
Version 1.10 (2010-07-02)<br />
<br />
Further clarified use of 'from' and 'to' attributes; added missing condition values to the schema.<br />
(psa)<br />
Version 1.9 (2009-11-06)<br />
<br />
Added information for registration of port 5280 with IANA.<br />
(psa)<br />
Version 1.8 (2009-04-30)<br />
<br />
Removed secure attribute because it did not solve the problem it was intended to solve; added security consideration regarding link between connection manager and application server; changed "stanza" to "payload" for disambiguation with XMPP; clarified design objectives and relationship to similar technologies; corrected several errors in the schema.<br />
(psa/jm)<br />
Version 1.7 (2008-10-29)<br />
<br />
Moved alternative script syntax to historical specification; added implementation note about HTTP Pipelining; adjusted architectural description.<br />
(psa)<br />
Version 1.6 (2007-02-21)<br />
<br />
Multiple clarifications and restructuring without changes to protocol itself; changed title to BOSH; added section that fully explains the technique underlying the protocol; separated XMPP-specific features into new XEP-0206; added optional new Script Syntax and session pauses; added Acknowledgements section; added from and ver attributes; added hold attribute to session creation response; clarified polling too-frequently error; recommended that clients use HTTP Pipelining.<br />
(ip)<br />
Version 1.5 (2006-04-28)<br />
<br />
Added optional Multiple Streams section; added security considerations about encrypted HTTP connections; recommended use of SSL rather than HTTP over TLS; specified that request ID values must not exceed 9007199254740991; corrected datatypes of inactivity, polling, rid, and wait attributes in the schema; added <any/> and <anyAttribute/> elements to schema to optionally support non-XMPP XML elements and attributes; deprecated HTTP error codes in favor of new terminal binding conditions.<br />
(ip/psa)<br />
Version 1.4 (2005-12-14)<br />
<br />
Modified syntax of route attribute to be proto:host:port rather than XMPP URI/IRI.<br />
(psa)<br />
Version 1.3 (2005-11-02)<br />
<br />
Corrected stream:features namespace and the Recoverable Binding Conditions section; recommended that connection manager shall return secure attribute to client; recommended end-to-end encryption through proxy connection managers.<br />
(ip)<br />
Version 1.2 (2005-06-16)<br />
<br />
Specified optional use of route and secure attributes in session request. Minor correction: the stream features element should be included in the response that contains the authid attribute (this is not necessarily the session creation response).<br />
(ip)<br />
Version 1.1 (2005-06-02)<br />
<br />
Specified optional use of HTTP Accept-Encoding and Content-Encoding headers for compression at HTTP binding level.<br />
(ip)<br />
Version 1.0 (2005-03-03)<br />
<br />
Per a vote of the Jabber Council, advanced status to Draft.<br />
(psa)<br />
Version 0.10 (2004-11-08)<br />
<br />
Changed HTTP 401 errors to HTTP 404.<br />
(ip)<br />
Version 0.9 (2004-10-26)<br />
<br />
Added charset attribute.<br />
(ip/psa)<br />
Version 0.8 (2004-10-26)<br />
<br />
Specified that wait attribute must be included in the session creation response.<br />
(ip)<br />
Version 0.7 (2004-08-12)<br />
<br />
Defined appropriate XMPP stanza error conditions.<br />
(psa/ip)<br />
Version 0.6 (2004-07-19)<br />
<br />
Added xml:lang attribute to the session request; added recoverable binding error conditions.<br />
(ip)<br />
Version 0.5 (2004-05-07)<br />
<br />
Protocol refactored to enable simultaneous requests (request identifier attribute, wait attribute, hold attribute, requests attribute) and recovery of broken connections; added content attribute; removed all wrapper types except 'terminate'; updated error handling; made key mechanism optional (should use SSL/TLS instead).<br />
(ip/psa)<br />
Version 0.4 (2004-02-23)<br />
<br />
Fixed typos; removed "resource-constraint" binding error; added HTTP 403 error to table.<br />
(psa/ip)<br />
Version 0.3 (2004-02-19)<br />
<br />
Added 'authid' attribute to enable communication of XMPP stream ID (used in digest authentication); specified that Content-Types other than "text/xml" are allowed to support older HTTP clients; specified business rule for connection manager queueing of client requests; changed <packet/> to <body/> to support older HTTP clients; changed 'to' attribute on initialization element from MAY to SHOULD; recommended inclusion of unavailable presence in termination element sent from client; described architectural assumptions; specified binding-specific error handling.<br />
(psa/ip)<br />
Version 0.2 (2004-01-13)<br />
<br />
Added 'to' attribute on the initialization element; specified that 'text/html' is allowable for backwards-compatibility.<br />
(dss/psa/ip)<br />
Version 0.1 (2003-11-06)<br />
<br />
Initial version.<br />
(dss/psa)<br />
<br />
结束</div>
Snowqiang
http://wiki.jabbercn.org/XEP-0124
XEP-0124
2011-05-18T13:28:49Z
<p>Snowqiang: 添加分类, 修改头部信息</p>
<hr />
<div>[[Category:XMPP扩展]]<br />
[[Category:翻译中]]<br />
<br />
'''本文的英文原文来自[http://www.xmpp.org/extensions/xep-0124.html XEP-0124]'''<br />
<br />
'''XEP-0124: Bidirectional-streams Over Synchronous HTTP (BOSH)'''<br />
<br />
摘要: This specification defines a transport protocol that emulates the semantics of a long-lived, bidirectional TCP connection between two entities (such as a client and a server) by efficiently using multiple synchronous HTTP request/response pairs without requiring the use of frequent polling or chunked responses.<br />
作者: Ian Paterson, Dave Smith, Peter Saint-Andre, Jack Moffitt<br />
版权: © 1999 - 2011 XMPP Standards Foundation. SEE LEGAL NOTICES.<br />
状态: 草案<br />
类型: 标准跟踪<br />
版本: 2.0<br />
最后更新日期: 2010-07-02<br />
<br />
NOTICE: The protocol defined herein is a Draft Standard of the XMPP Standards Foundation. Implementations are encouraged and the protocol is appropriate for deployment in production systems, but some changes to the protocol are possible before it becomes a Final Standard.<br />
<br />
1. Introduction<br />
<br />
The Transmission Control Protocol (TCP; RFC 793 [1]) is often used to establish a stream-oriented connection between two entities. Such connections can often be long-lived to enable an interactive "session" between the entities. However, sometimes the nature of the device or network can prevent an application from maintaining a long-lived TCP connection to a server or peer. In this case, it is desirable to use an alternative connection method that emulates the behavior of a long-lived TCP connection using a sequenced series of requests and responses that are exchanged over short-lived connections. The appropriate request-response semantics are widely available via the Hypertext Transfer Protocol (HTTP) as specified in RFC 1945 [2] and RFC 2616 [3].<br />
<br />
BOSH, the technology defined in this specification, essentially provides a "drop-in" alternative to a long-lived, bidirectional TCP connection. It is a mature, full-featured technology that has been widely implemented and deployed since 2004. To our knowledge it was the first of many similar technologies, which now include the Comet methodology formalized in the Bayeux Protocol [4] as well as The Web Socket Protocol [5] and Reverse HTTP [6].<br />
<br />
BOSH is designed to transport any data efficiently and with minimal latency in both directions. For applications that require both "push" and "pull" semantics, BOSH is significantly more bandwidth-efficient and responsive than most other bidirectional HTTP-based transport protocols and the techniques now commonly known as "Ajax". BOSH achieves this efficiency and low latency by using so-called "long polling" with multiple synchronous HTTP request/response pairs. Furthermore, BOSH can address the needs of constrained clients by employing fully-compliant HTTP 1.0 without the need for "cookies" (see RFC 2965 [7]) [8] or even access to HTTP headers.<br />
<br />
BOSH was originally developed in the Jabber/XMPP community as a replacement for an even earlier HTTP-based technology called Jabber HTTP Polling [9]. Although BOSH assumes that the "payload" of HTTP requests and responses will be XML, the payload formats are not limited to XMPP stanzas (see XMPP Core [10]) and could contain a mixture of elements qualified by namespaces defined by different protocols (e.g., both XMPP and JSON). This mix is necessary because some connection managers might 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 payload is qualified by the correct namespace.<br />
<br />
Note: XMPP Over BOSH [11] documents some XMPP-specific extensions of this protocol that were formerly included in this document.<br />
2. Requirements<br />
<br />
The following design requirements reflect the need to offer performance as close as possible to a standard TCP connection.<br />
<br />
1. Compatible with constrained runtime environments* (e.g., mobile and browser-based clients).<br />
2. Compatible with proxies that buffer partial HTTP responses.<br />
3. Efficient through proxies that limit the duration of HTTP responses.<br />
4. Fully compatible with HTTP/1.0.<br />
5. Compatible with restricted network connections (e.g., firewalls, proxies, and gateways).<br />
6. Fault tolerant (e.g., session recovers after an underlying TCP connection breaks at any stage during an HTTP request).<br />
7. Extensible.<br />
8. Consume significantly less bandwidth than polling-based protocols.<br />
9. Significantly more responsive (lower latency) than polling-based protocols.<br />
10. Support for polling (for clients that are limited to a single HTTP connection at a time).<br />
11. In-order delivery of data.<br />
12. Guard against unauthorized users injecting HTTP requests into a session.<br />
13. Protect against denial of service attacks.<br />
14. Multiplexing of data streams.<br />
<br />
*Note: Compatibility with constrained runtime environments implies the following restrictions:<br />
<br />
1. Clients are not required to have programmatic access to the headers of each HTTP request and response (e.g., cookies or status codes).<br />
2. The body of each HTTP request and response is parsable XML with a single root element.<br />
3. Clients can specify the Content-Type of the HTTP responses they receive.<br />
<br />
3. Architectural Assumptions<br />
<br />
This document assumes that most implementations will utilize a specialized connection manager ("CM") to handle HTTP connections rather than the native connection type for the relevant application (e.g., TCP connections in XMPP). Effectively, such a connection manager is a specialized HTTP server that translates between the HTTP requests and responses defined herein and the data streams (or API) implemented by the server with which it communicates, thus enabling a client to connect to a server via HTTP on port 80 or 443 instead of an application-specific port. We can illustrate this graphically as follows:<br />
<br />
Server<br />
|<br />
| [unwrapped data streams]<br />
|<br />
HTTP CM<br />
|<br />
| [HTTP + <body/> wrapper]<br />
|<br />
Client<br />
<br />
<br />
This specification covers communication only between a client and the connection manager. It does not cover communication between the connection manager and the server, since such communications are implementation-specific (e.g., the server might 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 might be an independent translating proxy such that the server might believe it is talking directly to the client over TCP; or the connection manager and the server might use a component protocol or an API defined by the server implementation).<br />
<br />
Furthermore, no aspect of this protocol limits its use to communication between a client and a server. For example, it could be used for communication between a server and a peer server if such communication can occur for the relevant application (e.g., in XMPP). 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 the native connection transport for the relevant application. (However, on some unreliable networks, BOSH might enable more stable communication between servers.)<br />
4. The BOSH Technique<br />
<br />
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).<br />
<br />
The technique employed by BOSH 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.<br />
<br />
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 so to make sure the client can send more data immediately if necessary. (The client SHOULD NOT open more than two HTTP connections to the connection manager at the same time, [12] so it would otherwise have to wait until the connection manager responds to one of the requests.)<br />
<br />
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 TCP 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.<br />
<br />
If there is no traffic in either direction for an agreed amount of time (typically several 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 so 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. [13]<br />
<br />
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. Thus 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. Therefore, 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 were being used.<br />
<br />
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.<br />
5. HTTP Overview<br />
<br />
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).<br />
<br />
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 permitted by RFC 1945 or RFC 2616. For example, 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 might buffer each partial HTTP request or response and only forward the full request or response once it is available.<br />
<br />
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.<br />
<br />
Requests and responses MAY include HTTP headers not specified herein. The receiver SHOULD ignore any such headers.<br />
<br />
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). However, the responses to requests that are not part of the session sent over the same connection using HTTP pipelining (or queued to be sent over the same connection) might be delayed if they were sent while a request that is part of the session is being held (since the connection manager MUST send its responses in the same order that the requests were received, and the connection manager typically delays its responses).<br />
<br />
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.<br />
6. <body/> Wrapper Element<br />
<br />
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 transferred. The <body/> element and its content together MUST conform to the specifications set out in XML 1.0 [14]. They SHOULD also conform to Namespaces in XML [15]. The content MUST NOT contain any of the following (all defined in XML 1.0):<br />
<br />
*<br />
<br />
Partial XML elements<br />
*<br />
<br />
XML comments<br />
*<br />
<br />
XML processing instructions<br />
*<br />
<br />
Internal or external DTD subsets<br />
*<br />
<br />
Internal or external entity references (with the exception of predefined entities)<br />
<br />
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 "payloads" in this document, e.g., XMPP stanzas as defined in RFC 6120 or elements containing XML character data that represents objects using the JSON data interchange format as defined in RFC 4627 [16]). Each <body/> wrapper MAY contain payloads qualified under a wide variety of different namespaces.<br />
<br />
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.<br />
7. Initiating a BOSH Session<br />
7.1 Session Creation Request<br />
<br />
The first request from the client to the connection manager requests a new session.<br />
<br />
The <body/> element of the first request SHOULD possess the following attributes (they SHOULD NOT be included in any other requests except as specified under Adding Streams To A Session):<br />
<br />
* 'to' -- This attribute specifies the target domain of the first stream.<br />
* 'xml:lang' -- This attribute (as defined in Section 2.12 of XML 1.0 [17]) specifies the default language of any human-readable XML character data sent or received during the session.<br />
* 'ver' -- This attribute specifies the highest version of the BOSH protocol that the client supports. The numbering scheme is "<major>.<minor>" (where the minor number MAY be incremented higher than a single digit, so it MUST be treated as a separate integer). Note: The 'ver' attribute should not be confused with the version of any protocol being transported.<br />
* 'wait' -- This attribute specifies the longest time (in seconds) that the connection manager is allowed to wait before responding to any request during the session. This enables the client to limit the delay before it discovers any network failure, and to prevent its HTTP/TCP connection from expiring due to inactivity.<br />
* 'hold' -- This attribute specifies the maximum number of requests the connection manager is allowed to keep waiting at any one time during the session. If the client is not able to use HTTP Pipelining then this SHOULD be set to "1".<br />
<br />
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 both typically one or two orders of magnitude!<br />
<br />
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:example.com:9999"). [18] A connection manager that is configured to work only with a single server (or only with a defined list of domains and the associated list of hostnames and ports that are serving those domains) MAY ignore the 'route' attribute. (Note that the 'to' attribute specifies the domain being served, not the hostname of the machine that is serving the domain.)<br />
<br />
The <body/> element of the first request MAY also possess a 'from' attribute, which specifies the originator of the first stream and which enables the connection manager to forward the originating entity's identity to the application server (e.g., the JabberID of an entity that is connecting to an XMPP server; see XEP-0206).<br />
<br />
A client MAY include an 'ack' attribute (set to "1") to indicate that it will be using acknowledgements throughout the session and that the absence of an 'ack' attribute in any request is meaningful (see Acknowledgements).<br />
<br />
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".<br />
<br />
Example 1. Requesting a BOSH session<br />
<br />
POST /webclient HTTP/1.1<br />
Host: httpcm.example.com<br />
Accept-Encoding: gzip, deflate<br />
Content-Type: text/xml; charset=utf-8<br />
Content-Length: 104<br />
<br />
<body content='text/xml; charset=utf-8'<br />
from='user@example.com'<br />
hold='1'<br />
rid='1573741820'<br />
to='example.com'<br />
route='xmpp:example.com:9999'<br />
ver='1.6'<br />
wait='60'<br />
ack='1'<br />
xml:lang='en'<br />
xmlns='http://jabber.org/protocol/httpbind'/><br />
<br />
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.<br />
7.2 Session Creation Response<br />
<br />
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):<br />
<br />
* 'sid' -- This attribute specifies the SID<br />
* 'wait' -- This is the longest time (in seconds) that the connection manager will wait before responding to any request during the session. The time MUST be less than or equal to the value specified in the session request.<br />
<br />
The <body/> element SHOULD also include the following attributes (they SHOULD NOT be included in any other responses):<br />
<br />
* 'ver' -- This attribute specifies the highest version of the BOSH protocol that the connection manager supports, or the version specified by the client in its request, whichever is lower.<br />
* 'polling' -- This attribute specifies the shortest allowable polling interval (in seconds). This enables the client to not send empty request elements more often than desired (see Polling Sessions and Overactivity).<br />
* 'inactivity' -- This attribute specifies the longest allowable inactivity period (in seconds). This enables the client to ensure that the periods with no requests pending are never too long (see Polling Sessions and Inactivity).<br />
* 'requests' -- This attribute enables the connection manager to limit the number of simultaneous requests the client makes (see Overactivity and Polling Sessions). The RECOMMENDED values are either "2" or one more than the value of the 'hold' attribute specified in the session request.<br />
* 'hold' -- This attribute informs the client about the maximum number of requests the connection manager will keep waiting at any one time during the session. This value MUST NOT be greater than the value specified by the client in the session request.<br />
* 'to' -- This attribute communicates the identity of the backend server to which the client is attempting to connect.<br />
<br />
The connection manager MAY include an 'accept' attribute in the session creation response element, to specify a space-separated list of 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.<br />
<br />
A connection manager MAY include an 'ack' attribute (set to the value of the 'rid' attribute of the session creation request) to indicate that it will be using acknowledgements throughout the session and that the absence of an 'ack' attribute in any response is meaningful (see Acknowledgements).<br />
<br />
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 can request.<br />
<br />
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. [19]<br />
<br />
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 a BOSH Session), then in the same response the connection manager SHOULD also include the 'secure' attribute set to "true" or "1".<br />
<br />
Example 2. Session creation response<br />
<br />
HTTP/1.1 200 OK<br />
Content-Type: text/xml; charset=utf-8<br />
Content-Length: 128<br />
<br />
<body wait='60'<br />
inactivity='30'<br />
polling='5'<br />
requests='2'<br />
hold='1'<br />
ack='1573741820'<br />
accept='deflate,gzip'<br />
maxpause='120'<br />
sid='SomeSID'<br />
charsets='ISO_8859-1 ISO-2022-JP'<br />
ver='1.6'<br />
from='example.com'<br />
xmlns='http://jabber.org/protocol/httpbind'/><br />
<br />
Example 3. Subsequent response with 'from' and 'secure' attributes<br />
<br />
HTTP/1.1 200 OK<br />
Content-Type: text/xml; charset=utf-8<br />
Content-Length: 128<br />
<br />
<body from='example.com'<br />
xmlns='http://jabber.org/protocol/httpbind'/><br />
<br />
8. Sending and Receiving XML Payloads<br />
<br />
After the client has successfully completed all required preconditions, it can send and receive XML payloads via the HTTP binding.<br />
<br />
Example 4. Transmitting payloads<br />
<br />
POST /webclient HTTP/1.1<br />
Host: httpcm.example.com<br />
Accept-Encoding: gzip, deflate<br />
Content-Type: text/xml; charset=utf-8<br />
Content-Length: 188<br />
<br />
<body rid='1249243562'<br />
sid='SomeSID'<br />
xmlns='http://jabber.org/protocol/httpbind'><br />
<message to='contact@example.com'<br />
xmlns='jabber:client'><br />
<body>Good morning!</body><br />
</message><br />
<message to='friend@example.com'<br />
xmlns='jabber:client'><br />
<body>Hey, what&apos;s up?</body><br />
</message><br />
</body><br />
<br />
Upon receipt of a request, the connection manager SHOULD forward the content of the <body/> element to the server as soon as possible. In any case it MUST forward the content from different requests in the order specified by their 'rid' attributes.<br />
<br />
The connection manager MUST also return an HTTP 200 OK response with a <body/> element to the client. Note: This does not indicate that the payloads have been successfully delivered to the application server.<br />
<br />
It is RECOMMENDED that the connection manager not return an HTTP result until a payload has arrived from the application server for delivery to the client. However, the connection manager SHOULD NOT wait longer than the time specified by the client in the 'wait' attribute of its Session Creation Request, and it SHOULD NOT keep more HTTP requests waiting at a time than the number specified in the 'hold' attribute of the session creation request. In any case it MUST respond to requests in the order specified by their 'rid' attributes.<br />
<br />
If there are no payloads waiting or ready to be delivered within the waiting period, then the connection manager SHOULD include an empty <body/> element in the HTTP result:<br />
<br />
Example 5. Empty response<br />
<br />
HTTP/1.1 200 OK<br />
Content-Type: text/xml; charset=utf-8<br />
Content-Length: 64<br />
<br />
<body xmlns='http://jabber.org/protocol/httpbind'/><br />
<br />
If the connection manager has received one or more payloads from the application server for delivery to the client, then it SHOULD return the payloads in the body of its response as soon as possible after receiving them from the server. The example below includes payloads qualified by different namespaces:<br />
<br />
Example 6. Response with queued stanza<br />
<br />
HTTP/1.1 200 OK<br />
Content-Type: text/xml; charset=utf-8<br />
Content-Length: 185<br />
<br />
<body xmlns='http://jabber.org/protocol/httpbind'<br />
xmlns:json='http://json.org/'><br />
<message from='contact@example.com'<br />
to='user@example.com'<br />
xmlns='jabber:client'><br />
<body>Good morning to you!</body><br />
</message><br />
<message from='friend@example.com'<br />
to='user@example.com'<br />
xmlns='jabber:client'><br />
<body>Not much, how about with you?</body><br />
</message><br />
<json:json><br />
[<br />
{<br />
"precision": "zip",<br />
"Latitude": 37.7668,<br />
"Longitude": -122.3959,<br />
"Address": "",<br />
"City": "SAN FRANCISCO",<br />
"State": "CA",<br />
"Zip": "94107",<br />
"Country": "US"<br />
},<br />
{<br />
"precision": "zip",<br />
"Latitude": 37.371991,<br />
"Longitude": -122.026020,<br />
"Address": "",<br />
"City": "SUNNYVALE",<br />
"State": "CA",<br />
"Zip": "94085",<br />
"Country": "US"<br />
}<br />
]<br />
</json:json><br />
</body><br />
<br />
The client MAY poll the connection manager for incoming payloads by sending an empty <body/> element.<br />
<br />
Example 7. Requesting XML Payloads<br />
<br />
POST /webclient HTTP/1.1<br />
Host: httpcm.example.com<br />
Accept-Encoding: gzip, deflate<br />
Content-Type: text/xml; charset=utf-8<br />
Content-Length: 88<br />
<br />
<body rid='1249243563'<br />
sid='SomeSID'<br />
xmlns='http://jabber.org/protocol/httpbind'/><br />
<br />
The connection manager MUST wait and respond in the same way as it does after receiving payloads from the client.<br />
9. Acknowledgements<br />
9.1 Request Acknowledgements<br />
<br />
When responding to a request that it has been holding, if the connection manager finds it has already received another request with a higher 'rid' attribute (typically while it was holding the first request), then it MAY acknowledge the reception to the client. The connection manager MAY set the 'ack' attribute of any response to the value of the highest 'rid' attribute it has received in the case where it has also received all requests with lower 'rid' values.<br />
<br />
Example 8. Response with request acknowledgement<br />
<br />
HTTP/1.1 200 OK<br />
Content-Type: text/xml; charset=utf-8<br />
Content-Length: 64<br />
<br />
<body ack='1249243564'<br />
xmlns='http://jabber.org/protocol/httpbind'/><br />
<br />
If the connection manager will be including 'ack' attributes on responses during a session, then it MUST include an 'ack' attribute in its session creation response, and set the 'ack' attribute of responses throughout the session. The only exception is that, after its session creation response, the connection manager SHOULD NOT include an 'ack' attribute in any response if the value would be the 'rid' of the request being responded to.<br />
<br />
If the connection manager is permitted to hold more than one request at a time, then the reception of a lower-than-expected 'ack' value from the connection manager (or the unexpected abscence of an 'ack' attribute) can give the client an early warning that a network failure might have occurred (e.g., if the client believes the connection manager should have received another request by the time it responded).<br />
9.2 Response Acknowledgements<br />
<br />
The client MAY similarly inform the connection manager about the responses it has received by setting the 'ack' attribute of any request to the value of the highest 'rid' of a request for which it has already received a response in the case where it has also received all responses associated with lower 'rid' values. If the client will be including 'ack' attributes on requests during a session, then it MUST include an 'ack' attribute (set to '1') in its session creation request, and set the 'ack' attribute of requests throughout the session. The only exception is that, after its session creation request, the client SHOULD NOT include an 'ack' attribute in any request if it has received responses to all its previous requests.<br />
<br />
Example 9. Request with response acknowledgement<br />
<br />
POST /webclient HTTP/1.1<br />
Host: httpcm.example.com<br />
Accept-Encoding: gzip, deflate<br />
Content-Type: text/xml; charset=utf-8<br />
Content-Length: 88<br />
<br />
<body rid='1249243566'<br />
sid='SomeSID'<br />
ack='1249243564'<br />
xmlns='http://jabber.org/protocol/httpbind'/><br />
<br />
After receiving a request with an 'ack' value less than the 'rid' of the last request that it has already responded to, the connection manager MAY inform the client of the situation by sending its next response immediately instead of waiting until it has payloads to send to the client (e.g., if some time has passed since it responded). In this case it SHOULD include a 'report' attribute set to one greater than the 'ack' attribute it received from the client, and a 'time' attribute set to the number of milliseconds since it sent the response associated with the 'report' attribute.<br />
<br />
Example 10. Response with report<br />
<br />
HTTP/1.1 200 OK<br />
Content-Type: text/xml; charset=utf-8<br />
Content-Length: 64<br />
<br />
<body report='1249243565'<br />
time='852'<br />
xmlns='http://jabber.org/protocol/httpbind'/><br />
<br />
Upon reception of a response with 'report' and 'time' attributes, if the client has still not received the response associated with the request identifier specified by the 'report' attribute, then it MAY choose to resend the request associated with the missing response (see Broken Connections).<br />
10. Inactivity<br />
<br />
After receiving a response from the connection manager, if none of the client's requests are still being held by the connection manager (and if the session is not a Polling Session), the client SHOULD make a new request as soon as possible. In any case, if no requests are being held, the client MUST make a new request before the maximum inactivity period has expired. The length of this period (in seconds) is specified by the 'inactivity' attribute in the session creation response.<br />
<br />
If the connection manager has responded to all the requests it has received within a session and the time since its last response is longer than the maximum inactivity period, then it SHOULD assume the client has been disconnected and terminate the session without informing the client. If the client subsequently makes another request, then the connection manager SHOULD respond as if the session does not exist.<br />
<br />
If the connection manager did not specify a maximum inactivity period in the session creation response, then it SHOULD allow the client to be inactive for as long as it chooses.<br />
<br />
If the session is not a polling session then the connection manager SHOULD specify a relatively short inactivity period to ensure that disconnections are discovered as quickly as possible. The RECOMMENDED time would be a little more than the number of seconds for a comfortable network round trip between the connection manager and the client under difficult network conditions (since the client can be expected to make a new request immediately -- see above).<br />
<br />
If a client encounters an exceptional temporary situation during which it will be unable to send requests to the connection manager for a period of time greater than the maximum inactivity period (e.g., while a runtime environment changes from one web page to another), and if the connection manager included a 'maxpause' attribute in its Session Creation Response, then the client MAY request a temporary increase to the maximum inactivity period by including a 'pause' attribute in a request. Note: If the connection manager did not specify a 'maxpause' attribute at the start of the session then the client MUST NOT send a 'pause' attribute during the session.<br />
<br />
Example 11. Requesting a Session Pause<br />
<br />
POST /webclient HTTP/1.1<br />
Host: httpcm.example.com<br />
Accept-Encoding: gzip, deflate<br />
Content-Type: text/xml; charset=utf-8<br />
Content-Length: 98<br />
<br />
<body rid='1249243564'<br />
sid='SomeSID'<br />
pause='60'<br />
xmlns='http://jabber.org/protocol/httpbind'/><br />
<br />
Upon reception of a session pause request, if the requested period is not greater than the maximum permitted time, then the connection manager SHOULD respond immediately to all pending requests (including the pause request) and temporarily increase the maximum inactivity period to the requested time. Note: The response to the pause request MUST NOT contain any payloads.<br />
<br />
Note: If the client simply wants the connection manager to return all the requests it is holding then it MAY set the value of the 'pause' attribute to be the value of the 'inactivity' attribute in the connection manager's session creation response. (If the client believes it is in danger of becoming disconnected indefinitely then it MAY even request a temporary reduction of the maximum inactivity period by specifying a 'pause' value less than the 'inactivity' value, thus enabling the connection manager to discover any subsequent disconnection more quickly.)<br />
<br />
The connection manager SHOULD set the maximum inactivity period back to normal upon reception of the next request from the client (assuming the connection manager has not already terminated the session).<br />
11. Overactivity<br />
<br />
The client SHOULD NOT make more simultaneous requests than specified by the 'requests' attribute in the connection manager's Session Creation Response. However the client MAY make one additional request if it is to pause or terminate a session.<br />
<br />
If during any period the client sends a sequence of new requests (i.e. requests with incremented rid attributes, not repeat requests) longer than the number specified by the 'requests' attribute, and if the connection manager has not yet responded to any of the requests, and if the last request did not include either a 'pause' attribute or a 'type' attribute set to "terminate", then the connection manager SHOULD consider that the client is making too many simultaneous requests, and terminate the HTTP session with a 'policy-violation' terminal binding error to the client. Note: This behavior applies to equally to normal and polling sessions.<br />
<br />
Example 12. Too many simultaneous requests response<br />
<br />
HTTP/1.1 200 OK<br />
Content-Type: text/xml; charset=utf-8<br />
Content-Length: 68<br />
<br />
<body type='terminate'<br />
condition='policy-violation'<br />
xmlns='http://jabber.org/protocol/httpbind'/><br />
<br />
Note: If the connection manager did not specify a 'requests' attribute in the session creation response, then it MUST allow the client to send as many simultaneous requests as it chooses.<br />
<br />
If during any period the client sends a sequence of new requests equal in length to the number specified by the 'requests' attribute, and if the connection manager has not yet responded to any of the requests, and if the last request was empty and did not include either a 'pause' attribute or a 'type' attribute set to "terminate", and if the last two requests arrived within a period shorter than the number of seconds specified by the 'polling' attribute in the session creation response, then the connection manager SHOULD consider that the client is making requests more frequently than it was permitted and terminate the HTTP session and return a 'policy-violation' terminal binding error to the client. Note: the behavior for Polling Sessions is slightly different.<br />
<br />
Example 13. Too frequent requests response<br />
<br />
HTTP/1.1 200 OK<br />
Content-Type: text/xml; charset=utf-8<br />
Content-Length: 68<br />
<br />
<body type='terminate'<br />
condition='policy-violation'<br />
xmlns='http://jabber.org/protocol/httpbind'/><br />
<br />
Note: If the connection manager did not specify a 'polling' attribute in the session creation response, then it MUST allow the client to send requests as frequently as it chooses.<br />
12. Polling Sessions<br />
<br />
It is not always possible for a constrained client to either use HTTP Pipelining or open more than one HTTP connection with the connection manager at a time. In this case the client SHOULD inform the connection manager by setting the values of the 'wait' and/or 'hold' attributes in its session creation request to "0", and then "poll" the connection manager at regular intervals throughout the session for payloads it might have received from the server. Note: Even if the client does not request a polling session, the connection manager MAY require a client to use polling by setting the 'requests' attribute (which specifies the number of simultaneous requests the client can make) of its Session Creation Response to "1", however this is NOT RECOMMENDED.<br />
<br />
If a session will use polling, the connection manager SHOULD specify a higher than normal value for the 'inactivity' attribute (see Inactivity) in its session creation response. The increase SHOULD be greater than the value it specifies for the 'polling' attribute.<br />
<br />
If the client sends two consecutive empty new requests (i.e. requests with incremented rid attributes, not repeat requests) within a period shorter than the number of seconds specified by the 'polling' attribute (the shortest allowable polling interval) in the session creation response, and if the connection manager's response to the first request contained no payloads, then upon reception of the second request the connection manager SHOULD terminate the HTTP session and return a 'policy-violation' terminal binding error to the client.<br />
<br />
Example 14. Too frequent polling response<br />
<br />
HTTP/1.1 200 OK<br />
Content-Type: text/xml; charset=utf-8<br />
Content-Length: 68<br />
<br />
<body type='terminate'<br />
condition='policy-violation'<br />
xmlns='http://jabber.org/protocol/httpbind'/><br />
<br />
Note: If the connection manager did not specify a 'polling' attribute in the session creation response, then it MUST allow the client to poll as frequently as it chooses.<br />
13. Terminating the HTTP Session<br />
<br />
At any time, the client MAY gracefully terminate the session by sending a <body/> element with a 'type' attribute set to "terminate". The termination request MAY include one or more payloads that the connection manager MUST forward to the server to ensure graceful logoff.<br />
<br />
Example 15. Session termination by client<br />
<br />
POST /webclient HTTP/1.1<br />
Host: httpcm.example.com<br />
Accept-Encoding: gzip, deflate<br />
Content-Type: text/xml; charset=utf-8<br />
Content-Length: 153<br />
<br />
<body rid='1249243565'<br />
sid='SomeSID'<br />
type='terminate'<br />
xmlns='http://jabber.org/protocol/httpbind'><br />
<presence type='unavailable'<br />
xmlns='jabber:client'/><br />
</body><br />
<br />
The connection manager SHOULD respond to this request with an HTTP 200 OK containing an empty <body/> element.<br />
<br />
Example 16. Connection manager acknowledges termination<br />
<br />
HTTP/1.1 200 OK<br />
Content-Type: text/xml; charset=utf-8<br />
Content-Length: 72<br />
<br />
<body type='terminate'<br />
xmlns='http://jabber.org/protocol/httpbind'/><br />
<br />
Upon receiving the response, the client MUST consider the HTTP session to have been terminated.<br />
14. Request IDs<br />
14.1 Generation<br />
<br />
The client MUST generate a large, random, positive integer for the initial 'rid' (see Security Considerations) and then increment that value by one for each subsequent request. The client MUST take care to choose an initial 'rid' that will never be incremented above 9007199254740991 [21] within the session. In practice, a session would have to be extraordinarily long (or involve the exchange of an extraordinary number of packets) to exceed the defined limit.<br />
14.2 In-Order Message Forwarding<br />
<br />
When a client makes simultaneous requests, the connection manager might receive them out of order. The connection manager MUST forward the payloads to the server and respond to the client requests in the order specified by the 'rid' attributes. The client MUST process responses received from the connection manager in the order the requests were made.<br />
<br />
The connection manager SHOULD expect the 'rid' attribute to be within a window of values greater than the 'rid' of the previous request. The size of the window is equal to the maximum number of simultaneous requests allowed by the connection manager. If it receives a request with a 'rid' greater than the values in the window, then the connection manager MUST terminate the session with an error:<br />
<br />
Example 17. Unexpected rid error<br />
<br />
HTTP/1.1 200 OK<br />
Content-Type: text/xml; charset=utf-8<br />
Content-Length: 68<br />
<br />
<body type='terminate'<br />
condition='item-not-found'<br />
xmlns='http://jabber.org/protocol/httpbind'/><br />
<br />
14.3 Broken Connections<br />
<br />
Unreliable network communications or client constraints can result in broken connections. The connection manager SHOULD remember the 'rid' and the associated HTTP response body of the client's most recent requests which were not session pause requests (see Inactivity) and which did not result in an HTTP or binding error. The number of responses to non-pause requests kept in the buffer SHOULD be either the same as the maximum number of simultaneous requests allowed by the connection manager or, if Acknowledgements are being used, the number of responses that have not yet been acknowledged.<br />
<br />
If the network connection is broken or closed before the client receives a response to a request from the connection manager, then the client MAY resend an exact copy of the original request. Whenever the connection manager receives a request with a 'rid' that it has already received, it SHOULD return an HTTP 200 (OK) response that includes the buffered copy of the original XML response to the client (i.e., a <body/> wrapper possessing appropriate attributes and optionally containing one or more XML payloads). If the original response is not available (e.g., it is no longer in the buffer), then the connection manager MUST return an 'item-not-found' terminal binding error:<br />
<br />
Example 18. Response not in buffer error<br />
<br />
HTTP/1.1 200 OK<br />
Content-Type: text/xml; charset=utf-8<br />
Content-Length: 68<br />
<br />
<body type='terminate'<br />
condition='item-not-found'<br />
xmlns='http://jabber.org/protocol/httpbind'/><br />
<br />
Note: The error is the same whether the 'rid' is too large or too small. This makes it more difficult for an attacker to discover an acceptable value.<br />
15. Protecting Insecure Sessions<br />
15.1 Applicability<br />
<br />
The OPTIONAL key sequencing mechanism described here MAY be used if the client's session with the connection manager is not secure. The session SHOULD be considered secure only if all client requests are made via SSL (or TLS) HTTP connections and the connection manager generates an unpredictable session ID. If the session is secure, it is not necessary to use this key sequencing mechanism.<br />
<br />
Even if the session is not secure, the unpredictable session and request IDs specified in the preceding sections of this document already provide a level of protection similar to that provided by a connection bound to a single pair of persistent TCP/IP connections, and thus provide sufficient protection against a 'blind' attacker. However, in some circumstances, the key sequencing mechanism defined below helps to protect against a more determined and knowledgeable attacker.<br />
<br />
It is important to recognize that the key sequencing mechanism defined below helps to protect only against an attacker who is able to view the contents of all requests or responses in an insecure session but who is not able to alter the contents of those requests (in this case, the mechanism prevents the attacker from injecting HTTP requests into the session, e.g., termination requests or responses). However, the key sequencing mechanism does not provide any protection when the attacker is able to alter the contents of insecure requests or responses.<br />
15.2 Introduction<br />
<br />
The HTTP requests of each session MAY be spread across a series of different socket connections. This would enable an unauthorized user that obtains the session ID and request ID of a session to then use their own socket connection to inject <body/> request elements into the session and receive the corresponding responses.<br />
<br />
The key sequencing mechanism below protects against such attacks by enabling a connection manager to detect <body/> request elements injected by a third party.<br />
15.3 Generating the Key Sequence<br />
<br />
Prior to requesting a new session, the client MUST select an unpredictable counter ("n") and an unpredictable value ("seed"). The client then processes the "seed" through a cryptographic hash and converts the resulting 160 bits to a hexadecimal string K(1). It does this "n" times to arrive at the initial key K(n). The hashing algorithm MUST be SHA-1 as defined in RFC 3174 [22].<br />
<br />
Example 19. Creating the key sequence<br />
<br />
K(1) = hex(SHA-1(seed))<br />
K(2) = hex(SHA-1(K(1)))<br />
...<br />
K(n) = hex(SHA-1(K(n-1)))<br />
<br />
<br />
15.4 Use of Keys<br />
<br />
The client MUST set the 'newkey' attribute of the first request in the session to the value K(n).<br />
<br />
Example 20. Session Request with Initial Key<br />
<br />
POST /webclient HTTP/1.1<br />
Host: httpcm.example.com<br />
Accept-Encoding: gzip, deflate<br />
Content-Type: text/xml; charset=utf-8<br />
Content-Length: 104<br />
<br />
<body content='text/xml; charset=utf-8'<br />
hold='1'<br />
rid='1573741820'<br />
to='example.com'<br />
wait='60'<br />
xml:lang='en'<br />
newkey='ca393b51b682f61f98e7877d61146407f3d0a770'<br />
xmlns='http://jabber.org/protocol/httpbind'/><br />
<br />
The client MUST set the 'key' attribute of all subsequent requests to the value of the next key in the generated sequence (decrementing from K(n-1) towards K(1) with each request sent).<br />
<br />
Example 21. Request with Key<br />
<br />
POST /webclient HTTP/1.1<br />
Host: httpcm.example.com<br />
Accept-Encoding: gzip, deflate<br />
Content-Type: text/xml; charset=utf-8<br />
Content-Length: 88<br />
<br />
<body rid='1573741821'<br />
sid='SomeSID'<br />
key='bfb06a6f113cd6fd3838ab9d300fdb4fe3da2f7d'<br />
xmlns='http://jabber.org/protocol/httpbind'/><br />
<br />
The connection manager MAY verify the key by calculating the SHA-1 hash of the key and comparing it to the 'newkey' attribute of the previous request (or the 'key' attribute if the 'newkey' attribute was not set). If the values do not match (or if it receives a request without a 'key' attribute and the 'newkey' or 'key' attribute of the previous request was set), then the connection manager MUST NOT process the element, MUST terminate the session, and MUST return an 'item-not-found' terminal binding error.<br />
<br />
Example 22. Invalid Key Sequence Error<br />
<br />
HTTP/1.1 200 OK<br />
Content-Type: text/xml; charset=utf-8<br />
Content-Length: 68<br />
<br />
<body type='terminate'<br />
condition='item-not-found'<br />
xmlns='http://jabber.org/protocol/httpbind'/><br />
<br />
15.5 Switching to Another Key Sequence<br />
<br />
A client SHOULD choose a high value for "n" when generating the key sequence. However, if the session lasts long enough that the client arrives at the last key in the sequence K(1) then the client MUST switch to a new key sequence.<br />
<br />
The client MUST:<br />
<br />
1. Choose new values for "seed" and "n".<br />
2. Generate a new key sequence using the algorithm defined above.<br />
3. Set the 'key' attribute of the request to the next value in the old sequence (i.e. K(1), the last value).<br />
4. Set the 'newkey' attribute of the request to the value K(n) from the new sequence.<br />
<br />
Example 23. New Key Sequence<br />
<br />
POST /webclient HTTP/1.1<br />
Host: httpcm.example.com<br />
Accept-Encoding: gzip, deflate<br />
Content-Type: text/xml; charset=utf-8<br />
Content-Length: 188<br />
<br />
<body rid='1573741822'<br />
sid='SomeSID'<br />
key='6f825e81f4532b2c5fa2d12457d8a1f22e8f838e'<br />
newkey='113f58a37245ec9637266cf2fb6e48bfeaf7964e'<br />
xmlns='http://jabber.org/protocol/httpbind'><br />
<message to='contact@example.com'<br />
xmlns='jabber:client'><br />
<body>I said "Hi!"</body><br />
</message><br />
</body><br />
<br />
16. Multiple Streams<br />
16.1 Introduction<br />
<br />
The OPTIONAL feature described in this section enables multiple XML streams to be contained within a single HTTP session. This feature is essential in runtime environments that prevent HTTP Pipelining, thereby constraining the number of simultaneous HTTP requests a client can make to each connection manager, since clients running in such environments need multi-stream sessions if they are to connect using more than one account at the same time. This feature also reduces network traffic for any client that needs to establish parallel streams over HTTP.<br />
16.2 Discovery<br />
<br />
If a connection manager supports the multi-streams feature, it MUST include a 'stream' attribute in its Session Creation Response. If a client does not receive the 'stream' attribute then it MUST assume that the connection manager does not support the feature. [23]<br />
<br />
The 'stream' attribute identifies the first stream to be opened for the session. The value of each 'stream' attribute MUST be an opaque and unpredictable name that is unique within the context of the connection manager application.<br />
<br />
Example 24. Session creation response with stream name<br />
<br />
HTTP/1.1 200 OK<br />
Content-Type: text/xml; charset=utf-8<br />
Content-Length: 128<br />
<br />
<body wait='60'<br />
inactivity='30'<br />
polling='5'<br />
requests='2'<br />
hold='1'<br />
accept='deflate,gzip'<br />
stream='firstStreamName'<br />
maxpause='120'<br />
sid='SomeSID'<br />
charsets='ISO_8859-1 ISO-2022-JP'<br />
ver='1.6'<br />
from='example.com'<br />
xmlns='http://jabber.org/protocol/httpbind'/><br />
<br />
16.3 Adding Streams To A Session<br />
<br />
If the connection manager included a 'stream' attribute in its session creation response then the client MAY ask it to open another stream at any time by sending it an empty <body/> element with a 'to' attribute. The request MUST include valid 'sid' and 'rid' [24] attributes, and SHOULD also include an 'xml:lang' attribute. The request MAY include 'route', 'from' and 'secure' attributes (see Session Creation Request), but it SHOULD NOT include 'ver', 'content', 'hold' or 'wait' attributes (since a new session is not being created).<br />
<br />
Example 25. Requesting another stream<br />
<br />
POST /webclient HTTP/1.1<br />
Host: httpcm.example.com<br />
Accept-Encoding: gzip, deflate<br />
Content-Type: text/xml; charset=utf-8<br />
Content-Length: 104<br />
<br />
<body sid='SomeSID'<br />
rid='1573741820'<br />
to='example.com'<br />
route='xmpp:example.com:9999'<br />
xml:lang='en'<br />
xmlns='http://jabber.org/protocol/httpbind'/><br />
<br />
If the connection manager did not indicate its support for multiple streams at the start of the session, then it MUST ignore the extra attributes and treat the request as a normal empty request for payloads (see Sending and Receiving XML Payloads). [25] Otherwise it MUST open a new stream with the specified server (see Session Creation Response), generate a new stream name, and respond to the client with the name. The response MAY also include 'from' and 'secure' attributes, but it SHOULD NOT include 'sid', 'requests', 'polling', 'hold', 'inactivity', 'maxpause', 'accept', 'charsets', 'ver' or 'wait' attributes.<br />
<br />
Example 26. Add stream response<br />
<br />
HTTP/1.1 200 OK<br />
Content-Type: text/xml; charset=utf-8<br />
Content-Length: 128<br />
<br />
<body stream='secondStreamName'<br />
from='example.com'<br />
xmlns='http://jabber.org/protocol/httpbind'/><br />
<br />
Note: If the response did not include either 'from' or 'secure' attributes then they MAY be sent in a subsequent response instead (see Session Creation Response). In that case the 'stream' attribute MUST also be specified.<br />
16.4 Transmitting Payloads<br />
<br />
If more than one stream has been opened within a session, then all non-empty <body/> elements sent by the connection manager MUST include a 'stream' attribute that specifies which stream all the payloads it contains belong to. The client SHOULD include a 'stream' attribute for the same purpose. The client MAY omit the 'stream' attribute if it wants the connection manager to broadcast the payloads over all open streams. Note: A <body/> element MUST NOT contain different payloads for different streams.<br />
<br />
If a stream name does not correspond to one of the session's open streams, then the receiving connection manager SHOULD return an 'item-not-found' terminal binding error, or the receiving client SHOULD terminate the session. However, if the receiving entity has only just closed the stream (and the sender might not have been aware of that when it sent the payloads), then it MAY instead simply silently ignore any payloads the <body/> element contains.<br />
<br />
Note: Empty <body/> elements that do not include a 'from' or 'secure' attribute SHOULD NOT include a 'stream' attribute (since nothing is being transmitted for any stream). If such a <body/> element does include a 'stream' attribute then the receiving entity SHOULD ignore the attribute.<br />
<br />
Example 27. Client sends payload with a stream name<br />
<br />
POST /webclient HTTP/1.1<br />
Host: httpcm.example.com<br />
Accept-Encoding: gzip, deflate<br />
Content-Type: text/xml; charset=utf-8<br />
Content-Length: 188<br />
<br />
<body rid='1249243562'<br />
sid='SomeSID'<br />
stream='secondStreamName'<br />
xmlns='http://jabber.org/protocol/httpbind'><br />
<message to='contact@example.com'<br />
xmlns='jabber:client'><br />
<body>I said hello.</body><br />
</message><br />
</body><br />
<br />
Note: The value of the 'stream' attribute of the response MAY be different than the corresponding request. [26]<br />
<br />
Example 28. Connection manager responds with a different stream name<br />
<br />
HTTP/1.1 200 OK<br />
Content-Type: text/xml; charset=utf-8<br />
Content-Length: 185<br />
<br />
<body stream='firstStreamName'<br />
xmlns='http://jabber.org/protocol/httpbind'><br />
<message from='contact@example.com'<br />
to='user@example.com'<br />
xmlns='jabber:client'><br />
<body>Hi yourself!</body><br />
</message><br />
</body><br />
<br />
If no stream name is specified by the connection manager then the client MUST assume the payloads are associated with the first stream (even if the first stream has been closed).<br />
<br />
If no stream name is specified by the client then the connection manager MUST broadcast the payloads over all open streams. [27]<br />
<br />
Example 29. Client asks for a payload to be broadcast<br />
<br />
POST /webclient HTTP/1.1<br />
Host: httpcm.example.com<br />
Accept-Encoding: gzip, deflate<br />
Content-Type: text/xml; charset=utf-8<br />
Content-Length: 188<br />
<br />
<body rid='1249243562'<br />
sid='SomeSID'<br />
xmlns='http://jabber.org/protocol/httpbind'><br />
<presence xmlns='jabber:client'><br />
<show>away</show><br />
</presence><br />
</body><br />
<br />
16.5 Closing a Stream<br />
<br />
If more than one stream is open within a session, the client MAY close one open stream at any time using the procedure described in the section Terminating the HTTP Session above, taking care to specify the stream name with a 'stream' attribute. If the client closes the last stream the connection manager MUST terminate the session. If the client does not specify a stream name then the connection manager MUST close all open streams (sending any payloads the terminate request contains to all streams), and terminate the session.<br />
<br />
Example 30. Client closes one stream<br />
<br />
POST /webclient HTTP/1.1<br />
Host: httpcm.example.com<br />
Accept-Encoding: gzip, deflate<br />
Content-Type: text/xml; charset=utf-8<br />
Content-Length: 153<br />
<br />
<body rid='1249243564'<br />
sid='SomeSID'<br />
stream='secondStreamName'<br />
type='terminate'<br />
xmlns='http://jabber.org/protocol/httpbind'><br />
<presence type='unavailable'<br />
xmlns='jabber:client'/><br />
</body><br />
<br />
16.6 Error Conditions<br />
<br />
If more than one stream is open within a session, the connection manager MAY include a 'stream' attribute in a fatal binding error (see Terminal Binding Conditions). If a 'stream' attribute is specified then the stream MUST be closed by both entities but the session SHOULD NOT be terminated.<br />
<br />
Example 31. Fatal stream error<br />
<br />
HTTP/1.1 200 OK<br />
Content-Type: text/xml; charset=utf-8<br />
Content-Length: 68<br />
<br />
<body type='terminate'<br />
condition='remote-connection-failed'<br />
stream='secondStreamName'<br />
xmlns='http://jabber.org/protocol/httpbind'/><br />
<br />
Note: If the connection manager does not include a 'stream' attribute in a fatal binding error then all the session's open streams MUST be closed by both entities and the session MUST be terminated.<br />
17. Error and Status Codes<br />
<br />
There are four types of error and status reporting in HTTP responses:<br />
<br />
Table 1: Error Condition Types<br />
Condition Type Description<br />
HTTP Conditions (Deprecated) The connection manager responds to an invalid request from a legacy client with a standard HTTP error. These are used for binding syntax errors, possible attacks, etc. Note that constrained clients are unable to differentiate between HTTP errors.<br />
Terminal Binding Conditions These error conditions can be read by constrained clients. They are used for connection manager problems, abstracting stream errors, communication problems between the connection manager and the server, and invalid client requests (binding syntax errors, possible attacks, etc.)<br />
Recoverable Binding Conditions These report communication problems between the connection manager and the client. They do not terminate the session. Clients recover from these errors by resending all the preceding <body/> wrappers that have not received responses.<br />
Transported Protocol Conditions Errors relating to the XML payloads within <body/> wrappers are, in general, defined in the documentation of the protocol being transported. They do not terminate the session.<br />
<br />
Full descriptions are provided below.<br />
17.1 HTTP Conditions<br />
<br />
Note: All HTTP codes except 200 have been superseded by Terminal Binding Conditions to allow clients to determine whether the source of errors is the connection manager application or an HTTP intermediary.<br />
<br />
A legacy client (or connection manager) is a client (or connection manager) that did not include a 'ver' attribute in its session creation request (or response). A legacy client (or connection manager) will interpret (or respond with) HTTP error codes according to the table below. Non-legacy connection managers SHOULD NOT send HTTP error codes unless they are communicating with a legacy client. Upon receiving an HTTP error (400, 403, 404), a legacy client or any client that is communicating with a legacy connection manager MUST consider the HTTP session to be null and void. A non-legacy client that is communicating with a non-legacy connection manager MAY consider that the session is still active.<br />
<br />
Table 2: HTTP Error and Status Codes<br />
Code Name Superseded by Purpose<br />
200 OK - Response to valid client request.<br />
400 Bad Request bad-request Inform client that the format of an HTTP header or binding element is unacceptable (e.g., syntax error).<br />
403 Forbidden policy-violation Inform client that it has broken the session rules (polling too frequently, requesting too frequently, too many simultaneous requests).<br />
404 Not Found item-not-found Inform client that (1) 'sid' is not valid, (2) 'stream' is not valid, (3) 'rid' is larger than the upper limit of the expected window, (4) connection manager is unable to resend response, (5) 'key' sequence is invalid.<br />
<br />
Note: No other HTTP error and status codes were defined in the early versions of BOSH (e.g., Internal Server Error).<br />
17.2 Terminal Binding Conditions<br />
<br />
In any response it sends to the client, the connection manager MAY return a fatal error by setting a 'type' attribute of the <body/> element to "terminate". These binding errors imply that the HTTP session is terminated (unless a 'stream' attribute is specified -- see Multiple Stream Error Conditions).<br />
<br />
Note: Although many of these conditions are similar to the XMPP stream error conditions specified in RFC 6120, they are not to be confused with XMPP stream errors. In cases where BOSH is being used to transport XMPP, any fatal XMPP stream error conditions experienced between the connection manager and the XMPP server SHOULD only be reported using the "remote-stream-error" condition as described below.<br />
<br />
Example 32. Remote connection failed error<br />
<br />
HTTP/1.1 200 OK<br />
Content-Type: text/xml; charset=utf-8<br />
Content-Length: 68<br />
<br />
<body type='terminate'<br />
condition='remote-connection-failed'<br />
xmlns='http://jabber.org/protocol/httpbind'/><br />
<br />
The following values of the 'condition' attribute are defined:<br />
<br />
Table 3: Terminal Binding Error Conditions<br />
Condition Purpose<br />
bad-request* The format of an HTTP header or binding element received from the client is unacceptable (e.g., syntax error).<br />
host-gone The target domain specified in the 'to' attribute or the target host or port specified in the 'route' attribute is no longer serviced by the connection manager.<br />
host-unknown The target domain specified in the 'to' attribute or the target host or port specified in the 'route' attribute is unknown to the connection manager.<br />
improper-addressing The initialization element lacks a 'to' or 'route' attribute (or the attribute has no value) but the connection manager requires one.<br />
internal-server-error The connection manager has experienced an internal error that prevents it from servicing the request.<br />
item-not-found* (1) 'sid' is not valid, (2) 'stream' is not valid, (3) 'rid' is larger than the upper limit of the expected window, (4) connection manager is unable to resend response, (5) 'key' sequence is invalid.<br />
other-request Another request being processed at the same time as this request caused the session to terminate.<br />
policy-violation* The client has broken the session rules (polling too frequently, requesting too frequently, sending too many simultaneous requests).<br />
remote-connection-failed The connection manager was unable to connect to, or unable to connect securely to, or has lost its connection to, the server.<br />
remote-stream-error Encapsulates an error in the protocol being transported.<br />
see-other-uri The connection manager does not operate at this URI (e.g., the connection manager accepts only SSL or TLS connections at some https: URI rather than the http: URI requested by the client). The client can try POSTing to the URI in the content of the <uri/> child element.<br />
system-shutdown The connection manager is being shut down. All active HTTP sessions are being terminated. No new sessions can be created.<br />
undefined-condition The error is not one of those defined herein; the connection manager SHOULD include application-specific information in the content of the <body/> wrapper.<br />
<br />
* If the client did not include a 'ver' attribute in its session creation request then the connection manager SHOULD send a deprecated HTTP Error Condition instead of this terminal binding condition. If the connection manager did not include a 'ver' attribute in its session creation response then the client SHOULD expect it to send a deprecated HTTP Error Condition instead of this terminal binding condition.<br />
<br />
The following is an example of a "see-other-uri" condition:<br />
<br />
Example 33. See other URI error<br />
<br />
HTTP/1.1 200 OK<br />
Content-Type: text/xml; charset=utf-8<br />
Content-Length: 68<br />
<br />
<body condition='see-other-uri'<br />
type='terminate'<br />
xmlns='http://jabber.org/protocol/httpbind'><br />
<uri>https://secure.jabber.org/xmppcm</uri><br />
</body><br />
<br />
The following is an example including a "remote-stream-error" condition:<br />
<br />
Example 34. Remote error<br />
<br />
HTTP/1.1 200 OK<br />
Content-Type: text/xml; charset=utf-8<br />
Content-Length: 68<br />
<br />
<body condition='remote-stream-error'<br />
type='terminate'<br />
xmlns='http://jabber.org/protocol/httpbind'<br />
xmlns:stream='http://etherx.jabber.org/streams'><br />
<message from='contact@example.com'<br />
to='user@example.com'<br />
xmlns='jabber:client'><br />
<body>I said "Hi!"</body><br />
</message><br />
<stream:error><br />
<xml-not-well-formed xmlns='urn:ietf:params:xml:ns:xmpp-streams'/><br />
<text xmlns='urn:ietf:params:xml:ns:xmpp-streams'<br />
xml:lang='en'><br />
Some special application diagnostic information!<br />
</text><br />
<escape-your-data xmlns='application-ns'/><br />
</stream:error><br />
</body><br />
<br />
Naturally, the client MAY report binding errors to the connection manager as well, although this is unlikely.<br />
17.3 Recoverable Binding Conditions<br />
<br />
In any response it sends to the client, the connection manager MAY return a recoverable error by setting a 'type' attribute of the <body/> element to "error". These errors do not imply that the HTTP session is terminated.<br />
<br />
If it decides to recover from the error, then the client MUST repeat the HTTP request that resulted in the error, as well as all the preceding HTTP requests that have not received responses. The content of these requests MUST be identical to the <body/> elements of the original requests. This enables the connection manager to recover a session after the previous request was lost due to a communication failure.<br />
<br />
Example 35. Recoverable error<br />
<br />
HTTP/1.1 200 OK<br />
Content-Type: text/xml; charset=utf-8<br />
Content-Length: 68<br />
<br />
<body type='error'<br />
xmlns='http://jabber.org/protocol/httpbind'/><br />
<br />
17.4 XML Payload Conditions<br />
<br />
Application-level error conditions described in the documentation of the protocol being transported are routed to the client through the connection manager. They are transparent to the connection manager, and therefore out of scope for the transport binding defined herein.<br />
18. Implementation Notes<br />
18.1 HTTP Pipelining<br />
<br />
Even if the client requests HTTP Pipelining and the connection manager supports it, there is no guarantee that pipelining will succeed, because it might not be supported by intermediate proxies.<br />
<br />
The best the client can do is to request the use of HTTP Pipelining by setting the 'hold' attribute to a value of "1". If HTTP Pipelining does not work (because the server returns HTTP 1.0 or connection:close), then the client SHOULD degrade gracefully by using multiple connections.<br />
19. Security Considerations<br />
19.1 Connection Between Client and BOSH Service<br />
<br />
All communications between a client and a BOSH service SHOULD occur over encrypted HTTP connections. Negotiation of encryption between the client and the connection manager SHOULD occur at the transport layer or the HTTP layer, not the application layer; such negotiation SHOULD follow the HTTP/SSL protocol defined in SSL [28], although MAY follow the HTTP/TLS protocol defined in RFC 2818 [29] or the TLS Within HTTP protocol defined in RFC 2817 [30].<br />
<br />
If the HTTP connection used to send the initial session request is encrypted, then all the other HTTP connections used within the session MUST also be encrypted. Furthermore, if authentication certificates are exchanged when establishing the encrypted connection that is used to send the initial session request, then the client and/or connection manager SHOULD ensure that the same authentication certificates are employed for all subsequent connections used by the session. Once such a "secure session" has been established:<br />
<br />
* If the connection manager refuses to establish an encrypted connection or offers a different certificate, then the client SHOULD close the connection and terminate the session without sending any more requests.<br />
* If the client sends a wrapper element that is part of a "secure session" over a connection that either is not encrypted or uses a different certificate, then the connection manager SHOULD simply close the connection. The connection manager SHOULD NOT terminate the session since that would facilitate denial of service attacks.<br />
<br />
19.2 Connection Between BOSH Service and Application<br />
<br />
A BOSH service SHOULD encrypt its connection to the backend application using appropriate technologies such as Secure Sockets Layer (SSL), Transport Layer Security (TLS), and StartTLS if supported by the backend application. Alternatively, the BOSH service can be considered secure (1) if it is running on the same physical machine as the backend application or (2) if it running on the same private network as the backend application and the administrators are sure that unknown individuals or processes do not have access to that private network.<br />
<br />
If data privacy is desired, the client SHOULD encrypt its messages using an application-specific end-to-end encryption technology, because there is no way for the client to be sure that the BOSH service encrypts its connection to the application; methods for doing so are outside the scope of this specification.<br />
19.3 Unpredictable SID and RID<br />
<br />
The session identifier (SID) and initial request identifier (RID) are security-critical and therefore MUST be both unpredictable and nonrepeating (see RFC 1750 [31] for recommendations regarding randomness of SIDs and initial RIDs for security purposes).<br />
19.4 Use of SHA-1<br />
<br />
Recent research has shown that in select cases it is possible to compromise the hashes produced by the SHA-1 hashing algorithm (see RFC 4270 [32]). However, the use to which SHA-1 is put in BOSH will likely minimize the applicability of the attacks described in the literature. Furthermore, current estimates suggest that even with the recently-discovered attack, it would still take one year of computing by a government-sized entity to produce a collision.<br />
20. IANA Considerations<br />
<br />
TCP port 5280, conventially used for communication between BOSH clients and BOSH connection mangers, is registered with the Internet Assigned Numbers Authority (IANA) [33] in its port registry at IANA Port Numbers Registry [34], with a keyword of "xmpp-bosh". (Although use of this port is OPTIONAL, it is helpful to define this port in a standardized way so that BOSH clients can contact any given XMPP service via BOSH without the need either for DNS TXT records as described in Discovering Alternative XMPP Connection Methods [35] or for more advanced methods such as U-NAPTR.<br />
21. XMPP Registrar Considerations<br />
21.1 Protocol Namespaces<br />
<br />
The XMPP Registrar includes 'http://jabber.org/protocol/httpbind' in its registry of protocol namespaces.<br />
22. XML Schema<br />
<br />
<?xml version='1.0' encoding='UTF-8'?><br />
<br />
<xs:schema<br />
xmlns:xs='http://www.w3.org/2001/XMLSchema'<br />
xmlns:stream='http://etherx.jabber.org/streams'<br />
targetNamespace='http://jabber.org/protocol/httpbind'<br />
xmlns='http://jabber.org/protocol/httpbind'<br />
elementFormDefault='qualified'><br />
<br />
<xs:annotation><br />
<xs:documentation><br />
The protocol documented by this schema is defined in<br />
XEP-0124: http://www.xmpp.org/extensions/xep-0124.html<br />
</xs:documentation><br />
</xs:annotation><br />
<br />
<xs:import namespace='http://www.w3.org/XML/1998/namespace'<br />
schemaLocation='http://www.w3.org/2001/03/xml.xsd'/><br />
<br />
<xs:element name='body'><br />
<xs:complexType><br />
<xs:choice><br />
<xs:element name='uri'<br />
minOccurs='0'<br />
maxOccurs='1'<br />
type='xs:string'/><br />
<xs:any namespace='##other'<br />
minOccurs='0'<br />
maxOccurs='unbounded'<br />
processContents='lax'/><br />
</xs:choice><br />
<xs:attribute name='accept' type='xs:string' use='optional'/><br />
<xs:attribute name='ack' type='xs:positiveInteger' use='optional'/><br />
<xs:attribute name='authid' type='xs:string' use='optional'/><br />
<xs:attribute name='charsets' type='xs:NMTOKENS' use='optional'/><br />
<xs:attribute name='condition' use='optional'><br />
<xs:simpleType><br />
<xs:restriction base='xs:NCName'><br />
<xs:enumeration value='bad-request'/><br />
<xs:enumeration value='host-gone'/><br />
<xs:enumeration value='host-unknown'/><br />
<xs:enumeration value='improper-addressing'/><br />
<xs:enumeration value='internal-server-error'/><br />
<xs:enumeration value='item-not-found'/><br />
<xs:enumeration value='other-request'/><br />
<xs:enumeration value='policy-violation'/><br />
<xs:enumeration value='remote-connection-failed'/><br />
<xs:enumeration value='remote-stream-error'/><br />
<xs:enumeration value='see-other-uri'/><br />
<xs:enumeration value='system-shutdown'/><br />
<xs:enumeration value='undefined-condition'/><br />
</xs:restriction><br />
</xs:simpleType><br />
</xs:attribute><br />
<xs:attribute name='content' type='xs:string' use='optional'/><br />
<xs:attribute name='from' type='xs:string' use='optional'/><br />
<xs:attribute name='hold' type='xs:unsignedByte' use='optional'/><br />
<xs:attribute name='inactivity' type='xs:unsignedShort' use='optional'/><br />
<xs:attribute name='key' type='xs:string' use='optional'/><br />
<xs:attribute name='maxpause' type='xs:unsignedShort' use='optional'/><br />
<xs:attribute name='newkey' type='xs:string' use='optional'/><br />
<xs:attribute name='pause' type='xs:unsignedShort' use='optional'/><br />
<xs:attribute name='polling' type='xs:unsignedShort' use='optional'/><br />
<xs:attribute name='report' type='xs:positiveInteger' use='optional'/><br />
<xs:attribute name='requests' type='xs:unsignedByte' use='optional'/><br />
<xs:attribute name='rid' type='xs:positiveInteger' use='optional'/><br />
<xs:attribute name='route' type='xs:string' use='optional'/><br />
<xs:attribute name='sid' type='xs:string' use='optional'/><br />
<xs:attribute name='stream' type='xs:string' use='optional'/><br />
<xs:attribute name='time' type='xs:unsignedShort' use='optional'/><br />
<xs:attribute name='to' type='xs:string' use='optional'/><br />
<xs:attribute name='type' use='optional'><br />
<xs:simpleType><br />
<xs:restriction base='xs:NCName'><br />
<xs:enumeration value='error'/><br />
<xs:enumeration value='terminate'/><br />
</xs:restriction><br />
</xs:simpleType><br />
</xs:attribute><br />
<xs:attribute name='ver' type='xs:string' use='optional'/><br />
<xs:attribute name='wait' type='xs:unsignedShort' use='optional'/><br />
<xs:attribute ref='xml:lang' use='optional'/><br />
<xs:anyAttribute namespace='##other' processContents='lax'/><br />
</xs:complexType><br />
</xs:element><br />
<br />
</xs:schema><br />
<br />
<br />
23. Acknowledgements<br />
<br />
Thanks to Mike Cumings, Tomas Karasek, Tobias Markmann, Chris Seymour, Safa Sofuoğlu, Stefan Strigler, Matthew Wild, Kevin Winters, and Christopher Zorn for their feedback.<br />
Appendices<br />
Appendix A: Document Information<br />
<br />
Series: XEP<br />
Number: 0124<br />
Publisher: XMPP Standards Foundation<br />
Status: Draft<br />
Type: Standards Track<br />
Version: 1.10<br />
Last Updated: 2010-07-02<br />
Approving Body: XMPP Council<br />
Dependencies: RFC 1945, RFC 2616, RFC 3174<br />
Supersedes: None<br />
Superseded By: None<br />
Short Name: bosh<br />
Schema: <http://www.xmpp.org/schemas/httpbind.xsd><br />
Source Control: HTML RSS<br />
This document in other formats: XML PDF<br />
Appendix B: Author Information<br />
Ian Paterson<br />
<br />
Email: ian.paterson@clientside.co.uk<br />
JabberID: ian@zoofy.com<br />
Dave Smith<br />
<br />
Email: dizzyd@jabber.org<br />
JabberID: dizzyd@jabber.org<br />
Peter Saint-Andre<br />
<br />
Email: stpeter@jabber.org<br />
JabberID: stpeter@jabber.org<br />
URI: https://stpeter.im/<br />
Jack Moffitt<br />
<br />
Email: jack@chesspark.com<br />
JabberID: jack@chesspark.com<br />
Appendix C: Legal Notices<br />
Copyright<br />
This XMPP Extension Protocol is copyright © 1999 - 2011 by the XMPP Standards Foundation (XSF).<br />
Permissions<br />
Permission is hereby granted, free of charge, to any person obtaining a copy of this specification (the "Specification"), to make use of the Specification without restriction, including without limitation the rights to implement the Specification in a software program, deploy the Specification in a network service, and copy, modify, merge, publish, translate, distribute, sublicense, or sell copies of the Specification, and to permit persons to whom the Specification is furnished to do so, subject to the condition that the foregoing copyright notice and this permission notice shall be included in all copies or substantial portions of the Specification. Unless separate permission is granted, modified works that are redistributed shall not contain misleading information regarding the authors, title, number, or publisher of the Specification, and shall not claim endorsement of the modified works by the authors, any organization or project to which the authors belong, or the XMPP Standards Foundation.<br />
Disclaimer of Warranty<br />
## NOTE WELL: This Specification is provided on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, express or implied, including, without limitation, any warranties or conditions of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A PARTICULAR PURPOSE. ##<br />
Limitation of Liability<br />
In no event and under no legal theory, whether in tort (including negligence), contract, or otherwise, unless required by applicable law (such as deliberate and grossly negligent acts) or agreed to in writing, shall the XMPP Standards Foundation or any author of this Specification be liable for damages, including any direct, indirect, special, incidental, or consequential damages of any character arising from, out of, or in connection with the Specification or the implementation, deployment, or other use of the Specification (including but not limited to damages for loss of goodwill, work stoppage, computer failure or malfunction, or any and all other commercial damages or losses), even if the XMPP Standards Foundation or such author has been advised of the possibility of such damages.<br />
IPR Conformance<br />
This XMPP Extension Protocol has been contributed in full conformance with the XSF's Intellectual Property Rights Policy (a copy of which can be found at <http://xmpp.org/extensions/ipr-policy.shtml> or obtained by writing to XMPP Standards Foundation, 1899 Wynkoop Street, Suite 600, Denver, CO 80202 USA).<br />
Appendix D: Relation to XMPP<br />
<br />
The Extensible Messaging and Presence Protocol (XMPP) is defined in the XMPP Core (RFC 3920) and XMPP IM (RFC 3921) specifications contributed by the XMPP Standards Foundation to the Internet Standards Process, which is managed by the Internet Engineering Task Force in accordance with RFC 2026. Any protocol defined in this document has been developed outside the Internet Standards Process and is to be understood as an extension to XMPP rather than as an evolution, development, or modification of XMPP itself.<br />
Appendix E: Discussion Venue<br />
<br />
The primary venue for discussion of XMPP Extension Protocols is the <standards@xmpp.org> discussion list.<br />
<br />
Discussion on other xmpp.org discussion lists might also be appropriate; see <http://xmpp.org/about/discuss.shtml> for a complete list.<br />
<br />
Given that this XMPP Extension Protocol normatively references IETF technologies, discussion on the <xsf-ietf@xmpp.org> list might also be appropriate.<br />
<br />
Errata can be sent to <editor@xmpp.org>.<br />
Appendix F: Requirements Conformance<br />
<br />
The following requirements keywords as used in this document are to be interpreted as described in RFC 2119: "MUST", "SHALL", "REQUIRED"; "MUST NOT", "SHALL NOT"; "SHOULD", "RECOMMENDED"; "SHOULD NOT", "NOT RECOMMENDED"; "MAY", "OPTIONAL".<br />
Appendix G: Notes<br />
<br />
1. RFC 793: Transmission Control Protocol <http://tools.ietf.org/html/rfc0793>.<br />
<br />
2. RFC 1945: Hypertext Transfer Protocol -- HTTP/1.0 <http://tools.ietf.org/html/rfc1945>.<br />
<br />
3. RFC 2616: Hypertext Transport Protocol -- HTTP/1.1 <http://tools.ietf.org/html/rfc2616>.<br />
<br />
4. Bayeux Protocol <http://svn.cometd.org/trunk/bayeux/bayeux.html>.<br />
<br />
5. The Web Socket Protocol <http://tools.ietf.org/html/draft-hixie-thewebsocketprotocol>.<br />
<br />
6. Reverse HTTP <http://tools.ietf.org/html/draft-lentczner-rhttp>.<br />
<br />
7. RFC 2965: HTTP State Management Mechanism <http://tools.ietf.org/html/rfc2965>.<br />
<br />
8. Requiring cookies is sub-optimal because several significant computing platforms provide only limited access to underlying HTTP requests/responses; worse, some platforms hide or remove cookie-related headers.<br />
<br />
9. XEP-0025: Jabber HTTP Polling <http://xmpp.org/extensions/xep-0025.html>.<br />
<br />
10. RFC 6120: Extensible Messaging and Presence Protocol (XMPP): Core <http://tools.ietf.org/html/rfc6120>.<br />
<br />
11. XEP-0206: XMPP Over BOSH <http://xmpp.org/extensions/xep-0206.html>.<br />
<br />
12. In order to reduce network congestion, RFC 2616 recommends that clients SHOULD NOT keep more than two HTTP connections to the same HTTP server open at the same time. Clients running in constrained enviroments typically have no choice but to abide by that recommendation.<br />
<br />
13. If there is no traffic other than the "pings" then bandwidth consumption will be double that of a TCP connection (although double nothing is still nothing). If data is sent in large packets then bandwidth consumption will be almost identical.<br />
<br />
14. Extensible Markup Language (XML) 1.0 (Fourth Edition) <http://www.w3.org/TR/REC-xml/>.<br />
<br />
15. Namespaces in XML <http://www.w3.org/TR/REC-xml-names/>.<br />
<br />
16. RFC 4627: The application/json Media Type for JavaScript Object Notation (JSON) <http://tools.ietf.org/html/rfc4627>.<br />
<br />
17. Extensible Markup Language (XML) 1.0 (Fourth Edition) <http://www.w3.org/TR/REC-xml/>.<br />
<br />
18. Although the syntax of the 'route' attribute bears a superficial resemblance to a URI or IRI, it is not a URI/IRI and MUST NOT be processed in accordance with the rules specified in RFC 3986, RFC 3987, or (for XMPP) RFC 5122.<br />
<br />
19. Each character set name (or character encoding name -- we use the terms interchangeably) SHOULD be of type NMTOKEN, where the names are separated by the white space character #x20, resulting in a tokenized attribute type of NMTOKENS (see Section 3.3.1 of XML 1.0 [20]). Strictly speaking, the Character Sets registry maintained by the Internet Assigned Numbers Authority (see <http://www.iana.org/assignments/character-sets>) allows a character set name to contain any printable US-ASCII character, which might include characters not allowed by the NMTOKEN construction of XML 1.0; however, the only existing character set name which includes such a character is "NF_Z_62-010_(1973)".<br />
<br />
20. Extensible Markup Language (XML) 1.0 (Fourth Edition) <http://www.w3.org/TR/REC-xml/>.<br />
<br />
21. 9007199254740991 is 253-1. Some weakly typed languages use IEEE Standard 754 Doubles to represent all numbers. These Doubles cannot represent integers above 253 accurately.<br />
<br />
22. RFC 3174: US Secure Hash Algorithm 1 (SHA1) <http://tools.ietf.org/html/rfc3174>.<br />
<br />
23. Therefore a client and a connection manager will be compatible even if one or the other offers no support for multi-stream sessions.<br />
<br />
24. The 'rid' attribute is always incremented normally without reference to any 'stream' attribute.<br />
<br />
25. This helps to ensure backwards-compatibility with older implementations.<br />
<br />
26. Each HTTP response MUST belong to the same session as the request that triggered it, but not necessarily to the same stream.<br />
<br />
27. The broadcast payloads can be of any type.<br />
<br />
28. SSL V3.0 <http://wp.netscape.com/eng/ssl3/draft302.txt>.<br />
<br />
29. RFC 2818: HTTP Over TLS <http://tools.ietf.org/html/rfc2818>.<br />
<br />
30. RFC 2817: Upgrading to TLS Within HTTP/1.1 <http://tools.ietf.org/html/rfc2817>.<br />
<br />
31. RFC 1750: Randomness Recommendations for Security <http://tools.ietf.org/html/rfc1750>.<br />
<br />
32. RFC 4270: Attacks on Cryptographic Hashes in Internet Protocols <http://tools.ietf.org/html/rfc4270>.<br />
<br />
33. The Internet Assigned Numbers Authority (IANA) is the central coordinator for the assignment of unique parameter values for Internet protocols, such as port numbers and URI schemes. For further information, see <http://www.iana.org/>.<br />
<br />
34. IANA registry of port numbers <http://www.iana.org/assignments/port-numbers>.<br />
<br />
35. XEP-0156: Discovering Alternative XMPP Connection Methods <http://xmpp.org/extensions/xep-0156.html>.<br />
Appendix H: Revision History<br />
<br />
Note: Older versions of this specification might be available at http://xmpp.org/extensions/attic/<br />
Version 1.10 (2010-07-02)<br />
<br />
Further clarified use of 'from' and 'to' attributes; added missing condition values to the schema.<br />
(psa)<br />
Version 1.9 (2009-11-06)<br />
<br />
Added information for registration of port 5280 with IANA.<br />
(psa)<br />
Version 1.8 (2009-04-30)<br />
<br />
Removed secure attribute because it did not solve the problem it was intended to solve; added security consideration regarding link between connection manager and application server; changed "stanza" to "payload" for disambiguation with XMPP; clarified design objectives and relationship to similar technologies; corrected several errors in the schema.<br />
(psa/jm)<br />
Version 1.7 (2008-10-29)<br />
<br />
Moved alternative script syntax to historical specification; added implementation note about HTTP Pipelining; adjusted architectural description.<br />
(psa)<br />
Version 1.6 (2007-02-21)<br />
<br />
Multiple clarifications and restructuring without changes to protocol itself; changed title to BOSH; added section that fully explains the technique underlying the protocol; separated XMPP-specific features into new XEP-0206; added optional new Script Syntax and session pauses; added Acknowledgements section; added from and ver attributes; added hold attribute to session creation response; clarified polling too-frequently error; recommended that clients use HTTP Pipelining.<br />
(ip)<br />
Version 1.5 (2006-04-28)<br />
<br />
Added optional Multiple Streams section; added security considerations about encrypted HTTP connections; recommended use of SSL rather than HTTP over TLS; specified that request ID values must not exceed 9007199254740991; corrected datatypes of inactivity, polling, rid, and wait attributes in the schema; added <any/> and <anyAttribute/> elements to schema to optionally support non-XMPP XML elements and attributes; deprecated HTTP error codes in favor of new terminal binding conditions.<br />
(ip/psa)<br />
Version 1.4 (2005-12-14)<br />
<br />
Modified syntax of route attribute to be proto:host:port rather than XMPP URI/IRI.<br />
(psa)<br />
Version 1.3 (2005-11-02)<br />
<br />
Corrected stream:features namespace and the Recoverable Binding Conditions section; recommended that connection manager shall return secure attribute to client; recommended end-to-end encryption through proxy connection managers.<br />
(ip)<br />
Version 1.2 (2005-06-16)<br />
<br />
Specified optional use of route and secure attributes in session request. Minor correction: the stream features element should be included in the response that contains the authid attribute (this is not necessarily the session creation response).<br />
(ip)<br />
Version 1.1 (2005-06-02)<br />
<br />
Specified optional use of HTTP Accept-Encoding and Content-Encoding headers for compression at HTTP binding level.<br />
(ip)<br />
Version 1.0 (2005-03-03)<br />
<br />
Per a vote of the Jabber Council, advanced status to Draft.<br />
(psa)<br />
Version 0.10 (2004-11-08)<br />
<br />
Changed HTTP 401 errors to HTTP 404.<br />
(ip)<br />
Version 0.9 (2004-10-26)<br />
<br />
Added charset attribute.<br />
(ip/psa)<br />
Version 0.8 (2004-10-26)<br />
<br />
Specified that wait attribute must be included in the session creation response.<br />
(ip)<br />
Version 0.7 (2004-08-12)<br />
<br />
Defined appropriate XMPP stanza error conditions.<br />
(psa/ip)<br />
Version 0.6 (2004-07-19)<br />
<br />
Added xml:lang attribute to the session request; added recoverable binding error conditions.<br />
(ip)<br />
Version 0.5 (2004-05-07)<br />
<br />
Protocol refactored to enable simultaneous requests (request identifier attribute, wait attribute, hold attribute, requests attribute) and recovery of broken connections; added content attribute; removed all wrapper types except 'terminate'; updated error handling; made key mechanism optional (should use SSL/TLS instead).<br />
(ip/psa)<br />
Version 0.4 (2004-02-23)<br />
<br />
Fixed typos; removed "resource-constraint" binding error; added HTTP 403 error to table.<br />
(psa/ip)<br />
Version 0.3 (2004-02-19)<br />
<br />
Added 'authid' attribute to enable communication of XMPP stream ID (used in digest authentication); specified that Content-Types other than "text/xml" are allowed to support older HTTP clients; specified business rule for connection manager queueing of client requests; changed <packet/> to <body/> to support older HTTP clients; changed 'to' attribute on initialization element from MAY to SHOULD; recommended inclusion of unavailable presence in termination element sent from client; described architectural assumptions; specified binding-specific error handling.<br />
(psa/ip)<br />
Version 0.2 (2004-01-13)<br />
<br />
Added 'to' attribute on the initialization element; specified that 'text/html' is allowable for backwards-compatibility.<br />
(dss/psa/ip)<br />
Version 0.1 (2003-11-06)<br />
<br />
Initial version.<br />
(dss/psa)<br />
<br />
END</div>
Snowqiang
http://wiki.jabbercn.org/XEP-0124
XEP-0124
2011-05-18T13:19:51Z
<p>Snowqiang: 新建xep-0124:Bidirectional-streams Over Synchronous HTTP</p>
<hr />
<div>XEP-0124: Bidirectional-streams Over Synchronous HTTP (BOSH)<br />
Abstract: This specification defines a transport protocol that emulates the semantics of a long-lived, bidirectional TCP connection between two entities (such as a client and a server) by efficiently using multiple synchronous HTTP request/response pairs without requiring the use of frequent polling or chunked responses.<br />
Authors: Ian Paterson, Dave Smith, Peter Saint-Andre, Jack Moffitt<br />
Copyright: © 1999 - 2011 XMPP Standards Foundation. SEE LEGAL NOTICES.<br />
Status: Draft<br />
Type: Standards Track<br />
Version: 1.10<br />
Last Updated: 2010-07-02<br />
<br />
NOTICE: The protocol defined herein is a Draft Standard of the XMPP Standards Foundation. Implementations are encouraged and the protocol is appropriate for deployment in production systems, but some changes to the protocol are possible before it becomes a Final Standard.<br />
<br />
1. Introduction<br />
<br />
The Transmission Control Protocol (TCP; RFC 793 [1]) is often used to establish a stream-oriented connection between two entities. Such connections can often be long-lived to enable an interactive "session" between the entities. However, sometimes the nature of the device or network can prevent an application from maintaining a long-lived TCP connection to a server or peer. In this case, it is desirable to use an alternative connection method that emulates the behavior of a long-lived TCP connection using a sequenced series of requests and responses that are exchanged over short-lived connections. The appropriate request-response semantics are widely available via the Hypertext Transfer Protocol (HTTP) as specified in RFC 1945 [2] and RFC 2616 [3].<br />
<br />
BOSH, the technology defined in this specification, essentially provides a "drop-in" alternative to a long-lived, bidirectional TCP connection. It is a mature, full-featured technology that has been widely implemented and deployed since 2004. To our knowledge it was the first of many similar technologies, which now include the Comet methodology formalized in the Bayeux Protocol [4] as well as The Web Socket Protocol [5] and Reverse HTTP [6].<br />
<br />
BOSH is designed to transport any data efficiently and with minimal latency in both directions. For applications that require both "push" and "pull" semantics, BOSH is significantly more bandwidth-efficient and responsive than most other bidirectional HTTP-based transport protocols and the techniques now commonly known as "Ajax". BOSH achieves this efficiency and low latency by using so-called "long polling" with multiple synchronous HTTP request/response pairs. Furthermore, BOSH can address the needs of constrained clients by employing fully-compliant HTTP 1.0 without the need for "cookies" (see RFC 2965 [7]) [8] or even access to HTTP headers.<br />
<br />
BOSH was originally developed in the Jabber/XMPP community as a replacement for an even earlier HTTP-based technology called Jabber HTTP Polling [9]. Although BOSH assumes that the "payload" of HTTP requests and responses will be XML, the payload formats are not limited to XMPP stanzas (see XMPP Core [10]) and could contain a mixture of elements qualified by namespaces defined by different protocols (e.g., both XMPP and JSON). This mix is necessary because some connection managers might 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 payload is qualified by the correct namespace.<br />
<br />
Note: XMPP Over BOSH [11] documents some XMPP-specific extensions of this protocol that were formerly included in this document.<br />
2. Requirements<br />
<br />
The following design requirements reflect the need to offer performance as close as possible to a standard TCP connection.<br />
<br />
1. Compatible with constrained runtime environments* (e.g., mobile and browser-based clients).<br />
2. Compatible with proxies that buffer partial HTTP responses.<br />
3. Efficient through proxies that limit the duration of HTTP responses.<br />
4. Fully compatible with HTTP/1.0.<br />
5. Compatible with restricted network connections (e.g., firewalls, proxies, and gateways).<br />
6. Fault tolerant (e.g., session recovers after an underlying TCP connection breaks at any stage during an HTTP request).<br />
7. Extensible.<br />
8. Consume significantly less bandwidth than polling-based protocols.<br />
9. Significantly more responsive (lower latency) than polling-based protocols.<br />
10. Support for polling (for clients that are limited to a single HTTP connection at a time).<br />
11. In-order delivery of data.<br />
12. Guard against unauthorized users injecting HTTP requests into a session.<br />
13. Protect against denial of service attacks.<br />
14. Multiplexing of data streams.<br />
<br />
*Note: Compatibility with constrained runtime environments implies the following restrictions:<br />
<br />
1. Clients are not required to have programmatic access to the headers of each HTTP request and response (e.g., cookies or status codes).<br />
2. The body of each HTTP request and response is parsable XML with a single root element.<br />
3. Clients can specify the Content-Type of the HTTP responses they receive.<br />
<br />
3. Architectural Assumptions<br />
<br />
This document assumes that most implementations will utilize a specialized connection manager ("CM") to handle HTTP connections rather than the native connection type for the relevant application (e.g., TCP connections in XMPP). Effectively, such a connection manager is a specialized HTTP server that translates between the HTTP requests and responses defined herein and the data streams (or API) implemented by the server with which it communicates, thus enabling a client to connect to a server via HTTP on port 80 or 443 instead of an application-specific port. We can illustrate this graphically as follows:<br />
<br />
Server<br />
|<br />
| [unwrapped data streams]<br />
|<br />
HTTP CM<br />
|<br />
| [HTTP + <body/> wrapper]<br />
|<br />
Client<br />
<br />
<br />
This specification covers communication only between a client and the connection manager. It does not cover communication between the connection manager and the server, since such communications are implementation-specific (e.g., the server might 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 might be an independent translating proxy such that the server might believe it is talking directly to the client over TCP; or the connection manager and the server might use a component protocol or an API defined by the server implementation).<br />
<br />
Furthermore, no aspect of this protocol limits its use to communication between a client and a server. For example, it could be used for communication between a server and a peer server if such communication can occur for the relevant application (e.g., in XMPP). 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 the native connection transport for the relevant application. (However, on some unreliable networks, BOSH might enable more stable communication between servers.)<br />
4. The BOSH Technique<br />
<br />
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).<br />
<br />
The technique employed by BOSH 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.<br />
<br />
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 so to make sure the client can send more data immediately if necessary. (The client SHOULD NOT open more than two HTTP connections to the connection manager at the same time, [12] so it would otherwise have to wait until the connection manager responds to one of the requests.)<br />
<br />
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 TCP 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.<br />
<br />
If there is no traffic in either direction for an agreed amount of time (typically several 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 so 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. [13]<br />
<br />
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. Thus 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. Therefore, 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 were being used.<br />
<br />
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.<br />
5. HTTP Overview<br />
<br />
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).<br />
<br />
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 permitted by RFC 1945 or RFC 2616. For example, 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 might buffer each partial HTTP request or response and only forward the full request or response once it is available.<br />
<br />
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.<br />
<br />
Requests and responses MAY include HTTP headers not specified herein. The receiver SHOULD ignore any such headers.<br />
<br />
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). However, the responses to requests that are not part of the session sent over the same connection using HTTP pipelining (or queued to be sent over the same connection) might be delayed if they were sent while a request that is part of the session is being held (since the connection manager MUST send its responses in the same order that the requests were received, and the connection manager typically delays its responses).<br />
<br />
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.<br />
6. <body/> Wrapper Element<br />
<br />
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 transferred. The <body/> element and its content together MUST conform to the specifications set out in XML 1.0 [14]. They SHOULD also conform to Namespaces in XML [15]. The content MUST NOT contain any of the following (all defined in XML 1.0):<br />
<br />
*<br />
<br />
Partial XML elements<br />
*<br />
<br />
XML comments<br />
*<br />
<br />
XML processing instructions<br />
*<br />
<br />
Internal or external DTD subsets<br />
*<br />
<br />
Internal or external entity references (with the exception of predefined entities)<br />
<br />
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 "payloads" in this document, e.g., XMPP stanzas as defined in RFC 6120 or elements containing XML character data that represents objects using the JSON data interchange format as defined in RFC 4627 [16]). Each <body/> wrapper MAY contain payloads qualified under a wide variety of different namespaces.<br />
<br />
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.<br />
7. Initiating a BOSH Session<br />
7.1 Session Creation Request<br />
<br />
The first request from the client to the connection manager requests a new session.<br />
<br />
The <body/> element of the first request SHOULD possess the following attributes (they SHOULD NOT be included in any other requests except as specified under Adding Streams To A Session):<br />
<br />
* 'to' -- This attribute specifies the target domain of the first stream.<br />
* 'xml:lang' -- This attribute (as defined in Section 2.12 of XML 1.0 [17]) specifies the default language of any human-readable XML character data sent or received during the session.<br />
* 'ver' -- This attribute specifies the highest version of the BOSH protocol that the client supports. The numbering scheme is "<major>.<minor>" (where the minor number MAY be incremented higher than a single digit, so it MUST be treated as a separate integer). Note: The 'ver' attribute should not be confused with the version of any protocol being transported.<br />
* 'wait' -- This attribute specifies the longest time (in seconds) that the connection manager is allowed to wait before responding to any request during the session. This enables the client to limit the delay before it discovers any network failure, and to prevent its HTTP/TCP connection from expiring due to inactivity.<br />
* 'hold' -- This attribute specifies the maximum number of requests the connection manager is allowed to keep waiting at any one time during the session. If the client is not able to use HTTP Pipelining then this SHOULD be set to "1".<br />
<br />
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 both typically one or two orders of magnitude!<br />
<br />
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:example.com:9999"). [18] A connection manager that is configured to work only with a single server (or only with a defined list of domains and the associated list of hostnames and ports that are serving those domains) MAY ignore the 'route' attribute. (Note that the 'to' attribute specifies the domain being served, not the hostname of the machine that is serving the domain.)<br />
<br />
The <body/> element of the first request MAY also possess a 'from' attribute, which specifies the originator of the first stream and which enables the connection manager to forward the originating entity's identity to the application server (e.g., the JabberID of an entity that is connecting to an XMPP server; see XEP-0206).<br />
<br />
A client MAY include an 'ack' attribute (set to "1") to indicate that it will be using acknowledgements throughout the session and that the absence of an 'ack' attribute in any request is meaningful (see Acknowledgements).<br />
<br />
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".<br />
<br />
Example 1. Requesting a BOSH session<br />
<br />
POST /webclient HTTP/1.1<br />
Host: httpcm.example.com<br />
Accept-Encoding: gzip, deflate<br />
Content-Type: text/xml; charset=utf-8<br />
Content-Length: 104<br />
<br />
<body content='text/xml; charset=utf-8'<br />
from='user@example.com'<br />
hold='1'<br />
rid='1573741820'<br />
to='example.com'<br />
route='xmpp:example.com:9999'<br />
ver='1.6'<br />
wait='60'<br />
ack='1'<br />
xml:lang='en'<br />
xmlns='http://jabber.org/protocol/httpbind'/><br />
<br />
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.<br />
7.2 Session Creation Response<br />
<br />
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):<br />
<br />
* 'sid' -- This attribute specifies the SID<br />
* 'wait' -- This is the longest time (in seconds) that the connection manager will wait before responding to any request during the session. The time MUST be less than or equal to the value specified in the session request.<br />
<br />
The <body/> element SHOULD also include the following attributes (they SHOULD NOT be included in any other responses):<br />
<br />
* 'ver' -- This attribute specifies the highest version of the BOSH protocol that the connection manager supports, or the version specified by the client in its request, whichever is lower.<br />
* 'polling' -- This attribute specifies the shortest allowable polling interval (in seconds). This enables the client to not send empty request elements more often than desired (see Polling Sessions and Overactivity).<br />
* 'inactivity' -- This attribute specifies the longest allowable inactivity period (in seconds). This enables the client to ensure that the periods with no requests pending are never too long (see Polling Sessions and Inactivity).<br />
* 'requests' -- This attribute enables the connection manager to limit the number of simultaneous requests the client makes (see Overactivity and Polling Sessions). The RECOMMENDED values are either "2" or one more than the value of the 'hold' attribute specified in the session request.<br />
* 'hold' -- This attribute informs the client about the maximum number of requests the connection manager will keep waiting at any one time during the session. This value MUST NOT be greater than the value specified by the client in the session request.<br />
* 'to' -- This attribute communicates the identity of the backend server to which the client is attempting to connect.<br />
<br />
The connection manager MAY include an 'accept' attribute in the session creation response element, to specify a space-separated list of 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.<br />
<br />
A connection manager MAY include an 'ack' attribute (set to the value of the 'rid' attribute of the session creation request) to indicate that it will be using acknowledgements throughout the session and that the absence of an 'ack' attribute in any response is meaningful (see Acknowledgements).<br />
<br />
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 can request.<br />
<br />
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. [19]<br />
<br />
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 a BOSH Session), then in the same response the connection manager SHOULD also include the 'secure' attribute set to "true" or "1".<br />
<br />
Example 2. Session creation response<br />
<br />
HTTP/1.1 200 OK<br />
Content-Type: text/xml; charset=utf-8<br />
Content-Length: 128<br />
<br />
<body wait='60'<br />
inactivity='30'<br />
polling='5'<br />
requests='2'<br />
hold='1'<br />
ack='1573741820'<br />
accept='deflate,gzip'<br />
maxpause='120'<br />
sid='SomeSID'<br />
charsets='ISO_8859-1 ISO-2022-JP'<br />
ver='1.6'<br />
from='example.com'<br />
xmlns='http://jabber.org/protocol/httpbind'/><br />
<br />
Example 3. Subsequent response with 'from' and 'secure' attributes<br />
<br />
HTTP/1.1 200 OK<br />
Content-Type: text/xml; charset=utf-8<br />
Content-Length: 128<br />
<br />
<body from='example.com'<br />
xmlns='http://jabber.org/protocol/httpbind'/><br />
<br />
8. Sending and Receiving XML Payloads<br />
<br />
After the client has successfully completed all required preconditions, it can send and receive XML payloads via the HTTP binding.<br />
<br />
Example 4. Transmitting payloads<br />
<br />
POST /webclient HTTP/1.1<br />
Host: httpcm.example.com<br />
Accept-Encoding: gzip, deflate<br />
Content-Type: text/xml; charset=utf-8<br />
Content-Length: 188<br />
<br />
<body rid='1249243562'<br />
sid='SomeSID'<br />
xmlns='http://jabber.org/protocol/httpbind'><br />
<message to='contact@example.com'<br />
xmlns='jabber:client'><br />
<body>Good morning!</body><br />
</message><br />
<message to='friend@example.com'<br />
xmlns='jabber:client'><br />
<body>Hey, what&apos;s up?</body><br />
</message><br />
</body><br />
<br />
Upon receipt of a request, the connection manager SHOULD forward the content of the <body/> element to the server as soon as possible. In any case it MUST forward the content from different requests in the order specified by their 'rid' attributes.<br />
<br />
The connection manager MUST also return an HTTP 200 OK response with a <body/> element to the client. Note: This does not indicate that the payloads have been successfully delivered to the application server.<br />
<br />
It is RECOMMENDED that the connection manager not return an HTTP result until a payload has arrived from the application server for delivery to the client. However, the connection manager SHOULD NOT wait longer than the time specified by the client in the 'wait' attribute of its Session Creation Request, and it SHOULD NOT keep more HTTP requests waiting at a time than the number specified in the 'hold' attribute of the session creation request. In any case it MUST respond to requests in the order specified by their 'rid' attributes.<br />
<br />
If there are no payloads waiting or ready to be delivered within the waiting period, then the connection manager SHOULD include an empty <body/> element in the HTTP result:<br />
<br />
Example 5. Empty response<br />
<br />
HTTP/1.1 200 OK<br />
Content-Type: text/xml; charset=utf-8<br />
Content-Length: 64<br />
<br />
<body xmlns='http://jabber.org/protocol/httpbind'/><br />
<br />
If the connection manager has received one or more payloads from the application server for delivery to the client, then it SHOULD return the payloads in the body of its response as soon as possible after receiving them from the server. The example below includes payloads qualified by different namespaces:<br />
<br />
Example 6. Response with queued stanza<br />
<br />
HTTP/1.1 200 OK<br />
Content-Type: text/xml; charset=utf-8<br />
Content-Length: 185<br />
<br />
<body xmlns='http://jabber.org/protocol/httpbind'<br />
xmlns:json='http://json.org/'><br />
<message from='contact@example.com'<br />
to='user@example.com'<br />
xmlns='jabber:client'><br />
<body>Good morning to you!</body><br />
</message><br />
<message from='friend@example.com'<br />
to='user@example.com'<br />
xmlns='jabber:client'><br />
<body>Not much, how about with you?</body><br />
</message><br />
<json:json><br />
[<br />
{<br />
"precision": "zip",<br />
"Latitude": 37.7668,<br />
"Longitude": -122.3959,<br />
"Address": "",<br />
"City": "SAN FRANCISCO",<br />
"State": "CA",<br />
"Zip": "94107",<br />
"Country": "US"<br />
},<br />
{<br />
"precision": "zip",<br />
"Latitude": 37.371991,<br />
"Longitude": -122.026020,<br />
"Address": "",<br />
"City": "SUNNYVALE",<br />
"State": "CA",<br />
"Zip": "94085",<br />
"Country": "US"<br />
}<br />
]<br />
</json:json><br />
</body><br />
<br />
The client MAY poll the connection manager for incoming payloads by sending an empty <body/> element.<br />
<br />
Example 7. Requesting XML Payloads<br />
<br />
POST /webclient HTTP/1.1<br />
Host: httpcm.example.com<br />
Accept-Encoding: gzip, deflate<br />
Content-Type: text/xml; charset=utf-8<br />
Content-Length: 88<br />
<br />
<body rid='1249243563'<br />
sid='SomeSID'<br />
xmlns='http://jabber.org/protocol/httpbind'/><br />
<br />
The connection manager MUST wait and respond in the same way as it does after receiving payloads from the client.<br />
9. Acknowledgements<br />
9.1 Request Acknowledgements<br />
<br />
When responding to a request that it has been holding, if the connection manager finds it has already received another request with a higher 'rid' attribute (typically while it was holding the first request), then it MAY acknowledge the reception to the client. The connection manager MAY set the 'ack' attribute of any response to the value of the highest 'rid' attribute it has received in the case where it has also received all requests with lower 'rid' values.<br />
<br />
Example 8. Response with request acknowledgement<br />
<br />
HTTP/1.1 200 OK<br />
Content-Type: text/xml; charset=utf-8<br />
Content-Length: 64<br />
<br />
<body ack='1249243564'<br />
xmlns='http://jabber.org/protocol/httpbind'/><br />
<br />
If the connection manager will be including 'ack' attributes on responses during a session, then it MUST include an 'ack' attribute in its session creation response, and set the 'ack' attribute of responses throughout the session. The only exception is that, after its session creation response, the connection manager SHOULD NOT include an 'ack' attribute in any response if the value would be the 'rid' of the request being responded to.<br />
<br />
If the connection manager is permitted to hold more than one request at a time, then the reception of a lower-than-expected 'ack' value from the connection manager (or the unexpected abscence of an 'ack' attribute) can give the client an early warning that a network failure might have occurred (e.g., if the client believes the connection manager should have received another request by the time it responded).<br />
9.2 Response Acknowledgements<br />
<br />
The client MAY similarly inform the connection manager about the responses it has received by setting the 'ack' attribute of any request to the value of the highest 'rid' of a request for which it has already received a response in the case where it has also received all responses associated with lower 'rid' values. If the client will be including 'ack' attributes on requests during a session, then it MUST include an 'ack' attribute (set to '1') in its session creation request, and set the 'ack' attribute of requests throughout the session. The only exception is that, after its session creation request, the client SHOULD NOT include an 'ack' attribute in any request if it has received responses to all its previous requests.<br />
<br />
Example 9. Request with response acknowledgement<br />
<br />
POST /webclient HTTP/1.1<br />
Host: httpcm.example.com<br />
Accept-Encoding: gzip, deflate<br />
Content-Type: text/xml; charset=utf-8<br />
Content-Length: 88<br />
<br />
<body rid='1249243566'<br />
sid='SomeSID'<br />
ack='1249243564'<br />
xmlns='http://jabber.org/protocol/httpbind'/><br />
<br />
After receiving a request with an 'ack' value less than the 'rid' of the last request that it has already responded to, the connection manager MAY inform the client of the situation by sending its next response immediately instead of waiting until it has payloads to send to the client (e.g., if some time has passed since it responded). In this case it SHOULD include a 'report' attribute set to one greater than the 'ack' attribute it received from the client, and a 'time' attribute set to the number of milliseconds since it sent the response associated with the 'report' attribute.<br />
<br />
Example 10. Response with report<br />
<br />
HTTP/1.1 200 OK<br />
Content-Type: text/xml; charset=utf-8<br />
Content-Length: 64<br />
<br />
<body report='1249243565'<br />
time='852'<br />
xmlns='http://jabber.org/protocol/httpbind'/><br />
<br />
Upon reception of a response with 'report' and 'time' attributes, if the client has still not received the response associated with the request identifier specified by the 'report' attribute, then it MAY choose to resend the request associated with the missing response (see Broken Connections).<br />
10. Inactivity<br />
<br />
After receiving a response from the connection manager, if none of the client's requests are still being held by the connection manager (and if the session is not a Polling Session), the client SHOULD make a new request as soon as possible. In any case, if no requests are being held, the client MUST make a new request before the maximum inactivity period has expired. The length of this period (in seconds) is specified by the 'inactivity' attribute in the session creation response.<br />
<br />
If the connection manager has responded to all the requests it has received within a session and the time since its last response is longer than the maximum inactivity period, then it SHOULD assume the client has been disconnected and terminate the session without informing the client. If the client subsequently makes another request, then the connection manager SHOULD respond as if the session does not exist.<br />
<br />
If the connection manager did not specify a maximum inactivity period in the session creation response, then it SHOULD allow the client to be inactive for as long as it chooses.<br />
<br />
If the session is not a polling session then the connection manager SHOULD specify a relatively short inactivity period to ensure that disconnections are discovered as quickly as possible. The RECOMMENDED time would be a little more than the number of seconds for a comfortable network round trip between the connection manager and the client under difficult network conditions (since the client can be expected to make a new request immediately -- see above).<br />
<br />
If a client encounters an exceptional temporary situation during which it will be unable to send requests to the connection manager for a period of time greater than the maximum inactivity period (e.g., while a runtime environment changes from one web page to another), and if the connection manager included a 'maxpause' attribute in its Session Creation Response, then the client MAY request a temporary increase to the maximum inactivity period by including a 'pause' attribute in a request. Note: If the connection manager did not specify a 'maxpause' attribute at the start of the session then the client MUST NOT send a 'pause' attribute during the session.<br />
<br />
Example 11. Requesting a Session Pause<br />
<br />
POST /webclient HTTP/1.1<br />
Host: httpcm.example.com<br />
Accept-Encoding: gzip, deflate<br />
Content-Type: text/xml; charset=utf-8<br />
Content-Length: 98<br />
<br />
<body rid='1249243564'<br />
sid='SomeSID'<br />
pause='60'<br />
xmlns='http://jabber.org/protocol/httpbind'/><br />
<br />
Upon reception of a session pause request, if the requested period is not greater than the maximum permitted time, then the connection manager SHOULD respond immediately to all pending requests (including the pause request) and temporarily increase the maximum inactivity period to the requested time. Note: The response to the pause request MUST NOT contain any payloads.<br />
<br />
Note: If the client simply wants the connection manager to return all the requests it is holding then it MAY set the value of the 'pause' attribute to be the value of the 'inactivity' attribute in the connection manager's session creation response. (If the client believes it is in danger of becoming disconnected indefinitely then it MAY even request a temporary reduction of the maximum inactivity period by specifying a 'pause' value less than the 'inactivity' value, thus enabling the connection manager to discover any subsequent disconnection more quickly.)<br />
<br />
The connection manager SHOULD set the maximum inactivity period back to normal upon reception of the next request from the client (assuming the connection manager has not already terminated the session).<br />
11. Overactivity<br />
<br />
The client SHOULD NOT make more simultaneous requests than specified by the 'requests' attribute in the connection manager's Session Creation Response. However the client MAY make one additional request if it is to pause or terminate a session.<br />
<br />
If during any period the client sends a sequence of new requests (i.e. requests with incremented rid attributes, not repeat requests) longer than the number specified by the 'requests' attribute, and if the connection manager has not yet responded to any of the requests, and if the last request did not include either a 'pause' attribute or a 'type' attribute set to "terminate", then the connection manager SHOULD consider that the client is making too many simultaneous requests, and terminate the HTTP session with a 'policy-violation' terminal binding error to the client. Note: This behavior applies to equally to normal and polling sessions.<br />
<br />
Example 12. Too many simultaneous requests response<br />
<br />
HTTP/1.1 200 OK<br />
Content-Type: text/xml; charset=utf-8<br />
Content-Length: 68<br />
<br />
<body type='terminate'<br />
condition='policy-violation'<br />
xmlns='http://jabber.org/protocol/httpbind'/><br />
<br />
Note: If the connection manager did not specify a 'requests' attribute in the session creation response, then it MUST allow the client to send as many simultaneous requests as it chooses.<br />
<br />
If during any period the client sends a sequence of new requests equal in length to the number specified by the 'requests' attribute, and if the connection manager has not yet responded to any of the requests, and if the last request was empty and did not include either a 'pause' attribute or a 'type' attribute set to "terminate", and if the last two requests arrived within a period shorter than the number of seconds specified by the 'polling' attribute in the session creation response, then the connection manager SHOULD consider that the client is making requests more frequently than it was permitted and terminate the HTTP session and return a 'policy-violation' terminal binding error to the client. Note: the behavior for Polling Sessions is slightly different.<br />
<br />
Example 13. Too frequent requests response<br />
<br />
HTTP/1.1 200 OK<br />
Content-Type: text/xml; charset=utf-8<br />
Content-Length: 68<br />
<br />
<body type='terminate'<br />
condition='policy-violation'<br />
xmlns='http://jabber.org/protocol/httpbind'/><br />
<br />
Note: If the connection manager did not specify a 'polling' attribute in the session creation response, then it MUST allow the client to send requests as frequently as it chooses.<br />
12. Polling Sessions<br />
<br />
It is not always possible for a constrained client to either use HTTP Pipelining or open more than one HTTP connection with the connection manager at a time. In this case the client SHOULD inform the connection manager by setting the values of the 'wait' and/or 'hold' attributes in its session creation request to "0", and then "poll" the connection manager at regular intervals throughout the session for payloads it might have received from the server. Note: Even if the client does not request a polling session, the connection manager MAY require a client to use polling by setting the 'requests' attribute (which specifies the number of simultaneous requests the client can make) of its Session Creation Response to "1", however this is NOT RECOMMENDED.<br />
<br />
If a session will use polling, the connection manager SHOULD specify a higher than normal value for the 'inactivity' attribute (see Inactivity) in its session creation response. The increase SHOULD be greater than the value it specifies for the 'polling' attribute.<br />
<br />
If the client sends two consecutive empty new requests (i.e. requests with incremented rid attributes, not repeat requests) within a period shorter than the number of seconds specified by the 'polling' attribute (the shortest allowable polling interval) in the session creation response, and if the connection manager's response to the first request contained no payloads, then upon reception of the second request the connection manager SHOULD terminate the HTTP session and return a 'policy-violation' terminal binding error to the client.<br />
<br />
Example 14. Too frequent polling response<br />
<br />
HTTP/1.1 200 OK<br />
Content-Type: text/xml; charset=utf-8<br />
Content-Length: 68<br />
<br />
<body type='terminate'<br />
condition='policy-violation'<br />
xmlns='http://jabber.org/protocol/httpbind'/><br />
<br />
Note: If the connection manager did not specify a 'polling' attribute in the session creation response, then it MUST allow the client to poll as frequently as it chooses.<br />
13. Terminating the HTTP Session<br />
<br />
At any time, the client MAY gracefully terminate the session by sending a <body/> element with a 'type' attribute set to "terminate". The termination request MAY include one or more payloads that the connection manager MUST forward to the server to ensure graceful logoff.<br />
<br />
Example 15. Session termination by client<br />
<br />
POST /webclient HTTP/1.1<br />
Host: httpcm.example.com<br />
Accept-Encoding: gzip, deflate<br />
Content-Type: text/xml; charset=utf-8<br />
Content-Length: 153<br />
<br />
<body rid='1249243565'<br />
sid='SomeSID'<br />
type='terminate'<br />
xmlns='http://jabber.org/protocol/httpbind'><br />
<presence type='unavailable'<br />
xmlns='jabber:client'/><br />
</body><br />
<br />
The connection manager SHOULD respond to this request with an HTTP 200 OK containing an empty <body/> element.<br />
<br />
Example 16. Connection manager acknowledges termination<br />
<br />
HTTP/1.1 200 OK<br />
Content-Type: text/xml; charset=utf-8<br />
Content-Length: 72<br />
<br />
<body type='terminate'<br />
xmlns='http://jabber.org/protocol/httpbind'/><br />
<br />
Upon receiving the response, the client MUST consider the HTTP session to have been terminated.<br />
14. Request IDs<br />
14.1 Generation<br />
<br />
The client MUST generate a large, random, positive integer for the initial 'rid' (see Security Considerations) and then increment that value by one for each subsequent request. The client MUST take care to choose an initial 'rid' that will never be incremented above 9007199254740991 [21] within the session. In practice, a session would have to be extraordinarily long (or involve the exchange of an extraordinary number of packets) to exceed the defined limit.<br />
14.2 In-Order Message Forwarding<br />
<br />
When a client makes simultaneous requests, the connection manager might receive them out of order. The connection manager MUST forward the payloads to the server and respond to the client requests in the order specified by the 'rid' attributes. The client MUST process responses received from the connection manager in the order the requests were made.<br />
<br />
The connection manager SHOULD expect the 'rid' attribute to be within a window of values greater than the 'rid' of the previous request. The size of the window is equal to the maximum number of simultaneous requests allowed by the connection manager. If it receives a request with a 'rid' greater than the values in the window, then the connection manager MUST terminate the session with an error:<br />
<br />
Example 17. Unexpected rid error<br />
<br />
HTTP/1.1 200 OK<br />
Content-Type: text/xml; charset=utf-8<br />
Content-Length: 68<br />
<br />
<body type='terminate'<br />
condition='item-not-found'<br />
xmlns='http://jabber.org/protocol/httpbind'/><br />
<br />
14.3 Broken Connections<br />
<br />
Unreliable network communications or client constraints can result in broken connections. The connection manager SHOULD remember the 'rid' and the associated HTTP response body of the client's most recent requests which were not session pause requests (see Inactivity) and which did not result in an HTTP or binding error. The number of responses to non-pause requests kept in the buffer SHOULD be either the same as the maximum number of simultaneous requests allowed by the connection manager or, if Acknowledgements are being used, the number of responses that have not yet been acknowledged.<br />
<br />
If the network connection is broken or closed before the client receives a response to a request from the connection manager, then the client MAY resend an exact copy of the original request. Whenever the connection manager receives a request with a 'rid' that it has already received, it SHOULD return an HTTP 200 (OK) response that includes the buffered copy of the original XML response to the client (i.e., a <body/> wrapper possessing appropriate attributes and optionally containing one or more XML payloads). If the original response is not available (e.g., it is no longer in the buffer), then the connection manager MUST return an 'item-not-found' terminal binding error:<br />
<br />
Example 18. Response not in buffer error<br />
<br />
HTTP/1.1 200 OK<br />
Content-Type: text/xml; charset=utf-8<br />
Content-Length: 68<br />
<br />
<body type='terminate'<br />
condition='item-not-found'<br />
xmlns='http://jabber.org/protocol/httpbind'/><br />
<br />
Note: The error is the same whether the 'rid' is too large or too small. This makes it more difficult for an attacker to discover an acceptable value.<br />
15. Protecting Insecure Sessions<br />
15.1 Applicability<br />
<br />
The OPTIONAL key sequencing mechanism described here MAY be used if the client's session with the connection manager is not secure. The session SHOULD be considered secure only if all client requests are made via SSL (or TLS) HTTP connections and the connection manager generates an unpredictable session ID. If the session is secure, it is not necessary to use this key sequencing mechanism.<br />
<br />
Even if the session is not secure, the unpredictable session and request IDs specified in the preceding sections of this document already provide a level of protection similar to that provided by a connection bound to a single pair of persistent TCP/IP connections, and thus provide sufficient protection against a 'blind' attacker. However, in some circumstances, the key sequencing mechanism defined below helps to protect against a more determined and knowledgeable attacker.<br />
<br />
It is important to recognize that the key sequencing mechanism defined below helps to protect only against an attacker who is able to view the contents of all requests or responses in an insecure session but who is not able to alter the contents of those requests (in this case, the mechanism prevents the attacker from injecting HTTP requests into the session, e.g., termination requests or responses). However, the key sequencing mechanism does not provide any protection when the attacker is able to alter the contents of insecure requests or responses.<br />
15.2 Introduction<br />
<br />
The HTTP requests of each session MAY be spread across a series of different socket connections. This would enable an unauthorized user that obtains the session ID and request ID of a session to then use their own socket connection to inject <body/> request elements into the session and receive the corresponding responses.<br />
<br />
The key sequencing mechanism below protects against such attacks by enabling a connection manager to detect <body/> request elements injected by a third party.<br />
15.3 Generating the Key Sequence<br />
<br />
Prior to requesting a new session, the client MUST select an unpredictable counter ("n") and an unpredictable value ("seed"). The client then processes the "seed" through a cryptographic hash and converts the resulting 160 bits to a hexadecimal string K(1). It does this "n" times to arrive at the initial key K(n). The hashing algorithm MUST be SHA-1 as defined in RFC 3174 [22].<br />
<br />
Example 19. Creating the key sequence<br />
<br />
K(1) = hex(SHA-1(seed))<br />
K(2) = hex(SHA-1(K(1)))<br />
...<br />
K(n) = hex(SHA-1(K(n-1)))<br />
<br />
<br />
15.4 Use of Keys<br />
<br />
The client MUST set the 'newkey' attribute of the first request in the session to the value K(n).<br />
<br />
Example 20. Session Request with Initial Key<br />
<br />
POST /webclient HTTP/1.1<br />
Host: httpcm.example.com<br />
Accept-Encoding: gzip, deflate<br />
Content-Type: text/xml; charset=utf-8<br />
Content-Length: 104<br />
<br />
<body content='text/xml; charset=utf-8'<br />
hold='1'<br />
rid='1573741820'<br />
to='example.com'<br />
wait='60'<br />
xml:lang='en'<br />
newkey='ca393b51b682f61f98e7877d61146407f3d0a770'<br />
xmlns='http://jabber.org/protocol/httpbind'/><br />
<br />
The client MUST set the 'key' attribute of all subsequent requests to the value of the next key in the generated sequence (decrementing from K(n-1) towards K(1) with each request sent).<br />
<br />
Example 21. Request with Key<br />
<br />
POST /webclient HTTP/1.1<br />
Host: httpcm.example.com<br />
Accept-Encoding: gzip, deflate<br />
Content-Type: text/xml; charset=utf-8<br />
Content-Length: 88<br />
<br />
<body rid='1573741821'<br />
sid='SomeSID'<br />
key='bfb06a6f113cd6fd3838ab9d300fdb4fe3da2f7d'<br />
xmlns='http://jabber.org/protocol/httpbind'/><br />
<br />
The connection manager MAY verify the key by calculating the SHA-1 hash of the key and comparing it to the 'newkey' attribute of the previous request (or the 'key' attribute if the 'newkey' attribute was not set). If the values do not match (or if it receives a request without a 'key' attribute and the 'newkey' or 'key' attribute of the previous request was set), then the connection manager MUST NOT process the element, MUST terminate the session, and MUST return an 'item-not-found' terminal binding error.<br />
<br />
Example 22. Invalid Key Sequence Error<br />
<br />
HTTP/1.1 200 OK<br />
Content-Type: text/xml; charset=utf-8<br />
Content-Length: 68<br />
<br />
<body type='terminate'<br />
condition='item-not-found'<br />
xmlns='http://jabber.org/protocol/httpbind'/><br />
<br />
15.5 Switching to Another Key Sequence<br />
<br />
A client SHOULD choose a high value for "n" when generating the key sequence. However, if the session lasts long enough that the client arrives at the last key in the sequence K(1) then the client MUST switch to a new key sequence.<br />
<br />
The client MUST:<br />
<br />
1. Choose new values for "seed" and "n".<br />
2. Generate a new key sequence using the algorithm defined above.<br />
3. Set the 'key' attribute of the request to the next value in the old sequence (i.e. K(1), the last value).<br />
4. Set the 'newkey' attribute of the request to the value K(n) from the new sequence.<br />
<br />
Example 23. New Key Sequence<br />
<br />
POST /webclient HTTP/1.1<br />
Host: httpcm.example.com<br />
Accept-Encoding: gzip, deflate<br />
Content-Type: text/xml; charset=utf-8<br />
Content-Length: 188<br />
<br />
<body rid='1573741822'<br />
sid='SomeSID'<br />
key='6f825e81f4532b2c5fa2d12457d8a1f22e8f838e'<br />
newkey='113f58a37245ec9637266cf2fb6e48bfeaf7964e'<br />
xmlns='http://jabber.org/protocol/httpbind'><br />
<message to='contact@example.com'<br />
xmlns='jabber:client'><br />
<body>I said "Hi!"</body><br />
</message><br />
</body><br />
<br />
16. Multiple Streams<br />
16.1 Introduction<br />
<br />
The OPTIONAL feature described in this section enables multiple XML streams to be contained within a single HTTP session. This feature is essential in runtime environments that prevent HTTP Pipelining, thereby constraining the number of simultaneous HTTP requests a client can make to each connection manager, since clients running in such environments need multi-stream sessions if they are to connect using more than one account at the same time. This feature also reduces network traffic for any client that needs to establish parallel streams over HTTP.<br />
16.2 Discovery<br />
<br />
If a connection manager supports the multi-streams feature, it MUST include a 'stream' attribute in its Session Creation Response. If a client does not receive the 'stream' attribute then it MUST assume that the connection manager does not support the feature. [23]<br />
<br />
The 'stream' attribute identifies the first stream to be opened for the session. The value of each 'stream' attribute MUST be an opaque and unpredictable name that is unique within the context of the connection manager application.<br />
<br />
Example 24. Session creation response with stream name<br />
<br />
HTTP/1.1 200 OK<br />
Content-Type: text/xml; charset=utf-8<br />
Content-Length: 128<br />
<br />
<body wait='60'<br />
inactivity='30'<br />
polling='5'<br />
requests='2'<br />
hold='1'<br />
accept='deflate,gzip'<br />
stream='firstStreamName'<br />
maxpause='120'<br />
sid='SomeSID'<br />
charsets='ISO_8859-1 ISO-2022-JP'<br />
ver='1.6'<br />
from='example.com'<br />
xmlns='http://jabber.org/protocol/httpbind'/><br />
<br />
16.3 Adding Streams To A Session<br />
<br />
If the connection manager included a 'stream' attribute in its session creation response then the client MAY ask it to open another stream at any time by sending it an empty <body/> element with a 'to' attribute. The request MUST include valid 'sid' and 'rid' [24] attributes, and SHOULD also include an 'xml:lang' attribute. The request MAY include 'route', 'from' and 'secure' attributes (see Session Creation Request), but it SHOULD NOT include 'ver', 'content', 'hold' or 'wait' attributes (since a new session is not being created).<br />
<br />
Example 25. Requesting another stream<br />
<br />
POST /webclient HTTP/1.1<br />
Host: httpcm.example.com<br />
Accept-Encoding: gzip, deflate<br />
Content-Type: text/xml; charset=utf-8<br />
Content-Length: 104<br />
<br />
<body sid='SomeSID'<br />
rid='1573741820'<br />
to='example.com'<br />
route='xmpp:example.com:9999'<br />
xml:lang='en'<br />
xmlns='http://jabber.org/protocol/httpbind'/><br />
<br />
If the connection manager did not indicate its support for multiple streams at the start of the session, then it MUST ignore the extra attributes and treat the request as a normal empty request for payloads (see Sending and Receiving XML Payloads). [25] Otherwise it MUST open a new stream with the specified server (see Session Creation Response), generate a new stream name, and respond to the client with the name. The response MAY also include 'from' and 'secure' attributes, but it SHOULD NOT include 'sid', 'requests', 'polling', 'hold', 'inactivity', 'maxpause', 'accept', 'charsets', 'ver' or 'wait' attributes.<br />
<br />
Example 26. Add stream response<br />
<br />
HTTP/1.1 200 OK<br />
Content-Type: text/xml; charset=utf-8<br />
Content-Length: 128<br />
<br />
<body stream='secondStreamName'<br />
from='example.com'<br />
xmlns='http://jabber.org/protocol/httpbind'/><br />
<br />
Note: If the response did not include either 'from' or 'secure' attributes then they MAY be sent in a subsequent response instead (see Session Creation Response). In that case the 'stream' attribute MUST also be specified.<br />
16.4 Transmitting Payloads<br />
<br />
If more than one stream has been opened within a session, then all non-empty <body/> elements sent by the connection manager MUST include a 'stream' attribute that specifies which stream all the payloads it contains belong to. The client SHOULD include a 'stream' attribute for the same purpose. The client MAY omit the 'stream' attribute if it wants the connection manager to broadcast the payloads over all open streams. Note: A <body/> element MUST NOT contain different payloads for different streams.<br />
<br />
If a stream name does not correspond to one of the session's open streams, then the receiving connection manager SHOULD return an 'item-not-found' terminal binding error, or the receiving client SHOULD terminate the session. However, if the receiving entity has only just closed the stream (and the sender might not have been aware of that when it sent the payloads), then it MAY instead simply silently ignore any payloads the <body/> element contains.<br />
<br />
Note: Empty <body/> elements that do not include a 'from' or 'secure' attribute SHOULD NOT include a 'stream' attribute (since nothing is being transmitted for any stream). If such a <body/> element does include a 'stream' attribute then the receiving entity SHOULD ignore the attribute.<br />
<br />
Example 27. Client sends payload with a stream name<br />
<br />
POST /webclient HTTP/1.1<br />
Host: httpcm.example.com<br />
Accept-Encoding: gzip, deflate<br />
Content-Type: text/xml; charset=utf-8<br />
Content-Length: 188<br />
<br />
<body rid='1249243562'<br />
sid='SomeSID'<br />
stream='secondStreamName'<br />
xmlns='http://jabber.org/protocol/httpbind'><br />
<message to='contact@example.com'<br />
xmlns='jabber:client'><br />
<body>I said hello.</body><br />
</message><br />
</body><br />
<br />
Note: The value of the 'stream' attribute of the response MAY be different than the corresponding request. [26]<br />
<br />
Example 28. Connection manager responds with a different stream name<br />
<br />
HTTP/1.1 200 OK<br />
Content-Type: text/xml; charset=utf-8<br />
Content-Length: 185<br />
<br />
<body stream='firstStreamName'<br />
xmlns='http://jabber.org/protocol/httpbind'><br />
<message from='contact@example.com'<br />
to='user@example.com'<br />
xmlns='jabber:client'><br />
<body>Hi yourself!</body><br />
</message><br />
</body><br />
<br />
If no stream name is specified by the connection manager then the client MUST assume the payloads are associated with the first stream (even if the first stream has been closed).<br />
<br />
If no stream name is specified by the client then the connection manager MUST broadcast the payloads over all open streams. [27]<br />
<br />
Example 29. Client asks for a payload to be broadcast<br />
<br />
POST /webclient HTTP/1.1<br />
Host: httpcm.example.com<br />
Accept-Encoding: gzip, deflate<br />
Content-Type: text/xml; charset=utf-8<br />
Content-Length: 188<br />
<br />
<body rid='1249243562'<br />
sid='SomeSID'<br />
xmlns='http://jabber.org/protocol/httpbind'><br />
<presence xmlns='jabber:client'><br />
<show>away</show><br />
</presence><br />
</body><br />
<br />
16.5 Closing a Stream<br />
<br />
If more than one stream is open within a session, the client MAY close one open stream at any time using the procedure described in the section Terminating the HTTP Session above, taking care to specify the stream name with a 'stream' attribute. If the client closes the last stream the connection manager MUST terminate the session. If the client does not specify a stream name then the connection manager MUST close all open streams (sending any payloads the terminate request contains to all streams), and terminate the session.<br />
<br />
Example 30. Client closes one stream<br />
<br />
POST /webclient HTTP/1.1<br />
Host: httpcm.example.com<br />
Accept-Encoding: gzip, deflate<br />
Content-Type: text/xml; charset=utf-8<br />
Content-Length: 153<br />
<br />
<body rid='1249243564'<br />
sid='SomeSID'<br />
stream='secondStreamName'<br />
type='terminate'<br />
xmlns='http://jabber.org/protocol/httpbind'><br />
<presence type='unavailable'<br />
xmlns='jabber:client'/><br />
</body><br />
<br />
16.6 Error Conditions<br />
<br />
If more than one stream is open within a session, the connection manager MAY include a 'stream' attribute in a fatal binding error (see Terminal Binding Conditions). If a 'stream' attribute is specified then the stream MUST be closed by both entities but the session SHOULD NOT be terminated.<br />
<br />
Example 31. Fatal stream error<br />
<br />
HTTP/1.1 200 OK<br />
Content-Type: text/xml; charset=utf-8<br />
Content-Length: 68<br />
<br />
<body type='terminate'<br />
condition='remote-connection-failed'<br />
stream='secondStreamName'<br />
xmlns='http://jabber.org/protocol/httpbind'/><br />
<br />
Note: If the connection manager does not include a 'stream' attribute in a fatal binding error then all the session's open streams MUST be closed by both entities and the session MUST be terminated.<br />
17. Error and Status Codes<br />
<br />
There are four types of error and status reporting in HTTP responses:<br />
<br />
Table 1: Error Condition Types<br />
Condition Type Description<br />
HTTP Conditions (Deprecated) The connection manager responds to an invalid request from a legacy client with a standard HTTP error. These are used for binding syntax errors, possible attacks, etc. Note that constrained clients are unable to differentiate between HTTP errors.<br />
Terminal Binding Conditions These error conditions can be read by constrained clients. They are used for connection manager problems, abstracting stream errors, communication problems between the connection manager and the server, and invalid client requests (binding syntax errors, possible attacks, etc.)<br />
Recoverable Binding Conditions These report communication problems between the connection manager and the client. They do not terminate the session. Clients recover from these errors by resending all the preceding <body/> wrappers that have not received responses.<br />
Transported Protocol Conditions Errors relating to the XML payloads within <body/> wrappers are, in general, defined in the documentation of the protocol being transported. They do not terminate the session.<br />
<br />
Full descriptions are provided below.<br />
17.1 HTTP Conditions<br />
<br />
Note: All HTTP codes except 200 have been superseded by Terminal Binding Conditions to allow clients to determine whether the source of errors is the connection manager application or an HTTP intermediary.<br />
<br />
A legacy client (or connection manager) is a client (or connection manager) that did not include a 'ver' attribute in its session creation request (or response). A legacy client (or connection manager) will interpret (or respond with) HTTP error codes according to the table below. Non-legacy connection managers SHOULD NOT send HTTP error codes unless they are communicating with a legacy client. Upon receiving an HTTP error (400, 403, 404), a legacy client or any client that is communicating with a legacy connection manager MUST consider the HTTP session to be null and void. A non-legacy client that is communicating with a non-legacy connection manager MAY consider that the session is still active.<br />
<br />
Table 2: HTTP Error and Status Codes<br />
Code Name Superseded by Purpose<br />
200 OK - Response to valid client request.<br />
400 Bad Request bad-request Inform client that the format of an HTTP header or binding element is unacceptable (e.g., syntax error).<br />
403 Forbidden policy-violation Inform client that it has broken the session rules (polling too frequently, requesting too frequently, too many simultaneous requests).<br />
404 Not Found item-not-found Inform client that (1) 'sid' is not valid, (2) 'stream' is not valid, (3) 'rid' is larger than the upper limit of the expected window, (4) connection manager is unable to resend response, (5) 'key' sequence is invalid.<br />
<br />
Note: No other HTTP error and status codes were defined in the early versions of BOSH (e.g., Internal Server Error).<br />
17.2 Terminal Binding Conditions<br />
<br />
In any response it sends to the client, the connection manager MAY return a fatal error by setting a 'type' attribute of the <body/> element to "terminate". These binding errors imply that the HTTP session is terminated (unless a 'stream' attribute is specified -- see Multiple Stream Error Conditions).<br />
<br />
Note: Although many of these conditions are similar to the XMPP stream error conditions specified in RFC 6120, they are not to be confused with XMPP stream errors. In cases where BOSH is being used to transport XMPP, any fatal XMPP stream error conditions experienced between the connection manager and the XMPP server SHOULD only be reported using the "remote-stream-error" condition as described below.<br />
<br />
Example 32. Remote connection failed error<br />
<br />
HTTP/1.1 200 OK<br />
Content-Type: text/xml; charset=utf-8<br />
Content-Length: 68<br />
<br />
<body type='terminate'<br />
condition='remote-connection-failed'<br />
xmlns='http://jabber.org/protocol/httpbind'/><br />
<br />
The following values of the 'condition' attribute are defined:<br />
<br />
Table 3: Terminal Binding Error Conditions<br />
Condition Purpose<br />
bad-request* The format of an HTTP header or binding element received from the client is unacceptable (e.g., syntax error).<br />
host-gone The target domain specified in the 'to' attribute or the target host or port specified in the 'route' attribute is no longer serviced by the connection manager.<br />
host-unknown The target domain specified in the 'to' attribute or the target host or port specified in the 'route' attribute is unknown to the connection manager.<br />
improper-addressing The initialization element lacks a 'to' or 'route' attribute (or the attribute has no value) but the connection manager requires one.<br />
internal-server-error The connection manager has experienced an internal error that prevents it from servicing the request.<br />
item-not-found* (1) 'sid' is not valid, (2) 'stream' is not valid, (3) 'rid' is larger than the upper limit of the expected window, (4) connection manager is unable to resend response, (5) 'key' sequence is invalid.<br />
other-request Another request being processed at the same time as this request caused the session to terminate.<br />
policy-violation* The client has broken the session rules (polling too frequently, requesting too frequently, sending too many simultaneous requests).<br />
remote-connection-failed The connection manager was unable to connect to, or unable to connect securely to, or has lost its connection to, the server.<br />
remote-stream-error Encapsulates an error in the protocol being transported.<br />
see-other-uri The connection manager does not operate at this URI (e.g., the connection manager accepts only SSL or TLS connections at some https: URI rather than the http: URI requested by the client). The client can try POSTing to the URI in the content of the <uri/> child element.<br />
system-shutdown The connection manager is being shut down. All active HTTP sessions are being terminated. No new sessions can be created.<br />
undefined-condition The error is not one of those defined herein; the connection manager SHOULD include application-specific information in the content of the <body/> wrapper.<br />
<br />
* If the client did not include a 'ver' attribute in its session creation request then the connection manager SHOULD send a deprecated HTTP Error Condition instead of this terminal binding condition. If the connection manager did not include a 'ver' attribute in its session creation response then the client SHOULD expect it to send a deprecated HTTP Error Condition instead of this terminal binding condition.<br />
<br />
The following is an example of a "see-other-uri" condition:<br />
<br />
Example 33. See other URI error<br />
<br />
HTTP/1.1 200 OK<br />
Content-Type: text/xml; charset=utf-8<br />
Content-Length: 68<br />
<br />
<body condition='see-other-uri'<br />
type='terminate'<br />
xmlns='http://jabber.org/protocol/httpbind'><br />
<uri>https://secure.jabber.org/xmppcm</uri><br />
</body><br />
<br />
The following is an example including a "remote-stream-error" condition:<br />
<br />
Example 34. Remote error<br />
<br />
HTTP/1.1 200 OK<br />
Content-Type: text/xml; charset=utf-8<br />
Content-Length: 68<br />
<br />
<body condition='remote-stream-error'<br />
type='terminate'<br />
xmlns='http://jabber.org/protocol/httpbind'<br />
xmlns:stream='http://etherx.jabber.org/streams'><br />
<message from='contact@example.com'<br />
to='user@example.com'<br />
xmlns='jabber:client'><br />
<body>I said "Hi!"</body><br />
</message><br />
<stream:error><br />
<xml-not-well-formed xmlns='urn:ietf:params:xml:ns:xmpp-streams'/><br />
<text xmlns='urn:ietf:params:xml:ns:xmpp-streams'<br />
xml:lang='en'><br />
Some special application diagnostic information!<br />
</text><br />
<escape-your-data xmlns='application-ns'/><br />
</stream:error><br />
</body><br />
<br />
Naturally, the client MAY report binding errors to the connection manager as well, although this is unlikely.<br />
17.3 Recoverable Binding Conditions<br />
<br />
In any response it sends to the client, the connection manager MAY return a recoverable error by setting a 'type' attribute of the <body/> element to "error". These errors do not imply that the HTTP session is terminated.<br />
<br />
If it decides to recover from the error, then the client MUST repeat the HTTP request that resulted in the error, as well as all the preceding HTTP requests that have not received responses. The content of these requests MUST be identical to the <body/> elements of the original requests. This enables the connection manager to recover a session after the previous request was lost due to a communication failure.<br />
<br />
Example 35. Recoverable error<br />
<br />
HTTP/1.1 200 OK<br />
Content-Type: text/xml; charset=utf-8<br />
Content-Length: 68<br />
<br />
<body type='error'<br />
xmlns='http://jabber.org/protocol/httpbind'/><br />
<br />
17.4 XML Payload Conditions<br />
<br />
Application-level error conditions described in the documentation of the protocol being transported are routed to the client through the connection manager. They are transparent to the connection manager, and therefore out of scope for the transport binding defined herein.<br />
18. Implementation Notes<br />
18.1 HTTP Pipelining<br />
<br />
Even if the client requests HTTP Pipelining and the connection manager supports it, there is no guarantee that pipelining will succeed, because it might not be supported by intermediate proxies.<br />
<br />
The best the client can do is to request the use of HTTP Pipelining by setting the 'hold' attribute to a value of "1". If HTTP Pipelining does not work (because the server returns HTTP 1.0 or connection:close), then the client SHOULD degrade gracefully by using multiple connections.<br />
19. Security Considerations<br />
19.1 Connection Between Client and BOSH Service<br />
<br />
All communications between a client and a BOSH service SHOULD occur over encrypted HTTP connections. Negotiation of encryption between the client and the connection manager SHOULD occur at the transport layer or the HTTP layer, not the application layer; such negotiation SHOULD follow the HTTP/SSL protocol defined in SSL [28], although MAY follow the HTTP/TLS protocol defined in RFC 2818 [29] or the TLS Within HTTP protocol defined in RFC 2817 [30].<br />
<br />
If the HTTP connection used to send the initial session request is encrypted, then all the other HTTP connections used within the session MUST also be encrypted. Furthermore, if authentication certificates are exchanged when establishing the encrypted connection that is used to send the initial session request, then the client and/or connection manager SHOULD ensure that the same authentication certificates are employed for all subsequent connections used by the session. Once such a "secure session" has been established:<br />
<br />
* If the connection manager refuses to establish an encrypted connection or offers a different certificate, then the client SHOULD close the connection and terminate the session without sending any more requests.<br />
* If the client sends a wrapper element that is part of a "secure session" over a connection that either is not encrypted or uses a different certificate, then the connection manager SHOULD simply close the connection. The connection manager SHOULD NOT terminate the session since that would facilitate denial of service attacks.<br />
<br />
19.2 Connection Between BOSH Service and Application<br />
<br />
A BOSH service SHOULD encrypt its connection to the backend application using appropriate technologies such as Secure Sockets Layer (SSL), Transport Layer Security (TLS), and StartTLS if supported by the backend application. Alternatively, the BOSH service can be considered secure (1) if it is running on the same physical machine as the backend application or (2) if it running on the same private network as the backend application and the administrators are sure that unknown individuals or processes do not have access to that private network.<br />
<br />
If data privacy is desired, the client SHOULD encrypt its messages using an application-specific end-to-end encryption technology, because there is no way for the client to be sure that the BOSH service encrypts its connection to the application; methods for doing so are outside the scope of this specification.<br />
19.3 Unpredictable SID and RID<br />
<br />
The session identifier (SID) and initial request identifier (RID) are security-critical and therefore MUST be both unpredictable and nonrepeating (see RFC 1750 [31] for recommendations regarding randomness of SIDs and initial RIDs for security purposes).<br />
19.4 Use of SHA-1<br />
<br />
Recent research has shown that in select cases it is possible to compromise the hashes produced by the SHA-1 hashing algorithm (see RFC 4270 [32]). However, the use to which SHA-1 is put in BOSH will likely minimize the applicability of the attacks described in the literature. Furthermore, current estimates suggest that even with the recently-discovered attack, it would still take one year of computing by a government-sized entity to produce a collision.<br />
20. IANA Considerations<br />
<br />
TCP port 5280, conventially used for communication between BOSH clients and BOSH connection mangers, is registered with the Internet Assigned Numbers Authority (IANA) [33] in its port registry at IANA Port Numbers Registry [34], with a keyword of "xmpp-bosh". (Although use of this port is OPTIONAL, it is helpful to define this port in a standardized way so that BOSH clients can contact any given XMPP service via BOSH without the need either for DNS TXT records as described in Discovering Alternative XMPP Connection Methods [35] or for more advanced methods such as U-NAPTR.<br />
21. XMPP Registrar Considerations<br />
21.1 Protocol Namespaces<br />
<br />
The XMPP Registrar includes 'http://jabber.org/protocol/httpbind' in its registry of protocol namespaces.<br />
22. XML Schema<br />
<br />
<?xml version='1.0' encoding='UTF-8'?><br />
<br />
<xs:schema<br />
xmlns:xs='http://www.w3.org/2001/XMLSchema'<br />
xmlns:stream='http://etherx.jabber.org/streams'<br />
targetNamespace='http://jabber.org/protocol/httpbind'<br />
xmlns='http://jabber.org/protocol/httpbind'<br />
elementFormDefault='qualified'><br />
<br />
<xs:annotation><br />
<xs:documentation><br />
The protocol documented by this schema is defined in<br />
XEP-0124: http://www.xmpp.org/extensions/xep-0124.html<br />
</xs:documentation><br />
</xs:annotation><br />
<br />
<xs:import namespace='http://www.w3.org/XML/1998/namespace'<br />
schemaLocation='http://www.w3.org/2001/03/xml.xsd'/><br />
<br />
<xs:element name='body'><br />
<xs:complexType><br />
<xs:choice><br />
<xs:element name='uri'<br />
minOccurs='0'<br />
maxOccurs='1'<br />
type='xs:string'/><br />
<xs:any namespace='##other'<br />
minOccurs='0'<br />
maxOccurs='unbounded'<br />
processContents='lax'/><br />
</xs:choice><br />
<xs:attribute name='accept' type='xs:string' use='optional'/><br />
<xs:attribute name='ack' type='xs:positiveInteger' use='optional'/><br />
<xs:attribute name='authid' type='xs:string' use='optional'/><br />
<xs:attribute name='charsets' type='xs:NMTOKENS' use='optional'/><br />
<xs:attribute name='condition' use='optional'><br />
<xs:simpleType><br />
<xs:restriction base='xs:NCName'><br />
<xs:enumeration value='bad-request'/><br />
<xs:enumeration value='host-gone'/><br />
<xs:enumeration value='host-unknown'/><br />
<xs:enumeration value='improper-addressing'/><br />
<xs:enumeration value='internal-server-error'/><br />
<xs:enumeration value='item-not-found'/><br />
<xs:enumeration value='other-request'/><br />
<xs:enumeration value='policy-violation'/><br />
<xs:enumeration value='remote-connection-failed'/><br />
<xs:enumeration value='remote-stream-error'/><br />
<xs:enumeration value='see-other-uri'/><br />
<xs:enumeration value='system-shutdown'/><br />
<xs:enumeration value='undefined-condition'/><br />
</xs:restriction><br />
</xs:simpleType><br />
</xs:attribute><br />
<xs:attribute name='content' type='xs:string' use='optional'/><br />
<xs:attribute name='from' type='xs:string' use='optional'/><br />
<xs:attribute name='hold' type='xs:unsignedByte' use='optional'/><br />
<xs:attribute name='inactivity' type='xs:unsignedShort' use='optional'/><br />
<xs:attribute name='key' type='xs:string' use='optional'/><br />
<xs:attribute name='maxpause' type='xs:unsignedShort' use='optional'/><br />
<xs:attribute name='newkey' type='xs:string' use='optional'/><br />
<xs:attribute name='pause' type='xs:unsignedShort' use='optional'/><br />
<xs:attribute name='polling' type='xs:unsignedShort' use='optional'/><br />
<xs:attribute name='report' type='xs:positiveInteger' use='optional'/><br />
<xs:attribute name='requests' type='xs:unsignedByte' use='optional'/><br />
<xs:attribute name='rid' type='xs:positiveInteger' use='optional'/><br />
<xs:attribute name='route' type='xs:string' use='optional'/><br />
<xs:attribute name='sid' type='xs:string' use='optional'/><br />
<xs:attribute name='stream' type='xs:string' use='optional'/><br />
<xs:attribute name='time' type='xs:unsignedShort' use='optional'/><br />
<xs:attribute name='to' type='xs:string' use='optional'/><br />
<xs:attribute name='type' use='optional'><br />
<xs:simpleType><br />
<xs:restriction base='xs:NCName'><br />
<xs:enumeration value='error'/><br />
<xs:enumeration value='terminate'/><br />
</xs:restriction><br />
</xs:simpleType><br />
</xs:attribute><br />
<xs:attribute name='ver' type='xs:string' use='optional'/><br />
<xs:attribute name='wait' type='xs:unsignedShort' use='optional'/><br />
<xs:attribute ref='xml:lang' use='optional'/><br />
<xs:anyAttribute namespace='##other' processContents='lax'/><br />
</xs:complexType><br />
</xs:element><br />
<br />
</xs:schema><br />
<br />
<br />
23. Acknowledgements<br />
<br />
Thanks to Mike Cumings, Tomas Karasek, Tobias Markmann, Chris Seymour, Safa Sofuoğlu, Stefan Strigler, Matthew Wild, Kevin Winters, and Christopher Zorn for their feedback.<br />
Appendices<br />
Appendix A: Document Information<br />
<br />
Series: XEP<br />
Number: 0124<br />
Publisher: XMPP Standards Foundation<br />
Status: Draft<br />
Type: Standards Track<br />
Version: 1.10<br />
Last Updated: 2010-07-02<br />
Approving Body: XMPP Council<br />
Dependencies: RFC 1945, RFC 2616, RFC 3174<br />
Supersedes: None<br />
Superseded By: None<br />
Short Name: bosh<br />
Schema: <http://www.xmpp.org/schemas/httpbind.xsd><br />
Source Control: HTML RSS<br />
This document in other formats: XML PDF<br />
Appendix B: Author Information<br />
Ian Paterson<br />
<br />
Email: ian.paterson@clientside.co.uk<br />
JabberID: ian@zoofy.com<br />
Dave Smith<br />
<br />
Email: dizzyd@jabber.org<br />
JabberID: dizzyd@jabber.org<br />
Peter Saint-Andre<br />
<br />
Email: stpeter@jabber.org<br />
JabberID: stpeter@jabber.org<br />
URI: https://stpeter.im/<br />
Jack Moffitt<br />
<br />
Email: jack@chesspark.com<br />
JabberID: jack@chesspark.com<br />
Appendix C: Legal Notices<br />
Copyright<br />
This XMPP Extension Protocol is copyright © 1999 - 2011 by the XMPP Standards Foundation (XSF).<br />
Permissions<br />
Permission is hereby granted, free of charge, to any person obtaining a copy of this specification (the "Specification"), to make use of the Specification without restriction, including without limitation the rights to implement the Specification in a software program, deploy the Specification in a network service, and copy, modify, merge, publish, translate, distribute, sublicense, or sell copies of the Specification, and to permit persons to whom the Specification is furnished to do so, subject to the condition that the foregoing copyright notice and this permission notice shall be included in all copies or substantial portions of the Specification. Unless separate permission is granted, modified works that are redistributed shall not contain misleading information regarding the authors, title, number, or publisher of the Specification, and shall not claim endorsement of the modified works by the authors, any organization or project to which the authors belong, or the XMPP Standards Foundation.<br />
Disclaimer of Warranty<br />
## NOTE WELL: This Specification is provided on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, express or implied, including, without limitation, any warranties or conditions of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A PARTICULAR PURPOSE. ##<br />
Limitation of Liability<br />
In no event and under no legal theory, whether in tort (including negligence), contract, or otherwise, unless required by applicable law (such as deliberate and grossly negligent acts) or agreed to in writing, shall the XMPP Standards Foundation or any author of this Specification be liable for damages, including any direct, indirect, special, incidental, or consequential damages of any character arising from, out of, or in connection with the Specification or the implementation, deployment, or other use of the Specification (including but not limited to damages for loss of goodwill, work stoppage, computer failure or malfunction, or any and all other commercial damages or losses), even if the XMPP Standards Foundation or such author has been advised of the possibility of such damages.<br />
IPR Conformance<br />
This XMPP Extension Protocol has been contributed in full conformance with the XSF's Intellectual Property Rights Policy (a copy of which can be found at <http://xmpp.org/extensions/ipr-policy.shtml> or obtained by writing to XMPP Standards Foundation, 1899 Wynkoop Street, Suite 600, Denver, CO 80202 USA).<br />
Appendix D: Relation to XMPP<br />
<br />
The Extensible Messaging and Presence Protocol (XMPP) is defined in the XMPP Core (RFC 3920) and XMPP IM (RFC 3921) specifications contributed by the XMPP Standards Foundation to the Internet Standards Process, which is managed by the Internet Engineering Task Force in accordance with RFC 2026. Any protocol defined in this document has been developed outside the Internet Standards Process and is to be understood as an extension to XMPP rather than as an evolution, development, or modification of XMPP itself.<br />
Appendix E: Discussion Venue<br />
<br />
The primary venue for discussion of XMPP Extension Protocols is the <standards@xmpp.org> discussion list.<br />
<br />
Discussion on other xmpp.org discussion lists might also be appropriate; see <http://xmpp.org/about/discuss.shtml> for a complete list.<br />
<br />
Given that this XMPP Extension Protocol normatively references IETF technologies, discussion on the <xsf-ietf@xmpp.org> list might also be appropriate.<br />
<br />
Errata can be sent to <editor@xmpp.org>.<br />
Appendix F: Requirements Conformance<br />
<br />
The following requirements keywords as used in this document are to be interpreted as described in RFC 2119: "MUST", "SHALL", "REQUIRED"; "MUST NOT", "SHALL NOT"; "SHOULD", "RECOMMENDED"; "SHOULD NOT", "NOT RECOMMENDED"; "MAY", "OPTIONAL".<br />
Appendix G: Notes<br />
<br />
1. RFC 793: Transmission Control Protocol <http://tools.ietf.org/html/rfc0793>.<br />
<br />
2. RFC 1945: Hypertext Transfer Protocol -- HTTP/1.0 <http://tools.ietf.org/html/rfc1945>.<br />
<br />
3. RFC 2616: Hypertext Transport Protocol -- HTTP/1.1 <http://tools.ietf.org/html/rfc2616>.<br />
<br />
4. Bayeux Protocol <http://svn.cometd.org/trunk/bayeux/bayeux.html>.<br />
<br />
5. The Web Socket Protocol <http://tools.ietf.org/html/draft-hixie-thewebsocketprotocol>.<br />
<br />
6. Reverse HTTP <http://tools.ietf.org/html/draft-lentczner-rhttp>.<br />
<br />
7. RFC 2965: HTTP State Management Mechanism <http://tools.ietf.org/html/rfc2965>.<br />
<br />
8. Requiring cookies is sub-optimal because several significant computing platforms provide only limited access to underlying HTTP requests/responses; worse, some platforms hide or remove cookie-related headers.<br />
<br />
9. XEP-0025: Jabber HTTP Polling <http://xmpp.org/extensions/xep-0025.html>.<br />
<br />
10. RFC 6120: Extensible Messaging and Presence Protocol (XMPP): Core <http://tools.ietf.org/html/rfc6120>.<br />
<br />
11. XEP-0206: XMPP Over BOSH <http://xmpp.org/extensions/xep-0206.html>.<br />
<br />
12. In order to reduce network congestion, RFC 2616 recommends that clients SHOULD NOT keep more than two HTTP connections to the same HTTP server open at the same time. Clients running in constrained enviroments typically have no choice but to abide by that recommendation.<br />
<br />
13. If there is no traffic other than the "pings" then bandwidth consumption will be double that of a TCP connection (although double nothing is still nothing). If data is sent in large packets then bandwidth consumption will be almost identical.<br />
<br />
14. Extensible Markup Language (XML) 1.0 (Fourth Edition) <http://www.w3.org/TR/REC-xml/>.<br />
<br />
15. Namespaces in XML <http://www.w3.org/TR/REC-xml-names/>.<br />
<br />
16. RFC 4627: The application/json Media Type for JavaScript Object Notation (JSON) <http://tools.ietf.org/html/rfc4627>.<br />
<br />
17. Extensible Markup Language (XML) 1.0 (Fourth Edition) <http://www.w3.org/TR/REC-xml/>.<br />
<br />
18. Although the syntax of the 'route' attribute bears a superficial resemblance to a URI or IRI, it is not a URI/IRI and MUST NOT be processed in accordance with the rules specified in RFC 3986, RFC 3987, or (for XMPP) RFC 5122.<br />
<br />
19. Each character set name (or character encoding name -- we use the terms interchangeably) SHOULD be of type NMTOKEN, where the names are separated by the white space character #x20, resulting in a tokenized attribute type of NMTOKENS (see Section 3.3.1 of XML 1.0 [20]). Strictly speaking, the Character Sets registry maintained by the Internet Assigned Numbers Authority (see <http://www.iana.org/assignments/character-sets>) allows a character set name to contain any printable US-ASCII character, which might include characters not allowed by the NMTOKEN construction of XML 1.0; however, the only existing character set name which includes such a character is "NF_Z_62-010_(1973)".<br />
<br />
20. Extensible Markup Language (XML) 1.0 (Fourth Edition) <http://www.w3.org/TR/REC-xml/>.<br />
<br />
21. 9007199254740991 is 253-1. Some weakly typed languages use IEEE Standard 754 Doubles to represent all numbers. These Doubles cannot represent integers above 253 accurately.<br />
<br />
22. RFC 3174: US Secure Hash Algorithm 1 (SHA1) <http://tools.ietf.org/html/rfc3174>.<br />
<br />
23. Therefore a client and a connection manager will be compatible even if one or the other offers no support for multi-stream sessions.<br />
<br />
24. The 'rid' attribute is always incremented normally without reference to any 'stream' attribute.<br />
<br />
25. This helps to ensure backwards-compatibility with older implementations.<br />
<br />
26. Each HTTP response MUST belong to the same session as the request that triggered it, but not necessarily to the same stream.<br />
<br />
27. The broadcast payloads can be of any type.<br />
<br />
28. SSL V3.0 <http://wp.netscape.com/eng/ssl3/draft302.txt>.<br />
<br />
29. RFC 2818: HTTP Over TLS <http://tools.ietf.org/html/rfc2818>.<br />
<br />
30. RFC 2817: Upgrading to TLS Within HTTP/1.1 <http://tools.ietf.org/html/rfc2817>.<br />
<br />
31. RFC 1750: Randomness Recommendations for Security <http://tools.ietf.org/html/rfc1750>.<br />
<br />
32. RFC 4270: Attacks on Cryptographic Hashes in Internet Protocols <http://tools.ietf.org/html/rfc4270>.<br />
<br />
33. The Internet Assigned Numbers Authority (IANA) is the central coordinator for the assignment of unique parameter values for Internet protocols, such as port numbers and URI schemes. For further information, see <http://www.iana.org/>.<br />
<br />
34. IANA registry of port numbers <http://www.iana.org/assignments/port-numbers>.<br />
<br />
35. XEP-0156: Discovering Alternative XMPP Connection Methods <http://xmpp.org/extensions/xep-0156.html>.<br />
Appendix H: Revision History<br />
<br />
Note: Older versions of this specification might be available at http://xmpp.org/extensions/attic/<br />
Version 1.10 (2010-07-02)<br />
<br />
Further clarified use of 'from' and 'to' attributes; added missing condition values to the schema.<br />
(psa)<br />
Version 1.9 (2009-11-06)<br />
<br />
Added information for registration of port 5280 with IANA.<br />
(psa)<br />
Version 1.8 (2009-04-30)<br />
<br />
Removed secure attribute because it did not solve the problem it was intended to solve; added security consideration regarding link between connection manager and application server; changed "stanza" to "payload" for disambiguation with XMPP; clarified design objectives and relationship to similar technologies; corrected several errors in the schema.<br />
(psa/jm)<br />
Version 1.7 (2008-10-29)<br />
<br />
Moved alternative script syntax to historical specification; added implementation note about HTTP Pipelining; adjusted architectural description.<br />
(psa)<br />
Version 1.6 (2007-02-21)<br />
<br />
Multiple clarifications and restructuring without changes to protocol itself; changed title to BOSH; added section that fully explains the technique underlying the protocol; separated XMPP-specific features into new XEP-0206; added optional new Script Syntax and session pauses; added Acknowledgements section; added from and ver attributes; added hold attribute to session creation response; clarified polling too-frequently error; recommended that clients use HTTP Pipelining.<br />
(ip)<br />
Version 1.5 (2006-04-28)<br />
<br />
Added optional Multiple Streams section; added security considerations about encrypted HTTP connections; recommended use of SSL rather than HTTP over TLS; specified that request ID values must not exceed 9007199254740991; corrected datatypes of inactivity, polling, rid, and wait attributes in the schema; added <any/> and <anyAttribute/> elements to schema to optionally support non-XMPP XML elements and attributes; deprecated HTTP error codes in favor of new terminal binding conditions.<br />
(ip/psa)<br />
Version 1.4 (2005-12-14)<br />
<br />
Modified syntax of route attribute to be proto:host:port rather than XMPP URI/IRI.<br />
(psa)<br />
Version 1.3 (2005-11-02)<br />
<br />
Corrected stream:features namespace and the Recoverable Binding Conditions section; recommended that connection manager shall return secure attribute to client; recommended end-to-end encryption through proxy connection managers.<br />
(ip)<br />
Version 1.2 (2005-06-16)<br />
<br />
Specified optional use of route and secure attributes in session request. Minor correction: the stream features element should be included in the response that contains the authid attribute (this is not necessarily the session creation response).<br />
(ip)<br />
Version 1.1 (2005-06-02)<br />
<br />
Specified optional use of HTTP Accept-Encoding and Content-Encoding headers for compression at HTTP binding level.<br />
(ip)<br />
Version 1.0 (2005-03-03)<br />
<br />
Per a vote of the Jabber Council, advanced status to Draft.<br />
(psa)<br />
Version 0.10 (2004-11-08)<br />
<br />
Changed HTTP 401 errors to HTTP 404.<br />
(ip)<br />
Version 0.9 (2004-10-26)<br />
<br />
Added charset attribute.<br />
(ip/psa)<br />
Version 0.8 (2004-10-26)<br />
<br />
Specified that wait attribute must be included in the session creation response.<br />
(ip)<br />
Version 0.7 (2004-08-12)<br />
<br />
Defined appropriate XMPP stanza error conditions.<br />
(psa/ip)<br />
Version 0.6 (2004-07-19)<br />
<br />
Added xml:lang attribute to the session request; added recoverable binding error conditions.<br />
(ip)<br />
Version 0.5 (2004-05-07)<br />
<br />
Protocol refactored to enable simultaneous requests (request identifier attribute, wait attribute, hold attribute, requests attribute) and recovery of broken connections; added content attribute; removed all wrapper types except 'terminate'; updated error handling; made key mechanism optional (should use SSL/TLS instead).<br />
(ip/psa)<br />
Version 0.4 (2004-02-23)<br />
<br />
Fixed typos; removed "resource-constraint" binding error; added HTTP 403 error to table.<br />
(psa/ip)<br />
Version 0.3 (2004-02-19)<br />
<br />
Added 'authid' attribute to enable communication of XMPP stream ID (used in digest authentication); specified that Content-Types other than "text/xml" are allowed to support older HTTP clients; specified business rule for connection manager queueing of client requests; changed <packet/> to <body/> to support older HTTP clients; changed 'to' attribute on initialization element from MAY to SHOULD; recommended inclusion of unavailable presence in termination element sent from client; described architectural assumptions; specified binding-specific error handling.<br />
(psa/ip)<br />
Version 0.2 (2004-01-13)<br />
<br />
Added 'to' attribute on the initialization element; specified that 'text/html' is allowable for backwards-compatibility.<br />
(dss/psa/ip)<br />
Version 0.1 (2003-11-06)<br />
<br />
Initial version.<br />
(dss/psa)<br />
<br />
END</div>
Snowqiang
http://wiki.jabbercn.org/Ejabberd2:%E5%AE%89%E8%A3%85%E5%92%8C%E6%93%8D%E4%BD%9C%E6%8C%87%E5%8D%97
Ejabberd2:安装和操作指南
2011-05-18T12:40:03Z
<p>Snowqiang: 删广告</p>
<hr />
<div>[[Category:XMPP服务器]]<br />
[[Category:已翻译]]<br />
<br />
'''本文的英文原文来自 http://www.process-one.net/en/ejabberd/guide_en '''<br />
<br />
'''ejabberd 2.1.4 安装和管理指南'''<br />
<br />
==绪论==<br />
<br />
ejabberd是一个用[http://www.erlang.org/ Erlang/OTP]语言写的自由和开源的即时消息服务器.<br />
<br />
ejabberd是跨平台,分布式, 容错, 并基于开放标准的实时通讯系统.<br />
<br />
ejabberd的设计坚若磐石,是一个功能服丰富的XMPP服务器.<br />
<br />
ejabberd同时适合小规模布署和超大规模布署, 无论它们是否需要可伸缩性.<br />
<br />
===关键功能===<br />
<br />
ejabberd是:<br />
<br />
* 跨平台的: ejabberd可以运行在Microsoft Windows和Unix派生系统,例如Linux, FreeBSD和NetBSD.<br />
* 分布式的: 你可以在一个集群的机器上运行ejabberd,并且所有的机器都服务于同一个或一些Jabbe域. 当你需要更大容量的时候,你可以简单地增加一个廉价节点到你的集群里. 因此, 你不需要买一个昂贵的高端机器来支持上万个并发用户.<br />
* 容错: 你可以布署一个ejabberd集群,这样一个正常运行的服务的所有必需信息将被复制到所有节点. 这意味着如果其中一个节点崩溃了, 其他节点将无中断的继续运行. 另外, 也可以‘不停机’增加或更换节点.<br />
* 易于管理: ejabberd建立于开源的Erlang. 所以你不需要安装外部服数据库, 外部web服务器, 除此以外因为每个东西都已经包含在里面, 并且处于开箱可用状态. 其他管理上的好处包括:<br />
** 详尽的文档.<br />
** 便捷的安装程序,包括在Linux, Mac OS X, 以及Windows系统下.<br />
** Web管理.<br />
** 共享名册组.<br />
** 命令行管理工具.<br />
** 可外部集成的验证机制.<br />
** 发送匿名消息的能力. <br />
* 国际化: ejabberd领导国际化. 非常适合全球化. 相关功能包括:<br />
** 翻译成25种语言.<br />
** 支持[http://www.ietf.org/rfc/rfc3490.txt IDNA]. <br />
* 开放标准: ejabberd是的一个完全支持XMPP标准的开源Jabber服务器.<br />
** 完全兼容XMPP.<br />
** 基于XML的协议.<br />
** 支持的[http://www.ejabberd.im/protocols 协议]很多.<br />
<br />
===额外功能===<br />
<br />
而且, ejabberd广泛支持的其他先进特性:<br />
<br />
* 模块化<br />
** 只装在你想要的模块.<br />
** 在你自己的自定义模块扩展ejabberd. <br />
* 安全性<br />
** 支持c2s和s2s连接的SASL和STARTTLS.<br />
** 支持s2s连接的STARTTLS和Dialback.<br />
** 可通过HTTPS安全访问的Web管理. <br />
* 数据库<br />
** 快速布署的内部数据库(Mnesia).<br />
** 原生的MySQL支持.<br />
** 原生的PostgreSQL支持.<br />
** 支持ODBC数据存储.<br />
** 支持Microsoft SQL Server. <br />
* 验证<br />
** 内部验证.<br />
** PAM, LDAP 和 ODBC.<br />
** 外部验证脚本. <br />
* 其他<br />
** 支持虚拟主机.<br />
** XML流压缩 ([http://xmpp.org/extensions/xep-0138.html XEP-0138]).<br />
** 统计 ([http://xmpp.org/extensions/xep-0039.html XEP-0039]).<br />
** 支持IPv6的c2s和s2s连接.<br />
** 支持集群和HTML日志的[[XEP-0045|多用户聊天]]模块.<br />
** 基于用户vCards的用户目录.<br />
** 支持[http://xmpp.org/extensions/xep-0163.html 基于PubSub的个人事件]的[http://xmpp.org/extensions/xep-0060.html 发行-订阅]组件.<br />
** 支持web客户端: [http://xmpp.org/extensions/xep-0025.html HTTP轮询]和[http://xmpp.org/extensions/xep-0206.html HTTP绑定(BOSH)]服务.<br />
** IRC网关.<br />
** 组件支持: 安装特定网关之后和外部网络的接口,如 AIM, ICQ 和 MSN.<br />
<br />
==安装Installing ejabberd==<br />
===用ejabberd二进制安装包安装===<br />
<br />
最简单的安装ejabberd即时消息服务器的方法可能是使用ProcessOne发布的二进制安装包. 已发布的ejabberd版本的二进制安装包在 ProcessOne ejabberd 下载页可以找到: http://www.process-one.net/en/ejabberd/downloads<br />
<br />
安装包将布署和配置一个完整的不需要任何依赖的ejabberd服务器.<br />
<br />
在 *nix 系统里, 记住启动之前把二进制安装包文件的属性设置成可执行的. 例如:<br />
<br />
<source lang="bash"><br />
chmod +x ejabberd-2.0.0_1-linux-x86-installer.bin<br />
./ejabberd-2.0.0_1-linux-x86-installer.bin<br />
</source><br />
<br />
ejabberd可以任何时候手工启动, 或在系统启动时由操作系统自动启动.<br />
<br />
要手动启动和停止, 可使用安装包建立的桌面快捷方式. 如果机器没有图形系统, 使用在ejabberd安装目录下的 ’bin’ 目录脚本 ’start’ 和 ’stop’.<br />
<br />
Windows安装包把ejabberd安装成了系统服务, 同时有一个快捷方式可以启动一个调试控制台给有经验的管理员使用. 如果你想ejabberd在开机时自动启动, 进入Windows服务设置界面并把ejabberd设置成自动启动. 注意Windows服务还是一个开发中的特性, 例如它不能读取ejabberdctl.cfg文件.<br />
<br />
在一个 *nix 系统, 如果你想ejabberd在开机时启动成为一个服务, 从 ’bin’目录拷贝 ejabberd.init 到类似 /etc/init.d/ejabberd (取决于你的操作系统的把本). 新建一个系统用户 ejabberd; 它将用于启动该服务的脚本. 然后你可以以root身份调用 /etc/inid.d/ejabberd 来启动服务.<br />
<br />
如果ejabberd不能在Windows里正确地启动, 尝试用启动菜单或桌面的快捷方式启动它. 如果window显式错误14001, 解决方案是安装: "Microsoft Visual C++ 2005 SP1 Redistributable Package". 你可以从 http://www.microsoft.com/ 下载它. 然后卸载并再次安装ejabberd.<br />
<br />
如果ejabberd不能正确启动并且生成一个崩溃的dump, 表示有严重问题. 在Windows下你可以尝试使用 bin/live.bat 脚本启动ejabberd, 或在其它操作系统执行命令 bin/ejabberdctl live . 用这个办法你可以看到Erlang提供的错误消息并且辨别出确切的问题.<br />
<br />
ejabberdctl管理脚本位于 bin 目录. 关于ejabberdctl和用于微调Erlang运行时系统的可配置选项,详见 [[Ejabberd2:安装和操作指南#ejabberdctl|4.1]] 章.<br />
<br />
===用操作系统特定的包安装ejabberd===<br />
<br />
一些操作系统提供了特定的适应系统体系结构和库的ejabberd包. 它经常也会检查依赖的包并执行基本的配置任务,类似新建初始管理帐号. 例如Debian和Gentoo. 更多信息请查找你的操作系统提供的资源.<br />
<br />
那些包经常新建一个脚本,类似 /etc/init.d/ejabberd,在开机时启动和停止 ejabberd 服务.<br />
<br />
===用CEAN安装ejabberd===<br />
<br />
[http://cean.process-one.net/ CEAN] (Comprehensive Erlang Archive Network) 是一个存放了很多Erlang程序二进制包的仓库,包括了ejabberd和它所有的依赖包. 这些二进制包可用于多种不同的系统结构, 所以对于二进制安装包和操作系统的ejabberd包来说,这是一个备选.<br />
<br />
根据你如何处理你的CEAN安装而定,你需要新建自己的 ejabberd 启动脚本. 缺省的ejabberdctl脚本位于 ejabberd 的 priv 目录并且用作一个示例.<br />
<br />
===从源码安装ejabberd===<br />
<br />
发布ejabberd稳定版的规范方式是源码包. 从源码编译ejabberd在 *nix 系统是非常容易的, 只要你的系统拥有所有的依赖包.<br />
<br />
====需求====<br />
<br />
为了在一个‘类Unix’ 操作系统编译ejabberd, 你需要:<br />
<br />
* GNU Make<br />
* GCC<br />
* Libexpat 1.95 或更高版本<br />
* Erlang/OTP R10B-9 或更高版本. 推荐的版本是 R12B-5. 对 R13 的支持是实验性质的.<br />
* OpenSSL 0.9.6 或更高版本, 用于 STARTTLS, SASL 和 SSL 加密. 可选的, 高度推荐.<br />
* Zlib 1.2.3 或更高版本, 用于支持流压缩 ([http://xmpp.org/extensions/xep-0138.html XEP-0138]). 可选的.<br />
* Erlang mysql library. 可选的. 用于支持 MySQL 验证或存储. 见 [[Ejabberd2:安装和操作指南#MySQL|3.2.1]] 节.<br />
* Erlang pgsql library. 可选的. 用于支持 PostgreSQL 验证或存储. 见 [[Ejabberd2:安装和操作指南#PostgreSQL|3.2.3]] 节.<br />
* PAM library. 可选的. 用于F 可插拔的验证模块 (PAM). 见 [[Ejabberd2:安装和操作指南#PAM验证|3.1.4]] 节.<br />
* GNU Iconv 1.8 或更高版本, 用于 IRC 网关 (mod_irc). 可选的. 在系统里不需要 GNU Libc. 见 [[Ejabberd2:安装和操作指南#mod_irc|3.3.8]] 节.<br />
* ImageMagick’s 转换程序. 可选的. 用于 CAPTCHA 挑战. 见 [[Ejabberd2:安装和操作指南#CAPTCHA|3.1.8]] 节.<br />
* exmpp 0.9.2 或更高版本. 可选的. 用于以 [http://xmpp.org/extensions/xep-0227.html XEP-0227] XML文件格式导入/导出用户数据.<br />
<br />
====下载源码====<br />
<br />
ejabberd的发布版本在 ProcessOne ejabberd 下载页: http://www.process-one.net/en/ejabberd/downloads<br />
<br />
另外, 最新的开发源码可使用命令行从 Git 仓库获得:<br />
<br />
<source lang="bash"><br />
git clone git://git.process-one.net/ejabberd/mainline.git ejabberd<br />
cd ejabberd<br />
git checkout -b 2.1.x origin/2.1.x<br />
</source><br />
<br />
====编译====<br />
<br />
编译ejabberd可执行以下命令:<br />
<br />
<source lang="bash"><br />
./configure<br />
make<br />
</source><br />
<br />
编译配置脚本允许很多选项. 要获得所有选项列表执行以下命令:<br />
<br />
<source lang="bash"><br />
./configure --help<br />
</source><br />
<br />
一些你可能有兴趣修改的选项如下:<br />
<br />
'''--prefix=/'''<br />
<br />
指定运行make install命令时文件将要拷贝的路径.<br />
<br />
'''--enable-user[=USER]'''<br />
<br />
允许普通系统用户执行ejabberdctl脚本 (参见 [[Ejabberd2:安装和操作指南#ejabberd|4.1]] 节), 读取配置, 读写 spool 目录, 读写 log 目录. 这个帐号的用户和组必须在运行make install之前就存在于机器上. 这个帐号不需要一个暴露的 HOME 目录, 因为缺省将使用 /var/lib/ejabberd/ .<br />
<br />
'''--enable-pam'''<br />
<br />
允许PAM验证方法 (参见 [[Ejabberd2:安装和操作指南#PAM验证|3.1.4]] 节).<br />
<br />
'''--enable-odbc or --enable-mssql'''<br />
<br />
如果你想使用外部数据库则需要这个选项. 详见 [[Ejabberd2:安装和操作指南#数据库和LDAP配置|3.2]] 节.<br />
<br />
'''--enable-full-xml'''<br />
<br />
允许使用基于XML的优化. 例如它将使用 CDATA 来逃逸 XMPP 流中的字符串. 只有你确定你的XMPP客户端有一个全兼容的XML分析器才使用这个选项.<br />
<br />
'''--disable-transient-supervisors'''<br />
<br />
对临时进程禁止使用Erlang/OTP监督.<br />
<br />
====安装====<br />
<br />
安装ejabberd到目标目录, 执行以下命令:<br />
<br />
<source lang="bash"><br />
make install<br />
</source><br />
<br />
注意安装ejabberd的时候你可能需要系统管理员的权限.<br />
<br />
缺省的新建文件和目录如下:<br />
<br />
'''/etc/ejabberd/'''<br />
配置文件目录:<br />
'''ejabberd.cfg'''<br />
ejabberd配置文件<br />
'''ejabberdctl.cfg'''<br />
管理脚本配置文件<br />
'''inetrc'''<br />
网络DNS配置文件<br />
<br />
'''/lib/ejabberd/'''<br />
'''ebin/'''<br />
Erlang二进制文件(*.beam) <br />
'''include/'''<br />
Erlang头文件(*.hrl) <br />
'''priv/'''<br />
运行时需要的其他文件<br />
'''bin/'''<br />
可执行程序<br />
'''lib/'''<br />
二进制系统文件(*.so) <br />
'''msgs/'''<br />
翻译文件(*.msgs) <br />
<br />
'''/sbin/ejabberdctl'''<br />
管理脚本(见 [[Ejabberd2:安装和操作指南#ejabberdctl|4.1]] 节) <br />
<br />
'''/share/doc/ejabberd/'''<br />
ejabberd文档<br />
<br />
'''/var/lib/ejabberd/'''<br />
Spool目录:<br />
'''.erlang.cookie'''<br />
Erlang cookie文件(见 [[Ejabberd2:安装和操作指南# Erlang Cookie|5.3]] 节) <br />
'''acl.DCD, ...'''<br />
Mnesia数据库spool文件(*.DCD, *.DCL, *.DAT) <br />
<br />
'''/var/log/ejabberd/'''<br />
日志目录(见 [[Ejabberd2:安装和操作指南#日志文件|7.1]] 节):<br />
'''ejabberd.log'''<br />
ejabberd服务日志<br />
'''erlang.log'''<br />
Erlang/OTP系统日志<br />
<br />
====启动====<br />
<br />
你可以使用ejabberdctl命令行管理脚本来启动和停止ejabberd. 如果你提供了配置选项 --enable-user=USER (见 [[Ejabberd2:安装和操作指南#编译|2.4.3]] 节), 你可以以那个系统帐号或root的身份执行ejabberdctl.<br />
<br />
用法示例:<br />
<br />
<source lang="bash"><br />
ejabberdctl start<br />
<br />
ejabberdctl status<br />
The node ejabberd@localhost is started with status: started<br />
ejabberd is running in that node<br />
<br />
ejabberdctl stop<br />
</source><br />
<br />
如果ejabberd无法启动并生成一个崩溃dump, 表示有严重问题. 你可以尝试使用命令ejabberdctl live启动ejabberd来查看由Erlang提供的出错信息并识别出确切的问题.<br />
<br />
关于ejabberdctl和微调Erlang运行时系统的可配置选项,详见 [[Ejabberd2:安装和操作指南#ejabberdctl|4.1]] 节.<br />
<br />
如果你希望ejabberd在开机时以服务身份启动, 拷贝 ejabberd.init 到类似 /etc/init.d/ejabberd 目录(取决于你的操作系统版本). 新建一个系统用户ejabberd; 它将被启动该服务的脚本使用. 然后你可以以root身份在开机时调用 /etc/inid.d/ejabberd 来启动该服务.<br />
<br />
====BSD的具体说明====<br />
<br />
在BSD系统编译ejabberd的命令为:<br />
<br />
<source lang="xml"><br />
gmake<br />
</source><br />
<br />
====Sun Solaris的具体说明====<br />
<br />
你需要一个GNU install, 但是Solaris里没有带. 如果你的Solaris系统是为 [http://www.blastwave.org/ blastwave.org] 包仓库配置的,这将很容易安装. 确保 /opt/csw/bin 目录在你的 PATH 参数里,然后运行:<br />
<br />
<source lang="bash"><br />
pkg-get -i fileutils<br />
</source><br />
<br />
如果那个软件名为 ginstall, 修改 ejabberd Makefile 脚本以适应你的系统, 例如:<br />
<br />
<source lang="bash"><br />
cat Makefile | sed s/install/ginstall/ > Makefile.gi<br />
</source><br />
<br />
最终这样安装ejabberd:<br />
<br />
<source lang="bash"><br />
gmake -f Makefile.gi ginstall<br />
</source><br />
<br />
====Microsoft Windows的具体说明====<br />
=====需求=====<br />
<br />
要在一个Microsoft Windows系统里编译ejabberd, 你需要:<br />
<br />
* MS Visual C++ 6.0 Compiler<br />
* [http://www.erlang.org/download.html Erlang/OTP R11B-5]<br />
* [http://sourceforge.net/project/showfiles.php?group_id=10127&package_id=11277 Expat 2.0.0或更高版本]<br />
* [http://www.gnu.org/software/libiconv/ GNU Iconv 1.9.2 (可选的)]<br />
* [http://www.slproweb.com/products/Win32OpenSSL.html Shining Light OpenSSL 0.9.8d或更高版本(使能SSL连接)]<br />
* [http://www.zlib.net/ Zlib 1.2.3或更高版本]<br />
<br />
=====编译=====<br />
<br />
我们假定你将把很多库文件尽可能放在 C:\sdk\ 目录,这样更容易跟踪为了安装ejabberd都需要些什么.<br />
<br />
1. 安装 Erlang emulator (例如, 在 C:\sdk\erl5.5.5).<br />
<br />
2. 安装 Expat 库文件到 C:\sdk\Expat-2.0.0 目录.<br />
<br />
拷贝文件 C:\sdk\Expat-2.0.0\Libs\libexpat.dll 到你的Windows系统目录(例如, C:\WINNT 或 C:\WINNT\System32)<br />
<br />
3. 编译和安装 Iconv 库到目录 C:\sdk\GnuWin32.<br />
<br />
拷贝文件 C:\sdk\GnuWin32\bin\lib*.dll 到你的Windows系统目录(更多安装指引可在iconv分发版的 README.woe32 文件找到 ).<br />
<br />
注意: 也可以不拷贝 libexpat.dll 和 iconv.dll 到Windows系统目录, 而是把目录 C:\sdk\Expat-2.0.0\Libs 和 C:\sdk\GnuWin32\bin 加到 PATH 环境变量去.<br />
<br />
4. 安装 OpenSSL 到 C:\sdk\OpenSSL 目录并增加 C:\sdk\OpenSSL\lib\VC 到你的环境变量或拷贝二进制文件到你的系统目录.<br />
<br />
5. 安装 ZLib 到 C:\sdk\gnuWin32 目录. 拷贝 C:\sdk\GnuWin32\bin\zlib1.dll 到你的系统目录. 如果你修改了你的 path ,它应该在安装 libiconv 之后已经设置好了.<br />
<br />
6. 确保你能从你的路径访问Erlang二进制文件. 例如: set PATH=%PATH%;"C:\sdk\erl5.6.5\bin"<br />
<br />
7. 取决于你如果结束实际的库文件安装,你可能需要在文件configure.erl中检查和调整路径.<br />
<br />
8. 在目录ejabberd\src中运行:<br />
<br />
<source lang="bash"><br />
configure.bat<br />
nmake -f Makefile.win32<br />
</source><br />
<br />
9. 编辑文件 ejabberd\src\ejabberd.cfg 并运行 <br />
<br />
<source lang="bash"><br />
werl -s ejabberd -name ejabberd<br />
</source><br />
<br />
===新建XMPP管理帐号===<br />
<br />
你需要一个XMPP帐号并赋予他管理权限来进行ejabberd Web管理:<br />
<br />
1. 在你的ejabberd服务器注册一个XMPP帐号, 例如admin1@example.org. 有两个办法来注册一个XMPP帐号:<br />
<br />
:1.1. 使用ejabberdctl (见 4.1 节):<br />
<br />
<source lang="bash"><br />
ejabberdctl register admin1 example.org FgT5bk3<br />
</source><br />
<br />
:1.2. 使用一个XMPP客户端进行带内注册(见 3.3.18 节). <br />
<br />
2. 编辑ejabberd配置文件来给你创建的XMPP帐号赋予管理权限:<br />
<br />
<source lang="text"><br />
{acl, admins, {user, "admin1", "example.org"}}.<br />
{access, configure, [{allow, admins}]}.<br />
</source><br />
<br />
你可以赋予管理权限给多个XMPP帐号, 也可以赋予权限给其他XMPP服务器.<br />
<br />
3. 重启ejabberd以装载新配置.<br />
<br />
4. 用你的浏览器打开Web管理界面(http://server:port/admin/). 确保键入了完整的JID作为用户名(在这个例子里是: admin1@example.org. 你需要加一个后缀的原因是因为ejabberd支持虚拟主机.<br />
<br />
===升级ejabberd===<br />
<br />
要升级一个ejabberd安装到一个新版本, 简单地卸载这个旧版本, 然后安装新版本就可以了. 当然, 重要的是配置文件和Mnesia数据库spool目录不能删除.<br />
<br />
在它需要的时候ejabberd在启动时会自动更新Mnesia数据表. 如果你也使用一个外部数据库来存储一些模块, 检查新的ejabberd版本的发布备注(release notes)是否指出也需要更新那些表.<br />
<br />
==配置ejabberd==<br />
===基本配置===<br />
<br />
配置文件将在你第一次启动ejabberd时装载. 从该文件获得的内容将被解析并存储到内部的ejabberd数据库. 以后的配置将从数据库装载,并且任何配置文件里的命令都会被添加到数据库里.<br />
<br />
注意 ejabberd永远不编辑配置文件. 所以, 使用Web管理修改的配置被存储在数据库, 而不是反射到配置文件. 如果你想那些修改在ejabberd重启后还有效, 你可以同时也修改配置文件, 或删除它的所有内容.<br />
<br />
配置文件包含一系列Erlang条款. 以‘%’ 标志开始的行被忽略. 每个条款是一组元素,第一个元素是一个选项的名称, 任何更多的元素则是该选项的值. 如果配置文件不包含类似‘hosts’选项, 旧的存储在数据库的主机名(s)将被启用.<br />
<br />
你可以重写存储在数据库的值,通过在配置文件的开始部分增加下面几行:<br />
<br />
<source lang="ini"><br />
override_global.<br />
override_local.<br />
override_acls.<br />
</source><br />
<br />
有了这些行,旧的全局选项(在一个集群的所有ejabberd节点之间分享), 本地选项(特有的用于本地ejabberd节点的) 以及 ACLs 将在新配置添加之前被移除.<br />
<br />
====主机名====<br />
<br />
选项 hosts 定义了包含一个或多个ejabberd将为其提供服务的域名的列表.<br />
<br />
语法是:<br />
<br />
'''{hosts, [HostName, ...]}.'''<br />
<br />
示例:<br />
<br />
* 服务一个域:<br />
<br />
<source lang="ini"><br />
{hosts, ["example.org"]}.<br />
</source><br />
<br />
* 服务多个域:<br />
<br />
<source lang="ini"><br />
{hosts, ["example.net", "example.com", "jabber.somesite.org"]}.<br />
</source><br />
<br />
====虚拟主机====<br />
<br />
每个虚拟主机的选项可以被独立定义,使用 host_config 选项.<br />
<br />
语法是:<br />
<br />
'''{host_config, HostName, [Option, ...]}'''<br />
<br />
示例:<br />
<br />
* 域example.net使用内部验证方法,同时域example.com使用运行在域localhost的LDAP服务器来进行验证:<br />
<br />
<source lang="ini"><br />
{host_config, "example.net", [{auth_method, internal}]}.<br />
<br />
{host_config, "example.com", [{auth_method, ldap},<br />
{ldap_servers, ["localhost"]},<br />
{ldap_uids, [{"uid"}]},<br />
{ldap_rootdn, "dc=localdomain"},<br />
{ldap_rootdn, "dc=example,dc=com"},<br />
{ldap_password, ""}]}.<br />
</source><br />
<br />
* 域example.net使用ODBC来进行验证,同时域example.com使用运行在域localhost和otherhost的LDAP服务器:<br />
<br />
<source lang="ini"><br />
{host_config, "example.net", [{auth_method, odbc},<br />
{odbc_server, "DSN=ejabberd;UID=ejabberd;PWD=ejabberd"}]}.<br />
<br />
{host_config, "example.com", [{auth_method, ldap},<br />
{ldap_servers, ["localhost", "otherhost"]},<br />
{ldap_uids, [{"uid"}]},<br />
{ldap_rootdn, "dc=localdomain"},<br />
{ldap_rootdn, "dc=example,dc=com"},<br />
{ldap_password, ""}]}.<br />
</source><br />
<br />
为了给一个虚拟主机指定特定的ejabberd模块, 你可能先为常规模块定义全局模块选项, 之后增加指定的模块给特定的虚拟主机. 为此, 把定义host_config的每个选项改成通用语法<br />
<br />
'''{OptionName, OptionValue}'''<br />
<br />
使用这个语法:<br />
<br />
'''{{add, OptionName}, OptionValue}'''<br />
<br />
在这个例子里,三个虚拟主机有一些相同的模块, 但是特定的虚拟主机也有不同的模块:<br />
<br />
<source lang="ini"><br />
%% 这个ejabberd服务器有三个虚拟主机:<br />
{hosts, ["one.example.org", "two.example.org", "three.example.org"]}.<br />
<br />
%% 这些是所有主机通用模块的配置<br />
{modules,<br />
[<br />
{mod_roster, []},<br />
{mod_configure, []},<br />
{mod_disco, []},<br />
{mod_private, []},<br />
{mod_time, []},<br />
{mod_last, []},<br />
{mod_version, []}<br />
]}.<br />
<br />
%% 增加一些模块给 vhost one:<br />
{host_config, "one.example.org",<br />
[{{add, modules}, [<br />
{mod_echo, [{host, "echo-service.one.example.org"}]}<br />
{mod_http_bind, []},<br />
{mod_logxml, []}<br />
]<br />
}<br />
]}.<br />
<br />
%% 只增加一个模块给 vhost two:<br />
{host_config, "two.example.org",<br />
[{{add, modules}, [<br />
{mod_echo, [{host, "mirror.two.example.org"}]}<br />
]<br />
}<br />
]}.<br />
</source><br />
<br />
====监听端口====<br />
<br />
选项 listen 定义ejabberd将监听哪些端口, 地址和网络协议,以及什么服务将运行在它们上面. 这个列表的每个元素是一组以下的元素:<br />
<br />
* 端口号. 还有可选的IP地址和/或一个传输协议.<br />
* 监听这个端口的模块.<br />
* TCP socke和监听中的模块的选项. <br />
<br />
这个选项的语法是:<br />
<br />
'''{listen, [Listener, ...]}.'''<br />
<br />
定义一个 listener 有很多语法.<br />
<br />
'''{PortNumber, Module, [Option, ...]}'''<br />
<br />
'''{{PortNumber, IPaddress}, Module, [Option, ...]}'''<br />
<br />
'''{{PortNumber, TransportProtocol}, Module, [Option, ...]}'''<br />
<br />
'''{{PortNumber, IPaddress, TransportProtocol}, Module, [Option, ...]}'''<br />
<br />
=====端口号,IP地址和传输协议=====<br />
<br />
端口号定义哪个端口监听链入的连接. 它可能是一个Jabber/XMPP标准端口(见 [[Ejabberd2:安装和操作指南#防火墙设定|5.1]] 节) 或任何其他合法的端口号.<br />
<br />
IP地址可能被表达为一个字符串或一个十进制或十六进制的 Erlang 组. socket 将只监听那个网络接口. 也可能指定一个通用地址, 这样ejabberd将监听所有地址. 取决于IP地址的类型, 将使用IPv4或IPv6. 当没有指定IP地址时, 它将监听所有IPv4网络地址.<br />
<br />
一些IP地址的示例值:<br />
<br />
* "0.0.0.0" 监听所有IPv4网络接口. 这是当没有指定IP地址时的缺省值.<br />
* "::" 监听所有IPv6网络接口<br />
* "10.11.12.13" 监听IPv4地址 10.11.12.13<br />
* "::FFFF:127.0.0.1" 是IPv6地址 ::FFFF:127.0.0.1/128<br />
* {10, 11, 12, 13} 是IPv4地址 10.11.12.13<br />
* {0, 0, 0, 0, 0, 65535, 32512, 1} 是IPv6地址 ::FFFF:127.0.0.1/128<br />
* {16#fdca, 16#8ab6, 16#a243, 16#75ef, 0, 0, 0, 1} 是IPv6地址 FDCA:8AB6:A243:75EF::1/128 <br />
<br />
传输协议可能是 tcp 或 udp. 缺省是 tcp.<br />
<br />
=====监听的模块=====<br />
<br />
可用的模块, 它们的目的以及允许使用哪些选项:<br />
<br />
'''ejabberd_c2s'''<br />
:处理c2s连接.<br />
:选项: access, certfile, max_fsm_queue, max_stanza_size, shaper, starttls, starttls_required, tls, zlib <br />
<br />
'''ejabberd_s2s_in'''<br />
:处理链入的s2s连接.<br />
:选项: max_stanza_size <br />
<br />
'''ejabberd_service'''<br />
:和一个[http://www.ejabberd.im/tutorials-transports 外部组件]的接口(定义于Jabber组件协议([http://xmpp.org/extensions/xep-0114.html XEP-0114]).<br />
:选项: access, hosts, max_fsm_queue, shaper, service_check_from <br />
<br />
'''ejabberd_stun'''<br />
:处理STUN绑定请求,定义于 [http://tools.ietf.org/html/rfc5389 RFC 5389].<br />
:选项: certfile <br />
<br />
'''ejabberd_http'''<br />
:处理链入的HTTP连接.<br />
:选项: captcha, certfile, http_bind, http_poll, request_handlers, tls, web_admin<br />
<br />
=====选项=====<br />
<br />
这是每个监听的模块允许使用的选项的详细描述:<br />
<br />
'''{access, AccessName}'''<br />
:这个选项定义访问的端口. 缺省值是 all. <br />
'''{backlog, Value}'''<br />
:这个backlog值定义等待中的连接的队列可以达到的最大长度. 如果服务器想处理很多的新链入连接,这个值需要增加。因为如果队列里没有足够的空间(ejabberd不能立刻接受它们),这些新连接可能被抛弃. 缺省值是 5. <br />
'''{certfile, Path}'''<br />
:包含缺省的SSL证书的文件的完整路径. 为一个给定的域定义一个证书文件, 使用全局选项 domain_certfile. <br />
'''{service_check_from, true|false}'''<br />
:这个选项只能被用于ejabberd_service. 它被用于禁止控制一个从外部组件发送的包的from字段. 这个选项要么是 true 要么是 false. 缺省值是 true ,它遵循 [http://xmpp.org/extensions/xep-0114.html XEP-0114]. <br />
'''{hosts, [Hostname, ...], [HostOption, ...]}'''<br />
:连接到ejabberd_service的外部Jabber组件可能服务一个或多个hostnames. 所以你可以为这个组件定义选项 HostOption ; 目前只允许的选项是当组件尝试连接到ejabberd时必需提供的密码: {password, Secret}. 注意你不能在不同的服务里定义同一个 ejabberd_service 组件: 为每个服务增加一个 ejabberd_service , 示例如下. <br />
'''captcha'''<br />
:简单的web页面,允许一个用户填一个 CAPTCHA 挑战(见 [[Ejabberd2:安装和操作指南#CAPTCHA|3.1.8]] 节). <br />
'''http_bind'''<br />
:这个选项允许支持HTTP绑定([http://xmpp.org/extensions/xep-0124.html XEP-0124]和[http://xmpp.org/extensions/xep-0206.html XEP-0206]) . HTTP绑定允许通过HTTP请求,从那些不允许从5222端口链出socket的防火墙后面访问ejabberd.<br />
:记住你也必须安装和激活mod_http_bind模块.<br />
:如果HTTP绑定激活了, 它将可以使用 http://server:port/http-bind/. 注意对HTTP绑定的支持也需要XMPP客户端. 也要注意HTTP绑定对一个基于web的XMPP客户端的主机也是很有意义的,例如[http://jwchat.sourceforge.net/ JWChat] (检查教程来给ejabberd安装JWChat,以及一个 [http://www.ejabberd.im/jwchat-localserver 内嵌的本地web服务器] 或 [http://www.ejabberd.im/jwchat-apache Apache]). <br />
'''http_poll'''<br />
:这个选项允许支持HTTP轮询([http://xmpp.org/extensions/xep-0025.html XEP-0025]). HTTP轮询允许通过HTTP请求,从那些不允许从5222端口链出socket的防火墙后面访问ejabberd.<br />
:如果激活了HTTP轮询, 它可以用 http://server:port/http-poll/. 注意对HTTP轮询的支持也需要XMPP客户端. 也要注意HTTP轮询对一个基于web的XMPP客户端的主机是很有意义的,例如[http://jwchat.sourceforge.net/ JWChat].<br />
:在没有链入的POST请求时一个客户端会话保持激活状态的最大时间段,可以用全局选项 http_poll_timeout 配置. 缺省值为5分钟. 这个选项可在 ejabberd.cfg 文件里定义, 时间的单位为秒: {http_poll_timeout, 300}. <br />
'''{max_fsm_queue, Size}'''<br />
:这个选项指定在一个FSM(有限状态机)队列里元素的最大数量. 大概来说, 在这这些队列的每个消息展示一个准备发送到它想要的外发的流的XML节. 如果队列大小达到限制(因为, 例如, 节的接收者太慢), 这个FSM和相应的连接(如果有)将被终止并且记录一个出错信息. 这个选项的合理的值依赖于你的硬件配置. 无论如何, 把这个大小设为1000个元素以上应该没什么感觉. 这个选项可被指定给 ejabberd_service 和 ejabberd_c2s listeners, 或也可以全局地指定给 ejabberd_s2s_out. 如果这个选项没有指定给 ejabberd_service 或 ejabberd_c2s listeners, 则使用全局配置的值. 允许的值为整数和 ’undefined’. 缺省值为: ’undefined’. <br />
'''{max_stanza_size, Size}'''<br />
:这个选项指定一个XML节的近似最大字节数. 近似的, 是因为它计算的精度是以一个被读数据块来的. 例如 {max_stanza_size, 65536}. 缺省值是无穷大. 推荐的值对于c2s连接是 65536,对于s2s连接 是 131072 . s2s 最大节数必须总是比 c2s 的限制更高. 谨慎修改此值,因为如果设置得太小可能导致意料之外的断链. <br />
'''{request_handlers, [ {Path, Module}, ...]}'''<br />
:指定一个或多个 handlers 来伺服HTTP请求. Path是一个字符串列表; 所以以那个 Path 启动的 URIs 将被 Module 伺服. 例如, 你希望 mod_foo to 伺服以 /a/b/ 开头的URIs, 同时你也希望 mod_http_bind 伺服 URIs /http-bind/, 使用这个选项: {request_handlers, [{["a", "b"], mod_foo}, {["http-bind"], mod_http_bind}]} <br />
'''{service_check_from, true|false}'''<br />
:通过使能这个选项, ejabberd 允许组件发送的包的’from’属性可以是任何随意的域. 注意 [http://xmpp.org/extensions/xep-0114.html XEP-0114] 要求域必须和组件的主机名吻合. 只有你确保自己需要的情况下才应该激活这个选项. 缺省值是: false. <br />
'''{shaper, none|ShaperName}'''<br />
:这个选项为端口定义一个塑型者 shaper (见 [[Ejabberd2:安装和操作指南#Shapers|3.1.6]] 节). 缺省值是 none. <br />
'''starttls'''<br />
:这个选项定义 STARTTLS 加密可以用于连接某端口. 你应该也设置 certfile 选项. 你可以使用全局选项 domain_certfile为一个特定的域定义一个证书文件. <br />
'''starttls_required'''<br />
:这个选项指定在连接到某端口时 STARTTLS 加密是必需的. 不允许不加密的连接. 你应该也设置 certfile 选项. 你可以使用全局选项 domain_certfile为一个特定的域定义一个证书文件. <br />
'''tls'''<br />
:这个选项指定某端口的通讯在连接之后将立刻使用SSL加密. 这是一个早期的Jabber软件使用的传统加密方法, 通常是在端口 5223 ,用于客户端-服务器通讯. 但是这个方法今天已经被藐视和不推荐了. 可取的加密方法是在端口5222使用 STARTTLS , 定义于 [[RFC3920|RFC 3920: XMPP核心]], 这个方法在 ejabberd 里可以使用 starttls 选项来激活. 如果这个选项被设置了, 你应该同时设置 certfile 选项. 选项 tls 也可用于 ejabberd_http 以支持 HTTPS. <br />
'''web_admin'''<br />
:这个选项激活为ejabberd管理激活 Web Admin ,可在 http://server:port/admin/ 访问. 登录和密码就是某个你在‘configure’ access rule里授权了的已注册用户的用户名和密码. <br />
'''zlib'''<br />
:这个选项指定在某端口的连接可使用 Zlib 流压缩(定义于 [http://xmpp.org/extensions/xep-0138.html XEP-0138]). <br />
<br />
有一些额外的全局选项(listen之外的)可以在ejabberd配置文件指定:<br />
<br />
'''{s2s_use_starttls, true|false}'''<br />
:这个选项定义是否为s2s连接使用 STARTTLS . <br />
'''{s2s_certfile, Path}'''<br />
:一个包含SSL证书的文件的全路径. <br />
'''{domain_certfile, Domain, Path}'''<br />
:包含一个特定域的SSL证书的文件的全路径. <br />
'''{outgoing_s2s_options, Methods, Timeout}'''<br />
:指定用哪个地址尝试连接, 以什么顺序, 以及连接超时时间(以毫秒计). 缺省第一次尝试连接使用IPv4地址, 如果失败它将尝试使用IPv6, 超时时间为 10000 毫秒. <br />
'''{s2s_dns_options, [ {Property, Value}, ...]}'''<br />
:指定用于DNS解析的 properties. 允许的 Properties 有: 以秒计的缺省值为10的 timeout 和缺省值为2的重试次数. <br />
'''{s2s_default_policy, allow|deny}'''<br />
:对于链入和链出到其他XMPP服务器的s2s连接的缺省策略. 缺省值是 allow. <br />
'''{{s2s_host, Host}, allow|deny}'''<br />
:指定是否允许一个特定远程主机的链入和链出s2s连接. 这允许限制 ejabberd 只和少数信任的服务器建立s2s连接, 或禁止一些特定的服务器. <br />
'''{s2s_max_retry_delay, Seconds}'''<br />
:连接失败后重试连接的最大允许延迟时间. 以秒计算. 这个缺省值是 300 秒 (5分钟). <br />
'''{max_fsm_queue, Size}'''<br />
:这个选项指定FSM(有限状态机)的队列里元素的最大数量. 大概来说, 在这些队列里每个消息展示一个准备发送到它想要的外发的流的XML节. 如果队列大小达到限制(因为, 例如, 节的接收者太慢), 这个FSM和相应的连接(如果有)将被终止并且记录一个出错信息. 这个选项的合理的值依赖于你的硬件配置. 无论如何, 把这个大小设为1000个元素以上应该没什么感觉. 这个选项可被指定给 ejabberd_service 和 ejabberd_c2s listeners, 或也可以全局地指定给 ejabberd_s2s_out. 如果这个选项没有指定给 ejabberd_service 或 ejabberd_c2s listeners, 则使用全局配置的值. 允许的值为整数和 ’undefined’. 缺省值为: ’undefined’. <br />
'''{route_subdomains, local|s2s}'''<br />
:定义 ejabberd 是必须直接把节从本地路由到子域 subdomains(兼容 [[RFC3920|RFC 3920: XMPP核心]]), 还是使用S2S到外部服务器 (兼容 [http://tools.ietf.org/html/draft-saintandre-rfc3920bis-09#section-11.3 RFC 3920 bis]).<br />
<br />
=====示例=====<br />
<br />
例如, 以下简单配置定义:<br />
<br />
* 有三个域. 缺省证书文件是 server.pem. 然而, 连接到域example.com的c2s和s2s使用文件example_com.pem.<br />
* 端口 5222 使用 STARTTLS 监听 c2s 连接, 同时允许简单连接用于旧的客户端.<br />
* 端口 5223 使用旧的 SSL 监听 c2s 连接 .<br />
* 端口 5269 使用 STARTTLS 监听 s2s 连接. 这个socket设为IPv6而不是IPv4.<br />
* 端口 3478 监听通过 UDP 发出的 STUN 请求 .<br />
* 端口 5280 监听 HTTP 请求, 并伺服 HTTP 轮询服务.<br />
* 端口 5281 监听 HTTP 请求, 并使用 HTTPS 伺服 Web Admin (见 [[Ejabberd2:安装和操作指南#Web管理|4.3]] 节). 这个socket只监听来自IP地址127.0.0.1的连接.<br />
<br />
<source lang="ini"><br />
{hosts, ["example.com", "example.org", "example.net"]}.<br />
{listen,<br />
[<br />
{5222, ejabberd_c2s, [<br />
{access, c2s},<br />
{shaper, c2s_shaper},<br />
starttls, {certfile, "/etc/ejabberd/server.pem"},<br />
{max_stanza_size, 65536}<br />
]},<br />
{5223, ejabberd_c2s, [<br />
{access, c2s},<br />
{shaper, c2s_shaper},<br />
tls, {certfile, "/etc/ejabberd/server.pem"},<br />
{max_stanza_size, 65536}<br />
]},<br />
{{5269, "::"}, ejabberd_s2s_in, [<br />
{shaper, s2s_shaper},<br />
{max_stanza_size, 131072}<br />
]},<br />
{{3478, udp}, ejabberd_stun, []},<br />
{5280, ejabberd_http, [<br />
http_poll<br />
]},<br />
{{5281, "127.0.0.1"}, ejabberd_http, [<br />
web_admin,<br />
tls, {certfile, "/etc/ejabberd/server.pem"},<br />
]}<br />
]<br />
}.<br />
{s2s_use_starttls, true}.<br />
{s2s_certfile, "/etc/ejabberd/server.pem"}.<br />
{domain_certfile, "example.com", "/etc/ejabberd/example_com.pem"}.<br />
</source><br />
<br />
在这个例子, 定义了以下配置:<br />
<br />
* 端口 5222 (所有IPv4地址)和端口5223 (SSL, IP 192.168.0.1 和 fdca:8ab6:a243:75ef::1)监听c2s连接 ,并禁止名为 ‘bad’的用户.<br />
* 端口 5269 (所有IPv4地址)为了允许安全通讯而使用STARTTLS监听s2s连接. 远程XMPP服务器的链入和链出连接被禁止, 只有两个服务器可以连接: "jabber.example.org" 和 "example.com".<br />
* 端口 5280 在所有的IPv4地址伺服 Web Admin 和 HTTP Polling 服务. 注意它也可能在不同端口伺服它们. [[Ejabberd2:安装和操作指南#Web管理|4.3]] 节的第二个例子展示了怎样确切的做法.<br />
* 除了管理员,所有用户的通讯流量限制为 1,000 Bytes/second<br />
* [http://www.ejabberd.im/pyaimt AIM 网关] aim.example.org 被连接到localhost IP 地址(127.0.0.1 and ::1)的 5233 端口 , 连接密码为‘aimsecret’.<br />
* ICQ 网关 JIT (icq.example.org and sms.example.org) 被以密码‘jitsecret’连接到端口 5234 .<br />
* [http://www.ejabberd.im/pymsnt MSN 网关] msn.example.org 被以密码‘msnsecret’连接到端口 5235 .<br />
* [http://www.ejabberd.im/yahoo-transport-2 Yahoo! 网关] yahoo.example.org 被以密码‘yahoosecret’连接到端口 5236 .<br />
* [http://www.ejabberd.im/jabber-gg-transport Gadu-Gadu 网关] gg.example.org 被以密码‘ggsecret’连接到端口 5237 .<br />
* [http://www.ejabberd.im/jmc Jabber Mail 组件] jmc.example.org 被以密码‘jmsecret’连接到端口 5238 .<br />
* 服务自定义允许特别的选项用来逃避对从这个组件发送的包里检查from属性. 这个组件可以从服务器以任何用户的身份发送包, 或者甚至以任何服务器的身份.<br />
<br />
<source lang="ini"><br />
{acl, blocked, {user, "bad"}}.<br />
{access, c2s, [{deny, blocked},<br />
{allow, all}]}.<br />
{shaper, normal, {maxrate, 1000}}.<br />
{access, c2s_shaper, [{none, admin},<br />
{normal, all}]}.<br />
{listen,<br />
[{5222, ejabberd_c2s, [<br />
{access, c2s},<br />
{shaper, c2s_shaper}<br />
]},<br />
{{5223, {192, 168, 0, 1}}, ejabberd_c2s, [<br />
{access, c2s},<br />
ssl, {certfile, "/path/to/ssl.pem"}<br />
]},<br />
{{5223, {16#fdca, 16#8ab6, 16#a243, 16#75ef, 0, 0, 0, 1}},<br />
ejabberd_c2s, [<br />
{access, c2s},<br />
ssl, {certfile, "/path/to/ssl.pem"}<br />
]},<br />
{5269, ejabberd_s2s_in, []},<br />
{{5280, {0, 0, 0, 0}}, ejabberd_http, [<br />
http_poll,<br />
web_admin<br />
]},<br />
{{5233, {127, 0, 0, 1}}, ejabberd_service, [<br />
{hosts, ["aim.example.org"],<br />
[{password, "aimsecret"}]}<br />
]},<br />
{{5233, "::1"}, ejabberd_service, [<br />
{hosts, ["aim.example.org"],<br />
[{password, "aimsecret"}]}<br />
]},<br />
{5234, ejabberd_service, [{hosts, ["icq.example.org", "sms.example.org"],<br />
[{password, "jitsecret"}]}]},<br />
{5235, ejabberd_service, [{hosts, ["msn.example.org"],<br />
[{password, "msnsecret"}]}]},<br />
{5236, ejabberd_service, [{hosts, ["yahoo.example.org"],<br />
[{password, "yahoosecret"}]}]},<br />
{5237, ejabberd_service, [{hosts, ["gg.example.org"],<br />
[{password, "ggsecret"}]}]},<br />
{5238, ejabberd_service, [{hosts, ["jmc.example.org"],<br />
[{password, "jmcsecret"}]}]},<br />
{5239, ejabberd_service, [{hosts, ["custom.example.org"],<br />
[{password, "customsecret"}]},<br />
{service_check_from, false}]}<br />
]<br />
}.<br />
{s2s_use_starttls, true}.<br />
{s2s_certfile, "/path/to/ssl.pem"}.<br />
{s2s_default_policy, deny}.<br />
{{s2s_host,"jabber.example.org"}, allow}.<br />
{{s2s_host,"example.com"}, allow}.<br />
</source><br />
<br />
注意, 对基于 jabberd14 或 WPJabber 的服务,你不得不做一个网关日志并通过它们本身做 XDB : <br />
<br />
<source lang="ini"><br />
<!--<br />
You have to add elogger and rlogger entries here when using ejabberd.<br />
In this case the transport will do the logging.<br />
--><br />
<br />
<log id='logger'><br />
<host/><br />
<logtype/><br />
<format>%d: [%t] (%h): %s</format><br />
<file>/var/log/jabber/service.log</file><br />
</log><br />
<br />
<!--<br />
Some XMPP server implementations do not provide<br />
XDB services (for example, jabberd2 and ejabberd).<br />
xdb_file.so is loaded in to handle all XDB requests.<br />
--><br />
<br />
<xdb id="xdb"><br />
<host/><br />
<load><br />
<!-- this is a lib of wpjabber or jabberd14 --><br />
<xdb_file>/usr/lib/jabber/xdb_file.so</xdb_file><br />
</load><br />
<xdb_file xmlns="jabber:config:xdb_file"><br />
<spool><jabberd:cmdline flag='s'>/var/spool/jabber</jabberd:cmdline></spool><br />
</xdb_file><br />
</xdb><br />
</source><br />
====验证====<br />
<br />
选项 auth_method 定义了用于验证用户的验证方法. 语法是:<br />
<br />
'''{auth_method, [Method, ...]}.'''<br />
<br />
ejabberd支持以下验证方法:<br />
<br />
* internal (缺省) — 见 [[Ejabberd2:安装和操作指南#内部|3.1.4.]] 节<br />
* external — 有[http://www.ejabberd.im/extauth 一些示例验证代码].<br />
* ldap — 见 [[Ejabberd2:安装和操作指南#LDAP|3.2.5.]] 节<br />
* odbc — 见 [[Ejabberd2:安装和操作指南#MySQL|3.2.1]], [[Ejabberd2:安装和操作指南#PostgreSQL|3.2.3]], [[Ejabberd2:安装和操作指南# Microsoft SQL Server|3.2.2]] 和 [[Ejabberd2:安装和操作指南#ODBC兼容|3.2.4.]] 节<br />
* anonymous — 见 [[Ejabberd2:安装和操作指南#SASL匿名和匿名登录|3.1.4.]] 节<br />
* pam — 见 [[Ejabberd2:安装和操作指南#SASL匿名和匿名登录|3.1.4.]] 节<br />
<br />
只有internal 和 odbc 方法支持新建帐号.<br />
<br />
=====内部=====<br />
<br />
ejabberd使用它的内部Mnesia数据库作为缺省的验证方法. 这个值 internal 将允许内部验证方法.<br />
<br />
例子:<br />
<br />
* 在example.org使用内部验证, 在example.net使用LDAP验证:<br />
<br />
<source lang="ini"><br />
{host_config, "example.org", [{auth_method, [internal]}]}.<br />
{host_config, "example.net", [{auth_method, [ldap]}]}.<br />
</source><br />
<br />
* 在所有虚拟主机使用内部验证:<br />
<br />
<source lang="ini"><br />
{auth_method, internal}.<br />
</source><br />
<br />
=====SASL匿名和匿名登录=====<br />
<br />
这个值 anonymous 将允许内部验证方法.<br />
<br />
匿名验证方法可以由以下选项配置. 记住你可以用 host_config 选项设置虚拟主机个别特有的选项(见 [[Ejabberd2:安装和操作指南#虚拟主机|3.1.2]] 节). 注意关于[http://support.process-one.net/doc/display/MESSENGER/Anonymous+users+support SASL匿名和匿名登录配置]也有一个详细的教程 .<br />
<br />
'''{allow_multiple_connections, false|true}'''<br />
:这个选项只用于匿名模式已经被允许的时候. 设置它为 true 意味着在匿名登录模式里,如果使用不同的资源来连接,同样的用户名可以被使用多次. 这个选项只在非常特殊的情况下有用. 缺省值是 false. <br />
'''{anonymous_protocol, sasl_anon | login_anon | both}'''<br />
:sasl_anon 意味着将使用 SASL 匿名方法. login_anon 意味着将使用匿名登录方法. both 意味着SASL匿名和匿名登录都允许. <br />
<br />
那些选项为每个虚拟主机定义的选项 host_config 参数 (见 [[Ejabberd2:安装和操作指南#虚拟主机|3.1.2]] 节).<br />
<br />
例子:<br />
<br />
* 在所有虚拟主机上允许匿名登录:<br />
<br />
<source lang="ini"><br />
{auth_method, [anonymous]}.<br />
{anonymous_protocol, login_anon}.<br />
</source><br />
<br />
* 类似前例, 但限于 public.example.org:<br />
<br />
<source lang="ini"><br />
{host_config, "public.example.org", [{auth_method, [anonymous]},<br />
{anonymous_protocol, login_anon}]}.<br />
</source><br />
<br />
* 在一个虚拟主机允许匿名登录和内部验证:<br />
<br />
<source lang="ini"><br />
{host_config, "public.example.org", [{auth_method, [internal,anonymous]},<br />
{anonymous_protocol, login_anon}]}.<br />
</source><br />
<br />
* 在一个虚拟主机允许SASL匿名:<br />
<br />
<source lang="ini"><br />
{host_config, "public.example.org", [{auth_method, [anonymous]},<br />
{anonymous_protocol, sasl_anon}]}.<br />
</source><br />
<br />
* 在一个虚拟主机允许SASL匿名和匿名登录:<br />
<br />
<source lang="ini"><br />
{host_config, "public.example.org", [{auth_method, [anonymous]},<br />
{anonymous_protocol, both}]}.<br />
</source><br />
<br />
* 在一个虚拟主机允许SASL匿名, 匿名登录, 和内部验证:<br />
<br />
<source lang="ini"><br />
{host_config, "public.example.org", [{auth_method, [internal,anonymous]},<br />
{anonymous_protocol, both}]}.<br />
</source><br />
<br />
=====PAM验证=====<br />
<br />
ejabberd支持通过可插拔的验证模块(PAM)来验证. PAM 目前在 AIX, FreeBSD, HP-UX, Linux, Mac OS X, NetBSD 和 Solaris里都支持. PAM 验证缺省是被禁止的, 所以你不得不使用 PAM support enabled 选项来配置并编译ejabberd:<br />
<br />
<source lang="bash"><br />
./configure --enable-pam && make install<br />
</source><br />
<br />
选项:<br />
<br />
'''{pam_service, Name}'''<br />
:这个选项定义了PAM服务名. 缺省是 "ejabberd". 更多信息请参考你的操作系统的 PAM 文档. <br />
<br />
例子:<br />
<br />
<source lang="ini"><br />
{auth_method, [pam]}.<br />
{pam_service, "ejabberd"}.<br />
</source><br />
<br />
虽然很容易在ejabberd里配置PAM支持, PAM本身介绍了一些安全问题:<br />
<br />
* 为执行PAM验证,ejabberd使用名为 epam 的外部C程序. 缺省的, 它位于 /var/lib/ejabberd/priv/bin/ 目录. 在这个例子里,如果你的PAM模块要求root权限(例如pam_unix.so),你不得不把它设为root可执行. 你也不得不为ejabberd赋予访问这个文件的权限,并移除所有其他权限. 以root权限执行以下命令:<br />
<br />
<source lang="bash"><br />
chown root:ejabberd /var/lib/ejabberd/priv/bin/epam<br />
chmod 4750 /var/lib/ejabberd/priv/bin/epam<br />
</source><br />
<br />
* 确保你已在你的系统安装了最新版本的PAM. 一些旧版本的PAM模块会导致内存溢出. 如果你不能使用最新版本, 你可以定期杀掉(1) epam 进程以减少它的内存消耗: ejabberd将立刻重启这个进程.<br />
* epam程序在验证失败时尝试关闭延迟. 然而, 一些PAM模块忽略这个行为并依靠它们自己的配置选项. 你可以新建一个配置文件ejabberd.pam. 这个例子展示如何在pam_unix.so模块关闭延迟:<br />
<br />
<source lang="ini"><br />
#%PAM-1.0<br />
auth sufficient pam_unix.so likeauth nullok nodelay<br />
account sufficient pam_unix.so<br />
</source><br />
<br />
:这不是一个已准备好使用的配置文件: 当你建立你自己的PAM配置时,你必须示意使用它. 注意如果你想在PAM配置文见里设置在验证失败时禁止延迟, 你不得不限制访问这个文件, 这样恶意用户就不能使用你的配置来执行暴力攻击.<br />
* 你可能希望只允许特定用户登录访问. pam_listfile.so 模块提供这个功能.<br />
* 如果你使用 pam_winbind 来对一个Windows Active Directory授权, 那么 /etc/nssswitch.conf 必须被配置成使用winbind.<br />
<br />
====访问规则====<br />
<br />
=====ACL定义=====<br />
<br />
在ejabberd里访问控制是通过访问控制列表(ACLs)来实现的. 配置文件中ACLs的声明语法如下:<br />
<br />
'''{acl, ACLName, ACLValue}.'''<br />
<br />
ACLValue 可以是以下之一:<br />
<br />
'''all'''<br />
:匹配所有JIDs. 例子:<br />
<source lang="ini"><br />
{acl, all, all}.<br />
</source><br />
'''{user, Username}'''<br />
:匹配第一个虚拟主机,名字为 Username 的用户. 例子:<br />
<source lang="ini"><br />
{acl, admin, {user, "yozhik"}}.<br />
</source><br />
'''{user, Username, Server}'''<br />
:匹配JID为Username@Server加任何资源的用户. 例子:<br />
<source lang="ini"><br />
{acl, admin, {user, "yozhik", "example.org"}}.<br />
</source><br />
'''{server, Server}'''<br />
:匹配从服务器Server来的任何JID. 例子:<br />
<source lang="ini"><br />
{acl, exampleorg, {server, "example.org"}}.<br />
</source><br />
'''{resource, Resource}'''<br />
:匹配任何资源为Resource的JID. 例子:<br />
<source lang="ini"><br />
{acl, mucklres, {resource, "muckl"}}.<br />
</source><br />
'''{shared_group, Groupname}'''<br />
:匹配这个虚拟主机上的共享名册组Groupname的任何成员. 例子:<br />
<source lang="ini"><br />
{acl, techgroupmembers, {shared_group, "techteam"}}.<br />
</source><br />
'''{shared_group, Groupname, Server}'''<br />
:匹配虚拟主机Server上的共享名册组Groupname的任何成员. 例子:<br />
<source lang="ini"><br />
{acl, techgroupmembers, {shared_group, "techteam", "example.org"}}.<br />
</source><br />
'''{user_regexp, Regexp}'''<br />
:匹配本地虚拟主机(们)上的任何名字符合Regexp的本地用户. 例子:<br />
<source lang="ini"><br />
{acl, tests, {user_regexp, "^test[0-9]*$"}}.<br />
</source><br />
'''{user_regexp, UserRegexp, Server}'''<br />
:匹配服务器Server上名字符合UserRegexp的任何用户. 例子:<br />
<source lang="ini"><br />
{acl, tests, {user_Userregexp, "^test", "example.org"}}.<br />
</source><br />
'''{server_regexp, Regexp}'''<br />
:匹配来自符合server_regexp的服务器的任何JID. 例子:<br />
<source lang="ini"><br />
{acl, icq, {server_regexp, "^icq\\."}}.<br />
</source><br />
'''{resource_regexp, Regexp}'''<br />
:匹配资源符合resource_regexp的任何JID. 例子:<br />
<source lang="ini"><br />
{acl, icq, {resource_regexp, "^laptop\\."}}.<br />
</source><br />
'''{node_regexp, UserRegexp, ServerRegexp}'''<br />
:匹配任何名字符合ServerRegexp的服务器上的任何名字符合UserRegexp的用户. Example:<br />
<source lang="ini"><br />
{acl, yohzik, {node_regexp, "^yohzik$", "^example.(com|org)$"}}.<br />
</source><br />
'''{user_glob, Glob}'''<br />
'''{user_glob, Glob, Server}'''<br />
'''{server_glob, Glob}'''<br />
'''{resource_glob, Glob}'''<br />
'''{node_glob, UserGlob, ServerGlob}'''<br />
:这和上面一样. 然而, 它使用 shell glob 模式而不是 regexp. 这些模式能拥有以下特别的字符:<br />
<br />
:'''*'''<br />
::匹配任何包含null字符的字符串. <br />
:''' ?'''<br />
:: 匹配任何单个字符. <br />
:''' [...]'''<br />
::匹配任何封闭的字符串. 字符范围由一对使用‘-’分割的字符串定义. 如果在 ‘[’之后的第一个字符是一个‘!’, 匹配任何不封闭的字符. <br />
<br />
以下 ACLName 是预定义的:<br />
<br />
'''all'''<br />
:匹配任何JID. <br />
'''none'''<br />
:不匹配任何JID.<br />
<br />
=====访问权限=====<br />
<br />
一个允许或禁止访问不同服务的条目. 语法是:<br />
<br />
'''{access, AccessName, [ {allow|deny, ACLName}, ...]}.'''<br />
<br />
当一个JID被检查到可以访问 Accessname, 服务器顺序检查是否那个 JID 匹配任何在列表里这一元组的第二个元素命名的 ACLs. 如果匹配, 返回第一个匹配的元组的第一个元素, 否则返回值‘deny’.<br />
<br />
如果你在一个虚拟主机定义了特定的访问权限, 记住全局定义的访问权限比它们拥有优先权. 这意味着, 当发生冲突的时候, 使用这个全局服务器上的赋予或禁止访问,而虚拟主机配置的访问控制无效.<br />
<br />
例子:<br />
<br />
<source lang="ini"><br />
{access, configure, [{allow, admin}]}.<br />
{access, something, [{deny, badmans},<br />
{allow, all}]}.<br />
</source><br />
<br />
以下 AccessName 是预定义的:<br />
<br />
'''all'''<br />
:总是返回值‘allow’. <br />
'''none'''<br />
:总是返回值‘deny’.<br />
<br />
=====使用ACL限制打开的会话=====<br />
<br />
特别的 access max_user_sessions 定义了每个用户的会话(已验证的连接)的最大数量. 如果一个用户尝试通过使用不同的资源打开更多的会话, 第一个打开的会话将被断掉连接. 这个 会话替换 的错误信息将被发送到断链的会话. 这个选项的值可能是一个数字, 或 infinity. 缺省值是 infinity.<br />
<br />
语法是:<br />
<br />
'''{access, max_user_sessions, [ {MaxNumber, ACLName}, ...]}.'''<br />
<br />
这个例子对所有用户限制每用户会话数为5, 对管理员限制为 10:<br />
<br />
<source lang="ini"><br />
{access, max_user_sessions, [{10, admin}, {5, all}]}.<br />
</source><br />
<br />
=====使用ACL限制到一个远程XMPP服务器的多个连接=====<br />
<br />
特别的 access max_s2s_connections 定义了可以建立多少个连接到一个特定的远程XMPP服务器. 缺省值是 infinity. 也可以使用 access max_s2s_connections_per_node.<br />
<br />
语法是:<br />
<br />
'''{access, max_s2s_connections, [ {MaxNumber, ACLName}, ...]}.'''<br />
<br />
例子: <br />
<br />
* 允许每个远程服务器最多3个连接:<br />
<br />
<source lang="ini"><br />
{access, max_s2s_connections, [{3, all}]}.<br />
</source><br />
<br />
====整形====<br />
<br />
整形允许你限制连接的通讯量. 语法是:<br />
<br />
'''{shaper, ShaperName, Kind}.'''<br />
<br />
目前只支持一种整形 maxrate . 语法如下:<br />
<br />
'''{maxrate, Rate}'''<br />
<br />
这里 Rate 代表最大允许每秒收到的字节数. 当一个连接超过了这个限制, ejabberd停止从socket读取,直到平均速率再次降到允许的最大值以下.<br />
<br />
例子:<br />
<br />
* 定义一个 shaper 名为 ‘normal’ ,限制流量速度为 1,000 bytes/second:<br />
<br />
<source lang="ini"><br />
{shaper, normal, {maxrate, 1000}}.<br />
<source><br />
<br />
* 定义一个 shaper 名为‘fast’,限制流量速度为 50,000 bytes/second:<br />
<br />
<source lang="ini"><br />
{shaper, fast, {maxrate, 50000}}.<br />
</source><br />
<br />
====缺省语言====<br />
<br />
这个选项 language 定义服务器能被XMPP客户端看到的字符串的缺省语言. 如果一个XMPP客户端不支持 xml:lang, 将使用这里定义的语言.<br />
<br />
这个选项的语法是:<br />
<br />
'''{language, Language}.'''<br />
<br />
缺省值是 en. 为了让它生效,在ejabberd的 msgs 目录必须有一个翻译文件 Language.msg.<br />
<br />
例如, 设置俄语为缺省语言:<br />
<br />
<source lang="ini"><br />
{language, "ru"}.<br />
</source><br />
<br />
附录 [[Ejabberd2:安装和操作指南#附录A 国际化和本地化|A]] 提供了关于国际化和本地化的更多细节.<br />
<br />
====CAPTCHA====<br />
<br />
一些ejabberd模块可被配置成在特定的动作上要求 CAPTCHA 挑战. 如果客户端不支持 CAPTCHA Forms ([http://xmpp.org/extensions/xep-0158.html XEP-0158]), 将提供一个web连接让用户用web浏览器填写挑战.<br />
<br />
提供了一个示例脚本使用 ImageMagick 的转换程序来生成图片 .<br />
<br />
配置选项为:<br />
<br />
'''{captcha_cmd, Path}'''<br />
:一个生成图片的脚本的全路径. 缺省值为空: "" <br />
'''{captcha_host, Host}'''<br />
:发给用户的 URL 的 Host 部分. 你可以包含端口号. 发给用户的 URL 的格式为: http://Host/captcha/ ,缺省值是第一个被配置的主机名. <br />
<br />
另外, 必须允许一个 ejabberd_http 监听者拥有 captcha 选项. 见 [[Ejabberd2:安装和操作指南#监听的模块|3.1.3]] 节.<br />
<br />
示例配置:<br />
<br />
<source lang="ini"><br />
{hosts, ["example.org"]}.<br />
<br />
{captcha_cmd, "/lib/ejabberd/priv/bin/captcha.sh"}.<br />
{captcha_host, "example.org:5280"}.<br />
<br />
{listen,<br />
[<br />
...<br />
{5280, ejabberd_http, [<br />
captcha,<br />
...<br />
]<br />
}<br />
<br />
]}.<br />
</source><br />
<br />
====STUN====<br />
<br />
ejabberd可以当作一个独立的 STUN 服务器 ([http://tools.ietf.org/html/rfc5389 RFC 5389]). 目前只支持绑定的使用. 在那个角色中,ejabberd 帮助客户端实现 Jingle ICE ([http://xmpp.org/extensions/xep-0176.html XEP-0176]) 支持来发现它们的外部地址和端口.<br />
<br />
你应该配置 ejabberd_stun 监听模块,如 [[Ejabberd2:安装和操作指南#监听端口|3.1.3]] 节所述. 如果定义了 certfile 选项, ejabberd 在同一个端口复用TCP连接和通过TCP连接的TLS . 很明显, certfile选项仅为tcp定义. 注意无论如何,支持 TCP 或 TLS over TCP ,对于绑定使用来说不是必需的,对于TURN功能是保留的. 只有udp传输可以随意配置.<br />
<br />
示例配置:<br />
<br />
<source lang="ini"><br />
{listen,<br />
[<br />
...<br />
{{3478, udp}, ejabberd_stun, []},<br />
{3478, ejabberd_stun, []},<br />
{5349, ejabberd_stun, [{certfile, "/etc/ejabberd/server.pem"}]},<br />
...<br />
]<br />
}.<br />
</source><br />
<br />
你也需要正确地配置 DNS SRV 记录,这样客户端可以很容易地发现一个为你的XMPP域服务的 STUN 服务器. 具体请参考[http://tools.ietf.org/html/rfc5389 RFC 5389]的[http://tools.ietf.org/html/rfc5389#section-9 DNS Discovery of a Server] 章节.<br />
<br />
示例 DNS SRV 配置:<br />
<br />
<source lang="ini"><br />
_stun._udp IN SRV 0 0 3478 stun.example.com.<br />
_stun._tcp IN SRV 0 0 3478 stun.example.com.<br />
_stuns._tcp IN SRV 0 0 5349 stun.example.com.<br />
</source><br />
<br />
====包含其它配置文件====<br />
<br />
一个配置文件中的选项 include_config_file 代表 ejabberd 包含了其他配置文件to include other configuration files immediately.<br />
<br />
基本语法:<br />
<br />
'''{include_config_file, Filename}.'''<br />
<br />
使用完整语法还可以指定子选项 suboptions :<br />
<br />
'''{include_config_file, Filename, [Suboption, ...]}.'''<br />
<br />
filename 可使用绝对路径, 或使用和主 ejabberd 配置文件相关的相对路径. 不能使用通配符. 文件必须存在且可读.<br />
<br />
以下子选项 suboptions 为:<br />
<br />
'''{disallow, [Optionname, ...]}'''<br />
:不允许使用那些被包含文件中的选项. 满足这个条件的选项立刻变成不可接受. 缺省值为空列表: [] <br />
'''{allow_only, [Optionname, ...]}'''<br />
:只允许使用这个被包含的配置文件中的选项. 不满足这个条件的选项立刻变成不可接受. 缺省值为: all <br />
<br />
这是个基本例子:<br />
<br />
<source lang="ini"><br />
{include_config_file, "/etc/ejabberd/additional.cfg"}.<br />
</source><br />
<br />
在这个例子里, 被包含的文件不允许包含一个监听 listen 选项. 如果出现了这个选项, 该选项将不被接受. 这个文件在主配置文件所在目录的一个子目录中.<br />
<br />
<source lang="ini"><br />
{include_config_file, "./example.org/additional_not_listen.cfg", [{disallow, [listen]}]}.<br />
</source><br />
<br />
在这个例子, ejabberd.cfg 定义了一些 ACL 和 Access rules, 然后包含了另一个文件,里面含有其他 rules:<br />
<br />
<source lang="ini"><br />
{acl, admin, {user, "admin", "localhost"}}.<br />
{access, announce, [{allow, admin}]}.<br />
{include_config_file, "/etc/ejabberd/acl_and_access.cfg", [{allow_only, [acl, access]}]}.<br />
</source><br />
<br />
并且文件 acl_and_access.cfg 的内容可能是, 例如:<br />
<br />
<source lang="ini"><br />
{acl, admin, {user, "bob", "localhost"}}.<br />
{acl, admin, {user, "jan", "localhost"}}.<br />
</source><br />
<br />
====配置文件中的宏选项====<br />
<br />
在ejabberd配置文件中, 有可能为一个值定义一个宏 macro,晚些时候使用这个宏定义一个选项.<br />
<br />
一个宏 macro 可用以下语法定义:<br />
<br />
'''{define_macro, ’MACRO’, Value}.'''<br />
<br />
MACRO 必须被一对单引号包住, 而且所有字母为大写; 检查以下例子. 值必须是任何合法的随意的 Erlang 条目.<br />
<br />
macro的第一个定义会被保留的, 同一个macro的其它定义被忽略.<br />
<br />
Macros 在包含了额外的配置文件之后会被处理, 所以有可能在知道用法之前就使用定义在被包含的配置文件里的 macros.<br />
<br />
不能使用定义在另一个macro里面的macro.<br />
<br />
有两个办法使用宏:<br />
<br />
'''’MACRO’'''<br />
:你可以把它当成一个 ejabberd 选项的值, 它将被替换成这个macro之前定义的值. 如果这个 macro 之前没有定义, 程序将崩溃并报错.<br />
'''{use_macro, ’MACRO’, Defaultvalue}'''<br />
:使用一个macro,即使它之前没有定义. 如果这个 macro 之前没有定义, 使用缺省值 defaultvalue. 这个用法看起来好像它已被定义并以以下方法使用:<br />
<br />
<source lang="ini"><br />
{define_macro, 'MACRO', Defaultvalue}.<br />
'MACRO'<br />
</source><br />
<br />
这个例子展示一个宏的基本使用:<br />
<br />
<source lang="ini"><br />
{define_macro, 'LOG_LEVEL_NUMBER', 5}.<br />
{loglevel, 'LOG_LEVEL_NUMBER'}.<br />
</source><br />
<br />
结果被ejabberd解释执行的选项为: {loglevel, 5}.<br />
<br />
这个例子展示值可以是任意的Erlang条目:<br />
<br />
<source lang="ini"><br />
{define_macro, 'USERBOB', {user, "bob", "localhost"}}.<br />
{acl, admin, 'USERBOB'}.<br />
</source><br />
<br />
结果被ejabberd解释执行的选项为: {acl, admin, {user, "bob", "localhost"}}.<br />
<br />
这个复杂的例子:<br />
<br />
<source lang="ini"><br />
{define_macro, 'NUMBER_PORT_C2S', 5222}.<br />
{define_macro, 'PORT_S2S_IN', {5269, ejabberd_s2s_in, []}}.<br />
{listen,<br />
[<br />
{'NUMBER_PORT_C2S', ejabberd_c2s, []},<br />
'PORT_S2S_IN',<br />
{{use_macro, 'NUMBER_PORT_HTTP', 5280}, ejabberd_http, []}<br />
]<br />
}.<br />
</source><br />
<br />
在解释执行之后结果为:<br />
<br />
<source lang="ini"><br />
{listen,<br />
[<br />
{5222, ejabberd_c2s, []},<br />
{5269, ejabberd_s2s_in, []},<br />
{5280, ejabberd_http, []}<br />
]<br />
}.<br />
</source><br />
<br />
===数据库和LDAP配置===<br />
<br />
ejabberd缺省使用它内部的 Mnesia 数据库. 然而, 也可能使用关系数据库或一个LDAP服务器来存储持久信息, 长时间存在的数据. ejabberd是非常弹性的: 你可以为不同的虚拟主机配置不同的验证方法, 你可以为相同的主机配置不同的验证机制(fallback), 你可以为模块设置不同的存储系统, 此外.<br />
<br />
ejabberd支持以下数据库:<br />
<br />
* [http://www.microsoft.com/sql/ Microsoft SQL Server]<br />
* [http://www.erlang.org/doc/apps/mnesia/index.html Mnesia]<br />
* [http://www.mysql.com/ MySQL]<br />
* [http://en.wikipedia.org/wiki/Open_Database_Connectivity 任何ODBC兼容数据库]<br />
* [http://www.postgresql.org/ PostgreSQL]<br />
<br />
以下 LDAP 服务器已经过ejabberd测试:<br />
<br />
* [http://www.microsoft.com/activedirectory/ Active Directory] (见 [[Ejabberd2:安装和操作指南#Active Directory|3.2.5]] 节)<br />
* [http://www.openldap.org/ OpenLDAP]<br />
* 通常任何LDAP兼容服务器都应该可以; 通知我们关于你以不在列表中的服务器的成功例子以便我们列在这里. <br />
<br />
关于虚拟主机,特别注意: 如果你在ejabberd.cfg (见 [[Ejabberd2:安装和操作指南#主机名|3.1.1]] 节) 定义了多个域, 你可能希望每个虚拟主机配置不同的数据库, 验证和存储, 这样在两个虚拟主机之间用户名就不会冲突和混淆. 为此, 下一节的选项描述了必须在每个虚拟主机的 host_config 内部配置 (见 [[Ejabberd2:安装和操作指南#虚拟主机|3.1.2]] 节). 例如:<br />
<br />
<source lang="ini"><br />
{host_config, "public.example.org", [<br />
{odbc_server, {pgsql, "localhost", "database-public-example-org", "ejabberd", "password"}},<br />
{auth_method, [odbc]}<br />
]}.<br />
</source><br />
<br />
====MySQL====<br />
<br />
尽管这一节将描述当你想使用原生的 MySQL驱动时 ejabberd 的配置, 它将不描述MySQL的安装和数据库的建立. 查看MySQL文档和教程 [http://support.process-one.net/doc/display/MESSENGER/Using+ejabberd+with+MySQL+native+driver 在ejabberd使用MySQL原生驱动] 获得关于这些话题的信息. 注意该教程中包含的关于ejabberd的配置和本节是重复的.<br />
<br />
而且, 目录 src/odbc 中的文件 mysql.sql 可能你会感兴趣. 这个文件包含ejabberd用于MySQL的schema. 该文件的结尾你可找到更新你的数据库架构schema的信息.<br />
<br />
=====驱动编译=====<br />
<br />
你可忽略此步骤,如果你已经使用ejabberd的二进制包安装了ejabberd,并使用了内含的MySQL支持.<br />
<br />
# 首先, 安装 [http://support.process-one.net/doc/display/CONTRIBS/Yxa Erlang MySQL 库]. 确保被编译的文件在你的 Erlang 路径中; 你可以把它们放到和你的ejabberd .beam 文件相同的目录.<br />
# 然后, 以允许支持 ODBC 的选项配置并安装 ejabberd (这也需要原生 MySQL 支持!). 为此, 使用以下命令:<br />
<br />
<source lang="bash"><br />
./configure --enable-odbc && make install<br />
</source><br />
<br />
=====数据库连接=====<br />
<br />
实际的数据库访问使用选项 odbc_server 来定义. 它的值通常用来定义我们是否想使用 ODBC, 或两个可用的原生接口之一, PostgreSQL 或 MySQL.<br />
<br />
为使用原生 MySQL 接口, 你可以通过一组如以下格式的参数:<br />
<br />
'''{mysql, "Server", "Database", "Username", "Password"}'''<br />
<br />
mysql是一个关键字应该被保持. 例如:<br />
<br />
'''{odbc_server, {mysql, "localhost", "test", "root", "password"}}.'''<br />
<br />
可选的, 有可能定义MySQL使用的端口. 这个选项只是在非常少的情况下有用, 当你没有以缺省端口设置来运行MySQL时. mysql参数可能是以下格式:<br />
<br />
'''{mysql, "Server", Port, "Database", "Username", "Password"}'''<br />
<br />
Port值应该是一个整数, 没有引号. 例如:<br />
<br />
'''{odbc_server, {mysql, "localhost", Port, "test", "root", "password"}}.'''<br />
<br />
缺省的ejabberd为每个虚拟主机打开10个到数据库的连接. 使用这个选项来修改该值:<br />
<br />
<source lang="ini"><br />
{odbc_pool_size, 10}.<br />
</source><br />
<br />
你可以配置一个时间间隔来做一个假的SQL请求以保持到数据库的连接激活. 缺省值为 ’undefined’, 所以没有做 keepalive 请求. 指定以秒计: 例如 28800 意味着 8 小时.<br />
<br />
<source lang="ini"><br />
{odbc_keepalive_interval, undefined}.<br />
</source><br />
<br />
如果到数据库的连接失败, ejabberd在重试之前等待30秒. 你可以这个选项修改这个间隔:<br />
<br />
<source lang="ini"><br />
{odbc_start_interval, 30}.<br />
</source><br />
<br />
=====验证=====<br />
<br />
这个选项值的名字可能被误导, 因为 auth_method 名字用于通过ODBC以及通过原生MySQL接口访问关系数据库. 无论如何, 第一个配置步骤是定义 odbc auth_method. 例如:<br />
<br />
<source lang="ini"><br />
{auth_method, [odbc]}.<br />
</source><br />
<br />
=====存储=====<br />
<br />
MySQL也能被从多个ejabberd模块用于存储信息. 见 [[Ejabberd2:安装和操作指南#模块一览|3.3.1]] 节看哪个模块有一个带‘_odbc’的版本. 这个后缀代表这个模块可以被用于类似MySQL的关系数据库. 为激活你的数据库的存储, 只要确保你的数据库运行正常 (见前一节), 并把不带后缀或ldap模块变量换成带有 odbc 的模块变量. 注意在同一个装载的模块里你不能有多个变量!<br />
<br />
====Microsoft SQL Server====<br />
<br />
尽管本节将描述当你想使用Microsoft SQL Server时ejabberd的配置, 它不描述Microsoft SQL Server的安装和数据库创建. 查看MySQL文档和教程 [http://support.process-one.net/doc/display/MESSENGER/Using+ejabberd+with+MySQL+native+driver 在ejabberd使用MySQL原生驱动] 获得关于这些话题的信息. 注意该教程中包含的关于ejabberd的配置和本节是重复的.<br />
<br />
而且, 目录 src/odbc 中的文件 mssql.sql 可能你会感兴趣. 这个文件包含ejabberd用于Microsoft SQL Server的schema. 该文件的结尾你可找到更新你的数据库架构schema的信息.<br />
<br />
=====驱动编译=====<br />
<br />
你可忽略此步骤,如果你已经使用ejabberd的二进制包安装了ejabberd,并使用了内含的ODBC支持.<br />
<br />
如果你想以ODBC方式使用Microsoft SQL Server, 你需要以支持ODBC和允许Microsoft SQL Server选项来配置, 编译和安装 ejabberd. 为此, 使用以下命令:<br />
<br />
<source lang="bash"><br />
./configure --enable-odbc --enable-mssql && make install<br />
</source><br />
<br />
=====数据库连接=====<br />
<br />
一个Microsoft SQL Server数据库连接的配置和为一个ODBC兼容服务器的配置相同 (见 [[Ejabberd2:安装和操作指南#ODBC兼容|3.2.4]] 节).<br />
<br />
=====验证=====<br />
<br />
一个Microsoft SQL Server数据库验证的配置和为一个ODBC兼容服务器的配置相同 (见 [[Ejabberd2:安装和操作指南#ODBC兼容|3.2.4]] 节).<br />
<br />
=====存储=====<br />
<br />
Microsoft SQL Server也可以被多个ejabberd模块用于存储信息. 见 [[Ejabberd2:安装和操作指南#模块一览|3.3.1]] 节看看哪个模块有一个带‘_odbc’的版本. 这个后缀代表这个模块可以被用于类似Microsoft SQL Server的关系数据库. 为激活你的数据库的存储, 只要确保你的数据库运行正常 (见前一节), 并把不带后缀或ldap模块变量换成带有 odbc 的模块变量. 注意在同一个装载的模块里你不能有多个变量!<br />
<br />
====PostgreSQL====<br />
<br />
尽管本节将描述当你想使用原生的PostgreSQL驱动时ejabberd的配置, 它不描述PostgreSQL的安装和数据库创建. 查看PostgreSQL文档和教程 [http://support.process-one.net/doc/display/MESSENGER/Using+ejabberd+with+MySQL+native+driver 在ejabberd使用MySQL原生驱动] 获得关于这些话题的信息. 注意该教程中包含的关于ejabberd的配置和本节是重复的.<br />
<br />
而且, 目录 src/odbc 中的文件 pg.sql 可能你会感兴趣. 这个文件包含ejabberd用于PostgreSQL的schema. 该文件的结尾你可找到更新你的数据库架构schema的信息.<br />
<br />
=====驱动编译=====<br />
<br />
你可忽略此步骤,如果你已经使用ejabberd的二进制包安装了ejabberd,并包含了对PostgreSQL的支持.<br />
<br />
# 首先, 从 [http://www.ejabberd.im/ejabberd-modules/ ejabberd-modules SVN 仓库]安装 Erlang pgsql 库. 确保被编译的文件在你的 Erlang 路径中; 你可以把它们放到和你的ejabberd .beam 文件相同的目录.<br />
# 然后, 以允许支持 ODBC 的选项配置并安装 ejabberd (对于原生的 PostgreSQL 支持这也是必需的!). 为此, 使用以下命令:<br />
<br />
<source lang="bash"><br />
./configure --enable-odbc && make install<br />
</source><br />
<br />
=====数据库连接=====<br />
<br />
实际的数据库访问使用选项 odbc_server 来定义. 它的值通常用来定义我们是否想使用 ODBC, 或两个可用的原生接口之一, PostgreSQL 或 MySQL.<br />
<br />
为使用原生 PostgreSQL 接口, 你可以通过一组如以下格式的参数:<br />
<br />
'''{pgsql, "Server", "Database", "Username", "Password"}'''<br />
<br />
pgsql是一个关键字应该被保持. 例如:<br />
<br />
'''{odbc_server, {pgsql, "localhost", "database", "ejabberd", "password"}}.'''<br />
<br />
可选的, 有可能定义PostgreSQL使用的端口. 这个选项只是在非常少的情况下有用, 当你没有以缺省端口设置来运行PostgreSQL时. pgsql参数可能是以下格式:<br />
<br />
'''{pgsql, "Server", Port, "Database", "Username", "Password"}'''<br />
<br />
Port值应该是一个整数, 没有引号. 例如:<br />
<br />
'''{odbc_server, {pgsql, "localhost", 5432, "database", "ejabberd", "password"}}.'''<br />
<br />
缺省的ejabberd为每个虚拟主机打开10个到数据库的连接. 使用这个选项来修改该值:<br />
<br />
<source lang="ini"><br />
{odbc_pool_size, 10}.<br />
</source><br />
<br />
你可以配置一个时间间隔来做一个假的SQL请求以保持到数据库的连接激活. 缺省值为 ’undefined’, 所以没有做 keepalive 请求. 指定以秒计: 例如 28800 意味着 8 小时.<br />
<br />
<source lang="ini"><br />
{odbc_keepalive_interval, undefined}.<br />
</source><br />
<br />
=====验证=====<br />
<br />
这个选项值的名字可能被误导, 因为 auth_method 名字用于通过ODBC以及通过原生PostgreSQL接口访问关系数据库. 无论如何, 第一个配置步骤是定义 odbc auth_method. 例如:<br />
<br />
<source lang="ini"><br />
{auth_method, [odbc]}.<br />
</source><br />
<br />
=====存储=====<br />
<br />
PostgreSQL也能被多个ejabberd模块用于存储信息. 见 [[Ejabberd2:安装和操作指南#模块一览|3.3.1]] 节看哪个模块有一个带‘_odbc’的版本. 这个后缀代表这个模块可以被用于类似PostgreSQL的关系数据库. 为激活你的数据库的存储, 只要确保你的数据库运行正常 (见前一节), 并把不带后缀或ldap模块变量换成带有 odbc 的模块变量. 注意在同一个装载的模块里你不能有多个变量!<br />
<br />
====ODBC兼容====<br />
<br />
尽管本节将描述当你想使用原生的ODBC 驱动时ejabberd的配置, 它不描述安装和数据库创建. 查看你的数据库的文档. 教程 [http://support.process-one.net/doc/display/MESSENGER/Using+ejabberd+with+MySQL+native+driver 在ejabberd使用MySQL原生驱动] 也会对你有所帮助. 注意该教程中包含的关于ejabberd的配置和本节是重复的.<br />
<br />
=====驱动编译=====<br />
<br />
你可忽略此步骤,如果你已经使用ejabberd的二进制包安装了ejabberd,并包含了对ODBC的支持.<br />
<br />
# 首先, 安装 [http://support.process-one.net/doc/display/CONTRIBS/Yxa Erlang MySQL 库] . 确保被编译的文件在你的 Erlang 路径中; 你可以把它们放到和你的ejabberd .beam 文件相同的目录.<br />
# 然后, 以允许支持 ODBC 的选项配置并安装 ejabberd. 为此, 使用以下命令:<br />
<br />
<source lang="bash"><br />
./configure --enable-odbc && make install<br />
</source><br />
<br />
=====数据库连接=====<br />
<br />
实际的数据库访问使用选项 odbc_server 来定义. 它的值通常用来定义我们是否想使用 ODBC, 或两个可用的原生接口之一, PostgreSQL 或 MySQL.<br />
<br />
通过ODBC使用数据库, 你可以通过一个ODBC连接字符串作为odbc_server参数. 例如:<br />
<br />
<source lang="ini"><br />
{odbc_server, "DSN=database;UID=ejabberd;PWD=password"}.<br />
</source><br />
<br />
缺省的ejabberd为每个虚拟主机打开10个到数据库的连接. 使用这个选项来修改该值:<br />
<br />
<source lang="ini"><br />
{odbc_pool_size, 10}.<br />
</source><br />
<br />
你可以配置一个时间间隔来做一个假的SQL请求以保持到数据库的连接激活. 缺省值为 ’undefined’, 所以没有做 keepalive 请求. 指定以秒计: 例如 28800 意味着 8 小时.<br />
<br />
<source lang="ini"><br />
{odbc_keepalive_interval, undefined}.<br />
</source><br />
<br />
=====验证=====<br />
<br />
第一个配置步骤是定义 odbc auth_method. 例如:<br />
<br />
<source lang="ini"><br />
{auth_method, [odbc]}.<br />
</source><br />
<br />
=====存储=====<br />
<br />
一个ODBC兼容数据库也能被多个ejabberd模块用于存储信息. 见 [[Ejabberd2:安装和操作指南#模块一览|3.3.1]] 节看哪个模块有一个带‘_odbc’的版本. 这个后缀代表这个模块可以被用于ODBC兼容的关系数据库. 为激活你的数据库的存储, 只要确保你的数据库运行正常 (见前一节), 并把不带后缀或ldap模块变量换成带有 odbc 的模块变量. 注意在同一个装载的模块里你不能有多个变量!<br />
<br />
====LDAP====<br />
<br />
ejabberd拥有内建的LDAP支持. 你可以通过LDAP服务器验证用户并使用LDAP目录作为vCard存储器. 共享名册还不支持.<br />
<br />
通常ejabberd把LDAP看作一个只读存储: 它可能察看数据, 但不能新建账号或修改存储在LDAP里的vCard. 然而, 修改密码是可能的,如果允许 mod_register 模块并且LDAP服务器支持[http://tools.ietf.org/html/rfc3062 RFC 3062].<br />
<br />
=====连接=====<br />
<br />
参数:<br />
<br />
'''{ldap_servers, [Servers, ...]}'''<br />
:你的LDAP服务器的IP地址或DNS名的列表 . 这个选项时必需的. <br />
'''{ldap_encrypt, none|tls}'''<br />
:到LDAP服务器的连接的加密类型. 允许的值为: none, tls. 这个值 tls 允许使用SSL加密LDAP连接. 注意 STARTTLS 加密是不支持的. 缺省值为: none. <br />
'''{ldap_tls_verify, false|soft|hard}'''<br />
:这个选项指定当允许TLS时是否验证LDAP服务器证书. 当选项值为 hard,如果证书非法,ejabberd 不继续往下走. 当选项值为 soft,即使检查失败ejabberd仍继续下去. 缺省值为 false,它意味着不执行检查. <br />
'''{ldap_port, Number}'''<br />
:连接到你的LDAP服务器的端口. 如果禁止加密,缺省端口为389; 如果允许加密则为636. 如果你配置了一个值, 它存储在 ejabberd的数据库里. 接着, 如果你从这个配置文件移除这个值, 之前存储在数据库的值将被缺省端口取代. <br />
'''{ldap_rootdn, RootDN}'''<br />
:绑定的DN. 缺省值为"", 它表示匿名连接 ‘anonymous connection’. <br />
'''{ldap_password, Password}'''<br />
:绑定密码 password. 缺省值为 "". <br />
<br />
例子:<br />
<br />
<source lang="ini"><br />
{auth_method, ldap}.<br />
{ldap_servers, ["ldap.example.org"]}.<br />
{ldap_port, 389}.<br />
{ldap_rootdn, "cn=Manager,dc=domain,dc=org"}.<br />
{ldap_password, "secret"}.<br />
</source><br />
<br />
注意目前的LDAP实现不支持SASL验证.<br />
<br />
=====验证=====<br />
<br />
你可以通过LDAP目录验证用户. 可用的选项有:<br />
<br />
'''{ldap_base, Base}'''<br />
:LDAP存储用户的帐号的基础目录. 这个选项是必需的. <br />
'''{ldap_uids, [ {ldap_uidattr} | {ldap_uidattr, ldap_uidattr_format}, ...]}'''<br />
:从中可以获得JID的LDAP属性的列表. 缺省属性为 [{"uid", "%u"}]. 属性的格式为: [{ldap_uidattr}] 或 [{ldap_uidattr, ldap_uidattr_format}]. 你可以使用多个逗号来分隔需要的属性. ldap_uidattr 和 ldap_uidattr_format 的值描述如下:<br />
<br />
:'''ldap_uidattr'''<br />
::存有JID的user部分的LDAP属性. 缺省值为"uid". <br />
:'''ldap_uidattr_format'''<br />
::ldap_uidattr变量的格式. 这个格式必须包含一个并且只有一个 pattern 变量 "%u",它将由JID的suer部分替换. 例如,"%u@example.org". 缺省值为 "%u". <br />
<br />
'''{ldap_filter, Filter}'''<br />
:[http://tools.ietf.org/html/rfc4515 RFC 4515] LDAP过滤器. 缺省的 Filter 值为: undefined. 例子: "(&(objectClass=shadowAccount)(memberOf=Jabber Users))". 请, 不要忘记关闭括号并且不要用多余的空格. 在过滤器里你也必须不使用ldap_uidattr属性,因为这个属性将被LDAP filter自动取代. <br />
'''{ldap_dn_filter, { Filter, FilterAttrs }}'''<br />
:应用于主过滤器返回的结果的过滤器. 这个filter执行额外的LDAP搜索以得到完整的结果. 当你无法在ldap_filter里定义所有filter rule时这是有用的. 你可以在Filter定义 "%u", "%d", "%s" and "%D" pattern 变量: "%u" 被用户的JID的user部分替代, "%d" 被相应的域(虚拟主机)替代, 所有 "%s" 变量被FilterAttrs属性值连续地替代,"%D" 被 Distinguished Name(DN) 替代. 缺省的,ldap_dn_filter 为 undefined. 例子:<br />
<br />
<source lang="ini"><br />
{ldap_dn_filter, {"(&(name=%s)(owner=%D)(user=%u@%d))", ["sn"]}}.<br />
</source><br />
<br />
:因为这个filter做了额外的LDAP lookups, 只在最后排序时使用它: 如果可能,尝试在 ldap_filter里定义所有 filter rules . <br />
'''{ldap_local_filter, Filter}'''<br />
:如果因为性能原因 (该 LDAP 服务器有很多注册用户)你不能使用 ldap_filter , 你可以使用这个本地 filter. local filter 在ejabberd检查一个属性, 而不是 LDAP, 所以限制了这个LDAP目录的负载. 缺省 filter 是: undefined. 示例值:<br />
<br />
<source lang="ini"><br />
{ldap_local_filter, {notequal, {"accountStatus",["disabled"]}}}.<br />
{ldap_local_filter, {equal, {"accountStatus",["enabled"]}}}.<br />
{ldap_local_filter, undefined}.<br />
</source><br />
<br />
=====示例=====<br />
<br />
======普通示例======<br />
<br />
让我们以 ldap.example.org 作为我们的 LDAP 服务器名. 我们在 "ou=Users,dc=example,dc=org" 目录使用他们的密码. 同时我们有 addressbook, 在 "ou=AddressBook,dc=example,dc=org" 目录它包含了用户的 emails 和他们的其他信息 . 到LDAP服务器的连接使用TLS加密, 并且使用自定义端口 6123. 相应的验证节应该看起来象这样:<br />
<br />
<source lang="ini"><br />
%% Authentication method<br />
{auth_method, ldap}.<br />
%% DNS name of our LDAP server<br />
{ldap_servers, ["ldap.example.org"]}.<br />
%% Bind to LDAP server as "cn=Manager,dc=example,dc=org" with password "secret"<br />
{ldap_rootdn, "cn=Manager,dc=example,dc=org"}.<br />
{ldap_password, "secret"}.<br />
{ldap_encrypt, tls}.<br />
{ldap_port, 6123}.<br />
%% Define the user's base<br />
{ldap_base, "ou=Users,dc=example,dc=org"}.<br />
%% We want to authorize users from 'shadowAccount' object class only<br />
{ldap_filter, "(objectClass=shadowAccount)"}.<br />
</source><br />
<br />
现在我们想使用用户的 LDAP-info 作为他们的 vCards. 在我们的 LDAP schema定义了四个属性: "mail" — email地址, "givenName" — 名, "sn" — 姓, "birthDay" — 生日. 我们也想用户搜索到每个其他人. 我们看如何设置:<br />
<br />
<source lang="ini"><br />
{modules,<br />
[<br />
...<br />
{mod_vcard_ldap,<br />
[<br />
%% We use the same server and port, but want to bind anonymously because<br />
%% our LDAP server accepts anonymous requests to<br />
%% "ou=AddressBook,dc=example,dc=org" subtree.<br />
{ldap_rootdn, ""},<br />
{ldap_password, ""},<br />
%% define the addressbook's base<br />
{ldap_base, "ou=AddressBook,dc=example,dc=org"},<br />
%% uidattr: user's part of JID is located in the "mail" attribute<br />
%% uidattr_format: common format for our emails<br />
{ldap_uids, [{"mail", "%u@mail.example.org"}]},<br />
%% We have to define empty filter here, because entries in addressbook does not<br />
%% belong to shadowAccount object class<br />
{ldap_filter, ""},<br />
%% Now we want to define vCard pattern<br />
{ldap_vcard_map,<br />
[{"NICKNAME", "%u", []}, % just use user's part of JID as his nickname<br />
{"GIVEN", "%s", ["givenName"]},<br />
{"FAMILY", "%s", ["sn"]},<br />
{"FN", "%s, %s", ["sn", "givenName"]}, % example: "Smith, John"<br />
{"EMAIL", "%s", ["mail"]},<br />
{"BDAY", "%s", ["birthDay"]}]},<br />
%% Search form<br />
{ldap_search_fields,<br />
[{"User", "%u"},<br />
{"Name", "givenName"},<br />
{"Family Name", "sn"},<br />
{"Email", "mail"},<br />
{"Birthday", "birthDay"}]},<br />
%% vCard fields to be reported<br />
%% Note that JID is always returned with search results<br />
{ldap_search_reported,<br />
[{"Full Name", "FN"},<br />
{"Nickname", "NICKNAME"},<br />
{"Birthday", "BDAY"}]}<br />
]},<br />
...<br />
]}.<br />
</source><br />
<br />
注意 mod_vcard_ldap 模块在LDAP搜索用户的信息之前会先检查用户是否存在.<br />
<br />
======Active Directory======<br />
<br />
Active Directory 只是一个预定义属性的LDAP-服务器. 示范配置如下:<br />
<br />
<source lang="ini"><br />
{auth_method, ldap}.<br />
{ldap_servers, ["office.org"]}. % List of LDAP servers<br />
{ldap_base, "DC=office,DC=org"}. % Search base of LDAP directory<br />
{ldap_rootdn, "CN=Administrator,CN=Users,DC=office,DC=org"}. % LDAP manager<br />
{ldap_password, "*******"}. % Password to LDAP manager<br />
{ldap_uids, [{"sAMAccountName"}]}.<br />
{ldap_filter, "(memberOf=*)"}.<br />
<br />
{modules,<br />
[<br />
...<br />
{mod_vcard_ldap,<br />
[{ldap_vcard_map,<br />
[{"NICKNAME", "%u", []},<br />
{"GIVEN", "%s", ["givenName"]},<br />
{"MIDDLE", "%s", ["initials"]},<br />
{"FAMILY", "%s", ["sn"]},<br />
{"FN", "%s", ["displayName"]},<br />
{"EMAIL", "%s", ["mail"]},<br />
{"ORGNAME", "%s", ["company"]},<br />
{"ORGUNIT", "%s", ["department"]},<br />
{"CTRY", "%s", ["c"]},<br />
{"LOCALITY", "%s", ["l"]},<br />
{"STREET", "%s", ["streetAddress"]},<br />
{"REGION", "%s", ["st"]},<br />
{"PCODE", "%s", ["postalCode"]},<br />
{"TITLE", "%s", ["title"]},<br />
{"URL", "%s", ["wWWHomePage"]},<br />
{"DESC", "%s", ["description"]},<br />
{"TEL", "%s", ["telephoneNumber"]}]},<br />
{ldap_search_fields,<br />
[{"User", "%u"},<br />
{"Name", "givenName"},<br />
{"Family Name", "sn"},<br />
{"Email", "mail"},<br />
{"Company", "company"},<br />
{"Department", "department"},<br />
{"Role", "title"},<br />
{"Description", "description"},<br />
{"Phone", "telephoneNumber"}]},<br />
{ldap_search_reported,<br />
[{"Full Name", "FN"},<br />
{"Nickname", "NICKNAME"},<br />
{"Email", "EMAIL"}]}<br />
]},<br />
...<br />
]}.<br />
</source><br />
<br />
===模块配置===<br />
<br />
选项 modules 定义ejabberd启动后将被装载的模块的列表. 列表中的每个条目是一个组,第一个元素是一个模块的名称,第二个是一个模块列表的选项.<br />
<br />
语法是:<br />
<br />
'''{modules, [ {ModuleName, ModuleOptions}, ...]}.'''<br />
<br />
例子:<br />
<br />
* 在这个例子里只有模块 mod_echo 被装载宁且没有在方括号内定义该模块的选项:<br />
<br />
<source lang="ini"><br />
{modules,<br />
[<br />
{mod_echo, []}<br />
]}.<br />
</source><br />
<br />
* 在第二个例子里不带选项地装载了模块 mod_echo, mod_time, 和 mod_version. 特别注意, 除了最后一个条目, 所有条目都以一个逗号结尾:<br />
<br />
<source lang="ini"><br />
{modules,<br />
[<br />
{mod_echo, []},<br />
{mod_time, []},<br />
{mod_version, []}<br />
]}.<br />
</source><br />
<br />
====模块一览====<br />
<br />
下表列出ejabberd里的所有模块.<br />
<br />
{|border="1" cellspacing="0"<br />
!模块 !!功能 !!依赖<br />
|-<br />
|mod_adhoc ||特定命令 ([http://xmpp.org/extensions/xep-0050.html XEP-0050]) || <br />
|-<br />
|mod_announce ||管理公告 ||推荐 mod_adhoc<br />
|-<br />
|mod_caps ||实体能力 ([http://xmpp.org/extensions/xep-0115.html XEP-0115]) ||<br />
|-<br />
|mod_configure ||使用特定命令配置服务器 ||mod_adhoc<br />
|-<br />
|mod_disco ||服务发现 ([[XEP-0030]]) ||<br />
|-<br />
|mod_echo ||XMPP节回音 ||<br />
|-<br />
|mod_irc ||IRC网关 ||<br />
|-<br />
|mod_last ||最后活动 ([http://xmpp.org/extensions/xep-0012.html XEP-0012]) ||<br />
|-<br />
|mod_last_odbc ||最后活动 ([http://xmpp.org/extensions/xep-0012.html XEP-0012]) ||支持的数据库 (*)<br />
|-<br />
|mod_muc ||多用户聊天 ([[XEP-0045]]) ||<br />
|-<br />
|mod_muc_log ||多用户聊天室记录 ||mod_muc<br />
|-<br />
|mod_offline ||离线消息存储 ([http://xmpp.org/extensions/xep-0160.html XEP-0160]) ||<br />
|-<br />
|mod_offline_odbc ||离线消息存储 ([http://xmpp.org/extensions/xep-0160.html XEP-0160]) ||支持的数据库 (*)<br />
|-<br />
|mod_ping ||XMPP Ping 和定期保持连接 ([http://xmpp.org/extensions/xep-0199.html XEP-0199]) ||<br />
|-<br />
|mod_privacy ||禁止通讯 ([[RFC3921|XMPP IM]]) ||<br />
|-<br />
|mod_privacy_odbc ||禁止通讯 (([[RFC3921|XMPP IM]]) ||支持的数据库 (*)<br />
|-<br />
|mod_private ||私有XML存储 ([http://xmpp.org/extensions/xep-0049.html XEP-0049]) ||<br />
|-<br />
|mod_private_odbc ||私有XML存储 ([http://xmpp.org/extensions/xep-0049.html XEP-0049]) ||支持的数据库 (*)<br />
|-<br />
|mod_proxy65 ||SOCKS5字节流 ([[XEP-0065]]) ||<br />
|-<br />
|mod_pubsub ||发行-订阅 ([[XEP-0060]]), PEP ([[XEP-0163]]) ||mod_caps<br />
|-<br />
|mod_pubsub_odbc ||发行-订阅 ([[XEP-0060]]), PEP ([[XEP-0163]]) ||支持的数据库 (*) 和 mod_caps<br />
|-<br />
|mod_register ||I带内注册 ([[XEP-0077]]) ||<br />
|-<br />
|mod_roster ||名册管理 ([[RFC3921|XMPP IM]]) ||<br />
|-<br />
|mod_roster_odbc ||名册管理 ([[RFC3921|XMPP IM]]) ||支持的数据库 (*)<br />
|-<br />
|mod_service_log ||拷贝用户消息到日志服务 ||<br />
|-<br />
|mod_shared_roster ||共享名册管理 ||mod_roster 或 mod_roster_odbc<br />
|-<br />
|mod_sic Server ||IP检查 ([[XEP-0279]]) ||<br />
|-<br />
|mod_stats ||统计信息收集 ([[XEP-0039]]) ||<br />
|-<br />
|mod_time ||实体时间 ([[XEP-0202]]) ||<br />
|-<br />
|mod_vcard ||电子名片 ([[XEP-0054]]) ||<br />
|-<br />
|mod_vcard_ldap ||电子名片 ([[XEP-0054]]) ||LDAP服务器<br />
|-<br />
|mod_vcard_odbc ||电子名片 ([[XEP-0054]]) ||支持的数据库 (*)<br />
|-<br />
|mod_vcard_xupdate ||基于vCard的头像 ([[XEP-0153]]) ||mod_vcard 或 mod_vcard_odbc<br />
|-<br />
|mod_version ||软件版本 ([[XEP-0092]]) ||<br />
|}<br />
<br />
* (*) 这个模块需要数据库支持. 关于支持的数据库列表, 见 [[Ejabberd2:安装和操作指南#数据库和LDAP配置|3.2]] 节. <br />
<br />
通过后缀你可以看到每个模块需要哪个数据库后端:<br />
<br />
* 没有后缀, 这意味着那个模块使用Erlang的内建数据库 Mnesia 作为后端.<br />
* ‘_odbc’, 这意味着该模块需要一个支持的数据库 (见 [[Ejabberd2:安装和操作指南#数据库和LDAP配置|3.2]] 节) 作为后端.<br />
* ‘_ldap’, 这意味着该模块需要一个LDAP服务器作为后端. <br />
<br />
如果你想要, 有可能使用一个关系数据库来存储信息件. 你可以通过在ejabberd 配置文件修改模块名称带上_odbc 后缀来实现这点. 你可以为以下数据使用关系数据库:<br />
<br />
* 最后连接日期和时间: 使用 mod_last_odbc 取代 mod_last.<br />
* 离线消息: 使用 mod_offline_odbc 取代 mod_offline.<br />
* 名册: 使用 mod_roster_odbc 取代 mod_roster.<br />
* 用户的VCARD: 使用 mod_vcard_odbc 取代 mod_vcard.<br />
* 私有XML存储: 使用 mod_private_odbc 取代 mod_private.<br />
* 用户黑名单规则: 使用 mod_privacy_odbc 取代 mod_privacy. <br />
<br />
你可以在ejabberd网站找到更多别人[http://www.ejabberd.im/contributions 捐献的模块]的信息. 请记住这些捐献可能不能用或它们有些bug和安全泄露. 所以, 使用他们是你们自己的风险!<br />
<br />
====通用选项====<br />
<br />
以下选项被多个模块使用. 所以, 它们被单列一节.<br />
<br />
=====iqdisc=====<br />
<br />
很多模块为处理发到这个服务器或一个用户(例如. 给 example.org 或给 user@example.org)的不同namespaces的IQ queries定义了处理程序. 这个选项定义了这些queries的处理原则.<br />
<br />
语法是:<br />
<br />
'''{iqdisc, Value}'''<br />
<br />
可能的值有:<br />
<br />
'''no_queue'''<br />
:一个拥有此处理原则的 namespace 的所有 queries 会被立即处理. 这也意味着在这个包完全处理完之前,不可以处理任何包. 如果一个query的处理可能消耗比较长的时间,今后将不推荐这个原则. <br />
'''one_queue'''<br />
:在这种情况下,将为一个拥有此处理原则的 namespace建立一个独立的队列来处理它们. 另外, 这个队列的处理和其他包的队列是并行的. 这个原则是最推荐的. <br />
'''{queues, N}'''<br />
:N个独立的队列被建立用来处理这些 queries. 因而 queries 被并行处理, 但是以一个可控的方法. <br />
'''parallel'''<br />
:对每一个拥有此原则的包产生一个独立的Erlang进程. 所以, 所有这些包被并行处理. 尽管Erlang进程的产生成本相对较低, 这可能中断服务器的正常工作, 因为Erlang模拟器对进程数量有限制 (缺省为32000). <br />
<br />
例子:<br />
<br />
<source lang="ini"><br />
{modules,<br />
[<br />
...<br />
{mod_time, [{iqdisc, no_queue}]},<br />
...<br />
]}.<br />
</source><br />
<br />
=====host=====<br />
<br />
这个选项定义一个ejabberd 模块提供的服务的 Jabber ID.<br />
<br />
语法是:<br />
<br />
'''{host, HostName}'''<br />
<br />
如果你在 HostName 里包含了关键字 "@HOST@" , 它在启动时被替换为真实的虚拟主机字符串.<br />
<br />
这个例子配置了 echo 模块以 Jabber ID mirror.example.org来提供它的回音服务:<br />
<br />
<source lang="ini"><br />
{modules,<br />
[<br />
...<br />
{mod_echo, [{host, "mirror.example.org"}]},<br />
...<br />
]}.<br />
</source><br />
<br />
无论如何, 如果有多个虚拟主机并且这个模块在所有虚拟主机中都被激活, 必须使用"@HOST@" 关键字:<br />
<br />
<source lang="ini"><br />
{modules,<br />
[<br />
...<br />
{mod_echo, [{host, "mirror.@HOST@"}]},<br />
...<br />
]}.<br />
</source><br />
<br />
====mod_announce====<br />
<br />
本模块允许配置用户广播公告并设定本日消息 (MOTD). 被配置的用户可以在一个XMPP客户端使用Ad-hoc命令或发送消息给指定的JIDs来执行这些动作.<br />
<br />
特定命令被列于服务发现. 要使用此功能, 必须激活 mod_adhoc 模块.<br />
<br />
可以发送消息的特定 JIDs 清单如下. 在每个条目的第一个 JID 将只应用于指定的虚拟主机 example.org, 而括号里的 JID 将应用于ejabberd的所有虚拟主机.<br />
<br />
'''example.org/announce/all (example.org/announce/all-hosts/all)'''<br />
:消息将被发送给所有注册用户. 如果用户在线并连接了多个资源, 只有高优先级的资源将收到消息. 如果注册用户没有连接, 消息将离线存储,假定激活了离线存储 (见 [[Ejabberd2:安装和操作指南#mod_offline|3.3.12] 节). <br />
'''example.org/announce/online (example.org/announce/all-hosts/online)'''<br />
:消息被发送到所有已连接的用户. 如果用户在线且连接了多个资源, 所有资源将接收到消息. <br />
'''example.org/announce/motd (example.org/announce/all-hosts/motd)'''<br />
:该消息被设置为每日消息 (MOTD) 并在用户登录时被发送给用户. 另外这个消息会被发送给所有连接的用户 (类似 announce/online). <br />
'''example.org/announce/motd/update (example.org/announce/all-hosts/motd/update)'''<br />
:该消息被设置为每日消息 (MOTD) 并在用户登录时被发送给用户. 这个消息不发送给任何当前已连接的用户. <br />
'''example.org/announce/motd/delete (example.org/announce/all-hosts/motd/delete)'''<br />
:任何发送到此JID的消息移除现有的每日消息 (MOTD). <br />
<br />
选项:<br />
<br />
'''{access, AccessName}'''<br />
:这个选项指定谁被允许发送公告并设置每日消息 (缺省的, 没有人能发送这类消息). <br />
<br />
例子:<br />
<br />
* 只有管理员能发送公告:<br />
<br />
<source lang="ini"><br />
{access, announce, [{allow, admins}]}.<br />
<br />
{modules,<br />
[<br />
...<br />
{mod_adhoc, []},<br />
{mod_announce, [{access, announce}]},<br />
...<br />
]}.<br />
</source><br />
<br />
* 管理员以及 direction 可发送公告:<br />
<br />
<source lang="ini"><br />
{acl, direction, {user, "big_boss", "example.org"}}.<br />
{acl, direction, {user, "assistant", "example.org"}}.<br />
{acl, admins, {user, "admin", "example.org"}}.<br />
<br />
{access, announce, [{allow, admins},<br />
{allow, direction}]}.<br />
<br />
{modules,<br />
[<br />
...<br />
{mod_adhoc, []},<br />
{mod_announce, [{access, announce}]},<br />
...<br />
]}.<br />
</source><br />
<br />
注意 mod_announce 在大的布署里可能是资源敏感的,因为它可能广播非常多的消息. 对于拥有成百上千用户的ejabberd实例,这个模块应该被禁止.<br />
<br />
====mod_disco====<br />
<br />
这个模块增加多服务发现 ([[XEP-0030]]) 的支持. 激活本模块, 你的服务器上的服务可以被XMPP客户端发现. 注意ejabberd没有模块支持被取代的 Jabber Browsing ([http://xmpp.org/extensions/xep-0011.html XEP-0011]) 和 Agent Information ([http://xmpp.org/extensions/xep-0094.html XEP-0094]). 于是,如果你想它们能发现你提供的服务,XMPP客户端需要支持这个比较新的发现协议.<br />
<br />
选项:<br />
<br />
'''{iqdisc, Discipline}'''<br />
:这定义服务发现的IQ queries的处理原则 (http://jabber.org/protocol/disco#items 和 http://jabber.org/protocol/disco#info) (见 [[Ejabberd2:安装和操作指南#iqdisc|3.3.2]]). <br />
'''{extra_domains, [Domain, ...]}'''<br />
:使用这个选项, 你可以指定一个增加到服务发现条目列表中的附加域的列表. <br />
'''{server_info, [ {Modules, Field, [Value, ...]}, ... ]}'''<br />
:指定关于本服务器的额外的信息, 参见 XMPP服务的联系地址 ([http://xmpp.org/extensions/xep-0157.html XEP-0157]). Modules 可以是关键字‘all’, 这种情况下信息被汇报给所有服务; 或是一个 ejabberd 模块的列表, 这种情况下信息仅被指定给那些模块提供的服务. 可以指定任意的 Field 和 Value , 不只是联系地址. <br />
<br />
例子:<br />
<br />
* 提供一个链接到jabber.org上的Jabber用户目录:<br />
<br />
<source lang="ini"><br />
{modules,<br />
[<br />
...<br />
{mod_disco, [{extra_domains, ["users.jabber.org"]}]},<br />
...<br />
]}.<br />
</source><br />
<br />
* 提供一个链接到其他服务器的网关:<br />
<br />
<source lang="ini"><br />
{modules,<br />
[<br />
...<br />
{mod_disco, [{extra_domains, ["icq.example.com",<br />
"msn.example.com"]}]},<br />
...<br />
]}.<br />
</source><br />
<br />
* 提供一个链接到一些友好的服务器:<br />
<br />
<source lang="ini"><br />
{modules,<br />
[<br />
...<br />
{mod_disco, [{extra_domains, ["example.org",<br />
"example.com"]}]},<br />
...<br />
]}.<br />
</source><br />
<br />
* 使用这个配置, 所有服务在主服务器显示滥用地址, 回复地址, 并同时在主服务器和vJUD服务显示管理员地址:<br />
<br />
<source lang="ini"><br />
{modules,<br />
[<br />
...<br />
{mod_disco, [{server_info, [<br />
{all,<br />
"abuse-addresses",<br />
["mailto:abuse@shakespeare.lit"]},<br />
{[mod_muc],<br />
"Web chatroom logs",<br />
["http://www.example.org/muc-logs"]},<br />
{[mod_disco],<br />
"feedback-addresses",<br />
["http://shakespeare.lit/feedback.php", "mailto:feedback@shakespeare.lit", "xmpp:feedback@shakespeare.lit"]},<br />
{[mod_disco, mod_vcard],<br />
"admin-addresses",<br />
["mailto:xmpp@shakespeare.lit", "xmpp:admins@shakespeare.lit"]}<br />
]}]},<br />
...<br />
]}.<br />
</source><br />
<br />
====mod_echo====<br />
<br />
本模块简单地对任何XMPP包发出回音给发送者. ejabberd和XMPP客户端调试可能对这个镜子感兴趣.<br />
<br />
选项:<br />
<br />
'''{host, HostName}'''<br />
:这个选项定义服务的Jabber ID. 如果 host 选项没指定, Jabber ID 将是前缀‘echo.’加该虚拟主机的 hostname . 关键字 "@HOST@" 在启动时被替换成真实的虚拟主机名. <br />
<br />
例子: 镜子, 镜子, 在墙上, 他们谁是最美丽的?<br />
<br />
<source lang="ini"><br />
{modules,<br />
[<br />
...<br />
{mod_echo, [{host, "mirror.example.org"}]},<br />
...<br />
]}.<br />
</source><br />
<br />
====mod_http_bind====<br />
<br />
本模块实现了定义于 [http://xmpp.org/extensions/xep-0124.html XEP-0124] 和 [http://xmpp.org/extensions/xep-0206.html XEP-0206]的 XMPP over Bosh (正式的名字是 HTTP Binding). 它在这个将被伺服的服务上以一个可配置的资源扩展了ejabberd的HTTP服务, .<br />
<br />
要使用 HTTP-Binding, 激活这个模块:<br />
<br />
<source lang="ini"><br />
{modules,<br />
[<br />
...<br />
{mod_http_bind, []},<br />
...<br />
]}.<br />
</source><br />
<br />
并增加 http_bind 到 HTTP 服务. 例如:<br />
<br />
<source lang="ini"><br />
{listen, <br />
[<br />
...<br />
{5280, ejabberd_http, [<br />
http_bind,<br />
http_poll,<br />
web_admin<br />
]<br />
},<br />
...<br />
]}.<br />
</source><br />
<br />
使用这个配置, module 将伺服发送给 http://example.org:5280/http-bind/ 的请求. 记住这个页面不是被设计给web浏览器使用的, 它是被支持XMPP over Bosh的XMPP客户端使用的.<br />
<br />
如果你想以不同的URI路径设置服务或使用一个不同的模块, 你可以使用选项request_handlers手工配置它. 例如:<br />
<br />
<source lang="ini"><br />
{listen, <br />
[<br />
...<br />
{5280, ejabberd_http, [<br />
{request_handlers, [{["http-bind"], mod_http_bind}]},<br />
http_poll,<br />
web_admin<br />
]<br />
},<br />
...<br />
]}.<br />
</source><br />
<br />
选项:<br />
<br />
'''{max_inactivity, Seconds}'''<br />
:以秒数定义最大闲置时间. 缺省值为30秒. 例如, 设置成50秒:<br />
<br />
<source lang="ini"><br />
{modules,<br />
[<br />
...<br />
{mod_http_bind, [ {max_inactivity, 50} ]},<br />
...<br />
]}.<br />
</source><br />
<br />
====mod_http_fileserver====<br />
<br />
这个简单的模块从本地磁盘通过HTTP提供文件服务.<br />
<br />
选项:<br />
<br />
'''{docroot, Path}'''<br />
:伺服文件的目录. <br />
'''{accesslog, Path}'''<br />
:使用一个类似Apache格式的日志文件. 如果没指定本选项则不记录日志. <br />
'''{directory_indices, [Index, ...]}'''<br />
:包含一个或多个目录的索引文件, 类似 Apache的 DirectoryIndex 变量. 当一个web请求去到一个目录而不是常规的文件, 那些目录的 indices 被顺序装载, 并且返回被发现的第一个. <br />
'''{custom_headers, [ {Name, Value}, ...]}'''<br />
:表明自定义的HTTP头将被包含在所有应答中. 缺省值是: [] <br />
'''{content_types, [ {Name, Type}, ...]}'''<br />
:指定内容类型的扩展. 已经定义了很多 content types , 使用本选项你可以增加新的定义, 修改或删除现存的. 要删除现有定义, 简单的以一个值定义它: ‘undefined’. <br />
'''{default_content_type, Type}'''<br />
:指定 content type 使用未知的扩展. 缺省是‘application/octet-stream’. <br />
<br />
这个实例配置将从本地目录 /var/www 在地址 http://example.org:5280/pub/archive/ 提供文件服务. 在这个例子定义了一个新的 content type ogg, png 重新定义了, 而 jpg 定义被删除了. 要使用本模块你必须激活它:<br />
<br />
<source lang="ini"><br />
{modules,<br />
[<br />
...<br />
{mod_http_fileserver, [<br />
{docroot, "/var/www"}, <br />
{accesslog, "/var/log/ejabberd/access.log"},<br />
{directory_indices, ["index.html", "main.htm"]},<br />
{custom_headers, [{"X-Powered-By", "Erlang/OTP"},<br />
{"X-Fry", "It's a widely-believed fact!"}<br />
]},<br />
{content_types, [{".ogg", "audio/ogg"},<br />
{".png", "image/png"},<br />
{".jpg", undefined}<br />
]},<br />
{default_content_type, "text/html"}<br />
]<br />
},<br />
...<br />
]}.<br />
</source><br />
<br />
并且在HTTP服务里把它定义为一个处理器:<br />
<br />
<source lang="ini"><br />
{listen, <br />
[<br />
...<br />
{5280, ejabberd_http, [<br />
...<br />
{request_handlers, [<br />
...<br />
{["pub", "archive"], mod_http_fileserver},<br />
...<br />
]<br />
},<br />
...<br />
]<br />
},<br />
...<br />
]}.<br />
</source><br />
<br />
====mod_irc====<br />
<br />
本模块是一个 IRC 网关用于加入IRC服务器的频道.<br />
<br />
最终用户信息:<br />
<br />
* 一个支持‘groupchat 1.0’或 Multi-User Chat ([[XEP-0045]])的XMPP客户端需要加入IRC频道.<br />
* 一个IRC频道可能被以近似相同的方式加入一个XMPP多用户聊天室. 不同处是房间名将变成‘channel%irc.example.org’,在这个情况下 irc.example.org 是伺服‘channel’的IRC服务器. 并且当然这个主机应该指向IRC网关而不是多用户聊天服务.<br />
* 你可以注册你的昵称,通过发送‘IDENTIFY password’到 nickserver!irc.example.org@irc.jabberserver.org.<br />
* 键入你的密码,通过发送‘LOGIN nick password’到 nickserver!irc.example.org@irc.jabberserver.org.<br />
* IRC网关提供 Ad-Hoc Commands ([http://xmpp.org/extensions/xep-0050.html XEP-0050]) 来加入一个频道, 并设定自定义的 IRC 用户名和编码.<br />
* 当使用一个流行的XMPP服务器, 可能它没有到一些IRC服务器的连接存在,因为它们限制从一个IP来的连接的数量. <br />
<br />
选项:<br />
<br />
'''{host, HostName}'''<br />
:这个选项定义该服务的 Jabber ID. 如果 host 选项未定义, Jabber ID 将是该虚拟主机的 hostname 加上前缀‘irc.’. 关键字 "@HOST@" 在启动时被替换成真实的虚拟主机名. <br />
'''{access, AccessName}'''<br />
:这个选项可被用于定义谁能使用 IRC 网关 (缺省值: all). <br />
'''{default_encoding, Encoding}'''<br />
:设置缺省的 IRC 编码. 缺省值: "koi8-r" <br />
<br />
例子:<br />
<br />
* 在第一个例子里, IRC网关在你的所有带有前缀‘irc.’的虚拟主机上可用. 进一步的, 任何人可以使用这个这个网关. 缺省编码设为 "iso8859-15".<br />
<br />
<source lang="ini"><br />
{modules,<br />
[<br />
...<br />
{mod_irc, [{access, all}, {default_encoding, "iso8859-15"}]},<br />
...<br />
]}.<br />
</source><br />
<br />
* 在下一个例子,IRC网关对于那些拥有前缀irc-t.net的JIDs可用. 而且, 这个网关只可以被example.org的两个用户以及example.com上的所有用户使用:<br />
<br />
<source lang="ini"><br />
{acl, paying_customers, {user, "customer1", "example.org"}}.<br />
{acl, paying_customers, {user, "customer2", "example.org"}}.<br />
{acl, paying_customers, {server, "example.com"}}.<br />
<br />
{access, irc_users, [{allow, paying_customers}, {deny, all}]}.<br />
<br />
{modules,<br />
[<br />
...<br />
{mod_irc, [{access, irc_users},<br />
{host, "irc.example.net"}]},<br />
...<br />
]}.<br />
</source><br />
<br />
====mod_last====<br />
<br />
本模块增加对最后活动([http://xmpp.org/extensions/xep-0012.html XEP-0012])的支持. 它可被用于发现什么时候离线用户最后一次访问服务器, 并知道在这台服务器上一个连接的用户的最后活动, 或查询ejabberd服务器的运行时间.<br />
<br />
选项:<br />
<br />
'''{iqdisc, Discipline}'''<br />
:这是为 最后活动(jabber:iq:last) IQ queries 定义处理原则(见 [[Ejabberd2:安装和操作指南#iqdisc|3.3.2]] 节).<br />
<br />
====mod_muc====<br />
<br />
本模块提供一个多用户聊天([[XEP-0045]])服务. 用户可以发现现有房间, 加入或新建房间. 房间的房客可以公开或私下聊天.<br />
<br />
多用户聊天的一些功能:<br />
<br />
* 发送公开或私有消息给房间房客.<br />
* 邀请其他用户到一个房间.<br />
* 设定一个房间的标题.<br />
* 建立密码保护房间.<br />
* 踢人或拉黑名单. <br />
<br />
这个MUC服务允许任何Jabber ID注册一个昵称, 这样没有别人可以在该MUC服务的任何房间使用那个昵称. 为了注册一个昵称, 在你的XMPP客户端打开服务发现并注册到该MUC服务.<br />
<br />
本模块支持集群和负载均衡. 一个模块可被每个集群节点启动. 在特定的时间房间分布于所有可用的MUC模块实例上. 多用户聊天模块是集群的但房间本身不是集群的,也不是容错的: 如果管理那些房间的节点挂了, 那些房间就消失了并且它们将在第一次尝试连接得到的可用节点上重建.<br />
<br />
Module 选项:<br />
<br />
'''{host, HostName}'''<br />
:这个选项定义服务的Jabber ID. 如果 host 选项未指定, 该Jabber ID将是虚拟主机的hostname加上前缀‘conference.’. 关键字 "@HOST@" 在启动时被替换为真实的虚拟主机名. <br />
'''{access, AccessName}'''<br />
:你可以指定谁有权使用多用户聊天服务. 缺省每个人都被允许使用它. <br />
'''{access_create, AccessName}'''<br />
:为配置在多用户聊天服务里谁被允许创建新房间 , 可使用这个选项. 缺省任何本地ejabberd服务器的帐号都被允许新建房间. <br />
'''{access_persistent, AccessName}'''<br />
:为配置谁被允许修改持久 ’persistent’房间的选项. 缺省任何本地ejabberd服务器的帐号被允许修改那个选项. <br />
'''{access_admin, AccessName}'''<br />
:这个选项指定谁被允许管理多用户聊天服务. 缺省值为 none, 它意味着只有房间创建者可以管理他的房间. 管理员们可以发送一个普通消息给服务 JID, 并且它将被作为一个服务消息显示在所有房间. 管理员们可以发送一个 groupchat 消息给一个激活的房间的JID, 并且该消息将被显示为一个服务消息. <br />
'''{history_size, Size}'''<br />
:当用户进入房间时被发送给用户的一个当前讨论的短小历史. 使用此选项你可以定义保持的历史数据数量,用来在用户加入房间时发送给他们. 这个值是一个整数. 设定这个值为 0 禁止历史功能并且, 导致一个结果, 没东西保留在内存里. 这个缺省值是 20. 这个值是全局的并且因而会影响服务的所有房间. <br />
'''{max_users, Number}'''<br />
:这个选项定义是服务级别的, 每房间允许的最大用户数. 它可以低于每个房间的配置但是不能在单个的房间配置里增加. 缺省值为200. <br />
'''{max_users_admin_threshold, Number}'''<br />
:这个选项定义,当房间允许的最大房客数量达到之后,被允许进入房间的服务管理员或房间所有者的数量. 缺省限制为 5. <br />
'''{max_user_conferences, Number}'''<br />
:这个选项定义给定用户能加入的房间的最大数量. 缺省值为 10. 这个选项被用于阻止可能的滥用. 注意这是个软限制: 一些用户有时候可以在集群配置里加入更多的会议. <br />
'''{max_room_id, Number}'''<br />
:这个选项定义,当新建一个房间时,Room ID 字符串的可以有的最大长度. 缺省值是不限制: infinite. <br />
'''{max_room_name, Number}'''<br />
:这个选项定义,当配置一个房间时,Room Name 字符串的可以有的最大长度. 缺省值是不限制: infinite. <br />
'''{max_room_desc, Number}'''<br />
:这个选项定义,当配置一个房间时,Room Description 字符串的可以有的最大长度. 缺省值是不限制: infinite. <br />
'''{min_message_interval, Number}'''<br />
:这个选项定义,在一个房客发送的两个消息之间的最小间隔时间,以秒计. 这个选项是全局的并且检查所有房间. 可使用一个十进制值. 当这个选项没定义时, 消息速率是不限制的. 这个功能可用来保护MUC服务不被房客滥用并限制服务广播的消息数量. 对于这个最小消息间隔时间,一个比较好的值是0.4秒. 如果一个房客试图更快地发送消息, 发回一个错误并解释这个消息已被抛弃并描述为什么消息不被接受的原因. <br />
'''{min_presence_interval, Number}'''<br />
:这个选项定义一个给定房客的两次出席信息变更之间的最小时间,以秒计. 这个选项是全局的并且会对所有房间生效. 可以用一个十进制数值. 当这个选项没有定义的时候, 没有限制. 这个选项可被用于保护一个MUC服务不被房客滥用. 如果一个房客试图在指定的间隔时间内更多次的变更出席信息, 这个出席信息被 ejabberd 缓存并只有在间隔延迟过期后最新的出席信息被广播给房间里的所有房客. 中间的出席信息包被安静的抛弃. 一个好的选项值是4秒. <br />
'''{default_room_options, [ {OptionName, OptionValue}, ...]}'''<br />
:这个选项允许定义期望的缺省房间选项. 注意一个房间的创建者可以在任何时候使用一个有MUC能力的XMPP客户端修改他自己的房间的选项. 可用的房间选项和缺省值有:<br />
<br />
: '''{allow_change_subj, true|false}'''<br />
::允许房客修改标题. <br />
: '''{allow_private_messages, true|false}'''<br />
::房客可以发送私有消息给其他房客. <br />
: '''{allow_query_users, true|false}'''<br />
::房客可发送 IQ queries 给其他房客. <br />
: '''{allow_user_invites, false|true}'''<br />
::允许房客发送邀请. <br />
: '''{allow_visitor_nickchange, true|false}'''<br />
::允许游客修改昵称. <br />
: '''{allow_visitor_status, true|false}'''<br />
::允许游客在出席信息更新里发送status状态文本. I如果不允许, 在广播出席信息更新给房间里所有的房客时这个 status 文本被剥离. <br />
: '''{anonymous, true|false}'''<br />
::这个房间是匿名的: 房客看不到其他房客的真实JIDs. 注意房间主持人们总是看得见房客的真实JIDs. <br />
: '''{logging, false|true}'''<br />
::公开消息被使用mod_muc_log记录. <br />
: '''{max_users, 200}'''<br />
::房间里房客的最大数量. <br />
: '''{members_by_default, true|false}'''<br />
::进入房间的房客缺省成为参与者, 所以他们有发言权 ’voice’. <br />
: '''{members_only, false|true}'''<br />
::只有房间成员可以进入. <br />
: '''{moderated, true|false}'''<br />
::只有拥有发言权 ’voice’的房客可以发送公开消息. <br />
: '''{password, "roompass123"}'''<br />
::房间密码. 你可能希望也激活下一个选项. <br />
: '''{password_protected, false|true}'''<br />
::要求密码才能进入房间. <br />
: '''{persistent, false|true}'''<br />
::即使最后一个房客离开,房间仍持久存在. <br />
: '''{public, true|false}'''<br />
::房间在MUC服务列表里是公开的, 所以它是可发现的. <br />
: '''{public_list, true|false}'''<br />
::参与者名单是公开的, 不需要进入房间就能拿到. <br />
: '''{title, "Room Title"}'''<br />
::一个自然语言的房间称谓. <br />
<br />
:所有房间选项能被设定为 true 或 false, 除了 password 和 title 是字符串, 以及 max_users 是整数. <br />
<br />
例子:<br />
<br />
* 在第一个例子里,每个人都允许使用多用户聊天服务. 每个人也将能创建房间但只有用户admin@example.org被允许管理任何房间. 在这个例子里他也是一个全局的管理员. 当admin@example.org发送一个消息,例如‘Tomorrow, the XMPP server will be moved to new hardware. This will involve service breakdowns around 23:00 UMT. We apologise for this inconvenience.’ 给 conference.example.org, 这个消息将被显示在所有激活的房间里. 在这个例子里历史功能被禁止了.<br />
<br />
<source lang="ini"><br />
{acl, admin, {user, "admin", "example.org"}}.<br />
<br />
{access, muc_admin, [{allow, admin}]}.<br />
<br />
{modules,<br />
[<br />
...<br />
{mod_muc, [{access, all},<br />
{access_create, all},<br />
{access_admin, muc_admin},<br />
{history_size, 0}]},<br />
...<br />
]}.<br />
</source><br />
<br />
* 在第二个例子里多用户聊天服务只允许在我们的域和其他的服务器上注册了的付费客户访问. 当然管理员也是允许访问房间的. 而且, 他是唯一被授权可以建立并管理房间的. 当admin@example.org发送一个消息,例如‘Tomorrow, the Jabber server will be moved to new hardware. This will involve service breakdowns around 23:00 UMT. We apologise for this inconvenience.’ 给 conference.example.org, 它将被显示在所有激活的房间里. 没有使用 history_size 选项, 这意味着这个功能被激活但缺省值为20个历史消息,将被发送给用户们.<br />
<br />
<source lang="ini"><br />
{acl, paying_customers, {user, "customer1", "example.net"}}.<br />
{acl, paying_customers, {user, "customer2", "example.com"}}.<br />
{acl, paying_customers, {user, "customer3", "example.org"}}.<br />
{acl, admin, {user, "admin", "example.org"}}.<br />
<br />
{access, muc_admin, [{allow, admin},<br />
{deny, all}]}.<br />
{access, muc_access, [{allow, paying_customers},<br />
{allow, admin},<br />
{deny, all}]}.<br />
<br />
{modules,<br />
[<br />
...<br />
{mod_muc, [{access, muc_access},<br />
{access_create, muc_admin},<br />
{access_admin, muc_admin}]},<br />
...<br />
]}.<br />
</source><br />
<br />
* 在以下例子里, MUC使用了反滥用选项. 一个房客每0.4秒不能发送超过一个消息并且不能超过每4秒之内变更一次出席信息. Room IDs 和 Room Names 的长度被限制为 20 个字符, 而 Room Description 限制为 300 个字符. 没有定义 ACLs, 但一些用户限制可能被加入:<br />
<br />
<source lang="ini"><br />
{modules,<br />
[<br />
...<br />
{mod_muc, [{min_message_interval, 0.4},<br />
{min_presence_interval, 4},<br />
{max_room_id, 20},<br />
{max_room_name, 20},<br />
{max_room_desc, 300}]},<br />
...<br />
]}.<br />
</source><br />
<br />
* 这个例子展示如何使用 default_room_options 来确保新建房间缺省拥有的选项.<br />
<br />
<source lang="ini"><br />
{modules,<br />
[<br />
...<br />
{mod_muc, [{access, muc_access},<br />
{access_create, muc_admin},<br />
{default_room_options,<br />
[<br />
{allow_change_subj, false},<br />
{allow_query_users, true},<br />
{allow_private_messages, true},<br />
{members_by_default, false},<br />
{title, "New chatroom"},<br />
{anonymous, false}<br />
]},<br />
{access_admin, muc_admin}]},<br />
...<br />
]}.<br />
</source><br />
<br />
====mod_muc_log====<br />
<br />
本模块允许可选的把多用户聊天 (MUC)的公开谈话记录转为HTML. 一旦你激活了这个模块, 用户可以使用有MUC能力的XMPP客户端加入一个房间, 并且如果他们有足够的权限, 他们可以请求一个配置表单来设定配置并允许房间记录.<br />
<br />
功能:<br />
<br />
* 每页顶端加上房间细节: room 称谓, JID, 作者, 标题以及配置.<br />
* 房间JID 在生成的HTML里是一个链接,可用来加入该房间(使用 [http://xmpp.org/rfcs/rfc5122.html XMPP URI]).<br />
* 标题和房间配置变更会被跟踪和显示.<br />
* 加入, 离开, 修改昵称, 踢人, 拉黑名单和‘/me’被跟踪和显示, 包括原因(如果有).<br />
* 生成的 HTML 文件是 XHTML 1.0 Transitional 和 CSS 兼容的.<br />
* 时间戳是自参考的链接.<br />
* 快速浏览的链接在顶上: 前一天, 下一天, 上.<br />
* CSS被用于style定义, 可以使用一个自定义的 CSS 文件.<br />
* 消息和标题里的URLs被转换为超链接.<br />
* 时间戳上的时区被显示在记录文件里.<br />
* 可在每一个页的顶部增加一个自定义链接. <br />
<br />
选项:<br />
<br />
'''{access_log, AccessName}'''<br />
:这个选项限制哪个房客被允许激活和禁止房间记录. 缺省值为 muc_admin. 注意对于为了这个缺省设定生效,你需要有一个用于 muc_admin 的 access rule . <br />
'''{cssfile, false|URL}'''<br />
:使用这个选项你可以设置是否该HTML文件应该使用一个自定义的CSS文件或他们需要使用嵌入的CSS文件. 被允许的值有 false 和一个指向某CSS文件的URL. 使用第一个值, HTML文件将包含一个嵌入的CSS代码. 使用后一个, 你可以指定自定义CSS文件的URL (例如: "http://example.com/my.css"). 缺省的值是 false. <br />
'''{dirname, room_jid|room_name}'''<br />
:允许配置房间目录的名字. 被允许的值有 room_jid 和 room_name. 使用前者的值, 房间目录名将是完整的房间JID. 使用后者, 房间目录名将只是房间的名字, 不包括 MUC服务名. 缺省值是room_jid. <br />
'''{dirtype, subdirs|plain}'''<br />
:新建目录的类型可使用此选项指定. 允许的值有 subdirs 和 plain. 使用前者, 子目录以每年和月新建. 使用后者, 记录文件名包含完整的日期, 并且没有子目录. 缺省值是 subdirs. <br />
'''{file_format, html|plaintext}'''<br />
:定义日志文件的格式: html 存储成HTML格式, plaintext 存储成纯文本. 缺省值为 html. <br />
'''{outdir, Path}'''<br />
:这个选项是应该被存储的HTML文件的目录的全路径. 确保ejabberd守候进程对那个目录有写权限. 缺省值为 "www/muc". <br />
'''{spam_prevention true|false}'''<br />
:为了阻止垃圾, spam_prevention 选项增加了一个特别的属性给链接来阻止它们通过搜索引擎来索引. 缺省值为 true, 它意味着 nofollow 属性将被加到用户提交的链接里. <br />
'''{timezone, local|universal}'''<br />
:记录的时区可使用本选项配置. 允许的值有 local 和 universal. 使用前者, 将使用Erlang通过操作系统获得的本地时间. 使用后者, 将使用GMT/UTC 时间. 缺省值为 local. <br />
'''{top_link, {URL, Text}}'''<br />
:使用本选项你可以定制化每个日志文件的右上角的链接. 缺省值是 {"/", "Home"}. <br />
<br />
例子:<br />
<br />
* 在第一个例子里,任何房间所有者能激活记录, 并将使用一个自定义的CSS文件 (http://example.com/my.css). 记录文件的名字将包含完整日期, 并且将没有子目录. 记录文件将被存储在 /var/www/muclogs, 且时区将是GMT/UTC. 最后, 顶端链接将是 <a href="http://www.jabber.ru/">Jabber.ru</a>.<br />
<br />
<source lang="ini"><br />
{access, muc, [{allow, all}]}.<br />
<br />
{modules,<br />
[<br />
...<br />
{mod_muc_log, [<br />
{access_log, muc},<br />
{cssfile, "http://example.com/my.css"},<br />
{dirtype, plain},<br />
{dirname, room_jid},<br />
{outdir, "/var/www/muclogs"},<br />
{timezone, universal},<br />
{spam_prevention, true},<br />
{top_link, {"http://www.jabber.ru/", "Jabber.ru"}}<br />
]},<br />
...<br />
]}.<br />
</source><br />
<br />
* 在第二个例子里只有admin1@example.org和admin2@example.net可以激活记录, 并且将使用嵌入的CSS文件. 记录名将只包含日期(数字), 且每年和月将有子目录. 这个记录文件将被存储在 /var/www/muclogs, 且将使用本地时间. 最后, 顶端链接将是缺省的 <a href="/">Home</a>.<br />
<br />
<source lang="ini"><br />
{acl, admins, {user, "admin1", "example.org"}}.<br />
{acl, admins, {user, "admin2", "example.net"}}.<br />
<br />
{access, muc_log, [{allow, admins},<br />
{deny, all}]}.<br />
<br />
{modules,<br />
[<br />
...<br />
{mod_muc_log, [<br />
{access_log, muc_log},<br />
{cssfile, false},<br />
{dirtype, subdirs},<br />
{outdir, "/var/www/muclogs"},<br />
{timezone, local}<br />
]},<br />
...<br />
]}.<br />
</source><br />
<br />
====mod_offline====<br />
<br />
本模块实现离线消息存储 ([http://xmpp.org/extensions/xep-0160.html XEP-0160]). 这意味着所有被发送给一个离线用户的消息将被存储在服务器上直到那个用户再次上线. 所以它非常类似邮件的工作. 注意 ejabberdctl 有一个命令删除过期的消息 (见 [[Ejabberd2:安装和操作指南#ejabberdctl|4.1]] 节).<br />
<br />
'''{access_max_user_messages, AccessName}'''<br />
:这个选项定义哪个 access rule 将被强迫用来限制一个用户所拥有的离线消息的最大数量(配额). 当一个用户有太多离线消息, 任何收到的新消息将被抛弃, 并且将返回一个 资源约束 错误给发送者. 缺省值为 max_user_offline_messages. 接着你可以用类似max_user_sessions的语法定义一个 access rule (见 [[Ejabberd2:安装和操作指南#用ACL限制打开的会话|3.1.5]] 节). <br />
<br />
这个例子允许强力用户拥有大到 5000 个离线消息, 管理员达到 2000, 所有其他用户达到 100.<br />
<br />
<source lang="ini"><br />
{acl, admin, {user, "admin1", "localhost"}}.<br />
{acl, admin, {user, "admin2", "example.org"}}.<br />
{acl, poweruser, {user, "bob", "example.org"}}.<br />
{acl, poweruser, {user, "jane", "example.org"}}.<br />
<br />
{access, max_user_offline_messages, [ {5000, poweruser}, {2000, admin}, {100, all} ]}.<br />
<br />
{modules,<br />
[<br />
...<br />
{mod_offline, [ {access_max_user_messages, max_user_offline_messages} ]},<br />
...<br />
]}.<br />
</source><br />
<br />
====mod_ping====<br />
<br />
这个模块实现对XMPP Ping ([[XEP-0199]]) 和 定期保持连接 的支持. 当本模块激活时,ejabberd正确应答 ping 请求, 如协议所述.<br />
<br />
配置选项:<br />
<br />
'''{send_pings, true|false}'''<br />
:如果这个选项设为 true, 服务器在一个给定的间隔时间 ping_interval发送 pings 给已连接的不活跃的客户端. 这对于保持活着的客户端连接或检查可用性是有用的. 缺省这个选项是禁止的. <br />
'''{ping_interval, Seconds}'''<br />
:多久发送一次 ping 给已连接的用户, 如果前一个选项被激活. 如果一个客户端连接在这个间隔内没有发送或接收任何节, 一个 ping 请求被发送给客户端. 缺省值为60秒. <br />
'''{timeout_action, none|kill}'''<br />
:当一个客户端在32秒内不回答一个服务器的ping请求时,服务器做什么. 缺省是什么也不做. <br />
<br />
这个例子激活了 Ping 应答, 配置该模块发送 pings 给4分钟内不活跃的客户端连接, 并且如果一个客户端在32秒内不回答 ping , 它的连接将被关闭:<br />
<br />
<source lang="ini"><br />
{modules,<br />
[<br />
...<br />
{mod_ping, [{send_pings, true}, {ping_interval, 240}, {timeout_action, kill}]},<br />
...<br />
]}.<br />
</source><br />
<br />
====mod_privacy====<br />
<br />
本模块实现定义于[[RFC3921|XMPP IM]]第十章的禁止通讯 (也被称为隐私规则) . 如果最终用户在他们的XMPP客户端也支持它, 他们将能够:<br />
<br />
* 收到某人的隐私列表privacy lists.<br />
* 增加, 删除, 和修改某人的隐私列表privacy lists.<br />
* 设置, 修改, 或减少激活的列表active lists.<br />
* 设置, 修改, 或减少缺省列表default list (即, 缺省那个列表是激活的).<br />
* 允许或禁止消息,基于JID, group, 或 订阅类型subscription type (或全局的).<br />
* 允许或禁止入站的出席信息通知,基于JID, group, 或 订阅类型subscription type (或全局的).<br />
* 允许或禁止出站的出席信息通知,基于JID, group, 或 订阅类型subscription type (或全局的).<br />
* 允许或禁止IQ节,基于JID, group, 或 订阅类型subscription type (或全局的).<br />
* 允许或禁止所有通讯,基于JID, group, 或 订阅类型subscription type (或全局的).<br />
<br />
:(从 http://xmpp.org/rfcs/rfc3921.html#privacy) <br />
<br />
选项:<br />
<br />
'''{iqdisc, Discipline}'''<br />
:这为禁止通讯(jabber:iq:privacy) IQ queries (见 [[Ejabberd2:安装和操作指南#iqdisc|3.3.2]] 节)定义处理原则 .<br />
<br />
====mod_private====<br />
<br />
本模块增加对私有XML存储([[XEP-0049]])的支持:<br />
<br />
:使用这个方法, XMPP实体能存储私有数据到服务器并在任何必要的时候获得它. 存储的数据可以是任何东西, 只要它是合法的XML. 对这个namespace的一个典型的用法是服务器端存储特定客户端的配置; 另一个是标签存储([[XEP-0048]]). <br />
<br />
选项:<br />
<br />
'''{iqdisc, Discipline}'''<br />
:这为私有XML存储 (jabber:iq:private) IQ queries 定义处理原则(见 [[Ejabberd2:安装和操作指南#iqdisc|3.3.2]]).<br />
<br />
====mod_proxy65====<br />
<br />
本模块实现SOCKS5字节流([[XEP-0065]]). 它允许把ejabberd当作一个在两个XMPP客户端之间的文件传输代理.<br />
选项:<br />
<br />
'''{host, HostName}'''<br />
:这个选项定义该服务的Jabber ID. 如果 host 选项没指定, Jabber ID将是该虚拟主机的hostname加上前缀‘proxy.’. 关键字 "@HOST@" 在启动时被替换为真实的虚拟主机名. <br />
'''{name, Text}'''<br />
:定义服务的服务发现名称. 缺省是 "SOCKS5 Bytestreams". <br />
'''{ip, IPTuple}'''<br />
:这个选项定义监听哪个网络接口. 缺省是该服务的DNS名解析到的一个IP地址, 或, 如果失败, 则是{127,0,0,1}. <br />
'''{port, Number}'''<br />
:这个选项定义监听链入连接的端口. 缺省是 7777. <br />
'''{hostname, HostName}'''<br />
:定义一个在建立和客户端的会话时服务声明的hostname. 当你在一个NAT后面运行这个服务的时候这是有用的. 缺省是 ip 选项的值. 例如: "proxy.mydomain.org", "200.150.100.50". 注意在流协商的时候不是所有客户端都懂得域名, 所以在这个选项设定域名时你应该思考两次. <br />
'''{auth_type, anonymous|plain}'''<br />
:SOCKS5验证类型. 可能的值有 anonymous 和 plain. 缺省是 anonymous. <br />
'''{access, AccessName}'''<br />
:为文件传输发起者定义 ACL. 缺省是 all. <br />
'''{max_connections, Number}'''<br />
:每个文件传输的发起者的激活连接的最大数. 缺省不限制. <br />
'''{shaper, none|ShaperName}'''<br />
:这个选项为文件传输端定义塑性shaper. 有最大带宽的Shaper将被选择. 缺省是 none. <br />
<br />
例子:<br />
<br />
* 本模块最简单的配置:<br />
<br />
<source lang="ini"><br />
{modules,<br />
[<br />
...<br />
{mod_proxy65, []},<br />
...<br />
]}.<br />
</source><br />
<br />
* 更复杂的配置.<br />
<br />
<source lang="ini"><br />
{acl, proxy_users, {server, "example.org"}}.<br />
{access, proxy65_access, [{allow, proxy_users}, {deny, all}]}.<br />
<br />
{acl, admin, {user, "admin", "example.org"}}.<br />
{shaper, proxyrate, {maxrate, 10240}}. %% 10 Kbytes/sec<br />
{access, proxy65_shaper, [{none, admin}, {proxyrate, proxy_users}]}.<br />
<br />
{modules,<br />
[<br />
...<br />
{mod_proxy65, [{host, "proxy1.example.org"},<br />
{name, "File Transfer Proxy"},<br />
{ip, {200,150,100,1}},<br />
{port, 7778},<br />
{max_connections, 5},<br />
{access, proxy65_access},<br />
{shaper, proxy65_shaper}]},<br />
...<br />
]}.<br />
</source><br />
<br />
====mod_pubsub====<br />
<br />
本模块提供一个发行-订阅 服务 ([[XEP-0060]]). 在mod_pubsub里,功能可以使用插件来扩展. 实现PEP (基于Pubsub的个人信息事件) ([[XEP-0163]]) 的plugin, 在缺省的 ejabberd 配置文件中是被允许的, 并且它需要 mod_caps.<br />
<br />
选项:<br />
<br />
'''{host, HostName}'''<br />
:这个选项定义了该服务的Jabber ID. 如果 host 选项没定义, Jabber ID将是该虚拟主机的hostname加上前缀‘pubsub.’. 关键字 "@HOST@" 在启动时被替换成真实的虚拟主机名. 如果你使用了 mod_pubsub_odbc, 请确保前缀只包含一个点dot, 例如‘pubsub.’, 或 ‘publish.’,. <br />
'''{access_createnode, AccessName}'''<br />
:这个选项使用 ACL 和 ACCESS来限制哪个用户被允许建立 pubsub 节点. 缺省本地ejabberd服务器的任何帐号被允许新建 pubsub 节点. <br />
'''{max_items_node, MaxItems}'''<br />
:定义可被一个节点存储的条目的最大数量. 缺省值为 10. <br />
'''{plugins, [ Plugin, ...]}'''<br />
:用于指定plugins使用哪个pubsub节点. 列表的第一个缺省被使用. 如果这个选项没定义, 缺省 plugins 列表为: ["flat"]. PubSub客户端能定义使用哪个plugin,当新建一个节点的时候: 增加 type=’plugin-name’ 属性到这个 create 节元素里. <br />
'''{nodetree, Nodetree}'''<br />
:用于指定使用哪个节点树 nodetree. 如果没定义, 缺省使用 pubsub nodetree : "tree". 每个主机只能使用一个 nodetree , 且被所有节点 plugins 共享.<br />
<br />
:"virtual" nodetree 不把节点存储在数据库里. 它使用tons of nodes存储资源到系统. 如果使用 "virtual" nodetree, 你只能允许那些节点 plugins: ["flat","pep"] 或 ["flat"]; 任何其他 plugins 配置将不工作. 同时, 所有节点将有缺省配置, 并且不能被修改. 使用 "virtual" nodetree 需要从一个干净的数据库启动, 如果你之前使用了缺省的 "tree" nodetree,它将不工作.<br />
<br />
:"dag" nodetree 为 PubSub集合节点([[XEP-0248]])提供实验性的支持. 在那种情况下你也应该增加 "dag" 节点 plugin 作为缺省值, 例如: {plugins, ["dag","flat","hometree","pep"]} <br />
'''{ignore_pep_from_offline, false|true}'''<br />
:用于指定是否我们应该获取当我们连接时在我们的名册里处于离线状态的联系人的PEP最后发行条目. 值有 true 或 false. 如果不定义, pubsub 假定为 true,所以我们只能获取在线联系人的最后条目. <br />
'''{last_item_cache, false|true}'''<br />
:指定是否 pubsub 应该缓存最后条目. 值为 true 或 false. 如果没定义, pubsub不缓存最后条目. 在没有那么多节点的系统上, 缓存最后条目加速了 pubsub 并允许增加用户连接频率. 开销主要是内存使用, 因为每个条目都存储在内存里. <br />
'''{pep_mapping, [ {Key, Value}, ...]}'''<br />
:这允许定义一个 键-值 列表来在给定 PEP 名字空间选择定义节点 plugins . 以下例子将为每个拥有 tune namespace的PEP节点使用 node_tune 替代 node_pep :<br />
<br />
<source lang="ini"><br />
{mod_pubsub, [{pep_mapping, [{"http://jabber.org/protocol/tune", "tune"}]}]}<br />
</source><br />
<br />
配置例子使用 flat 节点作为缺省值, 并允许使用 flat, nodetree 和 pep 节点:<br />
<br />
<source lang="ini"><br />
{modules,<br />
[<br />
...<br />
{mod_pubsub, [<br />
{access_createnode, pubsub_createnode},<br />
{plugins, ["flat", "hometree", "pep"]}<br />
]},<br />
...<br />
]}.<br />
</source><br />
<br />
使用 ODBC 数据库要求使用重复的plugins. 以下例子展示前一个配置加上 ODBC 之后的用法:<br />
<br />
<source lang="ini"><br />
{modules,<br />
[<br />
...<br />
{mod_pubsub_odbc, [<br />
{access_createnode, pubsub_createnode},<br />
{plugins, ["flat_odbc", "hometree_odbc", "pep_odbc"]}<br />
]},<br />
...<br />
]}.<br />
</source><br />
<br />
====mod_register====<br />
<br />
本模块增加对带内注册([[XEP-0077]])的支持. 这个协议允许最终用户使用XMPP客户端做:<br />
<br />
* 在服务器注册一个新帐号.<br />
* 在服务器上给一个现有帐号修改密码.<br />
* 删除一个服务器上的现有帐号. <br />
<br />
选项:<br />
<br />
'''{access, AccessName}'''<br />
:这个选项可被配置来指定限制注册的 rules. 如果一个 rule 在请求的用户名返回‘deny’, 那个用户名的注册被禁止. (缺省没有限制). <br />
'''{access_from, AccessName}'''<br />
:缺省的, ejabberd不允许从s2s或已有的c2s会话注册一个新帐号. 你可以修改它,通过在这个选项定义 access rule. 谨慎使用: 允许从s2s注册会导致流氓用户的不可控的大量帐号注册. <br />
'''{welcome_message, Message}'''<br />
:设定一个欢迎信息发送给每一个新注册的帐号. 第一个字符串是标题, 第二个字符串是消息 body. 在body里你可以用字符: \n 设定一个新行<br />
'''{registration_watchers, [ JID, ...]}'''<br />
:这个选项定义一个 JIDs 列表,每次有人注册新帐号,他们将收到通知. <br />
'''{iqdisc, Discipline}'''<br />
:这为带内注册(jabber:iq:register) IQ queries (见 [[Ejabberd2:安装和操作指南#iqdisc|3.3.2]] 节)定义处理原则. <br />
<br />
这个模块也从服务器读取另一个全局定义的选项: {registration_timeout, Timeout}. 这个选项限制从一个给定IP或用户名发出的注册请求的频率. 所以, 一个用户在前一个注册之后,经过这个数量的秒数之前不能从相同IP地址或JID注册一个新帐号. Timeout被表示为秒数, 并且必须是一个整数. 要禁止此限制, 把整数替换成单词,类似: infinity. 缺省值为: 600 秒.<br />
<br />
例子:<br />
<br />
* 下个例子禁止注册太短的帐号名 prohibits:<br />
<br />
<source lang="ini"><br />
{acl, shortname, {user_glob, "?"}}.<br />
{acl, shortname, {user_glob, "??"}}.<br />
%% The same using regexp:<br />
%%{acl, shortname, {user_regexp, "^..?$"}}.<br />
<br />
{access, register, [{deny, shortname},<br />
{allow, all}]}.<br />
<br />
{modules,<br />
[<br />
...<br />
{mod_register, [{access, register}]},<br />
...<br />
]}.<br />
</source><br />
<br />
* 这个配置禁止使用带内注册新建和删除帐号, 但允许现有帐号修改密码:<br />
<br />
<source lang="ini"><br />
{access, register, [{deny, all}]}.<br />
<br />
{modules,<br />
[<br />
...<br />
{mod_register, [{access, register}]},<br />
...<br />
]}.<br />
</source><br />
<br />
* 这个配置禁止所有带内注册功能: 新建, 删除帐号和修改密码:<br />
<br />
<source lang="ini"><br />
{modules,<br />
[<br />
...<br />
%% {mod_register, [{access, register}]},<br />
...<br />
]}.<br />
</source><br />
<br />
* 定义一个欢迎信息和两个注册观察者. 也定义一个注册超时为一小时:<br />
<br />
<source lang="ini"><br />
{registration_timeout, 3600}.<br />
{modules,<br />
[<br />
...<br />
{mod_register,<br />
[<br />
{welcome_message, {"Welcome!", "Hi.\nWelcome to this Jabber server.\n Check http://www.jabber.org\n\nBye"}},<br />
{registration_watchers, ["admin1@example.org", "boss@example.net"]}<br />
]},<br />
...<br />
]}.<br />
</source><br />
<br />
====mod_roster====<br />
<br />
本模块实现名册管理,定义于 RFC 3921: [[RFC3921|XMPP IM]]. 也支持 名册版本 ([[XEP-0237]]).<br />
<br />
选项:<br />
<br />
'''{iqdisc, Discipline}'''<br />
:这为名册管理 (jabber:iq:roster) IQ queries (see section [Ejabberd2:安装和操作指南[#iqdisc|3.3.2]] 节) 指定处理原则. <br />
'''{versioning, false|true}'''<br />
:激活名册版本. 这个选项缺省是禁止的. <br />
'''{store_current_id, false|true}'''<br />
:如果激活这个选项, 当前版本数量被存储在数据库. 如果被禁止, 版本数量在每次飞行计算. 激活这个选项同时减少ejabberd和数据库的负载. 任何情况下这个选项不影响客户端. 该选项只是当允许名册版本时有用. 该选项缺省是被禁止的. 重要: 如果你使用 mod_shared_roster, 你必须禁止这个选项. <br />
<br />
这个示例配置允许使用当前id存储的名册版本:<br />
<br />
<source lang="ini"><br />
{modules,<br />
[<br />
...<br />
{mod_roster, [{versioning, true}, {store_current_id, true}]},<br />
...<br />
]}.<br />
</source><br />
<br />
====mod_service_log====<br />
<br />
本模块通过一个XMPP消息审计服务,例如Bandersnatch,增加了对最终用户的包进行记录的支持. 所有用户包被封装在一个 <route/> 元素里并发送给一个特定服务(们).<br />
<br />
选项:<br />
<br />
'''{loggers, [Names, ...]}'''<br />
:使用这个选项可以指定将接收包的一个 (列表之一) 服务(们). <br />
<br />
例子s:<br />
<br />
* 这是把所有的用户包记录到运行在bandersnatch.example.com的Bandersnatch 服务,:<br />
<br />
<source lang="ini"><br />
{modules,<br />
[<br />
...<br />
{mod_service_log, [{loggers, ["bandersnatch.example.com"]}]},<br />
...<br />
]}.<br />
</source><br />
<br />
* 这是把所有最终用户的包记录到运行在bandersnatch.example.com的Bandersnatch服务以及运行在bandersnatch.example.org的备份服务上:<br />
<br />
<source lang="ini"><br />
{modules,<br />
[<br />
...<br />
{mod_service_log, [{loggers, ["bandersnatch.example.com",<br />
"bandersnatch.example.org"]}]},<br />
...<br />
]}.<br />
</source><br />
<br />
====mod_shared_roster====<br />
<br />
本模块允许你新建共享名册组. 这意味着你可以新建人员组,组里的成员从他们的名册里的其他组也可以看到成员. 这个功能的最大好处是最终用户不需要手工添加所有用户到他们的名册, 并且他们不能永久性地从共享名册组删除用户. 一个共享名册组可拥有来自任何XMPP服务器的成员, 但是出席信息from和to将只在创建该组的相同的虚拟主机的成员之间可用.<br />
<br />
共享名册组只可以通过Web管理编辑. 每个组有唯一标识符和以下参数:<br />
<br />
'''Name'''<br />
:组名, 它将被显示在名册里. <br />
'''Description'''<br />
:组描述. 这个参数不影响任何东西. <br />
'''Members'''<br />
:组成员的完整JIDs列表, 在Web管理 里面每行一个. 为了把虚拟主机上的所有注册用户设为成员, 你可以使用特殊的参数: @all@. 注意这个参数被设计用于一个只有几百用户的小服务器. <br />
'''Displayed groups'''<br />
:那些成员将出现在名册上的组的列表. <br />
<br />
例子:<br />
<br />
* 假设一个计算机俱乐部希望它的所有成员在他们的名册里看到所有其他成员. 为了达到这点, 他们需要建立一个共享名册组类似下表: <br />
<br />
{|border="1" cellspacing="0"<br />
|Identification ||Group ‘club_members’<br />
|-<br />
|Name ||俱乐部成员<br />
|-<br />
|Description ||来自计算机俱乐部的成员<br />
|-<br />
|Members ||<br />
{|border="1" cellspacing="0"<br />
|member1@example.org <br />
|- <br />
|member2@example.org<br />
|-<br />
|member3@example.org <br />
|}<br />
|-<br />
|Displayed groups ||club_members<br />
|}<br />
<br />
* 在另一个情况下,我们有一个公司,它有三个部门: 管理部, 市场部和销售部. 所有组成员应该在他们的名册里看到其他成员. 另外, 所有经理应该在他们的名册里有所有市场部和销售部的人. 同时, 所有市场人员和全部销售队伍应该看到所有经理. 这个场景可由新建以下共享名册组来达到,如下表所示:<br />
<br />
{|border="1" cellspacing="0"<br />
|Identification || Group ‘management’||Group ‘marketing’|| Group ‘sales’<br />
|-<br />
|Name ||管理部 ||市场部 ||销售部<br />
|-<br />
|Description || || ||<br />
|-<br />
|Members ||<br />
{|border="1" cellspacing="0"<br />
|manager1@example.org <br />
|- <br />
|manager2@example.org<br />
|-<br />
|manager3@example.org <br />
|-<br />
|manager4@example.org <br />
|}<br />
||<br />
{|border="1" cellspacing="0"<br />
|marketeer1@example.org <br />
|- <br />
|marketeer2@example.org<br />
|-<br />
|marketeer3@example.org <br />
|-<br />
|marketeer4@example.org <br />
|}<br />
||<br />
{|border="1" cellspacing="0"<br />
|saleswoman1@example.org <br />
|- <br />
|salesman1@example.org<br />
|-<br />
|saleswoman2@example.org <br />
|-<br />
|alesman2@example.org <br />
|}<br />
|-<br />
|Displayed groups ||<br />
{|border="1" cellspacing="0" width="100%"<br />
|管理 <br />
|- <br />
|市场<br />
|-<br />
|销售 <br />
|}<br />
||<br />
{|border="1" cellspacing="0" width="100%"<br />
|管理 <br />
|- <br />
|市场<br />
|}<br />
||<br />
{|border="1" cellspacing="0" width="100%"<br />
|管理 <br />
|-<br />
|销售 <br />
|}<br />
|}<br />
<br />
====mod_sic====<br />
<br />
本模块增加了对服务器IP检查 ([[XEP-0279]])的支持. 这个协议允许客户端发现它的外部IP地址.<br />
<br />
选项:<br />
<br />
'''{iqdisc, Discipline}'''<br />
:这为urn:xmpp:sic:0 IQ queries (见 [[Ejabberd2:安装和操作指南#iqdisc|3.3.2]] 节)定义了处理原则 .<br />
<br />
====mod_stats====<br />
<br />
This module adds support for Statistics Gathering (XEP-0039). This protocol allows you to retrieve next statistics from your ejabberd deployment:<br />
<br />
* Total number of registered users on the current virtual host (users/total).<br />
* Total number of registered users on all virtual hosts (users/all-hosts/total).<br />
* Total number of online users on the current virtual host (users/online).<br />
* Total number of online users on all virtual hosts (users/all-hosts/online). <br />
<br />
选项:<br />
<br />
'''{iqdisc, Discipline}'''<br />
:这为统计信息收集 (http://jabber.org/protocol/stats) IQ queries (见 [[Ejabberd2:安装和操作指南#iqdisc|3.3.2]] 节) 定义了处理原则. <br />
<br />
因为只有少量的客户端 (例如 Tkabber) 和软件库支持这个 XEP, 一些例子以 XML 方式给出 ,为了获得统计信息,你需要发送它. 它们是:<br />
<br />
* 你可以请求当前虚拟主机 (example.org)的在线用户数量:<br />
<br />
<source lang="xml"><br />
<iq to='example.org' type='get'><br />
<query xmlns='http://jabber.org/protocol/stats'><br />
<stat name='users/online'/><br />
</query><br />
</iq><br />
</source><br />
<br />
* 你可以请求所有虚拟主机上注册用户的总数量:<br />
<br />
<source lang="xml"><br />
<iq to='example.org' type='get'><br />
<query xmlns='http://jabber.org/protocol/stats'><br />
<stat name='users/all-hosts/total'/><br />
</query><br />
</iq><br />
</source><br />
<br />
====mod_time====<br />
<br />
本模块功能支持实体时间 ([[XEP-0202]]). 通过使用这个 XEP, 你能发现另一个实体所在位置的时间.<br />
<br />
选项:<br />
<br />
'''{iqdisc, Discipline}'''<br />
:这为实体时间 (jabber:iq:time) IQ queries (见 [[Ejabberd2:安装和操作指南#iqdisc|3.3.2]] 节)定义了处理原则 .<br />
<br />
====mod_vcard====<br />
<br />
本模块允许最终用户存储和接收他们的电子名片vCard, 以及接收别的用户的电子名片vCards, 定义于 vcard-temp ([[XEP-0054]]). 这个模块也实现了一个基于这些用户的vCards的简单的Jabber用户目录. 进一步的, 当收到请求时它允许服务器发送它自己的名片vCard.<br />
<br />
选项:<br />
<br />
'''{host, HostName}'''<br />
:这个选项定义该服务的Jabber ID. 如果 host 选项没定义, Jabber ID将是该虚拟主机的hostname加前缀‘vjud.’. 关键字 "@HOST@" 在启动时被替换成真实的虚拟主机名. <br />
'''{iqdisc, Discipline}'''<br />
:这为vcard-temp IQ queries (见 [[Ejabberd2:安装和操作指南#iqdisc|3.3.2]] 节)定义了处理原则 . <br />
'''{search, true|false}'''<br />
:这个选项定义是否允许搜索功能,如果禁止,选项 host 将被忽略,并且 Jabber用户目录服务将不出现在服务发现条目列表里. 缺省值为true. <br />
'''{matches, infinity|Number}'''<br />
:使用这个选项, 搜索结果的数量将被限制. 如果这下选项的值设为 infinity, 所有搜索结果被汇报. 缺省值为 30. <br />
'''{allow_return_all, false|true}'''<br />
:这个选项允许你指定是否输入字段为空来进行搜索操作应该返回所有已在他们的vCard中加入信息的用户. 缺省值为 false. <br />
'''{search_all_hosts, true|false}'''<br />
:如果这个选项设为 true, 搜索操作将应用于所有虚拟主机. 反之只有当前主机将被搜索. 缺省值为 true. 这个选项在 mod_vcard 是可用的, 但是在 mod_vcard_odbc 是不可用的. <br />
<br />
例子:<br />
<br />
* 在第一种情况下, 搜索结果被限制为20个条目, 当人们做空的搜索时,每个添加了信息到他们的vCard的用户将被列出 , 并且只有当前主机的用户会被返回:<br />
<br />
<source lang="ini"><br />
{modules,<br />
[<br />
...<br />
{mod_vcard, [{search, true},<br />
{matches, 20},<br />
{allow_return_all, true},<br />
{search_all_hosts, false}]},<br />
...<br />
]}.<br />
</source><br />
<br />
* 第二种情况不同在于,搜索结果是不限制的, 并且所有虚拟主机将被搜索而不是只有当前主机:<br />
<br />
<source lang="ini"><br />
{modules,<br />
[<br />
...<br />
{mod_vcard, [{search, true},<br />
{matches, infinity},<br />
{allow_return_all, true}]},<br />
...<br />
]}.<br />
</source><br />
<br />
====mod_vcard_ldap====<br />
<br />
ejabberd能映射LDAP属性到vCard字段. 这个行为在 mod_vcard_ldap 模块实现. 本模块不依赖于验证方法 (见 [[Ejabberd2:安装和操作指南#LDAP|3.2.5]] 节).<br />
<br />
经常的 ejabberd 对待 LDAP 像一个只读存储器: 它可能查看数据, 但是不能新建帐号或编辑存储在LDAP里的 vCard. 无论如何, 修改密码是可能的,如果 mod_register 模块激活了并且 LDAP 服务器支持 [http://tools.ietf.org/html/rfc3062 RFC 3062].<br />
<br />
mod_vcard_ldap模块有它自己的可选参数. 第一组参数和设定验证方法时的顶极LDAP参数含义相同: ldap_servers, ldap_port, ldap_rootdn, ldap_password, ldap_base, ldap_uids, and ldap_filter. 见 [[Ejabberd2:安装和操作指南#LDAP|3.2.5]] 节查看关于这些选项的详细信息. 如果这些选项中的一个没有设置, ejabberd将以相同哦功能名字查找顶极选项.<br />
<br />
第二组参数包括以下的 mod_vcard_ldap-专有 选项:<br />
<br />
'''{host, HostName}'''<br />
:这个选项定义该服务的Jabber ID. 如果 host 选项没定义, Jabber ID将是该虚拟主机的hostname加上前缀‘vjud.’. 关键字 "@HOST@" 在启动时被替换成真实的虚拟主机名. <br />
'''{iqdisc, Discipline}'''<br />
:这为 vcard-temp IQ queries (见 [[Ejabberd2:安装和操作指南#iqdisc|3.3.2]] 节)定义了处理原则 . <br />
'''{search, true|false}'''<br />
:这个选项指定是否搜索功能被允许(值: true) 或禁止(值: false). 如果禁止, 选项 host 将被忽略,并且Jabber用户目录服务将不出现在服务发现条目列表里. 缺省值为 true. <br />
'''{matches, infinity|Number}'''<br />
:使用这个选项, 搜索结果的数量被限制. 如果该选项值设为 infinity, 所有结果被汇报. 缺省值为 30. <br />
'''{ldap_vcard_map, [ {Name, Pattern, LDAPattributes}, ...]}'''<br />
:使用此选项,你可以设置一个表,映射LDAP属性到vCard字段. Name是 vCard 的类型名,定义于 [http://tools.ietf.org/html/rfc2426 RFC 2426]. Pattern是一个字符串,包含 pattern 变量 "%u", "%d" 或 "%s". LDAPattributes 是包含LDAP属性的列表. pattern变量 "%s" 将被从 List_of_LDAP_attributes顺序替换成 LDAP 属性值, "%u" 将被替换成一个JID的user部分, 而"%d" 将被替换成一个JID的domain部分. 缺省为:<br />
<br />
<source lang="ini"><br />
[{"NICKNAME", "%u", []},<br />
{"FN", "%s", ["displayName"]},<br />
{"LAST", "%s", ["sn"]},<br />
{"FIRST", "%s", ["givenName"]},<br />
{"MIDDLE", "%s", ["initials"]},<br />
{"ORGNAME", "%s", ["o"]},<br />
{"ORGUNIT", "%s", ["ou"]},<br />
{"CTRY", "%s", ["c"]},<br />
{"LOCALITY", "%s", ["l"]},<br />
{"STREET", "%s", ["street"]},<br />
{"REGION", "%s", ["st"]},<br />
{"PCODE", "%s", ["postalCode"]},<br />
{"TITLE", "%s", ["title"]},<br />
{"URL", "%s", ["labeleduri"]},<br />
{"DESC", "%s", ["description"]},<br />
{"TEL", "%s", ["telephoneNumber"]},<br />
{"EMAIL", "%s", ["mail"]},<br />
{"BDAY", "%s", ["birthDay"]},<br />
{"ROLE", "%s", ["employeeType"]},<br />
{"PHOTO", "%s", ["jpegPhoto"]}]<br />
</source><br />
<br />
'''{ldap_search_fields, [ {Name, Attribute}, ...]}'''<br />
:这个选项定义搜索表单和参与搜索的LDAP属性. Name 是搜索表单字段的名字,它将使用翻译文件自动翻译 (查看 msgs/*.msg 找寻可用的单词). Attribute 是LDAP属性或 pattern "%u". 缺省值是:<br />
<br />
<source lang="ini"><br />
[{"User", "%u"},<br />
{"Full Name", "displayName"},<br />
{"Given Name", "givenName"},<br />
{"Middle Name", "initials"},<br />
{"Family Name", "sn"},<br />
{"Nickname", "%u"},<br />
{"Birthday", "birthDay"},<br />
{"Country", "c"},<br />
{"City", "l"},<br />
{"Email", "mail"},<br />
{"Organization Name", "o"},<br />
{"Organization Unit", "ou"}]<br />
</source><br />
<br />
'''{ldap_search_reported, [ {SearchField, VcardField}, ...]}'''<br />
:这个选项定义哪个搜索字段应该汇报. SearchField 是一个搜索表单的字段名,它将使用翻译文件自动翻译 (去 msgs/*.msg 查看可用的单词). VcardField 是vCard 字段名,定义于 ldap_vcard_map 选项. 缺省为:<br />
<br />
<source lang="ini"><br />
[{"Full Name", "FN"},<br />
{"Given Name", "FIRST"},<br />
{"Middle Name", "MIDDLE"},<br />
{"Family Name", "LAST"},<br />
{"Nickname", "NICKNAME"},<br />
{"Birthday", "BDAY"},<br />
{"Country", "CTRY"},<br />
{"City", "LOCALITY"},<br />
{"Email", "EMAIL"},<br />
{"Organization Name", "ORGNAME"},<br />
{"Organization Unit", "ORGUNIT"}]<br />
</source><br />
<br />
例子:<br />
<br />
* 假设 ldap.example.org 是我们的一个LDAP服务器的名字. 我们有用户,他们的密码在 "ou=Users,dc=example,dc=org" 目录. 同时我们也有地址簿 addressbook, 它包含用户的 emails 和他们的其他信息, 在 "ou=AddressBook,dc=example,dc=org" 目录. 相应的验证节应该看起来是这样:<br />
<br />
<source lang="ini"><br />
%% 验证方法<br />
{auth_method, ldap}.<br />
%% 我们的LDAP服务器的DNS名<br />
{ldap_servers, ["ldap.example.org"]}.<br />
%% 我们想授权的用户仅为 'shadowAccount' object class<br />
{ldap_filter, "(objectClass=shadowAccount)"}.<br />
</source><br />
<br />
;现在我们想使用用户的 LDAP-信息 作为他们的 vCards. 我们在我们的 LDAP schema定义了四个属性: "mail" — emai地址, "givenName" — 名, "sn" — 姓, "birthDay" — 生日. 我们也想用户搜索到每个其他人. 让我们看一下如何设置:<br />
<br />
<source lang="ini"><br />
{modules,<br />
...<br />
{mod_vcard_ldap,<br />
[<br />
%% We use the same server and port, but want to bind anonymously because<br />
%% our LDAP server accepts anonymous requests to<br />
%% "ou=AddressBook,dc=example,dc=org" subtree.<br />
{ldap_rootdn, ""},<br />
{ldap_password, ""},<br />
%% define the addressbook's base<br />
{ldap_base, "ou=AddressBook,dc=example,dc=org"},<br />
%% uidattr: user's part of JID is located in the "mail" attribute<br />
%% uidattr_format: common format for our emails<br />
{ldap_uids, [{"mail","%u@mail.example.org"}]},<br />
%% We have to define empty filter here, because entries in addressbook does not<br />
%% belong to shadowAccount object class<br />
{ldap_filter, ""},<br />
%% Now we want to define vCard pattern<br />
{ldap_vcard_map,<br />
[{"NICKNAME", "%u", []}, % just use user's part of JID as his nickname<br />
{"FIRST", "%s", ["givenName"]},<br />
{"LAST", "%s", ["sn"]},<br />
{"FN", "%s, %s", ["sn", "givenName"]}, % example: "Smith, John"<br />
{"EMAIL", "%s", ["mail"]},<br />
{"BDAY", "%s", ["birthDay"]}]},<br />
%% Search form<br />
{ldap_search_fields,<br />
[{"User", "%u"},<br />
{"Name", "givenName"},<br />
{"Family Name", "sn"},<br />
{"Email", "mail"},<br />
{"Birthday", "birthDay"}]},<br />
%% vCard fields to be reported<br />
%% Note that JID is always returned with search results<br />
{ldap_search_reported,<br />
[{"Full Name", "FN"},<br />
{"Nickname", "NICKNAME"},<br />
{"Birthday", "BDAY"}]}<br />
]}<br />
...<br />
}.<br />
</source><br />
<br />
:注意 mod_vcard_ldap 模块在LDAP搜索用户的信息之前会先检查用户是否存在.<br />
<br />
* ldap_vcard_map 例子:<br />
<br />
<source lang="ini"><br />
{ldap_vcard_map,<br />
[{"NICKNAME", "%u", []},<br />
{"FN", "%s", ["displayName"]},<br />
{"CTRY", "Russia", []},<br />
{"EMAIL", "%u@%d", []},<br />
{"DESC", "%s\n%s", ["title", "description"]}<br />
]},<br />
</source><br />
<br />
* ldap_search_fields 例子:<br />
<br />
<source lang="ini"><br />
{ldap_search_fields,<br />
[{"User", "uid"},<br />
{"Full Name", "displayName"},<br />
{"Email", "mail"}<br />
]},<br />
</source><br />
<br />
* ldap_search_reported 例子:<br />
<br />
<source lang="ini"><br />
{ldap_search_reported,<br />
[{"Full Name", "FN"},<br />
{"Email", "EMAIL"},<br />
{"Birthday", "BDAY"},<br />
{"Nickname", "NICKNAME"}<br />
]},<br />
</source><br />
<br />
====mod_vcard_xupdate====<br />
<br />
用户的客户端能在该用户的vCard存储一个头像. 基于vCard的头像 协议 ([[XEP-0153]]) 提供了一个方法给客户端来通知联系人他的头像的哈希值. 然而, 简单或小的客户端可能没有实现那个协议.<br />
<br />
如果本模块被激活, 所有出站的客户端出席信息节代替客户端自动获得头像哈希值. 所以, 联系人收到这个带有更新数据的出席信息节(见 [[XEP-0153]]),就好像客户端自己把它插入进去的一样. 如果客户端已经在出席信息节里包含了这样的元素, 它被替换成 ejabberd 生成的元素.<br />
<br />
通过激活本模块, 每次 vCard 修改就重新进行一次哈希值计算, 每个由客户端发送的出席信息导致一次哈希值接收,以及一次出席信息节的重写. 因此, 激活本模块将在服务器发生一些计算开销,如果客户端频繁修改他们的出席信息的话.<br />
<br />
====mod_version====<br />
<br />
本模块实现软件版本([[XEP-0092]]). 所以, 当被查询时它应答 ejabberd 的版本.<br />
<br />
选项:<br />
<br />
'''{show_os, true|false}'''<br />
:是否应该显示操作系统. 缺省值是 true. <br />
'''{iqdisc, Discipline}'''<br />
:这为软件版本(jabber:iq:version) IQ queries (见 [[Ejabberd2:安装和操作指南#iqdisc|3.3.2]] 节)定义了处理原则 .<br />
<br />
==管理ejabberd服务器==<br />
===ejabberdctl===<br />
<br />
使用ejabberdctl命令行管理脚本,你可以执行ejabberdctl命令(详见下一节, [[Ejabberd2:安装和操作指南#ejabberdctl命令|4.1.1]]) 和一些普通的 ejabberd 命令 (详见 [[[[Ejabberd2:安装和操作指南#ejabberd命令|4.2]]). 这意味着你可以在一个本地或远程ejabberd服务器(通过提供参数 --node NODENAME)上启动,停止以及执行一些其他的管理任务.<br />
<br />
ejabberdctl脚本可在文件 ejabberdctl.cfg 里配置. 这个文件包含每个可配置的选项的详细的信息. 见 [[Ejabberd2:安装和操作指南#Erlang运行时系统|4.1.2]] 节.<br />
<br />
ejabberdctl脚本返回数字状态码. 成功显示为 0, 错误显示为 1, 其它码可被用于特定结果. 这可以由其他脚本使用,来自动决定一个命令是否成功, 例如使用: echo $?<br />
<br />
====ejabberdctl命令====<br />
<br />
不带任何参数执行 ejabberdctl时, 它显示可用的选项. 如果没有一个 ejabberd 服务器在运行, 可用的参数是:<br />
<br />
'''start'''<br />
:以后台模式启动ejabberd. 这是缺省方法. <br />
'''debug'''<br />
:连接一个 Erlang shell 到一个已存在的 ejabberd 服务器. 这允许在ejabberd服务器上执行交互命令. <br />
'''live'''<br />
:以live模式启动 ejabberd: shell 保持连接到已启动的服务器, 显示日志信息并允许执行交互命令. <br />
<br />
如果已经有一个ejabberd服务器在系统里运行, ejabberdctl 展示以下 ejabberdctl 命令以及那台服务器上所有可用的 ejabberd 命令 (见 [[Ejabberd2:安装和操作指南#ejabberd命令|4.2.1]] 节).<br />
<br />
ejabberdctl命令如下:<br />
<br />
'''help'''<br />
:获得关于ejabberdctl或任何可用的命令的帮助. 试下 ejabberdctl help help. <br />
'''status'''<br />
:检查ejabberd服务器的状态. <br />
'''stop'''<br />
:停止ejabberd服务器. <br />
'''restart'''<br />
:重启ejabberd服务器. <br />
'''mnesia'''<br />
:获得关于Mnesia数据库的信息. <br />
<br />
ejabberdctl脚本可被限制为需要验证并执行一些 ejabberd命令; 见 [[Ejabberd2:安装和操作指南#用AccessCommands限制执行|4.2.2]] 节. 增加这个选项到文件 ejabberd.cfg. 在这个例子没有限制:<br />
<br />
<source lang="ini"><br />
{ejabberdctl_access_commands, []}.<br />
</source><br />
<br />
如果账号 robot1@example.org 被注册到 ejabberd ,以密码 abcdef (使用 MD5 为 E8B501798950FC58AAD83C8C14978E), 并且 ejabberd.cfg 包含以下设定:<br />
<br />
<source lang="ini"><br />
{hosts, ["example.org"]}.<br />
{acl, bots, {user, "robot1", "example.org"}}.<br />
{access, ctlaccess, [{allow, bots}]}.<br />
{ejabberdctl_access_commands, [ {ctlaccess, [registered_users, register], []} ]}.<br />
</source><br />
<br />
那么你可以在 shell 里做这个:<br />
<br />
<source lang="bash"><br />
$ ejabberdctl registered_users example.org<br />
Error: no_auth_provided<br />
$ ejabberdctl --auth robot1 example.org E8B501798950FC58AAD83C8C14978E registered_users example.org<br />
robot1<br />
testuser1<br />
testuser2<br />
</source><br />
<br />
====Erlang运行时系统====<br />
<br />
ejabberd是一个 Erlang/OTP 应用,运行在一个Erlang运行时系统内部. 这个系统是用环境变量和命令行参数来配置的. ejabberdctl管理脚本可能会使用其中的一些. 你可以在ejabberdctl.cfg文件里配置其中的一部分, 里面已包含了关于它们的详细描述. 本节描述所有环境变量和命令行参数的参考.<br />
<br />
环境变量:<br />
<br />
'''EJABBERD_CONFIG_PATH'''<br />
:ejabberd配置文件的路径. <br />
'''EJABBERD_MSGS_PATH'''<br />
:翻译字符串的目录路径. <br />
'''EJABBERD_LOG_PATH'''<br />
:ejabberd服务日志文件的路径. <br />
'''EJABBERD_SO_PATH'''<br />
:二进制系统库的目录路径. <br />
'''EJABBERD_DOC_PATH'''<br />
:ejabberd文档的目录路径. <br />
'''EJABBERD_PID_PATH'''<br />
:ejabberd启动时建立的PID文件的路径. <br />
'''HOME'''<br />
:ejabberd的家Home目录的路径. 这个路径用于读取文件 .erlang.cookie. <br />
'''ERL_CRASH_DUMP'''<br />
:崩溃报告dump文件的路径. <br />
'''ERL_INETRC'''<br />
:指示使用名字解析的哪个IP. 如果使用 -sname, 要么指定这个选项,要么指定 -kernel inetrc filepath. <br />
'''ERL_MAX_PORTS'''<br />
:并发开放的Erlang端口的最大数量. <br />
'''ERL_MAX_ETS_TABLES'''<br />
:ETS和Mnesia表的最大数量. <br />
<br />
命令行参数:<br />
<br />
'''-sname ejabberd'''<br />
:这个Erlang节点将只使用主机名的第一部分来指定, 即,本域之外的其他Erlang节点不能够联系联络这个节点. 在大多数情况下这是可取的. <br />
'''-name ejabberd'''<br />
:这个Erlang节点将被完全指定. 这只在如果你计划在不同的网络配置一个ejabberd集群时有用. <br />
'''-kernel inetrc ’"/etc/ejabberd/inetrc"’'''<br />
:指出使用名字解析的哪个IP. 如果使用 -sname, 要么指定这个选项,要么指定 ERL_INETRC. <br />
'''-kernel inet_dist_listen_min 4200 inet_dist_listen_min 4210'''<br />
:定义 epmd ( [[Ejabberd2:安装和操作指南#epmd|5.2]] 节)可以监听的第一个和最后一个端口. <br />
'''-detached'''<br />
:启动Erlang系统并从系统控制台分离. 运行守护进程和后台进程时有用. <br />
'''-noinput'''<br />
:确保Erlang系统不尝试读任何输入. 运行守护进程和后台进程时有用. <br />
'''-pa /var/lib/ejabberd/ebin'''<br />
:指定Erlang二进制文件(*.beam)所在目录. <br />
'''-s ejabberd'''<br />
:告诉Erlang运行时系统启动ejabberd应用. <br />
'''-mnesia dir ’"/var/lib/ejabberd/"’'''<br />
:指定Mnesia数据库目录. <br />
'''-sasl sasl_error_logger {file, "/var/log/ejabberd/erlang.log"}'''<br />
:Erlang/OTP系统日志文件的路径. 这里SASL意味着 系统架构支持库“System Architecture Support Libraries” 而不是 简单验证和安全层 “Simple Authentication and Security Layer”. <br />
'''+K [true|false]'''<br />
:内核轮询. <br />
'''-smp [auto|enable|disable]'''<br />
:SMP(多CPU)支持. <br />
'''+P 250000'''<br />
:Erlang进程的最大数量. <br />
'''-remsh ejabberd@localhost'''<br />
:在一个远程Erlang节点打开一个Erlang shell. <br />
'''-hidden'''<br />
:到其他节点的连接是隐藏的(没有公开发布). 结果是这个节点不被认为是集群的一部分. 当启动一个临时的ctl或debug节点的时候这是很重要的. <br />
<br />
注意当使用shell脚本的时候一些字符需要逃逸, 例如 " 和 {}. 你可在Erlang手册页 (erl -man erl)找到其他选项.<br />
<br />
===ejabberd命令===<br />
<br />
一个ejabberd命令是一个通过名字指定的抽象函数, 在ejabberd_commands 服务里注册并有一个已定义的编号和出入和输出类型. 那些命令能被定义在任何Erlang模块并使用任何合法的前端执行.<br />
<br />
ejabberd包含一个前端用来执行ejabberd命令: 脚本ejabberdctl. 其他可被安装以不同方式来执行ejabberd命令的已知的前端有: ejabberd_xmlrpc (XML-RPC 服务), mod_rest (HTTP POST 服务), mod_shcommands (ejabberd WebAdmin 页面).<br />
<br />
====ejabberd命令清单====<br />
<br />
ejabberd缺省包含了一些ejabberd命令. 当更多模块被安装, 在前端又会有新命令可以用.<br />
<br />
获得可用命令和它们的帮助的最容易的方法, 是使用ejabberdctl脚本:<br />
<br />
<source lang="bash"><br />
$ ejabberdctl help<br />
Usage: ejabberdctl [--node nodename] [--auth user host password] command [options]<br />
<br />
Available commands in this ejabberd node:<br />
backup file Store the database to backup file<br />
connected_users List all established sessions<br />
connected_users_number Get the number of established sessions<br />
...<br />
</source><br />
<br />
最多人感兴趣的是:<br />
<br />
'''reopen_log'''<br />
:在日志文件改名之后重新打开它们. 如果在调用此命令之前旧文件没有被改名, 它们自动改名为 "*-old.log". 见 [[Ejabberd2:安装和操作指南#日志文件|7.1]] 节. <br />
'''backup ejabberd.backup'''<br />
:存储内部的 Mnesia 数据库到一个二进制备份文件. <br />
'''restore ejabberd.backup'''<br />
:立刻从一个二进制文件恢复内部的 Mnesia 数据库. 如果你有一个很大的数据库,这将消耗很多内存, 所以最好使用 install_fallback. <br />
'''install_fallback ejabberd.backup'''<br />
:安装成fallback的二进制备份文件: 它将在下一次ejabberd启动的时候被用于恢复数据库. 这意味着, 在运行这个命令之后, 你不得不重启 ejabberd. 这个命令比restore需要更少的内存. <br />
'''dump ejabberd.dump'''<br />
:Dump内部的 Mnesia 数据库到一个文本文件 dump. <br />
'''load ejabberd.dump'''<br />
:立刻从一个文本文件dump恢复. 这不建议用于大数据库, 因为它将消耗很多时间, 内存和cpu. 在那种情况下,它适合使用 backup 和 install_fallback. <br />
'''import_piefxis, export_piefxis, export_piefxis_host'''<br />
:这些选项可被用于迁移帐户,使用 [http://xmpp.org/extensions/xep-0227.html XEP-0227] 格式的 XML文件 从/到 另外一个 Jabber/XMPP 服务器或转移一个虚拟主机的用户到另一个 ejabberd 安装环境. 也见于 [https://support.process-one.net/doc/display/MESSENGER/ejabberd+migration+kit ejabberd迁移工具]. <br />
'''import_file, import_dir'''<br />
:这些选项可被用于迁移使用jabberd1.4格式的XML文件的帐户, 从其他 Jabber/XMPP 服务器. 已经有 [http://www.ejabberd.im/migrate-to-ejabberd 从其他软件迁移到ejabberd]的教程. <br />
'''delete_expired_messages'''<br />
:这个选项可被用于删除旧的离线消息. 当离线消息数量非常高的时候有用. <br />
'''delete_old_messages days'''<br />
:删除指定天数之前的离线消息. <br />
'''register user host password'''<br />
:在那个域以给定的密码注册一个帐号. <br />
'''unregister user host'''<br />
:注销给定帐号.<br />
<br />
====以AccessCommands限制执行====<br />
<br />
前端可能被配置成限制访问特定的命令. 在那种情况下, 必须提供验证信息. 在每个前端,AccessCommands 选项被定义在不同的地方. 但是所有情况下这个选项的语法都是相同的:<br />
<br />
<source lang="ini"><br />
AccessCommands = [ {Access, CommandNames, Arguments}, ...]<br />
Access = atom()<br />
CommandNames = all | [CommandName]<br />
CommandName = atom()<br />
Arguments = [ {ArgumentName, ArgumentValue}, ...]<br />
ArgumentName = atom()<br />
ArgumentValue = any()<br />
</source><br />
<br />
缺省值是不定义任何限制: []. 当执行一个命令时提供验证信息, 为一个被允许执行相应命令的本地XMPP帐号的 Username, Hostname 和 Password . 这意味着这个帐号必须在本地ejabberd已经注册, 因为这个信息将被验证. 可能提供纯文本密码或它的 MD5 哈希值.<br />
<br />
当定义了一个或多个访问限制,并且提供了验证信息, 每个限制被验证直到某人完全符合: 这个帐号和 Access rule匹配, 命令名字列于 CommandNames 之中, 并且提供的参数和Arguments不抵触.<br />
<br />
以下例子用来理解这个语法, 让我们假设那些选项:<br />
<br />
<source lang="ini"><br />
{hosts, ["example.org"]}.<br />
{acl, bots, {user, "robot1", "example.org"}}.<br />
{access, commaccess, [{allow, bots}]}.<br />
</source><br />
<br />
访问限制的列表只允许 robot1@example.org 执行所有命令:<br />
<br />
<source lang="ini"><br />
[{commaccess, all, []}]<br />
</source><br />
<br />
看看另一个限制列表 (相应的 ACL 和 ACCESS 没有显式):<br />
<br />
<source lang="ini"><br />
[<br />
%% 这个 bot 能执行所有命令:<br />
{bot, all, []},<br />
%% 这个 bot 只能执行命令 'dump'. 不限制参数:<br />
{bot_backups, [dump], []}<br />
%% 这个 bot 可执行所有命令,<br />
%% 但是如果使用 'host' 参数, 它必须是 "example.org":<br />
{bot_all_example, all, [{host, "example.org"}]},<br />
%% 这个 bot 只能执行命令 'register',<br />
%% 并且如果使用参数 'host' , 它必须是 "example.org":<br />
{bot_reg_example, [register], [{host, "example.org"}]},<br />
%% 这个 bot 能执行命令 'register' 和 'unregister',<br />
%% 如果使用参数 host , 它必须是 "test.org":<br />
{_bot_reg_test, [register, unregister], [{host, "test.org"}]}<br />
]<br />
</source><br />
<br />
===Web管理===<br />
<br />
ejabberd Web管理允许使用web浏览器管理大部分ejabberd.<br />
<br />
这个功能缺省是激活的: 一个使用选项 web_admin (见 [[Ejabberd2:安装和操作指南#监听端口|3.1.3]] 节)的 ejabberd_http 监听者被包含在监听的端口里. 然后你可以在你中意的wen浏览器里打开 http://server:port/admin/ . 你将被要求键入一个拥有管理员权限的ejabberd用户的 username (全 Jabber ID) 和 password . 在验证之后你将看到一个页面类似 figure 4.1.<br />
<br />
:''webadmmain.png''<br />
:''Figure 4.1: Top page from the Web Admin''<br />
<br />
这里你可以编辑访问限制, 管理用户, 建立备份, 管理数据库, 允许/禁止 监听的端口, 查看服务器统计数据,…<br />
<br />
access rule 配置决定那些帐号可以访问Web管理以及修改它. access rule webadmin_view 仅被赋予查看权限: 那些帐号能以只读方式浏览Web管理.<br />
<br />
示例配置:<br />
<br />
* 你可以把Web管理伺服于和HTTP 轮询界面相同的端口. 在这个了例子里你应该把你的web浏览器指向 http://example.org:5280/admin/ 来管理所有虚拟主机或指向 http://example.org:5280/admin/server/example.com/ 来管理虚拟主机 example.com. 在你访问Web管理之前你需要键入从一个被允许配置ejabberd的已注册的用户那里得到的 username, JID 和 password . 在这个例子里你可键入 username ‘admin@example.net’ 来管理所有虚拟主机 (第一个 URL). 如果你以‘admin@example.com’登录到http://example.org:5280/admin/server/example.com/ ,你只能管理虚拟主机 example.com. 帐号‘reviewer@example.com’可以只读模式浏览虚拟主机.<br />
<br />
<source lang="ini"><br />
{acl, admins, {user, "admin", "example.net"}}.<br />
{host_config, "example.com", [{acl, admins, {user, "admin", "example.com"}}]}.<br />
{host_config, "example.com", [{acl, viewers, {user, "reviewer", "example.com"}}]}.<br />
<br />
{access, configure, [{allow, admins}]}.<br />
{access, webadmin_view, [{allow, viewers}]}.<br />
<br />
{hosts, ["example.org"]}.<br />
<br />
{listen,<br />
[<br />
...<br />
{5280, ejabberd_http, [http_poll, web_admin]},<br />
...<br />
]}.<br />
</source><br />
<br />
* 因为安全的原因, 你可以在一个安全的连接上伺服Web管理, 在一个不同于HTTP轮询接口的端口上, 并把它绑定到内部的局域网IP. 这个Web管理将只能被浏览器从https://192.168.1.1:5282/admin/ 访问:<br />
<br />
<source lang="ini"><br />
{hosts, ["example.org"]}.<br />
<br />
{listen,<br />
[<br />
...<br />
{5280, ejabberd_http, [<br />
http_poll<br />
]},<br />
{{5282, "192.168.1.1"}, ejabberd_http, [<br />
web_admin,<br />
tls, {certfile, "/usr/local/etc/server.pem"}<br />
]},<br />
...<br />
]}.<br />
</source><br />
<br />
在ejabberd Web管理 特定的页面包含了一个连接到 ejabberd安装和操作指南 的相关章节. 为了显式这些链接, 本指南的一个 HTML 格式的拷贝必须安装在该系统上. 该文件缺省的放在 "/share/doc/ejabberd/guide.html". 该文档的目录可以被环境变量 EJABBERD_DOC_PATH 指定. 参见 [[Ejabberd2:安装和操作指南#Erlang运行时系统|4.1.2]] 节.<br />
<br />
===特设命令===<br />
<br />
如果你激活了 mod_configure 和 mod_adhoc, 你可以使用一个 XMPP 客户端在 ejabberd执行很多管理任务. 该客户端必须支持 Ad-Hoc Commands ([http://xmpp.org/extensions/xep-0050.html XEP-0050]), 而你必须以一个拥有适当权限的帐号登录到该 XMPP 服务器.<br />
<br />
===修改计算机主机名===<br />
<br />
ejabberd使用分布式的 Mnesia 数据库. 作为分布式数据库, Mnesia 强制它的文件一致性, 所以它在它里面存储Erlang节点名 (见 [[Ejabberd2:安装和操作指南#Erlang节点名|5.4]] 节). 一个Erlang节点的名字包含了该计算机的hostname. 所以, 如果你修改ejabberd运行的机器的名字,或当你移动ejabberd到一个不同的机器上,那么Erlang节点名也修改了.<br />
<br />
你有两个办法在一个新节点名的 ejabberd 上使用旧的 Mnesia 数据库: 把旧节点名放入 ejabberdctl.cfg, 或转换数据库到为新节点名.<br />
<br />
那些例子步骤将备份, 转换并装载 Mnesia 数据库. 你需要要么有旧的 Mnesia spool 目录,要么有一个 Mnesia 的备份. 如果你已经有一个旧的数据库的备份文件, 你可以直接去步骤 5. 你也需要知道旧节点名和新节点名. 如果你不知道它们, 执行ejabberdctl或在ejabberd 日志文件里查找它们.<br />
<br />
在开始之前, 设置一些变量:<br />
<br />
<source lang="bash"><br />
OLDNODE=ejabberd@oldmachine<br />
NEWNODE=ejabberd@newmachine<br />
OLDFILE=/tmp/old.backup<br />
NEWFILE=/tmp/new.backup<br />
</source><br />
<br />
1. 强制以旧节点名启动 ejabberd :<br />
<br />
<source lang="bash"><br />
ejabberdctl --node $OLDNODE start<br />
</source><br />
<br />
2. 生成一个备份文件:<br />
<br />
<source lang="bash"><br />
ejabberdctl --node $OLDNODE backup $OLDFILE<br />
</source><br />
<br />
3. 停止旧节点:<br />
<br />
<source lang="bash"><br />
ejabberdctl --node $OLDNODE stop<br />
</source><br />
<br />
4. 确保在 Mnesia spool 目录没有文件 . 例如:<br />
<br />
<source lang="bash"><br />
mkdir /var/lib/ejabberd/oldfiles<br />
mv /var/lib/ejabberd/*.* /var/lib/ejabberd/oldfiles/<br />
</source><br />
<br />
5. 启动 ejabberd. 不需要再指定任何节点名:<br />
<br />
<source lang="bash"><br />
ejabberdctl start<br />
</source><br />
<br />
6. 转换备份到新节点名:<br />
<br />
<source lang="bash"><br />
ejabberdctl mnesia_change_nodename $OLDNODE $NEWNODE $OLDFILE $NEWFILE<br />
</source><br />
<br />
7. 安装备份文件作为一个fallback:<br />
<br />
<source lang="bash"><br />
ejabberdctl install_fallback $NEWFILE<br />
</source><br />
<br />
8. 停止 ejabberd:<br />
<br />
<source lang="bash"><br />
ejabberdctl stop<br />
</source><br />
<br />
:你可能在日志文件看到一个错误信息, 这是正常的, 不要担心:<br />
<br />
<source lang="text"><br />
Mnesia(ejabberd@newmachine):<br />
** ERROR ** (ignoring core)<br />
** FATAL ** A fallback is installed and Mnesia must be restarted.<br />
Forcing shutdown after mnesia_down from ejabberd@newmachine...<br />
</source><br />
<br />
9. 现在你可以最后启动 ejabberd:<br />
<br />
<source lang="bash"><br />
ejabberdctl start<br />
</source><br />
<br />
10. 检查是否旧数据库的信息可用: accounts, rosters... 完成之后, 记住从公共目录删除临时备份文件.<br />
<br />
==ejabberd安全==<br />
===防火墙设置===<br />
<br />
当你配置防火墙的时候,你需要注意以下 TCP 端口: <br />
<br />
{|border="1" cellspacing="0"<br />
!端口 !!描述<br />
|-<br />
|5222 ||用于 Jabber/XMPP 客户端连接的标准端口, 纯文本或 STARTTLS.<br />
|-<br />
|5223 ||Jabber 客户端使用旧的 SSL 方法连接的标准端口 .<br />
|-<br />
|5269 ||用于 Jabber/XMPP 服务器连接的标准端口.<br />
|-<br />
|4369 ||EPMD ([[Ejabberd2:安装和操作指南#EPMD|5.2]] 节) 监听Erlang节点名请求.<br />
|-<br />
|端口范围 ||用于两个Erlang节点之间的连接. 这个范围是可配置的(见 [[Ejabberd2:安装和操作指南#EPMD|5.2]] 节).<br />
|}<br />
<br />
===epmd===<br />
<br />
[http://www.erlang.org/doc/man/epmd.html epmd (Erlang端口映射守候进程)] 是一个包含在 Erlang/OTP 里的小的名字服务器,并且在建立分布式 Erlang 通讯时被 Erlang 程序使用. ejabberd 需要 epmd 来使用 ejabberdctl 并且使用集群的ejabberd 节点时也需要它. 这个小的程序是由Erlang自动启动的, 并且永不停止. 如果 ejabberd 停止了, 并且没有任何其他 Erlang 程序运行在系统上, 如果你想的话可以安全地停止 epmd.<br />
<br />
ejabberd 运行在一个Erlang节点内部. 为了和 ejabberd 通讯, 脚本 ejabberdctl 启动一个新的 Erlang 节点并连接到这个运行着 ejabberd 的Erlang节点. 为了这个通讯能工作, epmd 必须运行和在端口4369监听名字请求. 你应该在防火墙以这种方式禁止端口4369,即只允许你机器上的程序访问它.<br />
<br />
如果你建立了一个许多 ejabberd 实例的集群, 每个 ejabberd 实例被称为一个 ejabberd 节点. 那些 ejabberd 节点使用一个特别的 Erlang 通讯方法来建立集群, 那么 EPMD 再次需要监听端口 4369. 所以, 如果你计划计建立一个 ejabberd 节点的集群,你必须为这个集群涉及的机器打开端口 4369. 记住禁止这个端口使得它无法从互联网访问到.<br />
<br />
一旦一个Erlang节点使用EPMD和端口4369解析了另一个Erlang节点的节点名, 节点之间就直接通讯. 在这个情况下使用的端口缺省是随机的, 但是可以在文件 ejabberdctl.cfg里配置. Erlang命令行参数被内部使用, 例如:<br />
<br />
<source lang="bash"><br />
erl ... -kernel inet_dist_listen_min 4370 inet_dist_listen_max 4375<br />
</source><br />
<br />
===Erlang Cookie===<br />
<br />
Erlang cookie 是一个数字和字母组成的字符串. 一个Erlang节点在启动时从命令行参数 -setcookie 读取cookie. 如果没有指定, 则从 $HOME/.erlang.cookie 读取cookie 文件. 如果这个文件不存在, 它会被立刻以一个随机的cookie建立. 两个Erlang节点只有它们有相同的cookie才会通讯 . 在Erlang节点上设置一个cookie允许你结构化你的Erlang网络并定义哪个节点被允许连接到哪个.<br />
<br />
感谢Erlang cookies, 你可以阻止对Erlang节点的错误访问, 例如当同一台机器上有许多Erlang节点运行不同程序的时候.<br />
<br />
设置一个安全cookie是一个简单的方法来增加非法访问你的Erlang节点的困难度. 然而, 对于阻止对Erlang节点的未授权访问或侵扰,cookie系统不是最终有效的. Erlang节点之间的通讯是未加密的, 所以 cookie 可能被网络上的探针读取. 推荐使得Erlang更加安全的方法是禁止端口4369.<br />
<br />
===Erlang节点名===<br />
<br />
一个Erlang节点可以拥有一个节点名. 这个名字可能很短 (如果用命令行参数 -sname 指定) 或很长 (如果用参数 -name 指定). 以 -sname 启动一个Erlang节点限制Erlang节点和LAN之间的通讯.<br />
<br />
使用选项 -sname 而不是 -name ,是一个简单增加对你的Erlang节点的未授权访问难度的方法. 然而, 对于阻止对Erlang节点的未授权访问或侵扰,它不是最终有效的. 因为有可能伪装你在另一个网络里使用一个修改过的 Erlang epmd. 推荐使得Erlang更加安全的方法是禁止端口4369.<br />
<br />
===敏感文件安全===<br />
<br />
<br />
ejabberd在文件系统里存储敏感数据要么使用纯文本要么是二进制文件. 文件系统许可应被设置为只允许适当的用户读, 写和执行那些文件和目录.<br />
<br />
'''ejabberd configuration file: /etc/ejabberd/ejabberd.cfg'''<br />
:包含外部组件的管理员的 JID 和密码. 备份文件可能也包含这个信息, 所以整个 /etc/ejabberd/ 目录的安全是必要的. <br />
'''ejabberd service log: /var/log/ejabberd/ejabberd.log'''<br />
:包含客户端的IP地址. 如果 loglevel 设为 5, 它包含全部的会话和密码. 如果使用了一个 logrotate 系统, 可能有好几个日志文件拥有类似的信息, 所以整个 /var/log/ejabberd/ 目录的安全是必要的. <br />
'''Mnesia database spool files in /var/lib/ejabberd/'''<br />
:这个文件存储二进制数据, 但是一些部分仍是可读的. 这个文件由 Mnesia 生成并且它们的许可不能被直接设置, 所以整个 /var/lib/ejabberd/ 目录的安全是必要的. <br />
'''Erlang cookie file: /var/lib/ejabberd/.erlang.cookie'''<br />
:见 [[Ejabberd2:安装和操作指南#Erlang Cookie|5.3]] 节.<br />
<br />
==集群==<br />
===如何工作===<br />
<br />
一个XMPP域是由一个或多个ejabberd节点伺服的. 这些节点可能运行在通过网络连接的不同的机器上. 它们都必须有能力连接到所有其他节点的4369端口, 并且必须有相同的 magic cookie (见 Erlang/OTP 文档, 换句话说,在所有节点上,文件 ~ejabberd/.erlang.cookie 必须是相同的 ). 这是必须的,因为所有节点交换关于已连接的用户, s2s连接, 已注册的服务, 等等…信息.<br />
<br />
每个 ejabberd 节点有意下模块:<br />
<br />
* router,<br />
* local router,<br />
* session manager,<br />
* s2s manager. <br />
<br />
====Router====<br />
<br />
这个模块是每个节点的XMPP包的主router. 它基于它们的目标域来路由它们. 它使用一个全局路由表. 在这个路由表里搜索到包的目的地的域, 并且如果找到, 这个包就被路由到适当的进程. 如果没找到, 它被送到 s2s manager.<br />
<br />
====Local Router====<br />
<br />
这个模块路由那些目的域等于服务器的主机名之一的包. 如果目的JID有一个空的 user 部分, 它路由到 session manager, 反之则它的处理依赖于它的内容.<br />
<br />
====Session Manager====<br />
<br />
这个模块路由包到本地用户. 它通过一个出席信息表查找一个包必须被发送给哪个用户资源. 然后该包要么路由到适当的 c2s 进程, 要么存储在离线存储 offline storage, 或弹回.<br />
<br />
====s2s Manager====<br />
<br />
这个模块路由包到其他 XMPP 服务器. 首先, 它检查是否已存在一个从该包的源域到目的域的s2s连接. 如果有, s2s manager 路由这个包到伺服这个连接的进程, 反之打开一个新的连接.<br />
<br />
===集群配置===<br />
<br />
假定你已经在一个机器named(第一个)上配置了 ejabberd , 并且你需要配置另外一个来做一个 ejabberd 集群. 那么按以下步骤做:<br />
<br />
1. 从第一台机器拷贝 ~ejabberd/.erlang.cookie 文件到第二台机器.<br />
<br />
:(或者) 你也可以增加‘-setcookie content_of_.erlang.cookie’选项到以下所有‘erl’ 命令.<br />
<br />
2. 在第二台机器上,在ejabberd工作目录中,以 ejabberd 守候进程用户运行以下命令:<br />
<br />
<source lang="bash"><br />
erl -sname ejabberd \<br />
-mnesia dir '"/var/lib/ejabberd/"' \<br />
-mnesia extra_db_nodes "['ejabberd@first']" \<br />
-s mnesia<br />
</source><br />
<br />
:这将启动 Mnesia 服务于和 ejabberd@first 相同的数据库. 你可以运行命令 ‘mnesia:info().’检查它. 你应该看到许多远程表和行,类似以下:<br />
<br />
:注意: 在你的系统里 Mnesia 目录可能是不同的. 要知道 ejabberd 期望在哪里找到 Mnesia 的缺省安装, 不带参数调用 ejabberdctl 然后它将显式一些帮助, 包括 Mnesia database spool 目录.<br />
<br />
<source lang="bash"><br />
running db nodes = [ejabberd@first, ejabberd@second]<br />
</source><br />
<br />
3. 现在在相同的‘erl’会话下运行以下命令:<br />
<br />
<source lang="bash"><br />
mnesia:change_table_copy_type(schema, node(), disc_copies).<br />
</source><br />
<br />
:这将为该数据库建立本地磁盘存储.<br />
<br />
:(或者) 在第二个节点通过Web管理修改scheme表的存储类型为‘RAM and disc copy’.<br />
<br />
4. 现在你可以增加更多表的复制到这个节点 ,使用‘mnesia:add_table_copy’ 或 ‘mnesia:change_table_copy_type’如上 (只是把 ‘schema’ 替换成其他表名,并且 ‘disc_copies’可以被替换成‘ram_copies’ 或 ‘disc_only_copies’).<br />
<br />
:哪个表被复制,依赖于你的需要, 你可以从‘mnesia:info().’命令得到一些提示, 通过查看每个位于 ’first’的表的大小和缺省的存储类型.<br />
<br />
复制一个表使得这个节点的这个表的查询更加快速. 写入, 另一方面, 将更慢. 而且当然如果复制之一的机器挂了, 其他复制将被使用.<br />
<br />
:看一下 [http://www.erlang.org/doc/apps/mnesia/Mnesia_chap5.html#5.3 Mnesia用户指南的 5.3 节(表 片段)]将有所帮助.<br />
<br />
: (或者) 同之前的条目, 但用于不同的表.<br />
<br />
5. 运行‘init:stop().’ 或只是 ‘q().’ 退出 Erlang shell. 这可能要花些时间,如果 Mnesia 还没有从first传输和处理完所有数据.<br />
<br />
6. 现在在第二台机器上使用和第一台机器类似的配置运行 ejabberd: 你可能不需要重复‘acl’ 和 ‘access’ 选项,因为它们将从第一台机器获得; 并且 mod_irc 只应该在集群里的一台机器上激活. <br />
<br />
你可以在其他机器上重复这些步骤来服务于这个域.<br />
<br />
===服务负载均衡===<br />
====组件负载均衡====<br />
====域负载均衡机制====<br />
<br />
ejabberd包含了一个机制来对插入一个ejabberd集群的组件进行负载均衡. 它意味着你可以在每一个ejabberd集群插入相同组件的一个或多个实例并且流量将自动分布.<br />
<br />
缺省的分布式机制尝试递送到组件的一个本地实例. 如果有多个本地实例可用, 随机地选取一个实例. 如果没有本地实例可用, 随机选取一个远程组件实例.<br />
<br />
如果你需要一个不同的行为, 你可以通过选项 domain_balancing 修改负载均衡行为. 这个选项的语法如下:<br />
<br />
<source lang="ini"><br />
{domain_balancing, "component.example.com", BalancingCriteria}.<br />
</source><br />
<br />
多个负载均衡标准可用:<br />
<br />
* destination: 使用包的to属性的全JID.<br />
* source: 使用包的from属性的全JID.<br />
* bare_destination: 使用包的to属性的纯JID(没有资源).<br />
* bare_source: 使用包的from属性的纯JID(没有资源). <br />
<br />
如果对应标准的这个值是相同的, 则集群中相同的组件实例将被使用.<br />
<br />
====负载均衡水桶====<br />
<br />
当一个给定的组件有失败的风险的时候, 域均衡可能导致服务麻烦. 如果一个组件失败了,服务将无法正确工作,除非会话被重新均衡了.<br />
<br />
在这种情况下, 最好限制这个问题在由失败组件处理的这些会话. 这就是 domain_balancing_component_number 选项所做的, 使负载均衡机制不动态化, 而是粘在固定数目的组件实例上.<br />
<br />
语法是:<br />
<br />
<source lang="ini"><br />
{domain_balancing_component_number, "component.example.com", Number}.<br />
</source><br />
<br />
==调试==<br />
===日志文件===<br />
<br />
一个ejabberd节点写两个日志文件:<br />
<br />
'''ejabberd.log'''<br />
:ejabberd 服务日志, 由 ejabberd 节点汇报的消息<br />
'''erlang.log'''<br />
:Erlang/OTP 系统日志, 由 Erlang/OTP 使用 SASL (系统架构支持库) 汇报的消息<br />
<br />
选项 loglevel 修改文件 ejabberd.log 的详细程度. 语法是:<br />
<br />
<source lang="ini"><br />
{loglevel, Level}.<br />
</source><br />
<br />
可能的 Level 有:<br />
<br />
'''0'''<br />
:没有ejabberd日志 (不推荐) <br />
'''1'''<br />
:紧急<br />
'''2'''<br />
:错误<br />
'''3'''<br />
:警告<br />
'''4'''<br />
:信息<br />
'''5'''<br />
:调试<br />
<br />
例如, 缺省配置为:<br />
<br />
<source lang="ini"><br />
{loglevel, 4}.<br />
</source><br />
<br />
日志文件持续增长, 所以推荐定期流转. 为了流转日志文件, 重命名这个文件然后重新打开它们. ejabberdctl命令reopen-log (请参考 [[Ejabberd2:安装和操作指南# ejabberdctl命令|4.1.1]] 节) 重新打开日志文件, 同时也重命名旧文件,如果你不重命名它们的话.<br />
<br />
===调试控制台===<br />
<br />
调试控制台是连接到一个已运行的 ejabberd 服务器的 Erlang shell. 使用这个 Erlang shell, 一个有经验的管理员可以执行复杂的任务.<br />
<br />
这个 shell 给予对ejabberd 服务器的完全控制, 所以使用它要非常小心. 在文章 [http://www.ejabberd.im/interconnect-erl-nodes Erlang节点的互连] 里有一些简单和安全的例子<br />
<br />
要退出这个shell, 关闭窗口或键入: control+c control+c.<br />
<br />
===Watchdog警告===<br />
<br />
ejabberd包含了一个看门狗 watchdog 机制,当找出和内存使用有关的问题时,对开发者可能有用. 如果ejabberd服务器的一个进程消耗了超过配置阀值的内存, 一个消息将被发送到ejabberd配置文件中选项 watchdog_admins 定义的 XMPP 帐号.<br />
<br />
语法是:<br />
<br />
'''{watchdog_admins, [JID, ...]}.'''<br />
<br />
消耗的内存以words衡量: 一个word在32位系统上是4字节bytes, 在64位系统上是8字节bytes. 这个阀值缺省是 1000000 words. 这个值可以用选项 watchdog_large_heap来配置, 或在一个会话中使用watchdog警报机器人.<br />
<br />
语法是:<br />
<br />
'''{watchdog_large_heap, Number}.'''<br />
<br />
示例配置:<br />
<br />
<source lang="ini"><br />
{watchdog_admins, ["admin2@localhost", "admin2@example.org"]}.<br />
{watchdog_large_heap, 30000000}.<br />
</source><br />
<br />
要移除watchdog管理员, 在选项里移除. 为了移除所有watchdog管理员, 设置该选项为空列表:<br />
<br />
<source lang="ini"><br />
{watchdog_admins, []}.<br />
</source><br />
<br />
==附录 A 国际化和本地化==<br />
<br />
ejabberd的源码支持本地化. 翻译者可编辑 [http://www.gnu.org/software/gettext/ gettext] .po 文件,使用任何可用的软件 (KBabel, Lokalize, Poedit...) 或一个简单的文本编辑器.<br />
<br />
接着gettext用来提取, 更新和导出那些 .po 文件成为能被ejabberd读取的 .msg 格式. 为执行那些管理任务, 在 src/ 目录执行 ''make translations''. 可翻译的字符串被从源码提取出来生成文件 ejabberd.pot. 这个文件合并每个 .po 文件来生成更新的 .po 文件. 最后那些 .po 文件被导出成 .msg 文件, 那是个容易被 ejabberd 读取的格式.<br />
<br />
所有內建的模块都支持内部的IQ queries的xml:lang 属性 . Figure A.1, 例如, 展示了应答以下 query:<br />
<br />
<source lang="xml"><br />
<iq id='5'<br />
to='example.org'<br />
type='get'<br />
xml:lang='ru'><br />
<query xmlns='http://jabber.org/protocol/disco#items'/><br />
</iq><br />
</source><br />
<br />
discorus.png<br />
Figure A.1: Service Discovery when xml:lang=’ru’<br />
<br />
Web管理也支持 Accept-Language HTTP 头.<br />
<br />
webadmmainru.png<br />
Figure A.2: Web Admin showing a virtual host when the web browser provides the HTTP header ‘Accept-Language: ru’<br />
<br />
==附录 B 发行备注==<br />
<br />
发行备注在 [http://www.process-one.net/en/ejabberd/release_notes/ ejabberd主页]<br />
<br />
==附录 C 鸣谢==<br />
<br />
感谢所有对本指南有贡献的人:<br />
<br />
* Alexey Shchepin (xmpp:aleksey@jabber.ru)<br />
* Badlop (xmpp:badlop@jabberes.org)<br />
* Evgeniy Khramtsov (xmpp:xram@jabber.ru)<br />
* Florian Zumbiehl (xmpp:florz@florz.de)<br />
* Michael Grigutsch (xmpp:migri@jabber.i-pobox.net)<br />
* Mickael Remond (xmpp:mremond@process-one.net)<br />
* Sander Devrieze (xmpp:s.devrieze@gmail.com)<br />
* Sergei Golovan (xmpp:sgolovan@nes.ru)<br />
* Vsevolod Pelipas (xmpp:vsevoload@jabber.ru)<br />
<br />
==附录 D 版权信息==<br />
<br />
略...<br />
<br />
Ejabberd Installation and Operation Guide.<br />
Copyright © 2003 — 2010 ProcessOne<br />
<br />
This document is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version.<br />
<br />
This document is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.<br />
<br />
You should have received a copy of the GNU General Public License along with this document; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.</div>
Snowqiang
http://wiki.jabbercn.org/Openfire:%E5%AE%89%E8%A3%85%E6%8C%87%E5%8D%97
Openfire:安装指南
2011-05-18T12:38:14Z
<p>Snowqiang: 删广告</p>
<hr />
<div>[[Category:XMPP服务器]]<br />
[[Category:已翻译]]<br />
<br />
'''本文的英文原文来自 http://www.igniterealtime.org/builds/openfire/docs/latest/documentation/install-guide.html '''<br />
<br />
'''安装指南'''<br />
<br />
Openfire是一个强大的即时消息(IM)和聊天服务器,它实现了XMPP协议。这份文件将引导您通过安装Openfire。对于更多的功能和信息的完整列表,请访问Openfire网站:http://www.igniterealtime.org/projects/openfire/<br />
<br />
==安装==<br />
<br />
===Windows===<br />
<br />
运行Openfire 安装包. 应用缺省将被安装于目录 c:\Program Files\Openfire .<br />
<br />
===Linux/Unix===<br />
<br />
可选择RPM包或tar.gz包. 如果使用RPM包, 用你的包管理器运行把它Openfire安装到目录 /opt/openfire:<br />
<br />
<source lang="bash"><br />
rpm -ivh openfire_3_0_0.rpm<br />
</source><br />
<br />
如果使用.tar.gz包, 解压到目录 /opt 或 /usr/bin:<br />
<br />
<source lang="bash"><br />
tar -xzvf openfire_3_0_0.tar.gz<br />
mv openfire /opt<br />
</source><br />
<br />
'''注意''': .tar.gz包不一定包含Java虚拟机(JRE). 所以, 你必须之前就有 JDK 或 JRE 1.5.0 (Java 5) 或之后安装到你的系统里. 你可以在命令行键入 "java -version" 来检查你的java版本,然后 (如果必要) 访问 http://java.sun.com 更新你的Java安装.<br />
<br />
==安装概述==<br />
<br />
为了完成Openfire的安装, 你需要执行以下步骤:<br />
<br />
# [[Openfire:安装指南#安装数据库|数据库]] - 如果你选择使用一个外部数据库, 你必须准备为Openfire准备好你的数据库.<br />
# [[Openfire:安装指南#安装服务器|安装]] - 使用内置的基于web的安装工具来安装和验证服务器的配置.<br />
# [[Openfire:安装指南#管理控制台|管理控制台]] - 使用基于web的管理工具来管理服务器.<br />
<br />
本文也包括以下信息:<br />
<br />
* [[Openfire:安装指南#在Windows下运行Openfire|在Windows下运行]]<br />
* [[Openfire:安装指南#在Unix/Linux下运行Openfire|在Unix/Linux下运行]]<br />
* [[Openfire:安装指南#在Unix/插件|安装和使用插件]]<br />
<br />
==分发版里的文件==<br />
<br />
你的分发版里的文件应该像下面这样 (为了简短一点,一些子目录被忽略了):<br />
<br />
<pre><br />
openfire/<br />
|- readme.html<br />
|- license.html<br />
|- conf/<br />
|- bin/<br />
|- jre/<br />
|- lib/<br />
|- plugins/<br />
|- admin/<br />
|- resources/<br />
|-database/<br />
|-security/<br />
|- documentation/<br />
</pre><br />
<br />
* '''conf''' 目录Openfire用来存放配置文件.<br />
* '''bin''' 目录包含了服务器的可执行文件. 根据你安装的不同分发版, 可用的执行文件也不同.<br />
* '''jre''' 目录包含了一个 Java 5 虚拟机,打包在Windows和RPM版本Openfire里面的.<br />
* '''lib''' 目录包含了运行Openfire所需要的库.<br />
* '''plugins''' 目录包含了服务器插件. 缺省地, Openfire带了一个基于web的管理控制台插件.<br />
* '''resources/database''' 目录包含 SQL 架构文件,用来新建Openfire数据库, 以及已有安装的更新脚本.<br />
* '''resources/security''' 目录是Openfire维护keystores的地方,用来支持SSL连接安全性.<br />
* '''documentation''' 目录包含了服务器文档.<br />
<br />
==安装数据库==<br />
<br />
Openfire能把它的数据存储在一个嵌入式的数据库里,你也能选择使用一个外部数据库,例如MySQL或Oracle. 如果你喜欢使用外部数据库, 你必须在开始安装之前准备好它. 更多信息见[http://www.igniterealtime.org/builds/openfire/docs/latest/documentation/database.html 数据库安装].<br />
<br />
==安装服务器==<br />
<br />
Openfire內建了一个基于web的, "向导"驱动的安装和配置工具. 简单地启动Openfire(分平台的指引如下) 并使用浏览器连接到管理控制台. 基于web的管理控制台的缺省端口是9090. 如果你和Openfire在同一台机器, 以下URL通常会起作用: http://127.0.0.1:9090.<br />
<br />
==管理控制台==<br />
<br />
在完成上述步骤之后, Openfire将被配置,你可以用基于web的管理控制台管理服务器. URL应该和你用来安装服务器用的那个一样,除非你在安装期间修改了那个端口.<br />
<br />
==在Windows下运行Openfire==<br />
<br />
如果你使用了Openfire安装包, 在你的开始菜单里会有一个快捷方式来启动图形化启动器. 否则, 在你的 Openfire 安装位置的 bin/ 目录运行 openfire.exe . 在启动界面上有一个按钮,允许你自动打开你的web浏览器连接正确的URL来完成服务器的安装<br />
<br />
http://www.igniterealtime.org/builds/openfire/docs/latest/documentation/images/launcher.png<br />
<br />
===Windows服务===<br />
<br />
如果你正在Windows下运行Openfire, 你或许想在初始化安装之后把Openfire作为一个标准的Windows来运行. 如果你使用Windows安装包, 一个 openfire-service.exe 文件将会出现在安装目录下的 bin 目录. 你可以使用这个可执行文件来安装和控制Openfire服务.<br />
<br />
从控制台窗口, 你可以运行以下命令:<br />
<br />
* '''openfire-service /install''' -- 安装服务.<br />
* '''openfire-service /uninstall''' -- 卸载服务.<br />
* '''openfire-service /start''' -- 启动服务.<br />
* '''openfire-service /stop''' -- 停止服务. <br />
<br />
http://www.igniterealtime.org/builds/openfire/docs/latest/documentation/images/windows_service.png<br />
<br />
你也可以在Windows控制面板使用服务工具来启动和停止服务.<br />
<br />
注意: 那个图形化的启动器目前和Windows服务还不兼容. 如果你安装了服务, 你应该使用上述的服务控制台来控制服务而不是这个图形启动器.<br />
<br />
===自定义参数===<br />
<br />
高级用户可能希望传递参数到Java虚拟机(VM)来定制Openfire的运行时环境. 你可以在你的Openfire安装目录下的 bin/ 目录建立 vmoptions 文件来做到这一点. 对于 Windows服务, 你要建一个新文本文件,名为 openfire-service.vmoptions. 每个给VM的参数应该独立占用文件中的一行. 例如, 设置最小堆栈大小为 512 MB 和最大 VM 堆栈为 1024 MB, 你可以用:<br />
<br />
<source lang="ini"><br />
-Xms512m<br />
-Xmx1024m<br />
</source><br />
<br />
要新建参数给普通的启动器, 新建一个文件,名为 openfired.vmoptions (因为 openfire.exe 启动器会调用 openfired.exe 可执行文件来实际地启动服务器).<br />
<br />
==在Linux/Unix下运行Openfire==<br />
<br />
如果你正在一个 Red Hat 或类 Red Hat 的系统上运行 (CentOS, Fedora, 等等), 我们建议使用RPM,因为它包含一些标准的类Red Hat环境的自定义处理. 假设你使用了RPM, 你可以使用 '''/etc/init.d/openfire''' 脚本启动和停止Openfire.<br />
<br />
<source lang="bash"><br />
# /etc/init.d/openfire<br />
Usage /etc/init.d/openfire {start|stop|restart|status|condrestart|reload}<br />
# /etc/init.d/openfire start<br />
Starting openfire:<br />
</source><br />
<br />
如果你正在一个不同的Linux/Unix变种下运行, 并且/或你使用了tar.gz '安装包', 你可以使用你的Openfire安装目录下的 bin/openfire 脚本启动和停止Openfire:<br />
<br />
<source lang="bash"><br />
# ./openfire<br />
Usage: ./openfire {start|stop}<br />
# ./openfire start<br />
Starting openfire<br />
</source><br />
<br />
如果你想把Openfire安装成一个服务, 在 bin/extra 目录提供了两个脚本:<br />
<br />
* redhat-postinstall.sh -- 自动把Openfire安装为Red Hat的服务. 它会新建一个"jive"用户,然后拷贝 openfired 脚本到你的 init.d 目录. 这个脚本必须以root身份来运行. 更多信息请看脚本里的注释.<br />
* openfired -- 把Openfire当成服务运行的脚本. 你必须手工配置这个脚本. 更多信息请看脚本里的注释.<br />
<br />
'''如果你通过RPM安装,不推荐你使用这些脚本. RPM已经把这些脚本照顾得很好了.'''<br />
<br />
===自定义参数===<br />
<br />
你可以在你的Openfire安装目录下的 bin/ 目录建立 vmoptions 文件来做到这一点. 对于 Windows服务, 你要建一个新文本文件,名为 openfire-service.vmoptions. 每个给VM的参数应该独立占用文件中的一行. 例如, 设置最小堆栈大小为 512 MB 和最大 VM 堆栈为 1024 MB, 你可以用:<br />
<br />
高级用户可能希望传递参数到Java虚拟机(VM)来定制Openfire的运行时环境. 如果你是通过RPM安装的, 你可以编辑 /etc/sysconfig/openfire 文件并找到 OPENFIRE_OPTS 选项来定制它. 如果你通过.tar.gz安装的, 你要调整你的启动脚本来满足你的需要.<br />
<br />
==插件==<br />
<br />
插件给Openfire增加了额外的特性和协议支持. 在安装完你的Openfire之后, 你可能想下载并安装插件以增进你的服务器. 插件可从 igniterealtime.org 的 plugins 页面下载或直接从内部的管理控制台直接下载.<br />
<br />
===安装插件===<br />
<br />
如果你从Openfire内部的管理控制台下载了一个插件, 它将被自动安装. 如果你手工下载这个插件(打包成一个.jar文件), 你可以通过把插件文件拷贝到Openfire安装目录下的 plugins/ 目录来布署它. 一个插件监控器将自动解包这个插件到一个目录并安装这个插件到Openfire. 你也可以在管理控制台使用"上传插件"功能(在 插件 标签页) 来从本地文件系统装入一个插件到服务器.<br />
<br />
===管理插件===<br />
<br />
插件可通过内部的Openfire管理控制台来管理. 你也可以在任何时候通过删除插件的JAR文件来手工删除一个插件(当你这么干了,Openfire将从内存自动移除这个插件并删除它的目录).</div>
Snowqiang
http://wiki.jabbercn.org/XEP-0096
XEP-0096
2011-05-18T12:37:04Z
<p>Snowqiang: 删广告</p>
<hr />
<div>[[Category:XMPP扩展]]<br />
[[Category:已翻译]]<br />
<br />
'''本文的英文原文来自[http://www.xmpp.org/extensions/xep-0096.html XEP-0096]'''<br />
<br />
'''XEP-0096: 文件传输'''<br />
<br />
摘要: 本文定义了一个XMPP流初始化扩展的外壳,用于两个实体之间的文件传输. 该协议提供了一个模块化框架使能交换被传输文件的信息以及参数的协商(例如使用的通道).<br />
<br />
作者: Thomas Muldowney, Matthew Miller, Ryan Eatmon<br />
<br />
版权: © 1999 - 2010 XMPP标准化基金会(XSF). 参见[[XEP-0096#附录C:法律通告|法律通告]].<br />
<br />
状态: 草案<br />
<br />
类型: 标准跟踪<br />
<br />
版本: 1.1<br />
<br />
最后更新日期: 2004-04-13<br />
<br />
注意: 这里定义的协议是XMPP标准化基金会的一个'''草案标准'''.对本协议的执行是被鼓励的,也适于布署到生产系统,但是在它成为最终标准之前可能还会有一些变动.<br />
<br />
==绪论==<br />
<br />
在Jabber社区,传统的文件传输的方法是Out-of-Band Data带外传输协议。该协议有一些缺点:<br />
<br />
# 它是不可靠的<br />
# 当有一方在防火墙后面的话,该协议无效<br />
# 对要交换的文件有元数据的限制。<br />
<br />
本文档定义了一个流启动的流程用于解决带外传输的问题,并提供了一种健壮的、可靠的通过Jabber网络文件传输的算法。<br />
<br />
==要求==<br />
<br />
* 允许无缝文件传输,包括必要的回滚机制。<br />
<br />
* 保证一方或者双方都在防火墙之后时,文件传输还能进行。<br />
<br />
* 定义一个完整的文件传输的元数据,如下:<br />
<br />
# description<br />
# size<br />
# name<br />
# date<br />
# hash<br />
<br />
* 可选的,支持文件传输的范围。<br />
<br />
==协议==<br />
<br />
文件传输情形属于http://jabber.org/protocol/si/profile/file-transfer命名空间。该情形很简单:由可能的描述可选择的传输范围的子元素组成的根元素组成。<br />
<br />
根元素<file>有4个属性。这些属性只有在流初始化的情况下使用:<br />
<br />
* size - 发送文件的大小,按字节计算<br />
<br />
* name - 发送者想要发送的文件名<br />
<br />
* date - 文件的最后修改日期。日期格式使用XMPP Date and Time Profiles指定的格式。<br />
<br />
* hash - 文件内容的MD5<br />
<br />
文件大小和文件名属性必须(MUST)在传输情形中出现,其他属性可以(MAY)出现。<br />
<br />
根元素还有2个可能的子元素:<desc> 和 <range>,他们都是可选的(OPTIONAL)。<br />
<br />
<desc>是发送者提供的对于文件描述,接收者可以更加明确被发送的是什么。它不能(MUST NOT)在结果中发送。<br />
<br />
当提供了<range>元素时,它不应该包含属性。这表示发送者能按照范围发送。当发送流初始化的结果中包含了<range>元素时,是用以下属性:<br />
<br />
* offset - 指定了位置,按字节计算,开始文件传输的起点。如果没有指定,默认值为0。<br />
<br />
* length - 指定了从偏移量开始的要接收的字节数。默认值是从偏移量开始到文件末尾的字节数。<br />
<br />
<range>元素中的2个元素都是可选的(OPTIONAL)。发送无属性的元素等同于没有<range>元素。当在流初始化的结果中没有<range>元素时,发送者必须(MUST)从偏移量为0处发送完整的文件。更通常的情况是,从偏移量位置开始根据指定长度通过字节流发送。<br />
<br />
===强制实现的技术===<br />
<br />
为了能够允许无缝实时进行文件传输以及适当的回滚机制,为了更好的处理这些情况,对于这些情况的具体实现必须(MUST)支持SOCKS5 Bytestreams [4] 和In-Band Bytestreams [5]。相关的命名空间也要包含于"stream-method"的可选值中,如下例子中所示:<br />
<br />
此外,具体的实现也可以(MAY)支持其他机制。<br />
<br />
==例子==<br />
<br />
'''例子1. 在流初始化中,简单的使用示例'''<br />
<br />
<source lang="xml"><br />
<iq type='set' id='offer1' to='receiver@jabber.org/resource'><br />
<si xmlns='http://jabber.org/protocol/si' <br />
id='a0'<br />
mime-type='text/plain'<br />
profile='http://jabber.org/protocol/si/profile/file-transfer'><br />
<file xmlns='http://jabber.org/protocol/si/profile/file-transfer'<br />
name='test.txt'<br />
size='1022'/><br />
<feature xmlns='http://jabber.org/protocol/feature-neg'><br />
<x xmlns='jabber:x:data' type='form'><br />
<field var='stream-method' type='list-single'><br />
<option><value>http://jabber.org/protocol/bytestreams</value></option><br />
<option><value>http://jabber.org/protocol/ibb</value></option><br />
</field><br />
</x><br />
</feature><br />
</si><br />
</iq><br />
</source><br />
<br />
'''例子2. 在流初始化结果中,简单的使用示例''' <br />
<br />
<source lang="xml"><br />
<iq type='result' to='sender@jabber.org/resource' id='offer1'><br />
<si xmlns='http://jabber.org/protocol/si'><br />
<feature xmlns='http://jabber.org/protocol/feature-neg'><br />
<x xmlns='jabber:x:data' type='submit'><br />
<field var='stream-method'><br />
<value>http://jabber.org/protocol/bytestreams</value><br />
</field><br />
</x><br />
</feature><br />
</si><br />
</iq><br />
</source><br />
<br />
'''例子3. 在流初始化中,完整的使用示例''' <br />
<br />
<source lang="xml"><br />
<iq type='set' id='offer1' to='receiver@jabber.org/resource'><br />
<si xmlns='http://jabber.org/protocol/si' <br />
id='a0'<br />
mime-type='text/plain'<br />
profile='http://jabber.org/protocol/si/profile/file-transfer'><br />
<file xmlns='http://jabber.org/protocol/si/profile/file-transfer'<br />
name='test.txt'<br />
size='1022'<br />
hash='552da749930852c69ae5d2141d3766b1'<br />
date='1969-07-21T02:56:15Z'><br />
<desc>This is a test. If this were a real file...</desc><br />
</file><br />
<feature xmlns='http://jabber.org/protocol/feature-neg'><br />
<x xmlns='jabber:x:data' type='form'><br />
<field var='stream-method' type='list-single'><br />
<option><value>http://jabber.org/protocol/bytestreams</value></option><br />
<option><value>http://jabber.org/protocol/ibb</value></option><br />
</field><br />
</x><br />
</feature><br />
</si><br />
</iq><br />
</source><br />
<br />
'''例子4. 在流初始化结果中,完整的使用示例''' <br />
<br />
<source lang="xml"><br />
<iq type='result' to='sender@jabber.org/resource' id='offer1'><br />
<si xmlns='http://jabber.org/protocol/si'><br />
<file xmlns='http://jabber.org/protocol/si/profile/file-transfer'/><br />
<feature xmlns='http://jabber.org/protocol/feature-neg'><br />
<x xmlns='jabber:x:data' type='submit'><br />
<field var='stream-method'><br />
<value>http://jabber.org/protocol/bytestreams</value><br />
</field><br />
</x><br />
</feature><br />
</si><br />
</iq><br />
</source><br />
<br />
从文件的起点处接收256个字节<br />
<br />
'''例子 5.''' <br />
<br />
<source lang="xml"><br />
<range length='256'/><br />
</source><br />
<br />
从文件偏移量为128个字节处开始接收256个字节<br />
<br />
'''例子 6.'''<br />
<br />
<source lang="xml"><br />
<range offset='128' length='256'/><br />
</source><br />
<br />
从文件偏移量为128个字节处开始接收剩下的文件<br />
<br />
'''例子 7.''' <br />
<br />
<source lang="xml"><br />
<range offset='128'/><br />
</source><br />
<br />
以下的范围等同于没有发送范围请求,整个文件将被发送。<br />
<br />
'''例子 8.''' <br />
<br />
<source lang="xml"><br />
<range/><br />
</source><br />
<br />
==IANA事项==<br />
<br />
本文不需要与Internet Assigned Numbers Authority (IANA) [6]交互。<br />
<br />
==XMPP注册事项==<br />
<br />
===流初始化情况===<br />
<br />
本文档描述的情形包含于由XMPP Registrar维护的流初始化情形注册(参考<http://www.xmpp.org/registrar/si-profiles.html>)。注册请求如下:<br />
<br />
<source lang="xml"><br />
<profile><br />
<name>http://jabber.org/protocol/si/profile/file-transfer</name><br />
<doc>XEP-0096</doc><br />
<desc>A profile for file transfer between any two entities.</desc><br />
</profile><br />
</source><br />
<br />
===URI查询类型===<br />
<br />
XMPP注册维护了XMPP URIs的查询和键-值对应的使用,并且被XMPP URI Query Components所验证(参考<http://www.xmpp.org/registrar/querytypes.html>)。<br />
<br />
就如下描述的,文件传输的注册类型是"sendfile"和"recvfile"。注意"sendfile"意味着另一个实体将发送一个文件给控制着IRI/URI的XMPP实体,"recvfile"意味着另一个实体将会从控制着IRI/URI的XMPP实体那里接收文件。<br />
<br />
====发送文件====<br />
<br />
为了允许另一个实体发送文件,IRI/URI就遵循如下:<br />
<br />
'''例子9. 发送文件:IRI/URI'''<br />
<br />
xmpp:romeo@montague.net/orchard?sendfile<br />
<br />
具体的应用程序应该(SHOULD)提供一个界面,允许用户提供关于要发送的文件的信息(比如,为了选择一个文件,“浏览”用户计算机的文件系统)。结果,应用程序应该(SHOULD)发送一个发布流初始化请求的信息给在IRI/URI封装的XMPP地址。<br />
<br />
'''例子 10. 发送文件:结果节点'''<br />
<br />
<source lang="xml"><br />
<message from='juliet@capulet.com/balcony' to='romeo@montague.net'><br />
<sipub xmlns='http://jabber.org/protocol/si-pub'<br />
id='publish-0123'<br />
mime-type='text/plain'<br />
profile='http://jabber.org/protocol/si/profile/file-transfer'><br />
<file xmlns='http://jabber.org/protocol/si/profile/file-transfer'<br />
name='missive.txt'<br />
size='1024'<br />
date='2005-11-29T11:21Z'/><br />
</sipub><br />
</message><br />
</source><br />
<br />
以下提交注册"sendfile"类型。<br />
<br />
<source lang="xml"><br />
<querytype><br />
<name>sendfile</name><br />
<proto>http://jabber.org/protocol/si/profile/file-transfer</proto><br />
<desc>enables initiation of an inbound file transfer to XMPP entity</desc><br />
<doc>XEP-0096</doc><br />
</querytype><br />
</source><br />
<br />
====接收文件====<br />
<br />
允许另一个实体接收文件,IRI/URI如下:<br />
<br />
'''例子11. 接收文件: IRI/URI'''<br />
<br />
xmpp:romeo@montague.net/orchard?recvfile;sid=pub234;mime-type=text%2Fplain;name=reply.txt;size=2048<br />
<br />
该IRI/URI等同于以下XML节点:<br />
<br />
'''例子12. 接收文件:等同的节点'''<br />
<br />
<source lang="xml"><br />
<message from='romeo@montague.net' to='juliet@capulet.com/balcony'><br />
<sipub xmlns='http://jabber.org/protocol/si-pub'<br />
id='pub234'<br />
mime-type='text/plain'<br />
profile='http://jabber.org/protocol/si/profile/file-transfer'><br />
<file xmlns='http://jabber.org/protocol/si/profile/file-transfer'<br />
name='reply.txt'<br />
size='2048'/><br />
</sipub><br />
</message><br />
</source><br />
<br />
根据XEP-0137,应用程序应该(SHOULD)通过发送如下表单初始化文件传输:<br />
<br />
'''例子13. 接收文件:结果节点'''<br />
<br />
<source lang="xml"><br />
<iq from='juliet@capulet.com/balcony' to='romeo@montague.net/orchard'><br />
<start xmlns='http://jabber.org/protocol/si-pub' id='pub234'/><br />
</iq><br />
</source><br />
<br />
注意:开始流的请求要发送给在XMPP IRI/URI中定义的实体的全JID。因此,IRI/URI应该(SHOULD)包含全JID。如果没有如此,接收者必须(MUST)通过出席信息或者服务发现来查找全JID。如果接收者不能查找到发送者的全JID(比如,在最后一次出现时,通过发送订阅出席请求并从发送者的资源接收到出席信息),那么它应该(SHOULD)取消文件传输。<br />
<br />
以下的提交注册了"recvfile"查询类型。<br />
<br />
<source lang="xml"><br />
<querytype><br />
<name>recvfile</name><br />
<proto>http://jabber.org/protocol/si/profile/file-transfer</proto><br />
<desc>enables initiation of an outbound file transfer from XMPP entity</desc><br />
<doc>XEP-0096</doc><br />
<keys><br />
<key><br />
<name>mime-type</name><br />
<desc>the MIME type of the file being offered</desc><br />
</key><br />
<key><br />
<name>name</name><br />
<desc>the name of the file being offered</desc><br />
</key><br />
<key><br />
<name>sid</name><br />
<desc>the session ID associated with the file being offered</desc><br />
</key><br />
<key><br />
<name>size</name><br />
<desc>the size in bytes of the file being offered</desc><br />
</key><br />
</keys><br />
</querytype><br />
</source><br />
<br />
==XML Schema==<br />
<br />
<source lang="xml"><br />
<?xml version='1.0' encoding='UTF-8'?><br />
<br />
<xs:schema<br />
xmlns:xs='http://www.w3.org/2001/XMLSchema'<br />
targetNamespace='http://jabber.org/protocol/si/profile/file-transfer'<br />
xmlns='http://jabber.org/protocol/si/profile/file-transfer'<br />
elementFormDefault='qualified'><br />
<br />
<xs:annotation><br />
<xs:documentation><br />
The protocol documented by this schema is defined in<br />
XEP-0096: http://www.xmpp.org/extensions/xep-0096.html<br />
</xs:documentation><br />
</xs:annotation><br />
<br />
<xs:element name='file'><br />
<xs:complexType><br />
<xs:sequence minOccurs='0'><br />
<xs:element name='desc' type='xs:string'/><br />
<xs:element ref='range'/><br />
</xs:sequence><br />
<xs:attribute name='date' type='xs:dateTime' use='optional'/><br />
<xs:attribute name='hash' type='xs:string' use='optional'/><br />
<xs:attribute name='name' type='xs:string' use='required'/><br />
<xs:attribute name='size' type='xs:integer' use='required'/><br />
</xs:complexType><br />
</xs:element><br />
<br />
<xs:element name='range'><br />
<xs:complexType><br />
<xs:simpleContent><br />
<xs:extension base='empty'><br />
<xs:attribute name='length' type='xs:integer' use='optional'/><br />
<xs:attribute name='offset' type='xs:integer' use='optional'/><br />
</xs:extension><br />
</xs:simpleContent><br />
</xs:complexType><br />
</xs:element><br />
<br />
<xs:simpleType name='empty'><br />
<xs:restriction base='xs:string'><br />
<xs:enumeration value=''/><br />
</xs:restriction><br />
</xs:simpleType><br />
<br />
</xs:schema><br />
</source><br />
<br />
==附录==<br />
===附录A:文档信息===<br />
<br />
系列:[http://xmpp.org/extensions/ XEP]<br />
<br />
序号:0096<br />
<br />
发布者:[http://xmpp.org/xsf/ XMPP标准基金会]<br />
<br />
状态:[http://xmpp.org/extensions/xep-0001.html#states-Draft 草案]<br />
<br />
类型:[http://www.xmpp.org/extensions/xep-0001.html#types-Standards%20Track 标准跟踪]<br />
<br />
版本:1.1<br />
<br />
最后更新:2004-04-13<br />
<br />
批准机构:[http://xmpp.org/council/ XMPP理事会]<br />
<br />
依赖标准:XMPP Core, XEP-0095<br />
<br />
替代标准:无<br />
<br />
被替代标准:无<br />
<br />
缩略名:si-filetransfer<br />
<br />
XML架构(Schema): <http://www.xmpp.org/schemas/file-transfer.xsd><br />
<br />
原文控制: [http://svn.xmpp.org:18080/browse/XMPP/trunk/extensions/xep-0096.xml HTML] [http://svn.xmpp.org:18080//changelog/~rss/XMPP/trunk/extensions/xep-0096.xml/rss.xml RSS]<br />
<br />
本文的其它格式: [http://xmpp.org/extensions/xep-0096.xml XML] [http://xmpp.org/extensions/xep-0096.pdf PDF]<br />
<br />
===附录B:作者信息===<br />
<br />
'''Thomas Muldowney'''<br />
<br />
:Email: [mailto:temas@jabber.org temas@jabber.org]<br />
<br />
:JabberID: temas@jabber.org<br />
<br />
'''Matthew Miller'''<br />
<br />
:Email: [mailto:linuxwolf@outer-planes.net linuxwolf@outer-planes.net]<br />
<br />
:JabberID: linuxwolf@outer-planes.net<br />
<br />
'''Ryan Eatmon'''<br />
<br />
:Email: [mailto:reatmon@jabber.org reatmon@jabber.org]<br />
<br />
:JabberID: reatmon@jabber.org<br />
<br />
{{Template:XEP附录CDEF}}<br />
<br />
===附录G:备注===<br />
<br />
# XEP-0066: Out of Band Data <http://www.xmpp.org/extensions/xep-0066.html>.<br />
# XEP-0095: Stream Initiation <http://www.xmpp.org/extensions/xep-0095.html>.<br />
# XEP-0082: XMPP Date and Time Profiles <http://www.xmpp.org/extensions/xep-0082.html>.<br />
# XEP-0065: SOCKS5 Bytestreams <http://www.xmpp.org/extensions/xep-0065.html>.<br />
# XEP-0047: In-Band Bytestreams <http://www.xmpp.org/extensions/xep-0047.html>.<br />
# 互联网编号分配机构(IANA) 是用于互联网协议的唯一性参数值分配的核心协调者, 例如号码和URI计划. 更多信息, 见 <http://www.iana.org/>.<br />
# XMPP登记员XMPP Registrar 维护着一个保留的协议名字空间以及用于由XMPP标准基金会批准的XMPP扩展协议的上下文参数的注册项的列表. 更多信息, 见 <http://xmpp.org/registrar/>.<br />
# XEP-0147: XMPP URI Query Components <http://www.xmpp.org/extensions/xep-0147.html>.<br />
# XEP-0137: Publishing Stream Initiation Requests <http://www.xmpp.org/extensions/xep-0137.html>.<br />
<br />
===附录H:修订历史===<br />
<br />
注意: 本协议的旧版本可能在 http://xmpp.org/extensions/attic/ 还可用<br />
<br />
Version 1.1 (2004-04-13)<br />
<br />
More fully defined the XMPP Registrar considerations. (psa) <br />
<br />
Version 1.1 (2003-12-30)<br />
<br />
Improved explanatory text; fixed several errors in the schema. (psa) <br />
<br />
Version 1.0 (2003-10-17)<br />
<br />
Per a vote of the Jabber Council, advanced status to Draft. (psa) <br />
<br />
Version 0.7 (2003-10-07)<br />
<br />
Added IBB as a MUST requirement. (tjm) <br />
<br />
Version 0.6 (2003-08-18)<br />
<br />
Cleaned up some namespace inconsistencies, added the <desc> element for file descriptions. (tjm) <br />
<br />
Version 0.5 (2003-07-15)<br />
<br />
Stream ids not needed on return results. Moved s5b, ibb, and url-data to the actual namespaces of the stream protocols. (rwe) <br />
<br />
Version 0.4 (2003-06-30)<br />
<br />
Fixed various typos and inconsistencies (lw) <br />
<br />
Version 0.3 (2003-06-30)<br />
<br />
Added XML Schema (lw) <br />
<br />
Version 0.2 (2003-06-24)<br />
<br />
Clarified many examples, added linuxwolf as an author (again, my bad, should have been there), clarified the allowed streams and how data is sent over it. (tjm) <br />
<br />
Version 0.1 (2003-06-10)<br />
<br />
Initial version. (tjm) <br />
<br />
----<br />
<br />
结束</div>
Snowqiang
http://wiki.jabbercn.org/XEP-0138
XEP-0138
2011-05-18T12:36:14Z
<p>Snowqiang: 删广告</p>
<hr />
<div>[[Category:XMPP扩展]]<br />
[[Category:已翻译]]<br />
<br />
'''本文的英文原文来自[http://www.xmpp.org/extensions/xep-0138.html XEP-0138]'''<br />
<br />
'''XEP-0138: 流压缩'''<br />
<br />
摘要: 本文定义了一个XMPP协议扩展,用于协商XML流的压缩,特别在标准TLS压缩无法协商的情况下. 该协议提供了一个模块化框架,可以容纳广泛的压缩算法; ZLIB 压缩算法是强制性的实现,但实现也可以可能支持额外的其他算法.<br />
<br />
作者: Joe Hildebrand, Peter Saint-Andre<br />
<br />
版权: © 1999 - 2010 XMPP标准化基金会(XSF). 参见[[XEP-0138#附录C:法律通告|法律通告]].<br />
<br />
状态: 最终版<br />
<br />
类型: 标准跟踪<br />
<br />
版本: 2.0<br />
<br />
最后更新日期: 2009-05-27<br />
<br />
注意: 这里定义的协议是XMPP标准化基金会的一个'''最终版''',可被认为是一个稳定的技术,供实现和布署.<br />
<br />
==绪论==<br />
<br />
[[RFC3920|XMPP Core]] [[XEP-0138#附录G:备注|1]]指明了使用TLS(参考[http://tools.ietf.org/html/rfc4346 RFC 4346] [[XEP-0138#附录G:备注|2]] )加密XML流,TLS包括了压缩加密流量的能力(参考[http://tools.ietf.org/html/rfc3749 RFC 3749] [[XEP-0138#附录G:备注|3]] )。然而,不是所有计算机平台都实现了TLS,而流压缩可以使基于这些平台的应用实现互通。本文档定义了在TLS之外的协议XML流的压缩算法。<br />
<br />
==用例==<br />
<br />
协议流如下:<br />
<br />
'''例子1. 收到实体提供的流压缩特征'''<br />
<br />
<source lang="xml"><br />
<stream:features><br />
<starttls xmlns='urn:ietf:params:xml:ns:xmpp-tls'/><br />
<compression xmlns='http://jabber.org/features/compress'><br />
<method>zlib</method><br />
<method>lzw</method><br />
</compression><br />
</stream:features><br />
</source><br />
<br />
注意:<compression/>元素必须(MUST)包含至少一个<method/>子元素。每个<method/>必须(MUST)包含指定了压缩方法的XML字符,方法名应该(SHOULD)是在本文档的 [[XEP-0138#压缩方法注册|压缩方法注册]] 中注册的。<br />
<br />
初始实体可能(MAY)在收到的压缩方法中请求一个压缩方法。<br />
<br />
'''例子2. 初始实体请求流压缩'''<br />
<br />
<source lang="xml"><br />
<ccompress xmlns='http://jabber.org/protocol/compress'><br />
<method>zlib</method><br />
</compress><br />
</source><br />
<br />
注意:如果初始实体不理解声明的压缩方法,它应该(SHOULD)忽略压缩选项,就像没有发布压缩方法一样处理。<br />
<br />
如果接受实体不支持初始实体请求的压缩方法,那么接收者实体必须(MUST)返回一个<unsupported-method/>错误<br />
<br />
'''例子3. 接收实体报告该方法不支持。'''<br />
<br />
<source lang="xml"><br />
<failure xmlns='http://jabber.org/protocol/compress'><br />
<unsupported-method/><br />
</failure><br />
</source><br />
<br />
如果接收实体发现请求的方法不能接受或者由于其他原因而不能使用,它必须(MUST)返回一个<setup-failed/>错误:<br />
<br />
'''例子4. 接收实体报告流压缩协商失败'''<br />
<br />
<source lang="xml"><br />
<failure xmlns='http://jabber.org/protocol/compress'><br />
<setup-failed/><br />
</failure><br />
</source><br />
<br />
注意:协商失败不应该(SHOULD NOT)被看作不可挽救的错误,因此不应该(SHOULD NOT)导致流错误。特别的,初始实体可以在失败后,重新协商。<br />
<br />
如果没有错误,接收实体必须(MUST)通知初始实体协商成功。<br />
<br />
'''例子5. 接收实体通知流压缩的协商结果'''<br />
<br />
<source lang="xml"><br />
<compressed xmlns='http://jabber.org/protocol/compress'/><br />
</source><br />
<br />
现在2个实体必须(MUST)都忽略先前的流(未压缩的),就像TLS协商和SASL协商(在RFC3920指定)一样,必须(MUST)用一个新的(压缩的)流开始通讯。因此初始实体必须(MUST)初始一个新的流给接收实体:<br />
<br />
'''例子6. 初始实体初始新的(压缩)流'''<br />
<br />
<source lang="xml"><br />
<stream:stream<br />
xmlns='jabber:client'<br />
xmlns:stream='http://etherx.jabber.org/streams'<br />
to='shakespeare.lit'><br />
</source><br />
<br />
如果在新的(压缩)流发送之后处理失败,发现出错的实体应该(SHOULD)生成出错流并关闭流。<br />
<br />
'''例子7. 因为流错误实体关闭流'''<br />
<br />
<source lang="xml"><br />
<stream:error><br />
<undefined-condition xmlns='urn:ietf:params:xml:ns:xmpp-streams'/><br />
<failure xmlns='http://jabber.org/protocol/compress'/><br />
<processing-failed/><br />
</failure><br />
</stream:error><br />
</stream:stream><br />
</source><br />
<br />
==业务规则==<br />
<br />
应用以下规则:<br />
<br />
* 如果正在协商流压缩,它必须(MUST)是双向的。<br />
<br />
* TLS压缩和流压缩不应该(SHOULD NOT)同时使用。<br />
<br />
* 如果TLS压缩失败了,那么之后可以再进行流压缩协商。<br />
<br />
关于流特性协商的顺序的细节,参考 [[XEP-0138#压缩方法注册|推荐的流特性协商顺序]]<br />
<br />
==强制实现的技术==<br />
<br />
在[http://tools.ietf.org/html/rfc1950 RFC 1950] [[XEP-0138#附录G:备注|5]] 中对ZLIB压缩方法的支持必需的(REQUIRED).<br />
<br />
所有其他方法是可选的;这些方法可能将来会进入本文的 [[XEP-0138#压缩方法注册|压缩方法注册]]章节所述的注册项.<br />
<br />
==可选的技术==<br />
<br />
除了ZLIB之外,具体的实现也可以(MAY)支持以下方法:<br />
<br />
[http://xmpp.org/extensions/xep-0229.html LZW流压缩] [[XEP-013#附录G:备注|6]]<br />
<br />
==实现注意==<br />
<br />
当使用ZLIB压缩的时候,在当前的发送完成之后,发送方的应用应该(SHOULD)完成ZLIB流部分刷新。注意这些语句有点含糊的:发送方的应用可能在发送每个XML节后刷新流并且发送数据,但是另一方面也可能在发送了等待发送队列里的所有节点后刷新流并且发送数据。何时刷新压缩应用的状态取决于发送方的应用。<br />
<br />
==安全事项==<br />
<br />
通过TLS(在[[RFC3920 RFC 3920]]中定义)加密的流和压缩流(在本文档定义的)并不是互相排斥的,但是通过TLS加密的流必须(MUST)在流压缩协商之前先协商,这是确保流的安全性。<br />
<br />
==IANA事项==<br />
<br />
本文档和互联网端口号授权组织 (IANA) [[XEP-0138#附录G:备注|7]]没有交互。<br />
<br />
==XMPP注册事项==<br />
<br />
===流特性===<br />
<br />
在流特性的注册项中,[http://xmpp.org/registrar/ XMPP注册项] [[XEP-0138#附录G:备注|8]]中包含'http://jabber.org/features/compress'<br />
<br />
===协议命名空间===<br />
<br />
在协议命名空间的注册项中,XMPP注册项中包含'http://jabber.org/protocol/compress'<br />
<br />
===压缩方法注册===<br />
<br />
在<http://www.xmpp.org/registrar/compress.html>中,XMPP注册项维护了压缩方法的注册。<br />
<br />
====过程====<br />
<br />
为了提交新的注册项到注册登记处,登记者必须根据以下表单将其包含在相关的扩展协议中或者发送邮件到<registrar@xmpp.org>:<br />
<br />
<source lang="xml"><br />
<method><br />
<name>the XML character data of the method element</name><br />
<desc>a natural-language description of the compression method</desc><br />
<doc>the document that specifies or registers the compression method</doc><br />
</method><br />
</source><br />
<br />
登记者可能同时登记多个压缩方法,每个方法都包含一个独立的<method/>元素。<br />
<br />
====注册====<br />
<br />
<source lang="xml"><br />
<method><br />
<name>zlib</name><br />
<desc>the ZLIB compression method</desc><br />
<doc>RFC 1950</doc><br />
</method><br />
</source><br />
<br />
==XML Schemas==<br />
<br />
===流特性===<br />
<br />
<source lang="xml"><br />
<?xml version='1.0' encoding='UTF-8'?><br />
<br />
<xs:schema<br />
xmlns:xs='http://www.w3.org/2001/XMLSchema'<br />
targetNamespace='http://jabber.org/features/compress'<br />
xmlns='http://jabber.org/features/compress'<br />
elementFormDefault='qualified'><br />
<br />
<xs:annotation><br />
<xs:documentation><br />
The protocol documented by this schema is defined in<br />
XEP-0138: http://www.xmpp.org/extensions/xep-0138.html<br />
</xs:documentation><br />
</xs:annotation><br />
<br />
<xs:element name='compression'><br />
<xs:complexType><br />
<xs:sequence><br />
<xs:element name='method' type='xs:NCName' maxOccurs='unbounded'/><br />
</xs:sequence><br />
</xs:complexType><br />
</xs:element><br />
<br />
</xs:schema><br />
</source><br />
<br />
===协议命名空间===<br />
<br />
<source lang="xml"><br />
<?xml version='1.0' encoding='UTF-8'?><br />
<br />
<xs:schema<br />
xmlns:xs='http://www.w3.org/2001/XMLSchema'<br />
targetNamespace='http://jabber.org/protocol/compress'<br />
xmlns='http://jabber.org/protocol/compress'<br />
elementFormDefault='qualified'><br />
<br />
<xs:import namespace='urn:ietf:params:xml:ns:xmpp-stanzas'/><br />
<br />
<xs:annotation><br />
<xs:documentation><br />
The protocol documented by this schema is defined in<br />
XEP-0138: http://www.xmpp.org/extensions/xep-0138.html<br />
</xs:documentation><br />
</xs:annotation><br />
<br />
<xs:element name='compress'><br />
<xs:complexType><br />
<xs:sequence><br />
<xs:element name='method' type='xs:NCName' minOccurs='1' maxOccurs='unbounded'/><br />
</xs:sequence><br />
</xs:complexType><br />
</xs:element><br />
<br />
<xs:element name='compressed' type='empty'/><br />
<br />
<xs:element name='failure'><br />
<xs:complexType><br />
<xs:choice><br />
<xs:element name='setup-failed' type='empty'/><br />
<xs:element name='processing-failed' type='empty'/><br />
<xs:element name='unsupported-method' type='empty'/><br />
<xs:sequence xmlns:err='urn:ietf:params:xml:ns:xmpp-stanzas'><br />
<xs:group ref='err:stanzaErrorGroup'/><br />
<xs:element ref='err:text' minOccurs='0'/><br />
</xs:sequence><br />
</xs:choice><br />
</xs:complexType><br />
</xs:element><br />
<br />
<xs:simpleType name='empty'><br />
<xs:restriction base='xs:string'><br />
<xs:enumeration value=''/><br />
</xs:restriction><br />
</xs:simpleType><br />
<br />
</xs:schema><br />
</source><br />
<br />
==附录==<br />
===附录A:文档信息===<br />
<br />
系列:[http://xmpp.org/extensions/ XEP]<br />
<br />
序号:0138<br />
<br />
发布者:[http://xmpp.org/xsf/ XMPP标准基金会]<br />
<br />
状态:[http://www.xmpp.org/extensions/xep-0001.html#states-Final 终结版]<br />
<br />
类型:[http://www.xmpp.org/extensions/xep-0001.html#types-Standards%20Track 标准跟踪]<br />
<br />
版本:2.0<br />
<br />
最后更新:2009-05-27<br />
<br />
批准机构:[http://xmpp.org/council/ XMPP理事会]<br />
<br />
依赖标准:XMPP Core<br />
<br />
替代标准:无<br />
<br />
被替代标准:无<br />
<br />
缩略名:compress<br />
<br />
compress名字空间的XML架构: <http://www.xmpp.org/schemas/compress.xsd><br />
<br />
feature名字空间的XML架构: <http://www.xmpp.org/schemas/compress-feature.xsd><br />
<br />
注册表: <http://xmpp.org/registrar/compress.html><br />
<br />
原文控制: [http://svn.xmpp.org:18080/browse/XMPP/trunk/extensions/xep-0138.xml HTML] [http://svn.xmpp.org:18080//changelog/~rss/XMPP/trunk/extensions/xep-0138.xml/rss.xml RSS]<br />
<br />
本文的其它格式: [http://xmpp.org/extensions/xep-0138.xml XML] [http://xmpp.org/extensions/xep-0138.pdf PDF]<br />
<br />
===附录B:作者信息===<br />
<br />
'''Joe Hildebrand'''<br />
<br />
:Email: [mailto:jhildebr@cisco.com jhildebr@cisco.com]<br />
<br />
:JabberID: hildjj@jabber.org<br />
<br />
'''Peter Saint-Andre'''<br />
<br />
:Email: [mailto:stpeter@jabber.org stpeter@jabber.org]<br />
<br />
:JabberID: stpeter@jabber.org<br />
<br />
:URI: https://stpeter.im/<br />
<br />
{{Template:XEP附录CDEF}}<br />
<br />
===附录G:备注===<br />
<br />
# RFC 3920: 可扩展的消息和出席信息协议 (XMPP): Core <http://tools.ietf.org/html/rfc3920>.<br />
# RFC 4346: TLS协议版本1.1 <http://tools.ietf.org/html/rfc4346>.<br />
# RFC 3749: TLS协议压缩方法 <http://tools.ietf.org/html/rfc3749>.<br />
# XEP-0170: 推荐的流特性协商顺序 <http://www.xmpp.org/extensions/xep-0170.html>.<br />
# RFC 1950: ZLIB压缩数据格式规范版本 3.3 <http://tools.ietf.org/html/rfc1950>.<br />
# XEP-0229: LZW流压缩 <http://www.xmpp.org/extensions/xep-0229.html>.<br />
# 互联网编号分配机构(IANA) 是用于互联网协议的唯一性参数值分配的核心协调者, 例如号码和URI计划. 更多信息, 见 <http://www.iana.org/>.<br />
# XMPP登记员XMPP Registrar 维护着一个保留的协议名字空间以及用于由XMPP标准基金会批准的XMPP扩展协议的上下文参数的注册项的列表. 更多信息, 见 <http://xmpp.org/registrar/>.<br />
<br />
===附录H:修订历史===<br />
<br />
注意: 本协议的旧版本可能在 http://xmpp.org/extensions/attic/ 还可用<br />
<br />
Version 2.0 (2009-05-27)<br />
<br />
Per a vote of the XMPP Council, advanced status to Final.<br />
<br />
(psa) <br />
<br />
Version 1.3 (2007-09-26)<br />
<br />
Moved specification of LZW algorithm to XEP-0229.<br />
<br />
(psa) <br />
<br />
Version 1.2 (2007-08-22)<br />
<br />
Clarified when compression shall be considered to start; per XEP-0170, specified that compression should be negotiated after SASL.<br />
<br />
(psa) <br />
<br />
Version 1.1 (2005-12-14)<br />
<br />
More completely specified error handling; mentioned LZW (DCLZ) method.<br />
<br />
(psa) <br />
<br />
Version 1.0 (2005-06-16)<br />
<br />
Per a vote of the Jabber Council, advanced status to Draft.<br />
<br />
(psa) <br />
<br />
Version 0.5 (2005-05-18)<br />
<br />
Modifications to address Council feedback: used RFC 3920 terminology; specified error conditions; specified ZLIB as mandatory to implement.<br />
<br />
(psa) <br />
<br />
Version 0.4 (2005-05-11)<br />
<br />
Corrected several errors in the schemas.<br />
<br />
(psa) <br />
<br />
Version 0.3 (2005-03-28)<br />
<br />
Specified compression methods registry.<br />
<br />
(psa) <br />
<br />
Version 0.2 (2004-09-28)<br />
<br />
Fixed TLS text per list discussion.<br />
<br />
(psa) <br />
<br />
Version 0.1 (2004-07-16)<br />
<br />
Initial version.<br />
<br />
(jjh/psa) <br />
<br />
----<br />
<br />
结束</div>
Snowqiang
http://wiki.jabbercn.org/XEP-0213
XEP-0213
2011-05-18T12:35:15Z
<p>Snowqiang: 删广告</p>
<hr />
<div>[[Category:XMPP扩展]]<br />
[[Category:已废弃]]<br />
<br />
'''本文的英文原文来自[http://www.xmpp.org/extensions/xep-0213.html XEP-0213]'''<br />
<br />
'''XEP-0213: XMPP中级客户端2008'''<br />
<br />
本文定义了XMPP中级客户端2008兼容级别.<br />
<br />
注意: 这里定义的协议是XMPP标准化基金会的一个草案标准.对本协议的执行是被鼓励的,也适于部署到生产系统,但是在它成为最终标准之前可能还会有一些变动.<br />
<br />
'''文档信息'''<br />
<br />
系列: [[XMPP扩展|XEP]]<br />
<br />
编号: 0213<br />
<br />
发行者: [[XMPP标准基金会]]<br />
<br />
状态: 草案<br />
<br />
类型: 标准跟踪<br />
<br />
版本: 1.0<br />
<br />
最后更新日期: 2007-07-11<br />
<br />
批准机构: [[XMPP理事会]]<br />
<br />
依赖于: [[XEP-0211]], XEP-0016, [[XEP-0045]], XEP-0054, XEP-0085, XEP-0155<br />
<br />
上文: 无<br />
<br />
下文: 无<br />
<br />
简称: 无<br />
<br />
Wiki页: <http://wiki.jabber.org/index.php/XMPP Intermediate IM Client 2008 (XEP-0213)><br />
<br />
'''作者信息'''<br />
<br />
'''Peter Saint-Andre'''<br />
<br />
:Email: [mailto:stpeter@jabber.org stpeter@jabber.org]<br />
<br />
:JabberID: [xmpp:stpeter@jabber.org stpeter@jabber.org]<br />
<br />
'''法律通告'''<br />
<br />
XMPP扩展协议的版权(1999-2007)归XMPP标准化基金会(XSF)所有,并完全遵守XSF的知识产权策略<http://www.xmpp.org/extensions/ipr-policy.shtml>. 本文可以任意分发,仅受限于创作公用协议的第四条.(<http://creativecommons.org/licenses/by/2.5/>).<br />
<br />
'''讨论地点'''<br />
<br />
首选的讨论的地方是标准讨论邮件列表: <http://mail.jabber.org/mailman/listinfo/standards>.<br />
<br />
'''XMPP 相关信息'''<br />
<br />
XMPP 是由XSF(XMPP标准化基金会)按互联网标准程序贡献的,和 IETF的RFC 2026兼容的规范,包括 XMPP核心(RFC 3920)和 XMPP IM(RFC 3921).在本文中定义的任何协议,都是在互联网标准程序之外开发的,是扩展XMPP,而不是改变、发展和修改 XMPP本身.<br />
<br />
'''一致性术语'''<br />
<br />
本文中以下关键词的含义如 RFC 2119 所述: "MUST", "SHALL", "REQUIRED"; "MUST NOT", "SHALL NOT"; "SHOULD", "RECOMMENDED"; "SHOULD NOT", "NOT RECOMMENDED"; "MAY", "OPTIONAL".<br />
<br />
==绪论==<br />
<br />
XMPP标准化基金会(XSF) [1|XMPP文档列表/XMPP扩展/XEP-0213#1] 定义了协议簇用于兼容性测试和软件认证. 本文定义了XMPP中级客户端认证级别.<br />
<br />
==定义==<br />
<br />
XMPP中级客户端2008认证级别定义如下:<br />
<br />
表1: 必需和建议的协议<br />
<br />
{|border="1" cellspacing="0" <br />
!协议 !!必需级别<br />
|-<br />
|[[XEP-0211] [2] | |必需<br />
|-<br />
|[http://www.xmpp.org/extensions/xep-0016.html Server-Based Privacy Rules] [3] ||推荐<br />
|-<br />
|[[XEP-0045]] [4], 实体用例和驻留者用例 ||必需<br />
|-<br />
|[http://www.xmpp.org/extensions/xep-0054.html vcard-temp] [5] ||推荐<br />
|-<br />
|[http://www.xmpp.org/extensions/xep-0085.html Chat State Notifications] [6] ||必需<br />
|-<br />
|[http://www.xmpp.org/extensions/xep-0155.html Stanza Session Negotiation] [7] ||推荐<br />
|}<br />
<br />
==实施备注==<br />
<br />
在这里一些被引用的协议本身依赖于(别的协议); 开发者必须查阅相应的协议以得到更多的信息.<br />
<br />
==安全事项==<br />
<br />
本文没有引入超越本协议所以来的那些协议所规定的的额外的安全事项.<br />
<br />
==IANA事项==<br />
<br />
本文不需要和Internet Assigned Numbers Authority (IANA) [8|XMPP文档列表/XMPP扩展/XEP-0213#8] 的交互.<br />
<br />
==XMPP注册项事项==<br />
<br />
本文不需要和 XMPP Registrar [9|XMPP文档列表/XMPP扩展/XEP-0213#9] 交互.<br />
<br />
==备注==<br />
<br />
# XMPP标准化基金会(XSF)是一个独立的非营利的会员组织, 其宗旨是发展XMPP的开放扩展. 更多信息参见 <http://www.xmpp.org/xsf/>.<br />
# XEP-0211: XMPP Basic Client 2008 <http://www.xmpp.org/extensions/xep-0211.html>.<br />
# XEP-0016: Server-Based Privacy Rules <http://www.xmpp.org/extensions/xep-0016.html>.<br />
# XEP-0045: Multi-User Chat <http://www.xmpp.org/extensions/xep-0045.html>.<br />
# XEP-0054: vcard-temp <http://www.xmpp.org/extensions/xep-0054.html>.<br />
# XEP-0085: Chat State Notifications <http://www.xmpp.org/extensions/xep-0085.html>.<br />
# XEP-0155: Stanza Session Negotiation <http://www.xmpp.org/extensions/xep-0155.html>.<br />
# 互联网分配号码授权(IANA) 是一个中枢协调者, 为互联网协议分配唯一的参数值, 例如端口号和URI 方案. 更多信息参见<http://www.iana.org/>.<br />
# XMPP登记维护了保留的协议名字空间的列表, 以及XMPP标准化基金会批准的用于XMPP扩展协议中的已登记参数. 更多信息参见<http://www.xmpp.org/registrar/>.<br />
<br />
==修订历史==<br />
<br />
'''Version 1.0 (2007-07-11)'''<br />
<br />
经过 XMPP理事会投票, 升级为草案.<br />
<br />
(psa)<br />
<br />
'''Version 0.5 (2007-07-11)'''<br />
<br />
增加了 XEP-0155 作为推荐.<br />
<br />
(psa)<br />
<br />
'''Version 0.4 (2007-06-11)'''<br />
<br />
增加了实施备注.<br />
<br />
(psa)<br />
<br />
'''Version 0.3 (2007-05-30)'''<br />
<br />
经过列表讨论, 移除了 XHTML-IM.<br />
<br />
(psa)<br />
<br />
'''Version 0.2 (2007-05-11)'''<br />
<br />
经过列表讨论, 修改了 MUC 支持, 增加了 privacy lists, 并增加了 vCard 支持.<br />
<br />
(psa)<br />
<br />
'''Version 0.1 (2007-04-20)'''<br />
<br />
初始发行版本.<br />
<br />
(psa)<br />
<br />
'''Version 0.0.1 (2007-03-30)'''<br />
<br />
第一个草案, 从 XEP-0117 分离出来. (psa)<br />
<br />
结束</div>
Snowqiang
http://wiki.jabbercn.org/XEP-0004
XEP-0004
2011-05-18T12:33:21Z
<p>Snowqiang: 删除广告;(</p>
<hr />
<div>[[Category:XMPP扩展]]<br />
[[Category:已翻译]]<br />
<br />
<br />
'''本文的英文原文来自[http://xmpp.org/extensions/xep-0004.html XEP-0004]'''<br />
<br />
'''XEP-0004: 数据表单'''<br />
<br />
摘要: 本文定义了一个XMPP扩展协议用于数据表单,可以用于worklows如服务配置以及特定应用的数据描述和报告。这个协议包括表单处理的轻量级语义(如请求,响应,提交和取消),定义了几种常见的字段类型(布尔、单个或多个选择的列表选项、单行或多行的文本,单个或多个JabberID、隐藏字段,等等),为以后的数据类型提供扩展性,可以用在广泛的应用中。该协议并不是要提供完整的表格处理功能(由W3C XForms技术提供),而是提供这种功能的基本子集给XMPP使用。<br />
<br />
作者: Ryan Eatmon, Joe Hildebrand, Jeremie Miller, Thomas Muldowney, Peter Saint-Andre<br />
<br />
XMPP扩展协议的版权(1999-2008)归XMPP标准化基金会(XSF)所有<br />
<br />
版权: © 1999 - 2010 XMPP标准化基金会(XSF). 参见[[XEP-0004#法律通告|法律通告]].<br />
<br />
状态: 最终<br />
<br />
类型: 标准跟踪<br />
<br />
版本: 2.9<br />
<br />
最后更新日期: 2007-08-13<br />
<br />
注意: 这里定义的协议是XMPP标准化基金会的一个最终标准.对于实现和布署来说可以被认为是一个稳定技术.<br />
<br />
==绪论==<br />
<br />
几个现有的Jabber/XMPP的协议包含用户和应用程序之间的结构数据交换,为常用的任务,如注册([http://xmpp.org/extensions/xep-0077.html In-Band Registration][[XEP-0004#附录G:备注|1]])和搜索([http://xmpp.org/extensions/xep-0055.html Jabber Search] [[XEP-0004#附录G:备注|2]])。不幸的是,这些早期的协议是“硬编码”,因此很大的限制了可交换信息的范围。此外,其他协议(如,[http://xmpp.org/extensions/xep-0045.html Multi-User Chat] [[XEP-0004#附录G:备注|3]])可能需要以交换数据为目的,例如配置,但是配置选项可能根据具体实施或部署不同。最后,开发人员可能要以灵活的方式扩展其他协议(如, [http://xmpp.org/extensions/xep-0030.html Service Discovery][[XEP-0004#附录G:备注|4]]),以提供在基本协议没有定义的信息。在所有这些情况下,这将有助于使用一个通用的数据描述格式,可以用于动态表单生成和各种情况下的数据“建模”。<br />
<br />
一个例子可能会有帮助。试想一下,当用户创建一个文本会议服务的多用户聊天室,该服务允许用户以各种方式配置房间。虽然大多数实现可能提供了一个较为常见的可配置功能集(讨论记录,房间拥有者的最大数量,等等)。还会有一些分歧:也许一个实现允许把房间日志以各种文件类型(XML,HTML,PDF等格式)和各种时间周期(每小时,每天,每周等)保存。而另一个实现,可能只存在登录的开/关选择一种格式(如,在HTML保存每日日志)。很明显,第一个实现比第二个实现有更多的配置选项。而不像“硬编码”每个选项通过不同的XML元素(如,<room_logging_period/>),一个好的设计应该包含更多灵活的格式。<br />
<br />
此处所描述的'jabber:x:data'协议为Jabber/XMPP实体的使用定义了灵活的格式,控制在“名称值”对的简单和[http://www.w3.org/TR/xforms/ XForms 1.0] [[XEP-0004#附录G:备注|5]](当这个协议被设计时才开始发展的)的复杂之间。在很多方面,'jabber:x:data' 与[http://www.w3.org/TR/xhtml1/ XHTML 1.0][[XEP-0004#附录G:备注|6]]的表单模块类似。但它提供一些Jabber特有的数据类型,允许应用程序请求数据字段,更自然地集成到IQ节的“workflow”语义中。而且它可以作为现有的Jabber/XMPP协议的扩展,而当这个协议被开发出来时,XHTML的表单模块却不能(尤其是当时并没有[http://www.w3.org/TR/2004/WD-xhtml-modularization-20040218/ Modularization of XHTML] [[XEP-0004#附录G:备注|7]])。<br />
<br />
==需求==<br />
<br />
本文档涉及下列需求:<br />
<br />
# '''数据收集''' -- 该协议应允许表单处理实体(通常是一个服务器,服务,或bot)从表单提交实体(通常是一个由用户控制的客户端)收集数据。应该是通过不同的数据字段来做,每个都可以是不同的数据“类型”,而且允许自由格式的输入或多个选项的选择(就像HTML表单一样)。<br />
# '''数据报告''' -- 该协议应允许表单处理的实体向表单提交的实体报告数据,再通过不同的数据字段。 <br />
# '''可移植性''' -- 协议应该尽量只定义普通数据格式和基本的数据类型。提示应该在相关的用户界面提供,但应该仅仅是提示,而不是严格的要求。 <br />
# '''简单''' -- 协议在客户端的实施应该简单,并且大多数复杂的工作(如,数据有效性和处理)应由服务器和组件去完成,而不是客户端。 <br />
# '''灵活性''' -- 协议应该具有灵活性和可扩展性,而不像“硬编码”。<br />
# '''兼容性''' -- 协议应该为已有的Jabber/XMPP协议定义一个扩展,而且不破坏已有的实现,除非绝对必要。<br />
<br />
==协议==<br />
<br />
'jabber:x:data' 命名空间的基本语法如下(正式的描述可以在下面的XML节中找到):<br />
<br />
<source lang="xml"><br />
<x xmlns='jabber:x:data' <br />
type='{form-type}'> <br />
<title/> <br />
<instructions/> <br />
<field var='field-name' <br />
type='{field-type}' <br />
label='description'> <br />
<desc/> <br />
<required/> <br />
<value>field-value</value> <br />
<option label='option-label'><value>option-value</value></option> <br />
<option label='option-label'><value>option-value</value></option> <br />
</field> <br />
</x> <br />
</source><br />
<br />
受'jabber:x:data' 命名空间限制的<x/>元素,应该包括直接作为<message/>节第一级子元素或作为<iq/> 节(其中第一级子元素是由一个"wrapper"命名空间限制的)的第二级子节。参见下文列举的限制。<br />
<br />
可选项<title/>和<instructions/>元素,允许表单处理实体把表单标记为一个整体并指定自然语言指令,后面跟着表单提交实体。这些元素的XML字符数据不应包含换行符(\n和\r字符),而任何换行符操作(如,在用户界面显示)在这里不是特指的。但<instructions/>元素的多个实体可以被包括在内。<br />
<br />
===表单类型===<br />
<br />
'jabber:x:data'表单中数据的收集或提供可以位于不同的上下文。例子包括一个需要填写的空表单,填好的表单,一个提交结果,一个搜索结果,或仅仅是用'jabber:x:data'命名空间封装的一组数据。完整的数据上下文由3个条件提供:<br />
<br />
# "wrapper"协议(即,以<iq/>节直接子元素为根元素的命名空间和受'jabber:x:data' 命名空间限制的<x/>元素的父元素)。<br />
# 一个包含事务(如,一个IQ "set"或"result")或会话结构(如,一个消息<thread/>)的表单的位置。<br />
# 表单中<x/>根元素的类型属性<br />
<br />
前面2件上下文信息有其他协议提供,而表单类型见下表描述。<br />
<br />
:'''表1:表单类型'''<br />
<br />
{|border="1" cellspacing="0" <br />
! 类型 !! 描述<br />
|-<br />
|表单 || 表单处理实体请求表单提交实体去完成表单。<br />
|-<br />
|提交 || 表单提交实体提交数据给表单处理实体。提交信息可以包含不是空表单提供的字段,但表单处理实体必须忽略任何无法识别的字段。<br />
|-<br />
|取消 || 表单提交实体取消给表单处理实体提交的数据。<br />
|-<br />
|结果 || 单处理实体返回数据(如查询结果)给表单提交实体,或数据是一个通用的数据集。<br />
|}<br />
<br />
<br />
<br />
<br />
为了维护表单类型中获取的数据的上下文,必须遵守以下规则:<br />
<br />
:* 对于<iq/>节,受"wrapper" 命名空间限制的根元素,以"form" 或"submit"的一种形式,必须以一种"result"形式的表单返回。受'jabber:x:data'命名空间限制的<x/>元素,必须是"wrapper"命名空间根元素的子元素。根据[http://tools.ietf.org/html/rfc3920 XMPP Core] [[XEP-0004#附录G:备注|8]]所定义, 'id' 属性必须在IQ结果中被复制。对于表单类型为"form" 或 "result",<iq/>节应该是"result"类型。对于表单类型为"submit" 或"cancel", <iq/>节应该是"set"类型。<br />
<br />
:* 对于<message/>节,如果提供的话,<thread/>应该在回复中被复制。受'jabber:x:data'命名空间限制的<x/>元素,必须是<message/>节的子元素。<br />
<br />
===字段元素===<br />
<br />
一个"form","submit",或 "result"类型的数据表单应该包含至少一个<field/>元素。一个"cancel"类型的表单,不应该包含任何<field/>元素。<br />
<br />
<br />
<field/>元素可以包含以下任何子元素:<br />
<br />
:'''<desc/>'''<br />
:该元素的XML字符数据提供了该字段一个自然语言的描述,为了在用户代理中介绍(如,作为一个"tool-tip",帮助按钮,或在字段附近的文本标记)。<desc/>元素不应包含换行符(\n和\r字符),因为布局负责用户代理,任何换行的处理(如,在用户界面演示)在这里是未指明的。(注意:提供一个字段的描述,使用<desc/>元素是被推荐的,而不是一个单独的"fixed"类型的<field/>元素。)<br />
<br />
:'''<required/>'''<br />
:该元素必须为空,标记所需的字段,为了被表单识别为有效字段。<br />
<br />
:'''<value/>'''<br />
:该元素的XML字符数据定义了在"form"类型数据表单中的字段(根据表单处理实体)的默认值,在"submit"类型数据表单中由表单提交实体提供的数据,或在"result"类型数据表单中的数据结果。在"form"类型数据表单中,如果表单处理实体通过<value/>元素提供了一个默认值,表单提交实体就不应该尝试去执行一个不同的默认值。<br />
<br />
:'''<option/>'''<br />
:在"list-single"或"list-multi"字段类型中的一个选项。<value/>子元素的XML字符定义了选项的值,而且标签属性为选项定义了一个人们易读的名称。<option/>元素必须且只能包含一个<value/>子元素。如果字段类型不是"list-single"或"list-multi",就一定不能包含<option/>元素。<br />
<br />
如果<field/>元素类型是其他的而不是“fixed”(见下文),它必须拥有一个'var'属性在表单中唯一标识字段(如果是“fixed”,可以拥有一个'var'属性)。<field/>元素可以拥有一个标签属性,为字段定义一个人们易读的名称。对于“form”类型的数据表单,每个<field/>元素应该拥有'type'属性,它定义了字段数据的数据 "type"(如果没有'type'被指定,则默认为"text-single")。在其他表单类型的上下文中提供的字段,也可以拥有一个'type'属性。对于"submit"类型的数据表单,'type'中包含的属性是可选的,因为表单处理实体被假定知道它处理的表单的数据类型。<br />
<br />
如果字段出现在用户页面上(如,问卷中的项或表单结果),在XML中的字段元素的顺序,应该决定出现在用户处的项目的顺序。<br />
<br />
===字段类型===<br />
以下字段类型代表Jabber/XMPP实体之间通用的数据类型。这些字段并打算像数据类型一样被广泛定义,如[http://www.w3.org/TR/xmlschema-2/ XML Schema Part 2] [[XEP-0004#附录G:备注|9]], 也没有定义用户界面元素。<br />
<br />
:'''表2:字段类型'''<br />
<br />
{|border="1" cellspacing="0" <br />
! 类型 !! 描述<br />
|-<br />
|布尔型 || 该字段允许一个实体收集或提供一个在两个选项中只能二选一的选择。默认值为"false"。[[XEP-0004#附录G:备注|10]]<br />
|-<br />
|固定 || 该字段是用于数据的描述(如,人们易读的"section"头信息)而不是数据的收集或提供。<value/>子元素不应该包含换行符(\n和\r字符);然而一个应用应该生成多个固定的字段,每个都包含<value/>子元素。<br />
|-<br />
|隐藏 || 该字段未展现给表单提交实体,但是和表单一起返回。表单提交实体不能修改隐藏字段的值,但如果这种行为被定义为是“使用协议”时可以这样做。<br />
|-<br />
|多jid || 该字段允许一个实体收集或提供多个Jabber ID。每个提供的JID应该是唯一的(比较确定的,包括Nodeprep的应用、Nameprep和Resourceprep profiles of Stringprep,按XMPP Core中说明的),而重复的JID一定会被忽略。*<br />
|-<br />
|单jid || 该字段允许一个实体收集或提供单个的Jabber ID。<br />
|-<br />
|多选项列表 || 该字段允许一个实体从很多选项中收集或提供一个或多个选项。表单提交实体从表单处理实体提交的选项中选择一个或多个项,而且不能插入新的选项。表单处理实体不能修改从表单处理实体处获取的项目的顺序,因为项目的顺序可能很重要。**<br />
|-<br />
|单选项列表|| 该字段允许一个实体从很多选项中收集或提供一个选项。表单提交实体从表单处理实体提交的选项中选择一个项,而且不能插入新的选项。**<br />
|-<br />
|多文本|| 该字段允许一个实体收集或提供多行的文本。***<br />
|-<br />
|私有文本|| 该字段允许一个实体收集或提供一行或一个词的文本,其应该在界面上遮蔽。(如,星号显示的多个实体)<br />
|-<br />
|单文本|| 该字段允许一个实体收集或提供一行或一个词的文本,其应该在界面上显示。这个字段类型是缺省的而且必须假定,当一个表单提交实体收到一个不知道的字段类型时。<br />
|}<br />
<br />
<br />
注意:为字段类型"jid-single"或"jid-multi"提供的数据必须包含一个或一个以上的有效Jabber ID,有效性是由XMPP Core(参看后面章节的Data Validation)定义的寻址规则决定的。<br />
<br />
注意:在list-multi和list-single中的<option/>元素必须是唯一的,唯一性是由‘label’属性的值和<value/>元素中的XML字符数据决定的。(即,2个都必须是唯一的)<br />
<br />
注意:为字段类型"text-multi"提供的数据不应该包含任何换行符(\n和\r字符)。而应用程序应该把数据分为多个字符串(基于平台插入的换行符),然后用不同的<value/>元素中的XML字符数据指定每一个字符串。同样的,以"text-multi"字段类型接收了多个<value/>元素的应用程序,应该把value元素中的XML字符数据合并成一个文本块以提交给用户。每一个字符串为平台适时的通过换行符分开。<br />
<br />
===表单结果中的多个项目===<br />
在某些情况下(如,查询请求的结果),传达多个项目是必须的。因此,一个"result"类型的数据表单可能包含2个上面基本语法没有描述的子元素:<br />
<br />
#只有一个<reported/>元素,可以理解为一个“表头”描述数据去遵循。 <br />
#零个或更多<item/>元素,可以理解为包含符合请求的数据(如果有的话)的"table cells"。 <br />
<br />
其语法如下:<br />
<br />
<source lang="xml"><br />
<x xmlns='jabber:x:data' <br />
type='result'> <br />
<reported> <br />
<field var='field-name' label='description' type='{field-type}'/> <br />
</reported> <br />
<item> <br />
<field var='field-name'> <br />
<value>field-value</value> <br />
</field> <br />
</item> <br />
<item> <br />
<field var='field-name'> <br />
<value>field-value</value> <br />
</field> <br />
</item> <br />
. <br />
. <br />
. <br />
</x> <br />
</source><br />
<br />
这些元素每个都必须包含一个或多个<field/>子元素。<reported/>元素为结果项定义数据格式,通过为每个项目指定所期望的字段。为此,除了'var'属性,<field/>元素还应该有'type'属性'label'属性;而且不能包含<value/>元素。在结果集中,每个<item/>元素定义一个项目,而且必须包含在<reported/>元素(虽然<value/>元素中的XML字符数据可能为空)中指定的字段。<br />
<br />
==数据有效性==<br />
<br />
数据有效性是表单处理实体(通常是一个服务器,服务,或bot)的责任,而不是表单提交实体(通常是一个由用户控制的客户端)。这有助于满足保持客户端实现简单的要求。如果表单处理实体确定提供的数据是无效的,它应该返回一个“不接受”的错误。选择在XMPP <text/>元素中提供文字说明,或识别问题的特殊应用子元素(参考[http://xmpp.org/extensions/xep-0086.html Error Condition Mappings] [[XEP-0004#附录G:备注|11]]中的映射和格式)。<br />
<br />
==例子==<br />
<br />
对于下面的例子,我们假设存在一个bot hosting服务在Jabber network上,位于<botster.shakespeare.lit>。这个服务允许注册用户创建和配置新的bots,对已经存在的bots查找和交互,等等。我们假定这些交互的发生使用的Ad-Hoc Commands [12]协议,协议被用作表单的"wrapper"协议,受'jabber:x:data'命名空间限制。下面章节中的例子,体现了前文中描述的数据表单协议的大部分特性。<br />
<br />
注意:额外的例子可以通过各种“使用协议”的说明书中找到。如XEP-0045:Multi-User Chat和XEP-0055:Jabber Search。<br />
<br />
===配置===<br />
<br />
:第一步是为用户在主机上创建一个新的bot。我们假设这是通过发送一个“创建”命令给期望的bot来实现的:<br />
<br />
:'''例1.用户请求Bot创建'''<br />
<br />
<source lang="xml"><br />
<iq from='romeo@montague.net/home' <br />
to='joogle@botster.shakespeare.lit' <br />
type='get' <br />
xml:lang='en' <br />
id='create1'> <br />
<command xmlns='http://jabber.org/protocol/commands' <br />
node='create' <br />
action='execute'/> <br />
</iq> <br />
</source><br />
<br />
:然后主服务返回一个数据表单个用户:<br />
<br />
:'''例2.服务返回一个Bot创建表单'''<br />
<br />
<source lang="xml"><br />
<iq from='joogle@botster.shakespeare.lit' <br />
to='romeo@montague.net/home' <br />
type='result' <br />
xml:lang='en' <br />
id='create1'> <br />
<command xmlns='http://jabber.org/protocol/commands' <br />
node='create' <br />
sessionid='create:20040408T0128Z' <br />
status='executing'> <br />
<x xmlns='jabber:x:data' type='form'> <br />
<title>Bot Configuration</title> <br />
<instructions>Fill out this form to configure your new bot!</instructions> <br />
<field type='hidden' <br />
var='FORM_TYPE'> <br />
<value>jabber:bot</value> <br />
</field> <br />
<field type='fixed'><value>Section 1: Bot Info</value></field> <br />
<field type='text-single' <br />
label='The name of your bot' <br />
var='botname'/> <br />
<field type='text-multi' <br />
label='Helpful description of your bot' <br />
var='description'/> <br />
<field type='boolean' <br />
label='Public bot?' <br />
var='public'> <br />
<required/> <br />
</field> <br />
<field type='text-private' <br />
label='Password for special access' <br />
var='password'/> <br />
<field type='fixed'><value>Section 2: Features</value></field> <br />
<field type='list-multi' <br />
label='What features will the bot support?' <br />
var='features'> <br />
<option label='Contests'><value>contests</value></option> <br />
<option label='News'><value>news</value></option> <br />
<option label='Polls'><value>polls</value></option> <br />
<option label='Reminders'><value>reminders</value></option> <br />
<option label='Search'><value>search</value></option> <br />
<value>news</value> <br />
<value>search</value> <br />
</field> <br />
<field type='fixed'><value>Section 3: Subscriber List</value></field> <br />
<field type='list-single' <br />
label='Maximum number of subscribers' <br />
var='maxsubs'> <br />
<value>20</value> <br />
<option label='10'><value>10</value></option> <br />
<option label='20'><value>20</value></option> <br />
<option label='30'><value>30</value></option> <br />
<option label='50'><value>50</value></option> <br />
<option label='100'><value>100</value></option> <br />
<option label='None'><value>none</value></option> <br />
</field> <br />
<field type='fixed'><value>Section 4: Invitations</value></field> <br />
<field type='jid-multi' <br />
label='People to invite' <br />
var='invitelist'> <br />
<desc>Tell all your friends about your new bot!</desc> <br />
</field> <br />
</x> <br />
</command> <br />
</iq> <br />
</source><br />
<br />
:然后用户提交配置表单:<br />
<br />
:'''例3.用户提交bot创建表单'''<br />
<br />
<source lang="xml"><br />
<iq from='romeo@montague.net/home' <br />
to='joogle@botster.shakespeare.lit' <br />
type='set' <br />
xml:lang='en' <br />
id='create2'> <br />
<command xmlns='http://jabber.org/protocol/commands' <br />
node='create' <br />
sessionid='create:20040408T0128Z'> <br />
<x xmlns='jabber:x:data' type='submit'> <br />
<field type='hidden' var='FORM_TYPE'> <br />
<value>jabber:bot</value> <br />
</field> <br />
<field type='text-single' var='botname'> <br />
<value>The Jabber Google Bot</value> <br />
</field> <br />
<field type='text-multi' var='description'> <br />
<value>This bot enables you to send requests to</value> <br />
<value>Google and receive the search results right</value> <br />
<value>in your Jabber client. It&apos; really cool!</value> <br />
<value>It even supports Google News!</value> <br />
</field> <br />
<field type='boolean' var='public'> <br />
<value>0</value> <br />
</field> <br />
<field type='text-private' var='password'> <br />
<value>v3r0na</value> <br />
</field> <br />
<field type='list-multi' var='features'> <br />
<value>news</value> <br />
<value>search</value> <br />
</field> <br />
<field type='list-single' var='maxsubs'> <br />
<value>50</value> <br />
</field> <br />
<field type='jid-multi' var='invitelist'> <br />
<value>juliet@capulet.com</value> <br />
<value>benvolio@montague.net</value> <br />
</field> <br />
</x> <br />
</command> <br />
</iq> <br />
</source><br />
<br />
:然后服务返回结果给用户:<br />
<br />
:'''例4.服务返回bot创建的结果'''<br />
<br />
<source lang="xml"><br />
<iq from='joogle@botster.shakespeare.lit' <br />
to='romeo@montague.net/home' <br />
type='result' <br />
xml:lang='en' <br />
id='create2'> <br />
<command xmlns='http://jabber.org/protocol/commands' <br />
node='create' <br />
sessionid='create:20040408T0128Z' <br />
status='completed'> <br />
<x xmlns='jabber:x:data' type='result'> <br />
<field type='hidden' var='FORM_TYPE'> <br />
<value>jabber:bot</value> <br />
</field> <br />
<field type='text-single' var='botname'> <br />
<value>The Jabber Google Bot</value> <br />
</field> <br />
<field type='boolean' var='public'> <br />
<value>0</value> <br />
</field> <br />
<field type='text-private' var='password'> <br />
<value>v3r0na</value> <br />
</field> <br />
<field type='list-multi' var='features'> <br />
<value>news</value> <br />
<value>search</value> <br />
</field> <br />
<field type='list-single' var='maxsubs'> <br />
<value>50</value> <br />
</field> <br />
<field type='jid-multi' var='invitelist'> <br />
<value>juliet@capulet.com</value> <br />
<value>benvolio@montague.net</value> <br />
</field> <br />
</x> <br />
</command> <br />
</iq><br />
</source><br />
<br />
===搜索===<br />
<br />
既然用户已经创建了这个搜索bot,我们假设他所邀请的好友中的一个,决定通过发送一个搜索请求来试一试:<br />
<br />
:'''例5.用户请求搜索表单'''<br />
<br />
<source lang="xml"><br />
<iq from='juliet@capulet.com/chamber' <br />
to='joogle@botster.shakespeare.lit' <br />
type='get' <br />
xml:lang='en' <br />
id='search1'> <br />
<command xmlns='http://jabber.org/protocol/commands' <br />
node='search' <br />
action='execute'/> <br />
</iq> <br />
</source><br />
<br />
:'''例6.服务返回搜索表单'''<br />
<br />
<source lang="xml"><br />
<iq from='joogle@botster.shakespeare.lit' <br />
to='juliet@capulet.com/chamber' <br />
type='result' <br />
xml:lang='en' <br />
id='search1'> <br />
<command xmlns='http://jabber.org/protocol/commands' <br />
node='search' <br />
status='executing'> <br />
<x xmlns='jabber:x:data' type='form'> <br />
<title>Joogle Search</title> <br />
<instructions>Fill out this form to search for information!</instructions> <br />
<field type='text-single' <br />
var='search_request'> <br />
<required/> <br />
</field> <br />
</x> <br />
</command> <br />
</iq> <br />
</source><br />
<br />
:'''例7.用户提交搜索表单'''<br />
<br />
<source lang="xml"><br />
<iq from='juliet@capulet.com/chamber' <br />
to='joogle@botster.shakespeare.lit' <br />
type='get' <br />
xml:lang='en' <br />
id='search2'> <br />
<command xmlns='http://jabber.org/protocol/commands' <br />
node='search'> <br />
<x xmlns='jabber:x:data' type='submit'> <br />
<field type='text-single' var='search_request'> <br />
<value>verona</value> <br />
</field> <br />
</x> <br />
</command> <br />
</iq> <br />
</source><br />
<br />
:'''例8.服务返回搜索结果'''<br />
<br />
<source lang="xml"><br />
<iq from='joogle@botster.shakespeare.lit' <br />
to='juliet@capulet.com/chamber' <br />
type='result' <br />
xml:lang='en' <br />
id='search2'> <br />
<command xmlns='http://jabber.org/protocol/commands' <br />
node='search' <br />
status='completed'> <br />
<x xmlns='jabber:x:data' type='result'> <br />
<title>Joogle Search: verona</title> <br />
<reported> <br />
<field var='name'/> <br />
<field var='url'/> <br />
</reported> <br />
<item> <br />
<field var='name'> <br />
<value>Comune di Verona - Benvenuti nel sito ufficiale</value> <br />
</field> <br />
<field var='url'> <br />
<value>http://www.comune.verona.it/</value> <br />
</field> <br />
</item> <br />
<item> <br />
<field var='name'> <br />
<value>benvenuto!</value> <br />
</field> <br />
<field var='url'> <br />
<value>http://www.hellasverona.it/</value> <br />
</field> <br />
</item> <br />
<item> <br />
<field var='name'> <br />
<value>Universita degli Studi di Verona - Home Page</value> <br />
</field> <br />
<field var='url'> <br />
<value>http://www.univr.it/</value> <br />
</field> <br />
</item> <br />
<item> <br />
<field var='name'> <br />
<value>Aeroporti del Garda</value> <br />
</field> <br />
<field var='url'> <br />
<value>http://www.aeroportoverona.it/</value> <br />
</field> <br />
</item> <br />
<item> <br />
<field var='name'> <br />
<value>Veronafiere - fiera di Verona</value> <br />
</field> <br />
<field var='url'> <br />
<value>http://www.veronafiere.it/</value> <br />
</field> <br />
</item> <br />
</x> <br />
</command> <br />
</iq><br />
</source><br />
<br />
==服务发现==<br />
<br />
如果一个实体支持包含受'jabber:x:data'命名空间限制的<x/>元素作为<message/>节直接子元素,它必须报告支持包含一个"jabber:x:data"(参看Protocol Namespaces中关于一个或多个永久命名空间的发行)的服务搜索特征,去响应服务搜索信息请求:<br />
<br />
:'''例9.服务搜索信息请求'''<br />
<br />
<source lang="xml"><br />
<iq type='get' <br />
from='romeo@montague.net/orchard' <br />
to='juliet@capulet.com/balcony' <br />
id='disco1'> <br />
<query xmlns='http://jabber.org/protocol/disco#info'/> <br />
</iq> <br />
</source><br />
<br />
:'''例10.服务搜索信息响应'''<br />
<br />
<source lang="xml"><br />
<iq type='result' <br />
from='juliet@capulet.com/balcony' <br />
to='romeo@montague.net/orchard' <br />
id='disco1'> <br />
<query xmlns='http://jabber.org/protocol/disco#info'> <br />
... <br />
<feature var='jabber:x:data'/> <br />
... <br />
</query> <br />
</iq> <br />
</source><br />
<br />
如果实体支持数据表单,间接的通过在wrapper命名空间中包含数据表单,它不能为'jabber:x:data'命名空间通知支持,因为在wrapper协助中的支持是隐性的。<br />
<br />
==安全性考虑==<br />
<br />
没有安全问题与上述的规范和XMPP Core中相关章节的描述有关。<br />
<br />
==IANA考虑==<br />
<br />
这份文档与[http://www.iana.org/ Internet Assigned Numbers Authority (IANA)] [[XEP-0004#附录G:备注|13]]无关。<br />
<br />
==XMPP注册考虑==<br />
<br />
===协议命名空间===<br />
<br />
[http://xmpp.org/registrar/ XMPP Registrar] [[XEP-0004#附录G:备注|14]]在它注册的协议命名空间中包含'jabber:x:data'命名空间。<br />
<br />
===参数值===<br />
<br />
XMPP注册员维持着一个与'jabber:x:data'命名空间相关的注册参数值。具体定义在[http://xmpp.org/extensions/xep-0068.html Field Standardization for Data Forms] [[XEP-0004#附录G:备注|15]]。注册的地方是<http://xmpp.org/registrar/formtypes.html>。<br />
<br />
==XML 架构==<br />
<br />
该架构是描述性的,不是规范的。<br />
<br />
<source lang="xml"><br />
<?xml version='1.0' encoding='UTF-8'?> <br />
<br />
<xs:schema <br />
xmlns:xs='http://www.w3.org/2001/XMLSchema' <br />
targetNamespace='jabber:x:data' <br />
xmlns='jabber:x:data' <br />
elementFormDefault='qualified'> <br />
<br />
<xs:annotation> <br />
<xs:documentation> <br />
The protocol documented by this schema is defined in <br />
XEP-0004: http://www.xmpp.org/extensions/xep-0004.html <br />
</xs:documentation> <br />
</xs:annotation> <br />
<br />
<xs:element name='x'> <br />
<xs:complexType> <br />
<xs:sequence> <br />
<xs:element name='instructions' <br />
minOccurs='0' <br />
maxOccurs='unbounded' <br />
type='xs:string'/> <br />
<xs:element name='title' minOccurs='0' type='xs:string'/> <br />
<xs:element ref='field' minOccurs='0' maxOccurs='unbounded'/> <br />
<xs:element ref='reported' minOccurs='0' maxOccurs='1'/> <br />
<xs:element ref='item' minOccurs='0' maxOccurs='unbounded'/> <br />
</xs:sequence> <br />
<xs:attribute name='type' use='required'> <br />
<xs:simpleType> <br />
<xs:restriction base='xs:NCName'> <br />
<xs:enumeration value='cancel'/> <br />
<xs:enumeration value='form'/> <br />
<xs:enumeration value='result'/> <br />
<xs:enumeration value='submit'/> <br />
</xs:restriction> <br />
</xs:simpleType> <br />
</xs:attribute> <br />
</xs:complexType> <br />
</xs:element> <br />
<br />
<xs:element name='field'> <br />
<xs:complexType> <br />
<xs:sequence> <br />
<xs:element name='desc' minOccurs='0' type='xs:string'/> <br />
<xs:element name='required' minOccurs='0' type='empty'/> <br />
<xs:element ref='value' minOccurs='0' maxOccurs='unbounded'/> <br />
<xs:element ref='option' minOccurs='0' maxOccurs='unbounded'/> <br />
</xs:sequence> <br />
<xs:attribute name='label' type='xs:string' use='optional'/> <br />
<xs:attribute name='type' use='optional'> <br />
<xs:simpleType> <br />
<xs:restriction base='xs:NCName'> <br />
<xs:enumeration value='boolean'/> <br />
<xs:enumeration value='fixed'/> <br />
<xs:enumeration value='hidden'/> <br />
<xs:enumeration value='jid-multi'/> <br />
<xs:enumeration value='jid-single'/> <br />
<xs:enumeration value='list-multi'/> <br />
<xs:enumeration value='list-single'/> <br />
<xs:enumeration value='text-multi'/> <br />
<xs:enumeration value='text-private'/> <br />
<xs:enumeration value='text-single'/> <br />
</xs:restriction> <br />
</xs:simpleType> <br />
</xs:attribute> <br />
<xs:attribute name='var' type='xs:string' use='optional'/> <br />
</xs:complexType> <br />
</xs:element> <br />
<br />
<xs:element name='option'> <br />
<xs:complexType> <br />
<xs:sequence> <br />
<xs:element ref='value'/> <br />
</xs:sequence> <br />
<xs:attribute name='label' type='xs:string' use='optional'/> <br />
</xs:complexType> <br />
</xs:element> <br />
<br />
<xs:element name='value' type='xs:string'/> <br />
<br />
<xs:element name='reported'> <br />
<xs:annotation> <br />
<xs:documentation> <br />
When contained in a "reported" element, the "field" element <br />
SHOULD NOT contain a "value" child. <br />
</xs:documentation> <br />
</xs:annotation> <br />
<xs:complexType> <br />
<xs:sequence> <br />
<xs:element ref='field' maxOccurs='unbounded'/> <br />
</xs:sequence> <br />
</xs:complexType> <br />
</xs:element> <br />
<br />
<xs:element name='item'> <br />
<xs:complexType> <br />
<xs:sequence> <br />
<xs:element ref='field' maxOccurs='unbounded'/> <br />
</xs:sequence> <br />
</xs:complexType> <br />
</xs:element> <br />
<br />
<xs:simpleType name='empty'> <br />
<xs:restriction base='xs:string'> <br />
<xs:enumeration value=''/> <br />
</xs:restriction> <br />
</xs:simpleType> <br />
<br />
</xs:schema> <br />
</source><br />
<br />
==最终状态的修改==<br />
<br />
当本规范已经是最终状态时,下面的实体协议已经做了修改:<br />
<br />
* 指定的'var'属性是所有字段类型所必须的,除了"fixed", 因为'var'属性是可选的。<br />
<br />
* 通过服务搜索指定何时去通知支持。<br />
<br />
* 移除引用<presence/>节。<br />
<br />
==草稿状态的修改==<br />
<br />
当本规范在草稿状态时,下面的实体协议已经做了修改:<br />
<br />
* <x/>元素可能直接包含在<message/>和<presence/>节中。<br />
* <x/>元素可能包含一个<title/>子元素,在表单或结果中。<br />
* <x/>元素必须拥有一个‘类型’属性。<br />
* <field/>元素可能是类型='jid-single'。<br />
* 结果可能以<item/>标签的方式返回报告。<br />
* 结果可能包含一个<reported/>元素的结果集。<br />
* <reported/>字段可能拥有一个‘类型’属性,提供如何与数据交互的提示(类型='jid-single'是最有用的)。<br />
<br />
==附录==<br />
===附录A:文档信息===<br />
<br />
系列:[http://xmpp.org/extensions/ XEP]<br />
<br />
序号:0004<br />
<br />
发布者:[http://xmpp.org/xsf/ XMPP标准基金会]<br />
<br />
状态:[http://www.xmpp.org/extensions/xep-0001.html#states-Final 终结版]<br />
<br />
类型:[http://www.xmpp.org/extensions/xep-0001.html#types-Standards%20Track 标准跟踪]<br />
<br />
版本:2.9<br />
<br />
最后更新:2007-07-13<br />
<br />
批准机构:[http://xmpp.org/council/ XMPP理事会]<br />
<br />
依赖标准:[[RFC3920|XMPP Core]]<br />
<br />
替代标准:无<br />
<br />
被替代标准:无<br />
<br />
缩略名:x-data<br />
<br />
XML架构:<http://www.xmpp.org/schemas/x-data.xsd><br />
<br />
原文控制: [http://svn.xmpp.org:18080/browse/XMPP/trunk/extensions/xep-0004.xml HTML] [http://svn.xmpp.org:18080//changelog/~rss/XMPP/trunk/extensions/xep-0004.xml/rss.xml RSS]<br />
<br />
本文的其它格式: [http://xmpp.org/extensions/xep-0004.xml XML] [http://xmpp.org/extensions/xep-0004.pdf PDF]<br />
<br />
<br />
===附录B:作者信息===<br />
<br />
'''Ryan Eatmon'''<br />
<br />
Email: [mailto:reatmon@jabber.org reatmon@jabber.org]<br />
<br />
JabberID: reatmon@jabber.org<br />
<br />
<br />
'''Joe Hildebrand'''<br />
<br />
Email: [mailto:jhildebr@cisco.com jhildebr@cisco.com]<br />
<br />
JabberID: hildjj@jabber.org<br />
<br />
<br />
'''Jeremie Miller'''<br />
<br />
Email: [mailto:jer@jabber.org jer@jabber.org]<br />
<br />
JabberID: jer@jabber.org<br />
<br />
<br />
'''Thomas Muldowney'''<br />
<br />
Email: [mailto:temas@jabber.org temas@jabber.org]<br />
<br />
JabberID: temas@jabber.org<br />
<br />
<br />
'''Peter Saint-Andre'''<br />
<br />
Email: [mailto:stpeter@jabber.org stpeter@jabber.org]<br />
<br />
JabberID: stpeter@jabber.org<br />
<br />
URI: https://stpeter.im/<br />
<br />
{{Template:XEP附录CDEF}}<br />
<br />
===附录G:备注===<br />
#XEP-0077: In-Band Registration <http://xmpp.org/extensions/xep-0077.html>.<br />
#XEP-0055: Jabber Search <http://xmpp.org/extensions/xep-0055.html>.<br />
#XEP-0045: Multi-User Chat <http://xmpp.org/extensions/xep-0045.html>.<br />
#XEP-0030: Service Discovery <http://xmpp.org/extensions/xep-0030.html>.<br />
#XForms 1.0 <http://www.w3.org/TR/xforms>.<br />
#XHTML 1.0 <http://www.w3.org/TR/xhtml1>.<br />
#Modularization of XHTML <http://www.w3.org/TR/2004/WD-xhtml-modularization-20040218/>.<br />
#RFC 3920: Extensible Messaging and Presence Protocol (XMPP): Core <http://tools.ietf.org/html/rfc3920>.<br />
#XML Schema Part 2: Datatypes <http://www.w3.org/TR/xmlschema-2/>.<br />
#In accordance with Section 3.2.2.1 of XML Schema Part 2: Datatypes, the allowable lexical representations for the xs:boolean datatype are the strings "0" and "false" for the concept 'false' and the strings "1" and "true" for the concept 'true'; implementations MUST support both styles of lexical representation.<br />
#XEP-0086: Error Condition Mappings <http://xmpp.org/extensions/xep-0086.html>.<br />
#XEP-0050: Ad-Hoc Commands <http://xmpp.org/extensions/xep-0050.html>.<br />
#The Internet Assigned Numbers Authority (IANA) is the central coordinator for the assignment of unique parameter values for Internet protocols, such as port numbers and URI schemes. For further information, see <http://www.iana.org/>.<br />
#The XMPP Registrar maintains a list of reserved protocol namespaces as well as registries of parameters used in the context of XMPP extension protocols approved by the XMPP Standards Foundation. For further information, see <http://xmpp.org/registrar/>.<br />
#XEP-0068: Field Data Standardization for Data Forms <http://xmpp.org/extensions/xep-0068.html>.<br />
<br />
===附录H:修订历史===<br />
<br />
注意: <br />
<br />
'''版本 2.9 (2007-08-13)'''<br />
<br />
Clarified the definition and handling of the list-multi and list-single field types; specified that hidden field values should not be modified unless such behavior is defined for the using protocol; specified that a submission should include all fields provided in the empty form and may include additional fields, but that additional fields must be ignored if not understood by the form-processing entity.<br />
<br />
(psa)<br />
<br />
'''版本 2.8 (2007-05-21)'''<br />
<br />
Removed mentions of presence stanzas; added section on discovering support; added section on substantive changes in Final state.<br />
<br />
(psa)<br />
<br />
'''版本 2.7 (2006-01-25)'''<br />
<br />
Incorporated errata: (1) clarified rules regarding inclusion of option and value elements depending on field type; (2) clarified handling of default values; (3) added value elements to list-multi field in Example 2; (4) harmonized spelling of form-processing entity and form-submitting entity.<br />
<br />
(psa)<br />
<br />
Version 2.6 (2004-10-13)<br />
Incorporated errata: (1) corrected syntax of <reported/> element (<field/> element should not contain a <value/> child); (2) corrected Example 8.<br />
<br />
(psa) <br />
Version 2.5 (2004-05-07)<br />
Clarified terminology regarding form-processing entities and form-submitting entities; corrected several small errors in the schema.<br />
<br />
(psa) <br />
Version 2.4 (2004-05-04)<br />
Per discussion by the authors and Jabber Council, specified that the 'var' attribute is required for all field types except "fixed", for which the 'var' attribute is optional.<br />
<br />
(psa) <br />
Version 2.3 (2004-03-31)<br />
Formalization and further editorial revisions.<br />
<br />
(psa) <br />
Version 2.2 (2004-01-22)<br />
Editorial revisions.<br />
<br />
(psa) <br />
Version 2.1 (2003-02-16)<br />
Added schema.<br />
<br />
(psa) <br />
Version 2.0 (2002-12-09)<br />
Per a vote of the Jabber Council, changed status to Final.<br />
<br />
(psa) <br />
Version 1.1 (2002-10-15)<br />
Call for Experience changes (see Changes in Draft State section). This version voted to Final on 2002-12-09.<br />
<br />
(rwe) <br />
Version 1.0 (2002-04-24)<br />
Per a vote of the Jabber Council, changed status to Draft.<br />
<br />
(psa) <br />
Version 0.6 (2002-03-15)<br />
Protocol tweaks based on Standards list discussion.<br />
<br />
(rwe) <br />
Version 0.5 (2002-02-06)<br />
Protocol tweaks based on implementation and discussion.<br />
<br />
(rwe) <br />
Version 0.4 (2001-11-16)<br />
Major redesign to attempt to clarify the scope of this document and limit what it is trying to solve.<br />
<br />
(rwe) <br />
Version 0.3 (2001-07-23)<br />
Protocol update<br />
<br />
(rwe) <br />
Version 0.2 (2001-06-29)<br />
Protocol update and DocBook version<br />
<br />
(rwe) <br />
Version 0.1 (2001-01-25)<br />
Initial release<br />
<br />
(rwe)</div>
Snowqiang
http://wiki.jabbercn.org/XEP-0128
XEP-0128
2011-05-18T12:31:19Z
<p>Snowqiang: </p>
<hr />
<div>[[Category:XMPP扩展]]<br />
[[Category:已翻译]]<br />
<br />
'''本文的英文原文来自[http://xmpp.org/extensions/xep-0128.html XEP-0128]'''<br />
<br />
'''XEP-0128: 发现服务扩展'''<br />
<br />
摘要: 这个文件规定了发现服务的扩展信息的最佳做法。<br />
<br />
作者: Peter Saint-Andre <br />
<br />
版权: © 1999 - 2010 XMPP标准化基金会(XSF). 参见[[XEP-0030#附录C:法律通告|法律通告]].<br />
<br />
现状: 活跃 <br />
<br />
类型: 信息 <br />
<br />
版本: 1.0 <br />
<br />
最后更新: 2004-10-20 <br />
<br />
<br />
注意:注意:此信息规范定义了一个最佳实践或协议配置文件已被批准的XMPP理事会和/或董事XSF局。实现是鼓励和最佳做法或协议配置文件是在生产系统中部署适当的。<br />
<br />
<br />
==简介==<br />
开发人员觉得[http://xmpp.org/extensions/xep-0030.html 发现服务]不能包含更多的信息. 例如, <identity/> 元素不包含'description'属性, 我们可以增加这个属性吗? 答案是可以,但现在不行,太迟了(因为XEP-0030是最终版). 因此,最好的办法是制定一个扩充机制.<br />
<br />
让我们参考一个示例. 一个[http://xmpp.org/extensions/xep-0045.html 多用户聊天室][http://xmpp.org/extensions/xep-0128.html#nt-id92624[2]] 可能想要获取更多的信息, 包括房间描述信息,房间主题,房间在线人数和房间所有者的JID.<br />
<br />
增加一个新属性的服务发现架构(即使真的是一个选项)不能解决的问题,因为一MUC的服务可能需要提供某些信息,而发布,[http://xmpp.org/extensions/xep-0060.html 订阅] [http://xmpp.org/extensions/xep-0128.html#nt-id92653[3]]服务可能需要提供其信息。 <br />
<br />
一个更好的解决办法是通过一个扩展的信息包括命名空间,提供了一种灵活的结构化数据格式定义合格。 谢天谢地,我们已经拥有了这样一个协议: [http://xmpp.org/extensions/xep-0004.html 数据表格] [http://xmpp.org/extensions/xep-0128.html#nt-id92681[4]]。 此外,我们拥有一个共同的方式来定义字段形式用于数据: [http://xmpp.org/extensions/xep-0068.html 数据表格现场标准化] [http://xmpp.org/extensions/xep-0128.html#nt-id92702 [5]]。 使用这些构建模块,我们可以定义为扩展服务发现结果的一些最佳做法。<br />
<br />
==建议==<br />
如果一个实体的希望提供服务发现协议的扩展信息,出现在回复信息内,它应该这样做:每个独立的<field/>元素包含<value/>点数据信息子节点,所有<field/>元素包含在一个类型为"result"命名空间值为'jabber:x:data'的<x/>元素里.<br />
<br />
<source lang="xml"><br />
<iq type="result"><br />
<query xmlns="http://jabber.org/protocol/disco#info"> <br />
...<br />
<x type='result' xmlns='jabber:x:data'><br />
<field var='[var-name]' label='[optional]'><br />
<value>[var-value]</value><br />
</field><br />
...<br />
</x><br />
</query><br />
</iq><br />
</source><br />
<br />
如果数据字段被用来在由XMPP标准基金会核准的议定书时,他们应该符合相关的XMPP扩展协议规范并按照XEP - 0068定义的规则注册,返回信息中包含一个<field/>元素,其'var'属性为"FORM_TYPE",其'type'属性的值为"hidden"。<br />
<br />
一个实体不能提供'http://jabber.org/protocol/disco#items' 命名空间相关子信息,因为服务发现的核心原则是:一个实体必须确定其身份,不界定的身份与子节点的实体.<br />
<br />
==示例==<br />
===IM服务器===<br />
<br />
以下是即时消息服务器返回一个标准的服务查询的例子.<br />
<br />
'''例1. 实体查询信息服务器'''<br />
<br />
<source lang="xml"><br />
<iq type='get' <br />
from='capulet.com' <br />
to='shakespeare.lit' <br />
id='disco1'> <br />
<query xmlns='http://jabber.org/protocol/disco#info'/><br />
</iq> <br />
<br />
<iq type='result' from='shakespeare.lit' <br />
to='capulet.com' <br />
id='disco1'> <br />
<query xmlns='http://jabber.org/protocol/disco#info'> <br />
<identity <br />
category='server' <br />
type='im' <br />
name='shakespeare.lit jabber server'/> <br />
<feature var='jabber:iq:register'/> <br />
<x xmlns='jabber:x:data' type='result'> <br />
<field var='FORM_TYPE' type='hidden'> <br />
<value>http://jabber.org/network/serverinfo</value> <br />
</field> <br />
<field var='c2s_port'> <br />
<value>5222</value> <br />
</field> <br />
<field var='c2s_port_ssl'> <br />
<value>5223</value> <br />
</field> <br />
<field var='http_access'> <br />
<value>http://shakespeare.lit/jabber</value> <br />
</field> <br />
<field var='ip_version'> <br />
<value>ipv4</value> <br />
<value>ipv6</value> <br />
</field> <br />
<field var='info_url'> <br />
<value>http://shakespeare.lit/support.php</value> <br />
</field> <br />
</x> <br />
</query> <br />
</iq><br />
</source><br />
<br />
===群===<br />
<br />
下面是在多用户房间里查询服务的例子.<br />
<br />
'''例2. 用户查询房间信息'''<br />
<br />
<source lang="xml"><br />
<iq type='get' <br />
from='hag66@shakespeare.lit/pda' <br />
to='darkcave@macbeth.shakespeare.lit' <br />
id='disco1'> <br />
<query xmlns='http://jabber.org/protocol/disco#info'/> <br />
</iq> <br />
<br />
<iq type='result' <br />
from='darkcave@macbeth.shakespeare.lit' <br />
to='hag66@shakespeare.lit/pda' <br />
id='disco1'> <br />
<query xmlns='http://jabber.org/protocol/disco#info'> <br />
<identity <br />
category='conference' <br />
type='text' <br />
name='A Dark Cave'/> <br />
<feature var='http://jabber.org/protocol/muc'/> <br />
<feature var='jabber:iq:register'/> <br />
<x xmlns='jabber:x:data' type='result'> <br />
<field var='FORM_TYPE' type='hidden'> <br />
<value>http://jabber.org/protocol/muc#roominfo</value> <br />
</field> <br />
<field var='muc#roominfo_description' label='Description'> <br />
<value>The place for all good witches!</value> <br />
</field> <br />
<field var='muc#roominfo_subject' label='Subject'> <br />
<value>Spells</value> <br />
</field> <br />
<field var='muc#roominfo_occupants' label='Number of occupants'> <br />
<value>3</value> <br />
</field> <br />
<field var='muc#roominfo_lang' label='Language of discussion'> <br />
<value>en</value> <br />
</field> <br />
</x> <br />
</query> <br />
</iq><br />
</source><br />
<br />
==实现说明==<br />
<br />
一般来说,XMPP标准基金会给每一个发现服务在注册登记时指定一个FORM_TYPE.此外,特定的应用可以定义应用程序以及具体FORM_TYPEs,一个实体可以有多个服务发现的身份(例如,一个XMPP服务器也可能作为一个发布,订阅服务)。因此,它是可能的(允许一个单一的服务发现的结果,发现含有多种服务扩展元素(可能高达2为每个标识元素))。然而,在实践中是不可能发现任何特定服务的结果将包含多个服务扩展元素的发现。<br />
<br />
==安全注意事项==<br />
<br />
应用程序应确网络上任何实体都能发现服务扩展信息.<br />
<br />
==IANA注意事项==<br />
<br />
这份文件并不需要与互联网分配编码机构(IANA) [6]互动.<br />
<br />
==XMPP协议注册事项==<br />
<br />
本文件并不需要的相互作用的XMPP注册 [ 7 ],但是,最佳做法是在XMPP的登记FORM_TYPEs和field值.<br />
<br />
==附录==<br />
<br />
===附录A:文档信息===<br />
<br />
系列:[http://xmpp.org/extensions/ XEP]<br />
<br />
序号:0128<br />
<br />
发布者:[http://xmpp.org/xsf/ XMPP标准基金会]<br />
<br />
状态:[http://www.xmpp.org/extensions/xep-0001.html#states-Final 终结版]<br />
<br />
类型:[http://www.xmpp.org/extensions/xep-0001.html#types-Standards%20Track 标准跟踪]<br />
<br />
版本:1.0<br />
<br />
最后更新:2004-10-20<br />
<br />
批准机构:[http://xmpp.org/council/ XMPP理事会]<br />
<br />
依赖标准:[[XEP-0004|XEP-0030|XEP-0068|XMPP Core]]<br />
<br />
取代: 无<br />
<br />
被替代标准:无<br />
<br />
缩略名:N/A<br />
<br />
原文控制: [http://svn.xmpp.org:18080/browse/XMPP/trunk/extensions/xep-0128.xml HTML] [http://svn.xmpp.org:18080//changelog/~rss/XMPP/trunk/extensions/xep-0128.xml/rss.xml RSS]<br />
<br />
本文的其它格式: [http://xmpp.org/extensions/xep-0030.xml XML] [http://xmpp.org/extensions/xep-0128.pdf PDF]<br />
<br />
<br />
--------------------------------------------------------------------------------<br />
===附录B:作者信息===<br />
'''Peter Saint-Andre'''<br />
<br />
Email: stpeter@jabber.org<br />
<br />
JabberID: stpeter@jabber.org<br />
<br />
URI: https://stpeter.im/<br />
<br />
<br />
<br />
{{Template:XEP附录CDEF}}<br />
<br />
===附录G:备注===<br />
1. XEP-0030: Service Discovery <http://xmpp.org/extensions/xep-0030.html>.<br />
<br />
2. XEP-0045: Multi-User Chat <http://xmpp.org/extensions/xep-0045.html>.<br />
<br />
3. XEP-0060: Publish-Subscribe <http://xmpp.org/extensions/xep-0060.html>.<br />
<br />
4. XEP-0004: Data Forms <http://xmpp.org/extensions/xep-0004.html>.<br />
<br />
5. XEP-0068: Field Data Standardization for Data Forms <http://xmpp.org/extensions/xep-0068.html>.<br />
<br />
6. The Internet Assigned Numbers Authority (IANA) is the central coordinator for the assignment of unique parameter values for Internet protocols, such as port numbers and URI schemes. For further information, see <http://www.iana.org/>.<br />
<br />
7. The XMPP Registrar maintains a list of reserved protocol namespaces as well as registries of parameters used in the context of XMPP extension protocols approved by the XMPP Standards Foundation. For further information, see <http://xmpp.org/registrar/>.<br />
<br />
<br />
--------------------------------------------------------------------------------<br />
If you are looking for a pair of pretty UGG Boots, you shouldn't miss this chance for purchasing UGG Classic Cardy Boots this season in our shop. Ugg Bailey Button would give people such a deep impression. UGG Classic Short Boots appreciate it not only by the high quality with steady innovations but also by its stylish designs. There is no doubt that it could go well with you casual outfits. There are many kinds of UGG Classic Tall Boots for different ages and tastes online. So pick up your own UGG Sandals now.<br />
<br />
===附录H:修订历史===<br />
注意: 本协议的旧版本可能在 http://xmpp.org/extensions/attic/ 还可用 <br />
<br />
Version 1.0 (2004-10-20)<br />
<br />
Per a vote of the Jabber Council, advanced status to Active; also added implementation notes. (psa) <br />
<br />
Version 0.2 (2004-03-15)<br />
<br />
Clarified syntax and corrected several errors; added IM server example. (psa) <br />
<br />
Version 0.1 (2004-03-05)<br />
<br />
Initial version. (psa) <br />
<br />
--------------------------------------------------------------------------------<br />
<br />
结束</div>
Snowqiang
http://wiki.jabbercn.org/RFC4622
RFC4622
2011-05-18T12:19:02Z
<p>Snowqiang: </p>
<hr />
<div>[[Category:XMPP正式RFC标准]]<br />
[[Category:已翻译]]<br />
<br />
'''本文的英文原文来自[http://www.ietf.org/rfc/rfc4622.txt RFC 4622]'''<br />
<br />
{|<br />
|网络工作组 || P. Saint-Andre<br />
|-<br />
|申请讨论: 4622 || Jabber软件基金会<br />
|-<br />
|类别: 标准跟踪 || 2006年7月<br />
|}<br />
<br />
::::'''用于 Extensible Messaging and Presence Protocol (XMPP) 的国际化资源标识符(IRIs)和统一资源标识符(URIs)'''<br />
<br />
'''关于本文的说明'''<br />
<br />
:本文为互联网社区定义了一个互联网标准跟踪协议,并且申请讨论协议和提出了改进的建议。请参照“互联网官方协议标准”的最新版本(STD 1)获得这个协议的标准化进程和状态。本文可以不受限制的分发。<br />
<br />
'''版权声明'''<br />
<br />
:本文版权属于互联网社区 (C) The Internet Society (2006).<br />
<br />
'''摘要'''<br />
<br />
:本文定义了在XMPP通信的时候,国际化资源标识符(IRIs)和统一资源标识符(URIs)在识别实体或与实体交互中的使用.<br />
<br />
==简介==<br />
<br />
:可扩展的消息和出席信息协议(XMPP)是一个流式的XML技术,允许任何两个网络上的实体准实时地交换XML元素(称为"XML节").<br />
<br />
:如[XMPP-CORE|XMPP文档列表/XMPP正式RFC标准/RFC3920]所定义, 在XMPP网络通信中使用的实体地址不能(must not)由一个Uniform Resource Identifier (URI)(定义在[URI])规划预设. 无论如何,一个XMPP网络之外的应用需要通过 URIs 或更时髦的方式,比如国际化资源标识符(IRIs; 见[IRI])来标识XMPP实体. 这些外部应用的例子包括,需要存储XMPP地址的数据库,非本地用户代理例如web浏览器,和提供接口给XMPP服务的日历应用程序.<br />
<br />
:XMPP地址的格式定义在[XMPP-CORE|XMPP文档列表/XMPP正式RFC标准/RFC3920]. 这样的一个地址可以包含几乎任何 [UNICODE] 字符并且必须(must)遵从很多[STRINGPREP]的profiles. 这使得XMPP地址完全国际化并且非常接近于一个没有scheme的IRI. 无论如何, 由于在IRS schemes中没有独立的注册项, 所以需要定义的XMPP标识符主要是作为URIs而不是IRIs, 并且注册一个XMPP URI scheme而不是一个IRI scheme. 所以, 本文做以下事情:<br />
<br />
* 说明如何标识 XMPP 实体作为 IRIs 或 URIs.<br />
<br />
* 说明如何与作为 IRIs 或 URIs 的 XMPP 实体交互.<br />
<br />
* 正式定义 XMPP IRIs and URIs 的语法.<br />
<br />
* 说明如何转换 XMPP IRIs 成为 URIs ,反之亦然.<br />
<br />
* 注册 xmpp URI scheme.<br />
<br />
===术语===<br />
<br />
:本文继承来自[IRI], [URI], 和 [XMPP-CORE|XMPP文档列表/XMPP正式RFC标准/RFC3920]的术语.<br />
<br />
:关键字 "MUST", "MUST NOT", "REQUIRED", "SHALL", "SHALL NOT", "SHOULD", "SHOULD NOT", "RECOMMENDED", "MAY", 和 "OPTIONAL" 在本文中的解释描述于 RFC 2119 [TERMS].<br />
<br />
==XMPP IRIs 和 URIs的使用==<br />
<br />
===基本原理===<br />
<br />
:如[[RFC3921|XMPP-IM]]所述, XMPP的即时消息和出席信息应用必须处理 im: 和 pres: URIs (由[CPIM] 和[CPP]定义). 无论如何, 有许多XMPP的其他应用(包括网络管理, 工作流系统, 通用 发行-订阅, 远程过程调用, 内容联合,游戏, 和中间件), 而这些应用没有实现即时消息和出席信息语义. 一个通用的XMPP实体不会实现任何已有的 URI规划的语义, 如 http:, ftp:, 或mailto: 规划. 所以, 需要定义一个新的 URI 规划, 以 IRI 或 URI 来标识或和任何XMPP实体交互 (不仅是即时消息和出席信息实体).<br />
<br />
:XMPP IRIs 和 URIs 定义由非本地接口和应用所使用, 主要目的是为了标识而非交互后者的区别,见 [URI]第一章第二节第二小节). 为了确保在XMPP网络中的互操作性, 当数据被路由到一个 XMPP 实体(例如, 当一个 XMPP 地址包含于一个XML节的'to' 或 'from' 属性中)或一个 XMPP 实体以别的方式为标准XMPP协议元素所标识, 这个实体必须(MUST)被赋予的地址格式为<[node@]domain[/resource]>(换言之, 没有一个预先的规划),这里一个XMPP地址的 "node identifier"部分,"domain identifier"部分, 和 "resource identifier"部分都遵守[XMPP-CORE第三章|XMPP文档列表/XMPP正式RFC标准/RFC3920#地址空间]所定义的规范.<br />
<br />
:(注意: 由于历史原因, XMPP中的术语"resource identifier"表示XMPP地址的可选部分,跟在域名后面并用"/"符号隔开(详细情况, 参照[XMPP-CORE第三章第四节|XMPP文档列表/XMPP正式RFC标准/RFC3920#地址空间]; 术语"resource identifier"的使用不要和[URI]的第一章第一节提供的"resource"和"identifier"弄混了).<br />
<br />
===格式===<br />
<br />
:如[[RFC3920|XMPP-CORE]]所述, 一个生来用于一个XMPP网络的XMPP地址是一个Unicode字符串, (1) 遵循一个特定系列的[STRINGPREP] profiles 和[IDNA] 约束, (2) 允许特定系列的语法规则, 并且 (3) 编码为[UTF-8]. 这样一个地址的格式可以被表示为扩张的巴斯科范式([ABNF])如下:<br />
<br />
[ node "@" ] domain [ "/" resource ]<br />
<br />
:在这个上下文中, "node" 和 "resource" 规则依赖于于独特的profiles of [STRINGPREP],而"domain" 规则依赖于[IDNA]说描述的国家化域名概念. (注意: 不需要参考IRI语法本身的punycode, 因为为了展示国际化域名任何punycode表述仅发生在XMPP应用内部. 无论如何, 在为XML节指明XMPP网络实体地址之前, 转换[IRI]语法到[IDNA]语法的工作是应用程序的责任.)<br />
<br />
:很自然, 为了被转化成 IRI 或 URI, 一个XMPP地址必须以一个规划进行预处理(特别的, xmpp规划)并且也可能需要要先进行转化以满足[IRI]和[URI]定义的规则. 更远一点, 为了和一个XMPP实体能有更多高级的交互能力而不只是简单地标识, 可能需要获得附加的URI语法和语义, 例如授权组件,查询组件, 以及碎片标识组件.<br />
<br />
:所以, 以下使用显示了用[ABNF]定义的巴斯科范式格式来用作XMPP IRI 的ABNF语法, 这里"ifragment", "ihost", 和 "iunreserved" 规则定义于[IRI], "pct-encoded"规则定义于[URI], 而 DQUOTE 定义于 [ABNF]:<br />
<br />
<pre><br />
xmppiri = "xmpp" ":" ihierxmpp<br />
[ "?" iquerycomp ]<br />
[ "#" ifragment ]<br />
ihierxmpp = iauthpath / ipathxmpp<br />
iauthpath = "//" iauthxmpp [ "/" ipathxmpp ]<br />
iauthxmpp = inodeid "@" ihost<br />
ipathxmpp = [ inodeid "@" ] ihost [ "/" iresid ]<br />
inodeid = *( iunreserved / pct-encoded / nodeallow )<br />
nodeallow = "!" / "$" / "(" / ")" / "*" / "+" / "," / ";" /<br />
"=" / "[" / "\" / "]" / "^" / "`" / "{" / "|" /<br />
"}"<br />
iresid = *( iunreserved / pct-encoded / resallow )<br />
resallow = "!" / DQUOTE / "$" / "&" / "'" / "(" / ")" /<br />
"*" / "+" / "," / ":" / ";" / "<" / "=" / ">" /<br />
"[" / "\" / "]" / "^" / "`" / "{" / "|" / "}"<br />
iquerycomp = iquerytype [ *ipair ]<br />
iquerytype = *iunreserved<br />
ipair = ";" ikey "=" ivalue<br />
ikey = *iunreserved<br />
ivalue = *( iunreserved / pct-encoded )<br />
</pre><br />
<br />
:无论如何, 前述的语法不适合包含在xmpp URI规划中的注册项中, 因为IANA只承认URI规划而不承认IRI规划. 所以,ABNF语法用于XMPP URI而不是IRI,定义见本文第三章第三节(见下文"IANA Registration"). 如果有必要把IRI语法转化成URI语法, 一个应用程序必须(MUST)遵守定义于[IRI]第三章第一节的映射过程.<br />
<br />
:以下是一个基本的XMPP IRI/URI例子,用于标识一个和XMPP服务器有关的节点:<br />
<br />
<pre><br />
xmpp:node@example.com<br />
</pre><br />
<br />
:以下章节提供各种组件对于XMPP IRI/URI的描述.<br />
<br />
===授权组件===<br />
<br />
:如本文第二章第八节所述, 在缺乏授权组件的时候, 处理程序将作为一个已配置的XMPP服务器的一个已配置的用户来进行验证. 也就是说, 授权组件章节不是必需的, 并且如果处理程序已经被缺省的证书配置好,授权组件将被忽略.<br />
<br />
:和RFC 3986第三章第二节一致, 授权组件由一个双斜杠("//")开始,结束于下一个单斜杠("/"), 问号("?"), 或数字符号("#")字符, 或由IRI/URI的结尾结束. 更完整的解释见本文第二章第八节第一小节, 一个授权组件的出席信息通知处理程序在授权组件中验证它是node@domain,而不是作为一个已配置的node@domain. (见本文的 安全性事项章节Security Considerations中关于验证的部分). (虽然授权组件被包含在大部分的XMPP IRIs 或 URIs中是不现实的, 但是如果适当的话规划允许它被包含.) 所以, 以下 XMPP IRI/URI 表明验证为 "guest@example.com":<br />
<br />
<pre><br />
xmpp://guest@example.com<br />
</pre><br />
<br />
:严重注意这和接下来的 XMPP IRI/URI是不相同的, 它标识一个节点"guest@example.com"而不是通知处理程序来验证它成为一个节点:<br />
<br />
<pre><br />
xmpp:guest@example.com<br />
</pre><br />
<br />
:类似的, 使用可能的查询组件 "?message" 来触发一个接口用于发送一条消息, 以下XMPP IRI/URI通知处理程序来验证为"guest@example.com"并发送一条消息给"support@example.com":<br />
<br />
<pre><br />
xmpp://guest@example.com/support@example.com?message<br />
</pre><br />
<br />
:对应的, 以下XMPP IRI/URI通知处理程序验证为它的已配置的缺省帐号并发送一条消息给"support@example.com":<br />
<br />
<pre><br />
xmpp:support@example.com?message<br />
</pre><br />
<br />
===路径组件===<br />
<br />
:一个XMPP IRI/URI的路径组件标识一个XMPP地址或指明IRI/URI处理最终要让一个XML节将去到的XMPP地址.<br />
<br />
:例如, 以下XMPP IRI/URI标识一个和XMPP服务器有关的节点:<br />
<br />
<pre><br />
xmpp:example-node@example.com<br />
</pre><br />
<br />
<br />
:以下XMPP IRI/URI标识一个和XMPP服务器有关的节点并带上特定的和那个节点相关的XMPP资源标识符:<br />
<br />
<pre><br />
xmpp:example-node@example.com/some-resource<br />
</pre><br />
<br />
:在XMPP地址中包含一个节点是可选的, 所以以下XMPP IRI/URI简单的标识了一个XMPP服务器:<br />
<br />
<pre><br />
xmpp:example.com<br />
</pre><br />
<br />
===查询组件==<br />
<br />
:有许多可能的用例用于在一个XMPP IRI/URI的查询组件中封装信息; 包含但不仅限于以下例子:<br />
<br />
* 发送一个XMPP消息节(见[[RFC3921|XMPP-IM]]),<br />
<br />
* 添加一个名册条目(见[[RFC3921|XMPP-IM]]),<br />
<br />
* 发送一个出席信息订阅项(见[[RFC3921|XMPP-IM]]),<br />
<br />
* 调查当前出席信息(见[[RFC3921|XMPP-IM]]),<br />
<br />
* 触发一个远程过程调用(见[XEP-0009]),<br />
<br />
* 查询另一个实体的身份或能力(见[[XEP-0030]]),<br />
<br />
* 加入一个基于XMPP的文本聊天室(见[[XEP-0045]]),<br />
<br />
* 和一个发行-订阅频道交互(见[[XEP-0060]]),<br />
<br />
* 提供一个SOAP接口(见[XEP-0072]), 以及<br />
<br />
* 注册另一个实体(见[[XEP-0077]]).<br />
<br />
:许多这些潜在的用例是应用程序特定的并且这类应用的全貌在XMPP的持续扩张发展中无法预知; 无论如何, Jabber/XMPP开发社区一致同意所有想象中的未来应用可能通过"query type"被封装, 通过一个或多个 "键-值"(key-value)对进行可选的补充(这类似于[HTML]中描述的"application/x-www-form-urlencoded" MIME 类型).<br />
<br />
:作为例子, 一个XMPP IRI/URI企图启动一个接口用于发送一条消息给XMPP实体"example-node@example.com", 可以用以下形式表达:<br />
<br />
<pre><br />
xmpp:example-node@example.com?message<br />
</pre><br />
<br />
:类似的, 一个XMPP IRI/URI企图启动一个接口用于发送一个有特定标题的消息给XMPP实体"example-node@example.com", 可以以下形式表达:<br />
<br />
<pre><br />
xmpp:example-node@example.com?message;subject=Hello%20World<br />
</pre><br />
<br />
:如果处理程序不理解查询组件或特定的查询类型, 它必须(MUST)忽略查询组件并把它当成它的IRI/URI部分, 例如,当成<xmpp:example-node@example.com>而不是 <xmpp:example-node@example.com?query>. 如果处理程序不理解查询组件的一个特定键, 它必须(MUST)忽略那个键以及与它相关的值.<br />
<br />
:大家知道, 存在许多种类的XMPP应用(包括现有的和潜在的), 而这些应用可以定义查询类型和键用于XMPP URIs的查询组件部分. XSF(XMPP Software Foundation)的XMPP Registrar 功能(见[XEP-0053])维护了这些查询类型的一个注册表和键, 网址在<http://www.xmpp.org/registrar/querytypes.html>. 为了帮助确保互操作性,任何定义在本文中的应用正在使用的格式应该(SHOULD)按照[XEP-0147]所定义的流程来提交任何相关的查询类型和键到那个注册表.<br />
<br />
===碎片标识组件===<br />
<br />
:如[URI]第三章第五节指出, "URI的碎片标识组件允许通过参考主要资源和附加标识信息来做二级资源的间接标识". 因为这个被XMPP IRI/URI标识的资源不产生任何可用的媒体类型(见[MIME]),所以(在[URI]术语中)一个XMPP资源不存在任何表述, 在XMPP IRIs/URIs中碎片标识组件的语义是"可能未知的considered unknown 和, 有效地,非强制性的" (ibid.). 典型的XMPP应用可以(MAY)为它们自己的目的来使用碎片标识组件. 无论如何,如果一个处理程序不理解碎片标识组件或XMPP IRI/URI中特定的碎片标识组件的语法, 它必须(MUST)忽略这个碎片标识组件.<br />
<br />
===XMPP IRIs/URIs的生成===<br />
<br />
====生成方法====<br />
<br />
:为了把一个XMPP节点标识符,域标识符,和资源标识符格式化成为一个XMPP IRI, 生成程序必须(MUST)首先确保XMPP地址符合[XMPP-CORE|XMPP文档列表/XMPP正式RFC标准/RFC3920]定义的规则, 包括相应的[STRINGPREP]的应用; 然后它必须(MUST)连接以下的东西:<br />
<br />
:# "xmpp"规划和":"符号<br />
:# 可选的 (如果在节点标识符之前包含了一个授权组件), 符号"//", 一个格式为node@domain的授权组件, 以及符号"/".<br />
:# 可选的(如果XMPP地址包含了一个 XMPP "节点标识符"), 一个Unicode字符集的字符串并遵守"inodeid"规则, 跟在"@"符号后面.<br />
:# 一个Unicode字符集的字符串并遵守"ihost"规则.<br />
:# 可选的(如果XMPP地址包含一个XMPP "资源标识符"), 符号"/"和一个Unicode字符集的字符串并遵守"iresid"规则.<br />
:# 可选的(如果一个查询组件被包含), 符号"?"和查询组件.<br />
:# 可选的(如果一个碎片标识组件被包含), "#"符号和碎片标识组件.<br />
<br />
:为了把一个resulting IRI格式化成一个XMPP URI, 一个应用必须(MUST)遵守[IRI]第三章第一节定义的映射过程.<br />
<br />
====生成备注====<br />
<br />
:某些特定的符号被允许存在于一个原生的XMPP地址的节点标识符, 域标识符, 和资源标识符部分, 但是被XMPP IRI中的"inodeid", "ihost", 和 "iresid"规则禁止. 具体来说, "#"和"?"符号被允许出现在节点标识符, "/", "?", "#", 和"@"符号被允许在资源标识符, 但是这些符号被用作XMPP IRIs的分隔符. 另外, " "([US-ASCII]空格)符号被允许在资源标识符中但是在IRIs中是禁止的. 所以, 当把一个XMPP地址转化为一个XMPP IRI时, 所有前述的符号必须(MUST)被部分编码.<br />
<br />
:考虑以下的在一个XMPP地址中的nasty节点:<br />
<br />
<pre><br />
nasty!#$%()*+,-.;=?[\]^_`{|}~node@example.com<br />
</pre><br />
<br />
<br />
:那个地址将被转化成以下的XMPP IRI:<br />
<br />
<pre><br />
xmpp:nasty!%23$%25()*+,-.;=%3F[\]^_`{|}~node@example.com<br />
</pre><br />
<br />
<br />
:考虑以下的在一个XMPP地址中的repulsive资源(为了看起来方便分成两行):<br />
<br />
<pre><br />
node@example.com<br />
/repulsive !#"$%&'()*+,-./:;<=>?@[\]^_`{|}~resource<br />
</pre><br />
<br />
:那个地址将被转化成以下的XMPP IRI(为了看起来方便分成两行):<br />
<br />
<pre><br />
xmpp:node@example.com<br />
/repulsive%20!%23"$%25&'()*+,-.%2F:;<=>%3F%40[\]^_`{|}~resource<br />
</pre><br />
<br />
:而且, 事实上被允许在一个XMPP地址中出现的任何[US-ASCII]范围之外的符号, 也在XMPP IRI中出现, 但是URI语法禁止这些符号直接显示并指出这样的符号必须(MUST)被部分编码. 为了确定和一个XMPP IRI相关的URI, 一个应用必须(MUST)遵守定义在[IRI]第三章第一节的映射过程.<br />
<br />
====生成例子====<br />
<br />
:考虑以下XMPP地址:<br />
<br />
<pre><br />
<ji&#x159;i@&#x10D;echy.example/v Praze><br />
</pre><br />
<br />
:注意: 字符串"&#x159;" 代表Unicode符号LATIN SMALL LETTER R WITH CARON, 并且字符串"&#x10D;" 代表Unicode符号LATIN SMALL LETTER C WITH CARON, 以下用于[IRI]"XML Notation"来表现无法在ASCII-only中表示的字符串(注意这些字符串也被展现在它们的字符准备规范表单中stringprep canonical form). '<'和'>'符号不是地址本身的一部分但为了易于理解而用来设定地址的结束. 对于那些不能读捷克语的人,这个例子可能被英语化为"george@czech-lands.example/In Prague".<br />
<br />
:和以上指定的过程一致, 生成程序将按以下步骤从这个地址生成一个合法的XMPP IRI:<br />
<br />
:# 确保XMPP地址符合[[RFC3920|XMPP-CORE]]定义的规则, 包括应用相应的[STRINGPREP] profiles和编码成[UTF-8]字符串.<br />
:# 连接以下:<br />
:## "xmpp"规划和":"符号.<br />
:## 一个"授权组件",如果有的话(本例没有展现).<br />
:## 一个Unicode字符串展示XMPP地址, 被以"inodeid","ihost",和"iresid"规则转换.<br />
:## "?"符号被一个"查询组件"跟随, 如果有适当的应用(本例没有展现).<br />
:## "#"符号被一个"碎片标识组件"跟随, 如果有适当的应用(本例没有展现).<br />
<br />
:结果是这个XMPP IRI:<br />
<br />
<pre><br />
<xmpp:ji&#x159;i@&#x10D;echy.example/v%20Praze><br />
</pre><br />
<br />
:为了从前述的IRI生成一个合法的XMPP URI, 应用必须(MUST)遵守定义在[IRI]第三章第一节的过程, 结果是以下的URI:<br />
<br />
<pre><br />
<xmpp:ji%C5%99i@%C4%8Dechy.example/v%20Praze><br />
</pre><br />
<br />
===XMPP IRIs/URIs的处理===<br />
<br />
====处理方法====<br />
<br />
:如果一个处理程序被显示为一个XMPP URI而不是一个XMPP IRI, 它必须(MUST)首先按以下定义在[IRI]第三章第二节的过程把这个URI转换成为IRI.<br />
<br />
:为了分解一个XMPP IRI用于和它所标识的实体交互, 一个处理程序必须(MUST)分解为:<br />
<br />
:# "xmpp"规划和":"符号.<br />
:# 授权组件, 如果有的话(在"//"符号和下一个"/"符号 "?"符号,"#"符号,或IRI的结尾之间的Unicode字符串,).<br />
:# 一个展示为XMPP地址的根据"inodeid", "ihost", "iresid"规则转换的Unicode字符串.<br />
:# 可选的查询组件, 如果有的话, 使用"?"符号作为分隔符.<br />
:# 可选的碎片标识组件, 如果有的话, 使用"#"符号作为分隔符.<br />
<br />
:在这一点上, 处理程序必须(MUST)确保结果的XMPP地址遵守[[RFC3920|XMPP-CORE]]定义的规则, 包括应用相应的[STRINGPREP]. 然后处理程序将 (1) 自行完成更多的XMPP处理, 或(2) 调用一个帮助程序来完成XMPP处理; 这样的XMPP处理很可能包括如下的步骤:<br />
<br />
:# 如果还未连接到一个XMPP服务器, 作为授权组件中指明的用户连接或作为已配置的XMPP服务器的已配置用户连接, 通常遵守[XMPP-CORE|XMPP文档列表/XMPP正式RFC标准/RFC3920]定义的XMPP连接过程.(注意: 处理程序应该(SHOULD)忽略授权组件,如果它已经用缺省的证书设置所配置.)<br />
:# 可选的, 决定预定接收者的种类(换言之,通过[XEP-0030]).<br />
:# 可选的, 根据预定接收者的种类展示一个适当的界面以及/或查询组件的内容给用户.<br />
:# 生成一个XMPP节把任何用户或应用的输入转换成它们相应的XMPP数据.<br />
:# 通过验证过的服务器连接发送XMPP节用于递送给预定接收者.<br />
<br />
====处理备注====<br />
<br />
:实施者可能注意到, 在第二章第八节第一小节结尾中描述的"更多的XMPP处理", 前两步类似HTTP 验证([HTTP-AUTH]), 后三步类似处理 mailto: URIs ([MAILTO]).<br />
<br />
:本文的第二章第七节第二小节说过, 特定的字符被允许出现在原生的XMPP地址的节点标识符, 域标识符, 和资源标识符部分, 但被XMPP IRI的"inodeid", "ihost", 和"iresid"规则禁止. 当处理一个XMPP IRI用来和XMPP实体交互的时候, 这些部分编码的符合XMPP IRIs的字节必须(MUST)被转化成在XMPP地址中允许的字符串.<br />
<br />
:考虑以下一个XMPP IRI中的nasty节点:<br />
<br />
<pre><br />
xmpp:nasty!%23$%()*+,-.;=%3F[\]^_`{|}~node@example.com<br />
</pre><br />
<br />
:那个IRI将被转化成以下的XMPP address:<br />
<br />
<pre><br />
nasty!#$%()*+,-.;=?[\]^_`{|}~node@example.com<br />
</pre><br />
<br />
:考虑以下一个XMPP IRI中的repulsive资源(为便于阅读分成两行):<br />
<br />
<pre><br />
xmpp:node@example.com<br />
/repulsive%20!%23"$%25&'()*+,-.%2F:;<=>%3F%40[\]^_`{|}~resource<br />
</pre><br />
<br />
<br />
:那个IRI将被转化成以下的XMPP地址(为便于阅读分成两行):<br />
<br />
<pre><br />
node@example.com<br />
/repulsive !#"$%&'()*+,-./:;<=>?@[\]^_`{|}~resource<br />
</pre><br />
<br />
====处理例子====<br />
<br />
:考虑从前一个例子中得到的XMPP URI:<br />
<br />
<pre><br />
<xmpp:ji%C5%99i@%C4%8Dechy.example/v%20Praze><br />
</pre><br />
<br />
:为了从那个URI生成一个合法的XMPP IRI, 应用程序必须(MUST)遵守[IRI]第三章第二节定义的过程, 结果得到以下IRI:<br />
<br />
<pre><br />
<xmpp:ji&#x159;i@&#x10D;echy.example/v%20Praze><br />
</pre><br />
<br />
:和以上指明的处理一致, 处理程序将移除"xmpp"规划和":"符号以从XMPP IRI中揭解开XMPP地址, 转换任何按照"inodeid", "ihost", 和"iresid"规则部分编码的字节成为相应的字符串(例如, "%20" 转化成空格符号).<br />
<br />
:结果是这个XMPP地址:<br />
<br />
<pre><br />
<ji&#x159;i@&#x10D;echy.example/v Praze><br />
</pre><br />
<br />
===国际化===<br />
<br />
:因为XMPP地址是[UTF-8]字符串并且因为在XMPP地址中[US-ASCII]范围之外的字节很容易被转化成部分编码的字节, XMPP地址被设计成能够很好地和Internationalized Resource Identifiers ([IRI])配合工作. 某些情况下, 除了stringprep检查, 语法相关的[US-ASCII]符号(例如, "?")转化, 以及根据"inodeid", "ihost", 和"iresid"规则把部分编码的字节转化为相应字符(例如, "%20"转成[US-ASCII]空格符), 一个XMPP IRI能通过加上"xmpp"规划和":"符号的前缀, 直接被构造成一个XMPP地址. 而且, 一个XMPP IRI遵照[IRI]第三章第一节定义的过程可以被转化成URI语法, 一个XMPP URI遵照[IRI]第三章第二节定义的过程可以被转化成IRI, 因而确保应用的互操作性的是能处理URIs但不能处理IRIs.<br />
<br />
==xmpp URI规划的IANA注册项==<br />
<br />
:和[URI-SCHEMES]一致, 本章提供注册xmpp URI规划需要的信息.<br />
<br />
===URI规划名===<br />
<br />
xmpp<br />
<br />
===状态===<br />
<br />
permanent<br />
<br />
===URI规划语法===<br />
<br />
:一个xmpp URI的语法使用[ABNF]定义的巴斯科范式定义在下文, 这里"fragment","host","pct-encoded",以及"unreserved"规则定义在[URI]而DQUOTE定义在[ABNF]:<br />
<br />
<pre><br />
xmppuri = "xmpp" ":" hierxmpp [ "?" querycomp ] [ "#" fragment ]<br />
hierxmpp = authpath / pathxmpp<br />
authpath = "//" authxmpp [ "/" pathxmpp ]<br />
authxmpp = nodeid "@" host<br />
pathxmpp = [ nodeid "@" ] host [ "/" resid ]<br />
nodeid = *( unreserved / pct-encoded / nodeallow )<br />
nodeallow = "!" / "$" / "(" / ")" / "*" / "+" / "," / ";" /<br />
"=" / "[" / "\" / "]" / "^" / "`" / "{" / "|" /<br />
"}"<br />
resid = *( unreserved / pct-encoded / resallow )<br />
resallow = "!" / DQUOTE / "$" / "&" / "'" / "(" / ")" /<br />
"*" / "+" / "," / ":" / ";" / "<" / "=" / ">" /<br />
"[" / "\" / "]" / "^" / "`" / "{" / "|" / "}"<br />
querycomp = querytype [ *pair ]<br />
querytype = *( unreserved / pct-encoded )<br />
pair = ";" key "=" value<br />
key = *( unreserved / pct-encoded )<br />
value = *( unreserved / pct-encoded )<br />
</pre><br />
<br />
===URI规划语义===<br />
<br />
:xmpp URI规划标识了使用XMPP进行本地通信的实体, 并且主要用于标识而非资源定位. 无论如何, 如果一个处理xmpp URI的应用能够用URI标识的XMPP地址进行交互, 它必须(MUST)遵从定义在[RFC4622第二章|XMPP文档列表/XMPP正式RFC标准/RFC4622#XMPP_IRIs_和_URIs的使用]的方法论, 来重构被封装的XMPP地址, 连接到适当的XMPP服务器, 并发送一个适当的XMPP"节"(XML碎片)给XMPP地址. (注意: 没有和xmpp URI规划关联的MIME类型.)<br />
<br />
===编码事项===<br />
<br />
:除了XMPP URIs, 还将有XMPP国际化资源标识符(IRIs). 在转换一个XMPP地址成为一个IRI之前(并且遵守[XMPP-CORE|XMPP文档列表/XMPP正式RFC标准/RFC3920]), XMPP地址必须由生成程序展现为[UTF-8](例如, 把应用内部的UTF-16字符串的地址转换为UTF-8字符串), 并且UTF-8字符串必须加上前缀"xmpp"规划和":"符号. 无论如何, 因为一个XMPP URI必须仅包含[US-ASCII]字符, 一个XMPP IRI的UTF-8字符串必须遵照RFC 3987定义的过程被转化成URI语法.<br />
<br />
===使用本URI规划名的应用/协议===<br />
<br />
:xmpp URI规划被设计用于从一个非原生的用户代理和一个XMPP网络之间的接口, 例如web浏览器, 以及其他需要标识XMPP实体成为全URIs或IRIs的非原生的应用.<br />
<br />
===互操作性事项===<br />
<br />
:已知还没有和使用xmpp URI规划有关的互操作性问题. 为了帮助确保互操作性, XSF的XMPP Registrar功能维护了一个query类型的注册表,用于那些可能的查询组件和XMPP URIs以及IRIs, 网址在<http://www.jabber.org/registrar/querytypes.html>.<br />
<br />
===安全性事项===<br />
<br />
:见[RFC4622第五章安全事项|XMPP文档列表/XMPP正式RFC标准/RFC4622#安全事项].<br />
<br />
===联系人===<br />
<br />
:Peter Saint-Andre {link:mailto:stpeter@jabber.org|mailto:stpeter@jabber.org},<br />
<br />
:[xmpp:stpeter@jabber.org xmpp:stpeter@jabber.org]<br />
<br />
===作者/变更管理者===<br />
<br />
:这个规划被注册在IETF树下. 同样的, IETF维护变更控制.<br />
<br />
===参考===<br />
<br />
[[RFC3920|XMPP-CORE]]<br />
<br />
==IANA事项==<br />
<br />
:本文注册了一个URI规划. 注册项模版能在本文第三章找到. 为了帮助确保互操作性, XSF(XMPP Software Foundation)的XMPP注册功能维护了一个查询组件和健的注册项, 用于XMPP URIs和IRIs的查询组件, 网址在<http://www.jabber.org/registrar/querytypes.html>.<br />
<br />
==安全事项==<br />
<br />
:从非原生的应用提供一个接口到XMPP服务器产生了新的安全隐患. 在[IRI], [URI],和[XMPP-CORE|XMPP文档列表/XMPP正式RFC标准/RFC3920]中讨论的安全事项适用于XMPP IRIs, 而在[URI],和[XMPP-CORE|XMPP文档列表/XMPP正式RFC标准/RFC3920]中讨论的安全事项适用于XMPP URIs. 遵循[URI-SCHEMES]第二章第七节和[URI]第七章, 以下章节定义了具体的安全事项.<br />
<br />
===可靠性和一致性===<br />
<br />
:假设格式为node@domain.tld的XMPP地址是通过向XMPP服务器注册创建的或由服务器的管理员提供, 这样的地址也可以被取消注册或取消供应. 所以, 标识这样的一个XMPP地址的XMPP IRI/URI可能是不可靠的并且其负责人,帐号拥有者,应用,或递送者是不一致的.<br />
<br />
:格式为node@domain.tld/resource的XMPP地址甚至可能更短暂(因为一个特定的XMPP资源标识符典型地关联于在一个XMPP服务器上的一个XMPP客户端的一个特定的,临时的会话); 所以标识这样一个XMPP地址的XMPP IRI/URI可能将是不可靠的以及和相关的同一会话不一致的. 无论如何, 定义于[XMPP-CORE第十章|XMPP文档列表/XMPP正式RFC标准/RFC3920#服务器处理XML节的规则]的过程有效地排除了任何潜在的由标识XMPP地址的XMPP IRI/URI缺少可靠性和一致性造成的混淆.<br />
<br />
:典型的格式为domain.tld的XMPP地址是长寿命的XMPP服务器或相关的服务; 当然尽管任何时候服务器或服务的管理员都可能让服务器或服务退役, 一般来讲标识这样的服务或服务器的IRIs/URIs是最可靠的以及和XMPP IRIs/URIs最一致的.<br />
<br />
:格式为domain.tld/resource的XMPP地址在XMPP网络还不常见; 无论如何, 标识这样的服务或服务器的IRIs/URIs的可靠性和一致性可能处于格式为domain.tld的XMPP地址和格式为node@domain.tld的XMPP 地址之间.<br />
<br />
===恶意的语句===<br />
<br />
:通过在XMPP IRIs/URIs中对端口号的禁止减少了XMPP IRIs/URIs的恶意的构造(因为端口号是用[DNS-SRV]查询的, 定义在[XMPP-CORE|XMPP文档列表/XMPP正式RFC标准/RFC3920]中).<br />
<br />
===后台转换===<br />
<br />
:因为基本的XMPP协议被定义用来实现消息和出席信息的交换而不是接收文件或类似的系统功能, 据不可靠消息XMPP IRIs/URIs的使用将导致有害的废弃品. 无论如何, 如果一个XMPP协议扩展定义了方法用于信息接收, 它必须(MUST)定义通过访问那个信息进行适当的控制. 另外, XMPP服务器不应该(SHOULD NOT)在本地解析XMPP IRIs/URIs而应该(SHOULD)只接受定义在[XMPP-CORE|XMPP文档列表/XMPP正式RFC标准/RFC3920]中的XML电信协议和任何期望往那里的扩展.<br />
<br />
===敏感信息===<br />
<br />
:通过web浏览器或其他非原生应用来和XMPP实体交互可能会暴露敏感信息(例如特定XMPP应用协议扩展支持)并且因此使得在原生XMPP网络中不可能发生的攻击在这里成为可能. 在决定XMPP IRIs or URIs中应当展示什么信息的时候必须非常小心.<br />
<br />
:具体来说, 在公众场合(例如,在网站)声明XMPP IRIs/URIs可能使恶意用户能够从XMPP IRIs/URIs的授权和路径组件收集XMPP地址并且从而发送未经请求的大量通信给那些地址所展示的用户或应用. 应该非常小心地平衡公开信息的好处和非自愿通信的潜在成本.<br />
<br />
:为了帮助纺织敏感信息泄露, 密码和其他用户证书被禁止出现在XMPP IRIs/URIs的授权组件中; 实际上它们不需要, 因为在XMPP中的[SASL]验证使得可以用SASL ANONYMOUS机制, 如果想要的话.<br />
<br />
===语义攻击===<br />
<br />
:尽管存在无等级的URI规划如[MAILTO], 通过联合人类用户可能预期所有URIs在规划名和":"符号之后包含"//"符号. 无论如何, 在XMPP IRIs/URIs中, "//"符号处于授权组件之前而不是路径组件之前. 因此,<br />
<br />
xmpp://guest@example.com 表示验证为"guest@example.com", 反之xmpp:guest@example.com 标识节点"guest@example.com". 处理程序必须(MUST)清晰地区分这两种格式, 而用户代理应该(SHOULD)不鼓励人类用户在XMPP IRIs/URIs中包含"//"符号, 因为使用授权组件被认为只在特定的情景中出现, 不是通常的情景.<br />
<br />
===欺骗===<br />
<br />
:在一个XMPP IRI中有效包含全范围的Unicode字符的能力可能使得进行特定格式的地址模拟(也成为"欺骗")更为容易. 无论如何, 关于这一点XMPP IRIs和其他IRIs没有不同, 为了帮助防止来自欺骗地址的攻击, 显示XMPP IRIs给人类用户的应用必须遵守关于地址模拟的最佳实践(例如, phenomenon被当成"phishing"). 具体的信息, 参考[IRI]的安全性事项.<br />
<br />
==参考==<br />
<br />
===标准参考===<br />
<br />
:[ABNF] Crocker, D. and P. Overell, "Augmented BNF for Syntax Specifications: ABNF", RFC 4234, October 2005.<br />
<br />
:[IRI] Duerst, M. and M. Suignard, "Internationalized Resource Identifiers (IRIs)", RFC 3987, January 2005.<br />
<br />
:[TERMS] Bradner, S., "Key words for use in RFCs to Indicate Requirement Levels", BCP 14, RFC 2119, March 1997.<br />
<br />
:[URI] Berners-Lee, T., Fielding, R., and L. Masinter, "Uniform Resource Identifier (URI): Generic Syntax", STD 66, RFC 3986, January 2005.<br />
<br />
:[[RFC3920|XMPP-CORE]] Saint-Andre, P., "Extensible Messaging and Presence Protocol (XMPP): Core", RFC 3920, October 2004.<br />
<br />
===信息参考===<br />
<br />
:[CPIM] Peterson, J., "Common Profile for Instant Messaging (CPIM)", RFC 3860, August 2004.<br />
<br />
:[CPP] Peterson, J., "Common Profile for Presence (CPP)", RFC 3859, August 2004.<br />
<br />
:[DNS-SRV] Gulbrandsen, A., Vixie, P., and L. Esibov, "A DNS RR for specifying the location of services (DNS SRV)", RFC 2782, February 2000.<br />
<br />
:[HTML] Raggett, D., "HTML 4.0 Specification", W3C REC REC-html40-19980424, April 1998.<br />
<br />
:[HTTP-AUTH] Franks, J., Hallam-Baker, P., Hostetler, J., Lawrence, S., Leach, P., Luotonen, A., and L. Stewart, "HTTP Authentication: Basic and Digest Access Authentication", RFC 2617, June 1999.<br />
<br />
:[IDNA] Faltstrom, P., Hoffman, P., and A. Costello, "Internationalizing Domain Names in Applications (IDNA)", RFC 3490, March 2003.<br />
<br />
:[XEP-0009] Adams, D., "Jabber-RPC", JSF JEP 0009, February 2006.<br />
<br />
:[[XEP-0030]] Hildebrand, J., Millard, P., Eatmon, R., and P. Saint-Andre, "Service Discovery", JSF JEP 0030, January 2006.<br />
<br />
:[[XEP-0045]] Saint-Andre, P., "Multi-User Chat", JSF JEP 0045, September 2005.<br />
<br />
:[[XEP-0053]] Saint-Andre, P., "Jabber Registrar", JSF JEP 0053, May 2004.<br />
<br />
:[[XEP-0060]] Millard, P., Saint-Andre, P., and R. Meijer, "Publish-Subscribe", JSF JEP 0060, June 2005.<br />
<br />
:[XEP-0072] Forno, F. and P. Saint-Andre, "SOAP Over XMPP", JSF JEP 0072, December 2005.<br />
<br />
:[[XEP-0077]] Saint-Andre, P., "In-Band Registration", JSF JEP 0077, January 2006.<br />
<br />
:[XEP-0147] Saint-Andre, P., "XMPP IRI/URI Query Components", JSF JEP 0147, March 2006.<br />
<br />
:[MAILTO] Hoffman, P., Masinter, L., and J. Zawinski, "The mailto URL scheme", RFC 2368, July 1998.<br />
<br />
:[MIME] Freed, N. and N. Borenstein, "Multipurpose Internet Mail Extensions (MIME) Part Two: Media Types", RFC 2046, November 1996.<br />
<br />
:[SASL] Melnikov, A. and K. Zeilenga, "Simple Authentication and Security Layer (SASL)", RFC 4422, June 2006.<br />
<br />
:[STRINGPREP] Hoffman, P. and M. Blanchet, "Preparation of Internationalized Strings ("STRINGPREP")", RFC 3454, December 2002.<br />
<br />
:[UNICODE] The Unicode Consortium, "The Unicode Standard, Version 3.2.0", 2000. The Unicode Standard, Version 3.2.0 is defined by The Unicode Standard, Version 3.0 (Reading, MA, Addison-Wesley, 2000. ISBN 0-201-61633-5), as amended by the Unicode Standard Annex #27: Unicode 3.1(http://www.unicode.org/reports/tr27/) and by the Unicode Standard Annex #28: Unicode 3.2 (http://www.unicode.org/reports/tr28/).<br />
<br />
:[URI-SCHEMES] Hansen, T., Hardie, T., and L. Masinter, "Guidelines and Registration Procedures for New URI Schemes", RFC 4395, February 2006.<br />
<br />
:[US-ASCII] American National Standards Institute, "Coded Character Set - 7-bit American Standard Code for Information Interchange", ANSI X3.4, 1986.<br />
<br />
:[UTF-8] Yergeau, F., "UTF-8, a transformation format of ISO 10646", STD 63, RFC 3629, November 2003.<br />
<br />
:[[RFC3921|XMPP-IM]] Saint-Andre, P., "Extensible Messaging and Presence Protocol (XMPP): Instant Messaging and Presence", RFC 3921, October 2004.<br />
<br />
'''作者地址'''<br />
<br />
:Peter Saint-Andre<br />
<br />
:XMPP Software Foundation<br />
<br />
:EMail: [mailto:stpeter@jabber.org stpeter@jabber.org]<br />
<br />
:URI: [xmpp:stpeter@jabber.org xmpp:stpeter@jabber.org]<br />
<br />
'''完整版权声明'''<br />
<br />
<pre><br />
Copyright (C) The Internet Society (2006).<br />
<br />
This document is subject to the rights, licenses and restrictions<br />
contained in BCP 78, and except as set forth therein, the authors<br />
retain all their rights.<br />
<br />
This document and the information contained herein are provided on an<br />
"AS IS" basis and THE CONTRIBUTOR, THE ORGANIZATION HE/SHE REPRESENTS<br />
OR IS SPONSORED BY (IF ANY), THE INTERNET SOCIETY AND THE INTERNET<br />
ENGINEERING TASK FORCE DISCLAIM ALL WARRANTIES, EXPRESS OR IMPLIED,<br />
INCLUDING BUT NOT LIMITED TO ANY WARRANTY THAT THE USE OF THE<br />
INFORMATION HEREIN WILL NOT INFRINGE ANY RIGHTS OR ANY IMPLIED<br />
WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE.<br />
</pre><br />
<br />
'''知识产权'''<br />
<br />
<pre><br />
The IETF takes no position regarding the validity or scope of any<br />
Intellectual Property Rights or other rights that might be claimed to<br />
pertain to the implementation or use of the technology described in<br />
this document or the extent to which any license under such rights<br />
might or might not be available; nor does it represent that it has<br />
made any independent effort to identify any such rights. Information<br />
on the procedures with respect to rights in RFC documents can be<br />
found in BCP 78 and BCP 79.<br />
<br />
Copies of IPR disclosures made to the IETF Secretariat and any<br />
assurances of licenses to be made available, or the result of an<br />
attempt made to obtain a general license or permission for the use of<br />
such proprietary rights by implementers or users of this<br />
specification can be obtained from the IETF on-line IPR repository at<br />
http://www.ietf.org/ipr.<br />
<br />
The IETF invites any interested party to bring to its attention any<br />
copyrights, patents or patent applications, or other proprietary<br />
rights that may cover technology that may be required to implement<br />
this standard. Please address the information to the IETF at<br />
ietf-ipr@ietf.org.<br />
</pre><br />
<br />
'''感谢'''<br />
<br />
<pre><br />
Funding for the RFC Editor function is provided by the IETF<br />
Administrative Support Activity (IASA).<br />
</pre></div>
Snowqiang
http://wiki.jabbercn.org/RFC3921
RFC3921
2011-05-18T12:12:23Z
<p>Snowqiang: </p>
<hr />
<div>[[Category:XMPP正式RFC标准]]<br />
[[Category:已翻译]]<br />
<br />
本文的英文原文来自[http://www.ietf.org/rfc/rfc3921.txt RFC 3921]<br />
<br />
{|<br />
|网络工作组 || Saint-Andre, Ed.<br />
|-<br />
|申请讨论: 3921 || Jabber软件基金会<br />
|-<br />
|类别: 标准跟踪 || 2004年10月<br />
|}<br />
<br />
::::'''可扩展的消息和出席信息协议 (XMPP): 即时消息和出席信息'''<br />
<br />
'''关于本文的说明'''<br />
<br />
:本文为互联网社区定义了一个互联网标准跟踪协议,并且申请讨论协议和提出了改进的建议。请参照“互联网官方协议标准”的最新版本(STD 1)获得这个协议的标准化进程和状态。本文可以不受限制的分发。<br />
<br />
'''版权声明'''<br />
<br />
:本文版权属于互联网社区 (C) The Internet Society (2004).<br />
<br />
'''摘要'''<br />
<br />
:本文定义了可扩展消息和出席信息协议(XMPP)的核心功能的扩展和应用,XMPP提供了RFC 2779 定义的基本的即时消息和出席信息功能。<br />
<br />
==绪论==<br />
<br />
===概览===<br />
<br />
:XMPP是一个流化XML[XML]元素的协议,用于准实时的交换消息和出席信息。XMPP的核心功能定义在Extensible Messaging and Presence Protocol (XMPP): Core [XMPP-CORE|XMPP文档列表/XMPP正式RFC标准/RFC3920]. 这些功能 -- 主要是 XML流, 使用 TLS和SASL,以及流的根元素之下的<message/>, <presence/>, 和 <iq/> 子元素 -- 为各种类型的准实时应用提供了一个构造基础, 它可以被放在核心的顶层,使用特定XML名字空间[XML-NAMES]发送特定的应用数据. 本文描述XMPP核心功能的扩展和应用,XMPP核心功能提供了RFC 2779 [IMP-REQS]定义的基本的即时消息和出席信息功能。<br />
<br />
===需求===<br />
<br />
:为了达到本文的目的, 基本的即时消息和出席信息应用的需求定义在[IMP-REQS],它是一个高阶的规定,一个用户必须完成以下用例:<br />
<br />
:*和其他用户交换消息<br />
:*和其他用户交换出席信息<br />
:*管理和其他用户之间的订阅和被订阅<br />
:*管理联系人列表中的条目(在 XMPP 中这被称为 "roster")<br />
:*屏蔽和特定的其他用户之间的通信(出或入)<br />
<br />
:这些功能领域的详细定义在[IMP-REQS]中, 感兴趣的用户可以直接阅读原文关于需求方面的内容。<br />
<br />
:[IMP-REQS]也规定出席信息服务必须从即时消息服务中分离; 例如, 它必须可能用这个协议来提供一个出席信息服务,一个即时消息服务,或同时提供两者. 尽管本文假定实现和部署希望提供统一的即时消息和出席信息服务, 但没有要求一个服务必须同时提供出席信息服务和即时消息服务, 并且协议也提供了把出席信息服务和即时消息服务分离成为独立服务的可能性.<br />
<br />
:注意: 虽然基于XMPP的即时消息和出席信息符合[IMP-REQS]的要求,但它不是特意为那个协议设计的,因为基础协议是在RFC 2779成文之前通过Jabber开放源代码社区的一个开放的开发过程发展出来的. 也请注意尽管在Jabber社区发展的协议中定义了许多其他方面的功能,但是这些协议不包含在本文之中,因为它们不是[IMP-REQS]所要求的.<br />
<br />
===术语===<br />
<br />
:本文继承了 [XMPP-CORE|XMPP文档列表/XMPP正式RFC标准/RFC3920]定义的术语.<br />
<br />
:大写关键字 "MUST", "MUST NOT", "REQUIRED", "SHALL", "SHALL NOT", "SHOULD", "SHOULD NOT", "RECOMMENDED", "MAY", 和 "OPTIONAL" 在本文中的含义定义在 BCP 14, RFC 2119 [TERMS].<br />
<br />
==XML 节的语法==<br />
<br />
:符合'jabber:client'和'jabber:server'名字空间的XML节的基本语义和通用属性已经在[XMPP-CORE|XMPP文档列表/XMPP正式RFC标准/RFC3920]中定义了. 无论如何, 这些名字空间也定义了一些其他的子元素, 比如通用属性'type'的值, 对于即时消息和出席信息应用就是特殊的. 因而, 在选择用于这类应用的特定用例之前, 我们在这里需要先描述一下XML节的语法, 用来补充[XMPP-CORE|XMPP文档列表/XMPP正式RFC标准/RFC3920]中的讨论.<br />
<br />
===消息语法===<br />
<br />
:符合'jabber:client' or 'jabber:server'名字空间的消息节用于"推" 信息到另一个实体. 在即时消息应用中通常的用法是包含,一个单独的消息,在一个聊天会话中的消息,一个多用户聊天室的上下文中的消息,标题或其他警告和错误的消息,<br />
<br />
====消息的类型====<br />
<br />
:一个消息节的'type' 属性是建议的(RECOMMENDED); 如果包含了它,它指明这个消息的会话上下文,从而提供一个关于表达的线索(例如, 在一个GUI中). 如果包含了它, 'type' 属性必须(MUST)是以下的值之一 :<br />
<br />
:*chat -- 消息是在一对一聊天会话的语境被发送. 一个兼容的客户端应该(SHOULD)在一个允许两个实体进行一对一聊天的界面中显示消息,包括适当的会话历史.<br />
<br />
:*error -- 发生了一个和上次发送者发送的消息有关的错误(关于节错误语法的详细信息, 参考 [XMPP-CORE|XMPP文档列表/XMPP正式RFC标准/RFC3920]). 一个兼容客户端应该(SHOULD)在一个适当的界面展示它以通知发送者这个错误的种类. <br />
<br />
:*groupchat -- 消息是在一个多用户聊天环境的语境下发送的(类似[IRC]). 一个兼容客户端应该(SHOULD)在允许多对多聊天的界面显示这个消息,包括, 包括这个聊天室的名册和适当的会话历史. 基于XMPP的群聊协议的完整定义超出了本文的范围.<br />
<br />
:*headline -- 一个消息可能是由一个递送或广播内容的自动化服务生成的(新闻, 体育, 市场信息, RSS feeds, 等等.). 这个消息是不需要回复的, 一个兼容客户端应该(SHOULD) 在一个适当的和单独消息,聊天会话,或群聊会话不同的界面显示这个消息(例如, 不给接收者提供回复能力).<br />
<br />
:*normal -- 这个消息是一个在一对一会话或群聊会话之外的单独消息, 并且它希望接收者能够回复.一个兼容客户端应该(SHOULD)在一个允许接收者回复的界面显示这个消息, 但不需要会话历史.<br />
<br />
:一个 IM 应用应该(SHOULD)支持所有前述的消息类型;如果一个应用接收了一个没有'type'属性的消息或这个应用不理解'type'属性的值, 它必须(MUST)认为这个消息是一个 "normal" 类型(如,"normal" 是缺省的). "error"类型必须(MUST)仅仅在应答一个和从别的实体接收到的消息有关的错误时生成.<br />
<br />
:尽管'type'属性是可选的(OPTIONAL), 处于礼貌原因对于消息的任何回复总是和原来的消息同一类型;此外, 一些特殊的应用(例如, 一个多用户聊天服务) 可以(MAY)根据它们的判断强制特定消息类型的使用(例如, type='groupchat').<br />
<br />
====子元素====<br />
<br />
:正如 扩展名字空间extended namespaces(第二章第四节)所述, 一个消息节可以(MAY)包含任何适当名字空间的子元素.<br />
<br />
:和缺省名字空间声明一致, 缺省消息节的名字空间是'jabber:client' 或 'jabber:server', 定义了某几个允许的消息节的子元素. 如果消息节的类型是 "error", 它必须(MUST)包含一个<error/>子元素; 详细情况, 见[XMPP-CORE|XMPP文档列表/XMPP正式RFC标准/RFC3920]. 否则, 消息节可以(MAY)包含以下子元素的任何一种并且无需显式地声明名字空间:<br />
<br />
:#<subject/><br />
:#<body/><br />
:#<thread/><br />
<br />
=====主题=====<br />
<br />
:<subject/> 元素包含了人类可读的 XML 字符数据指明这个消息的主题. <subject/>元素不能(MUST NOT)拥有任何属性, 除了'xml:lang'属性. <subject/> 元素可以(MAY)包含多个实例用于为同一主题提供备用版本, 但是仅在每个实例的拥有的'xml:lang'属性的值互不相同的时候才可以. <subject/> 元素不能(MUST NOT)包含混合的内容(定义在 [XML]第三章第二节第二小节).<br />
<br />
=====主体=====<br />
<br />
:<body/> 元素包含人类可读的XML字符数据表达消息的文本内容; 这个子元素通常会有但是是可选的(OPTIONAL). <body/>元素不能(MUST NOT)拥有任何属性, 除非是'xml:lang'属性. <body/> 元素可以(MAY)包含多个实例用于为同一主体提供备用版本, 但是仅在每个实例的拥有的'xml:lang'属性的值互不相同的时候才可以. <body/>元素不能(MUST NOT)包含混合的内容(定义在 [XML]第三章第二节第二小节). <br />
<br />
=====线索=====<br />
<br />
:<thread/> 元素包含非人类可读的XML字符数据表达一个标识符用于跟踪两个实体之间的一个会话线索(有时相当于一个"即时消息会话"). <thread/>元素的值是由发送者生成的并且应该(SHOULD)在任何回复中拷贝回来. 如果使用了它, 它必须(MUST)在这个流的会话线索中是唯一的并且必须(MUST)和那个会话相一致(一个从同一个全JID但不同线索ID接收到消息的客户端必须(MUST)假定这个有问题的消息存在于已有的会话线索之外. <thread/>元素的使用是可选的(OPTIONAL)并且不是用于标识独立的消息,而是标识会话. 一个消息节不能(MUST NOT)包含超过一个的<thread/>元素. <thread/>元素不能(MUST NOT)拥有任何属性. <thread/>属性的值必须(MUST)被实体处理成不透明的; 不能从它得到任何语义学上的含义,并且只能对它做精确的比较. <thread/>元素不能(MUST NOT)包含混合内容(定义在 [XML]第三章第二节第二小节).<br />
<br />
===出席信息语法===<br />
<br />
:符合'jabber:client' 或 'jabber:server'名字空间的出席信息节用于表达一个实体当前的网络可用性(离线或在线, 包括之后的各种亚状态和可选的用户名义的描述性文本), 并且通知其他实体它的可用性. 出席信息节也用于协商和管理对于其他实体的出席信息的订阅.<br />
<br />
====出席信息的类型====<br />
<br />
:出席信息节的'type'属性是可选的(OPTIONAL). 一个不拥有任何'type'属性的出席信息节用来通知服务器发送者已经在线并且可以进行通信了, 'type' 属性表示缺乏可用性, 请求管理对其他实体的出席信息的订阅, 请求其他实体的当前出席信息, 或发生了和上次发出的出席信息节有关的错误. 如果包含了它, 'type'属性必须(MUST)拥有以下值之一:<br />
<br />
:*unavailable -- 通知实体将不可通信.<br />
<br />
:*subscribe -- 发送者希望订阅接收者的出席信息.<br />
<br />
:*subscribed -- 发送者允许接收者接收他们的出席信息.<br />
<br />
:*unsubscribe -- 发送者取消订阅另一个实体的出席信息.<br />
<br />
:*unsubscribed -- 订阅者的请求被拒绝或以前的订阅被取消.<br />
<br />
:*probe -- 对一个实体当前的出席信息的请求; 只应(SHOULD)由服务器代替一个用户生成.<br />
<br />
:*error -- 处理或递送之前发送的出席信息节的时候发生了错误.<br />
<br />
:关于出席信息语义学的详细信息和基于XMPP的即时消息和出席信息应用程序的订阅模式,参考 交换出席信息Exchanging Presence Information(第五章) 和 管理订阅Managing Subscriptions(第六章).<br />
<br />
====子元素====<br />
<br />
:如 扩展名字空间extended namespaces(第二章第四节)所述, 一个出席信息节可以(MAY)包含任何适当名字空间的子元素.<br />
<br />
:和缺省名字空间声明一致, 缺省出席信息节的名字空间是'jabber:client' 或 'jabber:server', 定义了某几个允许的出席信息节的子元素. 如果出席信息节的类型是 "error", 它必须(MUST)包含一个<error/>子元素; 详细情况, 见[XMPP-CORE|XMPP文档列表/XMPP正式RFC标准/RFC3920]. 如果出席信息节不拥有'type'属性,它可以(MAY)包含以下任何子元素(注意<status/>子元素可以(MAY)在一个类型为"unavailable"或"subscribe"(出于历史原因)的出席信息中被发送):<br />
<br />
:#<show/><br />
:#<status/><br />
:#<priority/><br />
<br />
=====展示=====<br />
<br />
:可选的(OPTIONAL)<show/>元素包含非人类可读的XML字符数据表达一个特定的实体或资源的特定的可用性状态. 一个出席信息节不能(MUST NOT)包含多于一个<show/>元素. <show/>元素不能(MUST NOT)拥有任何属性. 如果提供了, 这个XML字符数据值必须(MUST)是以下之一(额外的可用性类型可以通过出席信息的适当名字空间来定义):<br />
<br />
:*away -- 实体或资源临时离开.<br />
<br />
:*chat -- 实体或资源在聊天中是激活的.<br />
<br />
:*dnd -- 实体或资源是忙(dnd = "不要打扰").<br />
<br />
:*xa -- 实体或资源是长时间的离开(xa = "长时间离开").<br />
<br />
:如果没有提供<show/>元素, 实体被假定是在线和可用的.<br />
<br />
=====状态=====<br />
<br />
:可选的(OPTIONAL)<status/>元素包含XML字符数据表达一个可用性状态的自然语言描述. 它通常用于联合show元素以提供可用性状态的详细描述(例如, "会议中"). <status/>元素不能(MUST NOT)拥有任何属性,除了'xml:lang'属性. <status/>元素可以(MAY)包含多个实例但是每个实例的'xml:lang'属性值必须各不相同.<br />
<br />
=====优先权=====<br />
<br />
:可选的(OPTIONAL)<priority/>元素包含非人类可读的XML字符数据指明资源的优先级别. 这个值必须(MUST)是一个介于-128和+127之间的数字. 一个出席信息小节不能(MUST NOT)包含超过一个的<priority/>元素. <priority/>元素不能(MUST NOT)拥有任何属性. 如果没有优先权被提供,一个服务器应该(SHOULD)认为优先级是零. 关于即时消息和出席信息系统中节路由的优先级的语义, 参考 处理XML节的服务器规则Server Rules for Handling XML Stanzas(第十一章).<br />
<br />
===IQ语法===<br />
<br />
:IQ节提供一个结构化的请求-应答机制. 这个机制的基本语义学(例如, 'id'属性是必需的(REQUIRED))定义在[XMPP-CORE|XMPP文档列表/XMPP正式RFC标准/RFC3920], 然而完成特定用例所需要的特定语义的所有案例定义在扩展名字空间extended namespace(第二章第四节)之中(注意'jabber:client'和'jabber:server'名字空间没有定义除通用的<error/>子元素之外的任何IQ节子元素). 本文定义了两个这样的名字空间,一个用于 名册管理Roster Management(第七章)而另一个用于 屏蔽通信Blocking Communication(第十章); 无论如何, 一个IQ节可以(MAY)包含符合任何扩展名字空间的结构化信息.<br />
<br />
===扩展名字空间===<br />
<br />
:因为在"jabber:client"或"jabber:server"名字空间中定义的三个XML节类型(也包括它们的属性和子元素)提供了一个基本功能级用于消息和出席信息, XMPP使用XML名字空间来扩展节用于提供额外的功能, 所以一个消息或出席信息节可以(MAY)包含一个或更多可选的子元素表达扩展消息含义的内容(例如, 一个XHTML格式版本的消息主体), 并且一个IQ节可以(MAY)包含一个这样的子元素. 这个子元素可以(MAY)有任何名字并且可以(MUST)拥有一个'xmlns'名字空间声明(不同于"jabber:client", "jabber:server", 或"http://etherx.jabber.org/streams")定义所有包含在子元素中的数据.<br />
<br />
:对于任何特定的扩展名字空间的支持在任何实现中的一部分是可选的(OPTIONAL)(除了在这里定义的扩展名字空间以外). 如果一个实体不理解这样一个名字空间, 实体被期望的行为依赖于这个实体是(1) 接收者 或 (2) 一个正在路由到接收者的实体<br />
<br />
:接收者: 如果一个接收者接收了一个包含不理解的子元素的节, 它应该(SHOULD)忽略那个特定的XML数据,例如, 它应该(SHOULD)不处理它或不向用户或相关的应用程序(如果有的话)显示它. 具体来说:<br />
<br />
::*如果一个实体接收了一个消息或出席信息节包含一个不理解的名字空间, 在节的未知名字空间的这部分应该(SHOULD)被忽略.<br />
<br />
::*如果一个实体接收了一个消息节中仅有的一个子元素是不理解的, 它必须(MUST)忽略整个节.<br />
<br />
::*如果一个实体接收了一个类型"get"或"set"的IQ节包含一个不理解的子元素, 这个实体应该(SHOULD)返回一个类型为"error"的<service-unavailable/>错误条件的IQ节.<br />
<br />
:路由: 如果一个路由实体(通常是一个服务器)处理一个包含它不理解的子元素的节, 它应该(SHOULD)原封不动地把它转给接收者而忽略相关的XML数据.<br />
<br />
==会话的建立==<br />
<br />
:绝大部分基于XMPP的消息和出席信息应用是由一个客户端-服务器体系结构实现的,为了参加期望的即时消息和出席信息活动,需要客户端在服务器上建立一个会话. 无论如何, 在客户端能够建立一个即时消息和出席信息会话之前有很多前提必须(MUST)满足. 它们是:<br />
<br />
:#流验证 -- 客户端在尝试建立一个会话或发送任何XML节之前必须(MUST)完成[XMPP-CORE|XMPP文档列表/XMPP正式RFC标准/RFC3920]中定义的流验证.<br />
:#资源绑定 -- 完成流验证之后, 一个客户端必须(MUST)绑定一个资源到流上,使得客户端的地址符合<user@domain/resource>格式, 然后实体以[XMPP-CORE|XMPP文档列表/XMPP正式RFC标准/RFC3920]规定的术语来说就是一个 已连接的资源"connected resource".<br />
<br />
:如果一个服务器支持会话, 在完成一个[XMPP-CORE|XMPP文档列表/XMPP正式RFC标准/RFC3920]定义的流验证之后它必须(MUST)在它向客户端声明的流特性中包含一个符合'urn:ietf:params:xml:ns:xmpp-session'名字空间的<session/>元素:<br />
<br />
:服务器向客户端声明会话确定特性:<br />
<br />
<source lang="xml"><br />
<stream:stream<br />
xmlns='jabber:client'<br />
xmlns:stream='http://etherx.jabber.org/streams'<br />
id='c2s_345'<br />
from='example.com'<br />
version='1.0'><br />
<stream:features><br />
<bind xmlns='urn:ietf:params:xml:ns:xmpp-bind'/><br />
<session xmlns='urn:ietf:params:xml:ns:xmpp-session'/><br />
</stream:features><br />
</source><br />
<br />
:收到需要会话确立的通知之后(并且是在完成资源绑定之后), 客户端如果想使用即时消息和出席信息功能必须(MUST)建立一个会话; 它向服务器发送一个符合'urn:ietf:params:xml:ns:xmpp-session'名字空间的类型为"set"并包含空的<session/>子元素的IQ节以完成这一步骤:<br />
<br />
:步骤 1: 客户端向服务器请求会话:<br />
<br />
<source lang="xml"><br />
<iq to='example.com'<br />
type='set'<br />
id='sess_1'><br />
<session xmlns='urn:ietf:params:xml:ns:xmpp-session'/><br />
</iq><br />
</source><br />
<br />
:步骤 2: 服务器通知客户端会话已经建立:<br />
<br />
<source lang="xml"><br />
<iq from='example.com'<br />
type='result'<br />
id='sess_1'/><br />
</source><br />
<br />
:建立会话之后, 一个 已连接的资源([XMPP-CORE|XMPP文档列表/XMPP正式RFC标准/RFC3920]术语)就被称为一个 激活的资源"active resource".<br />
<br />
:许多错误条件是可能的. 例如, 服务器可能遭遇一个内部条件阻碍了它建立会话, 用户名或授权身份可能缺乏建立会话的许可, 或同一个名字相关的这个资源ID已经有一个激活的资源.<br />
<br />
:如果服务器遭到一个内部条件阻碍了它建立会话, 它必须(MUST)返回一个错误.<br />
<br />
:步骤 2 (替代): 服务器应答一个错误(内部服务器错误):<br />
<br />
<source lang="xml"><br />
<iq from='example.com' type='error' id='sess_1'><br />
<session xmlns='urn:ietf:params:xml:ns:xmpp-session'/><br />
<error type='wait'><br />
<internal-server-error<br />
xmlns='urn:ietf:params:xml:ns:xmpp-stanzas'/><br />
</error><br />
</iq><br />
</source><br />
<br />
:如果用户名或资源不被允许建立一个会话, 服务器必须(MUST)返回一个错误(例如, 被禁止).<br />
<br />
:步骤 2 (替代): 服务器应答错误(用户名或资源不被允许建立一个会话):<br />
<br />
<source lang="xml"><br />
<iq from='example.com' type='error' id='sess_1'><br />
<session xmlns='urn:ietf:params:xml:ns:xmpp-session'/><br />
<error type='auth'><br />
<forbidden<br />
xmlns='urn:ietf:params:xml:ns:xmpp-stanzas'/><br />
</error><br />
</iq><br />
</source><br />
<br />
:如果同一名字已经存在一个激活的资源,服务器必须(MUST) (1) 终止这个激活的资源并允许新请求的会话, 或者 (2) 不允许新申请的会话并继续激活的资源. 服务器做哪一步取决于具体的实现, 尽管建议的(RECOMMENDED)实现 情景 #1. 在 情景 #1, 服务器应该(SHOULD)发送一个<conflict/>流错误给激活的资源, 终止用于这个激活的资源的XML流和相关的TCP连接, 并返回一个类型为"result" 的IQ节(表示成功)给新申请的会话. 在 情景 #2, 服务器应该(SHOULD)发送一个<conflict/>节错误给新申请的会话但是继续那个连接的XML流使得新申请的会话在发送另一个会话建立申请之前有机会协商出一个不冲突的资源ID.<br />
<br />
:步骤 2 (替代): 服务器通知现有的激活的资源 资源冲突(情景 #1):<br />
<br />
<source lang="xml"><br />
<stream:error><br />
<conflict xmlns='urn:ietf:params:xml:ns:xmpp-streams'/><br />
</stream:error><br />
</stream:stream><br />
</source><br />
<br />
:步骤 2 (替代): 服务器通知新申请的的会话资源冲突(情景 #2):<br />
<br />
<source lang="xml"><br />
<iq from='example.com' type='error' id='sess_1'><br />
<session xmlns='urn:ietf:params:xml:ns:xmpp-session'/><br />
<error type='cancel'><br />
<conflict xmlns='urn:ietf:params:xml:ns:xmpp-stanzas'/><br />
</error><br />
</iq><br />
</source><br />
<br />
:建立一个会话之后, 客户端应该(SHOULD)按以下描述来发送初始化出席信息并请求它的名册, 尽管这些动作是可选的(OPTIONAL).<br />
<br />
:注意: 在允许建立即时消息和出席信息会话之前, 一个服务器可能(MAY)需要先提供帐号. 可能的提供帐号的方法包括由服务器管理员新建帐号以及使用'jabber:iq:register'名字空间进行带内帐号注册; 后一个方法超出了本文的范围, 但是记录在[JEP-0077](译者注:这个协议已改名为 XEP-0077), 由 Jabber Software Foundation [JSF]发行(译者注:这个组织也已改名为XSF).<br />
<br />
==交换消息==<br />
<br />
:交换消息是XMPP的一个基本用途并且随之而来的是一个用户生成一个发给另一个实体的消息节. 正如 用于处理XML节的服务器规则Server Rules for Handling XML Stanzas(第十一章)中所定义的 , 发送者的服务器负责递送消息给预定的接收者(如果接收者在同一个服务器上)或路由消息给接收者的服务器(如果接收者在不同的服务器上).<br />
<br />
:关于消息节的语法和它们已定义的属性和子元素信息, 参考 消息语法Message Syntax(第二章第一节).<br />
<br />
===指明一个预定的接收者===<br />
<br />
:一个即时消息客户端应该(SHOULD)通过提供一个JID或<message/>节中不同于发送者的'to'属性来指定一个消息的预定接收者. 如果这个消息是在回复之前接收到的消息,而接收到的消息是从JID格式为<user@domain/resource>(例如,在一个聊天会话的上下文中)实体发来的, 这个回复消息的'to'地址的值应该(SHOULD)是<user@domain/resource>而不是<user@domain>,除非发送者知道(通过出席信息)预定的接收者的资源将不再可用. 如果消息是在任何现存的聊天会话或接收到的消息之外被发送的,'to'地址的值应该(SHOULD)格式为<user@domain>而不是<user@domain/resource>.<br />
<br />
===指定一个消息类型===<br />
<br />
:大家知道, 对于一个消息节来说拥有'type'属性(它的值代表了消息的会话上下文(参见 Type(第二章第一节第一小节)))是建议的(RECOMMENDED).<br />
<br />
:以下例子展示一个'type'属性的合法值:<br />
<br />
:例子: 一个已定义类型的消息:<br />
<br />
<source lang="xml"><br />
<message<br />
to='romeo@example.net'<br />
from='juliet@example.com/balcony'<br />
type='chat'<br />
xml:lang='en'><br />
<body>Wherefore art thou, Romeo?</body><br />
</message><br />
</source><br />
<br />
===指定一个消息主体===<br />
<br />
:一个消息节可以(MAY)(并且经常会)包含一个<body/>子元素,它的XML字符数据表达消息的主要含义(见 Body(第二章第一节第二小节第二小小节)).<br />
<br />
:例子: 一个带主体的消息:<br />
<br />
<source lang="xml"><br />
<message<br />
to='romeo@example.net'<br />
from='juliet@example.com/balcony'<br />
type='chat'<br />
xml:lang='en'><br />
<body>Wherefore art thou, Romeo?</body><br />
<body xml:lang='cz'>Pro&#x010D;e&#x017D; jsi ty, Romeo?</body><br />
</message><br />
</source><br />
<br />
===指定一个消息主题===<br />
<br />
:一个消息节可以(MAY)包含一个或多个<subject/>子元素指明消息的主题(见 Subject(第二章第一节第二小节第一小小节)).<br />
<br />
:例子: 一个带主题的消息:<br />
<br />
<source lang="xml"><br />
<message<br />
to='romeo@example.net'<br />
from='juliet@example.com/balcony'<br />
type='chat'<br />
xml:lang='en'><br />
<subject>I implore you!</subject><br />
<subject<br />
xml:lang='cz'>&#x00DA;p&#x011B;nliv&#x011B; prosim!</subject><br />
<body>Wherefore art thou, Romeo?</body><br />
<body xml:lang='cz'>Pro&#x010D;e&#x017D; jsi ty, Romeo?</body><br />
</message><br />
</source><br />
<br />
===指定一个会话线索===<br />
<br />
:一个消息可以(MAY)包含一个<thread/>子元素指定消息处于哪个会话线索, 用于跟踪会话(见 Thread(第二章第一节第二小节第三小小节)).<br />
<br />
:例子: 一个带线索的会话:<br />
<br />
<source lang="xml"><br />
<message<br />
to='romeo@example.net/orchard'<br />
from='juliet@example.com/balcony'<br />
type='chat'<br />
xml:lang='en'><br />
<body>Art thou not Romeo, and a Montague?</body><br />
<thread>e0ffe42b28561960c6b12b944a092794b9683a38</thread><br />
</message><br />
<message<br />
to='juliet@example.com/balcony'<br />
from='romeo@example.net/orchard'<br />
type='chat'<br />
xml:lang='en'><br />
<body>Neither, fair saint, if either thee dislike.</body><br />
<thread>e0ffe42b28561960c6b12b944a092794b9683a38</thread><br />
</message><br />
<message<br />
to='romeo@example.net/orchard'<br />
from='juliet@example.com/balcony'<br />
type='chat'<br />
xml:lang='en'><br />
<body>How cam'st thou hither, tell me, and wherefore?</body><br />
<thread>e0ffe42b28561960c6b12b944a092794b9683a38</thread><br />
</message><br />
</source><br />
<br />
==交换出席信息==<br />
<br />
:交换出席信息通过使用出席信息节直接和XMPP相关. 无论如何, 我们看到在这里和消息处理形成一个对比:尽管一个客户端可以(MAY)通过包含一个'to'地址直接给另一个实体发送出席信息, 通常出席信息通知(例如,不包含'type'的或类型为"unavailable"的并且没有'to'地址的出席信息节) 被客户端发送给它的服务器然后由服务器广播给任何订阅了发送实体的出席信息的实体(在 RFC 2778 [IMP-MODEL]术语中, 这些实体称为订阅者). 这个广播模式不适用于和订阅相关的节或类型为"error"的出席信息, 而仅适用于以上定义的出席信息通知. (注意: 虽然出席信息可以(MAY)由一个自动化服务代替用户提供, 通常它还是由用户的客户端提供.)<br />
<br />
:关于出席信息节的语法以及它们的已定义的属性和子元素的信息, 参考[XMPP-CORE|XMPP文档列表/XMPP正式RFC标准/RFC3920].<br />
<br />
===客户端和服务器出席信息职责===<br />
<br />
====初始化出席信息====<br />
<br />
:建立起一个会话之后, 一个客户端应该(SHOULD)发送初始化出席信息给服务器来通知它的通信可用性.如这里定义的, 初始化出席信息节 (1) 必须(MUST) 不拥有'to'地址(这表示它是由服务器代替客户端发送的广播) 并且 (2) 必须(MUST) 不拥有'type'属性(者表示拥护的可用性). 在发送初始化出席信息之后, 一个激活的资源被称为 可用的资源"available resource".<br />
<br />
:从一个客户端接收到初始化出席信息之后, 如果这个用户没有一个或更多的已存在的可用资源(如果这个用户已经有一个或更多可用的资源, 服务器明显不需要发送出席信息探测, 因为它已经拥有需要的信息),用户的服务器必须(MUST)做以下的步骤:<br />
<br />
:#从用户的全JID(例如,<user@example.com/resource>)发送出席信息探针(例如, 'type'属性值为'probe'的出席信息节)给已被这个用户订阅了的所有联系人以确定它们是否可用; 这些联系人就是那些显示在用户的名册中的JID并且'subscription'属性值为"to"或"both"(注意: 用户的服务器不能(MUST NOT)发送出席信息探针给用户已经屏蔽入站出席信息通知的联系人, 具体的描述在 屏蔽入站出席信息通知Blocking Inbound Presence Notifications(第十章第十节).)<br />
:#从用户的全JID (e.g.,<user@example.com/resource>)广播初始化出席信息给所有订阅了该用户的出席信息的联系人; 这些联系人就是那些显示在用户的名册中的JID并且'subscription'属性值为"from"或"both"(注意: 用户的服务器不能(MUST NOT)发送出席信息探针给用户已经屏蔽出站出席信息通知的联系人, 具体的描述在 屏蔽出站出席信息通知Blocking Outbound Presence Notifications(第十章第十一节).)<br />
<br />
:另外, 用户的服务器必须(MUST)从用户的新的可用的资源向用户任何现存的可用的资源(如果有的话)广播初始化出席信息.<br />
<br />
:从用户接收到初始化出席信息之后, 联系人的服务器必须(MUST)递送这个用户的出席信息节给所有联系人的可用资源相应的全JID(<contact@example.org/resource>), 但是仅适用于用户在联系人名册中并且订阅状态为"to"或"both"并且联系人的纯JID或全JID没有被屏蔽入站出席信息通知(定义在 屏蔽入站出席信息通知Blocking Inbound Presence Notifications(第十章第十节)).<br />
<br />
:如果用户的服务器接收到一个类型为"error"的出席信息节,而这个节是用来回复服务器代替用户向联系人发送的初始化出席信息, 它不应该(SHOULD NOT)发送更多的出席信息更新给那个联系人(直到并且除非它从这个联系人接收到一个出席信息节).<br />
<br />
====出席信息广播====<br />
<br />
:发送初始化出席信息之后, 用户可以(MAY)在任何时候更新它的出席信息,方法是在会话期间发送一个没有'to'地址也没有'type'属性的出席信息节或'type'属性值为"unavailable"的出席信息节.(注意:一个用户的客户端不应该(SHOULD NOT)发送一个出席信息更新来自行广播用户出席信息和可用性的改变信息.)<br />
<br />
:如果出席信息节缺乏'type'属性(例如, 表达可用性), 用户的服务器必须(MUST)广播那个出席信息节的全XML给所有联系人(满足以下三点) (1) 它们在用户的联系人名册中并且订阅类型是"from"或"both", (2) 用户对于这些联系人没有屏蔽出站出席信息通知, 并且 (3) 服务器在用户的会话期间没有从它们那里接收到出席信息错误(同样适用于这个用户的其他可用的资源).<br />
<br />
:如果出席信息节的'type'属性值是"unavailable", 用户的服务器必须(MUST)广播那个出席信息节的全XML给所有符合以上描述的实体, 也适用于用户曾经在会话过程中直接发送了可用出席信息的任何实体(如果用户还没来得及直接发送不可用出席信息给那个实体).<br />
<br />
====出席信息调查====<br />
<br />
:从用户接收到一个出席信息调查之后, 联系人的服务器应该(SHOULD)应答如下:<br />
<br />
:#如果用户联系人的名册中的状态不是 "From", "From + Pending Out", 或 "Both" (定义在 订阅状态Subscription States(第九章)), 联系人的服务器必须(MUST)返回一个类型为"error"的出席信息节应答这个出席信息调查 (无论如何, 如果一个服务器从这个服务器的主机名的子域或其他信任的服务接收到一个出席信息调查, 它可以(MAY)提供这个用户的出席信息给那个实体). 具体来说:<br />
:##如果用户在联系人的名册中的订阅状态是 "None", "None + Pending Out", 或 "To" (或根本不在联系人的名册中), 联系人的服务器必须(MUST)返回一个<forbidden/>节错误应答这个出席信息调查.<br />
:##如果用户在联系人的名册中的订阅状态是 "None + Pending In", "None + Pending Out/In", 或 "To + Pending In", 联系人的服务器必须(MUST)返回一个<not-authorized/>节错误应答这个出席信息调查.<br />
:#其次, 如果联系人对这个用户的纯JID或全JID屏蔽了出席信息通知(使用缺省列表或激活列表,定义在 屏蔽出站出席信息通知Blocking Outbound Presence Notifications (第十章第十一节)), 服务器不能(MUST NOT)应答这个出席信息调查.<br />
:#然后, 如果联系人没有可用的资源, 服务器必须(MUST) 要么 (1) 应答这个出席信息调查, 向这个用户发送服务器从联系人接收到的最后的类型为"unavailable"的出席信息节的全XML, 或 (2) 不应答.<br />
:#最后, 如果联系人至少有一个可用的资源, 服务器必须(MUST)应答这个出席信息调查, 向这个用户发送服务器从联系人的每一个可用的资源收到的最后的没有'to'属性的出席信息节的全XML (再一次的,对于每一个会话都要强制服从隐私列表).<br />
<br />
====直接出席信息====<br />
<br />
:一个用户可以(MAY)直接发送出席信息给另一个实体 (例如, 一个出席信息节,包含'to'属性并且值为另一个实体的JID并且没有'type'属性或'type'属性值为"unavailable"). 可能出现三种情形:<br />
<br />
:#如果用户在已经发送过初始化出席信息广播之后,发送不可用信息广播之前,直接发送出席信息给它的名册中一个订阅状态为"from" 或 "both"的联系人, 这个用户的服务器必须(MUST)路由或递送这个出席信息节的全XML(服从隐私列表)但是不应该(SHOULD NOT) 根据出席信息广播修改联系人的状态(例如, 它应该(SHOULD)在任何接下来的由用户初始化的出席信息广播包含这个联系人的JID).<br />
:#如果用户在已经发送过初始化出席信息广播之后,发送不可用信息广播之前,直接发送出席信息给一个不在用户名册中的实体并且其订阅状态为"from" 或 "both", 这个用户的服务器必须(MUST)路由或递送这个出席信息节的全XML(服从隐私列表)但是不能(MUST NOT) 根据可用性的出席信息广播来修改这个联系人的状态(例如, 它不能(MUST NOT)在任何接下来的由用户初始化的可用性的出席信息广播中包含这个联系人的JID); 无论如何, 如果无法从用户的可用的资源直接发送出席信息, 用户的服务器必须( MUST)广播不可用出席信息给那个实体(如果这个用户还没有直接发送不可用出席信息给那个实体).<br />
:#如果用户不是在已经发送过初始化出席信息广播之后,或在发送不可用信息广播之前,直接发送出席信息(例如, 资源激活了但是还不可用), 用户的服务器必须(MUST)认为用户向其直接发送出席信息的这个实体视为上述第二种情形中的那个实体,采用相同的处理方式.<br />
<br />
====不可用出席信息====<br />
<br />
:在和一个服务器结束它的会话之前, 客户端应该(SHOULD)雅致地成为不可用的,发送一个最后的没有'to'属性并且'type'属性值为"unavailable"的出席信息节(可选的, 最后的出席信息节可以(MAY)包含一个或多个<status/>元素以指明为什么用户不再可用). 无论如何, 用户的服务器不能(MUST NOT)依赖于从一个可用的资源接收最后的出席信息, 因为资源可能意外的变成不可用或可能被服务器判定超时. 如果用户的资源之一因为任何原因成为不可用的(包括雅致的或粗鲁的), 用户的服务器必须(MUST)广播不可用出席信息给所有如下的联系人 (1) 在用户的名册中并且订阅类型为 "from" 或 "both", (2) 用户没有对它们屏蔽出站出席信息的联系人, 以及 (3) 用户会话期间,服务器没有从它们那里收到出席信息错误的联系人; 用户的服务器也必须(MUST)发送不可用出席信息节给这个用户的任何其他可用的资源, 以及任何用户的资源曾经在会话期间直接向其发送过出席信息的实体(如果用户还没有直接发送不可用出席信息给那个实体). 在直接发送或广播不可用出席信息之后发送的任何没有'type'属性也没有'to'属性的出席信息节必须(MUST)由服务器广播给所有订阅者.<br />
<br />
====出席信息订阅====<br />
<br />
:一个订阅请求就是一个'type'属性值为"subscribe"的出席信息节. 如果订阅请求被发送给一个即时消息联系人, 在'to'属性中提供的JID的格式应该(SHOULD)是<contact@example.org>而不是<contact@example.org/resource>, 因为用户期望的结果通常是从联系人的所有资源接收到出席信息, 而不仅是'to'属性中的特定资源.<br />
<br />
:一个用户的服务器不能(MUST NOT)代替用户自动批准订阅请求. 所有订阅申请必须(MUST)直接发给用户的客户端, 具体来说就是这一用户的一个或多个可用的资源. 如果当订阅申请被用户的服务器接收到的时候没有这个用户的可用资源, 用户的服务器必须(MUST)保持这个订阅申请的记录并且在用户下次建立一个可用的资源时递送这个订阅申请, 直到这个用户批准或拒绝这个请求. 如果如果当订阅申请被用户的服务器接收到的时候这个用户有多于一个的可用资源, 用户的服务器必须(MUST)广播这个订阅申请给所有可用的资源(根据 处理XML节的服务器规则Server Rules for Handling XML Stanzas(第十一章)). (注意: 如果一个激活的资源还没有提供初始化出席信息, 服务器不能(MUST NOT)认为它是可用的并且因而不能(MUST NOT)发送订阅申请给它.) 无论如何, 如果用户从一个它已授权可以看到用户的出席信息的联系人那里收到一个类型为"subscribe"的出席信息节(例如, 当一个联系人重新同步订阅状态的时候),用户的服务器应该(SHOULD)代替用户自动应答. 另外, 用户的服务器可以(MAY)基于一个特定实现的法则(例如, 无论何时当用户的一个新的资源可用的时候, 或在一段特定长度的时间过去之后)选择重新发送一个未批准的未决订阅申请给这个联系人; 这有助于恢复可能和原始订阅申请有关的瞬间的,无声的错误.<br />
<br />
===指明可用性状态===<br />
<br />
:一个客户端可以(MAY)使用<show/>元素提供关于可用性状态的更多信息(参见 Show (第二章第二节第二小节第一小小节)).<br />
<br />
:例子: 可用性状态:<br />
<source lang="xml"><br />
<presence><br />
<br />
<show>dnd</show><br />
<br />
</presence><br />
</source><br />
<br />
===指明详细的可用性状态信息===<br />
<br />
:通过联合<show/>元素, 客户端使用<status/>元素可以(MAY)提供详细的可用性状态信息(参见Status (第二章第二节第二小节第二小小节)).<br />
<br />
:例子: 详细的状态信息:<br />
<br />
<source lang="xml"><br />
<presence xml:lang='en'><br />
<show>dnd</show><br />
<status>Wooing Juliet</status><br />
<status xml:lang='cz'>Ja dvo&#x0159;&#x00ED;m Juliet</status><br />
</presence><br />
</source><br />
<br />
===指明出席信息优先级===<br />
<br />
:客户端可以(MAY)使用<priority/>元素为它的资源提供优先级(参见 Priority (第二章第二节第二小节第三小小节)).<br />
<br />
:例子: 出席信息优先级:<br />
<br />
<source lang="xml"><br />
<presence xml:lang='en'><br />
<show>dnd</show><br />
<status>Wooing Juliet</status><br />
<status xml:lang='cz'>Ja dvo&#x0159;&#x00ED;m Juliet</status><br />
<priority>1</priority><br />
</presence><br />
</source><br />
<br />
===出席信息例子===<br />
<br />
:本章的例子用于阐明上述和出席信息相关的协议. 用户是 romeo@example.net, 他有一个可用的资源, 资源ID为 "orchard", 并且他的名册中有以下这些人:<br />
<br />
:*juliet@example.com (subscription="both" 并且她有两个可用的资源, 一个资源名为"chamber" 而另一个资源名为 "balcony")<br />
<br />
:*benvolio@example.org (subscription="to")<br />
<br />
:*mercutio@example.org (subscription="from")<br />
<br />
:例子 1: 用户发送初始化出席信息:<br />
<br />
<source lang="xml"><br />
<presence/><br />
</source><br />
<br />
:例子 2: 用户的服务器代替用户发送出席信息调查给 subscription="to" 和 subscription="both" 的联系人的可用资源:<br />
<br />
<source lang="xml"><br />
<presence<br />
type='probe'<br />
from='romeo@example.net/orchard'<br />
to='juliet@example.com'/><br />
<presence<br />
type='probe'<br />
from='romeo@example.net/orchard'<br />
to='benvolio@example.org'/><br />
</source><br />
<br />
:例子 3: 用户的服务器代替用户发送初始化出席信息给 subscription="from" 和 subscription="both"的联系人的可用资源:<br />
<br />
<source lang="xml"><br />
<presence<br />
from='romeo@example.net/orchard'<br />
to='juliet@example.com'/><br />
<presence<br />
from='romeo@example.net/orchard'<br />
to='mercutio@example.org'/><br />
</source><br />
<br />
:例子 4: 联系人的服务器代替所有可用的资源应答出席信息调查:<br />
<br />
<source lang="xml"><br />
<presence<br />
from='juliet@example.com/balcony'<br />
to='romeo@example.net/orchard'<br />
xml:lang='en'><br />
<show>away</show><br />
<status>be right back</status><br />
<priority>0</priority><br />
</presence><br />
<presence<br />
from='juliet@example.com/chamber'<br />
to='romeo@example.net/orchard'><br />
<priority>1</priority><br />
</presence><br />
<presence<br />
from='benvolio@example.org/pda'<br />
to='romeo@example.net/orchard'<br />
xml:lang='en'><br />
<show>dnd</show><br />
<status>gallivanting</status><br />
</presence><br />
</source><br />
<br />
:例子 5: 联系人的服务器递送用户的初始化出席信息给所有可用的资源或返回错误给用户:<br />
<br />
<source lang="xml"><br />
<presence<br />
from='romeo@example.net/orchard'<br />
to='juliet@example.com/chamber'/><br />
<presence<br />
from='romeo@example.net/orchard'<br />
to='juliet@example.com/balcony'/><br />
<presence<br />
type='error'<br />
from='mercutio@example.org'<br />
to='romeo@example.net/orchard'><br />
<error type='cancel'><br />
<gone xmlns='urn:ietf:params:xml:ns:xmpp-stanzas'/><br />
</error><br />
</presence><br />
</source><br />
<br />
:例子 6: 用户直接发送出席信息给另一个不在他的名册中的用户:<br />
<br />
<source lang="xml"><br />
<presence<br />
from='romeo@example.net/orchard'<br />
to='nurse@example.com'<br />
xml:lang='en'><br />
<show>dnd</show><br />
<status>courting Juliet</status><br />
<priority>0</priority><br />
</presence><br />
</source><br />
<br />
:例子 7: 用户发送更新的可用出席信息用于广播:<br />
<br />
<source lang="xml"><br />
<presence xml:lang='en'><br />
<show>away</show><br />
<status>I shall return!</status><br />
<priority>1</priority><br />
</presence><br />
</source><br />
<br />
:例子 8: 用户的服务器仅向一个联系人广播更新的出席信息 (不是那些返回错误的联系人,也不是那些用户直接向其发送出席信息的联系人):<br />
<br />
<source lang="xml"><br />
<presence<br />
from='romeo@example.net/orchard'<br />
to='juliet@example.com'<br />
xml:lang='en'><br />
<show>away</show><br />
<status>I shall return!</status><br />
<priority>1</priority><br />
</presence><br />
</source><br />
<br />
:例子 9: 联系人的服务器递送更新的出席信息给联系人所有可用的资源:<br />
<br />
<source lang="xml"><br />
[to "balcony" resource...]<br />
<presence<br />
from='romeo@example.net/orchard'<br />
to='juliet@example.com'<br />
xml:lang='en'><br />
<show>away</show><br />
<status>I shall return!</status><br />
<priority>1</priority><br />
</presence><br />
[to "chamber" resource...]<br />
<presence<br />
from='romeo@example.net/orchard'<br />
to='juliet@example.com'<br />
xml:lang='en'><br />
<show>away</show><br />
<status>I shall return!</status><br />
<priority>1</priority><br />
</presence><br />
</source><br />
<br />
:例子 10: 联系人的资源之一广播最后出席信息:<br />
<br />
<source lang="xml"><br />
<presence from='juliet@example.com/balcony' type='unavailable'/><br />
</source><br />
<br />
:例子 11: 联系人的服务器发送不可用出席信息给用户:<br />
<br />
<source lang="xml"><br />
<presence<br />
type='unavailable'<br />
from='juliet@example.com/balcony'<br />
to='romeo@example.net/orchard'/><br />
</source><br />
<br />
:例子 12: 用户发送最后出席信息:<br />
<br />
<source lang="xml"><br />
<presence from='romeo@example.net/orchard'<br />
type='unavailable'<br />
xml:lang='en'><br />
<status>gone home</status><br />
</presence><br />
</source><br />
<br />
:例子 13: 用户的服务器广播不可用出席信息给联系人,包括用户直接向其发送出席信息的那个人:<br />
<br />
<source lang="xml"><br />
<presence<br />
type='unavailable'<br />
from='romeo@example.net/orchard'<br />
to='juliet@example.com'<br />
xml:lang='en'><br />
<status>gone home</status><br />
</presence><br />
<presence<br />
from='romeo@example.net/orchard'<br />
to='nurse@example.com'<br />
xml:lang='en'><br />
<status>gone home</status><br />
</presence><br />
</source><br />
<br />
==管理订阅==<br />
<br />
:为了保护即时消息用户和任何其他实体的隐私, 出席信息和可用性信息仅向用户已批准的其他实体披露. 当一个用户同意其他用户可以看到它的出席信息, 这个实体被称为对于用户的出席信息有一个订阅. 订阅超越了会话; 实际上, 它一直存在直到订阅者取消订阅或被订阅者取消曾经授权的订阅为止. 在XMPP中订阅是通过发送包含特定属性的出席信息节来管理的.<br />
<br />
:注意: 在订阅和名册之间有重要的交互; 这些定义在 名册条目和出席信息订阅的集成Integration of Roster Items and Presence Subscriptions (第八章), 而且读者必须参考那一章才能完整地理解出席信息订阅.<br />
<br />
===请求一个订阅===<br />
<br />
:对另一个实体的出席信息的订阅请求是由发送一个类型为"subscribe"的出席信息节来开始的.<br />
<br />
:例子: 发送一个订阅请求:<br />
<br />
<source lang="xml"><br />
<presence to='juliet@example.com' type='subscribe'/><br />
</source><br />
<br />
:关于客户端和服务器在订阅请求中的职责, 参考 出席信息订阅Presence Subscriptions(第五章第一节第六小节).<br />
<br />
===处理一个订阅请求===<br />
<br />
:当一个客户端从另一个实体接收到一个订阅请求, 它必须(MUST)批准这个请求(发送一个类型为"subscribed"的出席信息节)或拒绝这个请求(发送一个类型为"unsubscribed"的出席信息节).<br />
<br />
:例子: 批准一个订阅请求:<br />
<br />
<source lang="xml"><br />
<presence to='romeo@example.net' type='subscribed'/><br />
</source><br />
<br />
:例子: 拒绝一个出席信息订阅的请求:<br />
<br />
<source lang="xml"><br />
<presence to='romeo@example.net' type='unsubscribed'/><br />
</source><br />
<br />
===从另一个实体取消一个订阅===<br />
<br />
:如果一个用户想取消一个曾经允许的订阅请求, 它发送一个类型为"unsubscribed"的出席信息节.<br />
<br />
:例子: 取消一个曾经允许的订阅请求:<br />
<br />
<source lang="xml"><br />
<presence to='romeo@example.net' type='unsubscribed'/><br />
</source><br />
<br />
===取消对于另一个实体的出席信息的订阅===<br />
<br />
:如果用户想取消对于另一个实体的出席信息的订阅, 它发送一个类型为"unsubscribe"的出席信息节.<br />
<br />
:例子: 取消对一个实体的出席信息的订阅:<br />
<br />
<source lang="xml"><br />
<presence to='juliet@example.com' type='unsubscribe'/><br />
</source><br />
<br />
==名册管理==<br />
<br />
:在XMPP中, 一个人的联系人列表被称为名册(roster), 它包括任意数量的特定名册条目, 每个名册条目被一个唯一的JID(通常格式是<contact@domain>)所标识. 一个用户的名册由用户的服务器代替用户储存从而这个用户可以从任何资源访问名册信息.<br />
<br />
:注意: 在名册和订阅之间有重要的交互; 这些定义在 名册条目和出席信息订阅的集成Integration of Roster Items and Presence Subscriptions (第八章), 而且读者必须参考那一章才能完整地理解名册管理.<br />
<br />
===语法和语义===<br />
<br />
:名册使用IQ节来管理, 具体来说就是符合'jabber:iq:roster'名字空间的<query/>子元素的含义.这个<query/>元素可以(MAY)包含一个或更多<item/>子元素, 每个描述一个唯一的名册条目或曰 联系人"contact".<br />
<br />
:每个名册条目的"key"或者说唯一标识符就是一个JID,封装在<item/>元素的'jid'属性(它是必需的(REQUIRED))之中. 如果这个条目是和另一个(人类)即时消息用户相关的,'jid'属性的值的格式应该(SHOULD)是<user@domain>.<br />
<br />
:和一个名册条目相关的出席信息订阅的状态从<item/>元素的'subscription'属性可以得到.这个属性允许的值包括:<br />
<br />
:* "none" -- 这个用户没有对这个联系人出席信息的订阅, 这个联系人也没有订阅用户的出席信息<br />
<br />
:* "to" -- 这个用户订阅了这个联系人的出席信息, 但是这个联系人没有订阅用户的出席信息<br />
<br />
:* "from" -- 这个联系人订阅了用户的出席信息, 但是这个用户没有订阅这个联系人的出席信息<br />
<br />
:* "both" -- 用户和联系人互相订阅了对方的出席信息<br />
<br />
:每个<item/>条目可以(MAY)包含一个'name'属性, 它设置和这个JID相关的"nickname", 取决于用户(而不是联系人). 'name'属性的值是不透明的.<br />
<br />
:每个<item/>条目可以(MAY)包含一个或多个<group/>子元素,用于把名册条目收集到多个类别之中. <group/>子元素的XML字符数据是不透明的.<br />
<br />
===商业规则===<br />
<br />
:在一个名册"set"中一个服务器必须(MUST)忽略任何'to'地址, 并且必须(MUST)认为任何名册"set"是应用于发送者的. 为了更多的安全性, 一个客户端应该(SHOULD)检查"roster push"(包含一个名册条目的类型为"set"的输入IQ)的"from"地址以保证它来自一个信任的源; 具体的, 这个节必须(MUST)没有 'from'属性(例如, 从服务器隐含的) 或'from'属性的值匹配用户的纯JID(格式为<user@domain>)或全JID(格式为<user@domain/resource>); 否则, 客户端应该(SHOULD)忽略这个"roster push".<br />
<br />
===登录时接收一个人的名册===<br />
<br />
:在连接到服务器并成为一个激活的资源之后, 一个客户端应该(SHOULD)在发送初始化出席信息之前请求名册(无论如何, 因为可能不是所有的资源都想接收名册, 例如, 一个带宽受限的连接, 客户端对于名册的请求是可选的(OPTIONAL)). 如果一个可用的资源在一个会话期间没有请求名册, 服务器不能(MUST NOT)向它发送出席信息订阅以及相关的名册更新.<br />
<br />
:例子: 客户端向服务器请求当前的名册:<br />
<br />
<source lang="xml"><br />
<iq from='juliet@example.com/balcony' type='get' id='roster_1'><br />
<query xmlns='jabber:iq:roster'/><br />
</iq><br />
</source><br />
<br />
:例子: 客户端从服务器收到名册:<br />
<br />
<source lang="xml"><br />
<iq to='juliet@example.com/balcony' type='result' id='roster_1'><br />
<query xmlns='jabber:iq:roster'><br />
<item jid='romeo@example.net'<br />
name='Romeo'<br />
subscription='both'><br />
<group>Friends</group><br />
</item><br />
<item jid='mercutio@example.org'<br />
name='Mercutio'<br />
subscription='from'><br />
<group>Friends</group><br />
</item><br />
<item jid='benvolio@example.org'<br />
name='Benvolio'<br />
subscription='both'><br />
<group>Friends</group><br />
</item><br />
</query><br />
</iq><br />
</source><br />
<br />
===增加一个名册条目===<br />
<br />
:任何时候, 一个用户可以(MAY)增加一个条目到他或她的名册.<br />
<br />
:例子: 客户端添加一个新的条目:<br />
<br />
<source lang="xml"><br />
<iq from='juliet@example.com/balcony' type='set' id='roster_2'><br />
<query xmlns='jabber:iq:roster'><br />
<item jid='nurse@example.com'<br />
name='Nurse'><br />
<group>Servants</group><br />
</item><br />
</query><br />
</iq><br />
</source><br />
<br />
:服务器必须(MUST)在持久信息存储机构中更新名册信息,并且也要向这个用户的所有已请求名册的可用资源推送这一改变. 这个"名册推送"包括一个类型为"set"的IQ节,从服务器发送给客户端,使用户的所有可用资源保持和基于服务器的名册信息的同步.<br />
<br />
:例子: 服务器 (1) 推送更新的名册信息给所有已请求名册的可用资源 并且 (2) 以一个IO结果应答发送的资源:<br />
<br />
<source lang="xml"><br />
<iq to='juliet@example.com/balcony'<br />
type='set'<br />
id='a78b4q6ha463'><br />
<query xmlns='jabber:iq:roster'><br />
<item jid='nurse@example.com'<br />
name='Nurse'<br />
subscription='none'><br />
<group>Servants</group><br />
</item><br />
</query><br />
</iq><br />
<iq to='juliet@example.com/chamber'<br />
type='set'<br />
id='a78b4q6ha464'><br />
<query xmlns='jabber:iq:roster'><br />
<item jid='nurse@example.com'<br />
name='Nurse'<br />
subscription='none'><br />
<group>Servants</group><br />
</item><br />
</query><br />
</iq><br />
<iq to='juliet@example.com/balcony' type='result' id='roster_2'/><br />
</source><br />
<br />
:正如IQ节类型(定义在[XMPP-CORE|XMPP文档列表/XMPP正式RFC标准/RFC3920])的语义所要求的,每个接收到了名册推送的资源必须(MUST)应答一个类型为"result"(或 "error")的IQ节.<br />
<br />
:例子: 资源应答一个IQ结果给服务器:<br />
<br />
<source lang="xml"><br />
<iq from='juliet@example.com/balcony'<br />
to='example.com'<br />
type='result'<br />
id='a78b4q6ha463'/><br />
<iq from='juliet@example.com/chamber'<br />
to='example.com'<br />
type='result'<br />
id='a78b4q6ha464'/><br />
</source><br />
<br />
===更新名册条目===<br />
<br />
:更新一个已有的名册条目(例如, 改变组) 的方法和增加一个新的名册条目是一样的, 换言之, 在IQ set 节中发送名册条目给服务器.<br />
<br />
:例子: 用户更新名册条目(增加组):<br />
<br />
<source lang="xml"><br />
<iq from='juliet@example.com/chamber' type='set' id='roster_3'><br />
<query xmlns='jabber:iq:roster'><br />
<item jid='romeo@example.net'<br />
name='Romeo'<br />
subscription='both'><br />
<group>Friends</group><br />
<group>Lovers</group><br />
</item><br />
</query><br />
</iq><br />
</source><br />
<br />
:正如增加一个名册条目, 当更新一个名册条目时服务器必须(MUST)在持久信息存储机构中更新名册信息, 并且也要初始化一个名册推送给这个用户的所有已请求名册的可用资源.<br />
<br />
===删除一个名册条目===<br />
<br />
:任何时候, 用户可以(MAY)从他或她的名册中删除一个条目,只要发送一个 IQ set 给服务器并确保其'subscription'属性值为"remove" (如果从一个客户端接收到'subscription'属性的任何其他值,一个兼容的服务器必须(MUST)忽略它).<br />
<br />
:例子: 客户端移除一个条目:<br />
<br />
<source lang="xml"><br />
<iq from='juliet@example.com/balcony' type='set' id='roster_4'><br />
<query xmlns='jabber:iq:roster'><br />
<item jid='nurse@example.com' subscription='remove'/><br />
</query><br />
</iq><br />
</source><br />
<br />
:和增加一个名册条目一样, 删除一个名册条目的时候服务器必须(MUST)在持久信息存储机构中更新名册信息,初始化一个名册推送给这个用户的所有已请求名册的可用资源(伴随着把'subscription'属性值设为"remove"),并且发送一个 IQ result 给初始化资源.<br />
<br />
:关于这个命令的含义的更多信息, 见 移除一个名册条目并取消所有订阅Removing a Roster Item and Cancelling All Subscriptions (第八章第六节).<br />
<br />
==名册条目和出席信息订阅的集成==<br />
<br />
===概览===<br />
<br />
:关于用户从或向别的联系人订阅出席信息,一个即时消息用户通常希望在名册条目和出席信息订阅之间有某些层次的集成. 本章描述了在XMPP即时消息应用中必须(MUST)支持的那些层次的集成.<br />
<br />
:有四种主要的订阅状态:<br />
<br />
:* None -- 这个用户没有对这个联系人出席信息的订阅, 这个联系人也没有订阅用户的出席信息<br />
<br />
:* To -- 这个用户订阅了这个联系人的出席信息, 但是这个联系人没有订阅用户的出席信息<br />
<br />
:* From -- 这个联系人订阅了用户的出席信息, 但是这个用户没有订阅这个联系人的出席信息<br />
<br />
:* Both -- 用户和联系人互相订阅了对方的出席信息(例如, 联合'from' 和 'to')<br />
<br />
:这些状态的每一个都被反射到用户和联系人双方的名册中, 从而导致持久的订阅状态.<br />
<br />
:在以下的子章节中将叙述这些订阅状态如何为了完成特定的已定义的用例而进行交互. 关于服务器和客户端处理所有订阅状态的细节 (包括处于以上所列的状态之外的未决状态)在 订阅状态Subscription States(第九章).<br />
<br />
:服务器不能(MUST NOT)发送出席信息订阅请求或名册推送给不可用的资源, 也不能给没有已请求的名册的可用资源.<br />
<br />
:在名册推送中'from'和'to'地址是可选的(OPTIONAL); 如果包含了, 它们的值应该(SHOULD)是那个会话的资源的全JID. 一个客户端必须(MUST)以一个类型为"result"的IQ节来承认每个名册推送(为了暂时的原因, 这些节不显示在以下的例子中但是按[XMPP-CORE|XMPP文档列表/XMPP正式RFC标准/RFC3920]定义的IQ语义学的规定它们是必需的).<br />
<br />
===用户向联系人订阅===<br />
<br />
:以下描述一个用户向一个联系人订阅的过程, 包括名册条目和订阅状态之间的互动.<br />
<br />
:1. 为了能够在用户的客户端界面处理联系人以及在服务器跟踪订阅, 用户的客户端应该(SHOULD)为新的名册条目执行一个"roster set". 这个请求包括发送一个类型为'set'的IQ节并拥有符合'jabber:iq:roster'名字空间的<query/>子元素, 它(<query/>元素)再包含一个<item/>子元素来定义新的名册条目; 这个<item/>元素必须(MUST)拥有一个'jid'属性, 可以(MAY)拥有一个'name'属性, 不能(MUST NOT)拥有一个'subscription'属性, 并且可以(MAY)包含一个或多个<group/>子元素:<br />
<br />
<source lang="xml"><br />
<iq type='set' id='set1'><br />
<query xmlns='jabber:iq:roster'><br />
<item<br />
jid='contact@example.org'<br />
name='MyContact'><br />
<group>MyBuddies</group><br />
</item><br />
</query><br />
</iq><br />
</source><br />
<br />
:2. 作为结果, 这个用户的服务器 (1) 必须(MUST)为这个新的名册条目初始化一个名册推送给这个用户的所有已经请求名册的可用资源, 其'subscription'属性的值为 "none"; 并且 (2) 必须(MUST)以一个 IQ result 应答发送的资源表明名册设置成功了:<br />
<br />
<source lang="xml"><br />
<iq type='set'><br />
<query xmlns='jabber:iq:roster'><br />
<item<br />
jid='contact@example.org'<br />
subscription='none'<br />
name='MyContact'><br />
<group>MyBuddies</group><br />
</item><br />
</query><br />
</iq><br />
<iq type='result' id='set1'/><br />
</source><br />
<br />
:3. 如果用户想向这个联系人请求出席信息的订阅, 用户的客户端必须(MUST)发送一个类型为'subscribe'的出席信息节给联系人:<br />
<br />
<source lang="xml"><br />
<presence to='contact@example.org' type='subscribe'/><br />
</source><br />
<br />
:4. 作为结果, 用户的服务器必须(MUST)初始化第二个名册推送给这个用户的所有已经请求名册的可用资源,把这个联系人设置成'none'订阅状态的未决子状态; 这个未决子状态是由名册条目中包含的ask='subscribe'属性所指示的:<br />
<br />
<source lang="xml"><br />
<iq type='set'><br />
<query xmlns='jabber:iq:roster'><br />
<item<br />
jid='contact@example.org'<br />
subscription='none'<br />
ask='subscribe'<br />
name='MyContact'><br />
<group>MyBuddies</group><br />
</item><br />
</query><br />
</iq><br />
</source><br />
<br />
:注意: 如果用户在发送订阅请求之前没有新建一个名册条目, 服务器必须(MUST)现在代替用户新建一个,然后发送一个名册推送给这个用户的所有已经请求名册的可用资源, 不含以上所示的'name'属性和<group/>子元素.<br />
<br />
:5. 用户的服务器也必须(MUST)把这个类型为"subscribe"的出席信息节的'from'地址设置为用户的纯JID(例如, <user@example.com>)(如果用户提供了设置为用户的全JID的'from'地址, 服务器应该(SHOULD)移除资源ID). 如果联系人和用户在不同的主机上, 用户的服务器必须(MUST)路由这个出席信息节到联系人的服务器来递送到这个联系人(这种情形的假定贯穿本文; 无论如何, 如果联系人在同一台主机, 那么服务器可以简单地直接递送出席信息节):<br />
<br />
<source lang="xml"><br />
<presence<br />
from='user@example.com'<br />
to='contact@example.org'<br />
type='subscribe'/><br />
</source><br />
<br />
:注意:如果用户的服务器从联系人的服务器收到了一个类型为"error"的出席信息节, 它必须(MUST)这个错误节给用户, 用户的客户端可以(MAY)确定那个错误是否对于上次用户发出的"subscribe"类型的出席信息节(例如, 通过跟踪'id'属性)的应答,然后选择重新发送"subscribe"请求还是发送一个"unsubscribe"类型的出席信息节给联系人以恢复到它的上一个状态.<br />
<br />
:6. 接收到指向联系人的"subscribe"类型的出席信息节之后, 这个联系人的服务器必须(MUST)决定是否至少有一个已请求名册的联系人的可用资源. 如果是, 它必须(MUST)递送这个订阅请求给这个联系人(如果不是, 联系人的服务器必须(MUST)离线存储这个订阅请求用于递送 when this condition is next met; 通常这是通过增加一个关于这个联系人的名册条目到用户名册中来实现的, 伴随着一个 "None + Pending In"的状态(定义在 订阅状态Subscription States (第九章)), 无论如何一个服务器不应该(SHOULD NOT)在那种状态下推送或递送名册条目给联系人). 不论何时订阅请求被递送到了, 联系人必须决定是否批准它(根据联系人的配置选项, 联系人的客户端可以(MAY)批准或拒绝订阅请求而无需向联系人显示). 这里我们假定这个 "happy path", 即联系人批准了订阅请求(替代的拒绝订阅请求的流程定义在第八章第二节第一小节). 在这种情形下, 这个联系人的客户端 (1) 应该(SHOULD) 执行一个roster set 为这个用户指明期望的昵称和组(如果有的话); 并且 (2) 必须(MUST)发送一个"subscribed"类型的出席信息节给这个用户以批准这个订阅请求.<br />
<br />
<source lang="xml"><br />
<iq type='set' id='set2'><br />
<query xmlns='jabber:iq:roster'><br />
<item<br />
jid='user@example.com'<br />
name='SomeUser'><br />
<group>SomeGroup</group><br />
</item><br />
</query><br />
</iq><br />
<presence to='user@example.com' type='subscribed'/><br />
</source><br />
<br />
:7. 作为结果, 联系人的服务器 (1) 必须(MUST) 初始化一个名册推送给所有联系人已请求名册的可用资源, 包含一个关于那个用户的名册条目,并且其订阅状态为'from'(甚至联系人不执行roster set,服务器也必须(MUST)发送它); (2) 必须(MUST)返回一个 IQ result 给发送的资源表示名册设置(roster set)成功了; (3) 必须(MUST)路由这个"subscribed"类型的出席信息节给用户, 首先把'from'地址设为联系人的纯JID(<contact@example.org>); 然后 (4) 必须(MUST)从所有联系人的可用资源向用户发送可用的出席信息:<br />
<br />
<source lang="xml"><br />
<iq type='set' to='contact@example.org/resource'><br />
<query xmlns='jabber:iq:roster'><br />
<item<br />
jid='user@example.com'<br />
subscription='from'<br />
name='SomeUser'><br />
<group>SomeGroup</group><br />
</item><br />
</query><br />
</iq><br />
<iq type='result' to='contact@example.org/resource' id='set2'/><br />
<presence<br />
from='contact@example.org'<br />
to='user@example.com'<br />
type='subscribed'/><br />
<presence<br />
from='contact@example.org/resource'<br />
to='user@example.com'/><br />
</source><br />
<br />
:注意: 如果联系人的服务器从用户的服务器收到一个"error"类型的出席信息节, 它必须(MUST)递送这个错误节给联系人, 联系人的客户端可以(MAY)确定那个错误是否对于上次联系人发出的"subscribe"类型的出席信息节(例如, 通过跟踪'id'属性)的应答,然后选择重新发送"subscribe"请求还是发送一个"unsubscribe"类型的出席信息节给用户以恢复到它的上一个状态. <br />
<br />
:8. 接收到一个指向用户的"subscribed"类型的出席信息节之后, 用户的服务器必须(MUST)首先检查在用户名册中的这个联系人的状态是: (a) subscription='none' and ask='subscribe' 还是 (b) subscription='from' and ask='subscribe'. 如果联系人不是以上述的状态在用户的名册中,用户的服务器必须(MUST)安静的忽略这个"subscribed"类型的出席信息节(例如, 服务器不能(MUST NOT)路由它到用户, 修改用户的名册, 或生成一个名册推送到用户的可用资源). 如果联系人以上述任何一种状态存在于用户的名册中, 用户的服务器 (1) 必须(MUST)从联系人向用户递送这个"subscribed"类型的出席信息节; (2)必须(MUST)初始化一个名册推送给所有已请求名册的这个用户的可用资源,包含一个关于这个联系人的更新的名册条目,同时其'subscription'属性值设置为"to"; 并且 (3) 必须(MUST)从每一个联系人的可用资源向每一个用户的可用资源递送服务器接收到的可用的出席信息节:<br />
<br />
<source lang="xml"><br />
<presence<br />
to='user@example.com'<br />
from='contact@example.org'<br />
type='subscribed'/><br />
<iq type='set'><br />
<query xmlns='jabber:iq:roster'><br />
<item<br />
jid='contact@example.org'<br />
subscription='to'<br />
name='MyContact'><br />
<group>MyBuddies</group><br />
</item><br />
</query><br />
</iq><br />
<presence<br />
from='contact@example.org/resource'<br />
to='user@example.com/resource'/><br />
</source><br />
<br />
:9. 接收到"subscribed"类型的出席信息节之后, 用户应该(SHOULD)承认接收到了订阅状态通知,<br />
要么发送一个"subscribe"类型的出席信息节给联系人证实它, 要么发送一个"unsubscribe"类型的出席信息节给联系人否认它;这个步骤不一定影响订阅状态(见 订阅状态Subscription States(第九章)的细节), 但是会让用户用户的服务器知道它必须(MUST)不再发送订阅状态改变通知给用户(见第九章第四节).<br />
<br />
:从用户这方面看, 现在存在一个向联系人的出席信息的订阅; 从联系人的方面看, 现在存在一个从用户的来的订阅.<br />
<br />
====替代流程: 联系人拒绝订阅请求====<br />
<br />
:以上活动流程展示了关于用户向联系人的订阅请求的 "happy path" . 如果联系人拒绝用户的订阅请求,那么主要的替代流程如下所述.<br />
<br />
:1. 如果联系人想拒绝这个请求, 联系人的客户端必须(MUST)发送一个"unsubscribed"类型的出席信息节给用户(取代第八章第二节中步骤6发送的 "subscribed"类型的出席信息节):<br />
<br />
<source lang="xml"><br />
<presence to='user@example.com' type='unsubscribed'/><br />
</source><br />
<br />
:2. 作为结果, 联系人的服务器必须(MUST)路由这个"unsubscribed"类型的出席信息节给用户,首先把'from'地址设为联系人的纯JID(<contact@example.org>):<br />
<br />
<source lang="xml"><br />
<presence<br />
from='contact@example.org'<br />
to='user@example.com'<br />
type='unsubscribed'/><br />
</source><br />
<br />
:注意: 如果联系人的服务器之前把用户添加到了联系人的名册中用来跟踪, 这时它必须(MUST)移除这个相关的条目.<br />
<br />
:3. 接收到指向用户的"unsubscribed"类型出席信息节之后, 用户的服务器 (1) 必须(MUST)地送那个出席信息节给用户 并且 (2) 必须(MUST) 初始化一个名册推送给这个用户的所有已请求名册的可用资源, 包含一个关于这个联系人的一个更新条目,其'subscription'属性设为"none"并且没有'ask'属性:<br />
<br />
<source lang="xml"><br />
<presence<br />
from='contact@example.org'<br />
to='user@example.com'<br />
type='unsubscribed'/><br />
<iq type='set'><br />
<query xmlns='jabber:iq:roster'><br />
<item<br />
jid='contact@example.org'<br />
subscription='none'<br />
name='MyContact'><br />
<group>MyBuddies</group><br />
</item><br />
</query><br />
</iq><br />
</source><br />
<br />
:4. 接收到类型为"unsubscribed"出席信息节之后, 用户应该(SHOULD)承认收到订阅状态通知, 要么发送一个"unsubscribe"类型的出席信息节给联系人证实它, 要么发送一个"subscribe"类型的出席信息节给联系人否认它; 这一步骤不影响订阅状态(见 订阅状态Subscription States(第九章)的细节), 但是让用户的服务器知道它必须(MUST)不再发送订阅状态改变的通知给用户(见第九章第四节).<br />
<br />
:作为这一行为的结果, 联系人现在在用户的名册中, 状态为"none",而用户根本不在联系人的名册中.<br />
<br />
===建立一个相互的订阅===<br />
<br />
:用户和联系人可以在前述"happy path"的基础上建立一个相互的订阅(例如, 一个"both"的订阅类型). 流程如下.<br />
<br />
:1. 如果联系人想建立一个相互的订阅, 联系人必须(MUST)发送一个订阅请求给用户(视联系人的配置选项而定, 联系人的客户端可以(MAY)自动发送它):<br />
<br />
<source lang="xml"><br />
<presence to='user@example.com' type='subscribe'/><br />
</source><br />
<br />
:2. 作为结果, 联系人的服务器 (1) 必须(MUST)初始化一个名册推送给联系人的所有已请求名册的可用资源, 伴随着用户仍在'from'订阅状态但同时有一个未决的'to'订阅状态(通过在名册条目中包含一个ask='subscribe'的属性来指示); 并且 (2) 必须(MUST)路由这个"subscribe"类型的出席信息节给用户(先把'from'地址设为联系人的纯JID(<contact@example.org>)):<br />
<br />
<source lang="xml"><br />
<iq type='set'><br />
<query xmlns='jabber:iq:roster'><br />
<item<br />
jid='user@example.com'<br />
subscription='from'<br />
ask='subscribe'<br />
name='SomeUser'><br />
<group>SomeGroup</group><br />
</item><br />
</query><br />
</iq><br />
<presence<br />
from='contact@example.org'<br />
to='user@example.com'<br />
type='subscribe'/><br />
</source><br />
<br />
:注意: 如果联系人的服务器从用户的服务器收到一个"error"类型的出席信息节, 它必须(MUST)递送这个错误节给联系人, 它的客户端可以(MAY)确定这个错误是用来应答上次发送的"subscribe"类型的出席信息节(换言之, 通过跟踪'id'属性) 并且选择重发这个"subscribe"请求还是发送一个"unsubscribe"类型的出席信息节给用户以把名册恢复到它的前一个状态.<br />
<br />
:3. 接收到指向用户的"subscribe"类型出席信息节之后, 用户的服务器必须确定是否至少有一个已请求名册可用资源. 如果是, 用户的服务器必须(MUST)递送这个订阅请求给用户(如果不是, 它必须(MUST)离线存储这个订阅请求等这种情形再次发生时递送). 无论何时订阅请求被递送了, 用户必须决定是否批准它(视用户的配置选项而定, 用户的客户端可以(MAY)批准或拒绝这个订阅请求而不需要向用户显示). 这里我们假定这是"happy path",用户批准了订阅请求(替代的拒绝订阅请求的流程定义在第八章第三节第一小节). 在这种情形下, 用户的客户端必须(MUST)发送一个"subscribed"类型的出席信息节给联系人表示批准了订阅请求.<br />
<br />
<source lang="xml"><br />
<presence to='contact@example.org' type='subscribed'/><br />
</source><br />
<br />
:4. 作为结果, 用户的服务器 (1) 必须(MUST)初始化一个名册推送给用户的所有已请求名册的可用资源, 包含一个关于联系人的名册条目,其'subscription'属性设为"both"; (2) 必须(MUST)路由这个"subscribed"类型的出席信息节给联系人(先把'from'地址设为用户的纯JID<user@example.com>)); 并且 (3) 必须(MUST)向联系人发送它从用户的每个可用资源收到的最近一次出席信息节的全XML(不带'to'属性)(强制每个会话遵守隐私列表):<br />
<br />
<source lang="xml"><br />
<iq type='set'><br />
<query xmlns='jabber:iq:roster'><br />
<item<br />
jid='contact@example.org'<br />
subscription='both'<br />
name='MyContact'><br />
<group>MyBuddies</group><br />
</item><br />
</query><br />
</iq><br />
<presence<br />
from='user@example.com'<br />
to='contact@example.org'<br />
type='subscribed'/><br />
<presence<br />
from='user@example.com/resource'<br />
to='contact@example.org'/><br />
</source><br />
<br />
:注意: 如果用户的服务器从联系人的服务器接收到一个"error"类型的出席信息节, 它必须(MUST)递送这个错误节给用户, 它客户端可以(MAY)确定这个错误是用来应答上次发出去的"subscribed"类型的出席信息节(换言之, 通过跟踪'id'属性) 并且选择重发这个订阅请求还是发送一个"unsubscribed"类型的出席信息节给联系人以把名册恢复到上次的状态.<br />
<br />
:5. 接收到指向联系人的"subscribed"类型的出席信息节之后, 联系人的服务器必须(MUST)首先检查用户在联系人的名册中的状态是否以下状态之一: (a) subscription='none' and ask='subscribe' 或 (b) subscription='from' and ask='subscribe'. 如果用户不是以上述两种状态之一存在于联系人的名册中, 联系人的服务器必须(MUST)安静地忽略这个"subscribed"类型的出席信息节(例如, 它不能(MUST NOT)路由它给联系人, 修改联系人的名册, 或生成一个名册推送给联系人的可用资源). 如果用户以上述两种状态之一存在于联系人的名册中, 联系人的服务器 (1) 必须(MUST)从用户向联系人递送这个"subscribed"类型的出席信息节; (2) 必须(MUST)初始化一个名册推送给这个联系人的所有已请求名册的可用资源, 包含一个关于这个用户的更新的名册条目,其'subscription'属性值设为"both"; 并且 (3) 必须(MUST)向这个联系人的每个可用资源递送它从这个用户的每个资源收到的可用出席信息节:<br />
<br />
<source lang="xml"><br />
<presence<br />
from='user@example.com'<br />
to='contact@example.org'<br />
type='subscribed'/><br />
<iq type='set'><br />
<query xmlns='jabber:iq:roster'><br />
<item<br />
jid='user@example.com'<br />
subscription='both'<br />
name='SomeUser'><br />
<group>SomeGroup</group><br />
</item><br />
</query><br />
</iq><br />
<presence<br />
from='user@example.com/resource'<br />
to='contact@example.org/resource'/><br />
</source><br />
<br />
:6. 收到"subscribed"类型的出席信息节之后, 联系人应该(SHOULD)承认收到订阅请求通知,要么发送一个"subscribe"的出席信息节给用户证实它,要么发送一个"unsubscribe"类型的出席信息节给用户否认它; 这一步骤不影响订阅状态(细节见 订阅状态Subscription States(第九章)), 但是让联系人的服务器知道它必须(MUST)不再发送订阅状态变更通知给联系人(见第九章第四节).<br />
<br />
:用户和联系人现在有了对双方的出席信息的一个相互订阅 -- 换言之, 这个订阅类型为 "both".<br />
<br />
====替代流程: 用户拒绝订阅请求====<br />
<br />
:以上活动流程展示了关于联系人对用户的订阅请求的 "happy path". 如果用户拒绝了联系人的订阅请求,其主要流程如下.<br />
<br />
:1. 如果用户想拒绝请求, 用户的客户端必须(MUST)发送一个"unsubscribed"类型的出席信息节给联系人(替代第八章第三节中的第三步中所发送的"subscribed"类型出席信息节):<br />
<br />
<source lang="xml"><br />
<presence to='contact@example.org' type='unsubscribed'/><br />
</source><br />
<br />
:2. 作为结果, 用户的服务器必须(MUST)路由这个"unsubscribed"类型的出席信息节给联系人(首先把'from'地址设为用户的纯JID(<user@example.com>)):<br />
<br />
<source lang="xml"><br />
<presence<br />
from='user@example.com'<br />
to='contact@example.org'<br />
type='unsubscribed'/><br />
</source><br />
<br />
:3. 接收到指向联系人的"unsubscribed"类型的出席信息节之后, 联系人的服务器 (1) 必须(MUST)递送这个出席信息节给联系人; 并且 (2) 必须(MUST)初始化一个名册推送给这个联系人的所有已请求名册的可用资源, 包含关于这个用户的更新的名册条目,其'subscription'属性的值设为"from"并且没有'ask'属性:<br />
<br />
<source lang="xml"><br />
<presence<br />
from='user@example.com'<br />
to='contact@example.org'<br />
type='unsubscribed'/><br />
<iq type='set'><br />
<query xmlns='jabber:iq:roster'><br />
<item<br />
jid='user@example.com'<br />
subscription='from'<br />
name='SomeUser'><br />
<group>SomeGroup</group><br />
</item><br />
</query><br />
</iq><br />
</source><br />
<br />
:4. 接收到"unsubscribed"类型的出席信息节之后, 联系人应该(SHOULD)承认收到那个订阅状态通知,要么向用户发送一个"unsubscribe"类型的出席信息节以证实它,要么向用户发送一个"subscribe"类型的出席信息以否认它; 这个步骤不会影响订阅状态(详见 订阅状态Subscription States(第九章)),但是让联系人的服务器知道它必须(MUST)不再发送订阅状态变更通知给联系人(见第九章第四节).<br />
<br />
:作为这一活动的结果, 订阅状态没有任何改变; 换言之, 联系人在用户的名册中的订阅状态为"to"并且用户在联系人的名册中的订阅状态为"from".<br />
<br />
===取消订阅===<br />
<br />
:在订阅了一个联系人的出席信息之后的任何时候, 一个用户可以(MAY)取消订阅. 在所有实例中用户发送来执行这一动作的XML是相同的, 接下来的订阅状态根据发出取消订阅命令时获得的订阅状态的情况而不同. 两种可能的情节描述如下.<br />
<br />
====情形 #1: 当订阅不是相互的时候取消订阅====<br />
<br />
:在第一种情形, 用户有一个向联系人的出席信息的订阅但是联系人没有对用户的出席信息的订阅(换言之, 订阅不是相互的).<br />
<br />
:1. 如果用户想取消对联系人的出席信息的订阅, 用户必须(MUST)发送一个"unsubscribe"类型的出席信息节给联系人:<br />
<br />
<source lang="xml"><br />
<presence to='contact@example.org' type='unsubscribe'/><br />
</source><br />
<br />
:2. 作为一个结果, 用户的服务器 (1) 必须(MUST) 发送一个名册推送给这个用户的所有已请求名册的可用资源,包含一个关于这个联系人的更新名册条目,其'subscription'属性设为"none"; 并且 (2) 必须(MUST)路由这个"unsubscribe"类型的出席信息节给联系人(首先把'from'地址设为用户的纯JID(<user@example.com>)):<br />
<br />
<source lang="xml"><br />
<iq type='set'><br />
<query xmlns='jabber:iq:roster'><br />
<item<br />
jid='contact@example.org'<br />
subscription='none'<br />
name='MyContact'><br />
<group>MyBuddies</group><br />
</item><br />
</query><br />
</iq><br />
<presence<br />
from='user@example.com'<br />
to='contact@example.org'<br />
type='unsubscribe'/><br />
</source><br />
<br />
:3. 接收到指向联系人的"unsubscribe"类型出席信息节之后, 联系人的服务器 (1) 必须(MUST)初始化一个名册推送给这个联系人的所有已请求名册的可用资源, 包含一个关于这个用户的名册条目,其'subscription'属性值设为"none" (如果联系人不可用或未曾请求名册, 联系人的服务器必须(MUST)修改名册条目并在下次联系人请求名册时发送那个已修改的条目); 并且 (2) 必须(MUST)递送这个"unsubscribe"状态改变通知给联系人:<br />
<br />
<source lang="xml"><br />
<iq type='set'><br />
<query xmlns='jabber:iq:roster'><br />
<item<br />
jid='user@example.com'<br />
subscription='none'<br />
name='SomeUser'><br />
<group>SomeGroup</group><br />
</item><br />
</query><br />
</iq><br />
<presence<br />
from='user@example.com'<br />
to='contact@example.org'<br />
type='unsubscribe'/><br />
</source><br />
<br />
:4. 接收到"unsubscribe"类型的出席信息节之后, 联系人应该(SHOULD)承认收到那个订阅状态通知,要么发送一个"unsubscribed"类型的出席信息节给用户以证实它,要么发送一个"subscribed"类型的出席信息节给用户否认它; 这个步骤不影响订阅状态(详见 订阅状态Subscription States (第九章)), 但是让联系人的服务器知道它必须(MUST)不再发送订阅状态变更通知给联系人(见第九章第四节).<br />
<br />
:5. 联系人的服务器接着 (1) 必须(MUST)发送一个"unsubscribed"类型的出席信息节给用户;并且 (2) 应该(SHOULD)向用户发送从这个联系人的所有可用资源收到的不可用出席信息:<br />
<br />
<source lang="xml"><br />
<presence<br />
from='contact@example.org'<br />
to='user@example.com'<br />
type='unsubscribed'/><br />
<presence<br />
from='contact@example.org/resource'<br />
to='user@example.com'<br />
type='unavailable'/><br />
</source><br />
<br />
:6. 当用户的服务器收到类型为"unsubscribed" 和 "unavailable"的出席信息节, 它必须(MUST)递送它们给用户:<br />
<br />
<source lang="xml"><br />
<presence<br />
from='contact@example.org'<br />
to='user@example.com'<br />
type='unsubscribed'/><br />
<presence<br />
from='contact@example.org/resource'<br />
to='user@example.com'<br />
type='unavailable'/><br />
</source><br />
<br />
:7. 接收到"unsubscribed"类型的出席信息节之后, 用户应该(SHOULD)承认收到那个订阅状态变更通知,要么向联系人发送一个"unsubscribe"类型的出席信息节以证实它,要么向联系人发送一个"subscribe"的出席信息节以否认它;这步骤不影响订阅状态(详见 订阅状态Subscription States(第九章)), 但是让用户的服务器知道它必须(MUST)不在发送订阅状态变更通知给用户(见第九章第四节).<br />
<br />
====情形 #2: 当订阅是相互的时候取消订阅====<br />
<br />
:在第二种情形下, 用户有一个向联系人的出席信息的订阅并且联系人也有一个向用户的出席信息的订阅(换言之, 订阅是相互的).<br />
<br />
:1. 如果用户想从联系人的出席信息取消订阅, 用户必须(MUST)发送一个"unsubscribe"类型的出席信息节给联系人:<br />
<br />
<source lang="xml"><br />
<presence to='contact@example.org' type='unsubscribe'/><br />
</source><br />
<br />
:2. 作为一个结果, 用户的服务器 (1) 必须(MUST)发送一个名册推送给这个用户的所有已请求名册的可用资源,包含一个关于这个联系人的更新名册条目,其'subscription'属性值设为"from"; 并且 (2) 必须(MUST)路由这个"unsubscribe"类型的出席信息节给这个联系人( 首先把'from'地址设为这个用户的纯 JID(<user@example.com>):<br />
<br />
<source lang="xml"><br />
<iq type='set'><br />
<query xmlns='jabber:iq:roster'><br />
<item<br />
jid='contact@example.org'<br />
subscription='from'<br />
name='MyContact'><br />
<group>MyBuddies</group><br />
</item><br />
</query><br />
</iq><br />
<presence<br />
from='user@example.com'<br />
to='contact@example.org'<br />
type='unsubscribe'/><br />
</source><br />
<br />
:3. 接收到指向联系人的"unsubscribe"类型的出席信息节之后, 联系人的服务器 (1) 必须(MUST)初始化一个名册推送给这个联系人的所有已请求名册的可用资源, 包含一个关于这个用户的名册条目,其'subscription'属性值设为"to" (如果联系人不可用或未曾请求名册, 联系人的服务去必须(MUST)修改这个名册条目并且等下次联系人请求名册的时候再发送这个修改过的名册条目); 并且 (2) 必须(MUST)递送这个"unsubscribe"状态变更通知给联系人:<br />
<br />
<source lang="xml"><br />
<iq type='set'><br />
<query xmlns='jabber:iq:roster'><br />
<item<br />
jid='user@example.com'<br />
subscription='to'<br />
name='SomeUser'><br />
<group>SomeGroup</group><br />
</item><br />
</query><br />
</iq><br />
<presence<br />
from='user@example.com'<br />
to='contact@example.org'<br />
type='unsubscribe'/><br />
</source><br />
<br />
:4. 接收到这个"unsubscribe"类型的出席信息节之后, 联系人应该(SHOULD)承认收到了那个订阅状态通知,要么向用户发送一个"unsubscribed"类型的出席信息节以证实它,要么向用户发送一个"subscribed"类型的出席信息节以否认它; 这个步骤不影响订阅状态(详见 订阅状态Subscription States(第九章)), 但是让联系人的服务器知道它必须(MUST)不再发送订阅状态变更通知给联系人(见第九章第四节).<br />
<br />
:5. 联系人的服务器然后 (1) 必须(MUST)发送一个"unsubscribed"类型的出席信息节给用户; 并且 (2) 应该(SHOULD)向用户发送它从联系人的所有可用资源收到的不可用出席信息:<br />
<br />
<source lang="xml"><br />
<presence<br />
from='contact@example.org'<br />
to='user@example.com'<br />
type='unsubscribed'/><br />
<presence<br />
from='contact@example.org/resource'<br />
to='user@example.com'<br />
type='unavailable'/><br />
</source><br />
<br />
:6. 当用户的服务器收到"unsubscribed"和"unavailable"类型的出席信息节, 它必须(MUST)递送它们给用户:<br />
<br />
<source lang="xml"><br />
<presence<br />
from='contact@example.org'<br />
to='user@example.com'<br />
type='unsubscribed'/><br />
<presence<br />
from='contact@example.org/resource'<br />
to='user@example.com'<br />
type='unavailable'/><br />
</source><br />
<br />
:7. 接收到"unsubscribed"类型的出席信息节之后, 用户应该(SHOULD)承认收到了那个订阅状态的通知,要么向联系人发送一个"unsubscribe"类型的出席信息节以证实它,要么向联系人发送一个"subscribe"类型的出席信息节以否认它;这个步骤不影响订阅状态(详见 订阅状态Subscription States(第九章)), 但是让用户的服务器知道它必须(MUST)不在发送订阅状态变更通知给用户(见第九章第四节).<br />
<br />
:注意: 显然这不会导致名册条目从用户的名册移除, 并且联系人仍然有一个对用户的出席信息的订阅.为了完全取消双向的订阅并完全从用户的名册中移除名册条目, 用户应该(SHOULD)使用subscription='remove'(定义在 移除一个名册条目并取消所有订阅项Removing a Roster Item and Cancelling All Subscriptions (第八章第六节))更新名册条目.<br />
<br />
===取消一个订阅项===<br />
<br />
:在批准来自一个用户的任何订阅请求之后的任何时候, 一个联系人可以(MAY)取消那个订阅项. 联系人在所有实例中执行这个动作中发送的XML是相同的, 接下来的订阅状态根据取消命令发出当时所获得的订阅状态而有所不同. 所有可能的情节描述如下.<br />
<br />
====情形 #1: 当订阅不是相互的时候取消订阅项====<br />
<br />
:在第一种情形下, 用户有一个对联系人的出席信息的订阅但是联系人没有对于用户的出席信息的订阅(换言之, 订阅还不是相互的).<br />
<br />
:1. 如果联系人想取消用户的订阅项, 联系人必须(MUST)发送一个"unsubscribed"类型的出席信息节给用户:<br />
<br />
<source lang="xml"><br />
<presence to='user@example.com' type='unsubscribed'/><br />
</source><br />
<br />
:2. 作为一个结果, 联系人的服务器 (1) 必须(MUST)发送一个名册推送给这个联系人的所有已请求名册的可用资源, 包含一个关于这个用户的更新的名册条目,其'subscription'属性值设为"none"; (2) 必须(MUST)路由这个"unsubscribed"类型的出席信息节给用户(首先把'from'地址设为联系人的纯JID(<contact@example.org>)); 并且 (3) 应该(SHOULD)向用户发送它从联系人的所有可用资源收到的不可用出席信息:<br />
<br />
<source lang="xml"><br />
<iq type='set'><br />
<query xmlns='jabber:iq:roster'><br />
<item<br />
jid='user@example.com'<br />
subscription='none'<br />
name='SomeUser'><br />
<group>SomeGroup</group><br />
</item><br />
</query><br />
</iq><br />
<presence<br />
from='contact@example.org'<br />
to='user@example.com'<br />
type='unsubscribed'/><br />
<presence<br />
from='contact@example.org/resource'<br />
to='user@example.com'<br />
type='unavailable'/><br />
</source><br />
<br />
:3. 接收到指向用户的"unsubscribed"类型的出席信息节之后, 用户的服务器 (1) 必须(MUST)初始化一个名册推送给这个用户的所有已请求名册的可用资源, 包含一个关于这个联系人的名册条目更新,其'subscription'属性值设为"none"(如果用户不可用或未曾请求名册, 用户的服务器必须(MUST)修改这个名册条目并且等下次用户请求名册的时候发送修改过的名册条目); (2) 必须(MUST)递送这个"unsubscribed"状态改变通知给这个用户的所有可用资源; 并且 (3) 必须(MUST)向这个用户的所有可用资源递送不可用出席信息:<br />
<br />
<source lang="xml"><br />
<iq type='set'><br />
<query xmlns='jabber:iq:roster'><br />
<item<br />
jid='contact@example.org'<br />
subscription='none'<br />
name='MyContact'><br />
<group>MyBuddies</group><br />
</item><br />
</query><br />
</iq><br />
<presence<br />
from='contact@example.org'<br />
to='user@example.com'<br />
type='unsubscribed'/><br />
<presence<br />
from='contact@example.org/resource'<br />
to='user@example.com'<br />
type='unavailable'/><br />
</source><br />
<br />
:4. 接收到"unsubscribed"类型的出席信息节之后, 用户应该(SHOULD)承认收到了那个订阅状态通知,要么向联系人发送一个"unsubscribe"出席信息节以证实它,要么向联系人发送一个"subscribe"类型的出席信息节以否认它;这个步骤不影响订阅状态(详见 订阅状态Subscription States(第九章)), 但是让服务器知道它必须(MUST)不再发送订阅状态变更通知给用户(见第九章第四节).<br />
<br />
====情形 #2: 当订阅项是相互的时候取消====<br />
<br />
:在这种情形下, 用户有一个对联系人的出席信息的订阅并且联系人也有一个对用户的出席信息的订阅(换言之, 订阅是相互的).<br />
<br />
:1. 如果联系人想取消用户的订阅, 联系人必须(MUST)发送一个"unsubscribed"类型的出席信息节给用户:<br />
<br />
<source lang="xml"><br />
<presence to='user@example.com' type='unsubscribed'/><br />
</source><br />
<br />
:2. 作为结果, 联系人的服务器 (1) 必须(MUST)发送一个名册推送给这个联系人的所有已请求名册的可用资源, 包含关于这个用户的一个更新的名册条目,其'subscription'属性值设为"to"; (2) 必须(MUST)路由这个"unsubscribed"类型的出席信息节给用户(首先把'from'地址设为联系人的纯JID(<contact@example.org>)); 并且 (3) 应该(SHOULD)向这个用户的所有可用资源发送它从联系人的所有可用资源收到的不可用出席信息:<br />
<br />
<source lang="xml"><br />
<iq type='set'><br />
<query xmlns='jabber:iq:roster'><br />
<item<br />
jid='user@example.com'<br />
subscription='to'<br />
name='SomeUser'><br />
<group>SomeGroup</group><br />
</item><br />
</query><br />
</iq><br />
<presence<br />
from='contact@example.org'<br />
to='user@example.com'<br />
type='unsubscribed'/><br />
<presence<br />
from='contact@example.org/resource'<br />
to='user@example.com'<br />
type='unavailable'/><br />
</source><br />
<br />
:3. 接收到指向用户的"unsubscribed"类型出席信息节之后, 用户的服务器 (1) 必须(MUST)初始化一个名册推送给这个用户的所有已请求名册的可用资源, 包含关于这个联系人的更新的名册条目,其'subscription'属性值设为"from"(如果这个用户不可用或未曾请求名册, 用户的服务器必须(MUST)修改这个名册条目并且等下次用户请求名册的时候发送修改过的条目给它); 并且(2) 必须(MUST)递送这个"unsubscribed"状态变更通知给用户的所有可用资源; 并且 (3) 必须(MUST)向这个用户的所有可用资源递送这个不可用出席信息:<br />
<br />
<source lang="xml"><br />
<iq type='set'><br />
<query xmlns='jabber:iq:roster'><br />
<item<br />
jid='contact@example.org'<br />
subscription='from'<br />
name='MyContact'><br />
<group>MyBuddies</group><br />
</item><br />
</query><br />
</iq><br />
<presence<br />
from='contact@example.org'<br />
to='user@example.com'<br />
type='unsubscribed'/><br />
<presence<br />
from='contact@example.org/resource'<br />
to='user@example.com'<br />
type='unavailable'/><br />
</source><br />
<br />
:4. 接收到这个"unsubscribed"类型的出席信息节之后, 用户应该(SHOULD)承认收到了那个订阅状态通知,要么向联系人发送一个"unsubscribe"类型的出席信息节以证实它,要么向联系人发送一个"subscribe"类型的出席信息节以否认它; 这一步骤不影响订阅状态(详见 订阅状态Subscription States (第九章)), 但是让用户的服务器知道它必须(MUST)不再发送订阅状态变更通知给用户(见第九章第四节).<br />
<br />
:注意: 显然这不会使得名册条目从联系人的名册中移除, 并且联系人仍然有一个对用户的出席信息的订阅. 为了完全双向的取消一个相互的订阅并且从联系人的名册中完全移除这个名册条目, 联系人应该以subscription='remove'(定义在 移除一个名册条目并取消所有订阅项Removing a Roster Item and Cancelling All Subscriptions (第八章第六节))更新名册条目.<br />
<br />
===移除一个名册条目并取消所有订阅项===<br />
<br />
:因为在双向完整移除一个名册条目和取消所有订阅的过程中可能有很多步骤, 名册管理协议包含一个"shortcut"方法来做这件事. 无论当前的订阅状态是什么, 这个过程可以通过发送一个roster set(包含一个用于这个联系人的条目,其'subscription'属性值设为"remove")来初始化:<br />
<br />
<source lang="xml"><br />
<iq type='set' id='remove1'><br />
<query xmlns='jabber:iq:roster'><br />
<item<br />
jid='contact@example.org'<br />
subscription='remove'/><br />
</query><br />
</iq><br />
</source><br />
<br />
:当用户从他或她的名册中移除一个联系人(通过把'subscription'属性值设为"remove"), 用户的服务器 (1) 必须(MUST)自动取消用户和联系人之间的任何现存的出席信息订阅项(包括相应的'to'和'from'); (2) 必须(MUST)从用户的名册移除这个名册条目并且通知这个用户的所有已请求名册的可用资源这个名册条目被移除了; (3) 必须(MUST)通知初始化的资源移除成功了; 并且 (4) 应该(SHOULD)向联系人发送它从这个用户的所有可用资源收到的不可用出席信息:<br />
<br />
<source lang="xml"><br />
<presence<br />
from='user@example.com'<br />
to='contact@example.org'<br />
type='unsubscribe'/><br />
<presence<br />
from='user@example.com'<br />
to='contact@example.org'<br />
type='unsubscribed'/><br />
<iq type='set'><br />
<query xmlns='jabber:iq:roster'><br />
<item<br />
jid='contact@example.org'<br />
subscription='remove'/><br />
</query><br />
</iq><br />
<iq type='result' id='remove1'/><br />
<presence<br />
from='user@example.com/resource'<br />
to='contact@example.org'<br />
type='unavailable'/><br />
</source><br />
<br />
:收到"unsubscribe"类型的出席信息后, 联系人的服务器 (1) 必须(MUST)初始化一个名册推送给这个联系人的所有已请求名册的可用资源,包含关于这个用户的一个更新的名册条目,其'subscription'属性值设为"to"(如果这个联系人不可用或未曾请求名册, 联系人的服务器必须(MUST)修改这个名册条目并且等下次联系人请求名册的时候发送这个修改过的条目给它); 并且 (2) 也必须(MUST)递送这个"unsubscribe"状态变更通知给这个联系人的所有可用资源:<br />
<br />
<source lang="xml"><br />
<iq type='set'><br />
<query xmlns='jabber:iq:roster'><br />
<item<br />
jid='user@example.com'<br />
subscription='to'<br />
name='SomeUser'><br />
<group>SomeGroup</group><br />
</item><br />
</query><br />
</iq><br />
<presence<br />
from='user@example.com'<br />
to='contact@example.org'<br />
type='unsubscribe'/><br />
</source><br />
<br />
:收到这个"unsubscribed"类型的出席信息节之后, 联系人的服务器 (1) 必须(MUST)初始化一个名册推送给这个联系人的所有已请求名册的可用资源,包含一个关于这个用户的更新的名册条目,其'subscription'属性值设为"none"(如果这个联系人不可用或未曾请求名册, 联系人的服务器必须(MUST)修改名册条目并且等下次联系人请求名册的时候把修改过的条目发送给它); 并且 (2) 也必须(MUST)递送这个"unsubscribe"状态改变通知给这个联系人的所有可用资源:<br />
<br />
<source lang="xml"><br />
<iq type='set'><br />
<query xmlns='jabber:iq:roster'><br />
<item<br />
jid='user@example.com'<br />
subscription='none'<br />
name='SomeUser'><br />
<group>SomeGroup</group><br />
</item><br />
</query><br />
</iq><br />
<presence<br />
from='user@example.com'<br />
to='contact@example.org'<br />
type='unsubscribed'/><br />
</source><br />
<br />
:接收到指向联系人的"unavailable"出席信息节之后, 联系人的服务器必须(MUST)递送这个不可用出席信息给这个用户的所有可用资源:<br />
<br />
<source lang="xml"><br />
<presence<br />
from='user@example.com/resource'<br />
to='contact@example.org'<br />
type='unavailable'/><br />
</source><br />
<br />
:注意: 当用户从用户的名册中移除联系人的时候, 这个联系人的名册最后状态是用户仍然在联系人名册中但是订阅状态为"none"; 为了完全移除关于这个用户的名册条目, 联系人也需要发送一个名册移除请求.<br />
<br />
==订阅状态==<br />
<br />
:本章提供关于订阅状态以及和订阅相关的出席信息节(换言之,类型为"subscribe", "subscribed", "unsubscribe",和 "unsubscribed"的出席信息节)的服务器处理过程的详细信息.<br />
<br />
===已定义的状态===<br />
<br />
:有九种可能的订阅状态, 从用户的(不是联系人的)角度描述如下:<br />
<br />
:# "None" = 联系人和用户互相没有被对方订阅, 并且也都没有从对方那里请求一个订阅<br />
:# "None + Pending Out" = 联系人和用户互相没有被对方订阅, 用户已经向联系人发送了一个订阅请求但还没有收到回复<br />
:# "None + Pending In" = 联系人和用户互相没有被对方订阅, 联系人已经向用户发送了一个订阅请求但还没有收到回复(注意: 在这种状态下联系人的服务器不应该(SHOULD NOT)推送或递送名册条目, 但是应该(SHOULD)等待,直到联系人的订阅请求已经从用户那里得到批准)<br />
:# "None + Pending Out/In" = 联系人和用户互相没有被对方订阅, 联系人已经向用户发送了一个订阅请求但还没有收到回复, 用户已经向联系人发送了一个订阅请求但还没有收到回复<br />
:# "To" = 用户已订阅联系人(单向)<br />
:# "To + Pending In" = 用户已订阅联系人, 联系人已经向用户发送了一个订阅请求但还没有收到回复<br />
:# "From" = 联系人已订阅用户(单向)<br />
:# "From + Pending Out" = 联系人已订阅用户(单向), 用户已经向联系人发送了一个订阅请求但还没有收到回复<br />
:# "Both" = 用户和联系人互相被对方订阅了(双向)<br />
<br />
===出站出席信息订阅节的服务器处理过程===<br />
<br />
:出站出席信息订阅节使用户能管理他或她对联系人的出席信息的订阅(通过"subscribe"和"unsubscribe"类型), 并且管理联系人对用户的出席信息的访问(通过"subscribed"和"unsubscribed"类型).<br />
<br />
:因为用户的服务器和联系人的服务器有可能失去对于订阅状态的同步, 用户的服务器必须(MUST)毫无例外地路由所有"subscribe"或"unsubscribe"类型的出站出席信息节给联系人,使用户能在需要的时候重新同步他或她的对联系人的出席信息的订阅.<br />
<br />
:如果从用户的角度来看,一个"subscribed"或"unsubscribed"类型的出席信息节不会导致一个订阅状态的变更,用户的服务器不应该(SHOULD NOT)路由这个节到联系人那里,并且不能(MUST NOT)做出一个状态变更. 如果这个节导致一个订阅状态的变更, 用户的服务器必须(MUST)路由这个节到联系人,并且必须(MUST)做出相应的状态变更. 这些规则总结如下这些表.<br />
<br />
:表 1: 推荐的出站"subscribed"节的处理<br />
<br />
{|border="1" cellspacing="0" <br />
!当前状态 !! 路由? !! 新状态<br />
|-<br />
|"None" || 否 || 状态不变 <br />
|-<br />
|"None + Pending Out" || 否 || 状态不变 <br />
|-<br />
|"None + Pending In" || 是 || "From" <br />
|-<br />
|"None + Pending Out/In" || 是 || "From + Pending Out" <br />
|-<br />
|"To" || 否 || 状态不变 <br />
|-<br />
|"To + Pending In" || 是 || "Both" <br />
|-<br />
|"From" || 否 || 状态不变 <br />
|-<br />
|"From + Pending Out" || 否 || 状态不变 <br />
|-<br />
|"Both" || 否 || 状态不变 <br />
|}<br />
<br />
:表 2: 推荐的出站"unsubscribed"节处理<br />
<br />
{|border="1" cellspacing="0" <br />
!当前状态 !! 路由? !! 新状态 <br />
|-<br />
|"None" || 否 || 状态不变 <br />
|-<br />
|"None + Pending Out" || 否 || 状态不变 <br />
|-<br />
|"None + Pending In" || 是 || "None" <br />
|-<br />
|"None + Pending Out/In" || 是 || "None + Pending Out" <br />
|-<br />
|"To" || 否 || 状态不变 <br />
|-<br />
|"To + Pending In" || 是 || "To" <br />
|-<br />
|"From" || 是 || "None"<br />
|-<br />
|"From + Pending Out" || 是 || "None + Pending Out"<br />
|-<br />
|"Both" || 是 || "To"<br />
|}<br />
<br />
===入站出席信息订阅节的服务器处理过程===<br />
<br />
:入站出席信息订阅节从用户请求一个订阅相关的动作(通过"subscribe"类型), 通知用户由联系人所做的订阅状态相关的动作(通过"unsubscribe"类型),或使联系人能够管理用户对联系人的出席信息的访问(通过"subscribed"和"unsubscribed"类型).<br />
<br />
:当用户的服务器为用户从联系人那里接收到一个订阅请求(换言之, 一个"subscribe"类型的出席信息节), 如果用户未曾允许联系人访问用户的出席信息或者没有未决的入站订阅请求, 它必须(MUST)递送那个请求给用户;无论如何, 如果有一个未决的入站订阅请求, 用户的服务器不应该(SHOULD NOT)递送这个新的请求, 因为上一个订阅请求可能已经被记录下来了. 如果用户已经允许联系人访问用户的出席信息,用户的服务器应该(SHOULD)对一个从联系人发来的"subscribe"类型的入站出席信息节自动回复(通过代替用户向联系人发送一个"subscribed"类型的出席信息节); 这个规则使得联系人可以在需要的时候重新同步订阅状态. 这些规则总结如下面这些表.<br />
<br />
:表 3: 推荐的入站"subscribe"节处理<br />
<br />
{|border="1" cellspacing="0" <br />
!当前状态 !! 递送? !! 新状态 <br />
|-<br />
|"None" || 是 || "None + Pending In"<br />
|-<br />
|"None + Pending Out" || 是 || "None + Pending Out/In" <br />
|-<br />
|"None + Pending In" || 否 || 状态不变<br />
|-<br />
|"None + Pending Out/In" || 否 || 状态不变 <br />
|-<br />
|"To" || 是 || "To + Pending In" <br />
|-<br />
|"To + Pending In" || 否 || 状态不变 <br />
|-<br />
|"From" || 否 * || 状态不变 <br />
|-<br />
|"From + Pending Out" || 否 * || 状态不变 <br />
|-<br />
|"Both" || 否 * || 状态不变 <br />
|}<br />
<br />
:* 服务器应该(SHOULD)以"subscribed"节自动回复<br />
<br />
:当用户的服务器为用户从联系人那里收到一个"unsubscribe"类型的出席信息节, 如果从用户的角度看这个节会导致一个订阅状态变更,那么用户的服务器应该(SHOULD)代替用户自动应答(发送一个"unsubscribed"类型的出席信息节给联系人), 必须(MUST)递送这个"unsubscribe"节给用户,并且必须(MUST)改变状态. 如果不会导致订阅状态变更, 用户的服务器不应该(SHOULD NOT)递送这个节并且不能(MUST NOT)改变状态. 这些规则总结如下表.<br />
<br />
:表 4: 推荐的入站"unsubscribe"节处理<br />
<br />
{|border="1" cellspacing="0" <br />
!当前状态 !! 递送? !! 新状态 <br />
|-<br />
|"None" || 否 || 状态不变 <br />
|-<br />
|"None + Pending Out" || 否 || 状态不变 <br />
|-<br />
|"None + Pending In" || 是 * || "None" <br />
|-<br />
|"None + Pending Out/In" || 是 * || "None + Pending Out" <br />
|-<br />
|"To" || 否 || 状态不变 <br />
|-<br />
|"To + Pending In" || 是 * || "To" <br />
|-<br />
|"From" || 是 * || "None" <br />
|-<br />
|"From + Pending Out" || 是 * || "None + Pending Out <br />
|-<br />
|"Both" || 是 * || "To" <br />
|}<br />
<br />
:* 服务器应该(SHOULD)以"unsubscribed"节自动应答<br />
<br />
:当用户的服务器为用户从联系人那里收到一个"subscribed"类型的出席信息节, 如果没有一个为访问联系人的出席信息的未决的出站请求,它不能(MUST NOT)递送这个节给用户并且不能(MUST NOT)改变订阅状态. 如果有一个为了访问联系人的出席信息的未决的出站请求并且这个"subscribed"类型的入站出席信息请求会导致一个订阅状态的改变,用户的服务器必须(MUST)递送这个节给用户并且必须(MUST)改变订阅状态. 如果用户已经有授权可以访问联系人的出席信息, 这个"subscribed"类型的入站出席信息节不导致一个订阅状态的变更;从而用户的服务器不应该(SHOULD NOT)递送这个节给用户并且不能(MUST NOT)改变订阅状态. 这些规则总结如下表.<br />
<br />
:表 5: 推荐的入站"subscribed"节处理<br />
<br />
{|border="1" cellspacing="0" <br />
!当前状态 !! 递送? !! 新状态 <br />
|-<br />
|"None" || 否 || 状态不变 <br />
|-<br />
|"None + Pending Out" || 是 || "To" <br />
|-<br />
|"None + Pending In" || 否 || 状态不变 <br />
|-<br />
|"None + Pending Out/In" || 是 || "To + Pending In" <br />
|-<br />
|"To" || 否 || 状态不变 <br />
|-<br />
|"To + Pending In" || 否 || 状态不变 <br />
|-<br />
|"From" || 否 || 状态不变 <br />
|-<br />
|"From + Pending Out" || 是 || "Both" <br />
|-<br />
|"Both" || 否 || 状态不变 <br />
|}<br />
<br />
:当用户的服务器为用户从联系人那里收到了一个"unsubscribed"类型的出席信息节, 如果有一个为了访问联系人的出席信息的未决的出站请求或者用户当前已经有授权可以访问联系人的出席信息,它必须(MUST)递送这个节给用户并且必须(MUST)改变订阅状态. 否则, 用户的服务器不应该(SHOULD NOT)递送这个节并且不能(MUST NOT)改变订阅状态. 这些规则总结如下表.<br />
<br />
:表 6: 推荐的入站"unsubscribed"节处理<br />
<br />
{|border="1" cellspacing="0" <br />
!当前状态 !! 递送? !! 新状态 <br />
|-<br />
|"None" || 否 || 状态不变<br />
|-<br />
|"None + Pending Out" || 是 || "None" <br />
|-<br />
|"None + Pending In" || 否 || 状态不变 <br />
|-<br />
|"None + Pending Out/In" || 是 || "None + Pending In" <br />
|-<br />
|"To" || 是 || "None" <br />
|-<br />
|"To + Pending In" || 是 || "None + Pending In" <br />
|-<br />
|"From" || 否 || 状态不变 <br />
|-<br />
|"From + Pending Out" || 是 || "From" <br />
|-<br />
|"Both" || 是 || "From" <br />
|}<br />
<br />
===服务器递送和客户端承认订阅请求以及状态变更通知===<br />
<br />
:当一个服务器收到一个"subscribe"类型的入站出席信息节(换言之, 一个订阅请求)或"subscribed"类型,"unsubscribe"类型, 或"unsubscribed"类型(换言之, 一个订阅状态变更通知), 除了发送适当的名册推送(或当下次名册被一个可用资源请求时发送更新的名册), 它必须(MUST)递送这个请求或通知给预定的接收者至少一次. 一个服务器可以(MAY)要求接收者的回执以承认接收到了所有状态变更通知(并且必须(MUST)要求承认订阅请求的情形, 换言之,类型的出席信息节"subscribe"). 为了要求回执, 一个服务器应该(SHOULD)在每次接收者登陆的时候发送这个请求或通知给它, 直到这个接收者承认收到这个通知(通过证实"affirming"或禁止"denying"这个通知),如下表:<br />
<br />
:表 7: 订阅状态变更通知的承认<br />
<br />
{|border="1" cellspacing="0" <br />
!节类型 !! 接受 !! 禁止 <br />
|-<br />
|subscribe || subscribed || unsubscribed <br />
|-<br />
|subscribed || subscribe || unsubscribe <br />
|-<br />
|unsubscribe || unsubscribed || subscribed <br />
|-<br />
|unsubscribed || unsubscribe || subscribe <br />
|}<br />
<br />
:显然, 根据前述的订阅状态图表, 一些回执节将被路由到联系人并且导致状态的变更, 而其他的则不会. 无论如何, 任何这样的节必须(MUST)导致服务器不再发送订阅状态变更通知给用户.<br />
<br />
:因为在接收到roster set(其'subscription'属性值设为"remove"(见 移除一个名册条目并且取消所有订阅项 Removing a Roster Item and Cancelling All Subscriptions (第八章第六节)))之后,用户的服务器必须(MUST)自动生成"unsubscribe"和"unsubscribed"类型的出站出席信息节,服务器必须(MUST)把一个名册移除请求视为发送所有这些出席信息节,以决定是否继续向用户发送"subscribe"或"subscribed"类型的订阅状态变更通知.<br />
<br />
==屏蔽通信==<br />
<br />
:大多数即时消息系统已发现有必要实现一些方法来为用户屏蔽来自某些特定的其他用户的通信(这在[IMP-REQS]的第五章第一节第五小节, 第五章第一节第十五小节,第五章第三节第二小节, 和第五章第四节第十小节中也有要求). 在XMPP中这是由管理某人的隐私列表来实现的(使用'jabber:iq:privacy'名字空间).<br />
<br />
:服务器端的隐私列表使得以下用例能够完成:<br />
<br />
:* 接收某人的隐私列表.<br />
<br />
:* 增加, 移除, 和 编辑某人的隐私列表.<br />
<br />
:* 设置, 改变, 或 取消 激活的列表.<br />
<br />
:* 设置, 改变, 或 取消 缺省的列表 (换言之, 缺省激活的那个列表).<br />
<br />
:* 基于JID, group, 或 subscription 类型(或全局的) 允许或屏蔽消息.<br />
<br />
:* 允许或屏蔽入站出席信息通知,基于 JID, group, 或 subscription 类型 (或全局的).<br />
<br />
:* 允许或屏蔽出站出席信息通知,基于 JID, group, 或 subscription 类型 (或全局的).<br />
<br />
:* 允许或屏蔽 IQ 节, 基于 JID, group,或 subscription 类型(或全局的).<br />
<br />
:* 允许或屏蔽所有通信, 基于 JID, group, 或 subscription 类型(或全局的).<br />
<br />
:注意: 出席信息通知不包括出席信息订阅,只包括广播给那些已订阅了用户出席信息的实体的出席信息. 因而这包括没有'type'属性或只包含type='unavailable'的的出席信息节.<br />
<br />
===语法和语义===<br />
<br />
:一个用户可以(MAY)定义一个或更多的隐私列表, 它们由用户的服务器保存. 每个<list/>元素包含一个或多个格式为<item/>元素的规则, 并且每个<item/>元素使用属性来定义一个隐私规则类型, 一个适用于规则的特定值, 相应的动作, 和处理顺序相应的条目位置.<br />
<br />
:语法如下:<br />
<br />
<source lang="xml"><br />
<iq><br />
<query xmlns='jabber:iq:privacy'><br />
<list name='foo'><br />
<item<br />
type='[jid|group|subscription]'<br />
value='bar'<br />
action='[allow|deny]'<br />
order='unsignedInt'><br />
[<message/>]<br />
[<presence-in/>]<br />
[<presence-out/>]<br />
[<iq/>]<br />
</item><br />
</list><br />
</query><br />
</iq><br />
</source><br />
<br />
:如果类型是"jid", 那么'value'属性必须(MUST)包含一个合法的Jabber ID. JIDs 应该(SHOULD)满足以下顺序:<br />
<br />
:# <user@domain/resource> (仅为匹配的资源)<br />
:# <user@domain> (任何匹配的资源)<br />
:# <domain/resource> (仅匹配的资源)<br />
:# <domain> (匹配这个域本身, 正如任何 user@domain, domain/resource, 或 包含一个子域的地址)<br />
<br />
:如果类型为"group", 那么'value'属性应该(SHOULD)包含组在用户的名册中的名字. (如果一个客户端尝试更新, 新建, 或删除一个不在用户名册中的组的列表条目, 服务器应该(SHOULD)返回给客户端一个<item-not-found/>节错误.)<br />
<br />
:如果类型是"subscription", 那么'value'属性必须(MUST)是"both", "to", "from", 或"none" (定义在 名册语法和语义Roster Syntax and Semantics (第七章第一节))中的一个人, 在这里 "none" 包括对于用户来说完全未知和根本不在用户名册中的实体.<br />
<br />
:如果没有包含'type'属性, 这个规则提供 失败"fall-through" 情景.<br />
<br />
::'action'属性必须(MUST)被包含并且它的值必须(MUST)是 允许"allow"或 禁止"deny".<br />
<br />
::'order'属性必须(MUST)被包含并且它的值必须(MUST)是一个在列表的所有条目中具有唯一性的非负整数. (如果一个客户端尝试以一个非唯一的order值建立或更新一个列表, 服务器必须(MUST)返回给客户端一个<bad-request/>节错误.)<br />
<br />
::<item/>元素可以(MAY)包含一个或更多子元素,使得一个实体可以指明更多的细微控制包括屏蔽哪些种类的节(换言之, 不只是简单地屏蔽所有节). 允许的子元素包括:<br />
<br />
:* <message/> -- 屏蔽引入消息节<br />
:* <iq/> -- 屏蔽引入 IQ 节<br />
:* <presence-in/> -- 屏蔽引入出席信息通知<br />
:* <presence-out/> -- 屏蔽外出出席信息通知<br />
<br />
:在"jabber:iq:privacy'名字空间之内, 一个"set"类型的IQ节的<query/>子元素不能(MUST NOT)包含超过一个子元素(换言之, 这个节必须(MUST)只包含一个<active/>元素, 一个<default/>元素, 或一个<list/>元素); 如果一个发送中的实体违反了这个规则, 接收中的实体必须(MUST)返回一个 return a <bad-request/>节错误.<br />
<br />
:当一个客户端增加或更新一个隐私列表, <list/>元素应该(SHOULD)包含至少一个<item/>子元素; 当一个客户端移除一个隐私列表的时候, <list/>元素不能(MUST NOT)包含任何<item/>子元素.<br />
<br />
:当一个客户端更新一个隐私列表的时候, 它必须包含所有想得到的条目(换言之, 不是一个"delta").<br />
<br />
===商业规则===<br />
<br />
:# 如果有一个为某会话设置的激活的列表, 它只影响为其激活的那个会话, 并且只在那一个会话的持续期间有效; 服务器必须(MUST)只应用激活列表,并且不能(MUST NOT)应用缺省列表(换言之, 列表没有层次"layering").<br />
:# 缺省列表总体适用于用户, 并且如果没有为一个节指向的目标session/resource设置激活列表,或用户当前没有会话,它会被处理.<br />
:# 如果没有为一个会话设置激活列表(或用户当前没有会话), 并且没有缺省列表,那么所有节应该被(SHOULD BE)接受或由服务器代替用户做适当的处理(遵守 用于处理XML节的服务器规则 Server Rules for Handling XML Stanzas (第十一章)).<br />
:# 隐私列表必须(MUST)是第一个由服务器应用的递送规则, 替代 (1) 定义在 用于处理XML节的服务器规则Server Rules for Handling XML Stanzas (第十一章)的路由和递送规则, 以及 (2)和订阅相关的出席信息节的处理(和相应的名册推送的生成) 定义在 名册条目和出席信息订阅的集成Integration of Roster Items and Presence Subscriptions (第八章).<br />
:# 服务器处理隐私列表条目的顺序是很重要的. 列表条目必须(MUST)按照每个<item/>的'order'属性的整数值的升序来处理.<br />
:# 一旦节和一个隐私列表规则匹配, 服务器必须(MUST)按照这个规则适当地处理这个节,然后终止处理.<br />
:# 如果在一个列表中没有提供一个fall-through的条目, fall-through 动作被假定为 允许"allow".<br />
:# 如果一个用户为一个激活列表更新定义, 之后的基于那个激活列表的操作必须(MUST)使用更新的定义(为了那些激活列表正应用的所有资源).<br />
:# 如果在用户的会话期间,在激活的或缺省的列表中定义的名册条目中的订阅状态改变了,或名册组改变了,接下来基于那个列表的处理必须(MUST)考虑计入这个已改变的状态或组(对那个列表当前应用的所有资源).<br />
:# 当一个规则的定义修改了的时候, 服务器必须(MUST)发送一个类型为"set"的IQ节给所有已连接的资源, 包括一个只有一个<list/>子元素的<query/>元素, 其'name'属性设为已修改的隐私列表的名字. 这些 隐私列表推送("privacy list pushes")遵守和用于名册管理的名册推送("roster pushes")同样的语义 , 除了被推送给已连接的资源的列表名字本身(不是完整的列表定义或那个"delta"). 是否接受这个修改了的列表定义最终由接收中的资源来决定, 尽管如果这个列表正在应用于一个已连接的资源,它应该(SHOULD)这样做.<br />
:# 当一个已连接的资源尝试移除一个列表或指定一个新的缺省列表,而那个列表应用于一个已连接的资源而不是正在发送的资源, 服务器必须(MUST)返回一个<conflict/>错误给发送中的资源并且不能(MUST NOT)执行这个请求的改变.<br />
<br />
===接收某人的隐私列表===<br />
<br />
:例子: 客户端向服务器请求隐私列表的名字:<br />
<br />
<source lang="xml"><br />
<iq from='romeo@example.net/orchard' type='get' id='getlist1'><br />
<query xmlns='jabber:iq:privacy'/><br />
</iq><br />
</source><br />
<br />
:例子: 服务器发送隐私列表的名字给客户端, 激活列表和缺省列表放在前面:<br />
<br />
<source lang="xml"><br />
<iq type='result' id='getlist1' to='romeo@example.net/orchard'><br />
<query xmlns='jabber:iq:privacy'><br />
<active name='private'/><br />
<default name='public'/><br />
<list name='public'/><br />
<list name='private'/><br />
<list name='special'/><br />
</query><br />
</iq><br />
</source><br />
<br />
:例子: 客户端向服务器请求一个隐私列表:<br />
<br />
<source lang="xml"><br />
<iq from='romeo@example.net/orchard' type='get' id='getlist2'><br />
<query xmlns='jabber:iq:privacy'><br />
<list name='public'/><br />
</query><br />
</iq><br />
</source><br />
<br />
:例子: 服务器发送一个隐私列表给客户端:<br />
<br />
<source lang="xml"><br />
<iq type='result' id='getlist2' to='romeo@example.net/orchard'><br />
<query xmlns='jabber:iq:privacy'><br />
<list name='public'><br />
<item type='jid'<br />
value='tybalt@example.com'<br />
action='deny'<br />
order='1'/><br />
<item action='allow' order='2'/><br />
</list><br />
</query><br />
</iq><br />
</source><br />
<br />
:例子: 客户端向服务器请求另一个隐私列表:<br />
<br />
<source lang="xml"><br />
<iq from='romeo@example.net/orchard' type='get' id='getlist3'><br />
<query xmlns='jabber:iq:privacy'><br />
<list name='private'/><br />
</query><br />
</iq><br />
</source><br />
<br />
:例子: 服务器发送另一个隐私列表给客户端:<br />
<br />
<source lang="xml"><br />
<iq type='result' id='getlist3' to='romeo@example.net/orchard'><br />
<query xmlns='jabber:iq:privacy'><br />
<list name='private'><br />
<item type='subscription'<br />
value='both'<br />
action='allow'<br />
order='10'/><br />
<item action='deny' order='15'/><br />
</list><br />
</query><br />
</iq><br />
</source><br />
<br />
:例子: 客户端再向服务器请求另一个隐私列表:<br />
<br />
<source lang="xml"><br />
<iq from='romeo@example.net/orchard' type='get' id='getlist4'><br />
<query xmlns='jabber:iq:privacy'><br />
<list name='special'/><br />
</query><br />
</iq><br />
</source><br />
<br />
:例子: 服务器再发送另一个隐私列表给客户端:<br />
<br />
<source lang="xml"><br />
<iq type='result' id='getlist4' to='romeo@example.net/orchard'><br />
<query xmlns='jabber:iq:privacy'><br />
<list name='special'><br />
<item type='jid'<br />
value='juliet@example.com'<br />
action='allow'<br />
order='6'/><br />
<item type='jid'<br />
value='benvolio@example.org'<br />
action='allow'<br />
order='7'/><br />
<item type='jid'<br />
value='mercutio@example.org'<br />
action='allow'<br />
order='42'/><br />
<item action='deny' order='666'/><br />
</list><br />
</query><br />
</iq><br />
</source><br />
<br />
:在这个例子中, 用户有三个列表: (1) 'public', 它允许所有人的通信,除了一个指定的实体(这是缺省列表); (2) 'private', 它只允许和这个用户有双向订阅的联系人的通信(这是激活的列表); 还有 (3) 'special', 它只允许三个指定的实体通信.<br />
<br />
:如果用户尝试接收一个列表但是这个列表的名字不存在, 服务器必须(MUST)返回一个<item-not-found/>节错误给用户:<br />
<br />
:例子: 客户端尝试接收不存在的列表:<br />
<br />
<source lang="xml"><br />
<iq to='romeo@example.net/orchard' type='error' id='getlist5'><br />
<query xmlns='jabber:iq:privacy'><br />
<list name='The Empty Set'/><br />
</query><br />
<error type='cancel'><br />
<item-not-found<br />
xmlns='urn:ietf:params:xml:ns:xmpp-stanzas'/><br />
</error><br />
</iq><br />
</source><br />
<br />
:用户在一次只被允许接收一个列表. 如果用户尝试同一个请求中接收超过一个列表, 服务器必须(MUST)返回一个<bad request/>节错误给用户:<br />
<br />
:例子: 客户端尝试接收多于一个的列表:<br />
<br />
<source lang="xml"><br />
<iq to='romeo@example.net/orchard' type='error' id='getlist6'><br />
<query xmlns='jabber:iq:privacy'><br />
<list name='public'/><br />
<list name='private'/><br />
<list name='special'/><br />
</query><br />
<error type='modify'><br />
<bad-request<br />
xmlns='urn:ietf:params:xml:ns:xmpp-stanzas'/><br />
</error><br />
</iq><br />
</source><br />
<br />
===管理激活列表===<br />
<br />
:为了设置或改变服务器当前应用的激活列表, 用户必须(MUST)发送一个类型为"set"的IQ节,包含一个符合'jabber:iq:privacy'名字空间的<query/>元素,这个元素<query/>又包含一个空的<active/>子元素,而这个<active/>拥有一个'name'属性,'name'属性值则设为期望的列表名.<br />
<br />
:例子: 客户端请求激活列表变更:<br />
<br />
<source lang="xml"><br />
<iq from='romeo@example.net/orchard' type='set' id='active1'><br />
<query xmlns='jabber:iq:privacy'><br />
<active name='special'/><br />
</query><br />
</iq><br />
</source><br />
<br />
:服务器必须(MUST)在返回结果给客户端之前激活并应用这个已请求的列表.<br />
<br />
:例子: 服务器承认激活列表变更成功:<br />
<br />
<source lang="xml"><br />
<iq type='result' id='active1' to='romeo@example.net/orchard'/><br />
</source><br />
<br />
:如果用户尝试设置一个激活列表但是列表名不存在, 服务器必须(MUST)返回一个<item-not-found/>节错误给用户:<br />
<br />
:例子: 客户端尝试设置一个不存在的列表作为激活列表:<br />
<br />
<source lang="xml"><br />
<iq to='romeo@example.net/orchard' type='error' id='active2'><br />
<query xmlns='jabber:iq:privacy'><br />
<active name='The Empty Set'/><br />
</query><br />
<error type='cancel'><br />
<item-not-found<br />
xmlns='urn:ietf:params:xml:ns:xmpp-stanzas'/><br />
</error><br />
</iq><br />
</source><br />
<br />
:为了取消使用任何激活列表, 已连接的资源必须(MUST)发送一个空的<active/>元素,并且不带'name'属性.<br />
<br />
:例子: 客户端取消使用激活列表:<br />
<br />
<source lang="xml"><br />
<iq from='romeo@example.net/orchard' type='set' id='active3'><br />
<query xmlns='jabber:iq:privacy'><br />
<active/><br />
</query><br />
</iq><br />
</source><br />
<br />
:例子: 服务器承认取消任何激活列表成功:<br />
<br />
<source lang="xml"><br />
<iq type='result' id='active3' to='romeo@example.net/orchard'/><br />
</source><br />
<br />
===管理缺省列表===<br />
<br />
:为了改变它的缺省列表(它对用户来说是全局应用的, 不只是发送中的资源), 用户必须(MUST)发送一个类型为"set"的IQ节, 它包含一个符合'jabber:iq:privacy'名字空间的<query/>元素,这个<query/>元素包含一个空的<default/>子元素,这个<default/>子元素拥有一个'name'属性,这个'name'属性的值设为期望的列表名.<br />
<br />
:例子: 用户请求变更缺省列表:<br />
<br />
<source lang="xml"><br />
<iq from='romeo@example.net/orchard' type='set' id='default1'><br />
<query xmlns='jabber:iq:privacy'><br />
<default name='special'/><br />
</query><br />
</iq><br />
</source><br />
<br />
:例子: 服务器承认缺省列表变更成功:<br />
<br />
<source lang="xml"><br />
<iq type='result' id='default1' to='romeo@example.net/orchard'/><br />
</source><br />
<br />
:如果用户尝试变更一个缺省列表但是这个缺省列表正在由至少一个已连接的但不是当前发送中的这个资源使用着,服务器必须(MUST)返回一个<conflict/>节错误给发送中的资源:<br />
<br />
:例子: 客户端尝试改变一个缺省列表但是这个列表正在被另一个资源使用:<br />
<br />
<source lang="xml"><br />
<iq to='romeo@example.net/orchard' type='error' id='default1'><br />
<query xmlns='jabber:iq:privacy'><br />
<default name='special'/><br />
</query><br />
<error type='cancel'><br />
<conflict<br />
xmlns='urn:ietf:params:xml:ns:xmpp-stanzas'/><br />
</error><br />
</iq><br />
</source><br />
<br />
:如果用户尝试设置一个缺省列表但是这个列表的名字不存在, 服务器必须(MUST)返回一个<item-not-found/>节错误给用户:<br />
<br />
:例子: 客户端尝试设置一个不存在的列表作为缺省列表:<br />
<br />
<source lang="xml"><br />
<iq to='romeo@example.net/orchard' type='error' id='default1'><br />
<query xmlns='jabber:iq:privacy'><br />
<default name='The Empty Set'/><br />
</query><br />
<error type='cancel'><br />
<item-not-found<br />
xmlns='urn:ietf:params:xml:ns:xmpp-stanzas'/><br />
</error><br />
</iq><br />
</source><br />
<br />
:为了取消使用缺省列表(换言之, 任何时候都使用域的节路由规则), 用户必须(MUST)发送一个空的不带'name'属性的<default/>元素.<br />
<br />
:例子: 客户端取消使用缺省列表:<br />
<br />
<source lang="xml"><br />
<iq from='romeo@example.net/orchard' type='set' id='default2'><br />
<query xmlns='jabber:iq:privacy'><br />
<default/><br />
</query><br />
</iq><br />
</source><br />
<br />
:例子: 服务器承认成功地取消了任何缺省列表:<br />
<br />
<source lang="xml"><br />
<iq type='result' id='default2' to='romeo@example.net/orchard'/><br />
</source><br />
<br />
:如果一个已连接的资源尝试取消一个用户全局的缺省列表但是这个缺省列表正在应用于另一个已连接的资源,服务器必须(MUST)返回一个<conflict/>错误给发送中的资源:<br />
<br />
:例子: 客户端尝试取消一个缺省列表但是这个列表正在被另一个资源使用:<br />
<br />
<source lang="xml"><br />
<iq to='romeo@example.net/orchard' type='error' id='default3'><br />
<query xmlns='jabber:iq:privacy'><br />
<default/><br />
</query><br />
<error type='cancel'><br />
<conflict<br />
xmlns='urn:ietf:params:xml:ns:xmpp-stanzas'/><br />
</error><br />
</iq><br />
</source><br />
<br />
===编辑一个隐私列表===<br />
<br />
:为了编辑一个隐私列表, 用户必须(MUST)一个类型为"set"的IQ节,包含一个符合'jabber:iq:privacy'名字空间的<query/>元素,这个<query/>元素包含一个拥有一个<list/>子元素,这个<list/>子元素拥有一个'name'属性,这个'name'属性的值设为用户想编辑的列表名. 这个<list/>元素必须(MUST)包含一个或多个<item/>元素, 它们包含了列表中的所有元素以指明用户期望的对列表的变更(不是the "delta").<br />
<br />
:例子: 客户端编辑隐私列表:<br />
<br />
<source lang="xml"><br />
<iq from='romeo@example.net/orchard' type='set' id='edit1'><br />
<query xmlns='jabber:iq:privacy'><br />
<list name='public'><br />
<item type='jid'<br />
value='tybalt@example.com'<br />
action='deny'<br />
order='3'/><br />
<item type='jid'<br />
value='paris@example.org'<br />
action='deny'<br />
order='5'/><br />
<item action='allow' order='68'/><br />
</list><br />
</query><br />
</iq><br />
</source><br />
<br />
:例子: 服务器承认列表编辑成功:<br />
<br />
<source lang="xml"><br />
<iq type='result' id='edit1' to='romeo@example.net/orchard'/><br />
</source><br />
<br />
:注意: 任何给定的条目的'order'属性值不是固定的. 因而在前述的例子中如果用户想在"tybalt@example.com"条目和"paris@example.org"条目之间增加4个条目, 用户的客户端必须(MUST)在向服务器提交列表之前对相关的条目重新编号.<br />
<br />
:服务器必须(MUST)现在发送一个 隐私列表推送"privacy list push"给所有已连接的资源:<br />
<br />
:例子: 基于列表编辑的隐私列表推送:<br />
<br />
<source lang="xml"><br />
<iq to='romeo@example.net/orchard' type='set' id='push1'><br />
<query xmlns='jabber:iq:privacy'><br />
<list name='public'/><br />
</query><br />
</iq><br />
<iq to='romeo@example.net/home' type='set' id='push2'><br />
<query xmlns='jabber:iq:privacy'><br />
<list name='public'/><br />
</query><br />
</iq><br />
</source><br />
<br />
:按照定义在[XMPP-CORE|XMPP文档列表/XMPP正式RFC标准/RFC3920]的IQ节语义, 每个已连接的子元素必须(MUST)返回一个如下的 IQ result 给服务器:<br />
<br />
:例子: 承认收到一个隐私列表推送:<br />
<br />
<source lang="xml"><br />
<iq from='romeo@example.net/orchard'<br />
type='result'<br />
id='push1'/><br />
<iq from='romeo@example.net/home'<br />
type='result'<br />
id='push2'/><br />
</source><br />
<br />
===增加一个新的隐私列表===<br />
<br />
:增加一个新的列表和编辑一个现有的列表使用的协议是相同的. 如果列表名和现有的列表名吻合, 这个增加新列表的请求将覆写那个旧的列表. 正如编辑列表一样, 服务器也必须(MUST)发送一个 隐私列表推送"privacy list push" 给所有已连接的资源.<br />
<br />
===移除一个隐私列表===<br />
<br />
:为了移除一个隐私列表, 用户必须(MUST)发送一个类型为"set"的IQ节,包含一个符合'jabber:iq:privacy'名字空间的<query/>元素,这个<query/>元素包含一个空的<list/>子元素,这个<list/>子元素拥有一个'name'属性,这个'name'属性的值设为用户想移除的列表名.<br />
<br />
:例子: 客户端移除一个隐私列表:<br />
<br />
<source lang="xml"><br />
<iq from='romeo@example.net/orchard' type='set' id='remove1'><br />
<query xmlns='jabber:iq:privacy'><br />
<list name='private'/><br />
</query><br />
</iq><br />
</source><br />
<br />
:例子: 服务器承认成功地移除列表:<br />
<br />
<source lang="xml"><br />
<iq type='result' id='remove1' to='romeo@example.net/orchard'/><br />
</source><br />
<br />
:如果一个用户尝试移除一个列表而这个列表正在被应用于至少一个和发送中的资源不同的已连接的资源, 服务器必须(MUST)返回一个<conflict/>节错误给用户; 换言之, 用户在尝试移除它之前必须(MUST)先设置另一个列表成为激活或缺省列表. 如果用户尝试移除一个列表但是列表名字不存在, 服务器必须(MUST)返回一个<item-not-found/>节错误给用户. 如果用户尝试在同一个请求中移除超过一个的列表, 服务器必须(MUST)反回一个<bad request/>节错误给用户.<br />
<br />
===屏蔽消息===<br />
<br />
:服务器端的隐私列表使得一个用户可以基于实体的JID,名册组,或订阅状态(或全局地)来屏蔽从其他实体引入的消息. 以下例子阐明这个协议. (注意: 为了精简, "result"类型的IQ节没有在以下例子中显示, 隐私列表推送也没有显示.)<br />
<br />
:例子: 基于JID的用户屏蔽:<br />
<br />
<source lang="xml"><br />
<iq from='romeo@example.net/orchard' type='set' id='msg1'><br />
<query xmlns='jabber:iq:privacy'><br />
<list name='message-jid-example'><br />
<item type='jid'<br />
value='tybalt@example.com'<br />
action='deny'<br />
order='3'><br />
<message/><br />
</item><br />
</list><br />
</query><br />
</iq><br />
</source><br />
<br />
:作为建立和应用前述列表的结果, 用户将不会接收到从特定JID发来的消息.<br />
<br />
:例子: 基于名册组的用户屏蔽:<br />
<br />
<source lang="xml"><br />
<iq from='romeo@example.net/orchard' type='set' id='msg2'><br />
<query xmlns='jabber:iq:privacy'><br />
<list name='message-group-example'><br />
<item type='group'<br />
value='Enemies'<br />
action='deny'<br />
order='4'><br />
<message/><br />
</item><br />
</list><br />
</query><br />
</iq><br />
</source><br />
<br />
:作为建立和应用前述列表的结果, 用户将不会收到从指定名册组中的任何实体发来的消息.<br />
<br />
:例子: 基于订阅状态的用户屏蔽:<br />
<br />
<source lang="xml"><br />
<iq from='romeo@example.net/orchard' type='set' id='msg3'><br />
<query xmlns='jabber:iq:privacy'><br />
<list name='message-sub-example'><br />
<item type='subscription'<br />
value='none'<br />
action='deny'<br />
order='5'><br />
<message/><br />
</item><br />
</list><br />
</query><br />
</iq><br />
</source><br />
<br />
:作为建立和应用前述列表的结果, 用户将不会收到从任何指定订阅状态的实体发来的消息.<br />
<br />
:例子: 全局的用户屏蔽:<br />
<br />
<source lang="xml"><br />
<iq from='romeo@example.net/orchard' type='set' id='msg4'><br />
<query xmlns='jabber:iq:privacy'><br />
<list name='message-global-example'><br />
<item action='deny' order='6'><br />
<message/><br />
</item><br />
</list><br />
</query><br />
</iq><br />
</source><br />
<br />
:作为建立和应用前述列表的结果, 用户将不会收到从任何其他用户发来的消息.<br />
<br />
===屏蔽入站出席信息通知===<br />
<br />
:服务器端的隐私列表使得用户可以基于实体的JID,名册组,或订阅状态(或全局地)屏蔽来自其他实体的入站出席信息通知. 以下例子阐明了这个协议.<br />
<br />
:注意: 出席信息通知不包括出席信息订阅,只是把出席信息广播给当前已订阅某个联系人的出席信息的用户. 所以它只包括没有'type'属性的或type='unavailable'的出席信息节.<br />
<br />
:例子: 基于JID的用户屏蔽:<br />
<br />
<source lang="xml"><br />
<iq from='romeo@example.net/orchard' type='set' id='presin1'><br />
<query xmlns='jabber:iq:privacy'><br />
<list name='presin-jid-example'><br />
<item type='jid'<br />
value='tybalt@example.com'<br />
action='deny'<br />
order='7'><br />
<presence-in/><br />
</item><br />
</list><br />
</query><br />
</iq><br />
</source><br />
<br />
:作为建立和应用前述列表的结果, 用户将不会收到从指定JID发来的出席信息通知.<br />
<br />
:例子: 基于名册组的用户屏蔽:<br />
<br />
<source lang="xml"><br />
<iq from='romeo@example.net/orchard' type='set' id='presin2'><br />
<query xmlns='jabber:iq:privacy'><br />
<list name='presin-group-example'><br />
<item type='group'<br />
value='Enemies'<br />
action='deny'<br />
order='8'><br />
<presence-in/><br />
</item><br />
</list><br />
</query><br />
</iq><br />
</source><br />
<br />
:作为建立和应用前述列表的结果, 用户将不会从指定的名册组中的任何实体收到出席信息通知.<br />
<br />
:例子: 基于订阅状态的用户屏蔽:<br />
<br />
<source lang="xml"><br />
<iq from='romeo@example.net/orchard' type='set' id='presin3'><br />
<query xmlns='jabber:iq:privacy'><br />
<list name='presin-sub-example'><br />
<item type='subscription'<br />
value='to'<br />
action='deny'<br />
order='9'><br />
<presence-in/><br />
</item><br />
</list><br />
</query><br />
</iq><br />
</source><br />
<br />
:作为建立和应用前述列表的结果, 用户将不会从指定订阅状态的任何实体收到出席信息通知.<br />
<br />
:例子: 全局的用户屏蔽:<br />
<br />
<source lang="xml"><br />
<iq from='romeo@example.net/orchard' type='set' id='presin4'><br />
<query xmlns='jabber:iq:privacy'><br />
<list name='presin-global-example'><br />
<item action='deny' order='11'><br />
<presence-in/><br />
</item><br />
</list><br />
</query><br />
</iq><br />
</source><br />
<br />
:作为建立和应用前述列表的结果, 用户将不会从任何其他实体收到出席信息通知.<br />
<br />
===屏蔽出站出席信息通知===<br />
<br />
:服务器端的隐私列表使用户能够屏蔽发出到其他实体的出席信息通知(基于实体的JID, 名册组, 或订阅状态 (或全局的)). 以下例子阐明了这个协议.<br />
<br />
:注意: 出席信息通知不包括出席信息订阅,只把出席信息广播给已订阅了用户的出席信息的联系人.所以 只包括没有'type'属性或type='unavailable'的出席信息节.<br />
<br />
:例子: 基于JID的用户屏蔽:<br />
<br />
<source lang="xml"><br />
<iq from='romeo@example.net/orchard' type='set' id='presout1'><br />
<query xmlns='jabber:iq:privacy'><br />
<list name='presout-jid-example'><br />
<item type='jid'<br />
value='tybalt@example.com'<br />
action='deny'<br />
order='13'><br />
<presence-out/><br />
</item><br />
</list><br />
</query><br />
</iq><br />
</source><br />
<br />
:作为建立和应用前述列表的结果, 用户将不会给指定JID发送出席信息通知.<br />
<br />
:例子: 基于名册组的用户屏蔽:<br />
<br />
<source lang="xml"><br />
<iq from='romeo@example.net/orchard' type='set' id='presout2'><br />
<query xmlns='jabber:iq:privacy'><br />
<list name='presout-group-example'><br />
<item type='group'<br />
value='Enemies'<br />
action='deny'<br />
order='15'><br />
<presence-out/><br />
</item><br />
</list><br />
</query><br />
</iq><br />
</source><br />
<br />
:作为建立和应用前述列表的结果, 用户将不会向指定名册组的任何实体发送出席信息通知.<br />
<br />
:例子: 基于订阅状态的用户屏蔽:<br />
<br />
<source lang="xml"><br />
<iq from='romeo@example.net/orchard' type='set' id='presout3'><br />
<query xmlns='jabber:iq:privacy'><br />
<list name='presout-sub-example'><br />
<item type='subscription'<br />
value='from'<br />
action='deny'<br />
order='17'><br />
<presence-out/><br />
</item><br />
</list><br />
</query><br />
</iq><br />
</source><br />
<br />
:作为建立和应用前述列表的结果, 用户将不会向指定订阅状态的任何实体发送出席信息通知.<br />
<br />
:例子: 全局的用户屏蔽:<br />
<br />
<source lang="xml"><br />
<iq from='romeo@example.net/orchard' type='set' id='presout4'><br />
<query xmlns='jabber:iq:privacy'><br />
<list name='presout-global-example'><br />
<item action='deny' order='23'><br />
<presence-out/><br />
</item><br />
</list><br />
</query><br />
</iq><br />
</source><br />
<br />
:作为建立和应用前述列表的结果, 用户将不会向任何其他用户发送出席信息通知.<br />
<br />
===屏蔽IQ节===<br />
<br />
:服务器端的隐私列表使用户能够屏蔽从其他实体进来的IQ节(基于实体的JID,名册组, 或订阅状态(或全局地)). 以下例子阐明了这个协议.<br />
<br />
:例子: 基于JID的用户屏蔽:<br />
<br />
<source lang="xml"><br />
<iq from='romeo@example.net/orchard' type='set' id='iq1'><br />
<query xmlns='jabber:iq:privacy'><br />
<list name='iq-jid-example'><br />
<item type='jid'<br />
value='tybalt@example.com'<br />
action='deny'<br />
order='29'><br />
<iq/><br />
</item><br />
</list><br />
</query><br />
</iq><br />
</source><br />
<br />
:作为建立和应用这个列表的结果, 用户将不会收到从指定JID发来的IQ节.<br />
<br />
:例子: 基于名册组的用户屏蔽:<br />
<br />
<source lang="xml"><br />
<iq from='romeo@example.net/orchard' type='set' id='iq2'><br />
<query xmlns='jabber:iq:privacy'><br />
<list name='iq-group-example'><br />
<item type='group'<br />
value='Enemies'<br />
action='deny'<br />
order='31'><br />
<iq/><br />
</item><br />
</list><br />
</query><br />
</iq><br />
</source><br />
<br />
:作为建立和应用前述列表的结果, 用户将不会收到从指定名册组的任何实体发来的IQ节.<br />
<br />
:例子: 基于订阅状态的用户屏蔽:<br />
<br />
<source lang="xml"><br />
<iq from='romeo@example.net/orchard' type='set' id='iq3'><br />
<query xmlns='jabber:iq:privacy'><br />
<list name='iq-sub-example'><br />
<item type='subscription'<br />
value='none'<br />
action='deny'<br />
order='17'><br />
<iq/><br />
</item><br />
</list><br />
</query><br />
</iq><br />
</source><br />
<br />
:作为建立和应用前述列表的结果, 用户将不会收到从指定订阅状态的任何实体发来的IQ节.<br />
<br />
:例子: 全局的用户屏蔽:<br />
<br />
<source lang="xml"><br />
<iq from='romeo@example.net/orchard' type='set' id='iq4'><br />
<query xmlns='jabber:iq:privacy'><br />
<list name='iq-global-example'><br />
<item action='deny' order='1'><br />
<iq/><br />
</item><br />
</list><br />
</query><br />
</iq><br />
</source><br />
<br />
:作为建立和应用前述列表的结果, 用户将不会收到从任何其他用户发来的IQ节.<br />
<br />
===屏蔽所有通信===<br />
<br />
:服务器端的隐私列表使用户能够基于其他实体的JID,名册组,或订阅状态(或全局的)屏蔽所有进来和出去的节. 注意那部包括订阅相关的出席信息节, 它们被排除在外 (定义在 屏蔽入站出席信息通知Blocking Inbound Presence Notifications (第十章第十节)). 以下例子阐明了这个协议.<br />
<br />
:例子: 基于JID的用户屏蔽:<br />
<br />
<source lang="xml"><br />
<iq from='romeo@example.net/orchard' type='set' id='all1'><br />
<query xmlns='jabber:iq:privacy'><br />
<list name='all-jid-example'><br />
<item type='jid'<br />
value='tybalt@example.com'<br />
action='deny'<br />
order='23'/><br />
</list><br />
</query><br />
</iq><br />
</source><br />
<br />
:作为建立和应用这个列表的结果, 用户将不会收到和发送任何通信给指定JID.<br />
<br />
:例子: 基于名册组的用户屏蔽:<br />
<br />
<source lang="xml"><br />
<iq from='romeo@example.net/orchard' type='set' id='all2'><br />
<query xmlns='jabber:iq:privacy'><br />
<list name='all-group-example'><br />
<item type='group'<br />
value='Enemies'<br />
action='deny'<br />
order='13'/><br />
</list><br />
</query><br />
</iq><br />
</source><br />
<br />
:作为建立和应用前述列表的结果, 用户将不会收到和发送和指定名册组的任何实体的通信.<br />
<br />
:例子: 基于订阅状态的用户屏蔽:<br />
<br />
<source lang="xml"><br />
<iq from='romeo@example.net/orchard' type='set' id='all3'><br />
<query xmlns='jabber:iq:privacy'><br />
<list name='all-sub-example'><br />
<item type='subscription'<br />
value='none'<br />
action='deny'<br />
order='11'/><br />
</list><br />
</query><br />
</iq><br />
</source><br />
<br />
:作为建立和应用前述列表的结果, 用户将不会收到和发送和指定订阅状态的任何实体的通信.<br />
<br />
:例子: 全局的用户屏蔽:<br />
<br />
<source lang="xml"><br />
<iq from='romeo@example.net/orchard' type='set' id='all4'><br />
<query xmlns='jabber:iq:privacy'><br />
<list name='all-global-example'><br />
<item action='deny' order='7'/><br />
</list><br />
</query><br />
</iq><br />
</source><br />
<br />
:作为建立和应用前述列表的结果, 用户将不会收到和发送和任何其他用户的通信.<br />
<br />
===已被屏蔽的实体尝试和用户通信===<br />
<br />
:如果一个已被屏蔽的实体尝试发送消息或出席信息给用户, 用户的服务器应该(SHOULD)安静的丢掉这个节并且不能(MUST NOT)返回一个错误给发送的实体.<br />
<br />
:如果一个已被屏蔽的实体尝试发送一个类型为"get"或"set"的IQ节给用户, 用户的服务器必须(MUST)给发送的实体一个<service-unavailable/>节错误, 因为这是一个客户端不理解IQ get或set的名字空间的时候所发送的标准错误码. 其他类型的IQ节应该(SHOULD)被服务器安静的丢弃.<br />
<br />
:例子: 已被屏蔽的实体尝试发送 IQ get:<br />
<br />
<source lang="xml"><br />
<iq type='get'<br />
to='romeo@example.net'<br />
from='tybalt@example.com/pda'<br />
id='probing1'><br />
<query xmlns='jabber:iq:version'/><br />
</iq><br />
</source><br />
<br />
:例子: 服务器返回一个错误给已被屏蔽的实体:<br />
<br />
<source lang="xml"><br />
<iq type='error'<br />
from='romeo@example.net'<br />
to='tybalt@example.com/pda'<br />
id='probing1'><br />
<query xmlns='jabber:iq:version'/><br />
<error type='cancel'><br />
<service-unavailable<br />
xmlns='urn:ietf:params:xml:ns:xmpp-stanzas'/><br />
</error><br />
</iq><br />
</source><br />
<br />
===高级启发===<br />
<br />
:当建立一个高级隐私启发的表达式的时候, 客户端应该(SHOULD)使用尽可能简单的表达式.<br />
<br />
:例如, 启发 "屏蔽不在我名册中的任何用户的通信" 可以使用以下任何一种方式来构造:<br />
<br />
:* 允许任何来自我的名册中的JID的通信 (换言之, 列出每个JID成为单独的列表条目), 但是屏蔽和其他任何人的通信<br />
<br />
:* 允许任何来自我的名册的某个组中的用户的通信(换言之, 列出每个组作为单独的条目), 但是屏蔽和任何其他人的通信<br />
<br />
:* 允许任何我的他(她)之间的订阅状态为'both'或'to'或'from'的用户的通信(换言之, 单独列出每个订阅状态值), 但是屏蔽和任何其他人的通信<br />
<br />
:* 屏蔽和任何订阅状态为'none'的用户的通信<br />
<br />
:最后一个表达式是最简单的并且应该(SHOULD)被使用; 这种情形下将被发送的XML如下:<br />
<br />
<source lang="xml"><br />
<iq type='set' id='heuristic1'><br />
<query xmlns='jabber:iq:privacy'><br />
<list name='heuristic-example'><br />
<item type='subscription'<br />
value='none'<br />
action='deny'<br />
order='437'/><br />
</list><br />
</query><br />
</iq><br />
</source><br />
<br />
==服务器处理XML节的规则==<br />
<br />
:用于服务器的基本路由和递送规则定义在[XMPP-CORE|XMPP文档列表/XMPP正式RFC标准/RFC3920]中. 本章定义附加的用于XMPP兼容的即时消息和出席信息服务器规则.<br />
<br />
===入站节===<br />
<br />
:如果一个入站的节的'to'属性的JID中的域标识符部分的主机名和服务器自身的主机名相同并且'to'属性的JID的格式是<user@example.com>或<user@example.com/resource>, 服务器必须(MUST)首先强制应用任何隐私列表(第十章),然后服从以下定义的规则:<br />
<br />
:# 如果JID的格式是<user@domain/resource>并且有一个可用的资源和这个全JID吻合, 接受这得服务器必须(MUST)递送这个节给那个资源.<br />
:# 然后如果JID的格式是<user@domain>或格式是<user@domain/resource>,并且和用户相关的帐号不存在, 接收者的服务器 (a) 如果它是一个出席信息节,应该(SHOULD) 安静的忽略这个节(换言之,既不递送它也不返回一个错误), (b) 如果它是一个IQ节,必须(MUST)返回一个<service-unavailable/>节错误给发送者, 并且 (c) 如果它是一个消息节,应该(SHOULD)返回一个<service-unavailable/>节错误给发送者.<br />
:# 然后如果JID的格式是<user@domain/resource>并且没有可用的资源和它的全JID匹配, 接收者的服务器 (a) 如果它是一个出席信息节,应该(SHOULD)安静地忽略这个节(换言之, 既不递送它也不返回一个错误), (b) 如果它是一个IQ节,必须(MUST)返回一个<service-unavailable/>节错误给发送者, 并且 (c) 如果它是一个消息节,应该(SHOULD)把这个节视为发往<user@domain>.<br />
:# 然后如果JID的格式是<user@domain>并且这个用户至少有一个可用的资源, 接收者的服务器必须(MUST)遵守以下规则:<br />
:## 对于消息节, 服务器应该(SHOULD)递送这个节给高优先级的可用资源(如果这个资源没有提供<priority/>元素的值, 服务器应该(SHOULD)认为它提供的值为零). 如果两个或更多的可用资源有相同的优先级, 服务器可以(MAY)使用一些其他的规则(例如, 最近的连接时间, 最近的活动时间, 或由一些<show/>值的层次所定义的最高的可用性) 来从它们中间选择,或可以(MAY)递送这个消息到所有这些资源. 无论如何, 服务器不能(MUST NOT)这个节到一个优先级为负数的可用资源; 如果唯一的一个可用资源的优先级是负数, 服务器应该(SHOULD)当成没有可用资源一样处理这个消息(定义在后面). 另外, 服务器不能(MUST NOT)重写'to'属性(换言之, 它必须(MUST)让它保持<user@domain>而不是改成<user@domain/resource>).<br />
:## 对于类型不是"probe"的出席信息节, 服务器必须(MUST)递送这个节给所有可用的资源;对于出席信息调查, 服务器应该(SHOULD)基于定义在 出席信息调查Presence Probes (第五章第一节第三小节)的规则来应答. 另外, 服务器不能(MUST NOT)重写'to'属性(换言之, 它必须(MUST)保持<user@domain>而不是改为<user@domain/resource>).<br />
:## 对于IQ节, 服务器本身必须(MUST)代替用户应答一个IQ result或一个IQ error, 并且不能(MUST NOT)递送这个IQ节给任何可用的资源. 具体来说, 如果合格的名字空间的语义定义了一个服务器可以提供的应答, 服务器必须(MUST)代替用户应答这个节; 如果没有, 服务器必须(MUST)应答一个<service-unavailable/>节错误.<br />
:# 然后如果JID的格式为<user@domain>并且没有这个用户的可用资源, 这个节如何处理依赖于节的类型:<br />
:## 对于类型为"subscribe", "subscribed", "unsubscribe", 和"unsubscribed"的出席信息节, 服务器必须(MUST)维持这个节的一个记并且至少递送这个节一次(也就是, 当这个用户下次建立一个可用的资源的时候); 另外, 服务器必须(MUST)递送类型为"subscribe"的出席信息节直到用户批准或拒绝这个订阅请求为止(参见 出席信息订阅Presence Subscriptions (第五章第一节第六小节)).<br />
:## 对于所有其他的出席信息节, 服务器应该(SHOULD)安静的忽略这个节,既不存储它用于以后递送也不代替用户应答它.<br />
:## 对于消息节, 服务器可以(MAY)选择代替用户存储这个节并且当用户下次可用的时候递送给他, 或通过一些其他的手段转发这个消息给用户(例如, 给用户的邮箱). 无论如何, 如果离线消息存储或消息转发没有激活, 服务器必须(MUST)返回发送者一个<service-unavailable/>节错误. (注意:离线信息存储和消息转发没有定义在 XMPP, 因为严格来说它们是实现和服务提供的问题.)<br />
:## 对于IQ节, 服务器本身必须(MUST)代替用户应答一个IQ result或一个IQ error. 具体来说,如果合法的名字空间的语义定义了一个服务器可以提供的应答, 服务器必须(MUST)代替用户应答这个节; 如果没有, 服务器必须(MUST)应答一个<service-unavailable/>节错误.<br />
<br />
===出站节===<br />
<br />
:如果出站节的'to'属性的地址的域标识符部分的主机名和服务器自身的一个主机名吻合, 服务器必须(MUST) 根据 入站节Inbound Stanzas(第十一章第一节)的规则递送这个节给一个本地实体.<br />
<br />
:如果出站节的'to'属性的地址的域标识符部分的主机名不和服务器自身的一个主机名吻合, 服务器必须(MUST)尝试路由这个节到外部域. 推荐的动作顺序定义如下:<br />
<br />
:# 首先尝试用一个"xmpp-server"服务和"tcp"协议的[SRV]服务解析这个外部的主机名,结果得到的资源记录格式如"_xmpp-server._tcp.example.com.", 定义在[XMPP-CORE|XMPP文档列表/XMPP正式RFC标准/RFC3920].<br />
:# 如果"xmpp-server"地址记录解析失败, 尝试解析"_im"或"_pres"[SRV]服务(定义在[IMP-SRV]), 使用"_im"服务用语<message/>节,使用"_pres"服务用语<presence/>节(如何处理<iq/>节取决于具体实现). 这样得到的结果是一个或多个格式为"_im.<proto>.example.com."或 "_pres.<proto>.example.com."的记录, 这里"<proto>"是一个注册在 即时消息SRV协议标签注册表Instant Messaging SRV Protocol Label registry中的一个标签,或者是 出席信息SRV协议标签注册表Presence SRV Protocol Label registry中的标签: 要么是"_xmpp",用于XMPP-aware的域,要么是一些 IANA注册的标签IANA-registered label (例如,"_simple") 用于 non-XMPP-aware 的域.<br />
:# 如果这两种SRV地址记录解析都失败了, 尝试执行一个通用的 IPv4/IPv6 地址记录解析来决定IP地址,使用"xmpp-server"端口号5269(已在IANA注册, 定义在[XMPP-CORE|XMPP文档列表/XMPP正式RFC标准/RFC3920]).<br />
<br />
:强烈鼓励部署服务器的管理员们保持 _im._xmpp, _pres._xmpp, 和 _xmpp._tcp SRV 记录正确同步, 因为不同的实现可能在"xmpp-server"查找之前执行"_im"和"_pres"查找.<br />
<br />
==即时消息和出席信息兼容性需求==<br />
<br />
:本章总结了即时消息和出席信息服务器和客户端为了保证兼容的实现而必须(MUST)支持的部分XMPP协议. 所有这些应用必须(MUST)遵守定义在[XMPP-CORE|XMPP文档列表/XMPP正式RFC标准/RFC3920]的要求. 本章的文字定义了附加的用于即时消息和出席信息的兼容性需求; 注意定义在这里的要求补充而不是替代核心需求. 也要注意一个服务器或客户端可以(MAY)仅支持出席信息或即时消息, 如果只想支持出席信息服务或即时消息服务,可以不必同时支持两个.<br />
<br />
===服务器===<br />
<br />
:除了核心服务器兼容需求之外, 一个即时消息和出席信息服务器必须(MUST)还要支持以下协议:<br />
<br />
:* 定义在本文中的所有服务器相关的即时消息和出席信息语法和语义, 包括代替客户端广播出席信息, 出席信息订阅, 名册存储和处理, 隐私列表, 以及 IM-specific 路由和递送规则<br />
<br />
===客户端===<br />
<br />
:除了核心的客户端兼容性需求之外, 一个即时消息和出席信息客户端还必须(MUST)支持以下协议:<br />
<br />
:* 生成和处理由XML规划定义的XML节的IM-specific语义, 包括消息和出席信息节以及它们的子元素的的'type'属性<br />
<br />
:* 所有本文定义的客户端相关的即时消息语法和语义, 包括出席信息订阅, 名册管理, 和隐私列表<br />
<br />
:* 端到端的对象加密(定义在 XMPP中的端到端对象加密End-to-End Object Encryption in the Extensible Messaging and Presence Protocol (XMPP) [XMPP-E2E])<br />
<br />
:一个客户端也必须(MUST)处理编码为"im:" URIs的地址(定义在[CPIM]), 并且可以(MAY)移除"im:"scheme并把地址解析委托给服务器(定义在 出站节Outbound Stanzas(第十一章第二节).<br />
<br />
==国际化事项==<br />
<br />
:关于国际化的考虑, 参考[XMPP-CORE|XMPP文档列表/XMPP正式RFC标准/RFC3920]相关章节.<br />
<br />
==安全性事项==<br />
<br />
:XMPP的核心安全性事项定义在[XMPP-CORE|XMPP文档列表/XMPP正式RFC标准/RFC3920]相关章节.<br />
<br />
:附加的事项仅适用于分散定义在本文许多地方的XMPP即时消息和出席信息应用; 特别是:<br />
<br />
:* 当一个服务器处理一个任何类型的入站节,这个节的预定接收者是和服务器的主机名相关的一个用户,服务器必须(MUST)首先强制应用任何隐私列表(第十章),见 处理XML节的服务器规则Server Rules for Handling XML Stanzas(第十一章)).<br />
<br />
:* 当一个服务器处理一个类型为"probe"的入站出席信息节,这个节的预定接收者是和服务器的主机名相关的一个用户, 如果这个发送者是一个由出席信息订阅决定的未被授权接收那个信息的实体,服务器不能(MUST NOT)揭露这个用户的出席信息(见 客户端和服务器出席信息职责Client and Server Presence Responsibilities (第五章第一节)).<br />
<br />
:* 当一个服务器处理一个任何类型的出站出席信息节,这个节没有type属性或type属性值为"unavailable", 为了确保这个出席信息不被广播给那些未被授权知道这个信息的实体, 它必须(MUST)服从客户端和服务器出席信息职责Client and Server Presence Responsibilities (第五章第一节) 定义的规则 .<br />
<br />
:* 当一个服务器生成一个错误节作为不存在的用户接收到的一个节的应答的时候, 使用<service-unavailable/>错误条件有助于防止著名的字典攻击, 因为这个错误和条件和其他一些错误条件相同,例如, 一个IQ子元素的名字空间不被理解, 或离线存储或消息转发不被一个域允许.<br />
<br />
==IANA事项==<br />
<br />
:很多相关的IANA事项, 参考[XMPP-CORE|XMPP文档列表/XMPP正式RFC标准/RFC3920]相关章节.<br />
<br />
===会话数据的XML名字空间名===<br />
<br />
:以下为XMPP中会话相关的数据定义了一个 URN 子名字空间. (这个名字空间名的格式遵循 IETF XML Registry [XML-REG].)<br />
<br />
::URI: urn:ietf:params:xml:ns:xmpp-session<br />
<br />
::Specification: RFC 3921<br />
<br />
::Description: This is the XML namespace name for session-related data in the Extensible Messaging and Presence Protocol (XMPP) as defined by RFC 3921.<br />
<br />
:Registrant Contact: IETF, XMPP Working Group, <xmppwg@jabber.org><br />
<br />
===即时消息SRV协议标签注册===<br />
<br />
:确定即时消息和出席信息地址[IMP-SRV],为那些能提供遵守"_im"SRV服务标签的服务定义了一个即时消息SRV协议标签注册表. 因为XMPP是其中一个协议, IANA在适当的注册项中注册了"_xmpp"协议标签,如下:<br />
<br />
::Protocol label: _xmpp<br />
<br />
::Specification: RFC 3921<br />
<br />
::Description: Instant messaging protocol label for the Extensible Messaging and Presence Protocol (XMPP) as defined by RFC 3921.<br />
<br />
::Registrant Contact: IETF, XMPP Working Group, <xmppwg@jabber.org><br />
<br />
===出席信息SRV协议标签注册===<br />
<br />
:确定即时消息和出席信息地址[IMP-SRV],为那些能够提供遵守"_pres"SRV服务标签的服务定义了一个出席信息SRV协议标签注册项. 因为XMPP是其中一个协议, IANA在适当的注册项中注册了"_xmpp"协议标签,如下:<br />
<br />
::Protocol label: _xmpp<br />
<br />
::Specification: RFC 3921<br />
<br />
::Description: Presence protocol label for the Extensible Messaging and Presence Protocol (XMPP) as defined by RFC 3921.<br />
<br />
::Registrant Contact: IETF, XMPP Working Group, <xmppwg@jabber.org><br />
<br />
==参考==<br />
<br />
===标准参考===<br />
<br />
:[CPIM] Peterson, J., "Common Profile for Instant Messaging (CPIM)", RFC 3860, August 2004.<br />
<br />
:[IMP-REQS] Day, M., Aggarwal, S., Mohr, G., and J. Vincent, "Instant Messaging/Presence Protocol Requirements", RFC 2779, February 2000.<br />
<br />
:[IMP-SRV] Peterson, J., "Address Resolution for Instant Messaging and Presence", RFC 3861, August 2004.<br />
<br />
:[SRV] Gulbrandsen, A., Vixie, P., and L. Esibov, "A DNS RR for specifying the location of services (DNS SRV)", RFC 2782, February 2000.<br />
<br />
:[TERMS] Bradner, S., "Key words for use in RFCs to Indicate Requirement Levels", BCP 14, RFC 2119, March 1997.<br />
<br />
:[XML] Bray, T., Paoli, J., Sperberg-McQueen, C., and E. Maler, "Extensible Markup Language (XML) 1.0 (2nd ed)", W3C REC-xml, October 2000, <http://www.w3.org/TR/REC-xml>.<br />
<br />
:[XML-NAMES] Bray, T., Hollander, D., and A. Layman, "Namespaces in XML", W3C REC-xml-names, January 1999, <http://www.w3.org/TR/REC-xml-names>.<br />
<br />
:[XMPP-CORE|XMPP文档列表/XMPP正式RFC标准/RFC3920] Saint-Andre, P., "Extensible Messaging and Presence Protocol (XMPP): Core", RFC 3920, October 2004.<br />
<br />
:[XMPP-E2E] Saint-Andre, P., "End-to-End Object Encryption in the Extensible Messaging and Presence Protocol (XMPP)", RFC 3923, October 2004.<br />
<br />
===信息参考===<br />
<br />
:[IMP-MODEL] Day, M., Rosenberg, J., and H. Sugano, "A Model for Presence and Instant Messaging", RFC 2778, February 2000.<br />
<br />
:[IRC] Oikarinen, J. and D. Reed, "Internet Relay Chat Protocol", RFC 1459, May 1993.<br />
<br />
:[JEP-0054] Saint-Andre, P., "vcard-temp", JSF JEP 0054, March 2003.<br />
<br />
:[JEP-0077] Saint-Andre, P., "In-Band Registration", JSF JEP 0077, August 2004.<br />
<br />
:[JEP-0078] Saint-Andre, P., "Non-SASL Authentication", JSF JEP 0078, July 2004.<br />
<br />
:[JSF] Jabber Software Foundation, "Jabber Software Foundation", <http://www.jabber.org/>.<br />
<br />
:[VCARD] Dawson, F. and T. Howes, "vCard MIME Directory Profile", RFC 2426, September 1998.<br />
<br />
:[XML-REG] Mealling, M., "The IETF XML Registry", BCP 81, RFC 3688, January 2004.<br />
<br />
==附录 A. vCards==<br />
<br />
:[IMP-REQS]的第三章第一节第三小节和第四章第一节第四小节要求可能为其他用户接收带外的联系人信息(例如,电话号码或电子邮件地址). 在Jabber社区中通常使用RFC 2426 [VCARD]中vCard规范的XML来表达这类信息,但这超出了XMPP的范围(这个协议的文档包含在[JEP-0054], 由[JSF]发行).<br />
<br />
译者注: [JSF]已改名为[XSF],[JEP-0054]已改名为[XEP-0054]<br />
<br />
==附录 B. XML规划==<br />
<br />
:接下来的XML规划是描述性的, 不是标准化的. 规划定义在XMPP的核心特性, 参考[XMPP-CORE|XMPP文档列表/XMPP正式RFC标准/RFC3920].<br />
<br />
===B.1 jabber:client===<br />
<br />
<source lang="xml"><br />
<?xml version='1.0' encoding='UTF-8'?><br />
<br />
<xs:schema<br />
xmlns:xs='http://www.w3.org/2001/XMLSchema'<br />
targetNamespace='jabber:client'<br />
xmlns='jabber:client'<br />
elementFormDefault='qualified'><br />
<br />
<xs:import namespace='urn:ietf:params:xml:ns:xmpp-stanzas'/><br />
<br />
<xs:element name='message'><br />
<xs:complexType><br />
<xs:sequence><br />
<xs:choice minOccurs='0' maxOccurs='unbounded'><br />
<xs:element ref='subject'/><br />
<xs:element ref='body'/><br />
<xs:element ref='thread'/><br />
</xs:choice><br />
<xs:any namespace='##other'<br />
minOccurs='0'<br />
maxOccurs='unbounded'/><br />
<xs:element ref='error'<br />
minOccurs='0'/><br />
</xs:sequence><br />
<xs:attribute name='from'<br />
type='xs:string'<br />
use='optional'/><br />
<xs:attribute name='id'<br />
type='xs:NMTOKEN'<br />
use='optional'/><br />
<xs:attribute name='to'<br />
type='xs:string'<br />
use='optional'/><br />
<xs:attribute name='type' use='optional' default='normal'><br />
<xs:simpleType><br />
<xs:restriction base='xs:NCName'><br />
<xs:enumeration value='chat'/><br />
<xs:enumeration value='error'/><br />
<xs:enumeration value='groupchat'/><br />
<xs:enumeration value='headline'/><br />
<xs:enumeration value='normal'/><br />
</xs:restriction><br />
</xs:simpleType><br />
</xs:attribute><br />
<xs:attribute ref='xml:lang' use='optional'/><br />
</xs:complexType><br />
</xs:element><br />
<br />
<xs:element name='body'><br />
<xs:complexType><br />
<xs:simpleContent><br />
<xs:extension base='xs:string'><br />
<xs:attribute ref='xml:lang' use='optional'/><br />
</xs:extension><br />
</xs:simpleContent><br />
</xs:complexType><br />
</xs:element><br />
<br />
<xs:element name='subject'><br />
<xs:complexType><br />
<xs:simpleContent><br />
<xs:extension base='xs:string'><br />
<xs:attribute ref='xml:lang' use='optional'/><br />
</xs:extension><br />
</xs:simpleContent><br />
</xs:complexType><br />
</xs:element><br />
<br />
<xs:element name='thread' type='xs:NMTOKEN'/><br />
<br />
<xs:element name='presence'><br />
<xs:complexType><br />
<xs:sequence><br />
<xs:choice minOccurs='0' maxOccurs='unbounded'><br />
<xs:element ref='show'/><br />
<xs:element ref='status'/><br />
<xs:element ref='priority'/><br />
</xs:choice><br />
<xs:any namespace='##other'<br />
minOccurs='0'<br />
maxOccurs='unbounded'/><br />
<xs:element ref='error'<br />
minOccurs='0'/><br />
</xs:sequence><br />
<xs:attribute name='from'<br />
type='xs:string'<br />
use='optional'/><br />
<xs:attribute name='id'<br />
type='xs:NMTOKEN'<br />
use='optional'/><br />
<xs:attribute name='to'<br />
type='xs:string'<br />
use='optional'/><br />
<xs:attribute name='type' use='optional'><br />
<xs:simpleType><br />
<xs:restriction base='xs:NCName'><br />
<xs:enumeration value='error'/><br />
<xs:enumeration value='probe'/><br />
<xs:enumeration value='subscribe'/><br />
<xs:enumeration value='subscribed'/><br />
<xs:enumeration value='unavailable'/><br />
<xs:enumeration value='unsubscribe'/><br />
<xs:enumeration value='unsubscribed'/><br />
</xs:restriction><br />
</xs:simpleType><br />
</xs:attribute><br />
<xs:attribute ref='xml:lang' use='optional'/><br />
</xs:complexType><br />
</xs:element><br />
<br />
<xs:element name='show'><br />
<xs:simpleType><br />
<xs:restriction base='xs:NCName'><br />
<xs:enumeration value='away'/><br />
<xs:enumeration value='chat'/><br />
<xs:enumeration value='dnd'/><br />
<xs:enumeration value='xa'/><br />
</xs:restriction><br />
</xs:simpleType><br />
</xs:element><br />
<br />
<xs:element name='status'><br />
<xs:complexType><br />
<xs:simpleContent><br />
<xs:extension base='xs:string'><br />
<xs:attribute ref='xml:lang' use='optional'/><br />
</xs:extension><br />
</xs:simpleContent><br />
</xs:complexType><br />
</xs:element><br />
<br />
<xs:element name='priority' type='xs:byte'/><br />
<br />
<xs:element name='iq'><br />
<xs:complexType><br />
<xs:sequence><br />
<xs:any namespace='##other'<br />
minOccurs='0'/><br />
<xs:element ref='error'<br />
minOccurs='0'/><br />
</xs:sequence><br />
<xs:attribute name='from'<br />
type='xs:string'<br />
use='optional'/><br />
<xs:attribute name='id'<br />
type='xs:NMTOKEN'<br />
use='required'/><br />
<xs:attribute name='to'<br />
type='xs:string'<br />
use='optional'/><br />
<xs:attribute name='type' use='required'><br />
<xs:simpleType><br />
<xs:restriction base='xs:NCName'><br />
<xs:enumeration value='error'/><br />
<xs:enumeration value='get'/><br />
<xs:enumeration value='result'/><br />
<xs:enumeration value='set'/><br />
</xs:restriction><br />
</xs:simpleType><br />
</xs:attribute><br />
<xs:attribute ref='xml:lang' use='optional'/><br />
</xs:complexType><br />
</xs:element><br />
<br />
<xs:element name='error'><br />
<xs:complexType><br />
<xs:sequence xmlns:err='urn:ietf:params:xml:ns:xmpp-stanzas'><br />
<xs:group ref='err:stanzaErrorGroup'/><br />
<xs:element ref='err:text'<br />
minOccurs='0'/><br />
</xs:sequence><br />
<xs:attribute name='code' type='xs:byte' use='optional'/><br />
<xs:attribute name='type' use='required'><br />
<xs:simpleType><br />
<xs:restriction base='xs:NCName'><br />
<xs:enumeration value='auth'/><br />
<xs:enumeration value='cancel'/><br />
<xs:enumeration value='continue'/><br />
<xs:enumeration value='modify'/><br />
<xs:enumeration value='wait'/><br />
</xs:restriction><br />
</xs:simpleType><br />
</xs:attribute><br />
</xs:complexType><br />
</xs:element><br />
<br />
</xs:schema><br />
</source><br />
<br />
===B.2 jabber:server===<br />
<br />
<source lang="xml"><br />
<br />
<?xml version='1.0' encoding='UTF-8'?><br />
<br />
<xs:schema<br />
xmlns:xs='http://www.w3.org/2001/XMLSchema'<br />
targetNamespace='jabber:server'<br />
xmlns='jabber:server'<br />
elementFormDefault='qualified'><br />
<br />
<xs:import namespace='urn:ietf:params:xml:ns:xmpp-stanzas'/><br />
<br />
<xs:element name='message'><br />
<xs:complexType><br />
<xs:sequence><br />
<xs:choice minOccurs='0' maxOccurs='unbounded'><br />
<xs:element ref='subject'/><br />
<xs:element ref='body'/><br />
<xs:element ref='thread'/><br />
</xs:choice><br />
<xs:any namespace='##other'<br />
minOccurs='0'<br />
maxOccurs='unbounded'/><br />
<xs:element ref='error'<br />
minOccurs='0'/><br />
</xs:sequence><br />
<xs:attribute name='from'<br />
type='xs:string'<br />
use='required'/><br />
<xs:attribute name='id'<br />
type='xs:NMTOKEN'<br />
use='optional'/><br />
<xs:attribute name='to'<br />
type='xs:string'<br />
use='required'/><br />
<xs:attribute name='type' use='optional' default='normal'><br />
<xs:simpleType><br />
<xs:restriction base='xs:NCName'><br />
<xs:enumeration value='chat'/><br />
<xs:enumeration value='error'/><br />
<xs:enumeration value='groupchat'/><br />
<xs:enumeration value='headline'/><br />
<xs:enumeration value='normal'/><br />
</xs:restriction><br />
</xs:simpleType><br />
</xs:attribute><br />
<xs:attribute ref='xml:lang' use='optional'/><br />
</xs:complexType><br />
</xs:element><br />
<br />
<xs:element name='body'><br />
<xs:complexType><br />
<xs:simpleContent><br />
<xs:extension base='xs:string'><br />
<xs:attribute ref='xml:lang' use='optional'/><br />
</xs:extension><br />
</xs:simpleContent><br />
</xs:complexType><br />
</xs:element><br />
<br />
<xs:element name='subject'><br />
<xs:complexType><br />
<xs:simpleContent><br />
<xs:extension base='xs:string'><br />
<xs:attribute ref='xml:lang' use='optional'/><br />
</xs:extension><br />
</xs:simpleContent><br />
</xs:complexType><br />
</xs:element><br />
<br />
<xs:element name='thread' type='xs:NMTOKEN'/><br />
<br />
<xs:element name='presence'><br />
<xs:complexType><br />
<xs:sequence><br />
<xs:choice minOccurs='0' maxOccurs='unbounded'><br />
<xs:element ref='show'/><br />
<xs:element ref='status'/><br />
<xs:element ref='priority'/><br />
</xs:choice><br />
<xs:any namespace='##other'<br />
minOccurs='0'<br />
maxOccurs='unbounded'/><br />
<xs:element ref='error'<br />
minOccurs='0'/><br />
</xs:sequence><br />
<xs:attribute name='from'<br />
type='xs:string'<br />
use='required'/><br />
<xs:attribute name='id'<br />
type='xs:NMTOKEN'<br />
use='optional'/><br />
<xs:attribute name='to'<br />
type='xs:string'<br />
use='required'/><br />
<xs:attribute name='type' use='optional'><br />
<xs:simpleType><br />
<xs:restriction base='xs:NCName'><br />
<xs:enumeration value='error'/><br />
<xs:enumeration value='probe'/><br />
<xs:enumeration value='subscribe'/><br />
<xs:enumeration value='subscribed'/><br />
<xs:enumeration value='unavailable'/><br />
<xs:enumeration value='unsubscribe'/><br />
<xs:enumeration value='unsubscribed'/><br />
</xs:restriction><br />
</xs:simpleType><br />
</xs:attribute><br />
<xs:attribute ref='xml:lang' use='optional'/><br />
</xs:complexType><br />
</xs:element><br />
<br />
<xs:element name='show'><br />
<xs:simpleType><br />
<xs:restriction base='xs:NCName'><br />
<xs:enumeration value='away'/><br />
<xs:enumeration value='chat'/><br />
<xs:enumeration value='dnd'/><br />
<xs:enumeration value='xa'/><br />
</xs:restriction><br />
</xs:simpleType><br />
</xs:element><br />
<br />
<xs:element name='status'><br />
<xs:complexType><br />
<xs:simpleContent><br />
<xs:extension base='xs:string'><br />
<xs:attribute ref='xml:lang' use='optional'/><br />
</xs:extension><br />
</xs:simpleContent><br />
</xs:complexType><br />
</xs:element><br />
<br />
<xs:element name='priority' type='xs:byte'/><br />
<br />
<xs:element name='iq'><br />
<xs:complexType><br />
<xs:sequence><br />
<xs:any namespace='##other'<br />
minOccurs='0'/><br />
<xs:element ref='error'<br />
minOccurs='0'/><br />
</xs:sequence><br />
<xs:attribute name='from'<br />
type='xs:string'<br />
use='required'/><br />
<xs:attribute name='id'<br />
type='xs:NMTOKEN'<br />
use='required'/><br />
<xs:attribute name='to'<br />
type='xs:string'<br />
use='required'/><br />
<xs:attribute name='type' use='required'><br />
<xs:simpleType><br />
<xs:restriction base='xs:NCName'><br />
<xs:enumeration value='error'/><br />
<xs:enumeration value='get'/><br />
<xs:enumeration value='result'/><br />
<xs:enumeration value='set'/><br />
</xs:restriction><br />
</xs:simpleType><br />
</xs:attribute><br />
<xs:attribute ref='xml:lang' use='optional'/><br />
</xs:complexType><br />
</xs:element><br />
<br />
<xs:element name='error'><br />
<xs:complexType><br />
<xs:sequence xmlns:err='urn:ietf:params:xml:ns:xmpp-stanzas'><br />
<xs:group ref='err:stanzaErrorGroup'/><br />
<xs:element ref='err:text'<br />
minOccurs='0'/><br />
</xs:sequence><br />
<xs:attribute name='code' type='xs:byte' use='optional'/><br />
<xs:attribute name='type' use='required'><br />
<xs:simpleType><br />
<xs:restriction base='xs:NCName'><br />
<xs:enumeration value='auth'/><br />
<xs:enumeration value='cancel'/><br />
<xs:enumeration value='continue'/><br />
<xs:enumeration value='modify'/><br />
<xs:enumeration value='wait'/><br />
</xs:restriction><br />
</xs:simpleType><br />
</xs:attribute><br />
</xs:complexType><br />
</xs:element><br />
<br />
</xs:schema><br />
</source><br />
<br />
===B.3 session===<br />
<br />
<source lang="xml"><br />
<?xml version='1.0' encoding='UTF-8'?><br />
<br />
<xs:schema<br />
xmlns:xs='http://www.w3.org/2001/XMLSchema'<br />
targetNamespace='urn:ietf:params:xml:ns:xmpp-session'<br />
xmlns='urn:ietf:params:xml:ns:xmpp-session'<br />
elementFormDefault='qualified'><br />
<br />
<xs:element name='session' type='empty'/><br />
<br />
<xs:simpleType name='empty'><br />
<xs:restriction base='xs:string'><br />
<xs:enumeration value=''/><br />
</xs:restriction><br />
</xs:simpleType><br />
<br />
</xs:schema><br />
</source><br />
<br />
===B.4 jabber:iq:privacy===<br />
<br />
<source lang="xml"><br />
<br />
<?xml version='1.0' encoding='UTF-8'?><br />
<br />
<xs:schema<br />
xmlns:xs='http://www.w3.org/2001/XMLSchema'<br />
targetNamespace='jabber:iq:privacy'<br />
xmlns='jabber:iq:privacy'<br />
elementFormDefault='qualified'><br />
<br />
<xs:element name='query'><br />
<xs:complexType><br />
<xs:sequence><br />
<xs:element ref='active'<br />
minOccurs='0'/><br />
<xs:element ref='default'<br />
minOccurs='0'/><br />
<xs:element ref='list'<br />
minOccurs='0'<br />
maxOccurs='unbounded'/><br />
</xs:sequence><br />
</xs:complexType><br />
</xs:element><br />
<br />
<xs:element name='active'><br />
<xs:complexType><br />
<xs:simpleContent><br />
<xs:extension base='xs:NMTOKEN'><br />
<xs:attribute name='name'<br />
type='xs:string'<br />
use='optional'/><br />
</xs:extension><br />
</xs:simpleContent><br />
</xs:complexType><br />
</xs:element><br />
<br />
<xs:element name='default'><br />
<xs:complexType><br />
<xs:simpleContent><br />
<xs:extension base='xs:NMTOKEN'><br />
<xs:attribute name='name'<br />
type='xs:string'<br />
use='optional'/><br />
</xs:extension><br />
</xs:simpleContent><br />
</xs:complexType><br />
</xs:element><br />
<br />
<xs:element name='list'><br />
<xs:complexType><br />
<xs:sequence><br />
<xs:element ref='item'<br />
minOccurs='0'<br />
maxOccurs='unbounded'/><br />
</xs:sequence><br />
<xs:attribute name='name'<br />
type='xs:string'<br />
use='required'/><br />
</xs:complexType><br />
</xs:element><br />
<br />
<xs:element name='item'><br />
<xs:complexType><br />
<xs:sequence><br />
<xs:element name='iq'<br />
minOccurs='0'<br />
type='empty'/><br />
<xs:element name='message'<br />
minOccurs='0'<br />
type='empty'/><br />
<xs:element name='presence-in'<br />
minOccurs='0'<br />
type='empty'/><br />
<xs:element name='presence-out'<br />
minOccurs='0'<br />
type='empty'/><br />
</xs:sequence><br />
<xs:attribute name='action' use='required'><br />
<xs:simpleType><br />
<xs:restriction base='xs:NCName'><br />
<xs:enumeration value='allow'/><br />
<xs:enumeration value='deny'/><br />
</xs:restriction><br />
</xs:simpleType><br />
</xs:attribute><br />
<xs:attribute name='order'<br />
type='xs:unsignedInt'<br />
use='required'/><br />
<xs:attribute name='type' use='optional'><br />
<xs:simpleType><br />
<xs:restriction base='xs:NCName'><br />
<xs:enumeration value='group'/><br />
<xs:enumeration value='jid'/><br />
<xs:enumeration value='subscription'/><br />
</xs:restriction><br />
</xs:simpleType><br />
</xs:attribute><br />
<xs:attribute name='value'<br />
type='xs:string'<br />
use='optional'/><br />
</xs:complexType><br />
</xs:element><br />
<br />
<xs:simpleType name='empty'><br />
<xs:restriction base='xs:string'><br />
<xs:enumeration value=''/><br />
</xs:restriction><br />
</xs:simpleType><br />
<br />
</xs:schema><br />
</source><br />
<br />
===B.5 jabber:iq:roster===<br />
<br />
<source lang="xml"><br />
<br />
<?xml version='1.0' encoding='UTF-8'?><br />
<br />
<xs:schema<br />
xmlns:xs='http://www.w3.org/2001/XMLSchema'<br />
targetNamespace='jabber:iq:roster'<br />
xmlns='jabber:iq:roster'<br />
elementFormDefault='qualified'><br />
<br />
<xs:element name='query'><br />
<xs:complexType><br />
<xs:sequence><br />
<xs:element ref='item'<br />
minOccurs='0'<br />
maxOccurs='unbounded'/><br />
</xs:sequence><br />
</xs:complexType><br />
</xs:element><br />
<br />
<xs:element name='item'><br />
<xs:complexType><br />
<xs:sequence><br />
<xs:element ref='group'<br />
minOccurs='0'<br />
maxOccurs='unbounded'/><br />
</xs:sequence><br />
<xs:attribute name='ask' use='optional'><br />
<xs:simpleType><br />
<xs:restriction base='xs:NCName'><br />
<xs:enumeration value='subscribe'/><br />
</xs:restriction><br />
</xs:simpleType><br />
</xs:attribute><br />
<xs:attribute name='jid' type='xs:string' use='required'/><br />
<xs:attribute name='name' type='xs:string' use='optional'/><br />
<xs:attribute name='subscription' use='optional'><br />
<xs:simpleType><br />
<xs:restriction base='xs:NCName'><br />
<xs:enumeration value='both'/><br />
<xs:enumeration value='from'/><br />
<xs:enumeration value='none'/><br />
<xs:enumeration value='remove'/><br />
<xs:enumeration value='to'/><br />
</xs:restriction><br />
</xs:simpleType><br />
</xs:attribute><br />
</xs:complexType><br />
</xs:element><br />
<br />
<xs:element name='group' type='xs:string'/><br />
<br />
</xs:schema><br />
</source><br />
<br />
==附录 C. Jabber IM Presence协议和XMPP之间的不同==<br />
<br />
:本章是非标准的.<br />
<br />
:译者注:附录D对于新接触XMPP的人没有什么意义,就不翻译了,免得浪费时间。因为现在RFC公布已经很久了,以前的Jabber实现很多都进化到XMPP了。<br />
<br />
:XMPP has been adapted from the protocols originally developed in the Jabber open-source community, which can be thought of as "XMPP 0.9". Because there exists a large installed base of Jabber implementations and deployments, it may be helpful to specify the key differences between the relevant Jabber protocols and XMPP in order to expedite and encourage upgrades of those implementations and deployments to XMPP. This section summarizes the differences that relate specifically to instant messaging and presence applications, while the corresponding section of [XMPP-CORE|XMPP文档列表/XMPP正式RFC标准/RFC3920] summarizes the differences that relate to all XMPP applications.<br />
<br />
===C.1 Session Establishment===<br />
<br />
:The client-to-server authentication protocol developed in the Jabber community assumed that every client is an IM client and therefore initiated an IM session upon successful authentication and resource binding, which are performed simultaneously (documentation of this protocol is contained in [JEP-0078], published by the Jabber Software Foundation [JSF]). XMPP maintains a stricter separation between core functionality and IM functionality; therefore, an IM session is not created until the client specifically requests one using the protocol defined under Session Establishment (Section 3).<br />
<br />
===C.2 Privacy Lists===<br />
<br />
:The Jabber community began to define a protocol for communications blocking (privacy lists) in late 2001, but that effort was deprecated once the XMPP Working Group was formed. Therefore the protocol defined under Blocking Communication (Section 10) is the only such protocol defined for use in the Jabber community.<br />
<br />
==贡献者==<br />
<br />
:XMPP的大部分核心方面是由1999年开始的Jabber开源社区开发的. 这个社区是由 Jeremie Miller建立的, 他于1999年1月发布了最初版的jabber server源代码. 主要的基础协议的早期贡献者还包括 Ryan Eatmon, Peter Millard, Thomas Muldowney,和 Dave Smith. XMPP工作组在即时消息和出席信息方面的工作主要集中在IM会话建立和通信屏蔽(隐私列表); 会话建立协议主要是由 Rob Norris 和 Joe Hildebrand 开发的, 隐私列表协议最初是由 Peter Millard.贡献的<br />
<br />
==致谢==<br />
<br />
:感谢许多在贡献者名单之外的人们. 尽管很难提供一个完整的名单, 以下个人对于定义协议或评论标准提供了很多帮助:<br />
:Thomas Charron, Richard Dobson, Schuyler Heath, Jonathan Hogg, Craig Kaes, Jacek Konieczny, Lisa Dusseault, Alexey Melnikov, Keith Minkler, Julian Missig, Pete Resnick, Marshall Rose, Jean-Louis Seguineau, Alexey Shchepin, Iain Shigeoka, and David Waite. 也感谢 XMPP工作组的成员和 IETF 社区在本文的成文过程中一直提供的评论和反馈。<br />
<br />
==作者地址==<br />
<br />
:Peter Saint-Andre (编辑)<br />
:Jabber Software Foundation<br />
<br />
:EMail: stpeter@jabber.org<br />
<br />
==完整的版权声明==<br />
<br />
:Copyright (C) The Internet Society (2004).<br />
<br />
:This document is subject to the rights, licenses and restrictions contained in BCP 78, and except as set forth therein, the authors retain all their rights. This document and the information contained herein are provided on an "AS IS" basis and THE CONTRIBUTOR, THE ORGANIZATION HE/S HE REPRESENTS OR IS SPONSORED BY (IF ANY), THE INTERNET SOCIETY AND THE INTERNET ENGINEERING TASK FORCE DISCLAIM ALL WARRANTIES, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO ANY WARRANTY THAT THE USE OF THE INFORMATION HEREIN WILL NOT INFRINGE ANY RIGHTS OR ANY IMPLIED WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE.<br />
<br />
==知识产权==<br />
<br />
:The IETF takes no position regarding the validity or scope of any Intellectual Property Rights or other rights that might be claimed to pertain to the implementation or use of the technology described in this document or the extent to which any license under such rights might or might not be available; nor does it represent that it has made any independent effort to identify any such rights. Information on the IETF's procedures with respect to rights in IETF Documents can be found in BCP 78 and BCP 79.<br />
<br />
:Copies of IPR disclosures made to the IETF Secretariat and any assurances of licenses to be made available, or the result of an attempt made to obtain a general license or permission for the use of such proprietary rights by implementers or users of this specification can be obtained from the IETF on-line IPR repository at http://www.ietf.org/ipr.<br />
<br />
:The IETF invites any interested party to bring to its attention any copyrights, patents or patent applications, or other proprietary rights that may cover technology that may be required to implement this standard. Please address the information to the IETF at ietf- ipr@ietf.org.<br />
<br />
==感谢==<br />
<br />
:目前为RFC编辑活动提供资金的Internet Society.</div>
Snowqiang
http://wiki.jabbercn.org/RFC3921
RFC3921
2011-05-18T12:09:33Z
<p>Snowqiang: </p>
<hr />
<div>[[Category:XMPP正式RFC标准]]<br />
[[Category:已翻译]]<br />
<br />
本文的英文原文来自[http://www.ietf.org/rfc/rfc3921.txt RFC 3921]<br />
<br />
{|<br />
|网络工作组 || Saint-Andre, Ed.<br />
|-<br />
|申请讨论: 3921 || Jabber软件基金会<br />
|-<br />
|类别: 标准跟踪 || 2004年10月<br />
|}<br />
<br />
::::'''可扩展的消息和出席信息协议 (XMPP): 即时消息和出席信息'''<br />
<br />
'''关于本文的说明'''<br />
<br />
:本文为互联网社区定义了一个互联网标准跟踪协议,并且申请讨论协议和提出了改进的建议。请参照“互联网官方协议标准”的最新版本(STD 1)获得这个协议的标准化进程和状态。本文可以不受限制的分发。<br />
<br />
'''版权声明'''<br />
<br />
:本文版权属于互联网社区 (C) The Internet Society (2004).<br />
<br />
'''摘要'''<br />
<br />
:本文定义了可扩展消息和出席信息协议(XMPP)的核心功能的扩展和应用,XMPP提供了RFC 2779 定义的基本的即时消息和出席信息功能。<br />
<br />
==绪论==<br />
<br />
===概览===<br />
<br />
:XMPP是一个流化XML[XML]元素的协议,用于准实时的交换消息和出席信息。XMPP的核心功能定义在Extensible Messaging and Presence Protocol (XMPP): Core [XMPP-CORE|XMPP文档列表/XMPP正式RFC标准/RFC3920]. 这些功能 -- 主要是 XML流, 使用 TLS和SASL,以及流的根元素之下的<message/>, <presence/>, 和 <iq/> 子元素 -- 为各种类型的准实时应用提供了一个构造基础, 它可以被放在核心的顶层,使用特定XML名字空间[XML-NAMES]发送特定的应用数据. 本文描述XMPP核心功能的扩展和应用,XMPP核心功能提供了RFC 2779 [IMP-REQS]定义的基本的即时消息和出席信息功能。<br />
<br />
===需求===<br />
<br />
:为了达到本文的目的, 基本的即时消息和出席信息应用的需求定义在[IMP-REQS],它是一个高阶的规定,一个用户必须完成以下用例:<br />
<br />
:*和其他用户交换消息<br />
:*和其他用户交换出席信息<br />
:*管理和其他用户之间的订阅和被订阅<br />
:*管理联系人列表中的条目(在 XMPP 中这被称为 "roster")<br />
:*屏蔽和特定的其他用户之间的通信(出或入)<br />
<br />
:这些功能领域的详细定义在[IMP-REQS]中, 感兴趣的用户可以直接阅读原文关于需求方面的内容。<br />
<br />
:[IMP-REQS]也规定出席信息服务必须从即时消息服务中分离; 例如, 它必须可能用这个协议来提供一个出席信息服务,一个即时消息服务,或同时提供两者. 尽管本文假定实现和部署希望提供统一的即时消息和出席信息服务, 但没有要求一个服务必须同时提供出席信息服务和即时消息服务, 并且协议也提供了把出席信息服务和即时消息服务分离成为独立服务的可能性.<br />
<br />
:注意: 虽然基于XMPP的即时消息和出席信息符合[IMP-REQS]的要求,但它不是特意为那个协议设计的,因为基础协议是在RFC 2779成文之前通过Jabber开放源代码社区的一个开放的开发过程发展出来的. 也请注意尽管在Jabber社区发展的协议中定义了许多其他方面的功能,但是这些协议不包含在本文之中,因为它们不是[IMP-REQS]所要求的.<br />
<br />
===术语===<br />
<br />
:本文继承了 [XMPP-CORE|XMPP文档列表/XMPP正式RFC标准/RFC3920]定义的术语.<br />
<br />
:大写关键字 "MUST", "MUST NOT", "REQUIRED", "SHALL", "SHALL NOT", "SHOULD", "SHOULD NOT", "RECOMMENDED", "MAY", 和 "OPTIONAL" 在本文中的含义定义在 BCP 14, RFC 2119 [TERMS].<br />
<br />
==XML 节的语法==<br />
<br />
:符合'jabber:client'和'jabber:server'名字空间的XML节的基本语义和通用属性已经在[XMPP-CORE|XMPP文档列表/XMPP正式RFC标准/RFC3920]中定义了. 无论如何, 这些名字空间也定义了一些其他的子元素, 比如通用属性'type'的值, 对于即时消息和出席信息应用就是特殊的. 因而, 在选择用于这类应用的特定用例之前, 我们在这里需要先描述一下XML节的语法, 用来补充[XMPP-CORE|XMPP文档列表/XMPP正式RFC标准/RFC3920]中的讨论.<br />
<br />
===消息语法===<br />
<br />
:符合'jabber:client' or 'jabber:server'名字空间的消息节用于"推" 信息到另一个实体. 在即时消息应用中通常的用法是包含,一个单独的消息,在一个聊天会话中的消息,一个多用户聊天室的上下文中的消息,标题或其他警告和错误的消息,<br />
<br />
====消息的类型====<br />
<br />
:一个消息节的'type' 属性是建议的(RECOMMENDED); 如果包含了它,它指明这个消息的会话上下文,从而提供一个关于表达的线索(例如, 在一个GUI中). 如果包含了它, 'type' 属性必须(MUST)是以下的值之一 :<br />
<br />
:*chat -- 消息是在一对一聊天会话的语境被发送. 一个兼容的客户端应该(SHOULD)在一个允许两个实体进行一对一聊天的界面中显示消息,包括适当的会话历史.<br />
<br />
:*error -- 发生了一个和上次发送者发送的消息有关的错误(关于节错误语法的详细信息, 参考 [XMPP-CORE|XMPP文档列表/XMPP正式RFC标准/RFC3920]). 一个兼容客户端应该(SHOULD)在一个适当的界面展示它以通知发送者这个错误的种类. <br />
<br />
:*groupchat -- 消息是在一个多用户聊天环境的语境下发送的(类似[IRC]). 一个兼容客户端应该(SHOULD)在允许多对多聊天的界面显示这个消息,包括, 包括这个聊天室的名册和适当的会话历史. 基于XMPP的群聊协议的完整定义超出了本文的范围.<br />
<br />
:*headline -- 一个消息可能是由一个递送或广播内容的自动化服务生成的(新闻, 体育, 市场信息, RSS feeds, 等等.). 这个消息是不需要回复的, 一个兼容客户端应该(SHOULD) 在一个适当的和单独消息,聊天会话,或群聊会话不同的界面显示这个消息(例如, 不给接收者提供回复能力).<br />
<br />
:*normal -- 这个消息是一个在一对一会话或群聊会话之外的单独消息, 并且它希望接收者能够回复.一个兼容客户端应该(SHOULD)在一个允许接收者回复的界面显示这个消息, 但不需要会话历史.<br />
<br />
:一个 IM 应用应该(SHOULD)支持所有前述的消息类型;如果一个应用接收了一个没有'type'属性的消息或这个应用不理解'type'属性的值, 它必须(MUST)认为这个消息是一个 "normal" 类型(如,"normal" 是缺省的). "error"类型必须(MUST)仅仅在应答一个和从别的实体接收到的消息有关的错误时生成.<br />
<br />
:尽管'type'属性是可选的(OPTIONAL), 处于礼貌原因对于消息的任何回复总是和原来的消息同一类型;此外, 一些特殊的应用(例如, 一个多用户聊天服务) 可以(MAY)根据它们的判断强制特定消息类型的使用(例如, type='groupchat').<br />
<br />
====子元素====<br />
<br />
:正如 扩展名字空间extended namespaces(第二章第四节)所述, 一个消息节可以(MAY)包含任何适当名字空间的子元素.<br />
<br />
:和缺省名字空间声明一致, 缺省消息节的名字空间是'jabber:client' 或 'jabber:server', 定义了某几个允许的消息节的子元素. 如果消息节的类型是 "error", 它必须(MUST)包含一个<error/>子元素; 详细情况, 见[XMPP-CORE|XMPP文档列表/XMPP正式RFC标准/RFC3920]. 否则, 消息节可以(MAY)包含以下子元素的任何一种并且无需显式地声明名字空间:<br />
<br />
:#<subject/><br />
:#<body/><br />
:#<thread/><br />
<br />
=====主题=====<br />
<br />
:<subject/> 元素包含了人类可读的 XML 字符数据指明这个消息的主题. <subject/>元素不能(MUST NOT)拥有任何属性, 除了'xml:lang'属性. <subject/> 元素可以(MAY)包含多个实例用于为同一主题提供备用版本, 但是仅在每个实例的拥有的'xml:lang'属性的值互不相同的时候才可以. <subject/> 元素不能(MUST NOT)包含混合的内容(定义在 [XML]第三章第二节第二小节).<br />
<br />
=====主体=====<br />
<br />
:<body/> 元素包含人类可读的XML字符数据表达消息的文本内容; 这个子元素通常会有但是是可选的(OPTIONAL). <body/>元素不能(MUST NOT)拥有任何属性, 除非是'xml:lang'属性. <body/> 元素可以(MAY)包含多个实例用于为同一主体提供备用版本, 但是仅在每个实例的拥有的'xml:lang'属性的值互不相同的时候才可以. <body/>元素不能(MUST NOT)包含混合的内容(定义在 [XML]第三章第二节第二小节). <br />
<br />
=====线索=====<br />
<br />
:<thread/> 元素包含非人类可读的XML字符数据表达一个标识符用于跟踪两个实体之间的一个会话线索(有时相当于一个"即时消息会话"). <thread/>元素的值是由发送者生成的并且应该(SHOULD)在任何回复中拷贝回来. 如果使用了它, 它必须(MUST)在这个流的会话线索中是唯一的并且必须(MUST)和那个会话相一致(一个从同一个全JID但不同线索ID接收到消息的客户端必须(MUST)假定这个有问题的消息存在于已有的会话线索之外. <thread/>元素的使用是可选的(OPTIONAL)并且不是用于标识独立的消息,而是标识会话. 一个消息节不能(MUST NOT)包含超过一个的<thread/>元素. <thread/>元素不能(MUST NOT)拥有任何属性. <thread/>属性的值必须(MUST)被实体处理成不透明的; 不能从它得到任何语义学上的含义,并且只能对它做精确的比较. <thread/>元素不能(MUST NOT)包含混合内容(定义在 [XML]第三章第二节第二小节).<br />
<br />
===出席信息语法===<br />
<br />
:符合'jabber:client' 或 'jabber:server'名字空间的出席信息节用于表达一个实体当前的网络可用性(离线或在线, 包括之后的各种亚状态和可选的用户名义的描述性文本), 并且通知其他实体它的可用性. 出席信息节也用于协商和管理对于其他实体的出席信息的订阅.<br />
<br />
====出席信息的类型====<br />
<br />
:出席信息节的'type'属性是可选的(OPTIONAL). 一个不拥有任何'type'属性的出席信息节用来通知服务器发送者已经在线并且可以进行通信了, 'type' 属性表示缺乏可用性, 请求管理对其他实体的出席信息的订阅, 请求其他实体的当前出席信息, 或发生了和上次发出的出席信息节有关的错误. 如果包含了它, 'type'属性必须(MUST)拥有以下值之一:<br />
<br />
:*unavailable -- 通知实体将不可通信.<br />
<br />
:*subscribe -- 发送者希望订阅接收者的出席信息.<br />
<br />
:*subscribed -- 发送者允许接收者接收他们的出席信息.<br />
<br />
:*unsubscribe -- 发送者取消订阅另一个实体的出席信息.<br />
<br />
:*unsubscribed -- 订阅者的请求被拒绝或以前的订阅被取消.<br />
<br />
:*probe -- 对一个实体当前的出席信息的请求; 只应(SHOULD)由服务器代替一个用户生成.<br />
<br />
:*error -- 处理或递送之前发送的出席信息节的时候发生了错误.<br />
<br />
:关于出席信息语义学的详细信息和基于XMPP的即时消息和出席信息应用程序的订阅模式,参考 交换出席信息Exchanging Presence Information(第五章) 和 管理订阅Managing Subscriptions(第六章).<br />
<br />
====子元素====<br />
<br />
:如 扩展名字空间extended namespaces(第二章第四节)所述, 一个出席信息节可以(MAY)包含任何适当名字空间的子元素.<br />
<br />
:和缺省名字空间声明一致, 缺省出席信息节的名字空间是'jabber:client' 或 'jabber:server', 定义了某几个允许的出席信息节的子元素. 如果出席信息节的类型是 "error", 它必须(MUST)包含一个<error/>子元素; 详细情况, 见[XMPP-CORE|XMPP文档列表/XMPP正式RFC标准/RFC3920]. 如果出席信息节不拥有'type'属性,它可以(MAY)包含以下任何子元素(注意<status/>子元素可以(MAY)在一个类型为"unavailable"或"subscribe"(出于历史原因)的出席信息中被发送):<br />
<br />
:#<show/><br />
:#<status/><br />
:#<priority/><br />
<br />
=====展示=====<br />
<br />
:可选的(OPTIONAL)<show/>元素包含非人类可读的XML字符数据表达一个特定的实体或资源的特定的可用性状态. 一个出席信息节不能(MUST NOT)包含多于一个<show/>元素. <show/>元素不能(MUST NOT)拥有任何属性. 如果提供了, 这个XML字符数据值必须(MUST)是以下之一(额外的可用性类型可以通过出席信息的适当名字空间来定义):<br />
<br />
:*away -- 实体或资源临时离开.<br />
<br />
:*chat -- 实体或资源在聊天中是激活的.<br />
<br />
:*dnd -- 实体或资源是忙(dnd = "不要打扰").<br />
<br />
:*xa -- 实体或资源是长时间的离开(xa = "长时间离开").<br />
<br />
:如果没有提供<show/>元素, 实体被假定是在线和可用的.<br />
<br />
=====状态=====<br />
<br />
:可选的(OPTIONAL)<status/>元素包含XML字符数据表达一个可用性状态的自然语言描述. 它通常用于联合show元素以提供可用性状态的详细描述(例如, "会议中"). <status/>元素不能(MUST NOT)拥有任何属性,除了'xml:lang'属性. <status/>元素可以(MAY)包含多个实例但是每个实例的'xml:lang'属性值必须各不相同.<br />
<br />
=====优先权=====<br />
<br />
:可选的(OPTIONAL)<priority/>元素包含非人类可读的XML字符数据指明资源的优先级别. 这个值必须(MUST)是一个介于-128和+127之间的数字. 一个出席信息小节不能(MUST NOT)包含超过一个的<priority/>元素. <priority/>元素不能(MUST NOT)拥有任何属性. 如果没有优先权被提供,一个服务器应该(SHOULD)认为优先级是零. 关于即时消息和出席信息系统中节路由的优先级的语义, 参考 处理XML节的服务器规则Server Rules for Handling XML Stanzas(第十一章).<br />
<br />
===IQ语法===<br />
<br />
:IQ节提供一个结构化的请求-应答机制. 这个机制的基本语义学(例如, 'id'属性是必需的(REQUIRED))定义在[XMPP-CORE|XMPP文档列表/XMPP正式RFC标准/RFC3920], 然而完成特定用例所需要的特定语义的所有案例定义在扩展名字空间extended namespace(第二章第四节)之中(注意'jabber:client'和'jabber:server'名字空间没有定义除通用的<error/>子元素之外的任何IQ节子元素). 本文定义了两个这样的名字空间,一个用于 名册管理Roster Management(第七章)而另一个用于 屏蔽通信Blocking Communication(第十章); 无论如何, 一个IQ节可以(MAY)包含符合任何扩展名字空间的结构化信息.<br />
<br />
===扩展名字空间===<br />
<br />
:因为在"jabber:client"或"jabber:server"名字空间中定义的三个XML节类型(也包括它们的属性和子元素)提供了一个基本功能级用于消息和出席信息, XMPP使用XML名字空间来扩展节用于提供额外的功能, 所以一个消息或出席信息节可以(MAY)包含一个或更多可选的子元素表达扩展消息含义的内容(例如, 一个XHTML格式版本的消息主体), 并且一个IQ节可以(MAY)包含一个这样的子元素. 这个子元素可以(MAY)有任何名字并且可以(MUST)拥有一个'xmlns'名字空间声明(不同于"jabber:client", "jabber:server", 或"http://etherx.jabber.org/streams")定义所有包含在子元素中的数据.<br />
<br />
:对于任何特定的扩展名字空间的支持在任何实现中的一部分是可选的(OPTIONAL)(除了在这里定义的扩展名字空间以外). 如果一个实体不理解这样一个名字空间, 实体被期望的行为依赖于这个实体是(1) 接收者 或 (2) 一个正在路由到接收者的实体<br />
<br />
:接收者: 如果一个接收者接收了一个包含不理解的子元素的节, 它应该(SHOULD)忽略那个特定的XML数据,例如, 它应该(SHOULD)不处理它或不向用户或相关的应用程序(如果有的话)显示它. 具体来说:<br />
<br />
::*如果一个实体接收了一个消息或出席信息节包含一个不理解的名字空间, 在节的未知名字空间的这部分应该(SHOULD)被忽略.<br />
<br />
::*如果一个实体接收了一个消息节中仅有的一个子元素是不理解的, 它必须(MUST)忽略整个节.<br />
<br />
::*如果一个实体接收了一个类型"get"或"set"的IQ节包含一个不理解的子元素, 这个实体应该(SHOULD)返回一个类型为"error"的<service-unavailable/>错误条件的IQ节.<br />
<br />
:路由: 如果一个路由实体(通常是一个服务器)处理一个包含它不理解的子元素的节, 它应该(SHOULD)原封不动地把它转给接收者而忽略相关的XML数据.<br />
<br />
==会话的建立==<br />
<br />
:绝大部分基于XMPP的消息和出席信息应用是由一个客户端-服务器体系结构实现的,为了参加期望的即时消息和出席信息活动,需要客户端在服务器上建立一个会话. 无论如何, 在客户端能够建立一个即时消息和出席信息会话之前有很多前提必须(MUST)满足. 它们是:<br />
<br />
:#流验证 -- 客户端在尝试建立一个会话或发送任何XML节之前必须(MUST)完成[XMPP-CORE|XMPP文档列表/XMPP正式RFC标准/RFC3920]中定义的流验证.<br />
:#资源绑定 -- 完成流验证之后, 一个客户端必须(MUST)绑定一个资源到流上,使得客户端的地址符合<user@domain/resource>格式, 然后实体以[XMPP-CORE|XMPP文档列表/XMPP正式RFC标准/RFC3920]规定的术语来说就是一个 已连接的资源"connected resource".<br />
<br />
:如果一个服务器支持会话, 在完成一个[XMPP-CORE|XMPP文档列表/XMPP正式RFC标准/RFC3920]定义的流验证之后它必须(MUST)在它向客户端声明的流特性中包含一个符合'urn:ietf:params:xml:ns:xmpp-session'名字空间的<session/>元素:<br />
<br />
:服务器向客户端声明会话确定特性:<br />
<br />
<source lang="xml"><br />
<stream:stream<br />
xmlns='jabber:client'<br />
xmlns:stream='http://etherx.jabber.org/streams'<br />
id='c2s_345'<br />
from='example.com'<br />
version='1.0'><br />
<stream:features><br />
<bind xmlns='urn:ietf:params:xml:ns:xmpp-bind'/><br />
<session xmlns='urn:ietf:params:xml:ns:xmpp-session'/><br />
</stream:features><br />
</source><br />
<br />
:收到需要会话确立的通知之后(并且是在完成资源绑定之后), 客户端如果想使用即时消息和出席信息功能必须(MUST)建立一个会话; 它向服务器发送一个符合'urn:ietf:params:xml:ns:xmpp-session'名字空间的类型为"set"并包含空的<session/>子元素的IQ节以完成这一步骤:<br />
<br />
:步骤 1: 客户端向服务器请求会话:<br />
<br />
<source lang="xml"><br />
<iq to='example.com'<br />
type='set'<br />
id='sess_1'><br />
<session xmlns='urn:ietf:params:xml:ns:xmpp-session'/><br />
</iq><br />
</source><br />
<br />
:步骤 2: 服务器通知客户端会话已经建立:<br />
<br />
<source lang="xml"><br />
<iq from='example.com'<br />
type='result'<br />
id='sess_1'/><br />
</source><br />
<br />
:建立会话之后, 一个 已连接的资源([XMPP-CORE|XMPP文档列表/XMPP正式RFC标准/RFC3920]术语)就被称为一个 激活的资源"active resource".<br />
<br />
:许多错误条件是可能的. 例如, 服务器可能遭遇一个内部条件阻碍了它建立会话, 用户名或授权身份可能缺乏建立会话的许可, 或同一个名字相关的这个资源ID已经有一个激活的资源.<br />
<br />
:如果服务器遭到一个内部条件阻碍了它建立会话, 它必须(MUST)返回一个错误.<br />
<br />
:步骤 2 (替代): 服务器应答一个错误(内部服务器错误):<br />
<br />
<source lang="xml"><br />
<iq from='example.com' type='error' id='sess_1'><br />
<session xmlns='urn:ietf:params:xml:ns:xmpp-session'/><br />
<error type='wait'><br />
<internal-server-error<br />
xmlns='urn:ietf:params:xml:ns:xmpp-stanzas'/><br />
</error><br />
</iq><br />
</source><br />
<br />
:如果用户名或资源不被允许建立一个会话, 服务器必须(MUST)返回一个错误(例如, 被禁止).<br />
<br />
:步骤 2 (替代): 服务器应答错误(用户名或资源不被允许建立一个会话):<br />
<br />
<source lang="xml"><br />
<iq from='example.com' type='error' id='sess_1'><br />
<session xmlns='urn:ietf:params:xml:ns:xmpp-session'/><br />
<error type='auth'><br />
<forbidden<br />
xmlns='urn:ietf:params:xml:ns:xmpp-stanzas'/><br />
</error><br />
</iq><br />
</source><br />
<br />
:如果同一名字已经存在一个激活的资源,服务器必须(MUST) (1) 终止这个激活的资源并允许新请求的会话, 或者 (2) 不允许新申请的会话并继续激活的资源. 服务器做哪一步取决于具体的实现, 尽管建议的(RECOMMENDED)实现 情景 #1. 在 情景 #1, 服务器应该(SHOULD)发送一个<conflict/>流错误给激活的资源, 终止用于这个激活的资源的XML流和相关的TCP连接, 并返回一个类型为"result" 的IQ节(表示成功)给新申请的会话. 在 情景 #2, 服务器应该(SHOULD)发送一个<conflict/>节错误给新申请的会话但是继续那个连接的XML流使得新申请的会话在发送另一个会话建立申请之前有机会协商出一个不冲突的资源ID.<br />
<br />
:步骤 2 (替代): 服务器通知现有的激活的资源 资源冲突(情景 #1):<br />
<br />
<source lang="xml"><br />
<stream:error><br />
<conflict xmlns='urn:ietf:params:xml:ns:xmpp-streams'/><br />
</stream:error><br />
</stream:stream><br />
</source><br />
<br />
:步骤 2 (替代): 服务器通知新申请的的会话资源冲突(情景 #2):<br />
<br />
<source lang="xml"><br />
<iq from='example.com' type='error' id='sess_1'><br />
<session xmlns='urn:ietf:params:xml:ns:xmpp-session'/><br />
<error type='cancel'><br />
<conflict xmlns='urn:ietf:params:xml:ns:xmpp-stanzas'/><br />
</error><br />
</iq><br />
</source><br />
<br />
:建立一个会话之后, 客户端应该(SHOULD)按以下描述来发送初始化出席信息并请求它的名册, 尽管这些动作是可选的(OPTIONAL).<br />
<br />
:注意: 在允许建立即时消息和出席信息会话之前, 一个服务器可能(MAY)需要先提供帐号. 可能的提供帐号的方法包括由服务器管理员新建帐号以及使用'jabber:iq:register'名字空间进行带内帐号注册; 后一个方法超出了本文的范围, 但是记录在[JEP-0077](译者注:这个协议已改名为 XEP-0077), 由 Jabber Software Foundation [JSF]发行(译者注:这个组织也已改名为XSF).<br />
<br />
==交换消息==<br />
<br />
:交换消息是XMPP的一个基本用途并且随之而来的是一个用户生成一个发给另一个实体的消息节. 正如 用于处理XML节的服务器规则Server Rules for Handling XML Stanzas(第十一章)中所定义的 , 发送者的服务器负责递送消息给预定的接收者(如果接收者在同一个服务器上)或路由消息给接收者的服务器(如果接收者在不同的服务器上).<br />
<br />
:关于消息节的语法和它们已定义的属性和子元素信息, 参考 消息语法Message Syntax(第二章第一节).<br />
<br />
===指明一个预定的接收者===<br />
<br />
:一个即时消息客户端应该(SHOULD)通过提供一个JID或<message/>节中不同于发送者的'to'属性来指定一个消息的预定接收者. 如果这个消息是在回复之前接收到的消息,而接收到的消息是从JID格式为<user@domain/resource>(例如,在一个聊天会话的上下文中)实体发来的, 这个回复消息的'to'地址的值应该(SHOULD)是<user@domain/resource>而不是<user@domain>,除非发送者知道(通过出席信息)预定的接收者的资源将不再可用. 如果消息是在任何现存的聊天会话或接收到的消息之外被发送的,'to'地址的值应该(SHOULD)格式为<user@domain>而不是<user@domain/resource>.<br />
<br />
===指定一个消息类型===<br />
<br />
:大家知道, 对于一个消息节来说拥有'type'属性(它的值代表了消息的会话上下文(参见 Type(第二章第一节第一小节)))是建议的(RECOMMENDED).<br />
<br />
:以下例子展示一个'type'属性的合法值:<br />
<br />
:例子: 一个已定义类型的消息:<br />
<br />
<source lang="xml"><br />
<message<br />
to='romeo@example.net'<br />
from='juliet@example.com/balcony'<br />
type='chat'<br />
xml:lang='en'><br />
<body>Wherefore art thou, Romeo?</body><br />
</message><br />
</source><br />
<br />
===指定一个消息主体===<br />
<br />
:一个消息节可以(MAY)(并且经常会)包含一个<body/>子元素,它的XML字符数据表达消息的主要含义(见 Body(第二章第一节第二小节第二小小节)).<br />
<br />
:例子: 一个带主体的消息:<br />
<br />
<source lang="xml"><br />
<message<br />
to='romeo@example.net'<br />
from='juliet@example.com/balcony'<br />
type='chat'<br />
xml:lang='en'><br />
<body>Wherefore art thou, Romeo?</body><br />
<body xml:lang='cz'>Pro&#x010D;e&#x017D; jsi ty, Romeo?</body><br />
</message><br />
</source><br />
<br />
===指定一个消息主题===<br />
<br />
:一个消息节可以(MAY)包含一个或多个<subject/>子元素指明消息的主题(见 Subject(第二章第一节第二小节第一小小节)).<br />
<br />
:例子: 一个带主题的消息:<br />
<br />
<source lang="xml"><br />
<message<br />
to='romeo@example.net'<br />
from='juliet@example.com/balcony'<br />
type='chat'<br />
xml:lang='en'><br />
<subject>I implore you!</subject><br />
<subject<br />
xml:lang='cz'>&#x00DA;p&#x011B;nliv&#x011B; prosim!</subject><br />
<body>Wherefore art thou, Romeo?</body><br />
<body xml:lang='cz'>Pro&#x010D;e&#x017D; jsi ty, Romeo?</body><br />
</message><br />
</source><br />
<br />
===指定一个会话线索===<br />
<br />
:一个消息可以(MAY)包含一个<thread/>子元素指定消息处于哪个会话线索, 用于跟踪会话(见 Thread(第二章第一节第二小节第三小小节)).<br />
<br />
:例子: 一个带线索的会话:<br />
<br />
<source lang="xml"><br />
<message<br />
to='romeo@example.net/orchard'<br />
from='juliet@example.com/balcony'<br />
type='chat'<br />
xml:lang='en'><br />
<body>Art thou not Romeo, and a Montague?</body><br />
<thread>e0ffe42b28561960c6b12b944a092794b9683a38</thread><br />
</message><br />
<message<br />
to='juliet@example.com/balcony'<br />
from='romeo@example.net/orchard'<br />
type='chat'<br />
xml:lang='en'><br />
<body>Neither, fair saint, if either thee dislike.</body><br />
<thread>e0ffe42b28561960c6b12b944a092794b9683a38</thread><br />
</message><br />
<message<br />
to='romeo@example.net/orchard'<br />
from='juliet@example.com/balcony'<br />
type='chat'<br />
xml:lang='en'><br />
<body>How cam'st thou hither, tell me, and wherefore?</body><br />
<thread>e0ffe42b28561960c6b12b944a092794b9683a38</thread><br />
</message><br />
</source><br />
<br />
==交换出席信息==<br />
<br />
:交换出席信息通过使用出席信息节直接和XMPP相关. 无论如何, 我们看到在这里和消息处理形成一个对比:尽管一个客户端可以(MAY)通过包含一个'to'地址直接给另一个实体发送出席信息, 通常出席信息通知(例如,不包含'type'的或类型为"unavailable"的并且没有'to'地址的出席信息节) 被客户端发送给它的服务器然后由服务器广播给任何订阅了发送实体的出席信息的实体(在 RFC 2778 [IMP-MODEL]术语中, 这些实体称为订阅者). 这个广播模式不适用于和订阅相关的节或类型为"error"的出席信息, 而仅适用于以上定义的出席信息通知. (注意: 虽然出席信息可以(MAY)由一个自动化服务代替用户提供, 通常它还是由用户的客户端提供.)<br />
<br />
:关于出席信息节的语法以及它们的已定义的属性和子元素的信息, 参考[XMPP-CORE|XMPP文档列表/XMPP正式RFC标准/RFC3920].<br />
<br />
===客户端和服务器出席信息职责===<br />
<br />
====初始化出席信息====<br />
<br />
:建立起一个会话之后, 一个客户端应该(SHOULD)发送初始化出席信息给服务器来通知它的通信可用性.如这里定义的, 初始化出席信息节 (1) 必须(MUST) 不拥有'to'地址(这表示它是由服务器代替客户端发送的广播) 并且 (2) 必须(MUST) 不拥有'type'属性(者表示拥护的可用性). 在发送初始化出席信息之后, 一个激活的资源被称为 可用的资源"available resource".<br />
<br />
:从一个客户端接收到初始化出席信息之后, 如果这个用户没有一个或更多的已存在的可用资源(如果这个用户已经有一个或更多可用的资源, 服务器明显不需要发送出席信息探测, 因为它已经拥有需要的信息),用户的服务器必须(MUST)做以下的步骤:<br />
<br />
:#从用户的全JID(例如,<user@example.com/resource>)发送出席信息探针(例如, 'type'属性值为'probe'的出席信息节)给已被这个用户订阅了的所有联系人以确定它们是否可用; 这些联系人就是那些显示在用户的名册中的JID并且'subscription'属性值为"to"或"both"(注意: 用户的服务器不能(MUST NOT)发送出席信息探针给用户已经屏蔽入站出席信息通知的联系人, 具体的描述在 屏蔽入站出席信息通知Blocking Inbound Presence Notifications(第十章第十节).)<br />
:#从用户的全JID (e.g.,<user@example.com/resource>)广播初始化出席信息给所有订阅了该用户的出席信息的联系人; 这些联系人就是那些显示在用户的名册中的JID并且'subscription'属性值为"from"或"both"(注意: 用户的服务器不能(MUST NOT)发送出席信息探针给用户已经屏蔽出站出席信息通知的联系人, 具体的描述在 屏蔽出站出席信息通知Blocking Outbound Presence Notifications(第十章第十一节).)<br />
<br />
:另外, 用户的服务器必须(MUST)从用户的新的可用的资源向用户任何现存的可用的资源(如果有的话)广播初始化出席信息.<br />
<br />
:从用户接收到初始化出席信息之后, 联系人的服务器必须(MUST)递送这个用户的出席信息节给所有联系人的可用资源相应的全JID(<contact@example.org/resource>), 但是仅适用于用户在联系人名册中并且订阅状态为"to"或"both"并且联系人的纯JID或全JID没有被屏蔽入站出席信息通知(定义在 屏蔽入站出席信息通知Blocking Inbound Presence Notifications(第十章第十节)).<br />
<br />
:如果用户的服务器接收到一个类型为"error"的出席信息节,而这个节是用来回复服务器代替用户向联系人发送的初始化出席信息, 它不应该(SHOULD NOT)发送更多的出席信息更新给那个联系人(直到并且除非它从这个联系人接收到一个出席信息节).<br />
<br />
====出席信息广播====<br />
<br />
:发送初始化出席信息之后, 用户可以(MAY)在任何时候更新它的出席信息,方法是在会话期间发送一个没有'to'地址也没有'type'属性的出席信息节或'type'属性值为"unavailable"的出席信息节.(注意:一个用户的客户端不应该(SHOULD NOT)发送一个出席信息更新来自行广播用户出席信息和可用性的改变信息.)<br />
<br />
:如果出席信息节缺乏'type'属性(例如, 表达可用性), 用户的服务器必须(MUST)广播那个出席信息节的全XML给所有联系人(满足以下三点) (1) 它们在用户的联系人名册中并且订阅类型是"from"或"both", (2) 用户对于这些联系人没有屏蔽出站出席信息通知, 并且 (3) 服务器在用户的会话期间没有从它们那里接收到出席信息错误(同样适用于这个用户的其他可用的资源).<br />
<br />
:如果出席信息节的'type'属性值是"unavailable", 用户的服务器必须(MUST)广播那个出席信息节的全XML给所有符合以上描述的实体, 也适用于用户曾经在会话过程中直接发送了可用出席信息的任何实体(如果用户还没来得及直接发送不可用出席信息给那个实体).<br />
<br />
====出席信息调查====<br />
<br />
:从用户接收到一个出席信息调查之后, 联系人的服务器应该(SHOULD)应答如下:<br />
<br />
:#如果用户联系人的名册中的状态不是 "From", "From + Pending Out", 或 "Both" (定义在 订阅状态Subscription States(第九章)), 联系人的服务器必须(MUST)返回一个类型为"error"的出席信息节应答这个出席信息调查 (无论如何, 如果一个服务器从这个服务器的主机名的子域或其他信任的服务接收到一个出席信息调查, 它可以(MAY)提供这个用户的出席信息给那个实体). 具体来说:<br />
:##如果用户在联系人的名册中的订阅状态是 "None", "None + Pending Out", 或 "To" (或根本不在联系人的名册中), 联系人的服务器必须(MUST)返回一个<forbidden/>节错误应答这个出席信息调查.<br />
:##如果用户在联系人的名册中的订阅状态是 "None + Pending In", "None + Pending Out/In", 或 "To + Pending In", 联系人的服务器必须(MUST)返回一个<not-authorized/>节错误应答这个出席信息调查.<br />
:#其次, 如果联系人对这个用户的纯JID或全JID屏蔽了出席信息通知(使用缺省列表或激活列表,定义在 屏蔽出站出席信息通知Blocking Outbound Presence Notifications (第十章第十一节)), 服务器不能(MUST NOT)应答这个出席信息调查.<br />
:#然后, 如果联系人没有可用的资源, 服务器必须(MUST) 要么 (1) 应答这个出席信息调查, 向这个用户发送服务器从联系人接收到的最后的类型为"unavailable"的出席信息节的全XML, 或 (2) 不应答.<br />
:#最后, 如果联系人至少有一个可用的资源, 服务器必须(MUST)应答这个出席信息调查, 向这个用户发送服务器从联系人的每一个可用的资源收到的最后的没有'to'属性的出席信息节的全XML (再一次的,对于每一个会话都要强制服从隐私列表).<br />
<br />
====直接出席信息====<br />
<br />
:一个用户可以(MAY)直接发送出席信息给另一个实体 (例如, 一个出席信息节,包含'to'属性并且值为另一个实体的JID并且没有'type'属性或'type'属性值为"unavailable"). 可能出现三种情形:<br />
<br />
:#如果用户在已经发送过初始化出席信息广播之后,发送不可用信息广播之前,直接发送出席信息给它的名册中一个订阅状态为"from" 或 "both"的联系人, 这个用户的服务器必须(MUST)路由或递送这个出席信息节的全XML(服从隐私列表)但是不应该(SHOULD NOT) 根据出席信息广播修改联系人的状态(例如, 它应该(SHOULD)在任何接下来的由用户初始化的出席信息广播包含这个联系人的JID).<br />
:#如果用户在已经发送过初始化出席信息广播之后,发送不可用信息广播之前,直接发送出席信息给一个不在用户名册中的实体并且其订阅状态为"from" 或 "both", 这个用户的服务器必须(MUST)路由或递送这个出席信息节的全XML(服从隐私列表)但是不能(MUST NOT) 根据可用性的出席信息广播来修改这个联系人的状态(例如, 它不能(MUST NOT)在任何接下来的由用户初始化的可用性的出席信息广播中包含这个联系人的JID); 无论如何, 如果无法从用户的可用的资源直接发送出席信息, 用户的服务器必须( MUST)广播不可用出席信息给那个实体(如果这个用户还没有直接发送不可用出席信息给那个实体).<br />
:#如果用户不是在已经发送过初始化出席信息广播之后,或在发送不可用信息广播之前,直接发送出席信息(例如, 资源激活了但是还不可用), 用户的服务器必须(MUST)认为用户向其直接发送出席信息的这个实体视为上述第二种情形中的那个实体,采用相同的处理方式.<br />
<br />
====不可用出席信息====<br />
<br />
:在和一个服务器结束它的会话之前, 客户端应该(SHOULD)雅致地成为不可用的,发送一个最后的没有'to'属性并且'type'属性值为"unavailable"的出席信息节(可选的, 最后的出席信息节可以(MAY)包含一个或多个<status/>元素以指明为什么用户不再可用). 无论如何, 用户的服务器不能(MUST NOT)依赖于从一个可用的资源接收最后的出席信息, 因为资源可能意外的变成不可用或可能被服务器判定超时. 如果用户的资源之一因为任何原因成为不可用的(包括雅致的或粗鲁的), 用户的服务器必须(MUST)广播不可用出席信息给所有如下的联系人 (1) 在用户的名册中并且订阅类型为 "from" 或 "both", (2) 用户没有对它们屏蔽出站出席信息的联系人, 以及 (3) 用户会话期间,服务器没有从它们那里收到出席信息错误的联系人; 用户的服务器也必须(MUST)发送不可用出席信息节给这个用户的任何其他可用的资源, 以及任何用户的资源曾经在会话期间直接向其发送过出席信息的实体(如果用户还没有直接发送不可用出席信息给那个实体). 在直接发送或广播不可用出席信息之后发送的任何没有'type'属性也没有'to'属性的出席信息节必须(MUST)由服务器广播给所有订阅者.<br />
<br />
====出席信息订阅====<br />
<br />
:一个订阅请求就是一个'type'属性值为"subscribe"的出席信息节. 如果订阅请求被发送给一个即时消息联系人, 在'to'属性中提供的JID的格式应该(SHOULD)是<contact@example.org>而不是<contact@example.org/resource>, 因为用户期望的结果通常是从联系人的所有资源接收到出席信息, 而不仅是'to'属性中的特定资源.<br />
<br />
:一个用户的服务器不能(MUST NOT)代替用户自动批准订阅请求. 所有订阅申请必须(MUST)直接发给用户的客户端, 具体来说就是这一用户的一个或多个可用的资源. 如果当订阅申请被用户的服务器接收到的时候没有这个用户的可用资源, 用户的服务器必须(MUST)保持这个订阅申请的记录并且在用户下次建立一个可用的资源时递送这个订阅申请, 直到这个用户批准或拒绝这个请求. 如果如果当订阅申请被用户的服务器接收到的时候这个用户有多于一个的可用资源, 用户的服务器必须(MUST)广播这个订阅申请给所有可用的资源(根据 处理XML节的服务器规则Server Rules for Handling XML Stanzas(第十一章)). (注意: 如果一个激活的资源还没有提供初始化出席信息, 服务器不能(MUST NOT)认为它是可用的并且因而不能(MUST NOT)发送订阅申请给它.) 无论如何, 如果用户从一个它已授权可以看到用户的出席信息的联系人那里收到一个类型为"subscribe"的出席信息节(例如, 当一个联系人重新同步订阅状态的时候),用户的服务器应该(SHOULD)代替用户自动应答. 另外, 用户的服务器可以(MAY)基于一个特定实现的法则(例如, 无论何时当用户的一个新的资源可用的时候, 或在一段特定长度的时间过去之后)选择重新发送一个未批准的未决订阅申请给这个联系人; 这有助于恢复可能和原始订阅申请有关的瞬间的,无声的错误.<br />
<br />
===指明可用性状态===<br />
<br />
:一个客户端可以(MAY)使用<show/>元素提供关于可用性状态的更多信息(参见 Show (第二章第二节第二小节第一小小节)).<br />
<br />
:例子: 可用性状态:<br />
<source lang="xml"><br />
<presence><br />
<br />
<show>dnd</show><br />
<br />
</presence><br />
</source><br />
<br />
===指明详细的可用性状态信息===<br />
<br />
:通过联合<show/>元素, 客户端使用<status/>元素可以(MAY)提供详细的可用性状态信息(参见Status (第二章第二节第二小节第二小小节)).<br />
<br />
:例子: 详细的状态信息:<br />
<br />
<source lang="xml"><br />
<presence xml:lang='en'><br />
<show>dnd</show><br />
<status>Wooing Juliet</status><br />
<status xml:lang='cz'>Ja dvo&#x0159;&#x00ED;m Juliet</status><br />
</presence><br />
</source><br />
<br />
===指明出席信息优先级===<br />
<br />
:客户端可以(MAY)使用<priority/>元素为它的资源提供优先级(参见 Priority (第二章第二节第二小节第三小小节)).<br />
<br />
:例子: 出席信息优先级:<br />
<br />
<source lang="xml"><br />
<presence xml:lang='en'><br />
<show>dnd</show><br />
<status>Wooing Juliet</status><br />
<status xml:lang='cz'>Ja dvo&#x0159;&#x00ED;m Juliet</status><br />
<priority>1</priority><br />
</presence><br />
</source><br />
<br />
===出席信息例子===<br />
<br />
:本章的例子用于阐明上述和出席信息相关的协议. 用户是 romeo@example.net, 他有一个可用的资源, 资源ID为 "orchard", 并且他的名册中有以下这些人:<br />
<br />
:*juliet@example.com (subscription="both" 并且她有两个可用的资源, 一个资源名为"chamber" 而另一个资源名为 "balcony")<br />
<br />
:*benvolio@example.org (subscription="to")<br />
<br />
:*mercutio@example.org (subscription="from")<br />
<br />
:例子 1: 用户发送初始化出席信息:<br />
<br />
<source lang="xml"><br />
<presence/><br />
</source><br />
<br />
:例子 2: 用户的服务器代替用户发送出席信息调查给 subscription="to" 和 subscription="both" 的联系人的可用资源:<br />
<br />
<source lang="xml"><br />
<presence<br />
type='probe'<br />
from='romeo@example.net/orchard'<br />
to='juliet@example.com'/><br />
<presence<br />
type='probe'<br />
from='romeo@example.net/orchard'<br />
to='benvolio@example.org'/><br />
</source><br />
<br />
:例子 3: 用户的服务器代替用户发送初始化出席信息给 subscription="from" 和 subscription="both"的联系人的可用资源:<br />
<br />
<source lang="xml"><br />
<presence<br />
from='romeo@example.net/orchard'<br />
to='juliet@example.com'/><br />
<presence<br />
from='romeo@example.net/orchard'<br />
to='mercutio@example.org'/><br />
</source><br />
<br />
:例子 4: 联系人的服务器代替所有可用的资源应答出席信息调查:<br />
<br />
<source lang="xml"><br />
<presence<br />
from='juliet@example.com/balcony'<br />
to='romeo@example.net/orchard'<br />
xml:lang='en'><br />
<show>away</show><br />
<status>be right back</status><br />
<priority>0</priority><br />
</presence><br />
<presence<br />
from='juliet@example.com/chamber'<br />
to='romeo@example.net/orchard'><br />
<priority>1</priority><br />
</presence><br />
<presence<br />
from='benvolio@example.org/pda'<br />
to='romeo@example.net/orchard'<br />
xml:lang='en'><br />
<show>dnd</show><br />
<status>gallivanting</status><br />
</presence><br />
</source><br />
<br />
:例子 5: 联系人的服务器递送用户的初始化出席信息给所有可用的资源或返回错误给用户:<br />
<br />
<source lang="xml"><br />
<presence<br />
from='romeo@example.net/orchard'<br />
to='juliet@example.com/chamber'/><br />
<presence<br />
from='romeo@example.net/orchard'<br />
to='juliet@example.com/balcony'/><br />
<presence<br />
type='error'<br />
from='mercutio@example.org'<br />
to='romeo@example.net/orchard'><br />
<error type='cancel'><br />
<gone xmlns='urn:ietf:params:xml:ns:xmpp-stanzas'/><br />
</error><br />
</presence><br />
</source><br />
<br />
:例子 6: 用户直接发送出席信息给另一个不在他的名册中的用户:<br />
<br />
<source lang="xml"><br />
<presence<br />
from='romeo@example.net/orchard'<br />
to='nurse@example.com'<br />
xml:lang='en'><br />
<show>dnd</show><br />
<status>courting Juliet</status><br />
<priority>0</priority><br />
</presence><br />
</source><br />
<br />
:例子 7: 用户发送更新的可用出席信息用于广播:<br />
<br />
<source lang="xml"><br />
<presence xml:lang='en'><br />
<show>away</show><br />
<status>I shall return!</status><br />
<priority>1</priority><br />
</presence><br />
</source><br />
<br />
:例子 8: 用户的服务器仅向一个联系人广播更新的出席信息 (不是那些返回错误的联系人,也不是那些用户直接向其发送出席信息的联系人):<br />
<br />
<source lang="xml"><br />
<presence<br />
from='romeo@example.net/orchard'<br />
to='juliet@example.com'<br />
xml:lang='en'><br />
<show>away</show><br />
<status>I shall return!</status><br />
<priority>1</priority><br />
</presence><br />
</source><br />
<br />
:例子 9: 联系人的服务器递送更新的出席信息给联系人所有可用的资源:<br />
<br />
<source lang="xml"><br />
[to "balcony" resource...]<br />
<presence<br />
from='romeo@example.net/orchard'<br />
to='juliet@example.com'<br />
xml:lang='en'><br />
<show>away</show><br />
<status>I shall return!</status><br />
<priority>1</priority><br />
</presence><br />
[to "chamber" resource...]<br />
<presence<br />
from='romeo@example.net/orchard'<br />
to='juliet@example.com'<br />
xml:lang='en'><br />
<show>away</show><br />
<status>I shall return!</status><br />
<priority>1</priority><br />
</presence><br />
</source><br />
<br />
:例子 10: 联系人的资源之一广播最后出席信息:<br />
<br />
<source lang="xml"><br />
<presence from='juliet@example.com/balcony' type='unavailable'/><br />
</source><br />
<br />
:例子 11: 联系人的服务器发送不可用出席信息给用户:<br />
<br />
<source lang="xml"><br />
<presence<br />
type='unavailable'<br />
from='juliet@example.com/balcony'<br />
to='romeo@example.net/orchard'/><br />
</source><br />
<br />
:例子 12: 用户发送最后出席信息:<br />
<br />
<source lang="xml"><br />
<presence from='romeo@example.net/orchard'<br />
type='unavailable'<br />
xml:lang='en'><br />
<status>gone home</status><br />
</presence><br />
</source><br />
<br />
:例子 13: 用户的服务器广播不可用出席信息给联系人,包括用户直接向其发送出席信息的那个人:<br />
<br />
<source lang="xml"><br />
<presence<br />
type='unavailable'<br />
from='romeo@example.net/orchard'<br />
to='juliet@example.com'<br />
xml:lang='en'><br />
<status>gone home</status><br />
</presence><br />
<presence<br />
from='romeo@example.net/orchard'<br />
to='nurse@example.com'<br />
xml:lang='en'><br />
<status>gone home</status><br />
</presence><br />
</source><br />
<br />
==管理订阅==<br />
<br />
:为了保护即时消息用户和任何其他实体的隐私, 出席信息和可用性信息仅向用户已批准的其他实体披露. 当一个用户同意其他用户可以看到它的出席信息, 这个实体被称为对于用户的出席信息有一个订阅. 订阅超越了会话; 实际上, 它一直存在直到订阅者取消订阅或被订阅者取消曾经授权的订阅为止. 在XMPP中订阅是通过发送包含特定属性的出席信息节来管理的.<br />
<br />
:注意: 在订阅和名册之间有重要的交互; 这些定义在 名册条目和出席信息订阅的集成Integration of Roster Items and Presence Subscriptions (第八章), 而且读者必须参考那一章才能完整地理解出席信息订阅.<br />
<br />
===请求一个订阅===<br />
<br />
:对另一个实体的出席信息的订阅请求是由发送一个类型为"subscribe"的出席信息节来开始的.<br />
<br />
:例子: 发送一个订阅请求:<br />
<br />
<source lang="xml"><br />
<presence to='juliet@example.com' type='subscribe'/><br />
</source><br />
<br />
:关于客户端和服务器在订阅请求中的职责, 参考 出席信息订阅Presence Subscriptions(第五章第一节第六小节).<br />
<br />
===处理一个订阅请求===<br />
<br />
:当一个客户端从另一个实体接收到一个订阅请求, 它必须(MUST)批准这个请求(发送一个类型为"subscribed"的出席信息节)或拒绝这个请求(发送一个类型为"unsubscribed"的出席信息节).<br />
<br />
:例子: 批准一个订阅请求:<br />
<br />
<source lang="xml"><br />
<presence to='romeo@example.net' type='subscribed'/><br />
</source><br />
<br />
:例子: 拒绝一个出席信息订阅的请求:<br />
<br />
<source lang="xml"><br />
<presence to='romeo@example.net' type='unsubscribed'/><br />
</source><br />
<br />
===从另一个实体取消一个订阅===<br />
<br />
:如果一个用户想取消一个曾经允许的订阅请求, 它发送一个类型为"unsubscribed"的出席信息节.<br />
<br />
:例子: 取消一个曾经允许的订阅请求:<br />
<br />
<source lang="xml"><br />
<presence to='romeo@example.net' type='unsubscribed'/><br />
</source><br />
<br />
===取消对于另一个实体的出席信息的订阅===<br />
<br />
:如果用户想取消对于另一个实体的出席信息的订阅, 它发送一个类型为"unsubscribe"的出席信息节.<br />
<br />
:例子: 取消对一个实体的出席信息的订阅:<br />
<br />
<source lang="xml"><br />
<presence to='juliet@example.com' type='unsubscribe'/><br />
</source><br />
<br />
==名册管理==<br />
<br />
:在XMPP中, 一个人的联系人列表被称为名册(roster), 它包括任意数量的特定名册条目, 每个名册条目被一个唯一的JID(通常格式是<contact@domain>)所标识. 一个用户的名册由用户的服务器代替用户储存从而这个用户可以从任何资源访问名册信息.<br />
<br />
:注意: 在名册和订阅之间有重要的交互; 这些定义在 名册条目和出席信息订阅的集成Integration of Roster Items and Presence Subscriptions (第八章), 而且读者必须参考那一章才能完整地理解名册管理.<br />
<br />
===语法和语义===<br />
<br />
:名册使用IQ节来管理, 具体来说就是符合'jabber:iq:roster'名字空间的<query/>子元素的含义.这个<query/>元素可以(MAY)包含一个或更多<item/>子元素, 每个描述一个唯一的名册条目或曰 联系人"contact".<br />
<br />
:每个名册条目的"key"或者说唯一标识符就是一个JID,封装在<item/>元素的'jid'属性(它是必需的(REQUIRED))之中. 如果这个条目是和另一个(人类)即时消息用户相关的,'jid'属性的值的格式应该(SHOULD)是<user@domain>.<br />
<br />
:和一个名册条目相关的出席信息订阅的状态从<item/>元素的'subscription'属性可以得到.这个属性允许的值包括:<br />
<br />
:* "none" -- 这个用户没有对这个联系人出席信息的订阅, 这个联系人也没有订阅用户的出席信息<br />
<br />
:* "to" -- 这个用户订阅了这个联系人的出席信息, 但是这个联系人没有订阅用户的出席信息<br />
<br />
:* "from" -- 这个联系人订阅了用户的出席信息, 但是这个用户没有订阅这个联系人的出席信息<br />
<br />
:* "both" -- 用户和联系人互相订阅了对方的出席信息<br />
<br />
:每个<item/>条目可以(MAY)包含一个'name'属性, 它设置和这个JID相关的"nickname", 取决于用户(而不是联系人). 'name'属性的值是不透明的.<br />
<br />
:每个<item/>条目可以(MAY)包含一个或多个<group/>子元素,用于把名册条目收集到多个类别之中. <group/>子元素的XML字符数据是不透明的.<br />
<br />
===商业规则===<br />
<br />
:在一个名册"set"中一个服务器必须(MUST)忽略任何'to'地址, 并且必须(MUST)认为任何名册"set"是应用于发送者的. 为了更多的安全性, 一个客户端应该(SHOULD)检查"roster push"(包含一个名册条目的类型为"set"的输入IQ)的"from"地址以保证它来自一个信任的源; 具体的, 这个节必须(MUST)没有 'from'属性(例如, 从服务器隐含的) 或'from'属性的值匹配用户的纯JID(格式为<user@domain>)或全JID(格式为<user@domain/resource>); 否则, 客户端应该(SHOULD)忽略这个"roster push".<br />
<br />
===登录时接收一个人的名册===<br />
<br />
:在连接到服务器并成为一个激活的资源之后, 一个客户端应该(SHOULD)在发送初始化出席信息之前请求名册(无论如何, 因为可能不是所有的资源都想接收名册, 例如, 一个带宽受限的连接, 客户端对于名册的请求是可选的(OPTIONAL)). 如果一个可用的资源在一个会话期间没有请求名册, 服务器不能(MUST NOT)向它发送出席信息订阅以及相关的名册更新.<br />
<br />
:例子: 客户端向服务器请求当前的名册:<br />
<br />
<source lang="xml"><br />
<iq from='juliet@example.com/balcony' type='get' id='roster_1'><br />
<query xmlns='jabber:iq:roster'/><br />
</iq><br />
</source><br />
<br />
:例子: 客户端从服务器收到名册:<br />
<br />
<source lang="xml"><br />
<iq to='juliet@example.com/balcony' type='result' id='roster_1'><br />
<query xmlns='jabber:iq:roster'><br />
<item jid='romeo@example.net'<br />
name='Romeo'<br />
subscription='both'><br />
<group>Friends</group><br />
</item><br />
<item jid='mercutio@example.org'<br />
name='Mercutio'<br />
subscription='from'><br />
<group>Friends</group><br />
</item><br />
<item jid='benvolio@example.org'<br />
name='Benvolio'<br />
subscription='both'><br />
<group>Friends</group><br />
</item><br />
</query><br />
</iq><br />
</source><br />
<br />
===增加一个名册条目===<br />
<br />
:任何时候, 一个用户可以(MAY)增加一个条目到他或她的名册.<br />
<br />
:例子: 客户端添加一个新的条目:<br />
<br />
<source lang="xml"><br />
<iq from='juliet@example.com/balcony' type='set' id='roster_2'><br />
<query xmlns='jabber:iq:roster'><br />
<item jid='nurse@example.com'<br />
name='Nurse'><br />
<group>Servants</group><br />
</item><br />
</query><br />
</iq><br />
</source><br />
<br />
:服务器必须(MUST)在持久信息存储机构中更新名册信息,并且也要向这个用户的所有已请求名册的可用资源推送这一改变. 这个"名册推送"包括一个类型为"set"的IQ节,从服务器发送给客户端,使用户的所有可用资源保持和基于服务器的名册信息的同步.<br />
<br />
:例子: 服务器 (1) 推送更新的名册信息给所有已请求名册的可用资源 并且 (2) 以一个IO结果应答发送的资源:<br />
<br />
<source lang="xml"><br />
<iq to='juliet@example.com/balcony'<br />
type='set'<br />
id='a78b4q6ha463'><br />
<query xmlns='jabber:iq:roster'><br />
<item jid='nurse@example.com'<br />
name='Nurse'<br />
subscription='none'><br />
<group>Servants</group><br />
</item><br />
</query><br />
</iq><br />
<iq to='juliet@example.com/chamber'<br />
type='set'<br />
id='a78b4q6ha464'><br />
<query xmlns='jabber:iq:roster'><br />
<item jid='nurse@example.com'<br />
name='Nurse'<br />
subscription='none'><br />
<group>Servants</group><br />
</item><br />
</query><br />
</iq><br />
<iq to='juliet@example.com/balcony' type='result' id='roster_2'/><br />
</source><br />
<br />
:正如IQ节类型(定义在[XMPP-CORE|XMPP文档列表/XMPP正式RFC标准/RFC3920])的语义所要求的,每个接收到了名册推送的资源必须(MUST)应答一个类型为"result"(或 "error")的IQ节.<br />
<br />
:例子: 资源应答一个IQ结果给服务器:<br />
<br />
<source lang="xml"><br />
<iq from='juliet@example.com/balcony'<br />
to='example.com'<br />
type='result'<br />
id='a78b4q6ha463'/><br />
<iq from='juliet@example.com/chamber'<br />
to='example.com'<br />
type='result'<br />
id='a78b4q6ha464'/><br />
</source><br />
<br />
===更新名册条目===<br />
<br />
:更新一个已有的名册条目(例如, 改变组) 的方法和增加一个新的名册条目是一样的, 换言之, 在IQ set 节中发送名册条目给服务器.<br />
<br />
:例子: 用户更新名册条目(增加组):<br />
<br />
<source lang="xml"><br />
<iq from='juliet@example.com/chamber' type='set' id='roster_3'><br />
<query xmlns='jabber:iq:roster'><br />
<item jid='romeo@example.net'<br />
name='Romeo'<br />
subscription='both'><br />
<group>Friends</group><br />
<group>Lovers</group><br />
</item><br />
</query><br />
</iq><br />
</source><br />
<br />
:正如增加一个名册条目, 当更新一个名册条目时服务器必须(MUST)在持久信息存储机构中更新名册信息, 并且也要初始化一个名册推送给这个用户的所有已请求名册的可用资源.<br />
<br />
===删除一个名册条目===<br />
<br />
:任何时候, 用户可以(MAY)从他或她的名册中删除一个条目,只要发送一个 IQ set 给服务器并确保其'subscription'属性值为"remove" (如果从一个客户端接收到'subscription'属性的任何其他值,一个兼容的服务器必须(MUST)忽略它).<br />
<br />
:例子: 客户端移除一个条目:<br />
<br />
<source lang="xml"><br />
<iq from='juliet@example.com/balcony' type='set' id='roster_4'><br />
<query xmlns='jabber:iq:roster'><br />
<item jid='nurse@example.com' subscription='remove'/><br />
</query><br />
</iq><br />
</source><br />
<br />
:和增加一个名册条目一样, 删除一个名册条目的时候服务器必须(MUST)在持久信息存储机构中更新名册信息,初始化一个名册推送给这个用户的所有已请求名册的可用资源(伴随着把'subscription'属性值设为"remove"),并且发送一个 IQ result 给初始化资源.<br />
<br />
:关于这个命令的含义的更多信息, 见 移除一个名册条目并取消所有订阅Removing a Roster Item and Cancelling All Subscriptions (第八章第六节).<br />
<br />
==名册条目和出席信息订阅的集成==<br />
<br />
===概览===<br />
<br />
:关于用户从或向别的联系人订阅出席信息,一个即时消息用户通常希望在名册条目和出席信息订阅之间有某些层次的集成. 本章描述了在XMPP即时消息应用中必须(MUST)支持的那些层次的集成.<br />
<br />
:有四种主要的订阅状态:<br />
<br />
:* None -- 这个用户没有对这个联系人出席信息的订阅, 这个联系人也没有订阅用户的出席信息<br />
<br />
:* To -- 这个用户订阅了这个联系人的出席信息, 但是这个联系人没有订阅用户的出席信息<br />
<br />
:* From -- 这个联系人订阅了用户的出席信息, 但是这个用户没有订阅这个联系人的出席信息<br />
<br />
:* Both -- 用户和联系人互相订阅了对方的出席信息(例如, 联合'from' 和 'to')<br />
<br />
:这些状态的每一个都被反射到用户和联系人双方的名册中, 从而导致持久的订阅状态.<br />
<br />
:在以下的子章节中将叙述这些订阅状态如何为了完成特定的已定义的用例而进行交互. 关于服务器和客户端处理所有订阅状态的细节 (包括处于以上所列的状态之外的未决状态)在 订阅状态Subscription States(第九章).<br />
<br />
:服务器不能(MUST NOT)发送出席信息订阅请求或名册推送给不可用的资源, 也不能给没有已请求的名册的可用资源.<br />
<br />
:在名册推送中'from'和'to'地址是可选的(OPTIONAL); 如果包含了, 它们的值应该(SHOULD)是那个会话的资源的全JID. 一个客户端必须(MUST)以一个类型为"result"的IQ节来承认每个名册推送(为了暂时的原因, 这些节不显示在以下的例子中但是按[XMPP-CORE|XMPP文档列表/XMPP正式RFC标准/RFC3920]定义的IQ语义学的规定它们是必需的).<br />
<br />
===用户向联系人订阅===<br />
<br />
:以下描述一个用户向一个联系人订阅的过程, 包括名册条目和订阅状态之间的互动.<br />
<br />
:1. 为了能够在用户的客户端界面处理联系人以及在服务器跟踪订阅, 用户的客户端应该(SHOULD)为新的名册条目执行一个"roster set". 这个请求包括发送一个类型为'set'的IQ节并拥有符合'jabber:iq:roster'名字空间的<query/>子元素, 它(<query/>元素)再包含一个<item/>子元素来定义新的名册条目; 这个<item/>元素必须(MUST)拥有一个'jid'属性, 可以(MAY)拥有一个'name'属性, 不能(MUST NOT)拥有一个'subscription'属性, 并且可以(MAY)包含一个或多个<group/>子元素:<br />
<br />
<source lang="xml"><br />
<iq type='set' id='set1'><br />
<query xmlns='jabber:iq:roster'><br />
<item<br />
jid='contact@example.org'<br />
name='MyContact'><br />
<group>MyBuddies</group><br />
</item><br />
</query><br />
</iq><br />
</source><br />
<br />
:2. 作为结果, 这个用户的服务器 (1) 必须(MUST)为这个新的名册条目初始化一个名册推送给这个用户的所有已经请求名册的可用资源, 其'subscription'属性的值为 "none"; 并且 (2) 必须(MUST)以一个 IQ result 应答发送的资源表明名册设置成功了:<br />
<br />
<source lang="xml"><br />
<iq type='set'><br />
<query xmlns='jabber:iq:roster'><br />
<item<br />
jid='contact@example.org'<br />
subscription='none'<br />
name='MyContact'><br />
<group>MyBuddies</group><br />
</item><br />
</query><br />
</iq><br />
<iq type='result' id='set1'/><br />
</source><br />
<br />
:3. 如果用户想向这个联系人请求出席信息的订阅, 用户的客户端必须(MUST)发送一个类型为'subscribe'的出席信息节给联系人:<br />
<br />
<source lang="xml"><br />
<presence to='contact@example.org' type='subscribe'/><br />
</source><br />
<br />
:4. 作为结果, 用户的服务器必须(MUST)初始化第二个名册推送给这个用户的所有已经请求名册的可用资源,把这个联系人设置成'none'订阅状态的未决子状态; 这个未决子状态是由名册条目中包含的ask='subscribe'属性所指示的:<br />
<br />
<source lang="xml"><br />
<iq type='set'><br />
<query xmlns='jabber:iq:roster'><br />
<item<br />
jid='contact@example.org'<br />
subscription='none'<br />
ask='subscribe'<br />
name='MyContact'><br />
<group>MyBuddies</group><br />
</item><br />
</query><br />
</iq><br />
</source><br />
<br />
:注意: 如果用户在发送订阅请求之前没有新建一个名册条目, 服务器必须(MUST)现在代替用户新建一个,然后发送一个名册推送给这个用户的所有已经请求名册的可用资源, 不含以上所示的'name'属性和<group/>子元素.<br />
<br />
:5. 用户的服务器也必须(MUST)把这个类型为"subscribe"的出席信息节的'from'地址设置为用户的纯JID(例如, <user@example.com>)(如果用户提供了设置为用户的全JID的'from'地址, 服务器应该(SHOULD)移除资源ID). 如果联系人和用户在不同的主机上, 用户的服务器必须(MUST)路由这个出席信息节到联系人的服务器来递送到这个联系人(这种情形的假定贯穿本文; 无论如何, 如果联系人在同一台主机, 那么服务器可以简单地直接递送出席信息节):<br />
<br />
<source lang="xml"><br />
<presence<br />
from='user@example.com'<br />
to='contact@example.org'<br />
type='subscribe'/><br />
</source><br />
<br />
:注意:如果用户的服务器从联系人的服务器收到了一个类型为"error"的出席信息节, 它必须(MUST)这个错误节给用户, 用户的客户端可以(MAY)确定那个错误是否对于上次用户发出的"subscribe"类型的出席信息节(例如, 通过跟踪'id'属性)的应答,然后选择重新发送"subscribe"请求还是发送一个"unsubscribe"类型的出席信息节给联系人以恢复到它的上一个状态.<br />
<br />
:6. 接收到指向联系人的"subscribe"类型的出席信息节之后, 这个联系人的服务器必须(MUST)决定是否至少有一个已请求名册的联系人的可用资源. 如果是, 它必须(MUST)递送这个订阅请求给这个联系人(如果不是, 联系人的服务器必须(MUST)离线存储这个订阅请求用于递送 when this condition is next met; 通常这是通过增加一个关于这个联系人的名册条目到用户名册中来实现的, 伴随着一个 "None + Pending In"的状态(定义在 订阅状态Subscription States (第九章)), 无论如何一个服务器不应该(SHOULD NOT)在那种状态下推送或递送名册条目给联系人). 不论何时订阅请求被递送到了, 联系人必须决定是否批准它(根据联系人的配置选项, 联系人的客户端可以(MAY)批准或拒绝订阅请求而无需向联系人显示). 这里我们假定这个 "happy path", 即联系人批准了订阅请求(替代的拒绝订阅请求的流程定义在第八章第二节第一小节). 在这种情形下, 这个联系人的客户端 (1) 应该(SHOULD) 执行一个roster set 为这个用户指明期望的昵称和组(如果有的话); 并且 (2) 必须(MUST)发送一个"subscribed"类型的出席信息节给这个用户以批准这个订阅请求.<br />
<br />
<source lang="xml"><br />
<iq type='set' id='set2'><br />
<query xmlns='jabber:iq:roster'><br />
<item<br />
jid='user@example.com'<br />
name='SomeUser'><br />
<group>SomeGroup</group><br />
</item><br />
</query><br />
</iq><br />
<presence to='user@example.com' type='subscribed'/><br />
</source><br />
<br />
:7. 作为结果, 联系人的服务器 (1) 必须(MUST) 初始化一个名册推送给所有联系人已请求名册的可用资源, 包含一个关于那个用户的名册条目,并且其订阅状态为'from'(甚至联系人不执行roster set,服务器也必须(MUST)发送它); (2) 必须(MUST)返回一个 IQ result 给发送的资源表示名册设置(roster set)成功了; (3) 必须(MUST)路由这个"subscribed"类型的出席信息节给用户, 首先把'from'地址设为联系人的纯JID(<contact@example.org>); 然后 (4) 必须(MUST)从所有联系人的可用资源向用户发送可用的出席信息:<br />
<br />
<source lang="xml"><br />
<iq type='set' to='contact@example.org/resource'><br />
<query xmlns='jabber:iq:roster'><br />
<item<br />
jid='user@example.com'<br />
subscription='from'<br />
name='SomeUser'><br />
<group>SomeGroup</group><br />
</item><br />
</query><br />
</iq><br />
<iq type='result' to='contact@example.org/resource' id='set2'/><br />
<presence<br />
from='contact@example.org'<br />
to='user@example.com'<br />
type='subscribed'/><br />
<presence<br />
from='contact@example.org/resource'<br />
to='user@example.com'/><br />
</source><br />
<br />
:注意: 如果联系人的服务器从用户的服务器收到一个"error"类型的出席信息节, 它必须(MUST)递送这个错误节给联系人, 联系人的客户端可以(MAY)确定那个错误是否对于上次联系人发出的"subscribe"类型的出席信息节(例如, 通过跟踪'id'属性)的应答,然后选择重新发送"subscribe"请求还是发送一个"unsubscribe"类型的出席信息节给用户以恢复到它的上一个状态. <br />
<br />
:8. 接收到一个指向用户的"subscribed"类型的出席信息节之后, 用户的服务器必须(MUST)首先检查在用户名册中的这个联系人的状态是: (a) subscription='none' and ask='subscribe' 还是 (b) subscription='from' and ask='subscribe'. 如果联系人不是以上述的状态在用户的名册中,用户的服务器必须(MUST)安静的忽略这个"subscribed"类型的出席信息节(例如, 服务器不能(MUST NOT)路由它到用户, 修改用户的名册, 或生成一个名册推送到用户的可用资源). 如果联系人以上述任何一种状态存在于用户的名册中, 用户的服务器 (1) 必须(MUST)从联系人向用户递送这个"subscribed"类型的出席信息节; (2)必须(MUST)初始化一个名册推送给所有已请求名册的这个用户的可用资源,包含一个关于这个联系人的更新的名册条目,同时其'subscription'属性值设置为"to"; 并且 (3) 必须(MUST)从每一个联系人的可用资源向每一个用户的可用资源递送服务器接收到的可用的出席信息节:<br />
<br />
<source lang="xml"><br />
<presence<br />
to='user@example.com'<br />
from='contact@example.org'<br />
type='subscribed'/><br />
<iq type='set'><br />
<query xmlns='jabber:iq:roster'><br />
<item<br />
jid='contact@example.org'<br />
subscription='to'<br />
name='MyContact'><br />
<group>MyBuddies</group><br />
</item><br />
</query><br />
</iq><br />
<presence<br />
from='contact@example.org/resource'<br />
to='user@example.com/resource'/><br />
</source><br />
<br />
:9. 接收到"subscribed"类型的出席信息节之后, 用户应该(SHOULD)承认接收到了订阅状态通知,<br />
要么发送一个"subscribe"类型的出席信息节给联系人证实它, 要么发送一个"unsubscribe"类型的出席信息节给联系人否认它;这个步骤不一定影响订阅状态(见 订阅状态Subscription States(第九章)的细节), 但是会让用户用户的服务器知道它必须(MUST)不再发送订阅状态改变通知给用户(见第九章第四节).<br />
<br />
:从用户这方面看, 现在存在一个向联系人的出席信息的订阅; 从联系人的方面看, 现在存在一个从用户的来的订阅.<br />
<br />
====替代流程: 联系人拒绝订阅请求====<br />
<br />
:以上活动流程展示了关于用户向联系人的订阅请求的 "happy path" . 如果联系人拒绝用户的订阅请求,那么主要的替代流程如下所述.<br />
<br />
:1. 如果联系人想拒绝这个请求, 联系人的客户端必须(MUST)发送一个"unsubscribed"类型的出席信息节给用户(取代第八章第二节中步骤6发送的 "subscribed"类型的出席信息节):<br />
<br />
<source lang="xml"><br />
<presence to='user@example.com' type='unsubscribed'/><br />
</source><br />
<br />
:2. 作为结果, 联系人的服务器必须(MUST)路由这个"unsubscribed"类型的出席信息节给用户,首先把'from'地址设为联系人的纯JID(<contact@example.org>):<br />
<br />
<source lang="xml"><br />
<presence<br />
from='contact@example.org'<br />
to='user@example.com'<br />
type='unsubscribed'/><br />
</source><br />
<br />
:注意: 如果联系人的服务器之前把用户添加到了联系人的名册中用来跟踪, 这时它必须(MUST)移除这个相关的条目.<br />
<br />
:3. 接收到指向用户的"unsubscribed"类型出席信息节之后, 用户的服务器 (1) 必须(MUST)地送那个出席信息节给用户 并且 (2) 必须(MUST) 初始化一个名册推送给这个用户的所有已请求名册的可用资源, 包含一个关于这个联系人的一个更新条目,其'subscription'属性设为"none"并且没有'ask'属性:<br />
<br />
<source lang="xml"><br />
<presence<br />
from='contact@example.org'<br />
to='user@example.com'<br />
type='unsubscribed'/><br />
<iq type='set'><br />
<query xmlns='jabber:iq:roster'><br />
<item<br />
jid='contact@example.org'<br />
subscription='none'<br />
name='MyContact'><br />
<group>MyBuddies</group><br />
</item><br />
</query><br />
</iq><br />
</source><br />
<br />
:4. 接收到类型为"unsubscribed"出席信息节之后, 用户应该(SHOULD)承认收到订阅状态通知, 要么发送一个"unsubscribe"类型的出席信息节给联系人证实它, 要么发送一个"subscribe"类型的出席信息节给联系人否认它; 这一步骤不影响订阅状态(见 订阅状态Subscription States(第九章)的细节), 但是让用户的服务器知道它必须(MUST)不再发送订阅状态改变的通知给用户(见第九章第四节).<br />
<br />
:作为这一行为的结果, 联系人现在在用户的名册中, 状态为"none",而用户根本不在联系人的名册中.<br />
<br />
===建立一个相互的订阅===<br />
<br />
:用户和联系人可以在前述"happy path"的基础上建立一个相互的订阅(例如, 一个"both"的订阅类型). 流程如下.<br />
<br />
:1. 如果联系人想建立一个相互的订阅, 联系人必须(MUST)发送一个订阅请求给用户(视联系人的配置选项而定, 联系人的客户端可以(MAY)自动发送它):<br />
<br />
<source lang="xml"><br />
<presence to='user@example.com' type='subscribe'/><br />
</source><br />
<br />
:2. 作为结果, 联系人的服务器 (1) 必须(MUST)初始化一个名册推送给联系人的所有已请求名册的可用资源, 伴随着用户仍在'from'订阅状态但同时有一个未决的'to'订阅状态(通过在名册条目中包含一个ask='subscribe'的属性来指示); 并且 (2) 必须(MUST)路由这个"subscribe"类型的出席信息节给用户(先把'from'地址设为联系人的纯JID(<contact@example.org>)):<br />
<br />
<source lang="xml"><br />
<iq type='set'><br />
<query xmlns='jabber:iq:roster'><br />
<item<br />
jid='user@example.com'<br />
subscription='from'<br />
ask='subscribe'<br />
name='SomeUser'><br />
<group>SomeGroup</group><br />
</item><br />
</query><br />
</iq><br />
<presence<br />
from='contact@example.org'<br />
to='user@example.com'<br />
type='subscribe'/><br />
</source><br />
<br />
:注意: 如果联系人的服务器从用户的服务器收到一个"error"类型的出席信息节, 它必须(MUST)递送这个错误节给联系人, 它的客户端可以(MAY)确定这个错误是用来应答上次发送的"subscribe"类型的出席信息节(换言之, 通过跟踪'id'属性) 并且选择重发这个"subscribe"请求还是发送一个"unsubscribe"类型的出席信息节给用户以把名册恢复到它的前一个状态.<br />
<br />
:3. 接收到指向用户的"subscribe"类型出席信息节之后, 用户的服务器必须确定是否至少有一个已请求名册可用资源. 如果是, 用户的服务器必须(MUST)递送这个订阅请求给用户(如果不是, 它必须(MUST)离线存储这个订阅请求等这种情形再次发生时递送). 无论何时订阅请求被递送了, 用户必须决定是否批准它(视用户的配置选项而定, 用户的客户端可以(MAY)批准或拒绝这个订阅请求而不需要向用户显示). 这里我们假定这是"happy path",用户批准了订阅请求(替代的拒绝订阅请求的流程定义在第八章第三节第一小节). 在这种情形下, 用户的客户端必须(MUST)发送一个"subscribed"类型的出席信息节给联系人表示批准了订阅请求.<br />
<br />
<source lang="xml"><br />
<presence to='contact@example.org' type='subscribed'/><br />
</source><br />
<br />
:4. 作为结果, 用户的服务器 (1) 必须(MUST)初始化一个名册推送给用户的所有已请求名册的可用资源, 包含一个关于联系人的名册条目,其'subscription'属性设为"both"; (2) 必须(MUST)路由这个"subscribed"类型的出席信息节给联系人(先把'from'地址设为用户的纯JID<user@example.com>)); 并且 (3) 必须(MUST)向联系人发送它从用户的每个可用资源收到的最近一次出席信息节的全XML(不带'to'属性)(强制每个会话遵守隐私列表):<br />
<br />
<source lang="xml"><br />
<iq type='set'><br />
<query xmlns='jabber:iq:roster'><br />
<item<br />
jid='contact@example.org'<br />
subscription='both'<br />
name='MyContact'><br />
<group>MyBuddies</group><br />
</item><br />
</query><br />
</iq><br />
<presence<br />
from='user@example.com'<br />
to='contact@example.org'<br />
type='subscribed'/><br />
<presence<br />
from='user@example.com/resource'<br />
to='contact@example.org'/><br />
</source><br />
<br />
:注意: 如果用户的服务器从联系人的服务器接收到一个"error"类型的出席信息节, 它必须(MUST)递送这个错误节给用户, 它客户端可以(MAY)确定这个错误是用来应答上次发出去的"subscribed"类型的出席信息节(换言之, 通过跟踪'id'属性) 并且选择重发这个订阅请求还是发送一个"unsubscribed"类型的出席信息节给联系人以把名册恢复到上次的状态.<br />
<br />
:5. 接收到指向联系人的"subscribed"类型的出席信息节之后, 联系人的服务器必须(MUST)首先检查用户在联系人的名册中的状态是否以下状态之一: (a) subscription='none' and ask='subscribe' 或 (b) subscription='from' and ask='subscribe'. 如果用户不是以上述两种状态之一存在于联系人的名册中, 联系人的服务器必须(MUST)安静地忽略这个"subscribed"类型的出席信息节(例如, 它不能(MUST NOT)路由它给联系人, 修改联系人的名册, 或生成一个名册推送给联系人的可用资源). 如果用户以上述两种状态之一存在于联系人的名册中, 联系人的服务器 (1) 必须(MUST)从用户向联系人递送这个"subscribed"类型的出席信息节; (2) 必须(MUST)初始化一个名册推送给这个联系人的所有已请求名册的可用资源, 包含一个关于这个用户的更新的名册条目,其'subscription'属性值设为"both"; 并且 (3) 必须(MUST)向这个联系人的每个可用资源递送它从这个用户的每个资源收到的可用出席信息节:<br />
<br />
<source lang="xml"><br />
<presence<br />
from='user@example.com'<br />
to='contact@example.org'<br />
type='subscribed'/><br />
<iq type='set'><br />
<query xmlns='jabber:iq:roster'><br />
<item<br />
jid='user@example.com'<br />
subscription='both'<br />
name='SomeUser'><br />
<group>SomeGroup</group><br />
</item><br />
</query><br />
</iq><br />
<presence<br />
from='user@example.com/resource'<br />
to='contact@example.org/resource'/><br />
</source><br />
<br />
:6. 收到"subscribed"类型的出席信息节之后, 联系人应该(SHOULD)承认收到订阅请求通知,要么发送一个"subscribe"的出席信息节给用户证实它,要么发送一个"unsubscribe"类型的出席信息节给用户否认它; 这一步骤不影响订阅状态(细节见 订阅状态Subscription States(第九章)), 但是让联系人的服务器知道它必须(MUST)不再发送订阅状态变更通知给联系人(见第九章第四节).<br />
<br />
:用户和联系人现在有了对双方的出席信息的一个相互订阅 \-\- 换言之, 这个订阅类型为 "both".<br />
<br />
====替代流程: 用户拒绝订阅请求====<br />
<br />
:以上活动流程展示了关于联系人对用户的订阅请求的 "happy path". 如果用户拒绝了联系人的订阅请求,其主要流程如下.<br />
<br />
:1. 如果用户想拒绝请求, 用户的客户端必须(MUST)发送一个"unsubscribed"类型的出席信息节给联系人(替代第八章第三节中的第三步中所发送的"subscribed"类型出席信息节):<br />
<br />
<source lang="xml"><br />
<presence to='contact@example.org' type='unsubscribed'/><br />
</source><br />
<br />
:2. 作为结果, 用户的服务器必须(MUST)路由这个"unsubscribed"类型的出席信息节给联系人(首先把'from'地址设为用户的纯JID(<user@example.com>)):<br />
<br />
<source lang="xml"><br />
<presence<br />
from='user@example.com'<br />
to='contact@example.org'<br />
type='unsubscribed'/><br />
</source><br />
<br />
:3. 接收到指向联系人的"unsubscribed"类型的出席信息节之后, 联系人的服务器 (1) 必须(MUST)递送这个出席信息节给联系人; 并且 (2) 必须(MUST)初始化一个名册推送给这个联系人的所有已请求名册的可用资源, 包含关于这个用户的更新的名册条目,其'subscription'属性的值设为"from"并且没有'ask'属性:<br />
<br />
<source lang="xml"><br />
<presence<br />
from='user@example.com'<br />
to='contact@example.org'<br />
type='unsubscribed'/><br />
<iq type='set'><br />
<query xmlns='jabber:iq:roster'><br />
<item<br />
jid='user@example.com'<br />
subscription='from'<br />
name='SomeUser'><br />
<group>SomeGroup</group><br />
</item><br />
</query><br />
</iq><br />
</source><br />
<br />
:4. 接收到"unsubscribed"类型的出席信息节之后, 联系人应该(SHOULD)承认收到那个订阅状态通知,要么向用户发送一个"unsubscribe"类型的出席信息节以证实它,要么向用户发送一个"subscribe"类型的出席信息以否认它; 这个步骤不会影响订阅状态(详见 订阅状态Subscription States(第九章)),但是让联系人的服务器知道它必须(MUST)不再发送订阅状态变更通知给联系人(见第九章第四节).<br />
<br />
:作为这一活动的结果, 订阅状态没有任何改变; 换言之, 联系人在用户的名册中的订阅状态为"to"并且用户在联系人的名册中的订阅状态为"from".<br />
<br />
===取消订阅===<br />
<br />
:在订阅了一个联系人的出席信息之后的任何时候, 一个用户可以(MAY)取消订阅. 在所有实例中用户发送来执行这一动作的XML是相同的, 接下来的订阅状态根据发出取消订阅命令时获得的订阅状态的情况而不同. 两种可能的情节描述如下.<br />
<br />
====情形 #1: 当订阅不是相互的时候取消订阅====<br />
<br />
:在第一种情形, 用户有一个向联系人的出席信息的订阅但是联系人没有对用户的出席信息的订阅(换言之, 订阅不是相互的).<br />
<br />
:1. 如果用户想取消对联系人的出席信息的订阅, 用户必须(MUST)发送一个"unsubscribe"类型的出席信息节给联系人:<br />
<br />
<source lang="xml"><br />
<presence to='contact@example.org' type='unsubscribe'/><br />
</source><br />
<br />
:2. 作为一个结果, 用户的服务器 (1) 必须(MUST) 发送一个名册推送给这个用户的所有已请求名册的可用资源,包含一个关于这个联系人的更新名册条目,其'subscription'属性设为"none"; 并且 (2) 必须(MUST)路由这个"unsubscribe"类型的出席信息节给联系人(首先把'from'地址设为用户的纯JID(<user@example.com>)):<br />
<br />
<source lang="xml"><br />
<iq type='set'><br />
<query xmlns='jabber:iq:roster'><br />
<item<br />
jid='contact@example.org'<br />
subscription='none'<br />
name='MyContact'><br />
<group>MyBuddies</group><br />
</item><br />
</query><br />
</iq><br />
<presence<br />
from='user@example.com'<br />
to='contact@example.org'<br />
type='unsubscribe'/><br />
</source><br />
<br />
:3. 接收到指向联系人的"unsubscribe"类型出席信息节之后, 联系人的服务器 (1) 必须(MUST)初始化一个名册推送给这个联系人的所有已请求名册的可用资源, 包含一个关于这个用户的名册条目,其'subscription'属性值设为"none" (如果联系人不可用或未曾请求名册, 联系人的服务器必须(MUST)修改名册条目并在下次联系人请求名册时发送那个已修改的条目); 并且 (2) 必须(MUST)递送这个"unsubscribe"状态改变通知给联系人:<br />
<br />
<source lang="xml"><br />
<iq type='set'><br />
<query xmlns='jabber:iq:roster'><br />
<item<br />
jid='user@example.com'<br />
subscription='none'<br />
name='SomeUser'><br />
<group>SomeGroup</group><br />
</item><br />
</query><br />
</iq><br />
<presence<br />
from='user@example.com'<br />
to='contact@example.org'<br />
type='unsubscribe'/><br />
</source><br />
<br />
:4. 接收到"unsubscribe"类型的出席信息节之后, 联系人应该(SHOULD)承认收到那个订阅状态通知,要么发送一个"unsubscribed"类型的出席信息节给用户以证实它,要么发送一个"subscribed"类型的出席信息节给用户否认它; 这个步骤不影响订阅状态(详见 订阅状态Subscription States (第九章)), 但是让联系人的服务器知道它必须(MUST)不再发送订阅状态变更通知给联系人(见第九章第四节).<br />
<br />
:5. 联系人的服务器接着 (1) 必须(MUST)发送一个"unsubscribed"类型的出席信息节给用户;并且 (2) 应该(SHOULD)向用户发送从这个联系人的所有可用资源收到的不可用出席信息:<br />
<br />
<source lang="xml"><br />
<presence<br />
from='contact@example.org'<br />
to='user@example.com'<br />
type='unsubscribed'/><br />
<presence<br />
from='contact@example.org/resource'<br />
to='user@example.com'<br />
type='unavailable'/><br />
</source><br />
<br />
:6. 当用户的服务器收到类型为"unsubscribed" 和 "unavailable"的出席信息节, 它必须(MUST)递送它们给用户:<br />
<br />
<source lang="xml"><br />
<presence<br />
from='contact@example.org'<br />
to='user@example.com'<br />
type='unsubscribed'/><br />
<presence<br />
from='contact@example.org/resource'<br />
to='user@example.com'<br />
type='unavailable'/><br />
</source><br />
<br />
:7. 接收到"unsubscribed"类型的出席信息节之后, 用户应该(SHOULD)承认收到那个订阅状态变更通知,要么向联系人发送一个"unsubscribe"类型的出席信息节以证实它,要么向联系人发送一个"subscribe"的出席信息节以否认它;这步骤不影响订阅状态(详见 订阅状态Subscription States(第九章)), 但是让用户的服务器知道它必须(MUST)不在发送订阅状态变更通知给用户(见第九章第四节).<br />
<br />
====情形 #2: 当订阅是相互的时候取消订阅====<br />
<br />
:在第二种情形下, 用户有一个向联系人的出席信息的订阅并且联系人也有一个向用户的出席信息的订阅(换言之, 订阅是相互的).<br />
<br />
:1. 如果用户想从联系人的出席信息取消订阅, 用户必须(MUST)发送一个"unsubscribe"类型的出席信息节给联系人:<br />
<br />
<source lang="xml"><br />
<presence to='contact@example.org' type='unsubscribe'/><br />
</source><br />
<br />
:2. 作为一个结果, 用户的服务器 (1) 必须(MUST)发送一个名册推送给这个用户的所有已请求名册的可用资源,包含一个关于这个联系人的更新名册条目,其'subscription'属性值设为"from"; 并且 (2) 必须(MUST)路由这个"unsubscribe"类型的出席信息节给这个联系人( 首先把'from'地址设为这个用户的纯 JID(<user@example.com>):<br />
<br />
<source lang="xml"><br />
<iq type='set'><br />
<query xmlns='jabber:iq:roster'><br />
<item<br />
jid='contact@example.org'<br />
subscription='from'<br />
name='MyContact'><br />
<group>MyBuddies</group><br />
</item><br />
</query><br />
</iq><br />
<presence<br />
from='user@example.com'<br />
to='contact@example.org'<br />
type='unsubscribe'/><br />
</source><br />
<br />
:3. 接收到指向联系人的"unsubscribe"类型的出席信息节之后, 联系人的服务器 (1) 必须(MUST)初始化一个名册推送给这个联系人的所有已请求名册的可用资源, 包含一个关于这个用户的名册条目,其'subscription'属性值设为"to" (如果联系人不可用或未曾请求名册, 联系人的服务去必须(MUST)修改这个名册条目并且等下次联系人请求名册的时候再发送这个修改过的名册条目); 并且 (2) 必须(MUST)递送这个"unsubscribe"状态变更通知给联系人:<br />
<br />
<source lang="xml"><br />
<iq type='set'><br />
<query xmlns='jabber:iq:roster'><br />
<item<br />
jid='user@example.com'<br />
subscription='to'<br />
name='SomeUser'><br />
<group>SomeGroup</group><br />
</item><br />
</query><br />
</iq><br />
<presence<br />
from='user@example.com'<br />
to='contact@example.org'<br />
type='unsubscribe'/><br />
</source><br />
<br />
:4. 接收到这个"unsubscribe"类型的出席信息节之后, 联系人应该(SHOULD)承认收到了那个订阅状态通知,要么向用户发送一个"unsubscribed"类型的出席信息节以证实它,要么向用户发送一个"subscribed"类型的出席信息节以否认它; 这个步骤不影响订阅状态(详见 订阅状态Subscription States(第九章)), 但是让联系人的服务器知道它必须(MUST)不再发送订阅状态变更通知给联系人(见第九章第四节).<br />
<br />
:5. 联系人的服务器然后 (1) 必须(MUST)发送一个"unsubscribed"类型的出席信息节给用户; 并且 (2) 应该(SHOULD)向用户发送它从联系人的所有可用资源收到的不可用出席信息:<br />
<br />
<source lang="xml"><br />
<presence<br />
from='contact@example.org'<br />
to='user@example.com'<br />
type='unsubscribed'/><br />
<presence<br />
from='contact@example.org/resource'<br />
to='user@example.com'<br />
type='unavailable'/><br />
</source><br />
<br />
:6. 当用户的服务器收到"unsubscribed"和"unavailable"类型的出席信息节, 它必须(MUST)递送它们给用户:<br />
<br />
<source lang="xml"><br />
<presence<br />
from='contact@example.org'<br />
to='user@example.com'<br />
type='unsubscribed'/><br />
<presence<br />
from='contact@example.org/resource'<br />
to='user@example.com'<br />
type='unavailable'/><br />
</source><br />
<br />
:7. 接收到"unsubscribed"类型的出席信息节之后, 用户应该(SHOULD)承认收到了那个订阅状态的通知,要么向联系人发送一个"unsubscribe"类型的出席信息节以证实它,要么向联系人发送一个"subscribe"类型的出席信息节以否认它;这个步骤不影响订阅状态(详见 订阅状态Subscription States(第九章)), 但是让用户的服务器知道它必须(MUST)不在发送订阅状态变更通知给用户(见第九章第四节).<br />
<br />
:注意: 显然这不会导致名册条目从用户的名册移除, 并且联系人仍然有一个对用户的出席信息的订阅.为了完全取消双向的订阅并完全从用户的名册中移除名册条目, 用户应该(SHOULD)使用subscription='remove'(定义在 移除一个名册条目并取消所有订阅项Removing a Roster Item and Cancelling All Subscriptions (第八章第六节))更新名册条目.<br />
<br />
===取消一个订阅项===<br />
<br />
:在批准来自一个用户的任何订阅请求之后的任何时候, 一个联系人可以(MAY)取消那个订阅项. 联系人在所有实例中执行这个动作中发送的XML是相同的, 接下来的订阅状态根据取消命令发出当时所获得的订阅状态而有所不同. 所有可能的情节描述如下.<br />
<br />
====情形 #1: 当订阅不是相互的时候取消订阅项====<br />
<br />
:在第一种情形下, 用户有一个对联系人的出席信息的订阅但是联系人没有对于用户的出席信息的订阅(换言之, 订阅还不是相互的).<br />
<br />
:1. 如果联系人想取消用户的订阅项, 联系人必须(MUST)发送一个"unsubscribed"类型的出席信息节给用户:<br />
<br />
<source lang="xml"><br />
<presence to='user@example.com' type='unsubscribed'/><br />
</source><br />
<br />
:2. 作为一个结果, 联系人的服务器 (1) 必须(MUST)发送一个名册推送给这个联系人的所有已请求名册的可用资源, 包含一个关于这个用户的更新的名册条目,其'subscription'属性值设为"none"; (2) 必须(MUST)路由这个"unsubscribed"类型的出席信息节给用户(首先把'from'地址设为联系人的纯JID(<contact@example.org>)); 并且 (3) 应该(SHOULD)向用户发送它从联系人的所有可用资源收到的不可用出席信息:<br />
<br />
<source lang="xml"><br />
<iq type='set'><br />
<query xmlns='jabber:iq:roster'><br />
<item<br />
jid='user@example.com'<br />
subscription='none'<br />
name='SomeUser'><br />
<group>SomeGroup</group><br />
</item><br />
</query><br />
</iq><br />
<presence<br />
from='contact@example.org'<br />
to='user@example.com'<br />
type='unsubscribed'/><br />
<presence<br />
from='contact@example.org/resource'<br />
to='user@example.com'<br />
type='unavailable'/><br />
</source><br />
<br />
:3. 接收到指向用户的"unsubscribed"类型的出席信息节之后, 用户的服务器 (1) 必须(MUST)初始化一个名册推送给这个用户的所有已请求名册的可用资源, 包含一个关于这个联系人的名册条目更新,其'subscription'属性值设为"none"(如果用户不可用或未曾请求名册, 用户的服务器必须(MUST)修改这个名册条目并且等下次用户请求名册的时候发送修改过的名册条目); (2) 必须(MUST)递送这个"unsubscribed"状态改变通知给这个用户的所有可用资源; 并且 (3) 必须(MUST)向这个用户的所有可用资源递送不可用出席信息:<br />
<br />
<source lang="xml"><br />
<iq type='set'><br />
<query xmlns='jabber:iq:roster'><br />
<item<br />
jid='contact@example.org'<br />
subscription='none'<br />
name='MyContact'><br />
<group>MyBuddies</group><br />
</item><br />
</query><br />
</iq><br />
<presence<br />
from='contact@example.org'<br />
to='user@example.com'<br />
type='unsubscribed'/><br />
<presence<br />
from='contact@example.org/resource'<br />
to='user@example.com'<br />
type='unavailable'/><br />
</source><br />
<br />
:4. 接收到"unsubscribed"类型的出席信息节之后, 用户应该(SHOULD)承认收到了那个订阅状态通知,要么向联系人发送一个"unsubscribe"出席信息节以证实它,要么向联系人发送一个"subscribe"类型的出席信息节以否认它;这个步骤不影响订阅状态(详见 订阅状态Subscription States(第九章)), 但是让服务器知道它必须(MUST)不再发送订阅状态变更通知给用户(见第九章第四节).<br />
<br />
====情形 #2: 当订阅项是相互的时候取消====<br />
<br />
:在这种情形下, 用户有一个对联系人的出席信息的订阅并且联系人也有一个对用户的出席信息的订阅(换言之, 订阅是相互的).<br />
<br />
:1. 如果联系人想取消用户的订阅, 联系人必须(MUST)发送一个"unsubscribed"类型的出席信息节给用户:<br />
<br />
<source lang="xml"><br />
<presence to='user@example.com' type='unsubscribed'/><br />
</source><br />
<br />
:2. 作为结果, 联系人的服务器 (1) 必须(MUST)发送一个名册推送给这个联系人的所有已请求名册的可用资源, 包含关于这个用户的一个更新的名册条目,其'subscription'属性值设为"to"; (2) 必须(MUST)路由这个"unsubscribed"类型的出席信息节给用户(首先把'from'地址设为联系人的纯JID(<contact@example.org>)); 并且 (3) 应该(SHOULD)向这个用户的所有可用资源发送它从联系人的所有可用资源收到的不可用出席信息:<br />
<br />
<source lang="xml"><br />
<iq type='set'><br />
<query xmlns='jabber:iq:roster'><br />
<item<br />
jid='user@example.com'<br />
subscription='to'<br />
name='SomeUser'><br />
<group>SomeGroup</group><br />
</item><br />
</query><br />
</iq><br />
<presence<br />
from='contact@example.org'<br />
to='user@example.com'<br />
type='unsubscribed'/><br />
<presence<br />
from='contact@example.org/resource'<br />
to='user@example.com'<br />
type='unavailable'/><br />
</source><br />
<br />
:3. 接收到指向用户的"unsubscribed"类型出席信息节之后, 用户的服务器 (1) 必须(MUST)初始化一个名册推送给这个用户的所有已请求名册的可用资源, 包含关于这个联系人的更新的名册条目,其'subscription'属性值设为"from"(如果这个用户不可用或未曾请求名册, 用户的服务器必须(MUST)修改这个名册条目并且等下次用户请求名册的时候发送修改过的条目给它); 并且(2) 必须(MUST)递送这个"unsubscribed"状态变更通知给用户的所有可用资源; 并且 (3) 必须(MUST)向这个用户的所有可用资源递送这个不可用出席信息:<br />
<br />
<source lang="xml"><br />
<iq type='set'><br />
<query xmlns='jabber:iq:roster'><br />
<item<br />
jid='contact@example.org'<br />
subscription='from'<br />
name='MyContact'><br />
<group>MyBuddies</group><br />
</item><br />
</query><br />
</iq><br />
<presence<br />
from='contact@example.org'<br />
to='user@example.com'<br />
type='unsubscribed'/><br />
<presence<br />
from='contact@example.org/resource'<br />
to='user@example.com'<br />
type='unavailable'/><br />
</source><br />
<br />
:4. 接收到这个"unsubscribed"类型的出席信息节之后, 用户应该(SHOULD)承认收到了那个订阅状态通知,要么向联系人发送一个"unsubscribe"类型的出席信息节以证实它,要么向联系人发送一个"subscribe"类型的出席信息节以否认它; 这一步骤不影响订阅状态(详见 订阅状态Subscription States (第九章)), 但是让用户的服务器知道它必须(MUST)不再发送订阅状态变更通知给用户(见第九章第四节).<br />
<br />
:注意: 显然这不会使得名册条目从联系人的名册中移除, 并且联系人仍然有一个对用户的出席信息的订阅. 为了完全双向的取消一个相互的订阅并且从联系人的名册中完全移除这个名册条目, 联系人应该以subscription='remove'(定义在 移除一个名册条目并取消所有订阅项Removing a Roster Item and Cancelling All Subscriptions (第八章第六节))更新名册条目.<br />
<br />
===移除一个名册条目并取消所有订阅项===<br />
<br />
:因为在双向完整移除一个名册条目和取消所有订阅的过程中可能有很多步骤, 名册管理协议包含一个"shortcut"方法来做这件事. 无论当前的订阅状态是什么, 这个过程可以通过发送一个roster set(包含一个用于这个联系人的条目,其'subscription'属性值设为"remove")来初始化:<br />
<br />
<source lang="xml"><br />
<iq type='set' id='remove1'><br />
<query xmlns='jabber:iq:roster'><br />
<item<br />
jid='contact@example.org'<br />
subscription='remove'/><br />
</query><br />
</iq><br />
</source><br />
<br />
:当用户从他或她的名册中移除一个联系人(通过把'subscription'属性值设为"remove"), 用户的服务器 (1) 必须(MUST)自动取消用户和联系人之间的任何现存的出席信息订阅项(包括相应的'to'和'from'); (2) 必须(MUST)从用户的名册移除这个名册条目并且通知这个用户的所有已请求名册的可用资源这个名册条目被移除了; (3) 必须(MUST)通知初始化的资源移除成功了; 并且 (4) 应该(SHOULD)向联系人发送它从这个用户的所有可用资源收到的不可用出席信息:<br />
<br />
<source lang="xml"><br />
<presence<br />
from='user@example.com'<br />
to='contact@example.org'<br />
type='unsubscribe'/><br />
<presence<br />
from='user@example.com'<br />
to='contact@example.org'<br />
type='unsubscribed'/><br />
<iq type='set'><br />
<query xmlns='jabber:iq:roster'><br />
<item<br />
jid='contact@example.org'<br />
subscription='remove'/><br />
</query><br />
</iq><br />
<iq type='result' id='remove1'/><br />
<presence<br />
from='user@example.com/resource'<br />
to='contact@example.org'<br />
type='unavailable'/><br />
</source><br />
<br />
:收到"unsubscribe"类型的出席信息后, 联系人的服务器 (1) 必须(MUST)初始化一个名册推送给这个联系人的所有已请求名册的可用资源,包含关于这个用户的一个更新的名册条目,其'subscription'属性值设为"to"(如果这个联系人不可用或未曾请求名册, 联系人的服务器必须(MUST)修改这个名册条目并且等下次联系人请求名册的时候发送这个修改过的条目给它); 并且 (2) 也必须(MUST)递送这个"unsubscribe"状态变更通知给这个联系人的所有可用资源:<br />
<br />
<source lang="xml"><br />
<iq type='set'><br />
<query xmlns='jabber:iq:roster'><br />
<item<br />
jid='user@example.com'<br />
subscription='to'<br />
name='SomeUser'><br />
<group>SomeGroup</group><br />
</item><br />
</query><br />
</iq><br />
<presence<br />
from='user@example.com'<br />
to='contact@example.org'<br />
type='unsubscribe'/><br />
</source><br />
<br />
:收到这个"unsubscribed"类型的出席信息节之后, 联系人的服务器 (1) 必须(MUST)初始化一个名册推送给这个联系人的所有已请求名册的可用资源,包含一个关于这个用户的更新的名册条目,其'subscription'属性值设为"none"(如果这个联系人不可用或未曾请求名册, 联系人的服务器必须(MUST)修改名册条目并且等下次联系人请求名册的时候把修改过的条目发送给它); 并且 (2) 也必须(MUST)递送这个"unsubscribe"状态改变通知给这个联系人的所有可用资源:<br />
<br />
<source lang="xml"><br />
<iq type='set'><br />
<query xmlns='jabber:iq:roster'><br />
<item<br />
jid='user@example.com'<br />
subscription='none'<br />
name='SomeUser'><br />
<group>SomeGroup</group><br />
</item><br />
</query><br />
</iq><br />
<presence<br />
from='user@example.com'<br />
to='contact@example.org'<br />
type='unsubscribed'/><br />
</source><br />
<br />
:接收到指向联系人的"unavailable"出席信息节之后, 联系人的服务器必须(MUST)递送这个不可用出席信息给这个用户的所有可用资源:<br />
<br />
<source lang="xml"><br />
<presence<br />
from='user@example.com/resource'<br />
to='contact@example.org'<br />
type='unavailable'/><br />
</source><br />
<br />
:注意: 当用户从用户的名册中移除联系人的时候, 这个联系人的名册最后状态是用户仍然在联系人名册中但是订阅状态为"none"; 为了完全移除关于这个用户的名册条目, 联系人也需要发送一个名册移除请求.<br />
<br />
==订阅状态==<br />
<br />
:本章提供关于订阅状态以及和订阅相关的出席信息节(换言之,类型为"subscribe", "subscribed", "unsubscribe",和 "unsubscribed"的出席信息节)的服务器处理过程的详细信息.<br />
<br />
===已定义的状态===<br />
<br />
:有九种可能的订阅状态, 从用户的(不是联系人的)角度描述如下:<br />
<br />
:# "None" = 联系人和用户互相没有被对方订阅, 并且也都没有从对方那里请求一个订阅<br />
:# "None + Pending Out" = 联系人和用户互相没有被对方订阅, 用户已经向联系人发送了一个订阅请求但还没有收到回复<br />
:# "None + Pending In" = 联系人和用户互相没有被对方订阅, 联系人已经向用户发送了一个订阅请求但还没有收到回复(注意: 在这种状态下联系人的服务器不应该(SHOULD NOT)推送或递送名册条目, 但是应该(SHOULD)等待,直到联系人的订阅请求已经从用户那里得到批准)<br />
:# "None + Pending Out/In" = 联系人和用户互相没有被对方订阅, 联系人已经向用户发送了一个订阅请求但还没有收到回复, 用户已经向联系人发送了一个订阅请求但还没有收到回复<br />
:# "To" = 用户已订阅联系人(单向)<br />
:# "To + Pending In" = 用户已订阅联系人, 联系人已经向用户发送了一个订阅请求但还没有收到回复<br />
:# "From" = 联系人已订阅用户(单向)<br />
:# "From + Pending Out" = 联系人已订阅用户(单向), 用户已经向联系人发送了一个订阅请求但还没有收到回复<br />
:# "Both" = 用户和联系人互相被对方订阅了(双向)<br />
<br />
===出站出席信息订阅节的服务器处理过程===<br />
<br />
:出站出席信息订阅节使用户能管理他或她对联系人的出席信息的订阅(通过"subscribe"和"unsubscribe"类型), 并且管理联系人对用户的出席信息的访问(通过"subscribed"和"unsubscribed"类型).<br />
<br />
:因为用户的服务器和联系人的服务器有可能失去对于订阅状态的同步, 用户的服务器必须(MUST)毫无例外地路由所有"subscribe"或"unsubscribe"类型的出站出席信息节给联系人,使用户能在需要的时候重新同步他或她的对联系人的出席信息的订阅.<br />
<br />
:如果从用户的角度来看,一个"subscribed"或"unsubscribed"类型的出席信息节不会导致一个订阅状态的变更,用户的服务器不应该(SHOULD NOT)路由这个节到联系人那里,并且不能(MUST NOT)做出一个状态变更. 如果这个节导致一个订阅状态的变更, 用户的服务器必须(MUST)路由这个节到联系人,并且必须(MUST)做出相应的状态变更. 这些规则总结如下这些表.<br />
<br />
:表 1: 推荐的出站"subscribed"节的处理<br />
<br />
{|border="1" cellspacing="0" <br />
!当前状态 !! 路由? !! 新状态<br />
|-<br />
|"None" || 否 || 状态不变 <br />
|-<br />
|"None + Pending Out" || 否 || 状态不变 <br />
|-<br />
|"None + Pending In" || 是 || "From" <br />
|-<br />
|"None + Pending Out/In" || 是 || "From + Pending Out" <br />
|-<br />
|"To" || 否 || 状态不变 <br />
|-<br />
|"To + Pending In" || 是 || "Both" <br />
|-<br />
|"From" || 否 || 状态不变 <br />
|-<br />
|"From + Pending Out" || 否 || 状态不变 <br />
|-<br />
|"Both" || 否 || 状态不变 <br />
|}<br />
<br />
:表 2: 推荐的出站"unsubscribed"节处理<br />
<br />
{|border="1" cellspacing="0" <br />
!当前状态 !! 路由? !! 新状态 <br />
|-<br />
|"None" || 否 || 状态不变 <br />
|-<br />
|"None + Pending Out" || 否 || 状态不变 <br />
|-<br />
|"None + Pending In" || 是 || "None" <br />
|-<br />
|"None + Pending Out/In" || 是 || "None + Pending Out" <br />
|-<br />
|"To" || 否 || 状态不变 <br />
|-<br />
|"To + Pending In" || 是 || "To" <br />
|-<br />
|"From" || 是 || "None"<br />
|-<br />
|"From \+ Pending Out" || 是 || "None \+ Pending Out"<br />
|-<br />
|"Both" || 是 || "To"<br />
|}<br />
<br />
===入站出席信息订阅节的服务器处理过程===<br />
<br />
:入站出席信息订阅节从用户请求一个订阅相关的动作(通过"subscribe"类型), 通知用户由联系人所做的订阅状态相关的动作(通过"unsubscribe"类型),或使联系人能够管理用户对联系人的出席信息的访问(通过"subscribed"和"unsubscribed"类型).<br />
<br />
:当用户的服务器为用户从联系人那里接收到一个订阅请求(换言之, 一个"subscribe"类型的出席信息节), 如果用户未曾允许联系人访问用户的出席信息或者没有未决的入站订阅请求, 它必须(MUST)递送那个请求给用户;无论如何, 如果有一个未决的入站订阅请求, 用户的服务器不应该(SHOULD NOT)递送这个新的请求, 因为上一个订阅请求可能已经被记录下来了. 如果用户已经允许联系人访问用户的出席信息,用户的服务器应该(SHOULD)对一个从联系人发来的"subscribe"类型的入站出席信息节自动回复(通过代替用户向联系人发送一个"subscribed"类型的出席信息节); 这个规则使得联系人可以在需要的时候重新同步订阅状态. 这些规则总结如下面这些表.<br />
<br />
:表 3: 推荐的入站"subscribe"节处理<br />
<br />
{|border="1" cellspacing="0" <br />
!当前状态 !! 递送? !! 新状态 <br />
|-<br />
|"None" || 是 || "None + Pending In"<br />
|-<br />
|"None + Pending Out" || 是 || "None + Pending Out/In" <br />
|-<br />
|"None + Pending In" || 否 || 状态不变<br />
|-<br />
|"None + Pending Out/In" || 否 || 状态不变 <br />
|-<br />
|"To" || 是 || "To + Pending In" <br />
|-<br />
|"To + Pending In" || 否 || 状态不变 <br />
|-<br />
|"From" || 否 * || 状态不变 <br />
|-<br />
|"From + Pending Out" || 否 * || 状态不变 <br />
|-<br />
|"Both" || 否 * || 状态不变 <br />
|}<br />
<br />
:* 服务器应该(SHOULD)以"subscribed"节自动回复<br />
<br />
:当用户的服务器为用户从联系人那里收到一个"unsubscribe"类型的出席信息节, 如果从用户的角度看这个节会导致一个订阅状态变更,那么用户的服务器应该(SHOULD)代替用户自动应答(发送一个"unsubscribed"类型的出席信息节给联系人), 必须(MUST)递送这个"unsubscribe"节给用户,并且必须(MUST)改变状态. 如果不会导致订阅状态变更, 用户的服务器不应该(SHOULD NOT)递送这个节并且不能(MUST NOT)改变状态. 这些规则总结如下表.<br />
<br />
:表 4: 推荐的入站"unsubscribe"节处理<br />
<br />
{|border="1" cellspacing="0" <br />
!当前状态 !! 递送? !! 新状态 <br />
|-<br />
|"None" || 否 || 状态不变 <br />
|-<br />
|"None + Pending Out" || 否 || 状态不变 <br />
|-<br />
|"None + Pending In" || 是 * || "None" <br />
|-<br />
|"None + Pending Out/In" || 是 * || "None \+ Pending Out" <br />
|-<br />
|"To" || 否 || 状态不变 <br />
|-<br />
|"To + Pending In" || 是 * || "To" <br />
|-<br />
|"From" || 是 * || "None" <br />
|-<br />
|"From + Pending Out" || 是 * || "None \+ Pending Out <br />
|-<br />
|"Both" || 是 * || "To" <br />
|}<br />
<br />
:* 服务器应该(SHOULD)以"unsubscribed"节自动应答<br />
<br />
:当用户的服务器为用户从联系人那里收到一个"subscribed"类型的出席信息节, 如果没有一个为访问联系人的出席信息的未决的出站请求,它不能(MUST NOT)递送这个节给用户并且不能(MUST NOT)改变订阅状态. 如果有一个为了访问联系人的出席信息的未决的出站请求并且这个"subscribed"类型的入站出席信息请求会导致一个订阅状态的改变,用户的服务器必须(MUST)递送这个节给用户并且必须(MUST)改变订阅状态. 如果用户已经有授权可以访问联系人的出席信息, 这个"subscribed"类型的入站出席信息节不导致一个订阅状态的变更;从而用户的服务器不应该(SHOULD NOT)递送这个节给用户并且不能(MUST NOT)改变订阅状态. 这些规则总结如下表.<br />
<br />
:表 5: 推荐的入站"subscribed"节处理<br />
<br />
{|border="1" cellspacing="0" <br />
!当前状态 !! 递送? !! 新状态 <br />
|-<br />
|"None" || 否 || 状态不变 <br />
|-<br />
|"None + Pending Out" || 是 || "To" <br />
|-<br />
|"None + Pending In" || 否 || 状态不变 <br />
|-<br />
|"None + Pending Out/In" || 是 || "To \+ Pending In" <br />
|-<br />
|"To" || 否 || 状态不变 <br />
|-<br />
|"To + Pending In" || 否 || 状态不变 <br />
|-<br />
|"From" || 否 || 状态不变 <br />
|-<br />
|"From + Pending Out" || 是 || "Both" <br />
|-<br />
|"Both" || 否 || 状态不变 <br />
|}<br />
<br />
:当用户的服务器为用户从联系人那里收到了一个"unsubscribed"类型的出席信息节, 如果有一个为了访问联系人的出席信息的未决的出站请求或者用户当前已经有授权可以访问联系人的出席信息,它必须(MUST)递送这个节给用户并且必须(MUST)改变订阅状态. 否则, 用户的服务器不应该(SHOULD NOT)递送这个节并且不能(MUST NOT)改变订阅状态. 这些规则总结如下表.<br />
<br />
:表 6: 推荐的入站"unsubscribed"节处理<br />
<br />
{|border="1" cellspacing="0" <br />
!当前状态 !! 递送? !! 新状态 <br />
|-<br />
|"None" || 否 || 状态不变<br />
|-<br />
|"None + Pending Out" || 是 || "None" <br />
|-<br />
|"None + Pending In" || 否 || 状态不变 <br />
|-<br />
|"None + Pending Out/In" || 是 || "None \+ Pending In" <br />
|-<br />
|"To" || 是 || "None" <br />
|-<br />
|"To + Pending In" || 是 || "None \+ Pending In" <br />
|-<br />
|"From" || 否 || 状态不变 <br />
|-<br />
|"From + Pending Out" || 是 || "From" <br />
|-<br />
|"Both" || 是 || "From" <br />
|}<br />
<br />
===服务器递送和客户端承认订阅请求以及状态变更通知===<br />
<br />
:当一个服务器收到一个"subscribe"类型的入站出席信息节(换言之, 一个订阅请求)或"subscribed"类型,"unsubscribe"类型, 或"unsubscribed"类型(换言之, 一个订阅状态变更通知), 除了发送适当的名册推送(或当下次名册被一个可用资源请求时发送更新的名册), 它必须(MUST)递送这个请求或通知给预定的接收者至少一次. 一个服务器可以(MAY)要求接收者的回执以承认接收到了所有状态变更通知(并且必须(MUST)要求承认订阅请求的情形, 换言之,类型的出席信息节"subscribe"). 为了要求回执, 一个服务器应该(SHOULD)在每次接收者登陆的时候发送这个请求或通知给它, 直到这个接收者承认收到这个通知(通过证实"affirming"或禁止"denying"这个通知),如下表:<br />
<br />
:表 7: 订阅状态变更通知的承认<br />
<br />
{|border="1" cellspacing="0" <br />
!节类型 !! 接受 !! 禁止 <br />
|-<br />
|subscribe || subscribed || unsubscribed <br />
|-<br />
|subscribed || subscribe || unsubscribe <br />
|-<br />
|unsubscribe || unsubscribed || subscribed <br />
|-<br />
|unsubscribed || unsubscribe || subscribe <br />
|}<br />
<br />
:显然, 根据前述的订阅状态图表, 一些回执节将被路由到联系人并且导致状态的变更, 而其他的则不会. 无论如何, 任何这样的节必须(MUST)导致服务器不再发送订阅状态变更通知给用户.<br />
<br />
:因为在接收到roster set(其'subscription'属性值设为"remove"(见 移除一个名册条目并且取消所有订阅项 Removing a Roster Item and Cancelling All Subscriptions (第八章第六节)))之后,用户的服务器必须(MUST)自动生成"unsubscribe"和"unsubscribed"类型的出站出席信息节,服务器必须(MUST)把一个名册移除请求视为发送所有这些出席信息节,以决定是否继续向用户发送"subscribe"或"subscribed"类型的订阅状态变更通知.<br />
<br />
==屏蔽通信==<br />
<br />
:大多数即时消息系统已发现有必要实现一些方法来为用户屏蔽来自某些特定的其他用户的通信(这在[IMP-REQS]的第五章第一节第五小节, 第五章第一节第十五小节,第五章第三节第二小节, 和第五章第四节第十小节中也有要求). 在XMPP中这是由管理某人的隐私列表来实现的(使用'jabber:iq:privacy'名字空间).<br />
<br />
:服务器端的隐私列表使得以下用例能够完成:<br />
<br />
:* 接收某人的隐私列表.<br />
<br />
:* 增加, 移除, 和 编辑某人的隐私列表.<br />
<br />
:* 设置, 改变, 或 取消 激活的列表.<br />
<br />
:* 设置, 改变, 或 取消 缺省的列表 (换言之, 缺省激活的那个列表).<br />
<br />
:* 基于JID, group, 或 subscription 类型(或全局的) 允许或屏蔽消息.<br />
<br />
:* 允许或屏蔽入站出席信息通知,基于 JID, group, 或 subscription 类型 (或全局的).<br />
<br />
:* 允许或屏蔽出站出席信息通知,基于 JID, group, 或 subscription 类型 (或全局的).<br />
<br />
:* 允许或屏蔽 IQ 节, 基于 JID, group,或 subscription 类型(或全局的).<br />
<br />
:* 允许或屏蔽所有通信, 基于 JID, group, 或 subscription 类型(或全局的).<br />
<br />
:注意: 出席信息通知不包括出席信息订阅,只包括广播给那些已订阅了用户出席信息的实体的出席信息. 因而这包括没有'type'属性或只包含type='unavailable'的的出席信息节.<br />
<br />
===语法和语义===<br />
<br />
:一个用户可以(MAY)定义一个或更多的隐私列表, 它们由用户的服务器保存. 每个<list/>元素包含一个或多个格式为<item/>元素的规则, 并且每个<item/>元素使用属性来定义一个隐私规则类型, 一个适用于规则的特定值, 相应的动作, 和处理顺序相应的条目位置.<br />
<br />
:语法如下:<br />
<br />
<source lang="xml"><br />
<iq><br />
<query xmlns='jabber:iq:privacy'><br />
<list name='foo'><br />
<item<br />
type='[jid|group|subscription]'<br />
value='bar'<br />
action='[allow|deny]'<br />
order='unsignedInt'><br />
[<message/>]<br />
[<presence-in/>]<br />
[<presence-out/>]<br />
[<iq/>]<br />
</item><br />
</list><br />
</query><br />
</iq><br />
</source><br />
<br />
:如果类型是"jid", 那么'value'属性必须(MUST)包含一个合法的Jabber ID. JIDs 应该(SHOULD)满足以下顺序:<br />
<br />
:# <user@domain/resource> (仅为匹配的资源)<br />
:# <user@domain> (任何匹配的资源)<br />
:# <domain/resource> (仅匹配的资源)<br />
:# <domain> (匹配这个域本身, 正如任何 user@domain, domain/resource, 或 包含一个子域的地址)<br />
<br />
:如果类型为"group", 那么'value'属性应该(SHOULD)包含组在用户的名册中的名字. (如果一个客户端尝试更新, 新建, 或删除一个不在用户名册中的组的列表条目, 服务器应该(SHOULD)返回给客户端一个<item-not-found/>节错误.)<br />
<br />
:如果类型是"subscription", 那么'value'属性必须(MUST)是"both", "to", "from", 或"none" (定义在 名册语法和语义Roster Syntax and Semantics (第七章第一节))中的一个人, 在这里 "none" 包括对于用户来说完全未知和根本不在用户名册中的实体.<br />
<br />
:如果没有包含'type'属性, 这个规则提供 失败"fall-through" 情景.<br />
<br />
::'action'属性必须(MUST)被包含并且它的值必须(MUST)是 允许"allow"或 禁止"deny".<br />
<br />
::'order'属性必须(MUST)被包含并且它的值必须(MUST)是一个在列表的所有条目中具有唯一性的非负整数. (如果一个客户端尝试以一个非唯一的order值建立或更新一个列表, 服务器必须(MUST)返回给客户端一个<bad-request/>节错误.)<br />
<br />
::<item/>元素可以(MAY)包含一个或更多子元素,使得一个实体可以指明更多的细微控制包括屏蔽哪些种类的节(换言之, 不只是简单地屏蔽所有节). 允许的子元素包括:<br />
<br />
:* <message/> \-\- 屏蔽引入消息节<br />
:* <iq/> \-\- 屏蔽引入 IQ 节<br />
:* <presence-in/> \-\- 屏蔽引入出席信息通知<br />
:* <presence-out/> \-\- 屏蔽外出出席信息通知<br />
<br />
:在"jabber:iq:privacy'名字空间之内, 一个"set"类型的IQ节的<query/>子元素不能(MUST NOT)包含超过一个子元素(换言之, 这个节必须(MUST)只包含一个<active/>元素, 一个<default/>元素, 或一个<list/>元素); 如果一个发送中的实体违反了这个规则, 接收中的实体必须(MUST)返回一个 return a <bad-request/>节错误.<br />
<br />
:当一个客户端增加或更新一个隐私列表, <list/>元素应该(SHOULD)包含至少一个<item/>子元素; 当一个客户端移除一个隐私列表的时候, <list/>元素不能(MUST NOT)包含任何<item/>子元素.<br />
<br />
:当一个客户端更新一个隐私列表的时候, 它必须包含所有想得到的条目(换言之, 不是一个"delta").<br />
<br />
===商业规则===<br />
<br />
:# 如果有一个为某会话设置的激活的列表, 它只影响为其激活的那个会话, 并且只在那一个会话的持续期间有效; 服务器必须(MUST)只应用激活列表,并且不能(MUST NOT)应用缺省列表(换言之, 列表没有层次"layering").<br />
:# 缺省列表总体适用于用户, 并且如果没有为一个节指向的目标session/resource设置激活列表,或用户当前没有会话,它会被处理.<br />
:# 如果没有为一个会话设置激活列表(或用户当前没有会话), 并且没有缺省列表,那么所有节应该被(SHOULD BE)接受或由服务器代替用户做适当的处理(遵守 用于处理XML节的服务器规则 Server Rules for Handling XML Stanzas (第十一章)).<br />
:# 隐私列表必须(MUST)是第一个由服务器应用的递送规则, 替代 (1) 定义在 用于处理XML节的服务器规则Server Rules for Handling XML Stanzas (第十一章)的路由和递送规则, 以及 (2)和订阅相关的出席信息节的处理(和相应的名册推送的生成) 定义在 名册条目和出席信息订阅的集成Integration of Roster Items and Presence Subscriptions (第八章).<br />
:# 服务器处理隐私列表条目的顺序是很重要的. 列表条目必须(MUST)按照每个<item/>的'order'属性的整数值的升序来处理.<br />
:# 一旦节和一个隐私列表规则匹配, 服务器必须(MUST)按照这个规则适当地处理这个节,然后终止处理.<br />
:# 如果在一个列表中没有提供一个fall-through的条目, fall-through 动作被假定为 允许"allow".<br />
:# 如果一个用户为一个激活列表更新定义, 之后的基于那个激活列表的操作必须(MUST)使用更新的定义(为了那些激活列表正应用的所有资源).<br />
:# 如果在用户的会话期间,在激活的或缺省的列表中定义的名册条目中的订阅状态改变了,或名册组改变了,接下来基于那个列表的处理必须(MUST)考虑计入这个已改变的状态或组(对那个列表当前应用的所有资源).<br />
:# 当一个规则的定义修改了的时候, 服务器必须(MUST)发送一个类型为"set"的IQ节给所有已连接的资源, 包括一个只有一个<list/>子元素的<query/>元素, 其'name'属性设为已修改的隐私列表的名字. 这些 隐私列表推送("privacy list pushes")遵守和用于名册管理的名册推送("roster pushes")同样的语义 , 除了被推送给已连接的资源的列表名字本身(不是完整的列表定义或那个"delta"). 是否接受这个修改了的列表定义最终由接收中的资源来决定, 尽管如果这个列表正在应用于一个已连接的资源,它应该(SHOULD)这样做.<br />
:# 当一个已连接的资源尝试移除一个列表或指定一个新的缺省列表,而那个列表应用于一个已连接的资源而不是正在发送的资源, 服务器必须(MUST)返回一个<conflict/>错误给发送中的资源并且不能(MUST NOT)执行这个请求的改变.<br />
<br />
===接收某人的隐私列表===<br />
<br />
:例子: 客户端向服务器请求隐私列表的名字:<br />
<br />
<source lang="xml"><br />
<iq from='romeo@example.net/orchard' type='get' id='getlist1'><br />
<query xmlns='jabber:iq:privacy'/><br />
</iq><br />
</source><br />
<br />
:例子: 服务器发送隐私列表的名字给客户端, 激活列表和缺省列表放在前面:<br />
<br />
<source lang="xml"><br />
<iq type='result' id='getlist1' to='romeo@example.net/orchard'><br />
<query xmlns='jabber:iq:privacy'><br />
<active name='private'/><br />
<default name='public'/><br />
<list name='public'/><br />
<list name='private'/><br />
<list name='special'/><br />
</query><br />
</iq><br />
</source><br />
<br />
:例子: 客户端向服务器请求一个隐私列表:<br />
<br />
<source lang="xml"><br />
<iq from='romeo@example.net/orchard' type='get' id='getlist2'><br />
<query xmlns='jabber:iq:privacy'><br />
<list name='public'/><br />
</query><br />
</iq><br />
</source><br />
<br />
:例子: 服务器发送一个隐私列表给客户端:<br />
<br />
<source lang="xml"><br />
<iq type='result' id='getlist2' to='romeo@example.net/orchard'><br />
<query xmlns='jabber:iq:privacy'><br />
<list name='public'><br />
<item type='jid'<br />
value='tybalt@example.com'<br />
action='deny'<br />
order='1'/><br />
<item action='allow' order='2'/><br />
</list><br />
</query><br />
</iq><br />
</source><br />
<br />
:例子: 客户端向服务器请求另一个隐私列表:<br />
<br />
<source lang="xml"><br />
<iq from='romeo@example.net/orchard' type='get' id='getlist3'><br />
<query xmlns='jabber:iq:privacy'><br />
<list name='private'/><br />
</query><br />
</iq><br />
</source><br />
<br />
:例子: 服务器发送另一个隐私列表给客户端:<br />
<br />
<source lang="xml"><br />
<iq type='result' id='getlist3' to='romeo@example.net/orchard'><br />
<query xmlns='jabber:iq:privacy'><br />
<list name='private'><br />
<item type='subscription'<br />
value='both'<br />
action='allow'<br />
order='10'/><br />
<item action='deny' order='15'/><br />
</list><br />
</query><br />
</iq><br />
</source><br />
<br />
:例子: 客户端再向服务器请求另一个隐私列表:<br />
<br />
<source lang="xml"><br />
<iq from='romeo@example.net/orchard' type='get' id='getlist4'><br />
<query xmlns='jabber:iq:privacy'><br />
<list name='special'/><br />
</query><br />
</iq><br />
</source><br />
<br />
:例子: 服务器再发送另一个隐私列表给客户端:<br />
<br />
<source lang="xml"><br />
<iq type='result' id='getlist4' to='romeo@example.net/orchard'><br />
<query xmlns='jabber:iq:privacy'><br />
<list name='special'><br />
<item type='jid'<br />
value='juliet@example.com'<br />
action='allow'<br />
order='6'/><br />
<item type='jid'<br />
value='benvolio@example.org'<br />
action='allow'<br />
order='7'/><br />
<item type='jid'<br />
value='mercutio@example.org'<br />
action='allow'<br />
order='42'/><br />
<item action='deny' order='666'/><br />
</list><br />
</query><br />
</iq><br />
</source><br />
<br />
:在这个例子中, 用户有三个列表: (1) 'public', 它允许所有人的通信,除了一个指定的实体(这是缺省列表); (2) 'private', 它只允许和这个用户有双向订阅的联系人的通信(这是激活的列表); 还有 (3) 'special', 它只允许三个指定的实体通信.<br />
<br />
:如果用户尝试接收一个列表但是这个列表的名字不存在, 服务器必须(MUST)返回一个<item-not-found/>节错误给用户:<br />
<br />
:例子: 客户端尝试接收不存在的列表:<br />
<br />
<source lang="xml"><br />
<iq to='romeo@example.net/orchard' type='error' id='getlist5'><br />
<query xmlns='jabber:iq:privacy'><br />
<list name='The Empty Set'/><br />
</query><br />
<error type='cancel'><br />
<item-not-found<br />
xmlns='urn:ietf:params:xml:ns:xmpp-stanzas'/><br />
</error><br />
</iq><br />
</source><br />
<br />
:用户在一次只被允许接收一个列表. 如果用户尝试同一个请求中接收超过一个列表, 服务器必须(MUST)返回一个<bad request/>节错误给用户:<br />
<br />
:例子: 客户端尝试接收多于一个的列表:<br />
<br />
<source lang="xml"><br />
<iq to='romeo@example.net/orchard' type='error' id='getlist6'><br />
<query xmlns='jabber:iq:privacy'><br />
<list name='public'/><br />
<list name='private'/><br />
<list name='special'/><br />
</query><br />
<error type='modify'><br />
<bad-request<br />
xmlns='urn:ietf:params:xml:ns:xmpp-stanzas'/><br />
</error><br />
</iq><br />
</source><br />
<br />
===管理激活列表===<br />
<br />
:为了设置或改变服务器当前应用的激活列表, 用户必须(MUST)发送一个类型为"set"的IQ节,包含一个符合'jabber:iq:privacy'名字空间的<query/>元素,这个元素<query/>又包含一个空的<active/>子元素,而这个<active/>拥有一个'name'属性,'name'属性值则设为期望的列表名.<br />
<br />
:例子: 客户端请求激活列表变更:<br />
<br />
<source lang="xml"><br />
<iq from='romeo@example.net/orchard' type='set' id='active1'><br />
<query xmlns='jabber:iq:privacy'><br />
<active name='special'/><br />
</query><br />
</iq><br />
</source><br />
<br />
:服务器必须(MUST)在返回结果给客户端之前激活并应用这个已请求的列表.<br />
<br />
:例子: 服务器承认激活列表变更成功:<br />
<br />
<source lang="xml"><br />
<iq type='result' id='active1' to='romeo@example.net/orchard'/><br />
</source><br />
<br />
:如果用户尝试设置一个激活列表但是列表名不存在, 服务器必须(MUST)返回一个<item-not-found/>节错误给用户:<br />
<br />
:例子: 客户端尝试设置一个不存在的列表作为激活列表:<br />
<br />
<source lang="xml"><br />
<iq to='romeo@example.net/orchard' type='error' id='active2'><br />
<query xmlns='jabber:iq:privacy'><br />
<active name='The Empty Set'/><br />
</query><br />
<error type='cancel'><br />
<item-not-found<br />
xmlns='urn:ietf:params:xml:ns:xmpp-stanzas'/><br />
</error><br />
</iq><br />
</source><br />
<br />
:为了取消使用任何激活列表, 已连接的资源必须(MUST)发送一个空的<active/>元素,并且不带'name'属性.<br />
<br />
:例子: 客户端取消使用激活列表:<br />
<br />
<source lang="xml"><br />
<iq from='romeo@example.net/orchard' type='set' id='active3'><br />
<query xmlns='jabber:iq:privacy'><br />
<active/><br />
</query><br />
</iq><br />
</source><br />
<br />
:例子: 服务器承认取消任何激活列表成功:<br />
<br />
<source lang="xml"><br />
<iq type='result' id='active3' to='romeo@example.net/orchard'/><br />
</source><br />
<br />
===管理缺省列表===<br />
<br />
:为了改变它的缺省列表(它对用户来说是全局应用的, 不只是发送中的资源), 用户必须(MUST)发送一个类型为"set"的IQ节, 它包含一个符合'jabber:iq:privacy'名字空间的<query/>元素,这个<query/>元素包含一个空的<default/>子元素,这个<default/>子元素拥有一个'name'属性,这个'name'属性的值设为期望的列表名.<br />
<br />
:例子: 用户请求变更缺省列表:<br />
<br />
<source lang="xml"><br />
<iq from='romeo@example.net/orchard' type='set' id='default1'><br />
<query xmlns='jabber:iq:privacy'><br />
<default name='special'/><br />
</query><br />
</iq><br />
</source><br />
<br />
:例子: 服务器承认缺省列表变更成功:<br />
<br />
<source lang="xml"><br />
<iq type='result' id='default1' to='romeo@example.net/orchard'/><br />
</source><br />
<br />
:如果用户尝试变更一个缺省列表但是这个缺省列表正在由至少一个已连接的但不是当前发送中的这个资源使用着,服务器必须(MUST)返回一个<conflict/>节错误给发送中的资源:<br />
<br />
:例子: 客户端尝试改变一个缺省列表但是这个列表正在被另一个资源使用:<br />
<br />
<source lang="xml"><br />
<iq to='romeo@example.net/orchard' type='error' id='default1'><br />
<query xmlns='jabber:iq:privacy'><br />
<default name='special'/><br />
</query><br />
<error type='cancel'><br />
<conflict<br />
xmlns='urn:ietf:params:xml:ns:xmpp-stanzas'/><br />
</error><br />
</iq><br />
</source><br />
<br />
:如果用户尝试设置一个缺省列表但是这个列表的名字不存在, 服务器必须(MUST)返回一个<item-not-found/>节错误给用户:<br />
<br />
:例子: 客户端尝试设置一个不存在的列表作为缺省列表:<br />
<br />
<source lang="xml"><br />
<iq to='romeo@example.net/orchard' type='error' id='default1'><br />
<query xmlns='jabber:iq:privacy'><br />
<default name='The Empty Set'/><br />
</query><br />
<error type='cancel'><br />
<item-not-found<br />
xmlns='urn:ietf:params:xml:ns:xmpp-stanzas'/><br />
</error><br />
</iq><br />
</source><br />
<br />
:为了取消使用缺省列表(换言之, 任何时候都使用域的节路由规则), 用户必须(MUST)发送一个空的不带'name'属性的<default/>元素.<br />
<br />
:例子: 客户端取消使用缺省列表:<br />
<br />
<source lang="xml"><br />
<iq from='romeo@example.net/orchard' type='set' id='default2'><br />
<query xmlns='jabber:iq:privacy'><br />
<default/><br />
</query><br />
</iq><br />
</source><br />
<br />
:例子: 服务器承认成功地取消了任何缺省列表:<br />
<br />
<source lang="xml"><br />
<iq type='result' id='default2' to='romeo@example.net/orchard'/><br />
</source><br />
<br />
:如果一个已连接的资源尝试取消一个用户全局的缺省列表但是这个缺省列表正在应用于另一个已连接的资源,服务器必须(MUST)返回一个<conflict/>错误给发送中的资源:<br />
<br />
:例子: 客户端尝试取消一个缺省列表但是这个列表正在被另一个资源使用:<br />
<br />
<source lang="xml"><br />
<iq to='romeo@example.net/orchard' type='error' id='default3'><br />
<query xmlns='jabber:iq:privacy'><br />
<default/><br />
</query><br />
<error type='cancel'><br />
<conflict<br />
xmlns='urn:ietf:params:xml:ns:xmpp-stanzas'/><br />
</error><br />
</iq><br />
</source><br />
<br />
===编辑一个隐私列表===<br />
<br />
:为了编辑一个隐私列表, 用户必须(MUST)一个类型为"set"的IQ节,包含一个符合'jabber:iq:privacy'名字空间的<query/>元素,这个<query/>元素包含一个拥有一个<list/>子元素,这个<list/>子元素拥有一个'name'属性,这个'name'属性的值设为用户想编辑的列表名. 这个<list/>元素必须(MUST)包含一个或多个<item/>元素, 它们包含了列表中的所有元素以指明用户期望的对列表的变更(不是the "delta").<br />
<br />
:例子: 客户端编辑隐私列表:<br />
<br />
<source lang="xml"><br />
<iq from='romeo@example.net/orchard' type='set' id='edit1'><br />
<query xmlns='jabber:iq:privacy'><br />
<list name='public'><br />
<item type='jid'<br />
value='tybalt@example.com'<br />
action='deny'<br />
order='3'/><br />
<item type='jid'<br />
value='paris@example.org'<br />
action='deny'<br />
order='5'/><br />
<item action='allow' order='68'/><br />
</list><br />
</query><br />
</iq><br />
</source><br />
<br />
:例子: 服务器承认列表编辑成功:<br />
<br />
<source lang="xml"><br />
<iq type='result' id='edit1' to='romeo@example.net/orchard'/><br />
</source><br />
<br />
:注意: 任何给定的条目的'order'属性值不是固定的. 因而在前述的例子中如果用户想在"tybalt@example.com"条目和"paris@example.org"条目之间增加4个条目, 用户的客户端必须(MUST)在向服务器提交列表之前对相关的条目重新编号.<br />
<br />
:服务器必须(MUST)现在发送一个 隐私列表推送"privacy list push"给所有已连接的资源:<br />
<br />
:例子: 基于列表编辑的隐私列表推送:<br />
<br />
<source lang="xml"><br />
<iq to='romeo@example.net/orchard' type='set' id='push1'><br />
<query xmlns='jabber:iq:privacy'><br />
<list name='public'/><br />
</query><br />
</iq><br />
<iq to='romeo@example.net/home' type='set' id='push2'><br />
<query xmlns='jabber:iq:privacy'><br />
<list name='public'/><br />
</query><br />
</iq><br />
</source><br />
<br />
:按照定义在[XMPP-CORE|XMPP文档列表/XMPP正式RFC标准/RFC3920]的IQ节语义, 每个已连接的子元素必须(MUST)返回一个如下的 IQ result 给服务器:<br />
<br />
:例子: 承认收到一个隐私列表推送:<br />
<br />
<source lang="xml"><br />
<iq from='romeo@example.net/orchard'<br />
type='result'<br />
id='push1'/><br />
<iq from='romeo@example.net/home'<br />
type='result'<br />
id='push2'/><br />
</source><br />
<br />
===增加一个新的隐私列表===<br />
<br />
:增加一个新的列表和编辑一个现有的列表使用的协议是相同的. 如果列表名和现有的列表名吻合, 这个增加新列表的请求将覆写那个旧的列表. 正如编辑列表一样, 服务器也必须(MUST)发送一个 隐私列表推送"privacy list push" 给所有已连接的资源.<br />
<br />
===移除一个隐私列表===<br />
<br />
:为了移除一个隐私列表, 用户必须(MUST)发送一个类型为"set"的IQ节,包含一个符合'jabber:iq:privacy'名字空间的<query/>元素,这个<query/>元素包含一个空的<list/>子元素,这个<list/>子元素拥有一个'name'属性,这个'name'属性的值设为用户想移除的列表名.<br />
<br />
:例子: 客户端移除一个隐私列表:<br />
<br />
<source lang="xml"><br />
<iq from='romeo@example.net/orchard' type='set' id='remove1'><br />
<query xmlns='jabber:iq:privacy'><br />
<list name='private'/><br />
</query><br />
</iq><br />
</source><br />
<br />
:例子: 服务器承认成功地移除列表:<br />
<br />
<source lang="xml"><br />
<iq type='result' id='remove1' to='romeo@example.net/orchard'/><br />
</source><br />
<br />
:如果一个用户尝试移除一个列表而这个列表正在被应用于至少一个和发送中的资源不同的已连接的资源, 服务器必须(MUST)返回一个<conflict/>节错误给用户; 换言之, 用户在尝试移除它之前必须(MUST)先设置另一个列表成为激活或缺省列表. 如果用户尝试移除一个列表但是列表名字不存在, 服务器必须(MUST)返回一个<item-not-found/>节错误给用户. 如果用户尝试在同一个请求中移除超过一个的列表, 服务器必须(MUST)反回一个<bad request/>节错误给用户.<br />
<br />
===屏蔽消息===<br />
<br />
:服务器端的隐私列表使得一个用户可以基于实体的JID,名册组,或订阅状态(或全局地)来屏蔽从其他实体引入的消息. 以下例子阐明这个协议. (注意: 为了精简, "result"类型的IQ节没有在以下例子中显示, 隐私列表推送也没有显示.)<br />
<br />
:例子: 基于JID的用户屏蔽:<br />
<br />
<source lang="xml"><br />
<iq from='romeo@example.net/orchard' type='set' id='msg1'><br />
<query xmlns='jabber:iq:privacy'><br />
<list name='message-jid-example'><br />
<item type='jid'<br />
value='tybalt@example.com'<br />
action='deny'<br />
order='3'><br />
<message/><br />
</item><br />
</list><br />
</query><br />
</iq><br />
</source><br />
<br />
:作为建立和应用前述列表的结果, 用户将不会接收到从特定JID发来的消息.<br />
<br />
:例子: 基于名册组的用户屏蔽:<br />
<br />
<source lang="xml"><br />
<iq from='romeo@example.net/orchard' type='set' id='msg2'><br />
<query xmlns='jabber:iq:privacy'><br />
<list name='message-group-example'><br />
<item type='group'<br />
value='Enemies'<br />
action='deny'<br />
order='4'><br />
<message/><br />
</item><br />
</list><br />
</query><br />
</iq><br />
</source><br />
<br />
:作为建立和应用前述列表的结果, 用户将不会收到从指定名册组中的任何实体发来的消息.<br />
<br />
:例子: 基于订阅状态的用户屏蔽:<br />
<br />
<source lang="xml"><br />
<iq from='romeo@example.net/orchard' type='set' id='msg3'><br />
<query xmlns='jabber:iq:privacy'><br />
<list name='message-sub-example'><br />
<item type='subscription'<br />
value='none'<br />
action='deny'<br />
order='5'><br />
<message/><br />
</item><br />
</list><br />
</query><br />
</iq><br />
</source><br />
<br />
:作为建立和应用前述列表的结果, 用户将不会收到从任何指定订阅状态的实体发来的消息.<br />
<br />
:例子: 全局的用户屏蔽:<br />
<br />
<source lang="xml"><br />
<iq from='romeo@example.net/orchard' type='set' id='msg4'><br />
<query xmlns='jabber:iq:privacy'><br />
<list name='message-global-example'><br />
<item action='deny' order='6'><br />
<message/><br />
</item><br />
</list><br />
</query><br />
</iq><br />
</source><br />
<br />
:作为建立和应用前述列表的结果, 用户将不会收到从任何其他用户发来的消息.<br />
<br />
===屏蔽入站出席信息通知===<br />
<br />
:服务器端的隐私列表使得用户可以基于实体的JID,名册组,或订阅状态(或全局地)屏蔽来自其他实体的入站出席信息通知. 以下例子阐明了这个协议.<br />
<br />
:注意: 出席信息通知不包括出席信息订阅,只是把出席信息广播给当前已订阅某个联系人的出席信息的用户. 所以它只包括没有'type'属性的或type='unavailable'的出席信息节.<br />
<br />
:例子: 基于JID的用户屏蔽:<br />
<br />
<source lang="xml"><br />
<iq from='romeo@example.net/orchard' type='set' id='presin1'><br />
<query xmlns='jabber:iq:privacy'><br />
<list name='presin-jid-example'><br />
<item type='jid'<br />
value='tybalt@example.com'<br />
action='deny'<br />
order='7'><br />
<presence-in/><br />
</item><br />
</list><br />
</query><br />
</iq><br />
</source><br />
<br />
:作为建立和应用前述列表的结果, 用户将不会收到从指定JID发来的出席信息通知.<br />
<br />
:例子: 基于名册组的用户屏蔽:<br />
<br />
<source lang="xml"><br />
<iq from='romeo@example.net/orchard' type='set' id='presin2'><br />
<query xmlns='jabber:iq:privacy'><br />
<list name='presin-group-example'><br />
<item type='group'<br />
value='Enemies'<br />
action='deny'<br />
order='8'><br />
<presence-in/><br />
</item><br />
</list><br />
</query><br />
</iq><br />
</source><br />
<br />
:作为建立和应用前述列表的结果, 用户将不会从指定的名册组中的任何实体收到出席信息通知.<br />
<br />
:例子: 基于订阅状态的用户屏蔽:<br />
<br />
<source lang="xml"><br />
<iq from='romeo@example.net/orchard' type='set' id='presin3'><br />
<query xmlns='jabber:iq:privacy'><br />
<list name='presin-sub-example'><br />
<item type='subscription'<br />
value='to'<br />
action='deny'<br />
order='9'><br />
<presence-in/><br />
</item><br />
</list><br />
</query><br />
</iq><br />
</source><br />
<br />
:作为建立和应用前述列表的结果, 用户将不会从指定订阅状态的任何实体收到出席信息通知.<br />
<br />
:例子: 全局的用户屏蔽:<br />
<br />
<source lang="xml"><br />
<iq from='romeo@example.net/orchard' type='set' id='presin4'><br />
<query xmlns='jabber:iq:privacy'><br />
<list name='presin-global-example'><br />
<item action='deny' order='11'><br />
<presence-in/><br />
</item><br />
</list><br />
</query><br />
</iq><br />
</source><br />
<br />
:作为建立和应用前述列表的结果, 用户将不会从任何其他实体收到出席信息通知.<br />
<br />
===屏蔽出站出席信息通知===<br />
<br />
:服务器端的隐私列表使用户能够屏蔽发出到其他实体的出席信息通知(基于实体的JID, 名册组, 或订阅状态 (或全局的)). 以下例子阐明了这个协议.<br />
<br />
:注意: 出席信息通知不包括出席信息订阅,只把出席信息广播给已订阅了用户的出席信息的联系人.所以 只包括没有'type'属性或type='unavailable'的出席信息节.<br />
<br />
:例子: 基于JID的用户屏蔽:<br />
<br />
<source lang="xml"><br />
<iq from='romeo@example.net/orchard' type='set' id='presout1'><br />
<query xmlns='jabber:iq:privacy'><br />
<list name='presout-jid-example'><br />
<item type='jid'<br />
value='tybalt@example.com'<br />
action='deny'<br />
order='13'><br />
<presence-out/><br />
</item><br />
</list><br />
</query><br />
</iq><br />
</source><br />
<br />
:作为建立和应用前述列表的结果, 用户将不会给指定JID发送出席信息通知.<br />
<br />
:例子: 基于名册组的用户屏蔽:<br />
<br />
<source lang="xml"><br />
<iq from='romeo@example.net/orchard' type='set' id='presout2'><br />
<query xmlns='jabber:iq:privacy'><br />
<list name='presout-group-example'><br />
<item type='group'<br />
value='Enemies'<br />
action='deny'<br />
order='15'><br />
<presence-out/><br />
</item><br />
</list><br />
</query><br />
</iq><br />
</source><br />
<br />
:作为建立和应用前述列表的结果, 用户将不会向指定名册组的任何实体发送出席信息通知.<br />
<br />
:例子: 基于订阅状态的用户屏蔽:<br />
<br />
<source lang="xml"><br />
<iq from='romeo@example.net/orchard' type='set' id='presout3'><br />
<query xmlns='jabber:iq:privacy'><br />
<list name='presout-sub-example'><br />
<item type='subscription'<br />
value='from'<br />
action='deny'<br />
order='17'><br />
<presence-out/><br />
</item><br />
</list><br />
</query><br />
</iq><br />
</source><br />
<br />
:作为建立和应用前述列表的结果, 用户将不会向指定订阅状态的任何实体发送出席信息通知.<br />
<br />
:例子: 全局的用户屏蔽:<br />
<br />
<source lang="xml"><br />
<iq from='romeo@example.net/orchard' type='set' id='presout4'><br />
<query xmlns='jabber:iq:privacy'><br />
<list name='presout-global-example'><br />
<item action='deny' order='23'><br />
<presence-out/><br />
</item><br />
</list><br />
</query><br />
</iq><br />
</source><br />
<br />
:作为建立和应用前述列表的结果, 用户将不会向任何其他用户发送出席信息通知.<br />
<br />
===屏蔽IQ节===<br />
<br />
:服务器端的隐私列表使用户能够屏蔽从其他实体进来的IQ节(基于实体的JID,名册组, 或订阅状态(或全局地)). 以下例子阐明了这个协议.<br />
<br />
:例子: 基于JID的用户屏蔽:<br />
<br />
<source lang="xml"><br />
<iq from='romeo@example.net/orchard' type='set' id='iq1'><br />
<query xmlns='jabber:iq:privacy'><br />
<list name='iq-jid-example'><br />
<item type='jid'<br />
value='tybalt@example.com'<br />
action='deny'<br />
order='29'><br />
<iq/><br />
</item><br />
</list><br />
</query><br />
</iq><br />
</source><br />
<br />
:作为建立和应用这个列表的结果, 用户将不会收到从指定JID发来的IQ节.<br />
<br />
:例子: 基于名册组的用户屏蔽:<br />
<br />
<source lang="xml"><br />
<iq from='romeo@example.net/orchard' type='set' id='iq2'><br />
<query xmlns='jabber:iq:privacy'><br />
<list name='iq-group-example'><br />
<item type='group'<br />
value='Enemies'<br />
action='deny'<br />
order='31'><br />
<iq/><br />
</item><br />
</list><br />
</query><br />
</iq><br />
</source><br />
<br />
:作为建立和应用前述列表的结果, 用户将不会收到从指定名册组的任何实体发来的IQ节.<br />
<br />
:例子: 基于订阅状态的用户屏蔽:<br />
<br />
<source lang="xml"><br />
<iq from='romeo@example.net/orchard' type='set' id='iq3'><br />
<query xmlns='jabber:iq:privacy'><br />
<list name='iq-sub-example'><br />
<item type='subscription'<br />
value='none'<br />
action='deny'<br />
order='17'><br />
<iq/><br />
</item><br />
</list><br />
</query><br />
</iq><br />
</source><br />
<br />
:作为建立和应用前述列表的结果, 用户将不会收到从指定订阅状态的任何实体发来的IQ节.<br />
<br />
:例子: 全局的用户屏蔽:<br />
<br />
<source lang="xml"><br />
<iq from='romeo@example.net/orchard' type='set' id='iq4'><br />
<query xmlns='jabber:iq:privacy'><br />
<list name='iq-global-example'><br />
<item action='deny' order='1'><br />
<iq/><br />
</item><br />
</list><br />
</query><br />
</iq><br />
</source><br />
<br />
:作为建立和应用前述列表的结果, 用户将不会收到从任何其他用户发来的IQ节.<br />
<br />
===屏蔽所有通信===<br />
<br />
:服务器端的隐私列表使用户能够基于其他实体的JID,名册组,或订阅状态(或全局的)屏蔽所有进来和出去的节. 注意那部包括订阅相关的出席信息节, 它们被排除在外 (定义在 屏蔽入站出席信息通知Blocking Inbound Presence Notifications (第十章第十节)). 以下例子阐明了这个协议.<br />
<br />
:例子: 基于JID的用户屏蔽:<br />
<br />
<source lang="xml"><br />
<iq from='romeo@example.net/orchard' type='set' id='all1'><br />
<query xmlns='jabber:iq:privacy'><br />
<list name='all-jid-example'><br />
<item type='jid'<br />
value='tybalt@example.com'<br />
action='deny'<br />
order='23'/><br />
</list><br />
</query><br />
</iq><br />
</source><br />
<br />
:作为建立和应用这个列表的结果, 用户将不会收到和发送任何通信给指定JID.<br />
<br />
:例子: 基于名册组的用户屏蔽:<br />
<br />
<source lang="xml"><br />
<iq from='romeo@example.net/orchard' type='set' id='all2'><br />
<query xmlns='jabber:iq:privacy'><br />
<list name='all-group-example'><br />
<item type='group'<br />
value='Enemies'<br />
action='deny'<br />
order='13'/><br />
</list><br />
</query><br />
</iq><br />
</source><br />
<br />
:作为建立和应用前述列表的结果, 用户将不会收到和发送和指定名册组的任何实体的通信.<br />
<br />
:例子: 基于订阅状态的用户屏蔽:<br />
<br />
<source lang="xml"><br />
<iq from='romeo@example.net/orchard' type='set' id='all3'><br />
<query xmlns='jabber:iq:privacy'><br />
<list name='all-sub-example'><br />
<item type='subscription'<br />
value='none'<br />
action='deny'<br />
order='11'/><br />
</list><br />
</query><br />
</iq><br />
</source><br />
<br />
:作为建立和应用前述列表的结果, 用户将不会收到和发送和指定订阅状态的任何实体的通信.<br />
<br />
:例子: 全局的用户屏蔽:<br />
<br />
<source lang="xml"><br />
<iq from='romeo@example.net/orchard' type='set' id='all4'><br />
<query xmlns='jabber:iq:privacy'><br />
<list name='all-global-example'><br />
<item action='deny' order='7'/><br />
</list><br />
</query><br />
</iq><br />
</source><br />
<br />
:作为建立和应用前述列表的结果, 用户将不会收到和发送和任何其他用户的通信.<br />
<br />
===已被屏蔽的实体尝试和用户通信===<br />
<br />
:如果一个已被屏蔽的实体尝试发送消息或出席信息给用户, 用户的服务器应该(SHOULD)安静的丢掉这个节并且不能(MUST NOT)返回一个错误给发送的实体.<br />
<br />
:如果一个已被屏蔽的实体尝试发送一个类型为"get"或"set"的IQ节给用户, 用户的服务器必须(MUST)给发送的实体一个<service-unavailable/>节错误, 因为这是一个客户端不理解IQ get或set的名字空间的时候所发送的标准错误码. 其他类型的IQ节应该(SHOULD)被服务器安静的丢弃.<br />
<br />
:例子: 已被屏蔽的实体尝试发送 IQ get:<br />
<br />
<source lang="xml"><br />
<iq type='get'<br />
to='romeo@example.net'<br />
from='tybalt@example.com/pda'<br />
id='probing1'><br />
<query xmlns='jabber:iq:version'/><br />
</iq><br />
</source><br />
<br />
:例子: 服务器返回一个错误给已被屏蔽的实体:<br />
<br />
<source lang="xml"><br />
<iq type='error'<br />
from='romeo@example.net'<br />
to='tybalt@example.com/pda'<br />
id='probing1'><br />
<query xmlns='jabber:iq:version'/><br />
<error type='cancel'><br />
<service-unavailable<br />
xmlns='urn:ietf:params:xml:ns:xmpp-stanzas'/><br />
</error><br />
</iq><br />
</source><br />
<br />
===高级启发===<br />
<br />
:当建立一个高级隐私启发的表达式的时候, 客户端应该(SHOULD)使用尽可能简单的表达式.<br />
<br />
:例如, 启发 "屏蔽不在我名册中的任何用户的通信" 可以使用以下任何一种方式来构造:<br />
<br />
:* 允许任何来自我的名册中的JID的通信 (换言之, 列出每个JID成为单独的列表条目), 但是屏蔽和其他任何人的通信<br />
<br />
:* 允许任何来自我的名册的某个组中的用户的通信(换言之, 列出每个组作为单独的条目), 但是屏蔽和任何其他人的通信<br />
<br />
:* 允许任何我的他(她)之间的订阅状态为'both'或'to'或'from'的用户的通信(换言之, 单独列出每个订阅状态值), 但是屏蔽和任何其他人的通信<br />
<br />
:* 屏蔽和任何订阅状态为'none'的用户的通信<br />
<br />
:最后一个表达式是最简单的并且应该(SHOULD)被使用; 这种情形下将被发送的XML如下:<br />
<br />
<source lang="xml"><br />
<iq type='set' id='heuristic1'><br />
<query xmlns='jabber:iq:privacy'><br />
<list name='heuristic-example'><br />
<item type='subscription'<br />
value='none'<br />
action='deny'<br />
order='437'/><br />
</list><br />
</query><br />
</iq><br />
</source><br />
<br />
==服务器处理XML节的规则==<br />
<br />
:用于服务器的基本路由和递送规则定义在[XMPP-CORE|XMPP文档列表/XMPP正式RFC标准/RFC3920]中. 本章定义附加的用于XMPP兼容的即时消息和出席信息服务器规则.<br />
<br />
===入站节===<br />
<br />
:如果一个入站的节的'to'属性的JID中的域标识符部分的主机名和服务器自身的主机名相同并且'to'属性的JID的格式是<user@example.com>或<user@example.com/resource>, 服务器必须(MUST)首先强制应用任何隐私列表(第十章),然后服从以下定义的规则:<br />
<br />
:# 如果JID的格式是<user@domain/resource>并且有一个可用的资源和这个全JID吻合, 接受这得服务器必须(MUST)递送这个节给那个资源.<br />
:# 然后如果JID的格式是<user@domain>或格式是<user@domain/resource>,并且和用户相关的帐号不存在, 接收者的服务器 (a) 如果它是一个出席信息节,应该(SHOULD) 安静的忽略这个节(换言之,既不递送它也不返回一个错误), (b) 如果它是一个IQ节,必须(MUST)返回一个<service-unavailable/>节错误给发送者, 并且 (c) 如果它是一个消息节,应该(SHOULD)返回一个<service-unavailable/>节错误给发送者.<br />
:# 然后如果JID的格式是<user@domain/resource>并且没有可用的资源和它的全JID匹配, 接收者的服务器 (a) 如果它是一个出席信息节,应该(SHOULD)安静地忽略这个节(换言之, 既不递送它也不返回一个错误), (b) 如果它是一个IQ节,必须(MUST)返回一个<service-unavailable/>节错误给发送者, 并且 (c) 如果它是一个消息节,应该(SHOULD)把这个节视为发往<user@domain>.<br />
:# 然后如果JID的格式是<user@domain>并且这个用户至少有一个可用的资源, 接收者的服务器必须(MUST)遵守以下规则:<br />
:## 对于消息节, 服务器应该(SHOULD)递送这个节给高优先级的可用资源(如果这个资源没有提供<priority/>元素的值, 服务器应该(SHOULD)认为它提供的值为零). 如果两个或更多的可用资源有相同的优先级, 服务器可以(MAY)使用一些其他的规则(例如, 最近的连接时间, 最近的活动时间, 或由一些<show/>值的层次所定义的最高的可用性) 来从它们中间选择,或可以(MAY)递送这个消息到所有这些资源. 无论如何, 服务器不能(MUST NOT)这个节到一个优先级为负数的可用资源; 如果唯一的一个可用资源的优先级是负数, 服务器应该(SHOULD)当成没有可用资源一样处理这个消息(定义在后面). 另外, 服务器不能(MUST NOT)重写'to'属性(换言之, 它必须(MUST)让它保持<user@domain>而不是改成<user@domain/resource>).<br />
:## 对于类型不是"probe"的出席信息节, 服务器必须(MUST)递送这个节给所有可用的资源;对于出席信息调查, 服务器应该(SHOULD)基于定义在 出席信息调查Presence Probes (第五章第一节第三小节)的规则来应答. 另外, 服务器不能(MUST NOT)重写'to'属性(换言之, 它必须(MUST)保持<user@domain>而不是改为<user@domain/resource>).<br />
:## 对于IQ节, 服务器本身必须(MUST)代替用户应答一个IQ result或一个IQ error, 并且不能(MUST NOT)递送这个IQ节给任何可用的资源. 具体来说, 如果合格的名字空间的语义定义了一个服务器可以提供的应答, 服务器必须(MUST)代替用户应答这个节; 如果没有, 服务器必须(MUST)应答一个<service-unavailable/>节错误.<br />
:# 然后如果JID的格式为<user@domain>并且没有这个用户的可用资源, 这个节如何处理依赖于节的类型:<br />
:## 对于类型为"subscribe", "subscribed", "unsubscribe", 和"unsubscribed"的出席信息节, 服务器必须(MUST)维持这个节的一个记并且至少递送这个节一次(也就是, 当这个用户下次建立一个可用的资源的时候); 另外, 服务器必须(MUST)递送类型为"subscribe"的出席信息节直到用户批准或拒绝这个订阅请求为止(参见 出席信息订阅Presence Subscriptions (第五章第一节第六小节)).<br />
:## 对于所有其他的出席信息节, 服务器应该(SHOULD)安静的忽略这个节,既不存储它用于以后递送也不代替用户应答它.<br />
:## 对于消息节, 服务器可以(MAY)选择代替用户存储这个节并且当用户下次可用的时候递送给他, 或通过一些其他的手段转发这个消息给用户(例如, 给用户的邮箱). 无论如何, 如果离线消息存储或消息转发没有激活, 服务器必须(MUST)返回发送者一个<service-unavailable/>节错误. (注意:离线信息存储和消息转发没有定义在 XMPP, 因为严格来说它们是实现和服务提供的问题.)<br />
:## 对于IQ节, 服务器本身必须(MUST)代替用户应答一个IQ result或一个IQ error. 具体来说,如果合法的名字空间的语义定义了一个服务器可以提供的应答, 服务器必须(MUST)代替用户应答这个节; 如果没有, 服务器必须(MUST)应答一个<service-unavailable/>节错误.<br />
<br />
===出站节===<br />
<br />
:如果出站节的'to'属性的地址的域标识符部分的主机名和服务器自身的一个主机名吻合, 服务器必须(MUST) 根据 入站节Inbound Stanzas(第十一章第一节)的规则递送这个节给一个本地实体.<br />
<br />
:如果出站节的'to'属性的地址的域标识符部分的主机名不和服务器自身的一个主机名吻合, 服务器必须(MUST)尝试路由这个节到外部域. 推荐的动作顺序定义如下:<br />
<br />
:# 首先尝试用一个"xmpp-server"服务和"tcp"协议的[SRV]服务解析这个外部的主机名,结果得到的资源记录格式如"_xmpp-server._tcp.example.com.", 定义在[XMPP-CORE|XMPP文档列表/XMPP正式RFC标准/RFC3920].<br />
:# 如果"xmpp-server"地址记录解析失败, 尝试解析"_im"或"_pres"[SRV]服务(定义在[IMP-SRV]), 使用"_im"服务用语<message/>节,使用"_pres"服务用语<presence/>节(如何处理<iq/>节取决于具体实现). 这样得到的结果是一个或多个格式为"_im.<proto>.example.com."或 "_pres.<proto>.example.com."的记录, 这里"<proto>"是一个注册在 即时消息SRV协议标签注册表Instant Messaging SRV Protocol Label registry中的一个标签,或者是 出席信息SRV协议标签注册表Presence SRV Protocol Label registry中的标签: 要么是"_xmpp",用于XMPP-aware的域,要么是一些 IANA注册的标签IANA-registered label (例如,"_simple") 用于 non-XMPP-aware 的域.<br />
:# 如果这两种SRV地址记录解析都失败了, 尝试执行一个通用的 IPv4/IPv6 地址记录解析来决定IP地址,使用"xmpp-server"端口号5269(已在IANA注册, 定义在[XMPP-CORE|XMPP文档列表/XMPP正式RFC标准/RFC3920]).<br />
<br />
:强烈鼓励部署服务器的管理员们保持 _im._xmpp, _pres._xmpp, 和 _xmpp._tcp SRV 记录正确同步, 因为不同的实现可能在"xmpp-server"查找之前执行"_im"和"_pres"查找.<br />
<br />
==即时消息和出席信息兼容性需求==<br />
<br />
:本章总结了即时消息和出席信息服务器和客户端为了保证兼容的实现而必须(MUST)支持的部分XMPP协议. 所有这些应用必须(MUST)遵守定义在[XMPP-CORE|XMPP文档列表/XMPP正式RFC标准/RFC3920]的要求. 本章的文字定义了附加的用于即时消息和出席信息的兼容性需求; 注意定义在这里的要求补充而不是替代核心需求. 也要注意一个服务器或客户端可以(MAY)仅支持出席信息或即时消息, 如果只想支持出席信息服务或即时消息服务,可以不必同时支持两个.<br />
<br />
===服务器===<br />
<br />
:除了核心服务器兼容需求之外, 一个即时消息和出席信息服务器必须(MUST)还要支持以下协议:<br />
<br />
:* 定义在本文中的所有服务器相关的即时消息和出席信息语法和语义, 包括代替客户端广播出席信息, 出席信息订阅, 名册存储和处理, 隐私列表, 以及 IM-specific 路由和递送规则<br />
<br />
===客户端===<br />
<br />
:除了核心的客户端兼容性需求之外, 一个即时消息和出席信息客户端还必须(MUST)支持以下协议:<br />
<br />
:* 生成和处理由XML规划定义的XML节的IM-specific语义, 包括消息和出席信息节以及它们的子元素的的'type'属性<br />
<br />
:* 所有本文定义的客户端相关的即时消息语法和语义, 包括出席信息订阅, 名册管理, 和隐私列表<br />
<br />
:* 端到端的对象加密(定义在 XMPP中的端到端对象加密End-to-End Object Encryption in the Extensible Messaging and Presence Protocol (XMPP) [XMPP-E2E])<br />
<br />
:一个客户端也必须(MUST)处理编码为"im:" URIs的地址(定义在[CPIM]), 并且可以(MAY)移除"im:"scheme并把地址解析委托给服务器(定义在 出站节Outbound Stanzas(第十一章第二节).<br />
<br />
==国际化事项==<br />
<br />
:关于国际化的考虑, 参考[XMPP-CORE|XMPP文档列表/XMPP正式RFC标准/RFC3920]相关章节.<br />
<br />
==安全性事项==<br />
<br />
:XMPP的核心安全性事项定义在[XMPP-CORE|XMPP文档列表/XMPP正式RFC标准/RFC3920]相关章节.<br />
<br />
:附加的事项仅适用于分散定义在本文许多地方的XMPP即时消息和出席信息应用; 特别是:<br />
<br />
:* 当一个服务器处理一个任何类型的入站节,这个节的预定接收者是和服务器的主机名相关的一个用户,服务器必须(MUST)首先强制应用任何隐私列表(第十章),见 处理XML节的服务器规则Server Rules for Handling XML Stanzas(第十一章)).<br />
<br />
:* 当一个服务器处理一个类型为"probe"的入站出席信息节,这个节的预定接收者是和服务器的主机名相关的一个用户, 如果这个发送者是一个由出席信息订阅决定的未被授权接收那个信息的实体,服务器不能(MUST NOT)揭露这个用户的出席信息(见 客户端和服务器出席信息职责Client and Server Presence Responsibilities (第五章第一节)).<br />
<br />
:* 当一个服务器处理一个任何类型的出站出席信息节,这个节没有type属性或type属性值为"unavailable", 为了确保这个出席信息不被广播给那些未被授权知道这个信息的实体, 它必须(MUST)服从客户端和服务器出席信息职责Client and Server Presence Responsibilities (第五章第一节) 定义的规则 .<br />
<br />
:* 当一个服务器生成一个错误节作为不存在的用户接收到的一个节的应答的时候, 使用<service-unavailable/>错误条件有助于防止著名的字典攻击, 因为这个错误和条件和其他一些错误条件相同,例如, 一个IQ子元素的名字空间不被理解, 或离线存储或消息转发不被一个域允许.<br />
<br />
==IANA事项==<br />
<br />
:很多相关的IANA事项, 参考[XMPP-CORE|XMPP文档列表/XMPP正式RFC标准/RFC3920]相关章节.<br />
<br />
===会话数据的XML名字空间名===<br />
<br />
:以下为XMPP中会话相关的数据定义了一个 URN 子名字空间. (这个名字空间名的格式遵循 IETF XML Registry [XML-REG].)<br />
<br />
::URI: urn:ietf:params:xml:ns:xmpp-session<br />
<br />
::Specification: RFC 3921<br />
<br />
::Description: This is the XML namespace name for session-related data in the Extensible Messaging and Presence Protocol (XMPP) as defined by RFC 3921.<br />
<br />
:Registrant Contact: IETF, XMPP Working Group, <xmppwg@jabber.org><br />
<br />
===即时消息SRV协议标签注册===<br />
<br />
:确定即时消息和出席信息地址[IMP-SRV],为那些能提供遵守"_im"SRV服务标签的服务定义了一个即时消息SRV协议标签注册表. 因为XMPP是其中一个协议, IANA在适当的注册项中注册了"_xmpp"协议标签,如下:<br />
<br />
::Protocol label: _xmpp<br />
<br />
::Specification: RFC 3921<br />
<br />
::Description: Instant messaging protocol label for the Extensible Messaging and Presence Protocol (XMPP) as defined by RFC 3921.<br />
<br />
::Registrant Contact: IETF, XMPP Working Group, <xmppwg@jabber.org><br />
<br />
===出席信息SRV协议标签注册===<br />
<br />
:确定即时消息和出席信息地址[IMP-SRV],为那些能够提供遵守"_pres"SRV服务标签的服务定义了一个出席信息SRV协议标签注册项. 因为XMPP是其中一个协议, IANA在适当的注册项中注册了"_xmpp"协议标签,如下:<br />
<br />
::Protocol label: _xmpp<br />
<br />
::Specification: RFC 3921<br />
<br />
::Description: Presence protocol label for the Extensible Messaging and Presence Protocol (XMPP) as defined by RFC 3921.<br />
<br />
::Registrant Contact: IETF, XMPP Working Group, <xmppwg@jabber.org><br />
<br />
==参考==<br />
<br />
===标准参考===<br />
<br />
:[CPIM] Peterson, J., "Common Profile for Instant Messaging (CPIM)", RFC 3860, August 2004.<br />
<br />
:[IMP-REQS] Day, M., Aggarwal, S., Mohr, G., and J. Vincent, "Instant Messaging/Presence Protocol Requirements", RFC 2779, February 2000.<br />
<br />
:[IMP-SRV] Peterson, J., "Address Resolution for Instant Messaging and Presence", RFC 3861, August 2004.<br />
<br />
:[SRV] Gulbrandsen, A., Vixie, P., and L. Esibov, "A DNS RR for specifying the location of services (DNS SRV)", RFC 2782, February 2000.<br />
<br />
:[TERMS] Bradner, S., "Key words for use in RFCs to Indicate Requirement Levels", BCP 14, RFC 2119, March 1997.<br />
<br />
:[XML] Bray, T., Paoli, J., Sperberg-McQueen, C., and E. Maler, "Extensible Markup Language (XML) 1.0 (2nd ed)", W3C REC-xml, October 2000, <http://www.w3.org/TR/REC-xml>.<br />
<br />
:[XML-NAMES] Bray, T., Hollander, D., and A. Layman, "Namespaces in XML", W3C REC-xml-names, January 1999, <http://www.w3.org/TR/REC-xml-names>.<br />
<br />
:[XMPP-CORE|XMPP文档列表/XMPP正式RFC标准/RFC3920] Saint-Andre, P., "Extensible Messaging and Presence Protocol (XMPP): Core", RFC 3920, October 2004.<br />
<br />
:[XMPP-E2E] Saint-Andre, P., "End-to-End Object Encryption in the Extensible Messaging and Presence Protocol (XMPP)", RFC 3923, October 2004.<br />
<br />
===信息参考===<br />
<br />
:[IMP-MODEL] Day, M., Rosenberg, J., and H. Sugano, "A Model for Presence and Instant Messaging", RFC 2778, February 2000.<br />
<br />
:[IRC] Oikarinen, J. and D. Reed, "Internet Relay Chat Protocol", RFC 1459, May 1993.<br />
<br />
:[JEP-0054] Saint-Andre, P., "vcard-temp", JSF JEP 0054, March 2003.<br />
<br />
:[JEP-0077] Saint-Andre, P., "In-Band Registration", JSF JEP 0077, August 2004.<br />
<br />
:[JEP-0078] Saint-Andre, P., "Non-SASL Authentication", JSF JEP 0078, July 2004.<br />
<br />
:[JSF] Jabber Software Foundation, "Jabber Software Foundation", <http://www.jabber.org/>.<br />
<br />
:[VCARD] Dawson, F. and T. Howes, "vCard MIME Directory Profile", RFC 2426, September 1998.<br />
<br />
:[XML-REG] Mealling, M., "The IETF XML Registry", BCP 81, RFC 3688, January 2004.<br />
<br />
==附录 A. vCards==<br />
<br />
:[IMP-REQS]的第三章第一节第三小节和第四章第一节第四小节要求可能为其他用户接收带外的联系人信息(例如,电话号码或电子邮件地址). 在Jabber社区中通常使用RFC 2426 [VCARD]中vCard规范的XML来表达这类信息,但这超出了XMPP的范围(这个协议的文档包含在[JEP-0054], 由[JSF]发行).<br />
<br />
译者注: [JSF]已改名为[XSF],[JEP-0054]已改名为[XEP-0054]<br />
<br />
==附录 B. XML规划==<br />
<br />
:接下来的XML规划是描述性的, 不是标准化的. 规划定义在XMPP的核心特性, 参考[XMPP-CORE|XMPP文档列表/XMPP正式RFC标准/RFC3920].<br />
<br />
===B.1 jabber:client===<br />
<br />
<source lang="xml"><br />
<?xml version='1.0' encoding='UTF-8'?><br />
<br />
<xs:schema<br />
xmlns:xs='http://www.w3.org/2001/XMLSchema'<br />
targetNamespace='jabber:client'<br />
xmlns='jabber:client'<br />
elementFormDefault='qualified'><br />
<br />
<xs:import namespace='urn:ietf:params:xml:ns:xmpp-stanzas'/><br />
<br />
<xs:element name='message'><br />
<xs:complexType><br />
<xs:sequence><br />
<xs:choice minOccurs='0' maxOccurs='unbounded'><br />
<xs:element ref='subject'/><br />
<xs:element ref='body'/><br />
<xs:element ref='thread'/><br />
</xs:choice><br />
<xs:any namespace='##other'<br />
minOccurs='0'<br />
maxOccurs='unbounded'/><br />
<xs:element ref='error'<br />
minOccurs='0'/><br />
</xs:sequence><br />
<xs:attribute name='from'<br />
type='xs:string'<br />
use='optional'/><br />
<xs:attribute name='id'<br />
type='xs:NMTOKEN'<br />
use='optional'/><br />
<xs:attribute name='to'<br />
type='xs:string'<br />
use='optional'/><br />
<xs:attribute name='type' use='optional' default='normal'><br />
<xs:simpleType><br />
<xs:restriction base='xs:NCName'><br />
<xs:enumeration value='chat'/><br />
<xs:enumeration value='error'/><br />
<xs:enumeration value='groupchat'/><br />
<xs:enumeration value='headline'/><br />
<xs:enumeration value='normal'/><br />
</xs:restriction><br />
</xs:simpleType><br />
</xs:attribute><br />
<xs:attribute ref='xml:lang' use='optional'/><br />
</xs:complexType><br />
</xs:element><br />
<br />
<xs:element name='body'><br />
<xs:complexType><br />
<xs:simpleContent><br />
<xs:extension base='xs:string'><br />
<xs:attribute ref='xml:lang' use='optional'/><br />
</xs:extension><br />
</xs:simpleContent><br />
</xs:complexType><br />
</xs:element><br />
<br />
<xs:element name='subject'><br />
<xs:complexType><br />
<xs:simpleContent><br />
<xs:extension base='xs:string'><br />
<xs:attribute ref='xml:lang' use='optional'/><br />
</xs:extension><br />
</xs:simpleContent><br />
</xs:complexType><br />
</xs:element><br />
<br />
<xs:element name='thread' type='xs:NMTOKEN'/><br />
<br />
<xs:element name='presence'><br />
<xs:complexType><br />
<xs:sequence><br />
<xs:choice minOccurs='0' maxOccurs='unbounded'><br />
<xs:element ref='show'/><br />
<xs:element ref='status'/><br />
<xs:element ref='priority'/><br />
</xs:choice><br />
<xs:any namespace='##other'<br />
minOccurs='0'<br />
maxOccurs='unbounded'/><br />
<xs:element ref='error'<br />
minOccurs='0'/><br />
</xs:sequence><br />
<xs:attribute name='from'<br />
type='xs:string'<br />
use='optional'/><br />
<xs:attribute name='id'<br />
type='xs:NMTOKEN'<br />
use='optional'/><br />
<xs:attribute name='to'<br />
type='xs:string'<br />
use='optional'/><br />
<xs:attribute name='type' use='optional'><br />
<xs:simpleType><br />
<xs:restriction base='xs:NCName'><br />
<xs:enumeration value='error'/><br />
<xs:enumeration value='probe'/><br />
<xs:enumeration value='subscribe'/><br />
<xs:enumeration value='subscribed'/><br />
<xs:enumeration value='unavailable'/><br />
<xs:enumeration value='unsubscribe'/><br />
<xs:enumeration value='unsubscribed'/><br />
</xs:restriction><br />
</xs:simpleType><br />
</xs:attribute><br />
<xs:attribute ref='xml:lang' use='optional'/><br />
</xs:complexType><br />
</xs:element><br />
<br />
<xs:element name='show'><br />
<xs:simpleType><br />
<xs:restriction base='xs:NCName'><br />
<xs:enumeration value='away'/><br />
<xs:enumeration value='chat'/><br />
<xs:enumeration value='dnd'/><br />
<xs:enumeration value='xa'/><br />
</xs:restriction><br />
</xs:simpleType><br />
</xs:element><br />
<br />
<xs:element name='status'><br />
<xs:complexType><br />
<xs:simpleContent><br />
<xs:extension base='xs:string'><br />
<xs:attribute ref='xml:lang' use='optional'/><br />
</xs:extension><br />
</xs:simpleContent><br />
</xs:complexType><br />
</xs:element><br />
<br />
<xs:element name='priority' type='xs:byte'/><br />
<br />
<xs:element name='iq'><br />
<xs:complexType><br />
<xs:sequence><br />
<xs:any namespace='##other'<br />
minOccurs='0'/><br />
<xs:element ref='error'<br />
minOccurs='0'/><br />
</xs:sequence><br />
<xs:attribute name='from'<br />
type='xs:string'<br />
use='optional'/><br />
<xs:attribute name='id'<br />
type='xs:NMTOKEN'<br />
use='required'/><br />
<xs:attribute name='to'<br />
type='xs:string'<br />
use='optional'/><br />
<xs:attribute name='type' use='required'><br />
<xs:simpleType><br />
<xs:restriction base='xs:NCName'><br />
<xs:enumeration value='error'/><br />
<xs:enumeration value='get'/><br />
<xs:enumeration value='result'/><br />
<xs:enumeration value='set'/><br />
</xs:restriction><br />
</xs:simpleType><br />
</xs:attribute><br />
<xs:attribute ref='xml:lang' use='optional'/><br />
</xs:complexType><br />
</xs:element><br />
<br />
<xs:element name='error'><br />
<xs:complexType><br />
<xs:sequence xmlns:err='urn:ietf:params:xml:ns:xmpp-stanzas'><br />
<xs:group ref='err:stanzaErrorGroup'/><br />
<xs:element ref='err:text'<br />
minOccurs='0'/><br />
</xs:sequence><br />
<xs:attribute name='code' type='xs:byte' use='optional'/><br />
<xs:attribute name='type' use='required'><br />
<xs:simpleType><br />
<xs:restriction base='xs:NCName'><br />
<xs:enumeration value='auth'/><br />
<xs:enumeration value='cancel'/><br />
<xs:enumeration value='continue'/><br />
<xs:enumeration value='modify'/><br />
<xs:enumeration value='wait'/><br />
</xs:restriction><br />
</xs:simpleType><br />
</xs:attribute><br />
</xs:complexType><br />
</xs:element><br />
<br />
</xs:schema><br />
</source><br />
<br />
===B.2 jabber:server===<br />
<br />
<source lang="xml"><br />
<br />
<?xml version='1.0' encoding='UTF-8'?><br />
<br />
<xs:schema<br />
xmlns:xs='http://www.w3.org/2001/XMLSchema'<br />
targetNamespace='jabber:server'<br />
xmlns='jabber:server'<br />
elementFormDefault='qualified'><br />
<br />
<xs:import namespace='urn:ietf:params:xml:ns:xmpp-stanzas'/><br />
<br />
<xs:element name='message'><br />
<xs:complexType><br />
<xs:sequence><br />
<xs:choice minOccurs='0' maxOccurs='unbounded'><br />
<xs:element ref='subject'/><br />
<xs:element ref='body'/><br />
<xs:element ref='thread'/><br />
</xs:choice><br />
<xs:any namespace='##other'<br />
minOccurs='0'<br />
maxOccurs='unbounded'/><br />
<xs:element ref='error'<br />
minOccurs='0'/><br />
</xs:sequence><br />
<xs:attribute name='from'<br />
type='xs:string'<br />
use='required'/><br />
<xs:attribute name='id'<br />
type='xs:NMTOKEN'<br />
use='optional'/><br />
<xs:attribute name='to'<br />
type='xs:string'<br />
use='required'/><br />
<xs:attribute name='type' use='optional' default='normal'><br />
<xs:simpleType><br />
<xs:restriction base='xs:NCName'><br />
<xs:enumeration value='chat'/><br />
<xs:enumeration value='error'/><br />
<xs:enumeration value='groupchat'/><br />
<xs:enumeration value='headline'/><br />
<xs:enumeration value='normal'/><br />
</xs:restriction><br />
</xs:simpleType><br />
</xs:attribute><br />
<xs:attribute ref='xml:lang' use='optional'/><br />
</xs:complexType><br />
</xs:element><br />
<br />
<xs:element name='body'><br />
<xs:complexType><br />
<xs:simpleContent><br />
<xs:extension base='xs:string'><br />
<xs:attribute ref='xml:lang' use='optional'/><br />
</xs:extension><br />
</xs:simpleContent><br />
</xs:complexType><br />
</xs:element><br />
<br />
<xs:element name='subject'><br />
<xs:complexType><br />
<xs:simpleContent><br />
<xs:extension base='xs:string'><br />
<xs:attribute ref='xml:lang' use='optional'/><br />
</xs:extension><br />
</xs:simpleContent><br />
</xs:complexType><br />
</xs:element><br />
<br />
<xs:element name='thread' type='xs:NMTOKEN'/><br />
<br />
<xs:element name='presence'><br />
<xs:complexType><br />
<xs:sequence><br />
<xs:choice minOccurs='0' maxOccurs='unbounded'><br />
<xs:element ref='show'/><br />
<xs:element ref='status'/><br />
<xs:element ref='priority'/><br />
</xs:choice><br />
<xs:any namespace='##other'<br />
minOccurs='0'<br />
maxOccurs='unbounded'/><br />
<xs:element ref='error'<br />
minOccurs='0'/><br />
</xs:sequence><br />
<xs:attribute name='from'<br />
type='xs:string'<br />
use='required'/><br />
<xs:attribute name='id'<br />
type='xs:NMTOKEN'<br />
use='optional'/><br />
<xs:attribute name='to'<br />
type='xs:string'<br />
use='required'/><br />
<xs:attribute name='type' use='optional'><br />
<xs:simpleType><br />
<xs:restriction base='xs:NCName'><br />
<xs:enumeration value='error'/><br />
<xs:enumeration value='probe'/><br />
<xs:enumeration value='subscribe'/><br />
<xs:enumeration value='subscribed'/><br />
<xs:enumeration value='unavailable'/><br />
<xs:enumeration value='unsubscribe'/><br />
<xs:enumeration value='unsubscribed'/><br />
</xs:restriction><br />
</xs:simpleType><br />
</xs:attribute><br />
<xs:attribute ref='xml:lang' use='optional'/><br />
</xs:complexType><br />
</xs:element><br />
<br />
<xs:element name='show'><br />
<xs:simpleType><br />
<xs:restriction base='xs:NCName'><br />
<xs:enumeration value='away'/><br />
<xs:enumeration value='chat'/><br />
<xs:enumeration value='dnd'/><br />
<xs:enumeration value='xa'/><br />
</xs:restriction><br />
</xs:simpleType><br />
</xs:element><br />
<br />
<xs:element name='status'><br />
<xs:complexType><br />
<xs:simpleContent><br />
<xs:extension base='xs:string'><br />
<xs:attribute ref='xml:lang' use='optional'/><br />
</xs:extension><br />
</xs:simpleContent><br />
</xs:complexType><br />
</xs:element><br />
<br />
<xs:element name='priority' type='xs:byte'/><br />
<br />
<xs:element name='iq'><br />
<xs:complexType><br />
<xs:sequence><br />
<xs:any namespace='##other'<br />
minOccurs='0'/><br />
<xs:element ref='error'<br />
minOccurs='0'/><br />
</xs:sequence><br />
<xs:attribute name='from'<br />
type='xs:string'<br />
use='required'/><br />
<xs:attribute name='id'<br />
type='xs:NMTOKEN'<br />
use='required'/><br />
<xs:attribute name='to'<br />
type='xs:string'<br />
use='required'/><br />
<xs:attribute name='type' use='required'><br />
<xs:simpleType><br />
<xs:restriction base='xs:NCName'><br />
<xs:enumeration value='error'/><br />
<xs:enumeration value='get'/><br />
<xs:enumeration value='result'/><br />
<xs:enumeration value='set'/><br />
</xs:restriction><br />
</xs:simpleType><br />
</xs:attribute><br />
<xs:attribute ref='xml:lang' use='optional'/><br />
</xs:complexType><br />
</xs:element><br />
<br />
<xs:element name='error'><br />
<xs:complexType><br />
<xs:sequence xmlns:err='urn:ietf:params:xml:ns:xmpp-stanzas'><br />
<xs:group ref='err:stanzaErrorGroup'/><br />
<xs:element ref='err:text'<br />
minOccurs='0'/><br />
</xs:sequence><br />
<xs:attribute name='code' type='xs:byte' use='optional'/><br />
<xs:attribute name='type' use='required'><br />
<xs:simpleType><br />
<xs:restriction base='xs:NCName'><br />
<xs:enumeration value='auth'/><br />
<xs:enumeration value='cancel'/><br />
<xs:enumeration value='continue'/><br />
<xs:enumeration value='modify'/><br />
<xs:enumeration value='wait'/><br />
</xs:restriction><br />
</xs:simpleType><br />
</xs:attribute><br />
</xs:complexType><br />
</xs:element><br />
<br />
</xs:schema><br />
</source><br />
<br />
===B.3 session===<br />
<br />
<source lang="xml"><br />
<?xml version='1.0' encoding='UTF-8'?><br />
<br />
<xs:schema<br />
xmlns:xs='http://www.w3.org/2001/XMLSchema'<br />
targetNamespace='urn:ietf:params:xml:ns:xmpp-session'<br />
xmlns='urn:ietf:params:xml:ns:xmpp-session'<br />
elementFormDefault='qualified'><br />
<br />
<xs:element name='session' type='empty'/><br />
<br />
<xs:simpleType name='empty'><br />
<xs:restriction base='xs:string'><br />
<xs:enumeration value=''/><br />
</xs:restriction><br />
</xs:simpleType><br />
<br />
</xs:schema><br />
</source><br />
<br />
===B.4 jabber:iq:privacy===<br />
<br />
<source lang="xml"><br />
<br />
<?xml version='1.0' encoding='UTF-8'?><br />
<br />
<xs:schema<br />
xmlns:xs='http://www.w3.org/2001/XMLSchema'<br />
targetNamespace='jabber:iq:privacy'<br />
xmlns='jabber:iq:privacy'<br />
elementFormDefault='qualified'><br />
<br />
<xs:element name='query'><br />
<xs:complexType><br />
<xs:sequence><br />
<xs:element ref='active'<br />
minOccurs='0'/><br />
<xs:element ref='default'<br />
minOccurs='0'/><br />
<xs:element ref='list'<br />
minOccurs='0'<br />
maxOccurs='unbounded'/><br />
</xs:sequence><br />
</xs:complexType><br />
</xs:element><br />
<br />
<xs:element name='active'><br />
<xs:complexType><br />
<xs:simpleContent><br />
<xs:extension base='xs:NMTOKEN'><br />
<xs:attribute name='name'<br />
type='xs:string'<br />
use='optional'/><br />
</xs:extension><br />
</xs:simpleContent><br />
</xs:complexType><br />
</xs:element><br />
<br />
<xs:element name='default'><br />
<xs:complexType><br />
<xs:simpleContent><br />
<xs:extension base='xs:NMTOKEN'><br />
<xs:attribute name='name'<br />
type='xs:string'<br />
use='optional'/><br />
</xs:extension><br />
</xs:simpleContent><br />
</xs:complexType><br />
</xs:element><br />
<br />
<xs:element name='list'><br />
<xs:complexType><br />
<xs:sequence><br />
<xs:element ref='item'<br />
minOccurs='0'<br />
maxOccurs='unbounded'/><br />
</xs:sequence><br />
<xs:attribute name='name'<br />
type='xs:string'<br />
use='required'/><br />
</xs:complexType><br />
</xs:element><br />
<br />
<xs:element name='item'><br />
<xs:complexType><br />
<xs:sequence><br />
<xs:element name='iq'<br />
minOccurs='0'<br />
type='empty'/><br />
<xs:element name='message'<br />
minOccurs='0'<br />
type='empty'/><br />
<xs:element name='presence-in'<br />
minOccurs='0'<br />
type='empty'/><br />
<xs:element name='presence-out'<br />
minOccurs='0'<br />
type='empty'/><br />
</xs:sequence><br />
<xs:attribute name='action' use='required'><br />
<xs:simpleType><br />
<xs:restriction base='xs:NCName'><br />
<xs:enumeration value='allow'/><br />
<xs:enumeration value='deny'/><br />
</xs:restriction><br />
</xs:simpleType><br />
</xs:attribute><br />
<xs:attribute name='order'<br />
type='xs:unsignedInt'<br />
use='required'/><br />
<xs:attribute name='type' use='optional'><br />
<xs:simpleType><br />
<xs:restriction base='xs:NCName'><br />
<xs:enumeration value='group'/><br />
<xs:enumeration value='jid'/><br />
<xs:enumeration value='subscription'/><br />
</xs:restriction><br />
</xs:simpleType><br />
</xs:attribute><br />
<xs:attribute name='value'<br />
type='xs:string'<br />
use='optional'/><br />
</xs:complexType><br />
</xs:element><br />
<br />
<xs:simpleType name='empty'><br />
<xs:restriction base='xs:string'><br />
<xs:enumeration value=''/><br />
</xs:restriction><br />
</xs:simpleType><br />
<br />
</xs:schema><br />
</source><br />
<br />
===B.5 jabber:iq:roster===<br />
<br />
<source lang="xml"><br />
<br />
<?xml version='1.0' encoding='UTF-8'?><br />
<br />
<xs:schema<br />
xmlns:xs='http://www.w3.org/2001/XMLSchema'<br />
targetNamespace='jabber:iq:roster'<br />
xmlns='jabber:iq:roster'<br />
elementFormDefault='qualified'><br />
<br />
<xs:element name='query'><br />
<xs:complexType><br />
<xs:sequence><br />
<xs:element ref='item'<br />
minOccurs='0'<br />
maxOccurs='unbounded'/><br />
</xs:sequence><br />
</xs:complexType><br />
</xs:element><br />
<br />
<xs:element name='item'><br />
<xs:complexType><br />
<xs:sequence><br />
<xs:element ref='group'<br />
minOccurs='0'<br />
maxOccurs='unbounded'/><br />
</xs:sequence><br />
<xs:attribute name='ask' use='optional'><br />
<xs:simpleType><br />
<xs:restriction base='xs:NCName'><br />
<xs:enumeration value='subscribe'/><br />
</xs:restriction><br />
</xs:simpleType><br />
</xs:attribute><br />
<xs:attribute name='jid' type='xs:string' use='required'/><br />
<xs:attribute name='name' type='xs:string' use='optional'/><br />
<xs:attribute name='subscription' use='optional'><br />
<xs:simpleType><br />
<xs:restriction base='xs:NCName'><br />
<xs:enumeration value='both'/><br />
<xs:enumeration value='from'/><br />
<xs:enumeration value='none'/><br />
<xs:enumeration value='remove'/><br />
<xs:enumeration value='to'/><br />
</xs:restriction><br />
</xs:simpleType><br />
</xs:attribute><br />
</xs:complexType><br />
</xs:element><br />
<br />
<xs:element name='group' type='xs:string'/><br />
<br />
</xs:schema><br />
</source><br />
<br />
==附录 C. Jabber IM Presence协议和XMPP之间的不同==<br />
<br />
:本章是非标准的.<br />
<br />
:译者注:附录D对于新接触XMPP的人没有什么意义,就不翻译了,免得浪费时间。因为现在RFC公布已经很久了,以前的Jabber实现很多都进化到XMPP了。<br />
<br />
:XMPP has been adapted from the protocols originally developed in the Jabber open-source community, which can be thought of as "XMPP 0.9". Because there exists a large installed base of Jabber implementations and deployments, it may be helpful to specify the key differences between the relevant Jabber protocols and XMPP in order to expedite and encourage upgrades of those implementations and deployments to XMPP. This section summarizes the differences that relate specifically to instant messaging and presence applications, while the corresponding section of [XMPP-CORE|XMPP文档列表/XMPP正式RFC标准/RFC3920] summarizes the differences that relate to all XMPP applications.<br />
<br />
===C.1 Session Establishment===<br />
<br />
:The client-to-server authentication protocol developed in the Jabber community assumed that every client is an IM client and therefore initiated an IM session upon successful authentication and resource binding, which are performed simultaneously (documentation of this protocol is contained in [JEP-0078], published by the Jabber Software Foundation [JSF]). XMPP maintains a stricter separation between core functionality and IM functionality; therefore, an IM session is not created until the client specifically requests one using the protocol defined under Session Establishment (Section 3).<br />
<br />
===C.2 Privacy Lists===<br />
<br />
:The Jabber community began to define a protocol for communications blocking (privacy lists) in late 2001, but that effort was deprecated once the XMPP Working Group was formed. Therefore the protocol defined under Blocking Communication (Section 10) is the only such protocol defined for use in the Jabber community.<br />
<br />
==贡献者==<br />
<br />
:XMPP的大部分核心方面是由1999年开始的Jabber开源社区开发的. 这个社区是由 Jeremie Miller建立的, 他于1999年1月发布了最初版的jabber server源代码. 主要的基础协议的早期贡献者还包括 Ryan Eatmon, Peter Millard, Thomas Muldowney,和 Dave Smith. XMPP工作组在即时消息和出席信息方面的工作主要集中在IM会话建立和通信屏蔽(隐私列表); 会话建立协议主要是由 Rob Norris 和 Joe Hildebrand 开发的, 隐私列表协议最初是由 Peter Millard.贡献的<br />
<br />
==致谢==<br />
<br />
:感谢许多在贡献者名单之外的人们. 尽管很难提供一个完整的名单, 以下个人对于定义协议或评论标准提供了很多帮助:<br />
:Thomas Charron, Richard Dobson, Schuyler Heath, Jonathan Hogg, Craig Kaes, Jacek Konieczny, Lisa Dusseault, Alexey Melnikov, Keith Minkler, Julian Missig, Pete Resnick, Marshall Rose, Jean-Louis Seguineau, Alexey Shchepin, Iain Shigeoka, and David Waite. 也感谢 XMPP工作组的成员和 IETF 社区在本文的成文过程中一直提供的评论和反馈。<br />
<br />
==作者地址==<br />
<br />
:Peter Saint-Andre (编辑)<br />
:Jabber Software Foundation<br />
<br />
:EMail: stpeter@jabber.org<br />
<br />
==完整的版权声明==<br />
<br />
:Copyright (C) The Internet Society (2004).<br />
<br />
:This document is subject to the rights, licenses and restrictions contained in BCP 78, and except as set forth therein, the authors retain all their rights. This document and the information contained herein are provided on an "AS IS" basis and THE CONTRIBUTOR, THE ORGANIZATION HE/S HE REPRESENTS OR IS SPONSORED BY (IF ANY), THE INTERNET SOCIETY AND THE INTERNET ENGINEERING TASK FORCE DISCLAIM ALL WARRANTIES, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO ANY WARRANTY THAT THE USE OF THE INFORMATION HEREIN WILL NOT INFRINGE ANY RIGHTS OR ANY IMPLIED WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE.<br />
<br />
==知识产权==<br />
<br />
:The IETF takes no position regarding the validity or scope of any Intellectual Property Rights or other rights that might be claimed to pertain to the implementation or use of the technology described in this document or the extent to which any license under such rights might or might not be available; nor does it represent that it has made any independent effort to identify any such rights. Information on the IETF's procedures with respect to rights in IETF Documents can be found in BCP 78 and BCP 79.<br />
<br />
:Copies of IPR disclosures made to the IETF Secretariat and any assurances of licenses to be made available, or the result of an attempt made to obtain a general license or permission for the use of such proprietary rights by implementers or users of this specification can be obtained from the IETF on-line IPR repository at http://www.ietf.org/ipr.<br />
<br />
:The IETF invites any interested party to bring to its attention any copyrights, patents or patent applications, or other proprietary rights that may cover technology that may be required to implement this standard. Please address the information to the IETF at ietf- ipr@ietf.org.<br />
<br />
==感谢==<br />
<br />
:目前为RFC编辑活动提供资金的Internet Society.</div>
Snowqiang
http://wiki.jabbercn.org/RFC3920
RFC3920
2011-05-18T11:59:03Z
<p>Snowqiang: /* B.1. 介绍 */</p>
<hr />
<div>[[Category:XMPP正式RFC标准]]<br />
[[Category:已翻译]]<br />
<br />
"本文的英文原文来自[http://www.ietf.org/rfc/rfc3920.txt RFC 3920]<br />
<br />
{|<br />
|网络工作组 || P. Saint-Andre, Ed.<br />
|-<br />
|申请讨论: 3920 || Jabber软件基金会<br />
|-<br />
|类别: 标准跟踪 || 2004年10月<br />
|}<br />
<br />
<br />
<br />
:::'''可扩展的消息和出席信息协议 (XMPP): 核心协议'''<br />
<br />
'''关于本文的说明'''<br />
<br />
:本文为互联网社区定义了一个互联网标准跟踪协议,并且申请讨论协议和提出了改进的建议。请参照“互联网官方协议标准”的最新版本(STD 1)获得这个协议的标准化进程和状态。本文可以不受限制的分发。<br />
<br />
'''版权声明'''<br />
<br />
:本文版权属于互联网社区 (C) The Internet Society (2004).<br />
<br />
'''摘要'''<br />
<br />
:本文定义了可扩展消息和出席信息协议(XMPP)的核心功能,这个协议采用XML流实现在任意两个网络终端接近实时的交换结构化信息。XMPP提供一个通用的可扩展的框架来交换XML数据,它主要用来建立即时消息和出席信息应用以实现 RFC 2779 的需求。 <br />
<br />
==绪论==<br />
<br />
===概览===<br />
<br />
:XMPP是一个开放式的XML协议,设计用于准实时消息和出席信息以及请求-响应服务。其基本的语法和语义最初主要是由Jabber开放源代码社区于1999年开发的。2002年,XMPP工作组被授权接手开发和改编Jabber协议以适应IETF的即时消息和出席信息技术。作为XMPP工作组的成果,本文定义了 XMPP 1.0 的核心功能;在 RFC 2779 [IMP-REQS] 中指定的提供即时消息和出席信息功能的扩展,定义在 XMPP-IM 协议 [the Extensible Messaging and Presence Protocol (XMPP): Instant Messaging and Presence] 中。<br />
<br />
===术语===<br />
<br />
:本文中大写的关键字 "MUST(必须)", "MUST NOT(不能)", "REQUIRED(必需)", "SHALL(将会)", "SHALL NOT(将不会)", "SHOULD(应该)", "SHOULD NOT(不应该)", "RECOMMENDED(建议)", "MAY(可以)", 和 "OPTIONAL(可选)" 的确切含义符合 BCP 14, RFC 2119 [TERMS].<br />
<br />
==通用的架构==<br />
<br />
===概览===<br />
<br />
:尽管XMPP没有指定任何特定的网络结构,但它通常是采用客户-服务器 架构进行实现,其中客户端通过TCP方式使用XMPP访问服务器,服务器之间也采用TCP方式进行通信。<br />
<br />
:以下是这一架构的抽象的示意图 (这里 "-" 表示使用 XMPP 通讯, "=" 表示可使用任何协议通讯)。<br />
<br />
<br />
C1----S1---S2---C3<br />
|<br />
C2----+--G1===FN1===FC1<br />
<br />
<br />
:符号的含义如下:<br />
<br />
::* C1, C2, C3 = XMPP 客户端<br />
<br />
::* S1, S2 = XMPP 服务器<br />
<br />
::* G1 = 一个XMPP和外部(非XMPP)消息网络之间进行“翻译”的网关<br />
<br />
::* FN1 = 一个外部消息网络<br />
<br />
::* FC1 = 外部消息网络上的一个客户端<br />
<br />
===服务器===<br />
<br />
:服务器充当XMPP通信的一个智能抽象层,它主要负责:<br />
<br />
:* 对受验证的客户端,服务器以及其他实体之间以XML流形式的连接和会话进行管理。<br />
<br />
:* 在这些实体间使用XML流对合理编址的XML节(第九章)进行路由<br />
<br />
:大部分 XMPP 兼容的服务器也负责存储客户端使用的数据 (比如基于XMPP协议的及时消息应用中的联系人名单); 在这种情况下, XML 数据直接服务器来处理,而不需要转发到其他实体。<br />
<br />
===客户端===<br />
<br />
:大部分客户端通过 TCP 连接直接连到服务器,并通过XMPP获得由服务器以及联合服务器所提供的全部功能。多个不同资源(比如不同的设备和地点)的客户端'''可以'''同时登陆并且并发的连接到一个服务器,每个不同资源的客户端通过XMPP地址的资源标识符来区分(比如<node@domain/ home> 和 <node@domain/work>),参见地址空间(第三章)。'''建议'''的客户端和服务器连接的端口是 5222 ,这个端口已经在 IANA(在第十五章第九节查阅端口号码) 注册了。<br />
<br />
===网关===<br />
<br />
:网关是一个特殊用途的服务器端的服务,主要功能是把 XMPP 翻译成外部(非XMPP)消息系统,并把返回的消息翻译成 XMPP 。例如到 email(参见 [SMTP] ),IRC(参见 [IRC] ),SIMPLE(参见 [SIMPLE] ),SMS 的网关;还有和别的消息服务的网关,比如AIM,ICQ,MSN Messenger,Yahoo! Instant Messenger。网关和服务器之间的通信,网关和外部消息系统的通信,不在本文描述范围之内。<br />
<br />
===网络===<br />
<br />
:因为每个服务器都是由一个网络地址来标识的并且服务器之间的通信是 客户-服务器 协议的直接扩展,实际上整个系统是由很多互通的服务器构成的。例如,<juliet@example.com> 可以和 <romeo@example.net> 交换消息,出席信息和其他信息。这种模式常见于那些需要使网络地址标准化的协议(比如 SMTP )。任意两个服务器之间的通信是可选(OPTIONAL)的。如果被激活,那么这种通信应该(SHOULD)通过 XML 流绑定到 TCP 连接上进行。建议的(RECOMMENDED)服务器之间的连接端口为 5269 ,这个端口号已经在 IANA (在第十五章第九节查阅端口号码)注册了。<br />
<br />
==地址空间==<br />
<br />
===概览===<br />
<br />
:一个实体可以是任何一个被认为是一个网络端点的东西(例如网络上的一个 ID ),而且它是通过XMPP进行通信的。所有这些实体都有一个具有唯一性的地址,并符合 RFC 2396 [URI]规范要求的格式。由于历史原因,一个 XMPP 实体的地址被称为 Jabber Identifier 或 JID 。一个合法的 JID 包括一组排列好的元素,包括域名(domain identifier),节点名(node identifier),和资源名(resource identifier)。<br />
<br />
:JID的语法定义,使用 [ABNF] 中的 Augmented Backus-Naur 格式。(IPv4 地址和 IPv6地址规则在 附录B 中的 [IPv6] 中定义;确定节点规则的合法字符顺序由 附录A 的 [STRINGPREP] 的 Nodeprep 部分来定义;确定资源规则的合法字符顺序由 附录B 的 [STRINGPREP] 的Resourceprep 部分来定义;子域名规则参考 [IDNA] 中关于国际域名标签的描述。)。<br />
<br />
::jid = [ node "@" ] domain [ "/" resource ]<br />
<br />
::domain = fqdn / address-literal<br />
<br />
::fqdn = (sub-domain 1*("." sub-domain))<br />
<br />
::sub-domain = (internationalized domain label)<br />
<br />
::address-literal = IPv4address / IPv6address<br />
<br />
:所有 JID 都是基于上述的结构。类似 <user@host/resource> 这种结构,最常用来标识一个即时消息用户,这个用户所连接的服务器,以及这个用户用于连接的资源(比如特定类型的客户端软件)。不过,节点类型不是客户端也是有可能的,比如一个用来提供多用户聊天服务的特定的聊天室,地址可以是 <room@service> (这里 “room“ 是聊天室的名字而 ”service“ 是多用户聊天服务的主机名),而加入了这个聊天室的某个特定的用户的地址则是 <room@service/nick> (这里 ”nick“ 是用户在聊天室的昵称)。许多其他的 JID 类型都是可能的(例如 <domain/resource> 可能是一个服务器端的脚本或服务)。<br />
<br />
:一个 JID 的每个合法部分(节点名,域名,资源名)的长度不能(MUST NOT)超过 1023 字节。也就是整体长度(包括 '@' 和 '/' )不能超过 3071 字节。<br />
<br />
===域名===<br />
<br />
:域名是一个主要的ID并且是 JID 中唯一必需(REQUIRED)的元素(一个纯粹的域名也是一个合法的 JID)。它通常代表网络的网关或者“主”服务器,其他实体通过连接它来实现 XML 转发和数据管理功能。然而,由一个域名标识引用的实体,并非总是一个服务器,它也可能是一个服务器的子域地址,提供额外的功能(比如多用户聊天服务,用户目录,或一个到外部消息系统的网关)。<br />
<br />
:每个服务器或者服务的域名,可以(MAY)是一个 IP 地址,但应该(SHOULD)是一个完全合法的域名(参见 [DNS]).一个域名ID必须(MUST)是 [IANA] 里定义的“国际化域名”,并且按 [STRINGPREP]中的 [NAMEPREP] profile进行成功的字符转换。在比较两个域名ID之前,服务器必须(MUST),客户端应该(SHOULD)首先按照Nameprep profile(定义在[IANA]中) 来转换每个域名的字符。<br />
<br />
===节点名===<br />
<br />
:节点名是一个可选(OPTIONAL)的第二 ID,放在域名之前并用符号"@"分开.它通常表示一个向服务器或网关请求和使用网络服务的实体(比如一个客户端),当然它也能够表示其他的实体(比如在多用户聊天系统中的一个房间). 节点名所代表的实体,它的地址依赖于一个特定的域名;在 XMPP 的即时消息和出席信息应用系统中,这个地址是“纯 JID” <node@domain> 中的一部分。<br />
<br />
:一个节点名必须按 [STRINGPREP] 中的 Nodeprep profile 进行成功的字符转换。在比较两个节点ID之前,服务器必须(MUST),客户端应该(SHOULD)首先按 Nodeprep profile 转换每个ID的字符。<br />
<br />
===资源名===<br />
<br />
:资源名是一个可选的第三 ID,它放在域名的后面并由符号"/"分开。资源名可以跟在 <node@domain>后面也可以跟在 <domain> 后面。它通常表示一个特定的会话,连接(比如设备或者所在位置),或者一个附属于某个节点ID实体相关实体的对象(比如多用户聊天室中的一个参加者)。对于服务器和和其他客户端来说,资源名是不透明的。当它提供必需的信息以完成资源绑定(参见第七章)的时候,通常是由客户端来实现的(尽管可以由客户端向服务器请求完成),然后显示为“已连接的资源”。一个实体可以(MAY)并发维护多个已连接的资源。每个已连接的资源由不同的资源ID来区分。<br />
<br />
:一个资源名必须(MUST)按 [STRINGPREP] 中的 Resourceprep profile 进行成功的格式化。在比较两个资源ID之前,服务器必须(MUST),客户端应该(SHOULD)首先按 Resourceprep profile 转换每个ID的字符。<br />
<br />
===地址的确认===<br />
<br />
:在 SASL (见第六章)握手之后(如果必要的话,也在资源绑定(见第七章)之后),正在接收流信息的实体必须(MUST)确认初始实体的 ID 。<br />
<br />
:对于服务器间的通信,在 SASL 握手时,如果没有指明授权的ID,这个初始的实体应该(SHOULD)是经过认证实体(参见 简单认证和安全层协议 [SASL] 中的定义)授权的ID(见第六章)。<br />
<br />
:对于客户端和服务器的通信,在 SASL 握手时,如果没有指明授权的ID,“纯 JID” (<node@domain>)应该(SHOULD)是经过认证实体(参见 [SASL] 中的定义)授权的ID,“全 JID” (<node@domain/resource>)的资源ID部分应该(SHOULD)是由客户端和服务器在资源绑定的时候商定的(参见第七章)。<br />
<br />
:接收的实体必须(MUST)确保结果JID(包括节点名,域名,资源名以及分隔符)与本章前面部分描述的规则和格式相一致;为了满足这些约束条件,接收实体可能(MAY)需要把初始实体的发送方 JID 替换成接收实体认可的规范 JID。<br />
<br />
==XML流==<br />
<br />
===概览===<br />
<br />
:两个基本概念,XML流和XML节,使得在出席信息已知的实体之间,异步交换低负载的结构化信息成为可能。这两个术语定义如下:<br />
<br />
:XML流的定义:一个XML流是一个容器,包含了两个实体之间通过网络交换的XML元素。一个XML流是由一个XML打开标签 <stream> (包含适当的属性和名字空间声明)开始的,流的结尾则是一个XML关闭L标签 </stream> 。在流的整个生命周期,初始化它的实体可以通过流发送大量的XML元素,用于流的握手(例如 TLS 握手(第五章) 或 SASL 握手(第六章))或XML节(在这里指符合缺省名字空间的元素,包括<message/>,<presence/>, 或 <iq/> 元素)。“初始的流”由初始化实体(通常是一个客户端或服务器)和接收实体(通常是一个服务器)握手,从接收实体来看,它就是那个初始实体的"会话".初始化流允许从初始化实体到接收实体的单向通信;为了使接收实体能够和初始实体交换信息,接收实体必须发起一个反向的握手(应答流).<br />
<br />
:XML节的定义: 一个XML节是一个实体通过 XML 流向另一个实体发送的结构化信息中的一个离散的语义单位。一个XML节直接存在于根元素<stream/>的下一级,这样可以说是很好的匹配了[XML](译者注:在标准参考一节)的第43条.任何XML节都是从一个XML流的下一级的某个打开标签(如 <presence>)开始,到相应的关闭标签(如 </presence>)。一个XML节可以(MAY)包含子元素(相关的属性,元素, 和 XML 字符数据等) 以表达完整的信息.在这里定义的XML节仅限于<message/>, <presence/>, 和 <iq/> 元素,具体描述间见 XML Stanzas(第九章);为TLS握手(第五章)、SASL握手(第六章)、服务器回拨(第八章)的需要而发送的XML元素,不被认为是一个XML节。<br />
<br />
:设想一个客户端和服务器会话的例子。为了连接一个服务器,一个客户端必须(MUST)发送一个打开标签<stream>给服务器,初始化一个XML流,也可选择(OPTIONAL)在这之前发送一段文本声明XML版本和支持的字符集(参见文本声明的内容(第十一章第四节); 也可看字符编码(第十一章第五节))。视本地化策略和提供的服务而定,服务器应该(SHOULD)回复一个XML流给客户端,同样的,也可选择在这之前发送一段文本声明。一旦客户端完成了SASL握手(第六章),客户端可以(MAY)通过流发送不限量的XML节给网络中的任何接收者。当客户端想关闭这个流,它只需要简单的发送一个关闭标签</stream>给服务器(或者作为另一个选择,可能由服务器关闭这个流)。然后,客户端和服务器都应该(SHOULD)彻底地终止这个连接(通常是一个TCP连接)。<br />
<br />
:那些习惯认为XML是一个以文本为中心风格的人可能希望看看一个与服务器连接的客户端会话,包含两个 打开-关闭 XML文档:一个是从客户端到服务器,一个是从服务器到客户端。下图中,根元素<stream/> 可以被认为是每个“文档”的文档实体,这两个“文档”通过累积那些在XML上传输的XML节来搭建的。无论如何,下图只是方便理解;实际上XMPP并不处理文档而是处理XML流和XML节。<br />
<br />
:基本上,一个XML流相当于一个会话期间所有XML节的一个信封。我们可以简单的把它描述成下图:<br />
<br />
|--------------------|<br />
| <stream> |<br />
|--------------------|<br />
| <presence> |<br />
| <show/> |<br />
| </presence> |<br />
|--------------------|<br />
| <message to='foo'> |<br />
| <body/> |<br />
| </message> |<br />
|--------------------|<br />
| <iq to='bar'> |<br />
| <query/> |<br />
| </iq> |<br />
|--------------------|<br />
| ... |<br />
|--------------------|<br />
| </stream> |<br />
|--------------------|<br />
<br />
===绑定到TCP===<br />
<br />
:虽然有很多非必需的连接使用XML流来绑定[TCP]连接(两个实体可以通过别的机制来互联,比如通过[HTPP]连接轮询),本规范只定义了 XMPP 到 TCP 的绑定。在客户和服务器通信的过程中,服务器必须(MUST)允许客户端共享一个TCP连接来传输XML节,包括从客户端传到服务器和从服务器传到客户端。在服务器之间的通信过程中,服务器必须(MUST)用一个 TCP连接 向对方发送 XML节,另一个 TCP连接(由对方初始化)接收对方的XML节,一共两个 TCP连接。<br />
<br />
===流的安全===<br />
<br />
:在XMPP 1.0中,当XML流开始握手时,TLS应该(SHOULD)按 第五章:TLS的使用 中的规定来使用,SASL必须(MUST)按 第六章:SASL的使用 中的规定来使用。尽管可能(MAY)存在某种共有的机制能够保证双向安全,但是“初始化流”(比如从初始化实体发给接收实体的流)和“应答流”(比如从接收实体发给初始化实体的流)还是必须(MUST)安全的分开。在流被验证之间,实体不应该(SHOULD NOT) 尝试通过流发送XML节(第九章);就算它这样做了,对方的实体也不能(MUST NOT)接受这些XML节,并且应该(SHOULD)返回一个 <not-authorized/> 的流错误信息并且终止当前TCP连接上双方的XML流;注意,这仅仅是针对XML节(包含在缺省命名空间中的 <message/>, <presence/>, 和 <iq/> 元素),而不是指那些用于 TLS握手(第五章)、SASL握手(第六章)握手的流。<br />
<br />
===stream 属性===<br />
<br />
:stream 元素的属性如下:<br />
<br />
:* to -- 'to' 属性应(SHOULD)仅出现在初始化实体发给接收实体的 XML 流的头当中,并且它的值必须(MUST)是接收实体所在的主机名。在接收实体发送给初始化实体的 XML 流的头中不应该(SHOULD NOT)出现 'to' 属性。若 'to' 属性出现在应答流中,则初始化实体应(SHOULD)忽略它。<br />
<br />
:* from -- 'from' 属性应(SHOULD)仅出现在接收实体发给初始化实体的 XML 流的头当中,并且它的值必须(MUST)是为当前初始化实体授权的接收实体所在的主机名。注意,不应该(SHOULD NOT)有 'from'属性出现在初始实体发送给接收实体的 XML流的头中;无论如何,如果'from'属性出现在初始化流中,接收实体应该(SHOULD)忽略它。<br />
<br />
:* id -- 'id'属性应该(SHOULD)仅用于接收实体发送给初始化实体 XML流的头。这个属性是一个由接收实体创建的具有唯一性的ID,一个初始实体和接收实体之间的会话ID,并且它在接收方的应用程序中(通常是一个服务器)必须(MUST)是唯一的。注意,这个流 ID 必须是足够安全的,所以它必须是不可预知的和不可重复的(参见[RANDOM] 了解如何获得随机性以保证安全性)。不应该(SHOULD NOT)有 'id'属性出现在初始实体发送给接收实体的 XML流的头中;无论如何,如果'id'属性出现在初始化流中,接收实体应该(SHOULD)忽略它。<br />
<br />
:* xml:lang -- 'xml:lang'属性(定义在[XML]中的第二章第十二节)应该(SHOULD)包含在初始化实体发给接收实体的 XML流的头中,以指定在流中传输的可读XML字符所使用的缺省语言。如果这个属性出现了,接收实体应该(SHOULD)记住它的值,作为初始化流和应答流的缺省属性;如果这个属性没有出现,接收实体应该(SHOULD)用一个可配置的缺省值用于双方的流,这个属性值必须(MUST)在应答流的头中传达。对于所有初始化流中传输的节,如果初始实体没有提供'xml:lang'属性,接收实体应该(SHOULD)应用缺省值;如果初始实体提供了'xml:lang'属性,接收实体不能(MUST NOT)修改或删除它(参见第九章第一节第五小节 xml:lang)。'xml:lang'属性的值必须(MUST)是一个 NMTOKEN (定义在[XML]的第二章第三节) 并且必须(MUST)遵守 RFC 3066 [LANGTAGS] 规定的格式。<br />
<br />
:* version -- version属性(最少需要"1.0")为本规范中和流相关的协议提供了支持。关于这个属性的生成和处理的详细规则将在下文中定义。<br />
<br />
:我们现在可以总结如下:<br />
<br />
{|border="1" cellspacing="0" <br />
! !! 初始化方发给接收方 !! 接收方发给初始化方<br />
|-<br />
|to || 接收方的主机名 || 忽略<br />
|-<br />
|from || 忽略 || 接收方的主机名<br />
|-<br />
|id || 忽略 || 会话键值<br />
|-<br />
|xml:lang || 缺省语言 || 缺省语言<br />
|-<br />
|version || 支持XMPP 1.0 || 支持XMPP 1.0<br />
|}<br />
<br />
====版本支持====<br />
<br />
:在这里XMPP的版本是"1.0";准确地说,这里囊括了和流相关的所有协议(TLS的使用 (第五章),SASL的使用(第六章), 和流错误(第四章第七节)),以及三个定义好的XML节类型(<message/>,<presence/>,和 <iq/>)。XMPP版本号的编号顺序是“<主版本号>.<副版本号>”。主版本和副版本号必须(MUST)是独立的整数并且每个号码可以(MAY)单独以阿拉伯数字增长。这样,"XMPP 2.4"的版本将比"XMPP 2.13"更低。号码前面 的“0”(比如XMPP 6.01)必须(MUST)被接收方忽略并且不能(MUST NOT)被发送出去.<br />
<br />
:如果流和节的格式或者必需的处理方式有了显著的改变,以至于老版本的实体如果只是简单的忽略它不理解的节和属性并且继续像老版本一样的处理方式,会使得老版本的实体不能够和新版本的实体交互,只有在这时候主版本号才应该(SHOULD)增加。副版本号显示新的性能,它必须(MUST)被副版本号更低的实体忽略,但被高(副)版本号的实体用于了解信息。例如,一个副版本号显示处理某种新定义的"type"属性的值(用于message,presence或IQ节)的能力;副版本号高的实体将会了解到与之通信的对方不能够理解这个"type"属性的值,所以将不会发送它。<br />
<br />
:以下规则是用于'版本'属性在实现流的头信息时如何生成和处理:<br />
<br />
:# 初始化实体必须(MUST)在初始化流的头信息中把'版本'的值设置成它所支持的最高版本。(比如,如果最高版本支持就是本规范,那么它必须(MUST)设置成"1.0").<br />
:# 接收实体必须(MUST)在应答流的头信息中把'版本'的值设置成初始化实体所提供的版本或它所支持的最高版本,取其中版本号较低的那一个。接收实体必须(MUST)把主版本号和副版本号作为数字来比较,而不是对"主版本号.副版本号"这个字符串进行比较.<br />
:# 如果在应答流的头信息的版本号中至少有一个主版本号低于初始化流的头信息的版本号,并且如前所述,新版本的实体不能够和旧版本实体交互,初始化实体应该(SHUOULD)生成一个<unsupported-version/>的流错误信息并终止XML流和它的TCP连接。<br />
:# 如果一个实体收到一个头信息中没有'version'属性的流,这个实体必须(MUST)把对方实体的'version'当成'0.0'并且在它发送的应答流的头中也不应该(SHOULD NOT)包含'version'属性.<br />
<br />
===名字空间声明===<br />
<br />
:流的元素必须(MUST)同时满足一个流名字空间声明和一个缺省名字空间声明("名字空间声明"定义在 XML 名字空间定义 [XML-NAMES]中).关于流名字空间和缺省名字空间的详细信息,参考 名字空间的名字和前缀(第十一章第二节).<br />
<br />
===流的特性===<br />
<br />
:如果初始化的实体在初始化流的头信息中设置'version'属性的信息为"1.0",接收实体必须(MUST)向初始化实体发送一个 <features/> 子元素以声明任何可供协商的流一级的特性(或者其他需要声明的能力).目前,这仅用于声明本文中定义的 TLS的使用(第五章),SASL的使用(第六章)和资源绑定(第七章),以及 [XMPP-IM|XMPP文档列表/XMPP正式RFC标准/RFC3921] 中定义的会话的建立;无论如何,流特性这一功能将来可以用于声明任何可协商的特性.如果一个实体不理解或支持安全特性,它应该(SHOULD)忽略它.如果要在一个非安全相关的特性(比如资源绑定)被提议之前,完成一个或多个安全特性(比如TLS和SASL)的协商,这个非安全相关的特性不应该(SHOULD NOT)在相应的安全特性协商完毕之前被声明.<br />
<br />
===流错误===<br />
<br />
:流的根元素可以(MAY)包含一个 <error/> 子元素,由流的名字空间前缀作为它的前缀。这个"错误"子元素必须(MUST)由感知到发生了流级别错误的实体发送(通常是一个服务器而不是一个客户端)。<br />
<br />
====规则====<br />
<br />
:以下规则适用于流级别的错误:<br />
<br />
:* 它假定所有流级别的错误都是不可恢复的;所以,如果一个错误发生在流级别,发现这个错误的实体必须(MUST)发送一个流错误信息给另一个实体,发送一个关闭标签 </stream>,并终止这个流所在的TCP连接。<br />
<br />
:* 如果这个错误发生在流刚开始设置的时候,接收实体必须(MUST)仍然发送一个开放标签 <stream> ,并在流元素中包含一个<error/>的子元素,然后发送一个关闭标签 </stream>,最后终止相应的TCP连接。在这种情况下,如果初始化实体在 'to' 属性中提供了一个未知的主机名,服务器应该(SHOULD)在终止之前,先在流的头信息的 'from' 属性中提供一个服务器认证的主机名.<br />
<br />
====语法====<br />
<br />
:流错误的语法如下:<br />
<br />
<source lang="xml"><br />
<stream:error><br />
<defined-condition xmlns='urn:ietf:params:xml:ns:xmpp-streams'/><br />
<text xmlns='urn:ietf:params:xml:ns:xmpp-streams' xml:lang='langcode'><br />
OPTIONAL descriptive text<br />
</text><br />
[OPTIONAL application-specific condition element]<br />
</stream:error><br />
</source><br />
<br />
:<error/>元素:<br />
:* 必须(MUST)包含一个子元素以描述一个下文定义的节错误条件;这个子元素必须(MUST)符合'urn:ietf:params:xml:ns:xmpp-streams'名字空间.<br />
<br />
:* 可以(MAY)包含一个 <text/> 子元素,用XML字符数据描述错误的细节;这个元素必须(MUST)符合'urn:ietf:params:xml:ns:xmpp-streams'名字空间并且应该(SHOULD)拥有一个'xml:lang'属性表明XML字符数据的自然语言。<br />
<br />
:* 可以(MAY)包含一个子元素用于描述一个明确的应用程序错误条件;这个元素必须(MUST)符合一个应用程序定义的名字空间,并且它的结构是由那个名字空间定义的。<br />
<br />
: <text/> 元素是可选的(OPTIONAL)。如果有这个元素,它应该(SHOULD)仅用于提供描述或调试信息以补充一个已定义的条件或应用程序定义的条件。它不应该(SHOULD NOT)被一个应用程序当成一个可编程的信息。它不应该(SHOULD NOT)被用于向用户表达错误信息,但是可以(MAY)作为和条件元素相关的错误信息之外的附加说明。<br />
<br />
====已定义的条件====<br />
<br />
:以下流级别的错误条件是已定义的:<br />
<br />
:* <bad-format/> -- 实体已经发送XML但是不能被处理;这个错误可以(可以)被更多特定的XML相关的错误替换,比如 <bad-namespace-prefix/>, <invalid-xml/>, <restricted-xml/>, <unsupported-encoding/>, 以及 <xml-not-well-formed/>,尽管更多特定的错误是首选的。 <br />
<br />
:* <bad-namespace-prefix/> -- 实体发送的名字空间前缀不被支持,或者在一个需要某种前缀的元素中没有发送一个名字空间前缀(参见 XML Namespace Names and Prefixes (第十一章第二节)).<br />
<br />
:* <conflict/> -- 服务器正在关闭为这个实体激活的流,因为一个和已经存在的流有冲突的新的流已经被初始化。<br />
<br />
:* <connection-timeout/> -- 实体已经很长时间没有通过这个流发生任何通信流量(可由一个本地服务策略来配置).<br />
<br />
:* <host-gone/> -- 初始化实体在流的头信息中提供的'to'属性的值所指定的主机已经不再由这台服务器提供<br />
<br />
:* <host-unknown/> -- 由初始化实体在流的头信息中提供的 'to' 属性的值和由服务器提供的主机名不一致.<br />
<br />
:* <improper-addressing/> -- 一个在两台服务器之间传送的节缺少 'to' 或 'from' 属性(或者这个属性没有值).<br />
<br />
:* <internal-server-error/> -- 服务器配置错误或者其他未定义的内部错误,使得服务器无法提供流服务.<br />
<br />
:* <invalid-from/> -- 在'from'属性中提供的 JID 或 主机名地址,和认证的 JID不匹配 或服务器之间无法通过SASL(或回拨)协商出合法的域名,或客户端和服务器之间无法通过它进行认证和资源绑定。<br />
<br />
:* <invalid-id/> -- 流 ID 或回拨 ID 是非法的或和以前提供的 ID 不一致.<br />
<br />
:* <invalid-namespace/> -- 流名字空间和 "http://etherx.jabber.org/streams" 不相同或回拨名字空间和 "jabber:server:dialback" 不相同.(参考 XML Namespace Names and Prefixes (第十一章第二节)).<br />
<br />
:* <invalid-xml/> -- 实体通过流发送了一个非法的XML给执行验证的服务器 (参考 Validation (第十一章第三节)).<br />
<br />
:* <not-authorized/> -- 实体试图在流被验证之前发送数据或不被许可执行一个和流协商有关的动作,接收实体在发送错误信息之前不允许(MUST NOT)处理厌恶的节。<br />
<br />
:* <policy-violation/> -- 实体违反了某些本地服务策略;服务器可以(MAY)选择在 <text/> 元素或应用程序定义的错误条件(元素)中详细说明策略。<br />
<br />
:* <remote-connection-failed/> -- 服务器无法正确连接到用于验证或授权的远程实体。<br />
<br />
:* <resource-constraint/> -- 服务器缺乏必要的系统资源为流服务。<br />
<br />
:* <restricted-xml/> -- 实体试图发送受限的XML特性,比如一个注释,处理指示,DTD,实体参考,或保留的字符(参考 Restrictions (第十一章第一节)).<br />
<br />
:* <see-other-host/> -- 服务器将不提供服务给初始化实体但是把它重定向到另一台主机;服务器应该(SHOULD)在<see-other-host/>元素的XML字符数据中指明替代服务器名或IP地址(它必须(必须)是合法的域名标识)。<br />
<br />
:* <system-shutdown/> -- 服务器正在关机并且所有激活的流正在被关闭。<br />
<br />
:* <undefined-condition/> -- 错误条件不在本文已定义的错误条件列表之中;这个错误条件应该(SHOULD)仅用于"应用程序定义条件"元素.<br />
<br />
:* <unsupported-encoding/> -- 初始化实体以一个服务器不不支持的编码方式编码了一个流(参照Character Encoding (第十一章第五节)).<br />
<br />
:* <unsupported-stanza-type/> -- 初始化实体发送了一个流的一级子元素但是服务器不支持.<br />
<br />
:* <unsupported-version/> -- 由初始化实体在流的头信息中指定的'version'属性的值所指定的版本不被服务器支持;服务器可以(MAY)在<text/>元素中指定一个它支持的版本号.<br />
<br />
:* <xml-not-well-formed/> -- 初始化实体发送了一个不规范的XML(参考[XML]).<br />
<br />
====应用程序定义条件====<br />
<br />
:大家知道,应用程序可以(MAY)在error元素中包含一个适当名字空间的子元素来提供一个应用程序定义流错误信息."应用程序定义"元素应该(SHOULD)补充或甚至限定一个已定义的元素.所以 <error/> 元素将包含两个或三个子元素:<br />
<br />
<source lang="xml"><br />
<stream:error><br />
<xml-not-well-formed xmlns='urn:ietf:params:xml:ns:xmpp-streams'/><br />
<text xml:lang='en' xmlns='urn:ietf:params:xml:ns:xmpp-streams'><br />
Some special application diagnostic information!<br />
</text><br />
<escape-your-data xmlns='application-ns'/><br />
</stream:error><br />
</stream:stream><br />
</source><br />
<br />
===简化的流示例===<br />
<br />
:这里包含两个简化的例子,描述了基于流的客户端在服务器上的“会话”(这里"C"表示从客户端发给服务器,"S"表示从服务器发给客户端);这些例子只是用于举例说明原理.<br />
<br />
:一个基本的 "会话":<br />
<br />
<source lang="xml"><br />
C: <?xml version='1.0'?><br />
<stream:stream to='example.com' xmlns='jabber:client' xmlns:stream='http://etherx.jabber.org/streams' version='1.0'><br />
<br />
S: <?xml version='1.0'?><br />
<stream:stream from='example.com' id='someid' xmlns='jabber:client' xmlns:stream='http://etherx.jabber.org/streams' version='1.0'><br />
... encryption, authentication, and resource binding ...<br />
<br />
C: <message from='juliet@example.com' to='romeo@example.net' xml:lang='en'><br />
<br />
C: <body>Art thou not Romeo, and a Montague?</body><br />
<br />
C: </message><br />
<br />
S: <message from='romeo@example.net' to='juliet@example.com' xml:lang='en'><br />
<br />
S: <body>Neither, fair saint, if either thee dislike.</body><br />
<br />
S: </message><br />
<br />
C: </stream:stream><br />
<br />
S: </stream:stream><br />
</source><br />
<br />
<br />
:一个不成功的 "会话" :<br />
<br />
<source lang="xml"><br />
C: <?xml version='1.0'?><br />
<stream:stream to='example.com' xmlns='jabber:client' xmlns:stream='http://etherx.jabber.org/streams' version='1.0'><br />
<br />
S: <?xml version='1.0'?><br />
<stream:stream from='example.com' id='someid' xmlns='jabber:client' xmlns:stream='http://etherx.jabber.org/streams' version='1.0'><br />
... encryption, authentication, and resource binding ...<br />
<br />
C: <message xml:lang='en'><br />
<body>Bad XML, no closing body tag!<br />
</message><br />
<br />
S: <stream:error><br />
<xml-not-well-formed xmlns='urn:ietf:params:xml:ns:xmpp-streams'/><br />
</stream:error><br />
<br />
S: </stream:stream><br />
</source><br />
<br />
==TLS 的使用==<br />
<br />
===概览===<br />
<br />
:XMPP包含的一个保证流安全的方法来防止篡改和偷听.这个传输层安全协议[TLS]的频道加密方法, 模拟了类似的其他"STARTTLS"(见RFC 2595 [USINGTLS])的扩展,如 IMAP [IMAP], POP3 [POP3], and ACAP [ACAP]."STARTTLS"的扩展名字空间是'urn:ietf:params:xml:ns:xmpp-tls'.<br />
<br />
:一个给定域的管理员可以(MAY)要求客户端和服务器通信以及服务器之间通信时使用TLS,或者两者都要求。客户端应该(SHOULD)在尝试完成 SASL (第六章)握手之前使用 TLS,服务器应该(SHOULD)在两个域之间使用 TLS 以保证服务器间通信的安全。<br />
<br />
:以下是使用规则:<br />
<br />
::# 一个遵守本协议的初始化实体必须(MUST)在初始化流的头信息中包含一个'version'属性并把值设为“1.0”。<br />
::# 如果TLS握手发生在两个服务器之间,除非服务器声称的DNS主机名已经被解析(见第十四章第四节 Server-to-Server Communications),通信不能(MUST NOT)继续进行。<br />
::# 当一个遵守本协议的接收实体接收了一个初始化流(它的头信息中包含一个'version'属性并且值设为“1.0”),在发送应答流的的头信息(其中包含版本标记)之后,它必须发送(MUST)<starttls/>元素(名字空间为 'urn:ietf:params:xml:ns:xmpp-tls')以及其他它支持的流特性 。<br />
::# 如果初始化实体选择使用TLS,TLS握手必须在SASL握手之前完成;这个顺序用于帮助保护SASL握手时发送的认证信息的安全,同时可以在必要的时候在TLS握手之前为SASL外部机制提供证书。<br />
::# TLS握手期间,一个实体不能(MUST NOT)在流的根元素中发送任何空格符号作为元素的分隔符(在下面的TLS示例中的任何空格符都仅仅是为了便于阅读);这个禁令用来帮助确保安全层字节精度。<br />
::# 接收实体必须(MUST)在发送<proceed/> 元素的关闭符号">" 之后立刻开始TLS协商。初始化实体必须(MUST)在从接收实体接收到<proceed/> 元素的关闭符号">" 之后立刻开始TLS协商。<br />
::# 初始化实体必须(MUST)验证接收实体出示的证书;关于证书验证流程参见Certificate Validation ( 第十四章第二节)。<br />
::# 证书必须(MUST)检查初始化实体(比如一个用户)提供的主机名;而不是通过DNS系统解析出来的主机名;例如,如果用户指定一个主机名"example.com"而一个DNS SRV [SRV]查询返回"im.example.com",证书必须(MUST)检查"example.com".如果任何种类的XMPP实体(例如客户端或服务器)的JID出现在一个证书里,它必须(MUST)表现为一个别名实体里面的UTF8字符串,存在于subjectAltName之中。如何使用 [ASN.1] 对象标识符 "id-on-xmppAddr" 定义在本文的第五章第一节第一小节。<br />
::# 如果 TLS 握手成功了,接收实体必须(MUST) 丢弃TLS 生效之前从初始化实体得到的任何不可靠的信息.<br />
::# 如果 TLS 握手成功了,初始化实体必须(MUST) 丢弃TLS 生效之前从接收实体得到的任何不可靠的信息. <br />
::# 如果 TLS 握手成功了,接收实体不能(MUST NOT)在流重新开始的时候通过提供其他的流特性来向初始化实体提供 STARTTLS 扩展.<br />
::# 如果 TLS 握手成功了,初始化实体必须(MUST)继续进行SASL握手。<br />
::# 如果 TLS 握手失败了,接收实体必须(MUST)终止XML流和相应的TCP连接。<br />
::# 关于必须(MUST)支持的机制,参照 Mandatory-to-Implement Technologies (第十四章第七节) 。<br />
<br />
====用于 XMPP 地址的 ASN.1 对象标识符====<br />
<br />
:上文提到的[ASN.1] 对象标识符 "id-on-xmppAddr"定义如下:<br />
<br />
::id-pkix OBJECT IDENTIFIER ::= { iso(1) identified-organization(3)<br />
<br />
::dod(6) internet(1) security(5) mechanisms(5) pkix(7) }<br />
<br />
::id-on OBJECT IDENTIFIER ::= { id-pkix 8 } -- other name forms<br />
<br />
::id-on-xmppAddr OBJECT IDENTIFIER ::= { id-on 5 }<br />
<br />
::XmppAddr ::= UTF8String<br />
<br />
:对象标识符也可以(MAY)使用点分隔的格式,如 "1.3.6.1.5.5.7.8.5".<br />
<br />
===叙述===<br />
<br />
:当一个初始化实体用TLS保护一个和接收实体之间的流,其步骤如下:<br />
<br />
::# 初始化实体打开一个TCP连接,发送一个打开的XML流头信息(其'version'属性设置为"1.0")给接收实体以初始化一个流。<br />
::# 接收实体打开一个TCP连接,发送一个XML流头信息(其'version'属性设置为"1.0")给初始化实体作为应答。<br />
::# 接收实体向初始化实体提议STARTTLS范围(包括其他支持的流特性),如果TLS对于和接收实体交互是必需的,它应该(SHOULD)在<starttls/>元素中包含子元素<required/>.<br />
::# 初始化实体发出STARTTLS命令(例如, 一个符合'urn:ietf:params:xml:ns:xmpp-tls'名字空间的 <starttls/> 元素) 以通知接收实体它希望开始一个TLS握手来保护流。<br />
::# 接收实体必须(MUST)以'urn:ietf:params:xml:ns:xmpp-tls'名字空间中的<proceed/>元素或<failure/>元素应答。如果失败,接收实体必须(MUST)终止XML流和相应的TCP连接。如果继续进行,接收实体必须(MUST)尝试通过TCP连接完成TLS握手并且在TLS握手完成之前不能(MUST NOT)发送任何其他XML数据。<br />
::# 初始化实体和接收实体尝试完成TLS握手。(要符合[TLS]规范)<br />
::# 如果 TLS 握手不成功, 接收实体必须(MUST)终止 TCP 连接. 如果 TLS 握手成功, 初始化实体必须(MUST)发送给接收实体一个打开的XML流头信息来初始化一个新的流(先发送一个关闭标签</stream>是不必要的,因为接收实体和初始化实体必须(MUST)确保原来的流在TLS握手成功之后被关闭) 。<br />
::# 在从初始化实体收到新的流头信息之后,接收实体必须(MUST)发送一个新的XML流头信息给初始化实体作为应答,其中应包含可用的特性但不包含STATRTTLS特性。<br />
<br />
===客户端-服务器 示例===<br />
<br />
:以下例子展示一个客户端使用STARTTLS保护数据流 (注意: 以下步骤举例说明协议中的失败案例;在这个例子中它们并不详尽并且也不是必须被数据传输触发的).<br />
<br />
:步骤 1: 客户端初始化流给服务器:<br />
<br />
<source lang="xml"><br />
<stream:stream xmlns='jabber:client' xmlns:stream='http://etherx.jabber.org/streams' to='example.com' version='1.0'><br />
</source><br />
<br />
:步骤 2: 服务器发送一个流标签给客户端作为应答:<br />
<br />
<source lang="xml"><br />
<stream:stream xmlns='jabber:client' xmlns:stream='http://etherx.jabber.org/streams' id='c2s_123' from='example.com' version='1.0'><br />
</source><br />
<br />
:步骤 3: 服务器发送 STARTTLS 范围给客户端(包括验证机制和任何其他流特性):<br />
<br />
<source lang="xml"><br />
<stream:features><br />
<starttls xmlns='urn:ietf:params:xml:ns:xmpp-tls'><br />
<required/><br />
</starttls><br />
<mechanisms xmlns='urn:ietf:params:xml:ns:xmpp-sasl'><br />
<mechanism>DIGEST-MD5</mechanism><br />
<mechanism>PLAIN</mechanism><br />
</mechanisms><br />
</stream:features><br />
</source><br />
<br />
:步骤 4: 客户端发送 STARTTLS 命令给服务器:<br />
<br />
<source lang="xml"><br />
<starttls xmlns='urn:ietf:params:xml:ns:xmpp-tls'/><br />
</source><br />
<br />
:步骤 5: 服务器通知客户端可以继续进行:<br />
<br />
<source lang="xml"><br />
<proceed xmlns='urn:ietf:params:xml:ns:xmpp-tls'/><br />
</source><br />
<br />
:步骤 5 (或者): 服务器通知客户端 TLS 握手失败并关闭流和TCP连接:<br />
<br />
<source lang="xml"><br />
<failure xmlns='urn:ietf:params:xml:ns:xmpp-tls'/><br />
</stream:stream><br />
</source><br />
<br />
:步骤 6: 客户端和服务器尝试通过已有的TCP连接完成 TLS 握手.<br />
<br />
:步骤 7: 如果 TLS 握手成功, 客户端初始化一个新的流给服务器:<br />
<br />
<source lang="xml"><br />
<stream:stream xmlns='jabber:client' xmlns:stream='http://etherx.jabber.org/streams' to='example.com' version='1.0'><br />
</source><br />
<br />
:步骤 7 (或者): 如果 TLS 握手不成功, 服务器关闭 TCP 连接.<br />
<br />
:步骤 8: 服务器发送一个流头信息应答客户端,其中包括任何可用的流特性:<br />
<br />
<source lang="xml"><br />
<stream:stream xmlns='jabber:client' xmlns:stream='http://etherx.jabber.org/streams' from='example.com' id='c2s_234' version='1.0'><br />
<stream:features><br />
<mechanisms xmlns='urn:ietf:params:xml:ns:xmpp-sasl'><br />
<mechanism>DIGEST-MD5</mechanism><br />
<mechanism>PLAIN</mechanism><br />
<mechanism>EXTERNAL</mechanism><br />
</mechanisms><br />
</stream:features><br />
</source><br />
<br />
:步骤 9: 客户端继续 SASL 握手 (第六章).<br />
<br />
===服务器-服务器示例===<br />
<br />
:以下例子展示两个服务器之间使用STARTTLS保护数据流 (注意: 以下步骤举例说明协议中的失败案例;在这个例子中它们并不详尽并且也不是必须被数据传输触发的).<br />
<br />
:步骤 1: Server1 初始化流给 Server2:<br />
<br />
<source lang="xml"><br />
<stream:stream xmlns='jabber:server' xmlns:stream='http://etherx.jabber.org/streams' to='example.com' version='1.0'><br />
</source><br />
<br />
:步骤 2: Server2 发送一个流标签给 Server1 作为应答:<br />
<br />
<source lang="xml"><br />
<stream:stream xmlns='jabber:server' xmlns:stream='http://etherx.jabber.org/streams' from='example.com' id='s2s_123' version='1.0'><br />
</source><br />
<br />
:步骤 3: Server2 发送 STARTTLS 范围给 Server1 ,包括验证机制和任何其他流特性:<br />
<br />
<source lang="xml"><br />
<stream:features><br />
<starttls xmlns='urn:ietf:params:xml:ns:xmpp-tls'><br />
<required/><br />
</starttls><br />
<mechanisms xmlns='urn:ietf:params:xml:ns:xmpp-sasl'><br />
<mechanism>DIGEST-MD5</mechanism><br />
<mechanism>KERBEROS_V4</mechanism><br />
</mechanisms><br />
</stream:features><br />
</source><br />
<br />
:步骤 4: Server1 发送 STARTTLS 命令给 Server2:<br />
<br />
<source lang="xml"><br />
<starttls xmlns='urn:ietf:params:xml:ns:xmpp-tls'/><br />
</source><br />
<br />
:步骤 5: Server2 通知 Server1 允许继续进行:<br />
<br />
<source lang="xml"><br />
<proceed xmlns='urn:ietf:params:xml:ns:xmpp-tls'/><br />
</source><br />
<br />
:步骤 5 (或者): Server2 通知 Server1 TLS握手失败并关闭流:<br />
<br />
<source lang="xml"><br />
<failure xmlns='urn:ietf:params:xml:ns:xmpp-tls'/><br />
</stream:stream><br />
</source><br />
<br />
:步骤 6: Server1 和 Server2 尝试通过 TCP 完成 TLS 握手.<br />
<br />
:步骤 7: 如果 TLS 握手成功, Server1 初始化一个新的流给 Server2:<br />
<br />
<source lang="xml"><br />
<stream:stream xmlns='jabber:server' xmlns:stream='http://etherx.jabber.org/streams' to='example.com' version='1.0'><br />
</source><br />
<br />
:步骤 7 (或者): 如果 TLS 握手不成功, Server2 关闭 TCP 连接.<br />
<br />
:步骤 8: Server2 发送一个包含任何可用流特性的流头信息给 Server1 :<br />
<br />
<source lang="xml"><br />
<stream:stream xmlns='jabber:server' xmlns:stream='http://etherx.jabber.org/streams' from='example.com' id='s2s_234' version='1.0'><br />
<stream:features><br />
<mechanisms xmlns='urn:ietf:params:xml:ns:xmpp-sasl'><br />
<mechanism>DIGEST-MD5</mechanism><br />
<mechanism>KERBEROS_V4</mechanism><br />
<mechanism>EXTERNAL</mechanism><br />
</mechanisms><br />
</stream:features><br />
</source><br />
<br />
:步骤 9: Server1 继续进行 SASL 握手(第六章).<br />
<br />
==SASL 的使用==<br />
<br />
===概览===<br />
<br />
:XMPP 有一个验证流的方法,即XMPP特定的SASL(简单验证和安全层)[SASL]。SASL提供了一个通用的方法为基于连接的协议增加验证支持,而XMPP使用了一个普通的XML名字空间来满足SASL的需要。<br />
<br />
:以下规则应用于:<br />
<br />
:# 如果SASL协商发生在两台服务器之间,除非服务器宣称的DNS主机名得到解析,否则不能(MUST NOT)进行通信。(参见 服务器间的通信(第十四章第四节)).<br />
:# 如果初始化实体有能力使用 SASL 协商, 它必须(MUST)在初始化流的头信息中包含一个值为"1.0"的属性'version'。<br />
:# 如果接收实体有能力使用 SASL 协商, 它必须(MUST)在应答从初始化实体收到的打开流标签时(如果打开的流标签包含一个值为"1.0"的'version'属性),通过'urn:ietf:params:xml:ns:xmpp-sasl'名字空间中的<mechanisms/>元素声明一个或多个验证机制.<br />
:# 当 SASL 协商时, 一个实体不能(MUST NOT)在流的根元素中发送任何空格符号(匹配 production [3] content of [XML])作为元素之间的分隔符(在以下的SASL例子中任何空格符号的出现仅仅是为了增加可读性); 这条禁令帮助确保安全层字节的精确度。<br />
:# 当SASL握手时,在XML元素中使用的任何 XML 字符数据必须被编码成 base64, 编码遵循 RFC 3548 第三章的规定。<br />
:# 如果一个 简单名字"simple username" 规范被选定的SASL机制所支持,(比如, 这被 DIGEST-MD5 和 CRAM-MD5 机制支持但不被 EXTERNAL 和 GSSAPI 机制支持), 验证的时候初始化实体应该(SHOULD)在服务器间通信时提供 简单名字 自身的发送域(IP地址或包含在一个域标识符中的域名全称),在客户端与服务器之间通信时提供注册用户名(包含在一个XMPP节点标识符中的用户或节点名)。<br />
:# 如果初始化实体希望以另一个实体的身份出现并且SASL机制支持授权ID的传输,初始化实体在SASL握手时必须(MUST)提供一个授权ID。如果初始化实体不希望以另一个实体的身份出现,初始化实体在SASL握手时不能(MUST NOT)提供一个授权ID。在 [SASL] 的定义中,除非授权ID不同于从验证ID(详见[SASL])中得到的缺省的授权ID,初始化实体不能(MUST NOT)提供授权ID。如果提供了,这个授权ID的值必须(MUST)是<domain>的格式(对于服务器来说)或<node@domain>的格式(对于客户端来说). <br />
:# 在成功进行包括安全层的SASL握手之后,接收实体必须(MUST)丢弃任何从初始化实体得到的而不是从SASL协商本身获得的信息。<br />
:# 在成功进行包括安全层的SASL握手之后,初始化实体必须(MUST)丢弃任何从接收实体得到的而不是从SASL协商本身获得的信息。<br />
:# 参看 强制执行的技术 (第十四章第七节) ,了解关于必须(MUST)支持的机制.<br />
<br />
===叙述===<br />
<br />
:一个初始化实体使用SASL和接收实体做验证的步骤如下:<br />
<br />
:# 初始化实体请求SASL验证,它发送一个打开的XML流头信息给接收实体,其'version'属性的值为"1.0".<br />
:# 在发送一个XML流头回复之后,接收实体声明一个可用的SASL验证机制清单;每个机制作为一个<mechanism/>元素,作为子元素包含在<mechanisms/>容器元素(其名字空间为'urn:ietf:params:xml:ns:xmpp-sasl')中,而<mechanisms/>则包含在流名字空间中的<features/>元素中。如果在使用任何验证机制之前需要使用TLS(见第五章),接收实体不能(MUST NOT)在TLS握手之前提供可用的SASL验证机制清单。如果初始化实体在优先的TLS协商过程中呈现了一个合法的证书,接收实体应该(SHOULD)在SASL握手中提出一个SASL外部机制给初始化实体,尽管这个外部机制可以(MAY)在其它环境下提供。<br />
:# 初始化实体发送一个符合'urn:ietf:params:xml:ns:xmpp-sasl'名字空间的<auth/>元素(其中包含了适当的'mechanism'属性值)给接收实体,以选择一个机制。如果这个机制支持或需要,这个元素可以(MAY)包含XML字符数据(在SASL术语中,即“初始化应答”);如果初始化实体需要发送一个零字节的初始化应答,它必须(MUST)传输一个单独的等号作为应答,这表示应答有效但不包含数据。<br />
:# 如果必要,接收实体向初始化实体发送一个符合'urn:ietf:params:xml:ns:xmpp-sasl'名字空间的<challenge/>元素来发出挑战;这个元素可以(MAY)包含XML字符数据(必须按照初始化实体选择的SASL机制进行一致性运算)。<br />
:# 初始化实体向接收实体发送符合'urn:ietf:params:xml:ns:xmpp-sasl'名字空间的<response/>元素作为应答;这个元素可以(MAY)包含XML字符数据(必须按照初始化实体选择的SASL机制进行一致性运算)。<br />
:# 如果必要,接收实体发送更多的挑战给初始化实体,初始化实体发送更多的回应。<br />
<br />
:这一系列的 挑战/应答 组,持续进行直到发生以下三件事中的一件为止:<br />
<br />
:# 初始化实体向接收实体发送符合'urn:ietf:params:xml:ns:xmpp-sasl'名字空间的<abort/>元素以中止握手。在接收到<abort/>元素之后,接收实体应该(SHOULD)允许一个可配置的但是合理的重试次数(至少2次),然后它必须(MUST)终止TCP连接;这使得初始化实体(如一个最终用户客户端)能够容忍可能不正确的credentials(如密码输入错误)而不用强制重新连接。<br />
:# 接收实体向初始化实体发送符合'urn:ietf:params:xml:ns:xmpp-sasl'名字空间的<failure/>元素以报告握手失败(详细的失败原因应该在<failure/>的一个适当的子元素中沟通,在第六章第四节中的SASL Errors中定义)。如果失败的情况发生了,接收实体应该(SHOULD)允许一个可配置的但是合理的重试次数(至少2次), 然后它必须(MUST)终止TCP连接;这使得初始化实体(如一个最终用户客户端)能够容忍可能不正确的credentials(如密码输入错误)而不用强制重新连接。<br />
:# 接收实体向初始化实体发送符合'urn:ietf:params:xml:ns:xmpp-sasl'名字空间的<success/>元素以报告握手成功;如果所选择的SASL机制要求,这个元素可以(MAY)包含XML字符数据(见SASL术语,“成功的额外数据”)。接收到<success/> 元素之后,初始化实体必须(MUST)发送一个打开的XML流头信息给接收实体以发起一个新的的流(不需要先发送一个 </stream>标签,因为在发送和接收到<success/>元素之后,接收实体和初始化实体必须确认原来的流被关闭了)。从初始化实体接收到新的流头信息之后,接收实体必须(MUST)发送一个新的流头信息给初始化实体作为回应,附上任何可用的特性(但不包括 STARTTLS 和 SASL 特性)或一个空的 <features/> 元素(这表示没有更多的特性可用);任何没有在本文定义的附加特性必须(MUST)在XMPP的相关扩展中定义。<br />
<br />
===SASL 定义===<br />
<br />
:[SASL]的必要条件要求通过协议定义来提供以下信息:<br />
<br />
::service name(服务名): "xmpp"<br />
<br />
::initiation sequence(开始序列): 当初始化实体提供一个打开的XML流头信息并且接收实体善意回应之后,接收实体提供一个可接受的验证方法清单。初始化实体从这个清单中选择一个方法,把它作为 <auth/> 元素的 'mechanism' 属性的值发送给接收实体,也可以选择发送一个初始化应答以避免循环。<br />
<br />
::exchange sequence(交换序列): 挑战和回应的交换,从接收实体发送给初始化实体的 <challenge/> 元素和从初始化实体发送给接收实体的 <response/> 元素信息。接收实体通过发送 <failure/>元素报告失败,发送<success/>元素报告成功;初始化实体通过发送<abort/> 元素中止交换。成功的协商之后,两边都认为原来的XML流已经关闭并且都开始发送新的流头信息。<br />
<br />
::security layer negotiation(安全层协商): 安全层在接收实体发送 <success/> 元素的关闭字符">"之后立刻生效,在初始化实体发送 <success/> 元素的关闭字符">"之后也立刻生效。层的顺序是 [TCP],[TLS],然后是 [SASL],然后是 [XMPP]。<br />
<br />
::use of the authorization identity(授权ID的使用): 授权ID可在xmpp中用于表示一个客户端的非缺省的<node@domain>,或一个服务器的<domain> 。<br />
<br />
===SASL 错误===<br />
<br />
:SASL相关的错误条件定义如下:<br />
<br />
::* <aborted/> -- 接收实体认可由初始化实体发送的<abort/>元素;在回应一个<abort/>元素时发送。<br />
<br />
::* <incorrect-encoding/> -- 由初始化实体提供的数据无法处理,因为[BASE64]编码不正确(例如,因为编码不符合[BASE64]的第三章); 在回应一个包含初始化响应数据的<response/> 元素或<auth/>元素时发送.<br />
<br />
::* <invalid-authzid/> -- 由初始化实体提供的授权id是非法的,因为它的格式不正确或初始化实体无权给那个ID授权;在回应一个包含初始化响应数据的<response/> 元素或<auth/>元素时发送。<br />
<br />
::* <invalid-mechanism/> -- 初始化实体不能提供一个机制活、或请求一个不被接受实体支持的机制;在回应一个<auth/>元素时发送。<br />
<br />
::* <mechanism-too-weak/> -- 初始化实体请求的机制比服务器策略对它的要求弱;在回应一个包含初始化响应数据的<response/> 元素或<auth/>元素时发送。<br />
<br />
::* <not-authorized/> -- 验证失败,因为初始化实体没有提供合法的credentials(这包括但不限于未知用户名等情形);在回应一个包含初始化响应数据的<response/> 元素或<auth/>元素时发送。<br />
<br />
::* <temporary-auth-failure/> -- 验证失败,因为接收实体出现了临时的错误;在回应一个<response/> 元素或<auth/>元素时发送。<br />
<br />
===客户端-服务器 示例===<br />
<br />
:以下例子展示了一个客户端和一个服务器使用SASL作验证的数据流,通常是在成功的TLS握手之后(注意:以下显示的替代步骤仅用于举例说明协议的失败情形;它们不够详尽也不需要由例子中的数据传送来触发)。<br />
<br />
:步骤 1: 客户端初始化流给服务器:<br />
<br />
<source lang="xml"><br />
<stream:stream xmlns='jabber:client' xmlns:stream='http://etherx.jabber.org/streams' to='example.com' version='1.0'><br />
</source><br />
<br />
:步骤 2: 服务器向客户端发送流标签作为应答:<br />
<br />
<source lang="xml"><br />
<stream:stream xmlns='jabber:client' xmlns:stream='http://etherx.jabber.org/streams' id='c2s_234' from='example.com' version='1.0'><br />
</source><br />
<br />
:步骤 3: 服务器通知客户端可用的验证机制:<br />
<br />
<source lang="xml"><br />
<stream:features><br />
<mechanisms xmlns='urn:ietf:params:xml:ns:xmpp-sasl'><br />
<mechanism>DIGEST-MD5</mechanism><br />
<mechanism>PLAIN</mechanism><br />
</mechanisms><br />
</stream:features><br />
</source><br />
<br />
:步骤 4: 客户端选择一个验证机制:<br />
<br />
<source lang="xml"><br />
<auth xmlns='urn:ietf:params:xml:ns:xmpp-sasl' mechanism='DIGEST-MD5'/><br />
</source><br />
<br />
:步骤 5: 服务器发送一个 [BASE64] 编码的挑战给客户端:<br />
<br />
<source lang="xml"><br />
<challenge xmlns='urn:ietf:params:xml:ns:xmpp-sasl'><br />
cmVhbG09InNvbWVyZWFsbSIsbm9uY2U9Ik9BNk1HOXRFUUdtMmhoIixxb3A9ImF1dGgi<br />
LGNoYXJzZXQ9dXRmLTgsYWxnb3JpdGhtPW1kNS1zZXNzCg==<br />
</challenge><br />
</source><br />
<br />
:解码后的挑战信息是:<br />
<br />
<source lang="xml"><br />
realm="somerealm",nonce="OA6MG9tEQGm2hh",\<br />
qop="auth",charset=utf-8,algorithm=md5-sess<br />
</source><br />
<br />
:步骤 5 (替代): 服务器返回一个错误给客户端:<br />
<br />
<source lang="xml"><br />
<failure xmlns='urn:ietf:params:xml:ns:xmpp-sasl'><br />
<incorrect-encoding/><br />
</failure><br />
</stream:stream><br />
</source><br />
<br />
:步骤 6: 客户端发送一个[BASE64]编码的回应这个挑战:<br />
<br />
<source lang="xml"><br />
<response xmlns='urn:ietf:params:xml:ns:xmpp-sasl'><br />
dXNlcm5hbWU9InNvbWVub2RlIixyZWFsbT0ic29tZXJlYWxtIixub25jZT0i<br />
T0E2TUc5dEVRR20yaGgiLGNub25jZT0iT0E2TUhYaDZWcVRyUmsiLG5jPTAw<br />
MDAwMDAxLHFvcD1hdXRoLGRpZ2VzdC11cmk9InhtcHAvZXhhbXBsZS5jb20i<br />
LHJlc3BvbnNlPWQzODhkYWQ5MGQ0YmJkNzYwYTE1MjMyMWYyMTQzYWY3LGNo<br />
YXJzZXQ9dXRmLTgK<br />
</response><br />
</source><br />
<br />
:解码后的回应信息是:<br />
<br />
<source lang="xml"><br />
username="somenode",realm="somerealm",\<br />
nonce="OA6MG9tEQGm2hh",cnonce="OA6MHXh6VqTrRk",\<br />
nc=00000001,qop=auth,digest-uri="xmpp/example.com",\<br />
response=d388dad90d4bbd760a152321f2143af7,charset=utf-8<br />
</source><br />
<br />
:步骤 7: 服务器发送另一个[BASE64]编码的挑战给客户端:<br />
<br />
<source lang="xml"><br />
<challenge xmlns='urn:ietf:params:xml:ns:xmpp-sasl'><br />
cnNwYXV0aD1lYTQwZjYwMzM1YzQyN2I1NTI3Yjg0ZGJhYmNkZmZmZAo=<br />
</challenge><br />
</source><br />
<br />
:解码后的挑战信息是:<br />
<br />
<source lang="xml"><br />
rspauth=ea40f60335c427b5527b84dbabcdfffd<br />
</source><br />
<br />
:步骤 7 (或者): 服务器返回一个错误给客户端:<br />
<br />
<source lang="xml"><br />
<failure xmlns='urn:ietf:params:xml:ns:xmpp-sasl'><br />
<temporary-auth-failure/><br />
</failure><br />
</stream:stream><br />
</source><br />
<br />
:步骤 8: 客户端应答这个挑战:<br />
<br />
<source lang="xml"><br />
<response xmlns='urn:ietf:params:xml:ns:xmpp-sasl'/><br />
</source><br />
<br />
:步骤 9: 服务器通知客户端验证成功:<br />
<br />
<source lang="xml"><br />
<success xmlns='urn:ietf:params:xml:ns:xmpp-sasl'/><br />
</source><br />
<br />
:步骤 9 (或者): 服务器通知客户端验证失败:<br />
<br />
<source lang="xml"><br />
<failure xmlns='urn:ietf:params:xml:ns:xmpp-sasl'><br />
<temporary-auth-failure/><br />
</failure><br />
</stream:stream><br />
</source><br />
<br />
:步骤 10: 客户端发起一个新的流给服务器:<br />
<br />
<source lang="xml"><br />
<stream:stream xmlns='jabber:client' xmlns:stream='http://etherx.jabber.org/streams' to='example.com' version='1.0'><br />
</source><br />
<br />
:步骤 11: 服务器发送一个流头信息回应客户端,并附上任何可用的特性(或空的features元素):<br />
<br />
<source lang="xml"><br />
<stream:stream xmlns='jabber:client' xmlns:stream='http://etherx.jabber.org/streams' id='c2s_345' from='example.com' version='1.0'><br />
<stream:features><br />
<bind xmlns='urn:ietf:params:xml:ns:xmpp-bind'/><br />
<session xmlns='urn:ietf:params:xml:ns:xmpp-session'/><br />
</stream:features><br />
</source><br />
<br />
===服务器-服务器 示例===<br />
<br />
:以下例子展示了一个服务器和另一个服务器使用SASL作验证的数据流,通常是在成功的TLS握手之后(注意:以下显示的替代步骤仅用于举例说明协议的失败情形;它们不够详尽也不需要由例子中的数据传送来触发)。<br />
<br />
:步骤 1: 服务器1 发起一个流给 服务器2 :<br />
<br />
<source lang="xml"><br />
<stream:stream xmlns='jabber:server' xmlns:stream='http://etherx.jabber.org/streams' to='example.com' version='1.0'><br />
</source><br />
<br />
:步骤 2: 服务器2 回应一个流标签给 服务器1:<br />
<br />
<source lang="xml"><br />
<stream:stream xmlns='jabber:server' xmlns:stream='http://etherx.jabber.org/streams' from='example.com' id='s2s_234' version='1.0'><br />
</source><br />
<br />
:步骤 3: 服务器2 通知 服务器1 可用的验证机制:<br />
<br />
<source lang="xml"><br />
<stream:features><br />
<mechanisms xmlns='urn:ietf:params:xml:ns:xmpp-sasl'><br />
<mechanism>DIGEST-MD5</mechanism><br />
<mechanism>KERBEROS_V4</mechanism><br />
</mechanisms><br />
</stream:features><br />
</source><br />
<br />
:步骤 4: 服务器1 选择一个验证机制:<br />
<br />
<source lang="xml"><br />
<auth xmlns='urn:ietf:params:xml:ns:xmpp-sasl' mechanism='DIGEST-MD5'/><br />
</source><br />
<br />
:步骤 5: 服务器2 发送一个[BASE64]编码的挑战给 服务器1:<br />
<br />
<source lang="xml"><br />
<challenge xmlns='urn:ietf:params:xml:ns:xmpp-sasl'><br />
cmVhbG09InNvbWVyZWFsbSIsbm9uY2U9Ik9BNk1HOXRFUUdtMmhoIixxb3A9<br />
ImF1dGgiLGNoYXJzZXQ9dXRmLTgsYWxnb3JpdGhtPW1kNS1zZXNz<br />
</challenge><br />
</source><br />
<br />
:解码后的挑战信息是:<br />
<br />
<source lang="xml"><br />
realm="somerealm",nonce="OA6MG9tEQGm2hh",\<br />
qop="auth",charset=utf-8,algorithm=md5-sess<br />
</source><br />
<br />
:步骤 5 (替代): 服务器2 返回一个错误给 服务器1:<br />
<br />
<source lang="xml"><br />
<failure xmlns='urn:ietf:params:xml:ns:xmpp-sasl'><br />
<incorrect-encoding/><br />
</failure><br />
</stream:stream><br />
</source><br />
<br />
:步骤 6: 服务器1 发送一个[BASE64]编码的回应这个挑战:<br />
<br />
<source lang="xml"><br />
<response xmlns='urn:ietf:params:xml:ns:xmpp-sasl'><br />
dXNlcm5hbWU9ImV4YW1wbGUub3JnIixyZWFsbT0ic29tZXJlYWxtIixub25j<br />
ZT0iT0E2TUc5dEVRR20yaGgiLGNub25jZT0iT0E2TUhYaDZWcVRyUmsiLG5j<br />
PTAwMDAwMDAxLHFvcD1hdXRoLGRpZ2VzdC11cmk9InhtcHAvZXhhbXBsZS5v<br />
cmciLHJlc3BvbnNlPWQzODhkYWQ5MGQ0YmJkNzYwYTE1MjMyMWYyMTQzYWY3<br />
LGNoYXJzZXQ9dXRmLTgK<br />
</response><br />
</source><br />
<br />
:解码后的应答信息是:<br />
<br />
<source lang="xml"><br />
username="example.org",realm="somerealm",\<br />
nonce="OA6MG9tEQGm2hh",cnonce="OA6MHXh6VqTrRk",\<br />
nc=00000001,qop=auth,digest-uri="xmpp/example.org",\<br />
response=d388dad90d4bbd760a152321f2143af7,charset=utf-8<br />
</source><br />
<br />
:步骤 7: 服务器2 发送另外一个[BASE64]编码的挑战给 服务器1:<br />
<br />
<source lang="xml"><br />
<challenge xmlns='urn:ietf:params:xml:ns:xmpp-sasl'><br />
cnNwYXV0aD1lYTQwZjYwMzM1YzQyN2I1NTI3Yjg0ZGJhYmNkZmZmZAo=<br />
</challenge><br />
</source><br />
<br />
:解码后的挑战信息是:<br />
<br />
<source lang="xml"><br />
rspauth=ea40f60335c427b5527b84dbabcdfffd<br />
</source><br />
<br />
:步骤 7 (或者): 服务器2 返回一个错误给 服务器1:<br />
<br />
<source lang="xml"><br />
<failure xmlns='urn:ietf:params:xml:ns:xmpp-sasl'><br />
<invalid-authzid/><br />
</failure><br />
</stream:stream><br />
</source><br />
<br />
:步骤 8: 服务器1 回应挑战:<br />
<br />
<source lang="xml"><br />
<response xmlns='urn:ietf:params:xml:ns:xmpp-sasl'/><br />
</source><br />
<br />
:步骤 8 (或者): 服务器1 中止协商:<br />
<br />
<source lang="xml"><br />
<abort xmlns='urn:ietf:params:xml:ns:xmpp-sasl'/><br />
</source><br />
<br />
:步骤 9: 服务器2 通知 服务器1 验证成功:<br />
<br />
<source lang="xml"><br />
<success xmlns='urn:ietf:params:xml:ns:xmpp-sasl'/><br />
</source><br />
<br />
:步骤 9 (或者): 服务器2 通知 服务器1 验证失败:<br />
<br />
<source lang="xml"><br />
<failure xmlns='urn:ietf:params:xml:ns:xmpp-sasl'><br />
<aborted/><br />
</failure><br />
</stream:stream><br />
</source><br />
<br />
:步骤 10: 服务器1 重新发起一个新的流给 服务器2:<br />
<br />
<source lang="xml"><br />
<stream:stream xmlns='jabber:server' xmlns:stream='http://etherx.jabber.org/streams' to='example.com' version='1.0'><br />
</source><br />
<br />
:步骤 11: 服务器2 发送一个流头信息应答 服务器1 ,并附上任何可用的特性(或一个空的features元素).:<br />
<br />
<source lang="xml"><br />
<stream:stream xmlns='jabber:client' xmlns:stream='http://etherx.jabber.org/streams' from='example.com' id='s2s_345' version='1.0'><br />
<stream:features/><br />
</source><br />
<br />
==资源绑定==<br />
<br />
:在和接收实体完成 SASL 协商(第六章)之后,初始化实体可能(MAY)想要或者需要绑定一个特定的资源到流上.通常这仅适用于客户端: 为了满足本文定义的寻址格式(第三章)和节传输规则(第十章),客户端<node@domain>必须(MUST)拥有一个相关的资源ID(由服务器生成或由客户端程序提供);以确保在流上使用的地址是一个“全JID”(<node@domain/resource>)。<br />
<br />
:接收到一个成功的SASL握手之后,客户端必须(MUST)发送一个新的流头信息给服务器,服务器必须(MUST)返回一个包含可用的流特性列表的头信息。特别是,在成功的SASL握手之后如果服务器需要客户端绑定一个资源,它必须(MUST)在握手成功之后(而不是之前)发送给客户端的应答流特性中包含一个空的符合'urn:ietf:params:xml:ns:xmpp-bind'名字空间的<bind/>元素。:<br />
<br />
:服务器向客户端声明资源绑定特性:<br />
<br />
<source lang="xml"><br />
<stream:stream xmlns='jabber:client' xmlns:stream='http://etherx.jabber.org/streams' id='c2s_345' from='example.com' version='1.0'><br />
<stream:features><br />
<bind xmlns='urn:ietf:params:xml:ns:xmpp-bind'/><br />
</stream:features><br />
</source><br />
<br />
:收到要求资源绑定的通知后,客户端必须(MUST)通过发送一个符合'urn:ietf:params:xml:ns:xmpp-bind'名字空间的“set”类型的IQ节(参见 IQ 语义 (第九章第二节第三小节))给服务器来绑定一个资源到流中。<br />
<br />
:如果客户端端希望允许服务器给自己生成一个资源ID,它可以发送一个包含空的<bind/>元素的“set”类型的IQ节。:<br />
<br />
:客户端请求服务器绑定资源:<br />
<br />
<source lang="xml"><br />
<iq type='set' id='bind_1'><br />
<bind xmlns='urn:ietf:params:xml:ns:xmpp-bind'/><br />
</iq><br />
</source><br />
<br />
:一个支持资源绑定的服务器必须(MUST)自动生成一个资源ID给客户端。一个由服务器生成的资源ID对于那个<node@domain>必须(MUST)是唯一的。<br />
<br />
:如果客户端希望指定资源ID,它发送一个包含期望资源ID的“set”类型的 IQ节,把资源ID作为<bind/>元素下的<resource/>子元素的XML字符数据:<br />
<br />
:客户端绑定一个资源:<br />
<br />
<source lang="xml"><br />
<iq type='set' id='bind_2'><br />
<bind xmlns='urn:ietf:params:xml:ns:xmpp-bind'><br />
<resource>someresource</resource><br />
</bind><br />
</iq><br />
</source><br />
<br />
:一旦服务器为客户端生成了一个资源ID或接受了客户端自己提供的资源ID,它必须(MUST)返回一个“result”类型的 IQ 节给客户端,这个节必须包含一个指明全JID的<jid/>子元素表示服务器决定连接的资源:<br />
<br />
:服务器通知客户端资源绑定成功:<br />
<br />
<source lang="xml"><br />
<iq type='result' id='bind_2'><br />
<bind xmlns='urn:ietf:params:xml:ns:xmpp-bind'><br />
<jid>somenode@example.com/someresource</jid><br />
</bind><br />
</iq><br />
</source><br />
<br />
:一个服务器应该(SHOULD)接受客户端提供的资源ID,但是可以(MAY)用服务器生成的资源ID覆盖它;在这种情况下,服务器不应该(SHOULD NOT)返回一个错误信息一个(如<forbidden/>)给客户端,而应该(SHOULD)在上文所述的 IQ result 中返回生成的资源ID。<br />
<br />
:当一个客户端自行提供资源ID时,可能发生以下的节错误(参见 Stanza Errors (第九章第三节)):<br />
<br />
::- 提供的资源ID服务器无法处理,因为不符合资源字符规范Resourceprep(附录B)。<br />
<br />
::- 客户端不被允许绑定一个资源(如节点或用户已经达到允许连接的资源数限制)。<br />
<br />
::- 提供的资源ID已经被使用但是服务器不允许以同一个资源ID绑定多个连接。<br />
<br />
:协议对这些错误条件规定如下.<br />
<br />
::资源ID不能处理:<br />
<br />
<source lang="xml"><br />
<iq type='error' id='bind_2'><br />
<bind xmlns='urn:ietf:params:xml:ns:xmpp-bind'><br />
<resource>someresource</resource><br />
</bind><br />
<error type='modify'><br />
<bad-request xmlns='urn:ietf:params:xml:ns:xmpp-stanzas'/><br />
</error><br />
</iq><br />
</source><br />
<br />
::客户端不允许绑定一个资源:<br />
<br />
<source lang="xml"><br />
<iq type='error' id='bind_2'><br />
<bind xmlns='urn:ietf:params:xml:ns:xmpp-bind'><br />
<resource>someresource</resource><br />
</bind><br />
<error type='cancel'><br />
<not-allowed xmlns='urn:ietf:params:xml:ns:xmpp-stanzas'/><br />
</error><br />
</iq><br />
</source><br />
<br />
::资源ID已经在使用:<br />
<br />
<source lang="xml"><br />
<iq type='error' id='bind_2'><br />
<bind xmlns='urn:ietf:params:xml:ns:xmpp-bind'><br />
<resource>someresource</resource><br />
</bind><br />
<error type='cancel'><br />
<conflict xmlns='urn:ietf:params:xml:ns:xmpp-stanzas'/><br />
</error><br />
</iq><br />
</source><br />
<br />
:如果,在完成资源绑定步骤之前,客户端试图以符合'urn:ietf:params:xml:ns:xmpp-bind'名字空间的<bind/>子元素发送一个非IQ类型的XML节,服务器不能(MUST NOT)处理这个节,而应该(SHOULD)返回一个<not-authorized/>节错误信息给客户端.<br />
<br />
==服务器回拨==<br />
<br />
===概览===<br />
<br />
:Jabber协议接受的来自XMPP的包括“服务器回拨”方法,用于防治域名欺骗,使得欺骗XML节更为困难。服务器回拨不是一个安全机制,并且它的服务器身份认证结果很弱(参见服务器之间的通信(第十四章第四节)中关于这个方法的安全特性)。需要健壮的安全性的域名应该(SHOULD)使用TLS或SASL;细节参见服务器间的通信(第十四章第四节)。如果SASL用于服务器间通信,回拨就不需要用了(SHOULD NOT)。本文描述回拨的好处在于向后兼容现存的实现和部署。<br />
<br />
:服务器回拨方法由现存的DNS系统的存在而成为可能,因为一个服务器(通常)可以查询给定域的授权服务器。由于服务器回拨依赖于DNS,除非服务器宣称的DNS主机得到解析,域之间的通信无法进行(参见服务器间的通信(第十四章第四节))。<br />
<br />
:服务器回拨是单向性的,可在单一方向上对一个流进行(微弱的)身份验证.因为服务器回拨不是一个验证机制,通过回拨获得相互的认证是不可能的.因此,为了使得服务器之间的双向通信,服务器回拨必须(MUST)在每个方向上完成。<br />
<br />
:在服务器回拨中生成和检验密钥的方法必须(MUST)考虑计算被使用的主机名,由接收服务器生成的流ID,和只有授权服务器网络才知道的秘密。在服务器回拨中流ID是安全性的关键所以必须(MUST)是不可预知的和不可重复的(见[RANDOM]中关于使用随机数获得安全性的建议).<br />
<br />
:任何回拨协商过程中发生的错误必须(MUST)被当成一个流错误,并导致流以及相关的TCP连接的终止.可能发生的错误情况协议中描述如下.<br />
<br />
:以下术语适用:<br />
<br />
:* 发起服务器 -- 尝试在两个域之间建立连接的那个服务器.<br />
<br />
:* 接收服务器 -- 尝试验证发起服务期声称的域名的那台服务器.<br />
<br />
:* 授权(权威?Authoritative) 服务器 -- 回答发起服务器声称的DNS主机名的服务器;基本上这应该是那台发起服务器,但是它也可能是一个在发起服务器网络中独立的服务器。<br />
<br />
===事件顺序===<br />
<br />
:以下是回拨中的事件顺序的简介:<br />
<br />
:# 发起服务器和接收服务器建立一个连接。<br />
:# 发起服务器通过到连接发送一个 'key' 值给接收服务期。<br />
:# 接收服务器建立一个连接到授权服务器。<br />
:# 接收服务器发送一个相同的 'key' 值给授权服务器。<br />
:# 授权服务器回答这个key是否合法。<br />
:# 接收服务器通知发起服务器是否被验证通过。<br />
<br />
:我们用用以下图形展示这个事件流程(见附件s2s.png):<br />
<br />
{image:img=s2s}<br />
<br />
发起服务器 接收服务器<br />
----------- ---------<br />
| |<br />
| 建立连接 |<br />
| ----------------------> |<br />
| |<br />
| 发stream头 |<br />
| ----------------------> |<br />
| |<br />
| 发stream头 |<br />
| <---------------------- |<br />
| | <br />
| 发回拨key | 授权服务器<br />
| ----------------------> | -------------<br />
| | |<br />
| 建立连接 |<br />
| ----------------------> |<br />
| |<br />
| 发stream头 |<br />
| ----------------------> |<br />
| |<br />
| 发stream头 |<br />
| <---------------------- |<br />
| |<br />
| 发验证请求 |<br />
| ----------------------> |<br />
| |<br />
| 发验证响应 |<br />
| <---------------------- |<br />
|<br />
| 报告回拨结果 |<br />
| <---------------------- |<br />
| |<br />
<br />
===协议===<br />
<br />
:服务器之间互动的细节协议如下:<br />
<br />
:1. 发起服务器和接受服务器建立TCP连接.<br />
<br />
:2. 发起服务器发送流头信息给接收服务器:<br />
<br />
<source lang="xml"><br />
<stream:stream xmlns:stream='http://etherx.jabber.org/streams' xmlns='jabber:server' xmlns:db='jabber:server:dialback'><br />
</source><br />
<br />
:注意: 'to'和'from'属性在流的根元素是可选的(OPTIONAL). 其中包含的xmlns:db名字空间向接收服务器声明了发起服务器支持回拨. 如果名字空间不正确,接收实体必须(MUST)生成一个<invalid-namespace/>流错误条件并且终止XML流和相应的TCP连接.<br />
<br />
:3. 接收服务器应该(SHOULD)回送一个流头信息给发起服务器,为这次交互生成一个唯一性的ID :<br />
<br />
<source lang="xml"><br />
<stream:stream xmlns:stream='http://etherx.jabber.org/streams' xmlns='jabber:server' xmlns:db='jabber:server:dialback' id='457F9224A0...'><br />
</source><br />
<br />
:注意: 'to'和'from'属性在流的根元素是可选的(OPTIONAL). 如果名字空间不正确,发起服务器必须生成一个<invalid-namespace/>流错误条件并且终止XML流和相应的TCP连接.也要注意,在这里接收服务器应该(SHOULD)应答但是可以(MAY)出于安全策略考虑只是悄悄地终止XML流和TCP连接;无论如何,如果接收服务器希望继续,它必须(MUST)回送一个流头信息给发起服务器.<br />
<br />
:4. 发起服务器发送一个回拨密钥给接收服务器:<br />
<br />
<source lang="xml"><br />
<db:result to='Receiving Server' from='Originating Server'><br />
98AF014EDC0...<br />
</db:result><br />
</source><br />
<br />
:注意: 这个密钥不由接收服务器检查,因为接收服务器在会话之间(between sessions)不保存发起服务器的信息. 这个由发起服务器生成的密钥必须(MUST)是基于接收服务器在上一步骤中提供的ID值,以及发起服务器与授权服务器共享的安全机制生成的。 如果 'to' 地址的值和接收服务器知道的主机名不匹配,接收服务器必须(MUST)生成一个<host-unknown/>流错误条件并且终止XML流和相应的TCP连接. 如果 'from' 地址和接收服务器已经建立的连接的域名相吻合,接收服务器必须(MUST)维护这个已经存在的连接,直到证明这个新的连接是合法的为止;另外,接收实体可以(MAY)选择生成一个<not-authorized/> 流错误条件给这个新的连接并且终止和新连接申请相关的XML流及相应的TCP连接.<br />
<br />
:5. 接收服务器向发起服务器声明的那个域建立一个 TCP 连接,作为结果它连接到授权服务器. (注意: 为了优化性能, 在这里一个实现可以(MAY)重用现有的连接.)<br />
<br />
:6. 接收服务器发送一个流头信息给授权服务器:<br />
<br />
<source lang="xml"><br />
<stream:stream xmlns:stream='http://etherx.jabber.org/streams' xmlns='jabber:server' xmlns:db='jabber:server:dialback'><br />
</source><br />
<br />
:注意: 'to'和'from'属性在流的根元素是可选的(OPTIONAL). 如果名字空间不正确,授权服务器必须生成一个<invalid-namespace/>流错误条件并且终止XML流和相应的TCP连接. <br />
<br />
:7. 授权服务器发送流头信息给接收服务器:<br />
<br />
<source lang="xml"><br />
<stream:stream xmlns:stream='http://etherx.jabber.org/streams' xmlns='jabber:server' xmlns:db='jabber:server:dialback' id='1251A342B...'><br />
</source><br />
<br />
:注意: 如果名字空间不正确,接收服务器必须生成一个<invalid-namespace/>流错误条件并且终止它和授权服务器之间的XML流和相应的TCP连接. 如果一个流错误发生在接收服务器和 '''授权服务器''' 之间,接收服务器必须(MUST)生成一个 <remote-connection-failed/> 流错误条件并且终止它和 '''发起服务器''' 之间的XML流和相应的TCP连接.<br />
<br />
:8. 接收服务器发送一个密钥检查请求给授权服务器:<br />
<br />
<source lang="xml"><br />
<db:verify from='Receiving Server' to='Originating Server' id='457F9224A0...'><br />
98AF014EDC0...<br />
</db:verify><br />
</source><br />
<br />
:注意: 现在这里已经有了主机名,第三步中接收服务器发送给发起服务器的ID,第四步中发起服务器发送给接收服务器的密钥. 基于这些信息, 加上授权服务器网络共享的安全信息, 这个密钥被证实了.任何可用于验证的办法都可以(MAY)用于生成密钥. 如果 'to' 地址的值和授权服务器知道的主机名不匹配,授权服务器必须(MUST)生成一个<host-unknown/>流错误条件并且终止XML流和相应的TCP连接. 打开这个连接时,如果 'from' 地址和接收服务器声明的主机名(或任何合法的域,如验证过的接收服务器的子域名或寄宿在接收服务器上的其他经过验证的域)不符,授权服务器必须(MUST)生成一个<invalid-from/>流错误条件并且终止XML流和相应的TCP连接.<br />
<br />
:9. 授权服务器检查密钥是否合法:<br />
<br />
<source lang="xml"><br />
<db:verify from='Originating Server' to='Receiving Server' type='valid' id='457F9224A0...'/><br />
</source><br />
<br />
::或<br />
<br />
<source lang="xml"><br />
<db:verify from='Originating Server' to='Receiving Server' type='invalid' id='457F9224A0...'/><br />
</source><br />
<br />
:注意: 如果 ID 和第三步中接收服务器提供的不符,接收服务器必须(MUST)生成一个<invalid-id/>流错误条件并且终止XML流和相应的TCP连接. 如果 'to' 地址的值和接收服务器知道的主机名不匹配,接收服务器必须(MUST)生成一个<host-unknown/>流错误条件并且终止XML流和相应的TCP连接. 打开这个连接时,如果 'from' 地址和发起服务器声明的主机名(或任何合法的域,如验证过的发起服务器的子域名或寄宿在发起服务器上的其他经过验证的域)不符,接收服务器必须(MUST)生成一个<invalid-from/>流错误条件并且终止XML流和相应的TCP连接. 在返回验证信息给接收服务器之后,授权服务器应该(SHOULD)终止它们之间的流.<br />
<br />
:10. 接收服务器通知发起服务器结果:<br />
<br />
<source lang="xml"><br />
<db:result from='Receiving Server'to='Originating Server' type='valid'/><br />
</source><br />
<br />
:注意: 在这一个点上, 连接已经由 type='valid' 确认验证是通过了,还是没通过. 如果连接是非法的,接收服务器必须(MUST)终止XML流和相应的TCP连接. 如果连接是合法的, 数据可以从发起服务器发送由接收服务器读取;在此之前,所有发送给接收服务器的XML节应该(SHOULD)被丢弃.<br />
<br />
:进一步的结果是,接收服务器已经验证了发起服务器的ID,所以通过初始化流("initial stream",例如从发起服务器到接收服务器的流)发起服务器可以发送,接收服务器可以接受XML节. 为了使用应答流("response stream",例如从接收服务器到发起服务器的流)验证实体ID,回拨必须(MUST)在相对的两个方向上都完成.<br />
<br />
:在成功的回拨协商之后, 接收服务器应该(SHOULD)接受接下来发起服务器通过当前的合法连接发送的 <db:result/> 包 (例如, 发送给子域或其他寄宿在接收服务器上的主机名的验证请求); 这在单一方向上激活了原始合法连接的 "piggybacking" .<br />
<br />
:即使回拨协商成功了, 服务器仍然必须(MUST)检查从其他服务器接收的所有XML节的'from'和'to'属性; 如果一个节不符合这些限定, 收到这些节的服务器必须(MUST)生成一个<improper-addressing/> 流错误条件并终止XML流和相应的TCP连接. 而且, 一个服务器也必须(MUST)检查从其他的有合法域名的服务器的流中收到的节的'from'属性; 如果一个节不符合这一限定, 接收节的服务器必须(MUST)生成一个 <invalid-from/> 流错误条件并终止XML流和相应的TCP连接. 所有这些检查都用来帮助防止特定的节伪造行为.<br />
<br />
==XML节==<br />
<br />
:在 TLS 协商(第五章) (如果想要), SASL 协商(第六章), 和资源绑定(第七章)(如果需要)之后, XML节就可以通过流发送了. 在'jabber:client'和'jabber:server'名字空间中定义了三种XML节: <message/>, <presence/>, 和 <iq/>. 另外, 这三种节有五种通用的属性. 这些通用属性, 加上三种节的术语,在这里定义; 更多关于和即时消息及出席信息应用相关的XML节语法详细信息在[XMPP-IM|XMPP文档列表/XMPP正式RFC标准/RFC3921]中提供.<br />
<br />
===通用属性===<br />
<br />
:以下五种属性通用于 message, presence, 和 IQ 节:<br />
<br />
====to====<br />
<br />
:'to' 属性表示节的预期接收者的JID.<br />
<br />
:在'jabber:client'名字空间中, 一个节应该(SHOULD)处理一个'to'属性, 尽管由服务器处理的从客户端发给服务器的节(如, 发送给服务器用于广播给其他实体的出席信息) 应该不(SHOULD NOT)处理'to'属性.<br />
<br />
:在'jabber:server'名字空间中, 一个节必须(MUST)处理一个'to'属性; 如果一个服务器收到一个不符合此限定的节, 它必须(MUST)生成一个<improper-addressing/>流错误条件并终止和这个非法服务器的XML流和相应的TCP连接.<br />
<br />
:如果'to'属性的值非法或无法联络, 发现这个事实的实体(通常是发送者或接收者的服务器)必须(MUST)返回一个适当的错误给发送者, 错误节的'from'属性设置成非法节的提供的'to'属性的值.<br />
<br />
====from====<br />
<br />
:'from' 属性表示发送者的 JID .<br />
<br />
:当一个服务器接收了一个符合'jabber:client'名字空间的合法流的XML节, 它必须(MUST)做以下步骤中的一步:<br />
<br />
:# 验证客户端提供的'from'属性值就是那个相关实体连接的资源<br />
:# 为生成这个节的已连接的资源增加一个'from'地址(由服务器决定是纯JID或全JID)(参见 地址的决定 Determination of Addresses (第三章第五节))<br />
:# 如果一个客户端试图发送一个XML节,而它的'from'属性和这个实体已连接的资源不符, 服务器应该(SHOULD)返回一个<invalid-from/>流错误条件给客户端. 如果一个客户端试图通过一个尚未验证的流发送一个XML节, 服务器应该(SHOULD)返回一个<not-authorized/>流错误条件给客户端. 如果生成了, 所有这些条件必须(MUST)导致流的关闭和相应的TCP连接的终止; 这有助于防止不诚实的客户的拒绝服务攻击.<br />
<br />
:当一个服务器从服务器自身生成一个节用于一个已连接的客户端的信息发布(例如, 在服务器为客户端提供数据存储服务的情况下), 这个节必须(MUST) (1) 不包含 'from' 属性 或 (2) 包含一个'from'属性,它的值是这个账号的纯 JID (<node@domain>) 或 客户端的全 JID (<node@domain/resource>). 如果节不是由服务器自身生成的,那么一个服务器不能(MUST NOT)发送不带'from'属性的节. 当一个客户端接收到一个不包含'from'属性的节, 它必须(MUST)认为这个节是从客户端连接的服务器发来的.<br />
<br />
:在'jabber:server'名字空间, 一个节必须(MUST)处理一个'from'属性; 如果一个服务器接收到一个不符合此限定的节, 它必须(MUST)生成一个<improper-addressing/>流错误条件. 而且, 'from'属性的 JID值的域名ID部分必须(MUST)和以SASL协商连接或以回拨协商连接的发送服务器的主机名(或任何合法的域,如发送服务器主机名的合法子域,或其他寄宿在发送服务器上的合法域)吻合; 如果一个服务器接收到的节不符合此限定, 它必须(MUST)生成一个<invalid-from/>流错误条件. 所有这些条件都必须(MUST)导致流的关闭和相应的TCP连接的终止; 这有助于防止不诚实的客户端发起的拒绝服务攻击.<br />
<br />
====id====<br />
<br />
:可选的'id' 属性可以(MAY)用于为节的内部跟踪发送实体,从IQ节 语义来讲,就是通过发送和接收这些节来跟踪“请求-应答”型的交互行为。这个可选的(OPTIONAL)'id'属性值在一个域或一个流中是全局唯一的。IQ节语义学中对此有附加限定;见IQ Semantics (第九章第二节第三小节)。<br />
<br />
====type====<br />
<br />
:'type' 属性指明消息、出席信息或IQ节的意图或上下文的详细信息。'type'属性所允许的值依据节的类型是消息、出席信息还是IQ而有很大不同; 用于消息和出席信息节的值定义在即时消息和出席信息应用中,所以在[XMPP-IM|XMPP文档列表/XMPP正式RFC标准/RFC3921]中定义,反之用于IQ节的值定义了在一个 请求-应答 的“会话”中IQ节的角色,所以定义在IQ语义学中(第九章第二节第三小节)。 所有三种节的通用'type'值是"error";见Stanza Errors (第九章第三节)。<br />
<br />
====xml:lang====<br />
<br />
:如果一个节包含用于显示给人human user看的XML字符数据(在RFC 2277中有所解释[CHARSET],"internationalization is for humans"),这个节应该(SHOULD)处理一个'xml:lang'属性(定义在第二章第十二节[XML])。 'xml:lang'属性的值指明任何一个人类可读的XML字符数据的缺省语言, 它可以(MAY)被特定的子元素的'xml:lang'值重载。 如果一个节不处理一个'xml:lang'属性,一个实现必须(MUST)认为缺省的语言就是流属性中定义的语言(第四章第四节). 'xml:lang'属性值必须(MUST)是一个 NMTOKEN 并且必须(MUST)遵守 RFC 3066 [LANGTAGS]中定义的格式. <br />
<br />
===基本语义学===<br />
<br />
====消息语义学====<br />
<br />
:<message/>节类型可以被看作是一个"push"机制用于一个实体推送信息给另一个实体,类似发生在email系统中的通信. 所有消息节应该(SHOULD)处理一个表明预定的消息接收者的'to'属性;接收了这样一个节之后,一个服务器应该(SHOULD)路由或递送它给预定的接收者(见 Server Rules for Handling XML Stanzas (第十章)的XML节相关的通用路由和递送规则).<br />
<br />
====出席信息语义学====<br />
<br />
:<presence/> 元素可以被看作一个基本的广播或“出版-订阅”机制,用于多个实体接收某个已订阅的实体的信息(在这里,是网络可用性信息). 通常,一个发行实体应该(SHOULD)不带'to'属性发送一个出席信息,这时这个实体所连接的服务器应该(SHOULD)广播或多播(multiplex?)那个节给所有订阅的实体.无论如何,一个发行实体也可以(MAY)带'to'属性发送一个出席信息节,这时服务器应该(SHOULD)路由或递送这个节给预定的接收者.见 Server Rules for Handling XML Stanzas (第十章)的XML节相关的通用路由和递送规则,以及[XMPP-IM|XMPP文档列表/XMPP正式RFC标准/RFC3921]中即时消息和出席信息应用中出席信息的特定规则.<br />
<br />
====IQ语义学====<br />
<br />
:信息/查询(Info/Query),或曰IQ,是一个 请求-回应 机制,某些情况下类似[HTTP].IQ语义学使一个实体能够向另一个实体做出请求并做出应答. 请求和应答所包含的数据定义在IQ元素的一个直接的子元素的名字空间声明中, 并且由请求实体用'id'属性来跟踪这一交互行为. 因而,IQ交互伴随着一个结构化的数据交换的通用模式例如 get/result 或 set/result (尽管有时候会以一个错误信息应答某个请求):<br />
<br />
:以下是IQ的流程图,参见附件iq.png<br />
<br />
{image:img=iq}<br />
<br />
:为了强制执行这些语义学,要应用以下规则:<br />
<br />
:1. 对于IQ节来说'id'属性是必需的(REQUIRED).<br />
:2. 对于IQ节来说'type'属性是必需的(REQUIRED). 它的值必须(MUST)是以下之一:<br />
::* get -- 这个节是一个对信息或需求的请求.<br />
::* set -- 这个节提供需要的数据, 设置新的值, 或取代现有的值.<br />
::* result -- 这个节是一个对一个成功的 get 或 set 请求的应答.<br />
::* error -- 发生了一个错误,关于处理或递送上次发送的 get 或 set的(参见 节错误 Stanza Errors(第九章第三节)).<br />
:3. 一个接收到"get" 或 "set" 类型的IQ请求的实体必须(MUST)回复一个"result"或"error"类型的IQ应答(这个应答必须(MUST)保留相关请求的'id'属性).<br />
:4. 一个接收到"result"或"error"类型的IQ节的实体不能(MUST NOT)再发送更多的"result"或"error"类型的IQ应答; 无论如何, 如上所述, 请求实体可以(MAY)发送另一个请求(如, 一个"set"类型的IQ,通过get/result对提供查询(discovery)所需的信息).<br />
:5. 一个"get" 或 "set" 类型的IQ节必须(MUST)包含并只包含一个子元素指明特定请求或应答的语义.<br />
:6. 一个"result"类型的IQ节必须(MUST)包含零或一个子元素.<br />
:7. 一个"error"类型的IQ节应该(SHOULD)包含和"get"或"set"相关联的那个子元素并且必须(MUST)包含一个<error/>子元素;详细信息,见Stanza Errors (第九章第三节).<br />
<br />
===节错误===<br />
<br />
:节相关的错误的处理方式类似流错误(第四章第七节). 无论如何, 不像流错误, 节错误是可恢复的;所以错误节包含了暗示原来的发送者可以采取什么行动来补救这个错误.<br />
<br />
====规则====<br />
<br />
:以下规则适用于节相关的错误:<br />
<br />
:* 接收或处理实体察觉到一个节相关的错误条件时应该(MUST)返回给发送实体一个同类型的节(消息,出席信息,或IQ),这个节的'type'属性值则设置为"error"(这里这样的节称之为"error stanza").<br />
<br />
:* 生成一个错误节的实体应该(SHOULD)包含原来发送的XML,这样发送者可以检查它,并且如果必要,在尝试重新发送之前纠正它.<br />
<br />
:* 一个错误节必须(MUST)包含一个<error/>子元素.<br />
<br />
:* 如果'type'属性值不是"error"(或没有"type"属性),节不能(MUST NOT)包含一个<error/>子元素.<br />
<br />
:* 接收到一个错误节的实体不能(MUST NOT)应答这个节更多的错误节; 这有助于防止死循环.<br />
<br />
====语法====<br />
<br />
:节相关错误的语法如下:<br />
<br />
<source lang="xml"><br />
<stanza-kind to='sender' type='error'><br />
[RECOMMENDED to include sender XML here]<br />
<error type='error-type'><br />
<defined-condition xmlns='urn:ietf:params:xml:ns:xmpp-stanzas'/><br />
<text xmlns='urn:ietf:params:xml:ns:xmpp-stanzas' xml:lang='langcode'><br />
OPTIONAL descriptive text<br />
</text><br />
[OPTIONAL application-specific condition element]<br />
</error><br />
</stanza-kind><br />
</source><br />
<br />
:stanza-kind 是 message, presence, 或 iq 中的一个.<br />
<br />
:<error/> 元素的'type'属性值必须(MUST)是以下之一:<br />
<br />
:* cancel -- 不重试(这个错误是不可恢复的)<br />
<br />
:* continue -- 继续进行(这个条件只是一个警告)<br />
<br />
:* modify -- 改变数据之后重试<br />
<br />
:* auth -- 提供证书之后重试<br />
<br />
:* wait -- 等待之后重试(错误是暂时的)<br />
<br />
:<error/>元素:<br />
<br />
:* 必须(MUST)包含一个子元素,符合以下定义的节错误条件之一;这个元素(MUST)符合'urn:ietf:params:xml:ns:xmpp-stanzas'名字空间.<br />
<br />
:* 可以(MAY)包含一个<text/>子元素容纳XML字符数据用来描述错误的更多细节;这个元素必须(MUST)符合'urn:ietf:params:xml:ns:xmpp-stanzas'名字空间并且应该(SHOULD)处理'xml:lang'属性.<br />
<br />
:* 可以(MAY)包含一个应用程序定义的错误条件子元素;这个元素必须(MUST)符合一个应用程序定义的名字空间,并且它的结构由这个名字空间定义.<br />
<br />
:<text/>元素是可选的(OPTIONAL).如果包含它,它应该(SHOULD)仅用于提供描述或诊断信息以补充一个已定义的条件或应用程序定义的条件. 它不应(SHOULD NOT)被应用程序认为是一个程序性的. 它不应(SHOULD NOT)被用作向一个使用者展示的错误信息,但是可以(MAY)展示除条件元素(或元素们)相关的错误信息之外的信息.<br />
<br />
:最后,为了维护向后兼容性, 这个schema (定义在[XMPP-IM|XMPP文档列表/XMPP正式RFC标准/RFC3921])允许可选的在<error/>元素中包含一个("code")属性.<br />
<br />
====已定义的条件====<br />
<br />
:以下条件定义用于节错误.<br />
<br />
:* <bad-request/> -- 发送者发送的XML是不规范的或不能被处理(例如 一个IQ节包含了一个未被承认的'type'属性值); 相关的错误类型应该(SHOULD)是"modify".<br />
<br />
:* <conflict/> -- 不同意访问,因为相同的名字或地址已存在一个资源或会话;相关的错误类型应该( SHOULD)是"cancel".<br />
<br />
:* <feature-not-implemented/> -- 请求的特性未被接收者或服务器实现所以不能处理;相关的错误类型应该(SHOULD)是"cancel".<br />
<br />
:* <forbidden/> -- 请求实体没有必需的许可来执行这一动作;相关的错误类型应该(SHOULD)是"auth".<br />
<br />
:* <gone/> -- 接收者或服务器无法再以这个地址进行联系(错误节可以(MAY)在<gone/>元素的XML字符数据中包含一个新的地址);相关的错误类型应该(SHOULD)是"modify".<br />
<br />
:* <internal-server-error/> -- 服务器不能处理节,因为错误的配置或其他未定义的内部服务器错误;相关的错误类型应该(SHOULD)是"wait".<br />
<br />
:* <item-not-found/> -- JID地址或申请的条目无法找到;相关的错误类型应该(SHOULD)是"cancel".<br />
<br />
:* <jid-malformed/> -- 发送的实体提供的XMPP地址或与之通信的某个XMPP地址(如一个'to'属性值)或这个XMPP地址中的一部分(如一个资源ID)不符合寻址方案的语法(第三章);相关的错误类型应该(SHOULD)是"modify".<br />
<br />
:* <not-acceptable/> -- 接收者或服务器理解这个请求但是拒绝处理,因为它不符合某些接收者或服务器定义的标准(例如,一个关于消息中可接收的单词的本地策略);相关错误类型应该(SHOULD)是"modify".<br />
<br />
:* <not-allowed/> -- 接收者或服务器不允许任何实体执行这个动作;相关错误类型应该(SHOULD)是"cancel".<br />
<br />
:* <not-authorized/> -- 在被允许执行某个动作之前发送者必须提供适当的证书,或已提供了不正确的证书;相关错误类型应该(SHOULD)是"auth".<br />
<br />
:* <payment-required/> -- 请求实体未被授权访问请求的服务,因为需要付费;相关错误类型应该(SHOULD)是"auth".<br />
<br />
:* <recipient-unavailable/> -- 预定的接收者暂时不可用;相关错误类型应该(SHOULD)是"wait"(注意: 如果这样做会导致泄露预定接收者的网络可用性给一个未被授权了解此信息的实体,应用程序不应该(MUST NOT)返回这个错误).<br />
<br />
:* <redirect/> -- 接收者或服务器重定向这个请求信息到另一个实体,通常是暂时的(这个错误节应该 (SHOULD)在<redirect/>元素的XML字符数据中包含一个预备的地址,它必须(MUST)是一个合法的JID); 相关的错误类型应该(SHOULD)是"modify".<br />
<br />
:* <registration-required/> -- 请求实体未被授权访问请求的服务,因为需要注册;相关错误类型应该(SHOULD)是"auth".<br />
<br />
:* <remote-server-not-found/> -- 在预定的接收者的全部或部分JID中的一个远程服务器或服务不存在;相关错误类型应该(SHOULD)是"cancel".<br />
<br />
:* <remote-server-timeout/> -- 在预定的接收者(或需要完成的一个申请)的全部或部分JID中的一个远程服务器或服务无法在合理的时间内联系到;相关错误类型应该(SHOULD)是"wait".<br />
<br />
:* <resource-constraint/> -- 服务器或接收者缺乏足够的系统资源来服务请求;相关错误类型应该(SHOULD)是"wait".<br />
<br />
:* <service-unavailable/> -- 服务器或接收者目前无法提供被请求的服务;相关错误类型应该(SHOULD)是"cancel".<br />
<br />
:* <subscription-required/> -- 请求实体未被授权访问能请求的服务,因为需要订阅;相关错误类型应该(SHOULD)是"auth".<br />
<br />
:* <undefined-condition/> -- 错误条件不是本列表中定于的其他条件之一;任何错误类型可能和这个条件有关,并且它应该(SHOULD)仅用于关联一个应用程序定义的条件.<br />
<br />
:* <unexpected-request/> -- 接收者或服务器理解这个请求但是不希望是在这个时间(比如,请求的顺序颠倒);相关错误类型应该(SHOULD)是"wait".<br />
<br />
====应用程序定义条件====<br />
<br />
:大家知道,一个应用程序可以(MAY)通过在错误元素里包含一个适当名字空间的字元素来提供应用程序定义的节错误信息. 应用程序定义的元素应该(SHOULD)补充或进一步限定一个已定义的元素. 因而,<error/>元素将包含两个或三个子元素:<br />
<br />
<source lang="xml"><br />
<iq type='error' id='some-id'><br />
<error type='modify'><br />
<bad-request xmlns='urn:ietf:params:xml:ns:xmpp-stanzas'/><br />
<too-many-parameters xmlns='application-ns'/><br />
</error><br />
</iq><br />
<message type='error' id='another-id'><br />
<error type='modify'><br />
<undefined-condition xmlns='urn:ietf:params:xml:ns:xmpp-stanzas'/><br />
<text xml:lang='en' xmlns='urn:ietf:params:xml:ns:xmpp-stanzas'><br />
Some special application diagnostic information...<br />
</text><br />
<special-application-condition xmlns='application-ns'/><br />
</error><br />
</message><br />
</source><br />
<br />
==服务器处理XML节的规则==<br />
<br />
:兼容的服务器实现必须(MUST)确保两个实体之间的XML节按次序处理.<br />
<br />
:在按次序处理的需求之外, 每个服务器实现将包含它自己的递送树"delivery tree"以处理它接收到的节.这个树决定一个节是否需要路由到其他域, 在内部处理, 还是递送到和一个已连接的节点相关的资源. 以下规则适用:<br />
<br />
===没有'to'地址===<br />
<br />
:如果这个节没有'to'属性, 服务器应该(SHOULD)为发送它的实体处理这个节. 因为所有从其他服务器收到的节必须(MUST)拥有'to'属性, 这个规则仅适用于从一个连接到这台服务器的已注册实体(如一个客户端)收到的节.如果这个服务器收到一个没有'to'属性的出席信息节, 服务器应该(SHOULD)向那些订阅了这个发送实体的出席信息的所有实体广播它, 如果可能的话(即时消息和出席信息应用程序中出席信息广播的语义定义在[XMPP-IM|XMPP文档列表/XMPP正式RFC标准/RFC3921]). 如果服务器接收到一个类型为"get" 或 "set" 的没有'to'属性的节并且它理解这个节的名字空间下的内容, 它必须(MUST)为这个发送实体处理节(在这里"process"的含义是由相关的名字空间的语义所决定的)或返回一个错误给发送实体.<br />
<br />
===外部域===<br />
<br />
:如果'to'属性中的JID的域ID部分的主机名和服务器自身或其子域配置的主机名不匹配, 服务器应该(SHOULD)路由这个节到外部域(取决于本地服务规定或安全策略关于域间通信的规定).有两种可能的情况:<br />
<br />
::- 一个服务器之间的流已经存在于两个域之间: 发送者的服务器通过这个已存在的流为这个外部域路由这个节到授权服务器<br />
<br />
::- 两个域之间不存在服务器间的流: 发送者服务器 (1) 解析这个外部域的主机名(定义在服务器间的通信Server-to-Server Communications (第十四章第四节)), (2) 在两个域之间进行服务器到服务器的流协商(定义在 Use of TLS (第五章) 和 Use of SASL (第六章)), 然后 (3) 通过这个新建的流为外部域路由这个节到授权服务器<br />
<br />
:如果路由到接收者的服务器不成功, 发送者的服务器必须(MUST)返回一个错误给发送者; 如果接收者的服务器联系上了但是从接收者的服务器递送到接收者不成功, 接收者服务器必须(MUST)通过发送者的服务器返回一个错误给发送者.<br />
<br />
===子域===<br />
<br />
:如果'to'属性中的JID的域ID部分的主机名和服务器自身配置的主机名的一个子域名匹配,服务器必须(MUST)自己处理这个节或路由这个节到专门负责这个子域的特定服务(如果子域被配置了),或者返回一个错误给发送者(如果子域没有配置).<br />
<br />
===纯粹的域或特定的资源===<br />
<br />
:如果'to'属性中的JID的域ID部分的主机名和服务器自身配置的主机名本身匹配,并且'to'属性中的JID类型是<domain> 或 <domain/resource>, 服务器(或其中定于的资源)必须(MUST)根据节的类型适当的处理这个节或返回一个错误节给发送者.<br />
<br />
===同一域中的节点===<br />
<br />
:如果'to'属性中的JID的域ID部分的主机名和服务器自身配置的主机名本身匹配,并且'to'属性中的JID类型是<node@domain> 或 <node@domain/resource>, 服务器应该(SHOULD)递送这个节到节的'to'属性中的JID所指明的预定的接收者. 以下规则适用:<br />
<br />
:# 如果这个JID包含一个资源ID(例如, 格式是<node@domain/resource>)并且存在一个连接的资源符合这个全JID, 接收者服务器应该(SHOULD)递送这个节给正确符合这个资源ID的流或会话.<br />
:# 如果这个JID包含一个资源ID(例如, 格式是<node@domain/resource>)并且不存在一个连接的资源符合这个全JID, 接收者服务器应该(SHOULD)返回一个<service-unavailable/> 节错误给发送者.<br />
:# 如果这个JID的格式是<node@domain>并且存在至少一个此节点的连接资源, 接收服务器应该( SHOULD)递送这个节给至少其中一个已连接的资源, 依据应用程序定义的规则(一系列即时消息和出席信息应用程序的递送规则定义在[XMPP-IM|XMPP文档列表/XMPP正式RFC标准/RFC3921]).<br />
<br />
==XMPP中的XML用法==<br />
<br />
===限制===<br />
<br />
:XMPP是一个简单的流式XML元素的专用协议用于接近实时地交换结构化信息. 因为XMPP不需要任意的解析和所有的XML文档, 所以XMPP不需要支持[XML]的所有功能. 特殊的, 适用以下限制.<br />
<br />
:关于XML生成, 一个XMPP实现不能(MUST NOT)在XML流中注入以下任何东西:<br />
<br />
:* 注释 (第二章第五节[XML])<br />
<br />
:* 处理指示(第二章第六节 同上)<br />
<br />
:* 内部或外部的 DTD 子集 (第二章第八节 同上)<br />
<br />
:* 内部或外部的实体参考 (第四章第二节 同上) 除了预定实体以外(第四章第六节 同上)<br />
<br />
:* 字符数据或属性值包含和预定实体列表中吻合的未逃逸的unescaped字符(第四章第六节 同上); 这些字符必须(MUST)逃逸<br />
<br />
:关于XML处理, 如果一个XMPP实现接收到这些受限的XML数据,它必须(MUST)忽略这些数据.<br />
<br />
===XML 名字空间的名字和前缀===<br />
<br />
:XML名字空间[XML-NAMES]为所有XMPP兼容的XML建立数据所有权的严格界限. 这个名字空间的基本功能是把结构上混合在一起的XML元素区分出不同的词汇. 确保XMPP兼容的XML有名字空间的感知能力使得任何允许的XML可以被结构化的混合到任何XMPP数据元素中. XML名字空间的名字和前缀的规则在下一小节中.<br />
<br />
====流名字空间====<br />
<br />
:在所有的XML流头中必须声明一个流名字空间. 流名字空间必须(MUST)是 'http://etherx.jabber.org/streams'. 元素名<stream/>和它的<features/>和<error/>子元素必须(MUST)在所有实例中符合这个流名字空间前缀. 一个实现应该(SHOULD)只为这些元素生成'stream:'前缀, 并且由于历史原因可以(MAY)只接受'stream:'前缀.<br />
<br />
====缺省名字空间====<br />
<br />
:在所有的XML流中必须声明一个缺省的流名字空间用于定义允许的流根元素的一级子元素. 这个名字空间声明对于初始化流和应答流必须(MUST)是相同的使得双方的流都是合格一致的. 缺省的名字空间声明适用于流和所有在流中发送的节(除非由流名字空间或回拨名字空间的前缀显式的符合另一个名字空间).<br />
<br />
:一个服务器实现必须(MUST)支持以下两个缺省名字空间(由于历史原因, 一些实现可能(MAY)只支持这两个缺省名字空间):<br />
<br />
:* jabber:client -- 当流用于客户端和服务器的通信时声明这个缺省名字空间<br />
<br />
:* jabber:server -- 当流用于两个服务器间的通信时声明这个缺省名字空间<br />
<br />
:一个客户端实现必须(MUST)支持'jabber:client'缺省名字空间,并且由于历史原因可以(MAY)只支持这个缺省名字空间.<br />
<br />
:如果缺省名字空间是'jabber:client'或'jabber:server',一个实施不能(MUST NOT)在这个名字空间下为元素生成名字空间前缀. 一个实现不应该(SHOULD NOT)按照元素的内容(可能和流相反)生成不同于'jabber:client'和'jabber:server'名字空间前缀.<br />
<br />
:注意: 'jabber:client' 和 'jabber:server' 名字空间接近于相同但是用于不同的上下文(客户端服务器通信用'jabber:client' 而服务器间通信用'jabber:server'). 这两者之间仅有的不同在于在'jabber:client'中被发送的节中'to'和'from'属性是可选的(OPTIONAL),而在'jabber:server'中被发送的节中它们是必需的(REQUIRED). 如果兼容的实施接受一个符合'jabber:client'或'jabber:server'名字空间的流, 它必须(MUST)支持通用属性(第九章第一节)和三个核心节类型(message, presence, 和IQ)的基本语义(第九章第二节).<br />
<br />
====回拨名字空间====<br />
<br />
:所有用于服务器回拨的(第八章)元素都必须声明一个回拨名字空间. 回拨名字空间的名字必须(MUST)是'jabber:server:dialback'. 所有符合此名字空间的元素必须(MUST)有前缀. 一个实现应该(SHOULD)只为这些元素生成'db:'前缀并且只可以(MAY)接受'db:'前缀.<br />
<br />
===确认===<br />
<br />
:除了注意'jabber:server'名字空间中关于节中'to'和'from'地址的规定,一个服务器不需要为转发到客户端或其他服务器负责检查XML元素;一个实现可以(MAY)选择仅提供有效数据元素但这是可选的(OPTIONAL)(尽管一个实现不能(MUST NOT)接受不规范的XML). 客户端不应该(SHOULD NOT)滥用发送不符合schema的数据的能力, 并且应该(SHOULD)忽略接收到的XML流中任何和schema不一致的元素或属性值. XML流和节的有效性确认是可选的(OPTIONAL),并且在这里提到的schemas仅用于描述的用途.<br />
<br />
===文本声明的包含===<br />
<br />
:实现应该(SHOULD)在发送一个流头信息之前发送一个文本声明. 应用程序必须(MUST)遵守[XML]中关于环境(那里对文本声明做了规定)的规则.<br />
<br />
===字符编码===<br />
<br />
:实现必须(MUST)支持通用字符集Universal Character Set (ISO/IEC 10646-1 [UCS2])字符到UTF-8(RFC 3629 [UTF-8])的转换, 必须符合 RFC 2277 [CHARSET]. 实现不能(MUST NOT)试图使用任何其他的编码.<br />
<br />
==核心的兼容性要求==<br />
<br />
:本章总结了可扩展的消息和出席信息协议中的某些方面,为了实施的兼容性,它们必须(MUST)被服务器和客户端支持,当然协议的其他方面也应该(SHOULD)被支持. 为了兼容的目的, 我们在核心协议(它必须(MUST)被任何服务器或客户端支持, 无论是什么特定的应用)和即时消息协议(仅仅是在核心协议之上的即时消息和出席信息应用必须(MUST)支持它)之间划了一个级别. 在本章中定义了所有服务器和客户端的兼容性要求; 即时消息服务器和客户端的兼容性要求在[XMPP-IM|XMPP文档列表/XMPP正式RFC标准/RFC3921]的相关章节中定义.<br />
<br />
===服务器===<br />
<br />
:除了所有已定义的关于安全, XML使用, 和国际化的要求之外, 一个服务器还必须(MUST)支持以下核心协议以保证兼容性:<br />
<br />
:* 在地址中应用[STRINGPREP] 的 [NAMEPREP], Nodeprep (附录 A),和 Resourceprep (附录 B) profiles (包括确保域ID是[IDNA]中定义的国际化域名)<br />
<br />
:* XML流(第四章), 包括Use of TLS(第五章), Use of SASL(第六章), 和Resource Binding (第七章)<br />
<br />
:* 三个在stanza semantics(第九章第二节)中已定义的节类型(即,<message/>, <presence/>, 和<iq/>)的基本语义<br />
<br />
:* 生成错误的语法及相关的流, TLS, SASL, 和 XML节的语义<br />
<br />
:另外, 一个服务器可以(MAY)支持以下核心协议:<br />
<br />
:* 服务器回拨 (第八章)<br />
<br />
===客户端===<br />
<br />
:一个客户端必须(MUST)支持以下核心协议以满足兼容性:<br />
<br />
:* XML流(第四章), 包括Use of TLS(第五章), Use of SASL(第六章), 和Resource Binding (第七章)<br />
<br />
:* 三个在stanza semantics(第九章第二节)中已定义的节类型(即,<message/>, <presence/>, 和<iq/>)的基本语义<br />
<br />
:* 处理(并且, 如果可能, 生成) 错误的语法及相关的流, TLS, SASL, 和 XML节的语义<br />
<br />
:另外, 一个客户端应该(SHOULD)支持以下核心协议:<br />
<br />
:* 地址的生成应用[STRINGPREP] 的 [NAMEPREP], Nodeprep (附录 A),和 Resourceprep (附录 B) profiles <br />
<br />
==国际化事项==<br />
<br />
:XML流在Character Encoding(第十一章第五节)中定义为必须(MUST)被编码成UTF-8. 在Stream Attributes(第四章第四节)中特别定义了, 一个XML流应该(SHOULD)包含一个'xml:lang'属性,它被认为是通过这个用于人类用户解读的流发送的任何XML字符数据的缺省语言. 在 xml:lang (第九章第一节第五小节)特别定义了, 如果一个XML节是用来给人类用户解读,这个节应该(SHOULD)包含一个'xml:lang'属性. 服务器在为连接的实体路由或递送节的时候应该(SHOULD)应用缺省的'xml:lang'属性, 并且不能(MUST NOT)修改或删除它从其他实体收到的节的'xml:lang'属性.<br />
<br />
==安全性事项==<br />
<br />
===高安全性===<br />
<br />
:为了XMPP通信的目的(客户端-服务器 和 服务器-服务器), "高安全性"条款谈的是相互验证和完整性检查安全性技术的使用; 特别是, 当使用基于证书的验证来提供高安全性, 应该( SHOULD)建立一个带外的信任链,尽管一个共享签名证书可能允许以前不知道的证书在带内建立信任关系. 参见以下第十四章第二节关于证书确认程序.<br />
<br />
:实施必须(MUST)支持高安全性. 服务提供者应该(SHOULD)基于本地安全策略使用高安全性.<br />
<br />
===证书确认===<br />
<br />
:当一个XMPP点和另一个XMPP点安全的地通信, 它必须(MUST)确认对方终端的证书.有三种可能的情况:<br />
<br />
:情形 #1: 点包含一个终端实体证书,以根证书的证书链中一环出现(见[X509]中的第六章第一节).<br />
<br />
:情形 #2: 点的证书由一个对方不知道的证书授权.<br />
<br />
:情形 #3: 点的证书由自己签名.<br />
<br />
:在情形#1, 确认方必须(MUST)做以下两条之一:<br />
<br />
:# 根据[X509]的规则确认对方证书.然后证书应该(SHOULD)被对方接下来在[HTTP-TLS]中描述的规则反向确认预期的身份。但如果"xmpp"是subjectAltName扩展类型,则必须(MUST)使用证书中的显示的身份。如果这两项检查之一失败,用户导向的客户端必须(MUST)通知用户(客户端可以(MAY)给用户机会继续连接)或以一个坏证书的错误终止连接。自动客户端应该(SHOULD)终止连接(以一个坏证书错误)并在适当的日志中记录这个错误。自动客户端可以(MAY)提供一个配置设置成禁止检查,但同时必须(MUST)提供一个激活检查的配置。<br />
:# 点应该(SHOULD)出示证书给一个用户用于批准,包括完整的证书链.点必须(MUST)缓存这个证书(或一些其他不会忘记的表达方式比如一个哈希值).在将来的连接中,点必须(MUST)展示相同的证书并且如果改变了证书必须(MUST)通知用户.<br />
<br />
:在情形#2 和情形#3, 实现应该(SHOULD)执行上述第二条.<br />
<br />
===客户端-服务器通信===<br />
<br />
:一个兼容的客户端实现必须(MUST)支持TLS和SASL用于连接到服务器.<br />
<br />
:用于加密XML流的TLS协议(在 Use of TLS(第五章)定义)提供可信的机制帮助确保机密性和实体之间数据交换的完整性.<br />
<br />
:用于验证XML流的SASL协议(在 Use of SASL(第六章)定义)提供可靠的机制用于确认一个连接到服务器的客户端确实是它自己所声明的那个客户端.<br />
<br />
:服务器宣称的DNS主机名被解析之前,客户端-服务器通信不能(MUST NOT)继续进行。应该首先尝试解析[SRV]记录,其服务名为"xmpp-client",协议名为"tcp",整个资源记录类似"_xmpp-client._tcp.example.com."(使用字符"xmpp-client"表示服务ID是经过IANA注册).如果SRV查找失败,退而求其次,将查找一个正规的IPv4/IPv6地址记录来决定IP地址,使用"xmpp-client"端口5222,这个端口是在IANA注册了的。<br />
<br />
:客户端的IP地址和访问方法不能(MUST NOT)被服务器公开, 也不能被被任何原始服务器之外的服务器索取。这帮助保护客户端的服务器避免受到直接攻击(译者注:似乎应该是客户避免受到直接攻击,但原文如此)或被第三方知道它的身份。<br />
<br />
===服务器-服务器通信===<br />
<br />
:一个兼容的服务器实现必须(MUST)支持TLS和SASL,用于域间的通信.因为历史原因,一个兼容的实施也应该(SHOULD)支持服务器回拨(第八章).<br />
<br />
:因为服务提供者是一个策略问题,对于任何给定域和其他域的通信中,它是可选的(OPTIONAL),服务器之间的通信可以(MAY)被任何特定部署的管理员禁止。如果一个特殊的域允许域间的通信,它应该(SHOULD)允许高安全性。<br />
<br />
:管理员可能想在服务器间使用SASL来通信,以确保双方的验证和保密性(比如在机构的私有网络).兼容实施应该(SHOULD)为这个目的支持SASL.<br />
<br />
:服务器宣称的DNS主机名被解析之前,服务器-服务器通信不能(MUST NOT)继续进行。应该首先尝试解析[SRV]记录,其服务名为"xmpp-server",协议名为"tcp",整个资源记录类似"_xmpp-server._tcp.example.com."(使用字符"xmpp-server"表示服务ID是经过IANA注册的,注意要用"xmpp-server"取代以前用的"jabber",因为以前的用法不符合[SRV]标准;希望保持向后兼容的实现可以继续查找或应答"jabber"服务ID).如果SRV查找失败,退而求其次,将查找一个正规的IPv4/IPv6地址记录来决定IP地址,使用"xmpp-server"端口5269,这个端口是在IANA注册了的。<br />
<br />
:服务器回拨防止域欺骗,从而使得伪造XML节更为困难.它和SASL和TLS不一样,它不是一个用于验证、安全或加密服务器之间的流的机制, 所以只是服务器身份的微弱确认而已。而且除非它使用了DNSSec [DNSSEC]否则它 容易受到DNS中毒攻击,即使DNS信息是正确的,如果攻击者劫持了远程域,回拨也不能防止它的攻击.需要健壮的安全性的域应该(SHOULD)使用TLS和SASL.如果服务器间的验证使用了SASL,回拨就不应该(SHOULD NOT)使用了,因为它是多余的.<br />
<br />
===层的次序===<br />
<br />
:协议中的层的次序必须(MUST)如下堆积:<br />
<br />
:# TCP<br />
:# TLS<br />
:# SASL<br />
:# XMPP<br />
<br />
:这个次序的原理是,[TCP]是基于连接的层,被所有使用,所以处于最上层, [TLS]经常是由操作系统层提供,[SASL]经常由应用程序层提供, XMPP则是应用程序本身.<br />
<br />
===缺乏绑定到TLS的SASL通道===<br />
<br />
:SASL构架不提供一个机制来绑定SASL验证到一个提供机密性和完整性保护的安全层。这一通道绑定"channel binding"的缺乏阻碍了SASL确认低层安全性所绑定的源和目标终端和SASL所验证的结果是否一致。如果终端不一致, 低层安全性不能被信任用来保护SASL验证的实体之间的数据传输。在这种情况下,一个SASL安全层进行握手的时候应该有效的忽略低层安全性的存在。<br />
<br />
===强制实现的技术===<br />
<br />
:最低要求, 所有实现必须(MUST)支持以下机制:<br />
<br />
::对于验证: SASL [DIGEST-MD5] 机制<br />
<br />
::对于机密性: TLS (使用 TLS_RSA_WITH_3DES_EDE_CBC_SHA 密码)<br />
<br />
::对于两者: TLS 加 SASL EXTERNAL(使用 TLS_RSA_WITH_3DES_EDE_CBC_SHA 密码支持客户端证书)<br />
<br />
===防火墙===<br />
<br />
:使用XMPP通信通常是通过[TCP]连接到5222端口(客户端-服务器)或5269端口(服务器-服务器), 正如在IANA注册的那样(见 IANA Considerations (第十五章)). 使用这些广为人知的端口允许管理员很容易的通过一般的防火墙来激活或禁止XMPP活动.<br />
<br />
===在SASL中使用base64===<br />
<br />
:客户端和服务器都必须(MUST)确认在SASL协商中收到的任何[BASE64]数据. 一个实现必须(MUST)拒绝(不是忽略)任何非显式允许base64字母的字符串; 这有助于预防建立隐蔽通道泄漏信息的行为。一个实现不能(MUST NOT)在非法输入处中断,如果那个('=')被包含在一些和最后的数据字符(如, "=AAA" or "BBBB=CCC")不同的东西里面,必须(MUST)拒绝接下来的任何包含('=')的base64字符;这有助于防止对这个实现的缓存溢出攻击和其他攻击。Base 64编码从外表看隐藏了容易辨认的信息,例如密码,但是不提供任何算法机密性。Base 64编码必须(MUST)按照RFC 3548[BASE64]第三章的定义执行。<br />
<br />
===Stringprep Profiles===<br />
<br />
:为了处理域ID,XMPP使用了[STRINGPREP]中的[NAMEPREP] profile; 和Nameprep有关的安全性考虑, 参考[NAMEPREP]中的相关章节.<br />
<br />
:另外, XMPP 定义了两个[STRINGPREP]的 profiles: 用于node identifiers的Nodeprep(附录 A)和用于resource identifiers的Resourceprep(附录 B).<br />
<br />
:Unicode 和 ISO/IEC 10646 集有许多字符看起来相似. 在许多时候, 安全协议的使用者可能看起来吻合,比如当比较信任的第三方的名字的时候. 因为没有很多上下文的时候不可能映射看起来相似的字符,比如知道所用的字符集, stringprep不匹配相似字符串,也不因为一些字符串象看起来象别的字符串而禁止它们.<br />
<br />
:一个节点ID可能被作为一个实体的XMPP地址的一部分. 一个通常的用途是作为一个即时消息用户的用户名;另一个用途是作为一个多用途聊天室的名字; 很多其他种类的实体可能使用节点ID作为他们的地址的一部分。 这些服务的安全性可能会受到国际化节点ID的不同表达的威胁;例如, 一个用户键入一个单独的国际化的节点ID可能访问了另一个用户的帐号信息, 或一个用户可能获得访问一个受限的聊天室或服务的访问权限.<br />
<br />
:一个资源ID可能被作为一个实体的XMPP地址的一部分。一个通常的用户是即时消息用户所连接的资源(激活的会话)的名字; 另一个是作为多用户聊天室的某用户的昵称; 许多其他种类的实体可能使用资源ID作为他们地址的一部分.这些服务的安全性可能会受到国际化资源ID的不同表达的威胁;例如, 一个用户可能尝试以同一个名字初始化多个会话,或一个用户可能发送一个消息给多用户聊天室的一个人但实际上发给了另外一个人.<br />
<br />
==IANA 事项==<br />
<br />
===用于TLS数据的XML名字空间名===<br />
<br />
:XMPP中用于TLS相关数据的 URN 子名字空间定义如下. (这个名字空间的名字遵守The IETF XML Registry [XML-REG]定义的格式.)<br />
<br />
::URI: urn:ietf:params:xml:ns:xmpp-tls<br />
<br />
::Specification: RFC 3920<br />
<br />
::Description: This is the XML namespace name for TLS-related data in the Extensible Messaging and Presence Protocol (XMPP) as defined by RFC 3920.<br />
<br />
::Registrant Contact: IETF, XMPP Working Group, <xmppwg@jabber.org><br />
<br />
===用于SASL数据的XML名字空间名===<br />
<br />
:XMPP中用于SASL相关数据的 URN 子名字空间定义如下. (这个名字空间的名字遵守The IETF XML Registry [XML-REG]定义的格式.)<br />
<br />
::URI: urn:ietf:params:xml:ns:xmpp-sasl<br />
<br />
::Specification: RFC 3920<br />
<br />
::Description: This is the XML namespace name for SASL-related data in the Extensible Messaging and Presence Protocol (XMPP) as defined by RFC 3920.<br />
<br />
::Registrant Contact: IETF, XMPP Working Group, <xmppwg@jabber.org><br />
<br />
===用于流错误的XML名字空间名===<br />
<br />
:XMPP中用于流相关错误的 URN 子名字空间定义如下. (这个名字空间的名字遵守The IETF XML Registry [XML-REG]定义的格式.)<br />
<br />
::URI: urn:ietf:params:xml:ns:xmpp-streams<br />
<br />
::Specification: RFC 3920<br />
<br />
:Description: This is the XML namespace name for stream-related error data in the Extensible Messaging and Presence Protocol (XMPP) as defined by RFC 3920.<br />
<br />
::Registrant Contact: IETF, XMPP Working Group, <xmppwg@jabber.org><br />
<br />
===用于资源绑定的XML名字空间名===<br />
<br />
:XMPP中用于资源绑定的 URN 子名字空间定义如下. (这个名字空间的名字遵守The IETF XML Registry [XML-REG]定义的格式.)<br />
<br />
::URI: urn:ietf:params:xml:ns:xmpp-bind<br />
<br />
::Specification: RFC 3920<br />
<br />
::Description: This is the XML namespace name for resource binding in the Extensible Messaging and Presence Protocol (XMPP) as defined by RFC 3920.<br />
<br />
::Registrant Contact: IETF, XMPP Working Group, <xmppwg@jabber.org><br />
<br />
===用于节错误的XML名字空间名===<br />
<br />
:XMPP中用于节相关错误数据的 URN 子名字空间定义如下. (这个名字空间的名字遵守The IETF XML Registry [XML-REG]定义的格式.)<br />
<br />
::URI: urn:ietf:params:xml:ns:xmpp-stanzas<br />
<br />
::Specification: RFC 3920<br />
<br />
::Description: This is the XML namespace name for stanza-related error data in the Extensible Messaging and Presence Protocol (XMPP) as defined by RFC 3920.<br />
<br />
::Registrant Contact: IETF, XMPP Working Group, <xmppwg@jabber.org><br />
<br />
===Nodeprep Profile of Stringprep===<br />
<br />
:The Nodeprep profile of stringprep是在Nodeprep(附录 A)定义的. IANA已经在stringprep profile registry中注册了 Nodeprep.<br />
<br />
::Name of this profile:<br />
<br />
:::Nodeprep<br />
<br />
::RFC in which the profile is defined:<br />
<br />
:::RFC 3920<br />
<br />
::Indicator whether or not this is the newest version of the profile:<br />
<br />
:::This is the first version of Nodeprep<br />
<br />
===Resourceprep Profile of Stringprep===<br />
<br />
:The Resourceprep profile of stringprep是在Resourceprep(附录 B)定义的. IANA已经在stringprep profile registry中注册了Resourceprep.<br />
<br />
::Name of this profile:<br />
<br />
:::Resourceprep<br />
<br />
::RFC in which the profile is defined:<br />
<br />
:::RFC 3920<br />
<br />
::Indicator whether or not this is the newest version of the profile:<br />
<br />
:::This is the first version of Resourceprep<br />
<br />
===GSSAPI 服务名===<br />
<br />
:IANA已经注册了 "xmpp" 作为一个 GSSAPI [GSS-API] 服务名, 在SASL Definition (第六章第三节)定义了.<br />
<br />
===端口号===<br />
<br />
:IANA已经注册了"xmpp-client" 和 "xmpp-server" 作为[TCP]端口号5222和5269的关键字.<br />
<br />
:这些端口应该(SHOULD)用于客户端-服务器 和 服务器-服务器通信,但它们的使用是可选的(OPTIONAL).<br />
<br />
==参考==<br />
<br />
===标准化参考===<br />
<br />
:[ABNF] Crocker, D. and P. Overell, "Augmented BNF for Syntax Specifications: ABNF", RFC 2234, November 1997.<br />
<br />
:[BASE64] Josefsson, S., "The Base16, Base32, and Base64 Data Encodings", RFC 3548, July 2003.<br />
<br />
:[CHARSET] Alvestrand, H., "IETF Policy on Character Sets and Languages", BCP 18, RFC 2277, January 1998.<br />
<br />
:[DIGEST-MD5] Leach, P. and C. Newman, "Using Digest Authentication as a SASL Mechanism", RFC 2831, May 2000.<br />
<br />
:[DNS] Mockapetris, P., "Domain names - implementation and specification", STD 13, RFC 1035, November 1987.<br />
<br />
:[GSS-API] Linn, J., "Generic Security Service Application Program Interface Version 2, Update 1", RFC 2743, January 2000.<br />
<br />
:[HTTP-TLS] Rescorla, E., "HTTP Over TLS", RFC 2818, May 2000.<br />
<br />
:[IDNA] Faltstrom, P., Hoffman, P., and A. Costello, "Internationalizing Domain Names in Applications (IDNA)", RFC 3490, March 2003.<br />
<br />
:[IPv6] Hinden, R. and S. Deering, "Internet Protocol Version 6 (IPv6) Addressing Architecture", RFC 3513, April 2003.<br />
<br />
:[LANGTAGS] Alvestrand, H., "Tags for the Identification of Languages", BCP 47, RFC 3066, January 2001.<br />
<br />
:[NAMEPREP] Hoffman, P. and M. Blanchet, "Nameprep: A Stringprep Profile for Internationalized Domain Names (IDN)", RFC 3491, March 2003.<br />
<br />
:[RANDOM] Eastlake 3rd, D., Crocker, S., and J. Schiller, "Randomness Recommendations for Security", RFC 1750, December 1994.<br />
<br />
:[SASL] Myers, J., "Simple Authentication and Security Layer (SASL)", RFC 2222, October 1997.<br />
<br />
:[SRV] Gulbrandsen, A., Vixie, P., and L. Esibov, "A DNS RR for specifying the location of services (DNS SRV)", RFC 2782, February 2000.<br />
<br />
:[STRINGPREP] Hoffman, P. and M. Blanchet, "Preparation of Internationalized Strings ("stringprep")", RFC 3454, December 2002.<br />
<br />
:[TCP] Postel, J., "Transmission Control Protocol", STD 7, RFC 793, September 1981.<br />
<br />
:[TERMS] Bradner, S., "Key words for use in RFCs to Indicate Requirement Levels", BCP 14, RFC 2119, March 1997.<br />
<br />
:[TLS] Dierks, T. and C. Allen, "The TLS Protocol Version 1.0", RFC 2246, January 1999.<br />
<br />
:[UCS2] International Organization for Standardization, "Information Technology - Universal Multiple-octet coded Character Set (UCS) - Amendment 2: UCS Transformation Format 8 (UTF-8)", ISO Standard 10646-1 Addendum 2, October 1996.<br />
<br />
:[UTF-8] Yergeau, F., "UTF-8, a transformation format of ISO 10646", STD 63, RFC 3629, November 2003.<br />
<br />
:[X509] Housley, R., Polk, W., Ford, W., and D. Solo, "Internet X.509 Public Key Infrastructure Certificate and Certificate Revocation List (CRL) Profile", RFC 3280, April 2002.<br />
<br />
:[XML] Bray, T., Paoli, J., Sperberg-McQueen, C., and E. Maler, "Extensible Markup Language (XML) 1.0 (2nd ed)", W3C REC-xml, October 2000, <http://www.w3.org/TR/REC-xml>.<br />
<br />
:[XML-NAMES] Bray, T., Hollander, D., and A. Layman, "Namespaces in XML", W3C REC-xml-names, January 1999, <http://www.w3.org/TR/REC-xml-names>.<br />
<br />
===信息参考===<br />
<br />
:[ACAP] Newman, C. and J. Myers, "ACAP -- Application Configuration Access Protocol", RFC 2244, November 1997.<br />
<br />
:[ASN.1] CCITT, "Recommendation X.208: Specification of Abstract Syntax Notation One (ASN.1)", 1988.<br />
<br />
<br />
:[DNSSEC] Eastlake 3rd, D., "Domain Name System Security Extensions", RFC 2535, March 1999.<br />
<br />
:[HTTP] Fielding, R., Gettys, J., Mogul, J., Frystyk, H., Masinter, L., Leach, P., and T. Berners-Lee, "Hypertext Transfer Protocol -- HTTP/1.1", RFC 2616, June 1999.<br />
<br />
:[IMAP] Crispin, M., "INTERNET MESSAGE ACCESS PROTOCOL - VERSION 4rev1", RFC 3501, March 2003.<br />
<br />
:[IMP-REQS] Day, M., Aggarwal, S., Mohr, G., and J. Vincent, "Instant Messaging \/ Presence Protocol Requirements", RFC 2779, February 2000.<br />
<br />
:[IRC] Oikarinen, J. and D. Reed, "Internet Relay Chat Protocol", RFC 1459, May 1993.<br />
<br />
:[JEP-0029] Kaes, C., "Definition of Jabber Identifiers (JIDs)", JSF JEP 0029, October 2003.<br />
<br />
:[JEP-0078] Saint-Andre, P., "Non-SASL Authentication", JSF JEP 0078, July 2004.<br />
<br />
[JEP-0086] Norris, R. and P. Saint-Andre, "Error Condition Mappings", JSF JEP 0086, February 2004.<br />
<br />
:[JSF] Jabber Software Foundation, "Jabber Software Foundation", <http://www.jabber.org/>.<br />
<br />
:[POP3] Myers, J. and M. Rose, "Post Office Protocol - Version 3", STD 53, RFC 1939, May 1996.<br />
<br />
:[SIMPLE] SIMPLE Working Group, "SIMPLE WG", <http://www.ietf.org/html.charters/simple-charter.html>.<br />
<br />
:[SMTP] Klensin, J., "Simple Mail Transfer Protocol", RFC 2821, April 2001.<br />
<br />
:[URI] Berners-Lee, T., Fielding, R., and L. Masinter, "Uniform Resource Identifiers (URI): Generic Syntax", RFC 2396, August 1998.<br />
<br />
:[USINGTLS] Newman, C., "Using TLS with IMAP, POP3 and ACAP", RFC 2595, June 1999.<br />
<br />
:[XML-REG] Mealling, M., "The IETF XML Registry", BCP 81, RFC 3688, January 2004.<br />
<br />
:[[RFC3921]] Saint-Andre, P., Ed., "Extensible Messaging and Presence Protocol (XMPP): Instant Messaging and Presence", RFC 3921, October 2004.<br />
<br />
<br />
==附录 A. Nodeprep==<br />
<br />
===A.1. 介绍===<br />
<br />
:这个附录定义了 "Nodeprep" profile of [STRINGPREP]. 它定义了处理规则让用户能够在XMPP中输入国际化节点标识符并尽可能正确的获取正确的字符内容. (一个XMPP节点标识符是XMPP地址的可选部分,它在域名标识符和那个'@'分隔符之前;它经常但不是专门用来关联一个即时消息用户名)这些处理规则仅仅适用于XMPP节点标识符但不适用于任意文本或任何XMPP的其他方面.<br />
<br />
:这个脚本定义了以下这些, 正如 [STRINGPREP]要求的:<br />
<br />
:* 脚本预期的适用性: XMPP的国际化节点标识符<br />
<br />
:* 用于stringprep的输入输出字符集: Unicode 3.2, 定义在本附录的第二章<br />
<br />
:* 使用的映射: 定义在第三章<br />
<br />
:* Unicode正规化使用: 定义在第四章<br />
<br />
:* 禁止输出的字符串: 定义在第五章<br />
<br />
:* 双字节字符处理: 定义在第六章<br />
<br />
===A.2. 字符集===<br />
<br />
:本脚本使用Unicode 3.2的未分配编码列表,指向 Table A.1, 也定义在 [STRINGPREP]的附录 A 中.<br />
<br />
===A.3. 映射===<br />
<br />
:本脚本指定使用[STRINGPREP]的以下表:<br />
<br />
::Table B.1<br />
<br />
::Table B.2<br />
<br />
===A.4. 正规化===<br />
<br />
:本脚本指定 Unicode正规化使用 form KC, 定义在 [STRINGPREP]中.<br />
<br />
===A.5. 禁止输出===<br />
<br />
:本脚本指定使用以下的[STRINGPREP]表禁止输出.<br />
<br />
::Table C.1.1<br />
<br />
::Table C.1.2<br />
<br />
::Table C.2.1<br />
<br />
::Table C.2.2<br />
<br />
::Table C.3<br />
<br />
::Table C.4<br />
<br />
::Table C.5<br />
<br />
::Table C.6<br />
<br />
::Table C.7<br />
<br />
::Table C.8<br />
<br />
::Table C.9<br />
<br />
:另外, 以下Unicode字符也被禁止:<br />
<br />
: #x22 (")<br />
<br />
: #x26 (&)<br />
<br />
: #x27 (')<br />
<br />
: #x2F (/)<br />
<br />
: #x3A (:)<br />
<br />
: #x3C (<)<br />
<br />
: #x3E (>)<br />
<br />
: #x40 (@)<br />
<br />
===A.6. 双字节===<br />
<br />
:本脚本指定按照[STRINGPREP]第六章检查双字节.<br />
<br />
==附录 B. Resourceprep==<br />
<br />
===B.1. 介绍===<br />
<br />
:这个附录定义了 "Resourceprep" profile of [STRINGPREP]. 它定义了处理规则让用户能够在XMPP中输入国际化资源标识符并尽可能正确的获取正确的字符内容. (一个XMPP资源标识符是XMPP地址的可选部分,它在域名标识符和'/'分隔符之后;它经常但不是专门用来关联一个即时消息会话名)这些处理规则仅仅适用于XMPP资源标识符但不适用于任意文本或任何XMPP的其他方面.<br />
<br />
:这个脚本定义了以下这些, 正如 [STRINGPREP]要求的:<br />
<br />
:* 脚本预期的适用性: XMPP的国际化节点标识符<br />
<br />
:* 用于stringprep的输入输出字符集: Unicode 3.2, 定义在本附录的第二章<br />
<br />
:* 使用的映射: 定义在第三章<br />
<br />
:* Unicode正规化使用: 定义在第四章<br />
<br />
:* 禁止输出的字符串: 定义在第五章<br />
<br />
:* 双字节字符处理: 定义在第六章<br />
<br />
===B.2. 字符集===<br />
<br />
:本脚本使用Unicode 3.2的未分配编码列表,指向 Table A.1, 也定义在 [STRINGPREP]的附录<br />
<br />
===B.3. 映射===<br />
<br />
:本脚本指定使用[STRINGPREP]的以下表:<br />
<br />
::Table B.1<br />
<br />
===B.4. 正规化===<br />
<br />
:本脚本指定使用 Unicode normalization form KC, 定义在 [STRINGPREP]中.<br />
<br />
===B.5. 禁止输出===<br />
<br />
:本脚本指定使用以下的[STRINGPREP]表禁止输出.<br />
<br />
::Table C.1.2<br />
<br />
::Table C.2.1<br />
<br />
::Table C.2.2<br />
<br />
::Table C.3<br />
<br />
::Table C.4<br />
<br />
::Table C.5<br />
<br />
::Table C.6<br />
<br />
::Table C.7<br />
<br />
::Table C.8<br />
<br />
::Table C.9<br />
<br />
===B.6. 双字节===<br />
<br />
:本脚本指定按照[STRINGPREP]第六章检查双字节.<br />
<br />
==附录 C. XML 规划==<br />
<br />
:以下 XML schemas 是描述性的, 不是标准的. 'jabber:client' 和 'jabber:server' 名字空间的标准定义, 参照 [[RFC3921]].<br />
<br />
===C.1. Streams namespace===<br />
<br />
<source lang="xml"><br />
<?xml version='1.0' encoding='UTF-8'?><br />
<br />
<xs:schema<br />
xmlns:xs='http://www.w3.org/2001/XMLSchema'<br />
targetNamespace='http://etherx.jabber.org/streams'<br />
xmlns='http://etherx.jabber.org/streams'<br />
elementFormDefault='unqualified'><br />
<br />
<xs:element name='stream'><br />
<xs:complexType><br />
<xs:sequence xmlns:client='jabber:client'<br />
xmlns:server='jabber:server'<br />
xmlns:db='jabber:server:dialback'><br />
<xs:element ref='features' minOccurs='0' maxOccurs='1'/><br />
<xs:any namespace='urn:ietf:params:xml:ns:xmpp-tls'<br />
minOccurs='0'<br />
maxOccurs='unbounded'/><br />
<xs:any namespace='urn:ietf:params:xml:ns:xmpp-sasl'<br />
minOccurs='0'<br />
maxOccurs='unbounded'/><br />
<xs:choice minOccurs='0' maxOccurs='1'><br />
<xs:choice minOccurs='0' maxOccurs='unbounded'><br />
<xs:element ref='client:message'/><br />
<xs:element ref='client:presence'/><br />
<xs:element ref='client:iq'/><br />
</xs:choice><br />
<xs:choice minOccurs='0' maxOccurs='unbounded'><br />
<xs:element ref='server:message'/><br />
<xs:element ref='server:presence'/><br />
<xs:element ref='server:iq'/><br />
<xs:element ref='db:result'/><br />
<xs:element ref='db:verify'/><br />
</xs:choice><br />
</xs:choice><br />
<xs:element ref='error' minOccurs='0' maxOccurs='1'/><br />
</xs:sequence><br />
<xs:attribute name='from' type='xs:string' use='optional'/><br />
<xs:attribute name='id' type='xs:NMTOKEN' use='optional'/><br />
<xs:attribute name='to' type='xs:string' use='optional'/><br />
<xs:attribute name='version' type='xs:decimal' use='optional'/><br />
<xs:attribute ref='xml:lang' use='optional'/><br />
</xs:complexType><br />
</xs:element><br />
<br />
<xs:element name='features'><br />
<xs:complexType><br />
<xs:all xmlns:tls='urn:ietf:params:xml:ns:xmpp-tls'<br />
xmlns:sasl='urn:ietf:params:xml:ns:xmpp-sasl'<br />
xmlns:bind='urn:ietf:params:xml:ns:xmpp-bind'<br />
xmlns:sess='urn:ietf:params:xml:ns:xmpp-session'><br />
<xs:element ref='tls:starttls' minOccurs='0'/><br />
<xs:element ref='sasl:mechanisms' minOccurs='0'/><br />
<xs:element ref='bind:bind' minOccurs='0'/><br />
<xs:elemnt ref='sess:session' minOccurs='0'/><br />
</xs:all><br />
</xs:complexType><br />
</xs:element><br />
<br />
<xs:element name='error'><br />
<xs:complexType><br />
<xs:sequence xmlns:err='urn:ietf:params:xml:ns:xmpp-streams'><br />
<xs:group ref='err:streamErrorGroup'/><br />
<xs:element ref='err:text'<br />
minOccurs='0'<br />
maxOccurs='1'/><br />
</xs:sequence><br />
</xs:complexType><br />
</xs:element><br />
<br />
</xs:schema><br />
</source><br />
<br />
===C.2. Stream error namespace===<br />
<br />
<source lang="xml"><br />
<?xml version='1.0' encoding='UTF-8'?><br />
<br />
<xs:schema<br />
xmlns:xs='http://www.w3.org/2001/XMLSchema'<br />
targetNamespace='urn:ietf:params:xml:ns:xmpp-streams'<br />
xmlns='urn:ietf:params:xml:ns:xmpp-streams'<br />
elementFormDefault='qualified'><br />
<br />
<xs:element name='bad-format' type='empty'/><br />
<xs:element name='bad-namespace-prefix' type='empty'/><br />
<xs:element name='conflict' type='empty'/><br />
<xs:element name='connection-timeout' type='empty'/><br />
<xs:element name='host-gone' type='empty'/><br />
<xs:element name='host-unknown' type='empty'/><br />
<xs:element name='improper-addressing' type='empty'/><br />
<xs:element name='internal-server-error' type='empty'/><br />
<xs:element name='invalid-from' type='empty'/><br />
<xs:element name='invalid-id' type='empty'/><br />
<xs:element name='invalid-namespace' type='empty'/><br />
<xs:element name='invalid-xml' type='empty'/><br />
<xs:element name='not-authorized' type='empty'/><br />
<xs:element name='policy-violation' type='empty'/><br />
<xs:element name='remote-connection-failed' type='empty'/><br />
<xs:element name='resource-constraint' type='empty'/><br />
<xs:element name='restricted-xml' type='empty'/><br />
<xs:element name='see-other-host' type='xs:string'/><br />
<xs:element name='system-shutdown' type='empty'/><br />
<xs:element name='undefined-condition' type='empty'/><br />
<xs:element name='unsupported-encoding' type='empty'/><br />
<xs:element name='unsupported-stanza-type' type='empty'/><br />
<xs:element name='unsupported-version' type='empty'/><br />
<xs:element name='xml-not-well-formed' type='empty'/><br />
<br />
<xs:group name='streamErrorGroup'><br />
<xs:choice><br />
<xs:element ref='bad-format'/><br />
<xs:element ref='bad-namespace-prefix'/><br />
<xs:element ref='conflict'/><br />
<xs:element ref='connection-timeout'/><br />
<xs:element ref='host-gone'/><br />
<xs:element ref='host-unknown'/><br />
<xs:element ref='improper-addressing'/><br />
<xs:element ref='internal-server-error'/><br />
<xs:element ref='invalid-from'/><br />
<xs:element ref='invalid-id'/><br />
<xs:element ref='invalid-namespace'/><br />
<xs:element ref='invalid-xml'/><br />
<xs:element ref='not-authorized'/><br />
<xs:element ref='policy-violation'/><br />
<xs:element ref='remote-connection-failed'/><br />
<xs:element ref='resource-constraint'/><br />
<xs:element ref='restricted-xml'/><br />
<xs:element ref='see-other-host'/><br />
<xs:element ref='system-shutdown'/><br />
<xs:element ref='undefined-condition'/><br />
<xs:element ref='unsupported-encoding'/><br />
<xs:element ref='unsupported-stanza-type'/><br />
<xs:element ref='unsupported-version'/><br />
<xs:element ref='xml-not-well-formed'/><br />
</xs:choice><br />
</xs:group><br />
<br />
<xs:element name='text'><br />
<xs:complexType><br />
<xs:simpleContent><br />
<xs:extension base='xs:string'><br />
<xs:attribute ref='xml:lang' use='optional'/><br />
</xs:extension><br />
</xs:simpleContent><br />
</xs:complexType><br />
</xs:element><br />
<br />
<xs:simpleType name='empty'><br />
<xs:restriction base='xs:string'><br />
<xs:enumeration value=''/><br />
</xs:restriction><br />
</xs:simpleType><br />
<br />
</xs:schema><br />
</source><br />
<br />
===C.3. TLS namespace===<br />
<br />
<source lang="xml"><br />
<?xml version='1.0' encoding='UTF-8'?><br />
<br />
<xs:schema<br />
xmlns:xs='http://www.w3.org/2001/XMLSchema'<br />
targetNamespace='urn:ietf:params:xml:ns:xmpp-tls'<br />
xmlns='urn:ietf:params:xml:ns:xmpp-tls'<br />
elementFormDefault='qualified'><br />
<br />
<xs:element name='starttls'><br />
<xs:complexType><br />
<xs:sequence><br />
<xs:element<br />
name='required'<br />
minOccurs='0'<br />
maxOccurs='1'<br />
type='empty'/><br />
</xs:sequence><br />
</xs:complexType><br />
</xs:element><br />
<br />
<xs:element name='proceed' type='empty'/><br />
<xs:element name='failure' type='empty'/><br />
<br />
<xs:simpleType name='empty'><br />
<xs:restriction base='xs:string'><br />
<xs:enumeration value=''/><br />
</xs:restriction><br />
</xs:simpleType><br />
<br />
</xs:schema><br />
</source><br />
<br />
===C.4. SASL namespace===<br />
<br />
<source lang="xml"><br />
<?xml version='1.0' encoding='UTF-8'?><br />
<br />
<xs:schema<br />
xmlns:xs='http://www.w3.org/2001/XMLSchema'<br />
targetNamespace='urn:ietf:params:xml:ns:xmpp-sasl'<br />
xmlns='urn:ietf:params:xml:ns:xmpp-sasl'<br />
elementFormDefault='qualified'><br />
<br />
<xs:element name='mechanisms'><br />
<xs:complexType><br />
<xs:sequence><br />
<xs:element name='mechanism'<br />
maxOccurs='unbounded'<br />
type='xs:string'/><br />
</xs:sequence><br />
</xs:complexType><br />
</xs:element><br />
<br />
<xs:element name='auth'><br />
<xs:complexType><br />
<xs:simpleContent><br />
<xs:extension base='empty'><br />
<xs:attribute name='mechanism'<br />
type='xs:string'<br />
use='optional'/><br />
</xs:extension><br />
</xs:simpleContent><br />
</xs:complexType><br />
</xs:element><br />
<br />
<xs:element name='challenge' type='xs:string'/><br />
<xs:element name='response' type='xs:string'/><br />
<xs:element name='abort' type='empty'/><br />
<xs:element name='success' type='empty'/><br />
<br />
<xs:element name='failure'><br />
<xs:complexType><br />
<xs:choice minOccurs='0'><br />
<xs:element name='aborted' type='empty'/><br />
<xs:element name='incorrect-encoding' type='empty'/><br />
<xs:element name='invalid-authzid' type='empty'/><br />
<xs:element name='invalid-mechanism' type='empty'/><br />
<xs:element name='mechanism-too-weak' type='empty'/><br />
<xs:element name='not-authorized' type='empty'/><br />
<xs:element name='temporary-auth-failure' type='empty'/><br />
</xs:choice><br />
</xs:complexType><br />
</xs:element><br />
<xs:simpleType name='empty'><br />
<xs:restriction base='xs:string'><br />
<xs:enumeration value=''/><br />
</xs:restriction><br />
</xs:simpleType><br />
<br />
</xs:schema><br />
</source><br />
<br />
===C.5. Resource binding namespace===<br />
<br />
<source lang="xml"><br />
<?xml version='1.0' encoding='UTF-8'?><br />
<br />
<xs:schema<br />
xmlns:xs='http://www.w3.org/2001/XMLSchema'<br />
targetNamespace='urn:ietf:params:xml:ns:xmpp-bind'<br />
xmlns='urn:ietf:params:xml:ns:xmpp-bind'<br />
elementFormDefault='qualified'><br />
<br />
<xs:element name='bind'><br />
<xs:complexType><br />
<xs:choice minOccurs='0' maxOccurs='1'><br />
<xs:element name='resource' type='xs:string'/><br />
<xs:element name='jid' type='xs:string'/><br />
</xs:choice><br />
</xs:complexType><br />
</xs:element><br />
<br />
</xs:schema><br />
</source><br />
<br />
===C.6. Dialback namespace===<br />
<br />
<source lang="xml"><br />
<?xml version='1.0' encoding='UTF-8'?><br />
<br />
<xs:schema<br />
xmlns:xs='http://www.w3.org/2001/XMLSchema'<br />
targetNamespace='jabber:server:dialback'<br />
xmlns='jabber:server:dialback'<br />
elementFormDefault='qualified'><br />
<br />
<xs:element name='result'><br />
<xs:complexType><br />
<xs:simpleContent><br />
<xs:extension base='xs:token'><br />
<xs:attribute name='from' type='xs:string' use='required'/><br />
<xs:attribute name='to' type='xs:string' use='required'/><br />
<xs:attribute name='type' use='optional'><br />
<xs:simpleType><br />
<xs:restriction base='xs:NCName'><br />
<xs:enumeration value='invalid'/><br />
<xs:enumeration value='valid'/><br />
</xs:restriction><br />
</xs:simpleType><br />
</xs:attribute><br />
</xs:extension><br />
</xs:simpleContent><br />
</xs:complexType><br />
</xs:element><br />
<br />
<xs:element name='verify'><br />
<xs:complexType><br />
<xs:simpleContent><br />
<xs:extension base='xs:token'><br />
<xs:attribute name='from' type='xs:string' use='required'/><br />
<xs:attribute name='id' type='xs:NMTOKEN' use='required'/><br />
<xs:attribute name='to' type='xs:string' use='required'/><br />
<xs:attribute name='type' use='optional'><br />
<xs:simpleType><br />
<xs:restriction base='xs:NCName'><br />
<xs:enumeration value='invalid'/><br />
<xs:enumeration value='valid'/><br />
</xs:restriction><br />
</xs:simpleType><br />
</xs:attribute><br />
</xs:extension><br />
</xs:simpleContent><br />
</xs:complexType><br />
</xs:element><br />
<br />
</xs:schema><br />
</source><br />
<br />
===C.7. Stanza error namespace===<br />
<br />
<source lang="xml"><br />
<?xml version='1.0' encoding='UTF-8'?><br />
<br />
<xs:schema<br />
xmlns:xs='http://www.w3.org/2001/XMLSchema'<br />
targetNamespace='urn:ietf:params:xml:ns:xmpp-stanzas'<br />
xmlns='urn:ietf:params:xml:ns:xmpp-stanzas'<br />
elementFormDefault='qualified'><br />
<br />
<xs:element name='bad-request' type='empty'/><br />
<xs:element name='conflict' type='empty'/><br />
<xs:element name='feature-not-implemented' type='empty'/><br />
<xs:element name='forbidden' type='empty'/><br />
<xs:element name='gone' type='xs:string'/><br />
<xs:element name='internal-server-error' type='empty'/><br />
<xs:element name='item-not-found' type='empty'/><br />
<xs:element name='jid-malformed' type='empty'/><br />
<xs:element name='not-acceptable' type='empty'/><br />
<xs:element name='not-allowed' type='empty'/><br />
<xs:element name='payment-required' type='empty'/><br />
<xs:element name='recipient-unavailable' type='empty'/><br />
<xs:element name='redirect' type='xs:string'/><br />
<xs:element name='registration-required' type='empty'/><br />
<xs:element name='remote-server-not-found' type='empty'/><br />
<xs:element name='remote-server-timeout' type='empty'/><br />
<xs:element name='resource-constraint' type='empty'/><br />
<xs:element name='service-unavailable' type='empty'/><br />
<xs:element name='subscription-required' type='empty'/><br />
<xs:element name='undefined-condition' type='empty'/><br />
<xs:element name='unexpected-request' type='empty'/><br />
<br />
<xs:group name='stanzaErrorGroup'><br />
<xs:choice><br />
<xs:element ref='bad-request'/><br />
<xs:element ref='conflict'/><br />
<xs:element ref='feature-not-implemented'/><br />
<xs:element ref='forbidden'/><br />
<xs:element ref='gone'/><br />
<xs:element ref='internal-server-error'/><br />
<xs:element ref='item-not-found'/><br />
<xs:element ref='jid-malformed'/><br />
<xs:element ref='not-acceptable'/><br />
<xs:element ref='not-allowed'/><br />
<xs:element ref='payment-required'/><br />
<xs:element ref='recipient-unavailable'/><br />
<xs:element ref='redirect'/><br />
<xs:element ref='registration-required'/><br />
<xs:element ref='remote-server-not-found'/><br />
<xs:element ref='remote-server-timeout'/><br />
<xs:element ref='resource-constraint'/><br />
<xs:element ref='service-unavailable'/><br />
<xs:element ref='subscription-required'/><br />
<xs:element ref='undefined-condition'/><br />
<xs:element ref='unexpected-request'/><br />
</xs:choice><br />
</xs:group><br />
<br />
<xs:element name='text'><br />
<xs:complexType><br />
<xs:simpleContent><br />
<xs:extension base='xs:string'><br />
<xs:attribute ref='xml:lang' use='optional'/><br />
</xs:extension><br />
</xs:simpleContent><br />
</xs:complexType><br />
</xs:element><br />
<br />
<xs:simpleType name='empty'><br />
<xs:restriction base='xs:string'><br />
<xs:enumeration value=''/><br />
</xs:restriction><br />
</xs:simpleType><br />
<br />
</xs:schema><br />
</source><br />
<br />
==附录 D. 核心Jabber协议和XMPP的不同==<br />
<br />
:本章是非标准的.<br />
<br />
::译者注:附录D对于新接触XMPP的人没有什么意义,就不翻译了,免得浪费时间。因为现在RFC公布已经很久了,以前的Jabber实现很多都进化到XMPP了。<br />
<br />
:XMPP has been adapted from the protocols originally developed in the Jabber open-source community, which can be thought of as "XMPP 0.9". Because there exists a large installed base of Jabber implementations and deployments, it may be helpful to specify the key differences between the relevant Jabber protocols and XMPP in order to expedite and encourage upgrades of those implementations and deployments to XMPP. This section summarizes the core differences, while the corresponding section of [[RFC3921]] summarizes the differences that relate specifically to instant messaging and presence applications.<br />
<br />
===D.1. Channel Encryption===<br />
<br />
:It was common practice in the Jabber community to use SSL for channel encryption on ports other than 5222 and 5269 (the convention is to use ports 5223 and 5270). XMPP uses TLS over the IANA-registered ports for channel encryption, as defined under Use of TLS (Section 5) herein.<br />
<br />
===D.2. Authentication===<br />
<br />
:The client-server authentication protocol developed in the Jabber community used a basic IQ interaction qualified by the 'jabber:iq:auth' namespace (documentation of this protocol is contained in [JEP-0078], published by the Jabber Software Foundation [JSF]). XMPP uses SASL for authentication, as defined under Use of SASL (Section 6) herein.<br />
<br />
:The Jabber community did not develop an authentication protocol for server-to-server communications, only the Server Dialback (Section 8) protocol to prevent server poofing. XMPP supersedes Server Dialback with a true server-to-server authentication protocol, as defined under Use of SASL (Section 6) herein.<br />
<br />
===D.3. Resource Binding===<br />
<br />
:Resource binding in the Jabber community was handled via the 'jabber:iq:auth' namespace (which was also used for client authentication with a server). XMPP defines a dedicated namespace for resource binding as well as the ability for a server to generate a resource identifier on behalf of a client, as defined under Resource Binding (Section 7).<br />
<br />
===D.4. JID Processing===<br />
<br />
:JID processing was somewhat loosely defined by the Jabber community (documentation of forbidden characters and case handling is contained in [JEP-0029], published by the Jabber Software Foundation [JSF]). XMPP specifies the use of [NAMEPREP] for domain identifiers and supplements Nameprep with two additional [STRINGPREP] profiles for JID processing: Nodeprep (Appendix A) for node identifiers and Resourceprep (Appendix B) for resource identifiers.<br />
<br />
===D.5. Error Handling===<br />
<br />
:Stream-related errors were handled in the Jabber community via XML character data text in a <stream:error/> element. In XMPP, stream-related errors are handled via an extensible mechanism defined under Stream Errors (Section 4.7) herein. Stanza-related errors were handled in the Jabber community via HTTP-style error codes. In XMPP, stanza-related errors are handled via an extensible mechanism defined under Stanza Errors (Section 9.3) herein. (Documentation of a mapping between Jabber and XMPP error handling mechanisms is contained in [JEP-0086], published by the Jabber Software Foundation [JSF].)<br />
<br />
===D.6. Internationalization===<br />
<br />
:Although use of UTF-8 has always been standard practice within the Jabber community, the community did not define mechanisms for specifying the language of human-readable text provided in XML character data. XMPP specifies the use of the 'xml:lang' attribute in such contexts, as defined under Stream Attributes (Section 4.4) and xml:lang (Section 9.1.5) herein.<br />
<br />
===D.7. Stream Version Attribute===<br />
<br />
:The Jabber community did not include a 'version' attribute in stream headers. XMPP specifies inclusion of that attribute as a way to signal support for the stream features (authentication, encryption, etc.) defined under Version Support (Section 4.4.1) herein.<br />
<br />
==贡献者==<br />
<br />
:XMPP的大部分核心方面是由1999年开始的Jabber开源社区开发的. 这个社区是由 Jeremie Miller建立的, 他于1999年1月发布了最初版的jabber server源代码. 主要的基础协议的早期贡献者还包括 Ryan Eatmon, Peter Millard, Thomas Muldowney,和 Dave Smith. XMPP工作组的工作主要集中在安全性和国际化方面; 在这些领域, 使用 TLS 和 SASL 的协议最初是由 Rob Norris贡献的, stringprep profiles 最初是由 Joe Hildebrand贡献的. The error code syntax 是由Lisa Dusseault建议的.<br />
<br />
==致谢==<br />
<br />
:感谢许多在贡献者名单之外的人们. 尽管很难提供一个完整的名单, 以下个人对于定义协议或评论标准提供了很多帮助:<br />
<br />
:Thomas Charron, Richard Dobson, Sam Hartman, Schuyler Heath, Jonathan Hogg, Cullen Jennings, Craig Kaes, Jacek Konieczny, Alexey Melnikov, Keith Minkler, Julian Missig, Pete Resnick, Marshall Rose, Alexey Shchepin, Jean-Louis Seguineau, Iain Shigeoka, Greg Troxel, and David Waite. <br />
<br />
:也感谢 XMPP工作组的成员和 IETF 社区在本文的成文过程中一直提供的评论和反馈。<br />
<br />
<br />
==作者地址==<br />
<br />
:Peter Saint-Andre (editor)<br />
<br />
:Jabber Software Foundation<br />
<br />
:EMail: stpeter@jabber.org<br />
<br />
==完整的版权声明==<br />
<br />
:Copyright (C) The Internet Society (2004).<br />
<br />
:This document is subject to the rights, licenses and restrictions contained in BCP 78, and except as set forth therein, the authors retain all their rights. This document and the information contained herein are provided on an "AS IS" basis and THE CONTRIBUTOR, THE ORGANIZATION HE/S HE REPRESENTS OR IS SPONSORED BY (IF ANY), THE INTERNET SOCIETY AND THE INTERNET ENGINEERING TASK FORCE DISCLAIM ALL WARRANTIES, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO ANY WARRANTY THAT THE USE OF THE INFORMATION HEREIN WILL NOT INFRINGE ANY RIGHTS OR ANY IMPLIED WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE.<br />
<br />
==Intellectual Property==<br />
<br />
:The IETF takes no position regarding the validity or scope of any Intellectual Property Rights or other rights that might be claimed to pertain to the implementation or use of the technology described in this document or the extent to which any license under such rights might or might not be available; nor does it represent that it has made any independent effort to identify any such rights. Information on the IETF's procedures with respect to rights in IETF Documents can be found in BCP 78 and BCP 79. Copies of IPR disclosures made to the IETF Secretariat and any assurances of licenses to be made available, or the result of an attempt made to obtain a general license or permission for the use of such proprietary rights by implementers or users of this specification can be obtained from the IETF on-line IPR repository at http://www.ietf.org/ipr. The IETF invites any interested party to bring to its attention any copyrights, patents or patent applications, or other proprietary rights that may cover technology that may be required to implement this standard. Please address the information to the IETF at ietf-ipr@ietf.org.<br />
<br />
==感谢==<br />
<br />
:目前为RFC编辑活动提供资金的Internet Society.</div>
Snowqiang
http://wiki.jabbercn.org/RFC3920
RFC3920
2011-05-18T11:11:06Z
<p>Snowqiang: 处理'\'错误格式</p>
<hr />
<div>[[Category:XMPP正式RFC标准]]<br />
[[Category:已翻译]]<br />
<br />
"本文的英文原文来自[http://www.ietf.org/rfc/rfc3920.txt RFC 3920]<br />
<br />
{|<br />
|网络工作组 || P. Saint-Andre, Ed.<br />
|-<br />
|申请讨论: 3920 || Jabber软件基金会<br />
|-<br />
|类别: 标准跟踪 || 2004年10月<br />
|}<br />
<br />
<br />
<br />
:::'''可扩展的消息和出席信息协议 (XMPP): 核心协议'''<br />
<br />
'''关于本文的说明'''<br />
<br />
:本文为互联网社区定义了一个互联网标准跟踪协议,并且申请讨论协议和提出了改进的建议。请参照“互联网官方协议标准”的最新版本(STD 1)获得这个协议的标准化进程和状态。本文可以不受限制的分发。<br />
<br />
'''版权声明'''<br />
<br />
:本文版权属于互联网社区 (C) The Internet Society (2004).<br />
<br />
'''摘要'''<br />
<br />
:本文定义了可扩展消息和出席信息协议(XMPP)的核心功能,这个协议采用XML流实现在任意两个网络终端接近实时的交换结构化信息。XMPP提供一个通用的可扩展的框架来交换XML数据,它主要用来建立即时消息和出席信息应用以实现 RFC 2779 的需求。 <br />
<br />
==绪论==<br />
<br />
===概览===<br />
<br />
:XMPP是一个开放式的XML协议,设计用于准实时消息和出席信息以及请求-响应服务。其基本的语法和语义最初主要是由Jabber开放源代码社区于1999年开发的。2002年,XMPP工作组被授权接手开发和改编Jabber协议以适应IETF的即时消息和出席信息技术。作为XMPP工作组的成果,本文定义了 XMPP 1.0 的核心功能;在 RFC 2779 [IMP-REQS] 中指定的提供即时消息和出席信息功能的扩展,定义在 XMPP-IM 协议 [the Extensible Messaging and Presence Protocol (XMPP): Instant Messaging and Presence] 中。<br />
<br />
===术语===<br />
<br />
:本文中大写的关键字 "MUST(必须)", "MUST NOT(不能)", "REQUIRED(必需)", "SHALL(将会)", "SHALL NOT(将不会)", "SHOULD(应该)", "SHOULD NOT(不应该)", "RECOMMENDED(建议)", "MAY(可以)", 和 "OPTIONAL(可选)" 的确切含义符合 BCP 14, RFC 2119 [TERMS].<br />
<br />
==通用的架构==<br />
<br />
===概览===<br />
<br />
:尽管XMPP没有指定任何特定的网络结构,但它通常是采用客户-服务器 架构进行实现,其中客户端通过TCP方式使用XMPP访问服务器,服务器之间也采用TCP方式进行通信。<br />
<br />
:以下是这一架构的抽象的示意图 (这里 "-" 表示使用 XMPP 通讯, "=" 表示可使用任何协议通讯)。<br />
<br />
<br />
C1----S1---S2---C3<br />
|<br />
C2----+--G1===FN1===FC1<br />
<br />
<br />
:符号的含义如下:<br />
<br />
::* C1, C2, C3 = XMPP 客户端<br />
<br />
::* S1, S2 = XMPP 服务器<br />
<br />
::* G1 = 一个XMPP和外部(非XMPP)消息网络之间进行“翻译”的网关<br />
<br />
::* FN1 = 一个外部消息网络<br />
<br />
::* FC1 = 外部消息网络上的一个客户端<br />
<br />
===服务器===<br />
<br />
:服务器充当XMPP通信的一个智能抽象层,它主要负责:<br />
<br />
:* 对受验证的客户端,服务器以及其他实体之间以XML流形式的连接和会话进行管理。<br />
<br />
:* 在这些实体间使用XML流对合理编址的XML节(第九章)进行路由<br />
<br />
:大部分 XMPP 兼容的服务器也负责存储客户端使用的数据 (比如基于XMPP协议的及时消息应用中的联系人名单); 在这种情况下, XML 数据直接服务器来处理,而不需要转发到其他实体。<br />
<br />
===客户端===<br />
<br />
:大部分客户端通过 TCP 连接直接连到服务器,并通过XMPP获得由服务器以及联合服务器所提供的全部功能。多个不同资源(比如不同的设备和地点)的客户端'''可以'''同时登陆并且并发的连接到一个服务器,每个不同资源的客户端通过XMPP地址的资源标识符来区分(比如<node@domain/ home> 和 <node@domain/work>),参见地址空间(第三章)。'''建议'''的客户端和服务器连接的端口是 5222 ,这个端口已经在 IANA(在第十五章第九节查阅端口号码) 注册了。<br />
<br />
===网关===<br />
<br />
:网关是一个特殊用途的服务器端的服务,主要功能是把 XMPP 翻译成外部(非XMPP)消息系统,并把返回的消息翻译成 XMPP 。例如到 email(参见 [SMTP] ),IRC(参见 [IRC] ),SIMPLE(参见 [SIMPLE] ),SMS 的网关;还有和别的消息服务的网关,比如AIM,ICQ,MSN Messenger,Yahoo! Instant Messenger。网关和服务器之间的通信,网关和外部消息系统的通信,不在本文描述范围之内。<br />
<br />
===网络===<br />
<br />
:因为每个服务器都是由一个网络地址来标识的并且服务器之间的通信是 客户-服务器 协议的直接扩展,实际上整个系统是由很多互通的服务器构成的。例如,<juliet@example.com> 可以和 <romeo@example.net> 交换消息,出席信息和其他信息。这种模式常见于那些需要使网络地址标准化的协议(比如 SMTP )。任意两个服务器之间的通信是可选(OPTIONAL)的。如果被激活,那么这种通信应该(SHOULD)通过 XML 流绑定到 TCP 连接上进行。建议的(RECOMMENDED)服务器之间的连接端口为 5269 ,这个端口号已经在 IANA (在第十五章第九节查阅端口号码)注册了。<br />
<br />
==地址空间==<br />
<br />
===概览===<br />
<br />
:一个实体可以是任何一个被认为是一个网络端点的东西(例如网络上的一个 ID ),而且它是通过XMPP进行通信的。所有这些实体都有一个具有唯一性的地址,并符合 RFC 2396 [URI]规范要求的格式。由于历史原因,一个 XMPP 实体的地址被称为 Jabber Identifier 或 JID 。一个合法的 JID 包括一组排列好的元素,包括域名(domain identifier),节点名(node identifier),和资源名(resource identifier)。<br />
<br />
:JID的语法定义,使用 [ABNF] 中的 Augmented Backus-Naur 格式。(IPv4 地址和 IPv6地址规则在 附录B 中的 [IPv6] 中定义;确定节点规则的合法字符顺序由 附录A 的 [STRINGPREP] 的 Nodeprep 部分来定义;确定资源规则的合法字符顺序由 附录B 的 [STRINGPREP] 的Resourceprep 部分来定义;子域名规则参考 [IDNA] 中关于国际域名标签的描述。)。<br />
<br />
::jid = [ node "@" ] domain [ "/" resource ]<br />
<br />
::domain = fqdn / address-literal<br />
<br />
::fqdn = (sub-domain 1*("." sub-domain))<br />
<br />
::sub-domain = (internationalized domain label)<br />
<br />
::address-literal = IPv4address / IPv6address<br />
<br />
:所有 JID 都是基于上述的结构。类似 <user@host/resource> 这种结构,最常用来标识一个即时消息用户,这个用户所连接的服务器,以及这个用户用于连接的资源(比如特定类型的客户端软件)。不过,节点类型不是客户端也是有可能的,比如一个用来提供多用户聊天服务的特定的聊天室,地址可以是 <room@service> (这里 “room“ 是聊天室的名字而 ”service“ 是多用户聊天服务的主机名),而加入了这个聊天室的某个特定的用户的地址则是 <room@service/nick> (这里 ”nick“ 是用户在聊天室的昵称)。许多其他的 JID 类型都是可能的(例如 <domain/resource> 可能是一个服务器端的脚本或服务)。<br />
<br />
:一个 JID 的每个合法部分(节点名,域名,资源名)的长度不能(MUST NOT)超过 1023 字节。也就是整体长度(包括 '@' 和 '/' )不能超过 3071 字节。<br />
<br />
===域名===<br />
<br />
:域名是一个主要的ID并且是 JID 中唯一必需(REQUIRED)的元素(一个纯粹的域名也是一个合法的 JID)。它通常代表网络的网关或者“主”服务器,其他实体通过连接它来实现 XML 转发和数据管理功能。然而,由一个域名标识引用的实体,并非总是一个服务器,它也可能是一个服务器的子域地址,提供额外的功能(比如多用户聊天服务,用户目录,或一个到外部消息系统的网关)。<br />
<br />
:每个服务器或者服务的域名,可以(MAY)是一个 IP 地址,但应该(SHOULD)是一个完全合法的域名(参见 [DNS]).一个域名ID必须(MUST)是 [IANA] 里定义的“国际化域名”,并且按 [STRINGPREP]中的 [NAMEPREP] profile进行成功的字符转换。在比较两个域名ID之前,服务器必须(MUST),客户端应该(SHOULD)首先按照Nameprep profile(定义在[IANA]中) 来转换每个域名的字符。<br />
<br />
===节点名===<br />
<br />
:节点名是一个可选(OPTIONAL)的第二 ID,放在域名之前并用符号"@"分开.它通常表示一个向服务器或网关请求和使用网络服务的实体(比如一个客户端),当然它也能够表示其他的实体(比如在多用户聊天系统中的一个房间). 节点名所代表的实体,它的地址依赖于一个特定的域名;在 XMPP 的即时消息和出席信息应用系统中,这个地址是“纯 JID” <node@domain> 中的一部分。<br />
<br />
:一个节点名必须按 [STRINGPREP] 中的 Nodeprep profile 进行成功的字符转换。在比较两个节点ID之前,服务器必须(MUST),客户端应该(SHOULD)首先按 Nodeprep profile 转换每个ID的字符。<br />
<br />
===资源名===<br />
<br />
:资源名是一个可选的第三 ID,它放在域名的后面并由符号"/"分开。资源名可以跟在 <node@domain>后面也可以跟在 <domain> 后面。它通常表示一个特定的会话,连接(比如设备或者所在位置),或者一个附属于某个节点ID实体相关实体的对象(比如多用户聊天室中的一个参加者)。对于服务器和和其他客户端来说,资源名是不透明的。当它提供必需的信息以完成资源绑定(参见第七章)的时候,通常是由客户端来实现的(尽管可以由客户端向服务器请求完成),然后显示为“已连接的资源”。一个实体可以(MAY)并发维护多个已连接的资源。每个已连接的资源由不同的资源ID来区分。<br />
<br />
:一个资源名必须(MUST)按 [STRINGPREP] 中的 Resourceprep profile 进行成功的格式化。在比较两个资源ID之前,服务器必须(MUST),客户端应该(SHOULD)首先按 Resourceprep profile 转换每个ID的字符。<br />
<br />
===地址的确认===<br />
<br />
:在 SASL (见第六章)握手之后(如果必要的话,也在资源绑定(见第七章)之后),正在接收流信息的实体必须(MUST)确认初始实体的 ID 。<br />
<br />
:对于服务器间的通信,在 SASL 握手时,如果没有指明授权的ID,这个初始的实体应该(SHOULD)是经过认证实体(参见 简单认证和安全层协议 [SASL] 中的定义)授权的ID(见第六章)。<br />
<br />
:对于客户端和服务器的通信,在 SASL 握手时,如果没有指明授权的ID,“纯 JID” (<node@domain>)应该(SHOULD)是经过认证实体(参见 [SASL] 中的定义)授权的ID,“全 JID” (<node@domain/resource>)的资源ID部分应该(SHOULD)是由客户端和服务器在资源绑定的时候商定的(参见第七章)。<br />
<br />
:接收的实体必须(MUST)确保结果JID(包括节点名,域名,资源名以及分隔符)与本章前面部分描述的规则和格式相一致;为了满足这些约束条件,接收实体可能(MAY)需要把初始实体的发送方 JID 替换成接收实体认可的规范 JID。<br />
<br />
==XML流==<br />
<br />
===概览===<br />
<br />
:两个基本概念,XML流和XML节,使得在出席信息已知的实体之间,异步交换低负载的结构化信息成为可能。这两个术语定义如下:<br />
<br />
:XML流的定义:一个XML流是一个容器,包含了两个实体之间通过网络交换的XML元素。一个XML流是由一个XML打开标签 <stream> (包含适当的属性和名字空间声明)开始的,流的结尾则是一个XML关闭L标签 </stream> 。在流的整个生命周期,初始化它的实体可以通过流发送大量的XML元素,用于流的握手(例如 TLS 握手(第五章) 或 SASL 握手(第六章))或XML节(在这里指符合缺省名字空间的元素,包括<message/>,<presence/>, 或 <iq/> 元素)。“初始的流”由初始化实体(通常是一个客户端或服务器)和接收实体(通常是一个服务器)握手,从接收实体来看,它就是那个初始实体的"会话".初始化流允许从初始化实体到接收实体的单向通信;为了使接收实体能够和初始实体交换信息,接收实体必须发起一个反向的握手(应答流).<br />
<br />
:XML节的定义: 一个XML节是一个实体通过 XML 流向另一个实体发送的结构化信息中的一个离散的语义单位。一个XML节直接存在于根元素<stream/>的下一级,这样可以说是很好的匹配了[XML](译者注:在标准参考一节)的第43条.任何XML节都是从一个XML流的下一级的某个打开标签(如 <presence>)开始,到相应的关闭标签(如 </presence>)。一个XML节可以(MAY)包含子元素(相关的属性,元素, 和 XML 字符数据等) 以表达完整的信息.在这里定义的XML节仅限于<message/>, <presence/>, 和 <iq/> 元素,具体描述间见 XML Stanzas(第九章);为TLS握手(第五章)、SASL握手(第六章)、服务器回拨(第八章)的需要而发送的XML元素,不被认为是一个XML节。<br />
<br />
:设想一个客户端和服务器会话的例子。为了连接一个服务器,一个客户端必须(MUST)发送一个打开标签<stream>给服务器,初始化一个XML流,也可选择(OPTIONAL)在这之前发送一段文本声明XML版本和支持的字符集(参见文本声明的内容(第十一章第四节); 也可看字符编码(第十一章第五节))。视本地化策略和提供的服务而定,服务器应该(SHOULD)回复一个XML流给客户端,同样的,也可选择在这之前发送一段文本声明。一旦客户端完成了SASL握手(第六章),客户端可以(MAY)通过流发送不限量的XML节给网络中的任何接收者。当客户端想关闭这个流,它只需要简单的发送一个关闭标签</stream>给服务器(或者作为另一个选择,可能由服务器关闭这个流)。然后,客户端和服务器都应该(SHOULD)彻底地终止这个连接(通常是一个TCP连接)。<br />
<br />
:那些习惯认为XML是一个以文本为中心风格的人可能希望看看一个与服务器连接的客户端会话,包含两个 打开-关闭 XML文档:一个是从客户端到服务器,一个是从服务器到客户端。下图中,根元素<stream/> 可以被认为是每个“文档”的文档实体,这两个“文档”通过累积那些在XML上传输的XML节来搭建的。无论如何,下图只是方便理解;实际上XMPP并不处理文档而是处理XML流和XML节。<br />
<br />
:基本上,一个XML流相当于一个会话期间所有XML节的一个信封。我们可以简单的把它描述成下图:<br />
<br />
|--------------------|<br />
| <stream> |<br />
|--------------------|<br />
| <presence> |<br />
| <show/> |<br />
| </presence> |<br />
|--------------------|<br />
| <message to='foo'> |<br />
| <body/> |<br />
| </message> |<br />
|--------------------|<br />
| <iq to='bar'> |<br />
| <query/> |<br />
| </iq> |<br />
|--------------------|<br />
| ... |<br />
|--------------------|<br />
| </stream> |<br />
|--------------------|<br />
<br />
===绑定到TCP===<br />
<br />
:虽然有很多非必需的连接使用XML流来绑定[TCP]连接(两个实体可以通过别的机制来互联,比如通过[HTPP]连接轮询),本规范只定义了 XMPP 到 TCP 的绑定。在客户和服务器通信的过程中,服务器必须(MUST)允许客户端共享一个TCP连接来传输XML节,包括从客户端传到服务器和从服务器传到客户端。在服务器之间的通信过程中,服务器必须(MUST)用一个 TCP连接 向对方发送 XML节,另一个 TCP连接(由对方初始化)接收对方的XML节,一共两个 TCP连接。<br />
<br />
===流的安全===<br />
<br />
:在XMPP 1.0中,当XML流开始握手时,TLS应该(SHOULD)按 第五章:TLS的使用 中的规定来使用,SASL必须(MUST)按 第六章:SASL的使用 中的规定来使用。尽管可能(MAY)存在某种共有的机制能够保证双向安全,但是“初始化流”(比如从初始化实体发给接收实体的流)和“应答流”(比如从接收实体发给初始化实体的流)还是必须(MUST)安全的分开。在流被验证之间,实体不应该(SHOULD NOT) 尝试通过流发送XML节(第九章);就算它这样做了,对方的实体也不能(MUST NOT)接受这些XML节,并且应该(SHOULD)返回一个 <not-authorized/> 的流错误信息并且终止当前TCP连接上双方的XML流;注意,这仅仅是针对XML节(包含在缺省命名空间中的 <message/>, <presence/>, 和 <iq/> 元素),而不是指那些用于 TLS握手(第五章)、SASL握手(第六章)握手的流。<br />
<br />
===stream 属性===<br />
<br />
:stream 元素的属性如下:<br />
<br />
:* to -- 'to' 属性应(SHOULD)仅出现在初始化实体发给接收实体的 XML 流的头当中,并且它的值必须(MUST)是接收实体所在的主机名。在接收实体发送给初始化实体的 XML 流的头中不应该(SHOULD NOT)出现 'to' 属性。若 'to' 属性出现在应答流中,则初始化实体应(SHOULD)忽略它。<br />
<br />
:* from -- 'from' 属性应(SHOULD)仅出现在接收实体发给初始化实体的 XML 流的头当中,并且它的值必须(MUST)是为当前初始化实体授权的接收实体所在的主机名。注意,不应该(SHOULD NOT)有 'from'属性出现在初始实体发送给接收实体的 XML流的头中;无论如何,如果'from'属性出现在初始化流中,接收实体应该(SHOULD)忽略它。<br />
<br />
:* id -- 'id'属性应该(SHOULD)仅用于接收实体发送给初始化实体 XML流的头。这个属性是一个由接收实体创建的具有唯一性的ID,一个初始实体和接收实体之间的会话ID,并且它在接收方的应用程序中(通常是一个服务器)必须(MUST)是唯一的。注意,这个流 ID 必须是足够安全的,所以它必须是不可预知的和不可重复的(参见[RANDOM] 了解如何获得随机性以保证安全性)。不应该(SHOULD NOT)有 'id'属性出现在初始实体发送给接收实体的 XML流的头中;无论如何,如果'id'属性出现在初始化流中,接收实体应该(SHOULD)忽略它。<br />
<br />
:* xml:lang -- 'xml:lang'属性(定义在[XML]中的第二章第十二节)应该(SHOULD)包含在初始化实体发给接收实体的 XML流的头中,以指定在流中传输的可读XML字符所使用的缺省语言。如果这个属性出现了,接收实体应该(SHOULD)记住它的值,作为初始化流和应答流的缺省属性;如果这个属性没有出现,接收实体应该(SHOULD)用一个可配置的缺省值用于双方的流,这个属性值必须(MUST)在应答流的头中传达。对于所有初始化流中传输的节,如果初始实体没有提供'xml:lang'属性,接收实体应该(SHOULD)应用缺省值;如果初始实体提供了'xml:lang'属性,接收实体不能(MUST NOT)修改或删除它(参见第九章第一节第五小节 xml:lang)。'xml:lang'属性的值必须(MUST)是一个 NMTOKEN (定义在[XML]的第二章第三节) 并且必须(MUST)遵守 RFC 3066 [LANGTAGS] 规定的格式。<br />
<br />
:* version -- version属性(最少需要"1.0")为本规范中和流相关的协议提供了支持。关于这个属性的生成和处理的详细规则将在下文中定义。<br />
<br />
:我们现在可以总结如下:<br />
<br />
{|border="1" cellspacing="0" <br />
! !! 初始化方发给接收方 !! 接收方发给初始化方<br />
|-<br />
|to || 接收方的主机名 || 忽略<br />
|-<br />
|from || 忽略 || 接收方的主机名<br />
|-<br />
|id || 忽略 || 会话键值<br />
|-<br />
|xml:lang || 缺省语言 || 缺省语言<br />
|-<br />
|version || 支持XMPP 1.0 || 支持XMPP 1.0<br />
|}<br />
<br />
====版本支持====<br />
<br />
:在这里XMPP的版本是"1.0";准确地说,这里囊括了和流相关的所有协议(TLS的使用 (第五章),SASL的使用(第六章), 和流错误(第四章第七节)),以及三个定义好的XML节类型(<message/>,<presence/>,和 <iq/>)。XMPP版本号的编号顺序是“<主版本号>.<副版本号>”。主版本和副版本号必须(MUST)是独立的整数并且每个号码可以(MAY)单独以阿拉伯数字增长。这样,"XMPP 2.4"的版本将比"XMPP 2.13"更低。号码前面 的“0”(比如XMPP 6.01)必须(MUST)被接收方忽略并且不能(MUST NOT)被发送出去.<br />
<br />
:如果流和节的格式或者必需的处理方式有了显著的改变,以至于老版本的实体如果只是简单的忽略它不理解的节和属性并且继续像老版本一样的处理方式,会使得老版本的实体不能够和新版本的实体交互,只有在这时候主版本号才应该(SHOULD)增加。副版本号显示新的性能,它必须(MUST)被副版本号更低的实体忽略,但被高(副)版本号的实体用于了解信息。例如,一个副版本号显示处理某种新定义的"type"属性的值(用于message,presence或IQ节)的能力;副版本号高的实体将会了解到与之通信的对方不能够理解这个"type"属性的值,所以将不会发送它。<br />
<br />
:以下规则是用于'版本'属性在实现流的头信息时如何生成和处理:<br />
<br />
:# 初始化实体必须(MUST)在初始化流的头信息中把'版本'的值设置成它所支持的最高版本。(比如,如果最高版本支持就是本规范,那么它必须(MUST)设置成"1.0").<br />
:# 接收实体必须(MUST)在应答流的头信息中把'版本'的值设置成初始化实体所提供的版本或它所支持的最高版本,取其中版本号较低的那一个。接收实体必须(MUST)把主版本号和副版本号作为数字来比较,而不是对"主版本号.副版本号"这个字符串进行比较.<br />
:# 如果在应答流的头信息的版本号中至少有一个主版本号低于初始化流的头信息的版本号,并且如前所述,新版本的实体不能够和旧版本实体交互,初始化实体应该(SHUOULD)生成一个<unsupported-version/>的流错误信息并终止XML流和它的TCP连接。<br />
:# 如果一个实体收到一个头信息中没有'version'属性的流,这个实体必须(MUST)把对方实体的'version'当成'0.0'并且在它发送的应答流的头中也不应该(SHOULD NOT)包含'version'属性.<br />
<br />
===名字空间声明===<br />
<br />
:流的元素必须(MUST)同时满足一个流名字空间声明和一个缺省名字空间声明("名字空间声明"定义在 XML 名字空间定义 [XML-NAMES]中).关于流名字空间和缺省名字空间的详细信息,参考 名字空间的名字和前缀(第十一章第二节).<br />
<br />
===流的特性===<br />
<br />
:如果初始化的实体在初始化流的头信息中设置'version'属性的信息为"1.0",接收实体必须(MUST)向初始化实体发送一个 <features/> 子元素以声明任何可供协商的流一级的特性(或者其他需要声明的能力).目前,这仅用于声明本文中定义的 TLS的使用(第五章),SASL的使用(第六章)和资源绑定(第七章),以及 [XMPP-IM|XMPP文档列表/XMPP正式RFC标准/RFC3921] 中定义的会话的建立;无论如何,流特性这一功能将来可以用于声明任何可协商的特性.如果一个实体不理解或支持安全特性,它应该(SHOULD)忽略它.如果要在一个非安全相关的特性(比如资源绑定)被提议之前,完成一个或多个安全特性(比如TLS和SASL)的协商,这个非安全相关的特性不应该(SHOULD NOT)在相应的安全特性协商完毕之前被声明.<br />
<br />
===流错误===<br />
<br />
:流的根元素可以(MAY)包含一个 <error/> 子元素,由流的名字空间前缀作为它的前缀。这个"错误"子元素必须(MUST)由感知到发生了流级别错误的实体发送(通常是一个服务器而不是一个客户端)。<br />
<br />
====规则====<br />
<br />
:以下规则适用于流级别的错误:<br />
<br />
:* 它假定所有流级别的错误都是不可恢复的;所以,如果一个错误发生在流级别,发现这个错误的实体必须(MUST)发送一个流错误信息给另一个实体,发送一个关闭标签 </stream>,并终止这个流所在的TCP连接。<br />
<br />
:* 如果这个错误发生在流刚开始设置的时候,接收实体必须(MUST)仍然发送一个开放标签 <stream> ,并在流元素中包含一个<error/>的子元素,然后发送一个关闭标签 </stream>,最后终止相应的TCP连接。在这种情况下,如果初始化实体在 'to' 属性中提供了一个未知的主机名,服务器应该(SHOULD)在终止之前,先在流的头信息的 'from' 属性中提供一个服务器认证的主机名.<br />
<br />
====语法====<br />
<br />
:流错误的语法如下:<br />
<br />
<source lang="xml"><br />
<stream:error><br />
<defined-condition xmlns='urn:ietf:params:xml:ns:xmpp-streams'/><br />
<text xmlns='urn:ietf:params:xml:ns:xmpp-streams' xml:lang='langcode'><br />
OPTIONAL descriptive text<br />
</text><br />
[OPTIONAL application-specific condition element]<br />
</stream:error><br />
</source><br />
<br />
:<error/>元素:<br />
:* 必须(MUST)包含一个子元素以描述一个下文定义的节错误条件;这个子元素必须(MUST)符合'urn:ietf:params:xml:ns:xmpp-streams'名字空间.<br />
<br />
:* 可以(MAY)包含一个 <text/> 子元素,用XML字符数据描述错误的细节;这个元素必须(MUST)符合'urn:ietf:params:xml:ns:xmpp-streams'名字空间并且应该(SHOULD)拥有一个'xml:lang'属性表明XML字符数据的自然语言。<br />
<br />
:* 可以(MAY)包含一个子元素用于描述一个明确的应用程序错误条件;这个元素必须(MUST)符合一个应用程序定义的名字空间,并且它的结构是由那个名字空间定义的。<br />
<br />
: <text/> 元素是可选的(OPTIONAL)。如果有这个元素,它应该(SHOULD)仅用于提供描述或调试信息以补充一个已定义的条件或应用程序定义的条件。它不应该(SHOULD NOT)被一个应用程序当成一个可编程的信息。它不应该(SHOULD NOT)被用于向用户表达错误信息,但是可以(MAY)作为和条件元素相关的错误信息之外的附加说明。<br />
<br />
====已定义的条件====<br />
<br />
:以下流级别的错误条件是已定义的:<br />
<br />
:* <bad-format/> -- 实体已经发送XML但是不能被处理;这个错误可以(可以)被更多特定的XML相关的错误替换,比如 <bad-namespace-prefix/>, <invalid-xml/>, <restricted-xml/>, <unsupported-encoding/>, 以及 <xml-not-well-formed/>,尽管更多特定的错误是首选的。 <br />
<br />
:* <bad-namespace-prefix/> -- 实体发送的名字空间前缀不被支持,或者在一个需要某种前缀的元素中没有发送一个名字空间前缀(参见 XML Namespace Names and Prefixes (第十一章第二节)).<br />
<br />
:* <conflict/> -- 服务器正在关闭为这个实体激活的流,因为一个和已经存在的流有冲突的新的流已经被初始化。<br />
<br />
:* <connection-timeout/> -- 实体已经很长时间没有通过这个流发生任何通信流量(可由一个本地服务策略来配置).<br />
<br />
:* <host-gone/> -- 初始化实体在流的头信息中提供的'to'属性的值所指定的主机已经不再由这台服务器提供<br />
<br />
:* <host-unknown/> -- 由初始化实体在流的头信息中提供的 'to' 属性的值和由服务器提供的主机名不一致.<br />
<br />
:* <improper-addressing/> -- 一个在两台服务器之间传送的节缺少 'to' 或 'from' 属性(或者这个属性没有值).<br />
<br />
:* <internal-server-error/> -- 服务器配置错误或者其他未定义的内部错误,使得服务器无法提供流服务.<br />
<br />
:* <invalid-from/> -- 在'from'属性中提供的 JID 或 主机名地址,和认证的 JID不匹配 或服务器之间无法通过SASL(或回拨)协商出合法的域名,或客户端和服务器之间无法通过它进行认证和资源绑定。<br />
<br />
:* <invalid-id/> -- 流 ID 或回拨 ID 是非法的或和以前提供的 ID 不一致.<br />
<br />
:* <invalid-namespace/> -- 流名字空间和 "http://etherx.jabber.org/streams" 不相同或回拨名字空间和 "jabber:server:dialback" 不相同.(参考 XML Namespace Names and Prefixes (第十一章第二节)).<br />
<br />
:* <invalid-xml/> -- 实体通过流发送了一个非法的XML给执行验证的服务器 (参考 Validation (第十一章第三节)).<br />
<br />
:* <not-authorized/> -- 实体试图在流被验证之前发送数据或不被许可执行一个和流协商有关的动作,接收实体在发送错误信息之前不允许(MUST NOT)处理厌恶的节。<br />
<br />
:* <policy-violation/> -- 实体违反了某些本地服务策略;服务器可以(MAY)选择在 <text/> 元素或应用程序定义的错误条件(元素)中详细说明策略。<br />
<br />
:* <remote-connection-failed/> -- 服务器无法正确连接到用于验证或授权的远程实体。<br />
<br />
:* <resource-constraint/> -- 服务器缺乏必要的系统资源为流服务。<br />
<br />
:* <restricted-xml/> -- 实体试图发送受限的XML特性,比如一个注释,处理指示,DTD,实体参考,或保留的字符(参考 Restrictions (第十一章第一节)).<br />
<br />
:* <see-other-host/> -- 服务器将不提供服务给初始化实体但是把它重定向到另一台主机;服务器应该(SHOULD)在<see-other-host/>元素的XML字符数据中指明替代服务器名或IP地址(它必须(必须)是合法的域名标识)。<br />
<br />
:* <system-shutdown/> -- 服务器正在关机并且所有激活的流正在被关闭。<br />
<br />
:* <undefined-condition/> -- 错误条件不在本文已定义的错误条件列表之中;这个错误条件应该(SHOULD)仅用于"应用程序定义条件"元素.<br />
<br />
:* <unsupported-encoding/> -- 初始化实体以一个服务器不不支持的编码方式编码了一个流(参照Character Encoding (第十一章第五节)).<br />
<br />
:* <unsupported-stanza-type/> -- 初始化实体发送了一个流的一级子元素但是服务器不支持.<br />
<br />
:* <unsupported-version/> -- 由初始化实体在流的头信息中指定的'version'属性的值所指定的版本不被服务器支持;服务器可以(MAY)在<text/>元素中指定一个它支持的版本号.<br />
<br />
:* <xml-not-well-formed/> -- 初始化实体发送了一个不规范的XML(参考[XML]).<br />
<br />
====应用程序定义条件====<br />
<br />
:大家知道,应用程序可以(MAY)在error元素中包含一个适当名字空间的子元素来提供一个应用程序定义流错误信息."应用程序定义"元素应该(SHOULD)补充或甚至限定一个已定义的元素.所以 <error/> 元素将包含两个或三个子元素:<br />
<br />
<source lang="xml"><br />
<stream:error><br />
<xml-not-well-formed xmlns='urn:ietf:params:xml:ns:xmpp-streams'/><br />
<text xml:lang='en' xmlns='urn:ietf:params:xml:ns:xmpp-streams'><br />
Some special application diagnostic information!<br />
</text><br />
<escape-your-data xmlns='application-ns'/><br />
</stream:error><br />
</stream:stream><br />
</source><br />
<br />
===简化的流示例===<br />
<br />
:这里包含两个简化的例子,描述了基于流的客户端在服务器上的“会话”(这里"C"表示从客户端发给服务器,"S"表示从服务器发给客户端);这些例子只是用于举例说明原理.<br />
<br />
:一个基本的 "会话":<br />
<br />
<source lang="xml"><br />
C: <?xml version='1.0'?><br />
<stream:stream to='example.com' xmlns='jabber:client' xmlns:stream='http://etherx.jabber.org/streams' version='1.0'><br />
<br />
S: <?xml version='1.0'?><br />
<stream:stream from='example.com' id='someid' xmlns='jabber:client' xmlns:stream='http://etherx.jabber.org/streams' version='1.0'><br />
... encryption, authentication, and resource binding ...<br />
<br />
C: <message from='juliet@example.com' to='romeo@example.net' xml:lang='en'><br />
<br />
C: <body>Art thou not Romeo, and a Montague?</body><br />
<br />
C: </message><br />
<br />
S: <message from='romeo@example.net' to='juliet@example.com' xml:lang='en'><br />
<br />
S: <body>Neither, fair saint, if either thee dislike.</body><br />
<br />
S: </message><br />
<br />
C: </stream:stream><br />
<br />
S: </stream:stream><br />
</source><br />
<br />
<br />
:一个不成功的 "会话" :<br />
<br />
<source lang="xml"><br />
C: <?xml version='1.0'?><br />
<stream:stream to='example.com' xmlns='jabber:client' xmlns:stream='http://etherx.jabber.org/streams' version='1.0'><br />
<br />
S: <?xml version='1.0'?><br />
<stream:stream from='example.com' id='someid' xmlns='jabber:client' xmlns:stream='http://etherx.jabber.org/streams' version='1.0'><br />
... encryption, authentication, and resource binding ...<br />
<br />
C: <message xml:lang='en'><br />
<body>Bad XML, no closing body tag!<br />
</message><br />
<br />
S: <stream:error><br />
<xml-not-well-formed xmlns='urn:ietf:params:xml:ns:xmpp-streams'/><br />
</stream:error><br />
<br />
S: </stream:stream><br />
</source><br />
<br />
==TLS 的使用==<br />
<br />
===概览===<br />
<br />
:XMPP包含的一个保证流安全的方法来防止篡改和偷听.这个传输层安全协议[TLS]的频道加密方法, 模拟了类似的其他"STARTTLS"(见RFC 2595 [USINGTLS])的扩展,如 IMAP [IMAP], POP3 [POP3], and ACAP [ACAP]."STARTTLS"的扩展名字空间是'urn:ietf:params:xml:ns:xmpp-tls'.<br />
<br />
:一个给定域的管理员可以(MAY)要求客户端和服务器通信以及服务器之间通信时使用TLS,或者两者都要求。客户端应该(SHOULD)在尝试完成 SASL (第六章)握手之前使用 TLS,服务器应该(SHOULD)在两个域之间使用 TLS 以保证服务器间通信的安全。<br />
<br />
:以下是使用规则:<br />
<br />
::# 一个遵守本协议的初始化实体必须(MUST)在初始化流的头信息中包含一个'version'属性并把值设为“1.0”。<br />
::# 如果TLS握手发生在两个服务器之间,除非服务器声称的DNS主机名已经被解析(见第十四章第四节 Server-to-Server Communications),通信不能(MUST NOT)继续进行。<br />
::# 当一个遵守本协议的接收实体接收了一个初始化流(它的头信息中包含一个'version'属性并且值设为“1.0”),在发送应答流的的头信息(其中包含版本标记)之后,它必须发送(MUST)<starttls/>元素(名字空间为 'urn:ietf:params:xml:ns:xmpp-tls')以及其他它支持的流特性 。<br />
::# 如果初始化实体选择使用TLS,TLS握手必须在SASL握手之前完成;这个顺序用于帮助保护SASL握手时发送的认证信息的安全,同时可以在必要的时候在TLS握手之前为SASL外部机制提供证书。<br />
::# TLS握手期间,一个实体不能(MUST NOT)在流的根元素中发送任何空格符号作为元素的分隔符(在下面的TLS示例中的任何空格符都仅仅是为了便于阅读);这个禁令用来帮助确保安全层字节精度。<br />
::# 接收实体必须(MUST)在发送<proceed/> 元素的关闭符号">" 之后立刻开始TLS协商。初始化实体必须(MUST)在从接收实体接收到<proceed/> 元素的关闭符号">" 之后立刻开始TLS协商。<br />
::# 初始化实体必须(MUST)验证接收实体出示的证书;关于证书验证流程参见Certificate Validation ( 第十四章第二节)。<br />
::# 证书必须(MUST)检查初始化实体(比如一个用户)提供的主机名;而不是通过DNS系统解析出来的主机名;例如,如果用户指定一个主机名"example.com"而一个DNS SRV [SRV]查询返回"im.example.com",证书必须(MUST)检查"example.com".如果任何种类的XMPP实体(例如客户端或服务器)的JID出现在一个证书里,它必须(MUST)表现为一个别名实体里面的UTF8字符串,存在于subjectAltName之中。如何使用 [ASN.1] 对象标识符 "id-on-xmppAddr" 定义在本文的第五章第一节第一小节。<br />
::# 如果 TLS 握手成功了,接收实体必须(MUST) 丢弃TLS 生效之前从初始化实体得到的任何不可靠的信息.<br />
::# 如果 TLS 握手成功了,初始化实体必须(MUST) 丢弃TLS 生效之前从接收实体得到的任何不可靠的信息. <br />
::# 如果 TLS 握手成功了,接收实体不能(MUST NOT)在流重新开始的时候通过提供其他的流特性来向初始化实体提供 STARTTLS 扩展.<br />
::# 如果 TLS 握手成功了,初始化实体必须(MUST)继续进行SASL握手。<br />
::# 如果 TLS 握手失败了,接收实体必须(MUST)终止XML流和相应的TCP连接。<br />
::# 关于必须(MUST)支持的机制,参照 Mandatory-to-Implement Technologies (第十四章第七节) 。<br />
<br />
====用于 XMPP 地址的 ASN.1 对象标识符====<br />
<br />
:上文提到的[ASN.1] 对象标识符 "id-on-xmppAddr"定义如下:<br />
<br />
::id-pkix OBJECT IDENTIFIER ::= { iso(1) identified-organization(3)<br />
<br />
::dod(6) internet(1) security(5) mechanisms(5) pkix(7) }<br />
<br />
::id-on OBJECT IDENTIFIER ::= { id-pkix 8 } -- other name forms<br />
<br />
::id-on-xmppAddr OBJECT IDENTIFIER ::= { id-on 5 }<br />
<br />
::XmppAddr ::= UTF8String<br />
<br />
:对象标识符也可以(MAY)使用点分隔的格式,如 "1.3.6.1.5.5.7.8.5".<br />
<br />
===叙述===<br />
<br />
:当一个初始化实体用TLS保护一个和接收实体之间的流,其步骤如下:<br />
<br />
::# 初始化实体打开一个TCP连接,发送一个打开的XML流头信息(其'version'属性设置为"1.0")给接收实体以初始化一个流。<br />
::# 接收实体打开一个TCP连接,发送一个XML流头信息(其'version'属性设置为"1.0")给初始化实体作为应答。<br />
::# 接收实体向初始化实体提议STARTTLS范围(包括其他支持的流特性),如果TLS对于和接收实体交互是必需的,它应该(SHOULD)在<starttls/>元素中包含子元素<required/>.<br />
::# 初始化实体发出STARTTLS命令(例如, 一个符合'urn:ietf:params:xml:ns:xmpp-tls'名字空间的 <starttls/> 元素) 以通知接收实体它希望开始一个TLS握手来保护流。<br />
::# 接收实体必须(MUST)以'urn:ietf:params:xml:ns:xmpp-tls'名字空间中的<proceed/>元素或<failure/>元素应答。如果失败,接收实体必须(MUST)终止XML流和相应的TCP连接。如果继续进行,接收实体必须(MUST)尝试通过TCP连接完成TLS握手并且在TLS握手完成之前不能(MUST NOT)发送任何其他XML数据。<br />
::# 初始化实体和接收实体尝试完成TLS握手。(要符合[TLS]规范)<br />
::# 如果 TLS 握手不成功, 接收实体必须(MUST)终止 TCP 连接. 如果 TLS 握手成功, 初始化实体必须(MUST)发送给接收实体一个打开的XML流头信息来初始化一个新的流(先发送一个关闭标签</stream>是不必要的,因为接收实体和初始化实体必须(MUST)确保原来的流在TLS握手成功之后被关闭) 。<br />
::# 在从初始化实体收到新的流头信息之后,接收实体必须(MUST)发送一个新的XML流头信息给初始化实体作为应答,其中应包含可用的特性但不包含STATRTTLS特性。<br />
<br />
===客户端-服务器 示例===<br />
<br />
:以下例子展示一个客户端使用STARTTLS保护数据流 (注意: 以下步骤举例说明协议中的失败案例;在这个例子中它们并不详尽并且也不是必须被数据传输触发的).<br />
<br />
:步骤 1: 客户端初始化流给服务器:<br />
<br />
<source lang="xml"><br />
<stream:stream xmlns='jabber:client' xmlns:stream='http://etherx.jabber.org/streams' to='example.com' version='1.0'><br />
</source><br />
<br />
:步骤 2: 服务器发送一个流标签给客户端作为应答:<br />
<br />
<source lang="xml"><br />
<stream:stream xmlns='jabber:client' xmlns:stream='http://etherx.jabber.org/streams' id='c2s_123' from='example.com' version='1.0'><br />
</source><br />
<br />
:步骤 3: 服务器发送 STARTTLS 范围给客户端(包括验证机制和任何其他流特性):<br />
<br />
<source lang="xml"><br />
<stream:features><br />
<starttls xmlns='urn:ietf:params:xml:ns:xmpp-tls'><br />
<required/><br />
</starttls><br />
<mechanisms xmlns='urn:ietf:params:xml:ns:xmpp-sasl'><br />
<mechanism>DIGEST-MD5</mechanism><br />
<mechanism>PLAIN</mechanism><br />
</mechanisms><br />
</stream:features><br />
</source><br />
<br />
:步骤 4: 客户端发送 STARTTLS 命令给服务器:<br />
<br />
<source lang="xml"><br />
<starttls xmlns='urn:ietf:params:xml:ns:xmpp-tls'/><br />
</source><br />
<br />
:步骤 5: 服务器通知客户端可以继续进行:<br />
<br />
<source lang="xml"><br />
<proceed xmlns='urn:ietf:params:xml:ns:xmpp-tls'/><br />
</source><br />
<br />
:步骤 5 (或者): 服务器通知客户端 TLS 握手失败并关闭流和TCP连接:<br />
<br />
<source lang="xml"><br />
<failure xmlns='urn:ietf:params:xml:ns:xmpp-tls'/><br />
</stream:stream><br />
</source><br />
<br />
:步骤 6: 客户端和服务器尝试通过已有的TCP连接完成 TLS 握手.<br />
<br />
:步骤 7: 如果 TLS 握手成功, 客户端初始化一个新的流给服务器:<br />
<br />
<source lang="xml"><br />
<stream:stream xmlns='jabber:client' xmlns:stream='http://etherx.jabber.org/streams' to='example.com' version='1.0'><br />
</source><br />
<br />
:步骤 7 (或者): 如果 TLS 握手不成功, 服务器关闭 TCP 连接.<br />
<br />
:步骤 8: 服务器发送一个流头信息应答客户端,其中包括任何可用的流特性:<br />
<br />
<source lang="xml"><br />
<stream:stream xmlns='jabber:client' xmlns:stream='http://etherx.jabber.org/streams' from='example.com' id='c2s_234' version='1.0'><br />
<stream:features><br />
<mechanisms xmlns='urn:ietf:params:xml:ns:xmpp-sasl'><br />
<mechanism>DIGEST-MD5</mechanism><br />
<mechanism>PLAIN</mechanism><br />
<mechanism>EXTERNAL</mechanism><br />
</mechanisms><br />
</stream:features><br />
</source><br />
<br />
:步骤 9: 客户端继续 SASL 握手 (第六章).<br />
<br />
===服务器-服务器示例===<br />
<br />
:以下例子展示两个服务器之间使用STARTTLS保护数据流 (注意: 以下步骤举例说明协议中的失败案例;在这个例子中它们并不详尽并且也不是必须被数据传输触发的).<br />
<br />
:步骤 1: Server1 初始化流给 Server2:<br />
<br />
<source lang="xml"><br />
<stream:stream xmlns='jabber:server' xmlns:stream='http://etherx.jabber.org/streams' to='example.com' version='1.0'><br />
</source><br />
<br />
:步骤 2: Server2 发送一个流标签给 Server1 作为应答:<br />
<br />
<source lang="xml"><br />
<stream:stream xmlns='jabber:server' xmlns:stream='http://etherx.jabber.org/streams' from='example.com' id='s2s_123' version='1.0'><br />
</source><br />
<br />
:步骤 3: Server2 发送 STARTTLS 范围给 Server1 ,包括验证机制和任何其他流特性:<br />
<br />
<source lang="xml"><br />
<stream:features><br />
<starttls xmlns='urn:ietf:params:xml:ns:xmpp-tls'><br />
<required/><br />
</starttls><br />
<mechanisms xmlns='urn:ietf:params:xml:ns:xmpp-sasl'><br />
<mechanism>DIGEST-MD5</mechanism><br />
<mechanism>KERBEROS_V4</mechanism><br />
</mechanisms><br />
</stream:features><br />
</source><br />
<br />
:步骤 4: Server1 发送 STARTTLS 命令给 Server2:<br />
<br />
<source lang="xml"><br />
<starttls xmlns='urn:ietf:params:xml:ns:xmpp-tls'/><br />
</source><br />
<br />
:步骤 5: Server2 通知 Server1 允许继续进行:<br />
<br />
<source lang="xml"><br />
<proceed xmlns='urn:ietf:params:xml:ns:xmpp-tls'/><br />
</source><br />
<br />
:步骤 5 (或者): Server2 通知 Server1 TLS握手失败并关闭流:<br />
<br />
<source lang="xml"><br />
<failure xmlns='urn:ietf:params:xml:ns:xmpp-tls'/><br />
</stream:stream><br />
</source><br />
<br />
:步骤 6: Server1 和 Server2 尝试通过 TCP 完成 TLS 握手.<br />
<br />
:步骤 7: 如果 TLS 握手成功, Server1 初始化一个新的流给 Server2:<br />
<br />
<source lang="xml"><br />
<stream:stream xmlns='jabber:server' xmlns:stream='http://etherx.jabber.org/streams' to='example.com' version='1.0'><br />
</source><br />
<br />
:步骤 7 (或者): 如果 TLS 握手不成功, Server2 关闭 TCP 连接.<br />
<br />
:步骤 8: Server2 发送一个包含任何可用流特性的流头信息给 Server1 :<br />
<br />
<source lang="xml"><br />
<stream:stream xmlns='jabber:server' xmlns:stream='http://etherx.jabber.org/streams' from='example.com' id='s2s_234' version='1.0'><br />
<stream:features><br />
<mechanisms xmlns='urn:ietf:params:xml:ns:xmpp-sasl'><br />
<mechanism>DIGEST-MD5</mechanism><br />
<mechanism>KERBEROS_V4</mechanism><br />
<mechanism>EXTERNAL</mechanism><br />
</mechanisms><br />
</stream:features><br />
</source><br />
<br />
:步骤 9: Server1 继续进行 SASL 握手(第六章).<br />
<br />
==SASL 的使用==<br />
<br />
===概览===<br />
<br />
:XMPP 有一个验证流的方法,即XMPP特定的SASL(简单验证和安全层)[SASL]。SASL提供了一个通用的方法为基于连接的协议增加验证支持,而XMPP使用了一个普通的XML名字空间来满足SASL的需要。<br />
<br />
:以下规则应用于:<br />
<br />
:# 如果SASL协商发生在两台服务器之间,除非服务器宣称的DNS主机名得到解析,否则不能(MUST NOT)进行通信。(参见 服务器间的通信(第十四章第四节)).<br />
:# 如果初始化实体有能力使用 SASL 协商, 它必须(MUST)在初始化流的头信息中包含一个值为"1.0"的属性'version'。<br />
:# 如果接收实体有能力使用 SASL 协商, 它必须(MUST)在应答从初始化实体收到的打开流标签时(如果打开的流标签包含一个值为"1.0"的'version'属性),通过'urn:ietf:params:xml:ns:xmpp-sasl'名字空间中的<mechanisms/>元素声明一个或多个验证机制.<br />
:# 当 SASL 协商时, 一个实体不能(MUST NOT)在流的根元素中发送任何空格符号(匹配 production [3] content of [XML])作为元素之间的分隔符(在以下的SASL例子中任何空格符号的出现仅仅是为了增加可读性); 这条禁令帮助确保安全层字节的精确度。<br />
:# 当SASL握手时,在XML元素中使用的任何 XML 字符数据必须被编码成 base64, 编码遵循 RFC 3548 第三章的规定。<br />
:# 如果一个 简单名字"simple username" 规范被选定的SASL机制所支持,(比如, 这被 DIGEST-MD5 和 CRAM-MD5 机制支持但不被 EXTERNAL 和 GSSAPI 机制支持), 验证的时候初始化实体应该(SHOULD)在服务器间通信时提供 简单名字 自身的发送域(IP地址或包含在一个域标识符中的域名全称),在客户端与服务器之间通信时提供注册用户名(包含在一个XMPP节点标识符中的用户或节点名)。<br />
:# 如果初始化实体希望以另一个实体的身份出现并且SASL机制支持授权ID的传输,初始化实体在SASL握手时必须(MUST)提供一个授权ID。如果初始化实体不希望以另一个实体的身份出现,初始化实体在SASL握手时不能(MUST NOT)提供一个授权ID。在 [SASL] 的定义中,除非授权ID不同于从验证ID(详见[SASL])中得到的缺省的授权ID,初始化实体不能(MUST NOT)提供授权ID。如果提供了,这个授权ID的值必须(MUST)是<domain>的格式(对于服务器来说)或<node@domain>的格式(对于客户端来说). <br />
:# 在成功进行包括安全层的SASL握手之后,接收实体必须(MUST)丢弃任何从初始化实体得到的而不是从SASL协商本身获得的信息。<br />
:# 在成功进行包括安全层的SASL握手之后,初始化实体必须(MUST)丢弃任何从接收实体得到的而不是从SASL协商本身获得的信息。<br />
:# 参看 强制执行的技术 (第十四章第七节) ,了解关于必须(MUST)支持的机制.<br />
<br />
===叙述===<br />
<br />
:一个初始化实体使用SASL和接收实体做验证的步骤如下:<br />
<br />
:# 初始化实体请求SASL验证,它发送一个打开的XML流头信息给接收实体,其'version'属性的值为"1.0".<br />
:# 在发送一个XML流头回复之后,接收实体声明一个可用的SASL验证机制清单;每个机制作为一个<mechanism/>元素,作为子元素包含在<mechanisms/>容器元素(其名字空间为'urn:ietf:params:xml:ns:xmpp-sasl')中,而<mechanisms/>则包含在流名字空间中的<features/>元素中。如果在使用任何验证机制之前需要使用TLS(见第五章),接收实体不能(MUST NOT)在TLS握手之前提供可用的SASL验证机制清单。如果初始化实体在优先的TLS协商过程中呈现了一个合法的证书,接收实体应该(SHOULD)在SASL握手中提出一个SASL外部机制给初始化实体,尽管这个外部机制可以(MAY)在其它环境下提供。<br />
:# 初始化实体发送一个符合'urn:ietf:params:xml:ns:xmpp-sasl'名字空间的<auth/>元素(其中包含了适当的'mechanism'属性值)给接收实体,以选择一个机制。如果这个机制支持或需要,这个元素可以(MAY)包含XML字符数据(在SASL术语中,即“初始化应答”);如果初始化实体需要发送一个零字节的初始化应答,它必须(MUST)传输一个单独的等号作为应答,这表示应答有效但不包含数据。<br />
:# 如果必要,接收实体向初始化实体发送一个符合'urn:ietf:params:xml:ns:xmpp-sasl'名字空间的<challenge/>元素来发出挑战;这个元素可以(MAY)包含XML字符数据(必须按照初始化实体选择的SASL机制进行一致性运算)。<br />
:# 初始化实体向接收实体发送符合'urn:ietf:params:xml:ns:xmpp-sasl'名字空间的<response/>元素作为应答;这个元素可以(MAY)包含XML字符数据(必须按照初始化实体选择的SASL机制进行一致性运算)。<br />
:# 如果必要,接收实体发送更多的挑战给初始化实体,初始化实体发送更多的回应。<br />
<br />
:这一系列的 挑战/应答 组,持续进行直到发生以下三件事中的一件为止:<br />
<br />
:# 初始化实体向接收实体发送符合'urn:ietf:params:xml:ns:xmpp-sasl'名字空间的<abort/>元素以中止握手。在接收到<abort/>元素之后,接收实体应该(SHOULD)允许一个可配置的但是合理的重试次数(至少2次),然后它必须(MUST)终止TCP连接;这使得初始化实体(如一个最终用户客户端)能够容忍可能不正确的credentials(如密码输入错误)而不用强制重新连接。<br />
:# 接收实体向初始化实体发送符合'urn:ietf:params:xml:ns:xmpp-sasl'名字空间的<failure/>元素以报告握手失败(详细的失败原因应该在<failure/>的一个适当的子元素中沟通,在第六章第四节中的SASL Errors中定义)。如果失败的情况发生了,接收实体应该(SHOULD)允许一个可配置的但是合理的重试次数(至少2次), 然后它必须(MUST)终止TCP连接;这使得初始化实体(如一个最终用户客户端)能够容忍可能不正确的credentials(如密码输入错误)而不用强制重新连接。<br />
:# 接收实体向初始化实体发送符合'urn:ietf:params:xml:ns:xmpp-sasl'名字空间的<success/>元素以报告握手成功;如果所选择的SASL机制要求,这个元素可以(MAY)包含XML字符数据(见SASL术语,“成功的额外数据”)。接收到<success/> 元素之后,初始化实体必须(MUST)发送一个打开的XML流头信息给接收实体以发起一个新的的流(不需要先发送一个 </stream>标签,因为在发送和接收到<success/>元素之后,接收实体和初始化实体必须确认原来的流被关闭了)。从初始化实体接收到新的流头信息之后,接收实体必须(MUST)发送一个新的流头信息给初始化实体作为回应,附上任何可用的特性(但不包括 STARTTLS 和 SASL 特性)或一个空的 <features/> 元素(这表示没有更多的特性可用);任何没有在本文定义的附加特性必须(MUST)在XMPP的相关扩展中定义。<br />
<br />
===SASL 定义===<br />
<br />
:[SASL]的必要条件要求通过协议定义来提供以下信息:<br />
<br />
::service name(服务名): "xmpp"<br />
<br />
::initiation sequence(开始序列): 当初始化实体提供一个打开的XML流头信息并且接收实体善意回应之后,接收实体提供一个可接受的验证方法清单。初始化实体从这个清单中选择一个方法,把它作为 <auth/> 元素的 'mechanism' 属性的值发送给接收实体,也可以选择发送一个初始化应答以避免循环。<br />
<br />
::exchange sequence(交换序列): 挑战和回应的交换,从接收实体发送给初始化实体的 <challenge/> 元素和从初始化实体发送给接收实体的 <response/> 元素信息。接收实体通过发送 <failure/>元素报告失败,发送<success/>元素报告成功;初始化实体通过发送<abort/> 元素中止交换。成功的协商之后,两边都认为原来的XML流已经关闭并且都开始发送新的流头信息。<br />
<br />
::security layer negotiation(安全层协商): 安全层在接收实体发送 <success/> 元素的关闭字符">"之后立刻生效,在初始化实体发送 <success/> 元素的关闭字符">"之后也立刻生效。层的顺序是 [TCP],[TLS],然后是 [SASL],然后是 [XMPP]。<br />
<br />
::use of the authorization identity(授权ID的使用): 授权ID可在xmpp中用于表示一个客户端的非缺省的<node@domain>,或一个服务器的<domain> 。<br />
<br />
===SASL 错误===<br />
<br />
:SASL相关的错误条件定义如下:<br />
<br />
::* <aborted/> -- 接收实体认可由初始化实体发送的<abort/>元素;在回应一个<abort/>元素时发送。<br />
<br />
::* <incorrect-encoding/> -- 由初始化实体提供的数据无法处理,因为[BASE64]编码不正确(例如,因为编码不符合[BASE64]的第三章); 在回应一个包含初始化响应数据的<response/> 元素或<auth/>元素时发送.<br />
<br />
::* <invalid-authzid/> -- 由初始化实体提供的授权id是非法的,因为它的格式不正确或初始化实体无权给那个ID授权;在回应一个包含初始化响应数据的<response/> 元素或<auth/>元素时发送。<br />
<br />
::* <invalid-mechanism/> -- 初始化实体不能提供一个机制活、或请求一个不被接受实体支持的机制;在回应一个<auth/>元素时发送。<br />
<br />
::* <mechanism-too-weak/> -- 初始化实体请求的机制比服务器策略对它的要求弱;在回应一个包含初始化响应数据的<response/> 元素或<auth/>元素时发送。<br />
<br />
::* <not-authorized/> -- 验证失败,因为初始化实体没有提供合法的credentials(这包括但不限于未知用户名等情形);在回应一个包含初始化响应数据的<response/> 元素或<auth/>元素时发送。<br />
<br />
::* <temporary-auth-failure/> -- 验证失败,因为接收实体出现了临时的错误;在回应一个<response/> 元素或<auth/>元素时发送。<br />
<br />
===客户端-服务器 示例===<br />
<br />
:以下例子展示了一个客户端和一个服务器使用SASL作验证的数据流,通常是在成功的TLS握手之后(注意:以下显示的替代步骤仅用于举例说明协议的失败情形;它们不够详尽也不需要由例子中的数据传送来触发)。<br />
<br />
:步骤 1: 客户端初始化流给服务器:<br />
<br />
<source lang="xml"><br />
<stream:stream xmlns='jabber:client' xmlns:stream='http://etherx.jabber.org/streams' to='example.com' version='1.0'><br />
</source><br />
<br />
:步骤 2: 服务器向客户端发送流标签作为应答:<br />
<br />
<source lang="xml"><br />
<stream:stream xmlns='jabber:client' xmlns:stream='http://etherx.jabber.org/streams' id='c2s_234' from='example.com' version='1.0'><br />
</source><br />
<br />
:步骤 3: 服务器通知客户端可用的验证机制:<br />
<br />
<source lang="xml"><br />
<stream:features><br />
<mechanisms xmlns='urn:ietf:params:xml:ns:xmpp-sasl'><br />
<mechanism>DIGEST-MD5</mechanism><br />
<mechanism>PLAIN</mechanism><br />
</mechanisms><br />
</stream:features><br />
</source><br />
<br />
:步骤 4: 客户端选择一个验证机制:<br />
<br />
<source lang="xml"><br />
<auth xmlns='urn:ietf:params:xml:ns:xmpp-sasl' mechanism='DIGEST-MD5'/><br />
</source><br />
<br />
:步骤 5: 服务器发送一个 [BASE64] 编码的挑战给客户端:<br />
<br />
<source lang="xml"><br />
<challenge xmlns='urn:ietf:params:xml:ns:xmpp-sasl'><br />
cmVhbG09InNvbWVyZWFsbSIsbm9uY2U9Ik9BNk1HOXRFUUdtMmhoIixxb3A9ImF1dGgi<br />
LGNoYXJzZXQ9dXRmLTgsYWxnb3JpdGhtPW1kNS1zZXNzCg==<br />
</challenge><br />
</source><br />
<br />
:解码后的挑战信息是:<br />
<br />
<source lang="xml"><br />
realm="somerealm",nonce="OA6MG9tEQGm2hh",\<br />
qop="auth",charset=utf-8,algorithm=md5-sess<br />
</source><br />
<br />
:步骤 5 (替代): 服务器返回一个错误给客户端:<br />
<br />
<source lang="xml"><br />
<failure xmlns='urn:ietf:params:xml:ns:xmpp-sasl'><br />
<incorrect-encoding/><br />
</failure><br />
</stream:stream><br />
</source><br />
<br />
:步骤 6: 客户端发送一个[BASE64]编码的回应这个挑战:<br />
<br />
<source lang="xml"><br />
<response xmlns='urn:ietf:params:xml:ns:xmpp-sasl'><br />
dXNlcm5hbWU9InNvbWVub2RlIixyZWFsbT0ic29tZXJlYWxtIixub25jZT0i<br />
T0E2TUc5dEVRR20yaGgiLGNub25jZT0iT0E2TUhYaDZWcVRyUmsiLG5jPTAw<br />
MDAwMDAxLHFvcD1hdXRoLGRpZ2VzdC11cmk9InhtcHAvZXhhbXBsZS5jb20i<br />
LHJlc3BvbnNlPWQzODhkYWQ5MGQ0YmJkNzYwYTE1MjMyMWYyMTQzYWY3LGNo<br />
YXJzZXQ9dXRmLTgK<br />
</response><br />
</source><br />
<br />
:解码后的回应信息是:<br />
<br />
<source lang="xml"><br />
username="somenode",realm="somerealm",\<br />
nonce="OA6MG9tEQGm2hh",cnonce="OA6MHXh6VqTrRk",\<br />
nc=00000001,qop=auth,digest-uri="xmpp/example.com",\<br />
response=d388dad90d4bbd760a152321f2143af7,charset=utf-8<br />
</source><br />
<br />
:步骤 7: 服务器发送另一个[BASE64]编码的挑战给客户端:<br />
<br />
<source lang="xml"><br />
<challenge xmlns='urn:ietf:params:xml:ns:xmpp-sasl'><br />
cnNwYXV0aD1lYTQwZjYwMzM1YzQyN2I1NTI3Yjg0ZGJhYmNkZmZmZAo=<br />
</challenge><br />
</source><br />
<br />
:解码后的挑战信息是:<br />
<br />
<source lang="xml"><br />
rspauth=ea40f60335c427b5527b84dbabcdfffd<br />
</source><br />
<br />
:步骤 7 (或者): 服务器返回一个错误给客户端:<br />
<br />
<source lang="xml"><br />
<failure xmlns='urn:ietf:params:xml:ns:xmpp-sasl'><br />
<temporary-auth-failure/><br />
</failure><br />
</stream:stream><br />
</source><br />
<br />
:步骤 8: 客户端应答这个挑战:<br />
<br />
<source lang="xml"><br />
<response xmlns='urn:ietf:params:xml:ns:xmpp-sasl'/><br />
</source><br />
<br />
:步骤 9: 服务器通知客户端验证成功:<br />
<br />
<source lang="xml"><br />
<success xmlns='urn:ietf:params:xml:ns:xmpp-sasl'/><br />
</source><br />
<br />
:步骤 9 (或者): 服务器通知客户端验证失败:<br />
<br />
<source lang="xml"><br />
<failure xmlns='urn:ietf:params:xml:ns:xmpp-sasl'><br />
<temporary-auth-failure/><br />
</failure><br />
</stream:stream><br />
</source><br />
<br />
:步骤 10: 客户端发起一个新的流给服务器:<br />
<br />
<source lang="xml"><br />
<stream:stream xmlns='jabber:client' xmlns:stream='http://etherx.jabber.org/streams' to='example.com' version='1.0'><br />
</source><br />
<br />
:步骤 11: 服务器发送一个流头信息回应客户端,并附上任何可用的特性(或空的features元素):<br />
<br />
<source lang="xml"><br />
<stream:stream xmlns='jabber:client' xmlns:stream='http://etherx.jabber.org/streams' id='c2s_345' from='example.com' version='1.0'><br />
<stream:features><br />
<bind xmlns='urn:ietf:params:xml:ns:xmpp-bind'/><br />
<session xmlns='urn:ietf:params:xml:ns:xmpp-session'/><br />
</stream:features><br />
</source><br />
<br />
===服务器-服务器 示例===<br />
<br />
:以下例子展示了一个服务器和另一个服务器使用SASL作验证的数据流,通常是在成功的TLS握手之后(注意:以下显示的替代步骤仅用于举例说明协议的失败情形;它们不够详尽也不需要由例子中的数据传送来触发)。<br />
<br />
:步骤 1: 服务器1 发起一个流给 服务器2 :<br />
<br />
<source lang="xml"><br />
<stream:stream xmlns='jabber:server' xmlns:stream='http://etherx.jabber.org/streams' to='example.com' version='1.0'><br />
</source><br />
<br />
:步骤 2: 服务器2 回应一个流标签给 服务器1:<br />
<br />
<source lang="xml"><br />
<stream:stream xmlns='jabber:server' xmlns:stream='http://etherx.jabber.org/streams' from='example.com' id='s2s_234' version='1.0'><br />
</source><br />
<br />
:步骤 3: 服务器2 通知 服务器1 可用的验证机制:<br />
<br />
<source lang="xml"><br />
<stream:features><br />
<mechanisms xmlns='urn:ietf:params:xml:ns:xmpp-sasl'><br />
<mechanism>DIGEST-MD5</mechanism><br />
<mechanism>KERBEROS_V4</mechanism><br />
</mechanisms><br />
</stream:features><br />
</source><br />
<br />
:步骤 4: 服务器1 选择一个验证机制:<br />
<br />
<source lang="xml"><br />
<auth xmlns='urn:ietf:params:xml:ns:xmpp-sasl' mechanism='DIGEST-MD5'/><br />
</source><br />
<br />
:步骤 5: 服务器2 发送一个[BASE64]编码的挑战给 服务器1:<br />
<br />
<source lang="xml"><br />
<challenge xmlns='urn:ietf:params:xml:ns:xmpp-sasl'><br />
cmVhbG09InNvbWVyZWFsbSIsbm9uY2U9Ik9BNk1HOXRFUUdtMmhoIixxb3A9<br />
ImF1dGgiLGNoYXJzZXQ9dXRmLTgsYWxnb3JpdGhtPW1kNS1zZXNz<br />
</challenge><br />
</source><br />
<br />
:解码后的挑战信息是:<br />
<br />
<source lang="xml"><br />
realm="somerealm",nonce="OA6MG9tEQGm2hh",\<br />
qop="auth",charset=utf-8,algorithm=md5-sess<br />
</source><br />
<br />
:步骤 5 (替代): 服务器2 返回一个错误给 服务器1:<br />
<br />
<source lang="xml"><br />
<failure xmlns='urn:ietf:params:xml:ns:xmpp-sasl'><br />
<incorrect-encoding/><br />
</failure><br />
</stream:stream><br />
</source><br />
<br />
:步骤 6: 服务器1 发送一个[BASE64]编码的回应这个挑战:<br />
<br />
<source lang="xml"><br />
<response xmlns='urn:ietf:params:xml:ns:xmpp-sasl'><br />
dXNlcm5hbWU9ImV4YW1wbGUub3JnIixyZWFsbT0ic29tZXJlYWxtIixub25j<br />
ZT0iT0E2TUc5dEVRR20yaGgiLGNub25jZT0iT0E2TUhYaDZWcVRyUmsiLG5j<br />
PTAwMDAwMDAxLHFvcD1hdXRoLGRpZ2VzdC11cmk9InhtcHAvZXhhbXBsZS5v<br />
cmciLHJlc3BvbnNlPWQzODhkYWQ5MGQ0YmJkNzYwYTE1MjMyMWYyMTQzYWY3<br />
LGNoYXJzZXQ9dXRmLTgK<br />
</response><br />
</source><br />
<br />
:解码后的应答信息是:<br />
<br />
<source lang="xml"><br />
username="example.org",realm="somerealm",\<br />
nonce="OA6MG9tEQGm2hh",cnonce="OA6MHXh6VqTrRk",\<br />
nc=00000001,qop=auth,digest-uri="xmpp/example.org",\<br />
response=d388dad90d4bbd760a152321f2143af7,charset=utf-8<br />
</source><br />
<br />
:步骤 7: 服务器2 发送另外一个[BASE64]编码的挑战给 服务器1:<br />
<br />
<source lang="xml"><br />
<challenge xmlns='urn:ietf:params:xml:ns:xmpp-sasl'><br />
cnNwYXV0aD1lYTQwZjYwMzM1YzQyN2I1NTI3Yjg0ZGJhYmNkZmZmZAo=<br />
</challenge><br />
</source><br />
<br />
:解码后的挑战信息是:<br />
<br />
<source lang="xml"><br />
rspauth=ea40f60335c427b5527b84dbabcdfffd<br />
</source><br />
<br />
:步骤 7 (或者): 服务器2 返回一个错误给 服务器1:<br />
<br />
<source lang="xml"><br />
<failure xmlns='urn:ietf:params:xml:ns:xmpp-sasl'><br />
<invalid-authzid/><br />
</failure><br />
</stream:stream><br />
</source><br />
<br />
:步骤 8: 服务器1 回应挑战:<br />
<br />
<source lang="xml"><br />
<response xmlns='urn:ietf:params:xml:ns:xmpp-sasl'/><br />
</source><br />
<br />
:步骤 8 (或者): 服务器1 中止协商:<br />
<br />
<source lang="xml"><br />
<abort xmlns='urn:ietf:params:xml:ns:xmpp-sasl'/><br />
</source><br />
<br />
:步骤 9: 服务器2 通知 服务器1 验证成功:<br />
<br />
<source lang="xml"><br />
<success xmlns='urn:ietf:params:xml:ns:xmpp-sasl'/><br />
</source><br />
<br />
:步骤 9 (或者): 服务器2 通知 服务器1 验证失败:<br />
<br />
<source lang="xml"><br />
<failure xmlns='urn:ietf:params:xml:ns:xmpp-sasl'><br />
<aborted/><br />
</failure><br />
</stream:stream><br />
</source><br />
<br />
:步骤 10: 服务器1 重新发起一个新的流给 服务器2:<br />
<br />
<source lang="xml"><br />
<stream:stream xmlns='jabber:server' xmlns:stream='http://etherx.jabber.org/streams' to='example.com' version='1.0'><br />
</source><br />
<br />
:步骤 11: 服务器2 发送一个流头信息应答 服务器1 ,并附上任何可用的特性(或一个空的features元素).:<br />
<br />
<source lang="xml"><br />
<stream:stream xmlns='jabber:client' xmlns:stream='http://etherx.jabber.org/streams' from='example.com' id='s2s_345' version='1.0'><br />
<stream:features/><br />
</source><br />
<br />
==资源绑定==<br />
<br />
:在和接收实体完成 SASL 协商(第六章)之后,初始化实体可能(MAY)想要或者需要绑定一个特定的资源到流上.通常这仅适用于客户端: 为了满足本文定义的寻址格式(第三章)和节传输规则(第十章),客户端<node@domain>必须(MUST)拥有一个相关的资源ID(由服务器生成或由客户端程序提供);以确保在流上使用的地址是一个“全JID”(<node@domain/resource>)。<br />
<br />
:接收到一个成功的SASL握手之后,客户端必须(MUST)发送一个新的流头信息给服务器,服务器必须(MUST)返回一个包含可用的流特性列表的头信息。特别是,在成功的SASL握手之后如果服务器需要客户端绑定一个资源,它必须(MUST)在握手成功之后(而不是之前)发送给客户端的应答流特性中包含一个空的符合'urn:ietf:params:xml:ns:xmpp-bind'名字空间的<bind/>元素。:<br />
<br />
:服务器向客户端声明资源绑定特性:<br />
<br />
<source lang="xml"><br />
<stream:stream xmlns='jabber:client' xmlns:stream='http://etherx.jabber.org/streams' id='c2s_345' from='example.com' version='1.0'><br />
<stream:features><br />
<bind xmlns='urn:ietf:params:xml:ns:xmpp-bind'/><br />
</stream:features><br />
</source><br />
<br />
:收到要求资源绑定的通知后,客户端必须(MUST)通过发送一个符合'urn:ietf:params:xml:ns:xmpp-bind'名字空间的“set”类型的IQ节(参见 IQ 语义 (第九章第二节第三小节))给服务器来绑定一个资源到流中。<br />
<br />
:如果客户端端希望允许服务器给自己生成一个资源ID,它可以发送一个包含空的<bind/>元素的“set”类型的IQ节。:<br />
<br />
:客户端请求服务器绑定资源:<br />
<br />
<source lang="xml"><br />
<iq type='set' id='bind_1'><br />
<bind xmlns='urn:ietf:params:xml:ns:xmpp-bind'/><br />
</iq><br />
</source><br />
<br />
:一个支持资源绑定的服务器必须(MUST)自动生成一个资源ID给客户端。一个由服务器生成的资源ID对于那个<node@domain>必须(MUST)是唯一的。<br />
<br />
:如果客户端希望指定资源ID,它发送一个包含期望资源ID的“set”类型的 IQ节,把资源ID作为<bind/>元素下的<resource/>子元素的XML字符数据:<br />
<br />
:客户端绑定一个资源:<br />
<br />
<source lang="xml"><br />
<iq type='set' id='bind_2'><br />
<bind xmlns='urn:ietf:params:xml:ns:xmpp-bind'><br />
<resource>someresource</resource><br />
</bind><br />
</iq><br />
</source><br />
<br />
:一旦服务器为客户端生成了一个资源ID或接受了客户端自己提供的资源ID,它必须(MUST)返回一个“result”类型的 IQ 节给客户端,这个节必须包含一个指明全JID的<jid/>子元素表示服务器决定连接的资源:<br />
<br />
:服务器通知客户端资源绑定成功:<br />
<br />
<source lang="xml"><br />
<iq type='result' id='bind_2'><br />
<bind xmlns='urn:ietf:params:xml:ns:xmpp-bind'><br />
<jid>somenode@example.com/someresource</jid><br />
</bind><br />
</iq><br />
</source><br />
<br />
:一个服务器应该(SHOULD)接受客户端提供的资源ID,但是可以(MAY)用服务器生成的资源ID覆盖它;在这种情况下,服务器不应该(SHOULD NOT)返回一个错误信息一个(如<forbidden/>)给客户端,而应该(SHOULD)在上文所述的 IQ result 中返回生成的资源ID。<br />
<br />
:当一个客户端自行提供资源ID时,可能发生以下的节错误(参见 Stanza Errors (第九章第三节)):<br />
<br />
::- 提供的资源ID服务器无法处理,因为不符合资源字符规范Resourceprep(附录B)。<br />
<br />
::- 客户端不被允许绑定一个资源(如节点或用户已经达到允许连接的资源数限制)。<br />
<br />
::- 提供的资源ID已经被使用但是服务器不允许以同一个资源ID绑定多个连接。<br />
<br />
:协议对这些错误条件规定如下.<br />
<br />
::资源ID不能处理:<br />
<br />
<source lang="xml"><br />
<iq type='error' id='bind_2'><br />
<bind xmlns='urn:ietf:params:xml:ns:xmpp-bind'><br />
<resource>someresource</resource><br />
</bind><br />
<error type='modify'><br />
<bad-request xmlns='urn:ietf:params:xml:ns:xmpp-stanzas'/><br />
</error><br />
</iq><br />
</source><br />
<br />
::客户端不允许绑定一个资源:<br />
<br />
<source lang="xml"><br />
<iq type='error' id='bind_2'><br />
<bind xmlns='urn:ietf:params:xml:ns:xmpp-bind'><br />
<resource>someresource</resource><br />
</bind><br />
<error type='cancel'><br />
<not-allowed xmlns='urn:ietf:params:xml:ns:xmpp-stanzas'/><br />
</error><br />
</iq><br />
</source><br />
<br />
::资源ID已经在使用:<br />
<br />
<source lang="xml"><br />
<iq type='error' id='bind_2'><br />
<bind xmlns='urn:ietf:params:xml:ns:xmpp-bind'><br />
<resource>someresource</resource><br />
</bind><br />
<error type='cancel'><br />
<conflict xmlns='urn:ietf:params:xml:ns:xmpp-stanzas'/><br />
</error><br />
</iq><br />
</source><br />
<br />
:如果,在完成资源绑定步骤之前,客户端试图以符合'urn:ietf:params:xml:ns:xmpp-bind'名字空间的<bind/>子元素发送一个非IQ类型的XML节,服务器不能(MUST NOT)处理这个节,而应该(SHOULD)返回一个<not-authorized/>节错误信息给客户端.<br />
<br />
==服务器回拨==<br />
<br />
===概览===<br />
<br />
:Jabber协议接受的来自XMPP的包括“服务器回拨”方法,用于防治域名欺骗,使得欺骗XML节更为困难。服务器回拨不是一个安全机制,并且它的服务器身份认证结果很弱(参见服务器之间的通信(第十四章第四节)中关于这个方法的安全特性)。需要健壮的安全性的域名应该(SHOULD)使用TLS或SASL;细节参见服务器间的通信(第十四章第四节)。如果SASL用于服务器间通信,回拨就不需要用了(SHOULD NOT)。本文描述回拨的好处在于向后兼容现存的实现和部署。<br />
<br />
:服务器回拨方法由现存的DNS系统的存在而成为可能,因为一个服务器(通常)可以查询给定域的授权服务器。由于服务器回拨依赖于DNS,除非服务器宣称的DNS主机得到解析,域之间的通信无法进行(参见服务器间的通信(第十四章第四节))。<br />
<br />
:服务器回拨是单向性的,可在单一方向上对一个流进行(微弱的)身份验证.因为服务器回拨不是一个验证机制,通过回拨获得相互的认证是不可能的.因此,为了使得服务器之间的双向通信,服务器回拨必须(MUST)在每个方向上完成。<br />
<br />
:在服务器回拨中生成和检验密钥的方法必须(MUST)考虑计算被使用的主机名,由接收服务器生成的流ID,和只有授权服务器网络才知道的秘密。在服务器回拨中流ID是安全性的关键所以必须(MUST)是不可预知的和不可重复的(见[RANDOM]中关于使用随机数获得安全性的建议).<br />
<br />
:任何回拨协商过程中发生的错误必须(MUST)被当成一个流错误,并导致流以及相关的TCP连接的终止.可能发生的错误情况协议中描述如下.<br />
<br />
:以下术语适用:<br />
<br />
:* 发起服务器 -- 尝试在两个域之间建立连接的那个服务器.<br />
<br />
:* 接收服务器 -- 尝试验证发起服务期声称的域名的那台服务器.<br />
<br />
:* 授权(权威?Authoritative) 服务器 -- 回答发起服务器声称的DNS主机名的服务器;基本上这应该是那台发起服务器,但是它也可能是一个在发起服务器网络中独立的服务器。<br />
<br />
===事件顺序===<br />
<br />
:以下是回拨中的事件顺序的简介:<br />
<br />
:# 发起服务器和接收服务器建立一个连接。<br />
:# 发起服务器通过到连接发送一个 'key' 值给接收服务期。<br />
:# 接收服务器建立一个连接到授权服务器。<br />
:# 接收服务器发送一个相同的 'key' 值给授权服务器。<br />
:# 授权服务器回答这个key是否合法。<br />
:# 接收服务器通知发起服务器是否被验证通过。<br />
<br />
:我们用用以下图形展示这个事件流程(见附件s2s.png):<br />
<br />
{image:img=s2s}<br />
<br />
发起服务器 接收服务器<br />
----------- ---------<br />
| |<br />
| 建立连接 |<br />
| ----------------------> |<br />
| |<br />
| 发stream头 |<br />
| ----------------------> |<br />
| |<br />
| 发stream头 |<br />
| <---------------------- |<br />
| | <br />
| 发回拨key | 授权服务器<br />
| ----------------------> | -------------<br />
| | |<br />
| 建立连接 |<br />
| ----------------------> |<br />
| |<br />
| 发stream头 |<br />
| ----------------------> |<br />
| |<br />
| 发stream头 |<br />
| <---------------------- |<br />
| |<br />
| 发验证请求 |<br />
| ----------------------> |<br />
| |<br />
| 发验证响应 |<br />
| <---------------------- |<br />
|<br />
| 报告回拨结果 |<br />
| <---------------------- |<br />
| |<br />
<br />
===协议===<br />
<br />
:服务器之间互动的细节协议如下:<br />
<br />
:1. 发起服务器和接受服务器建立TCP连接.<br />
<br />
:2. 发起服务器发送流头信息给接收服务器:<br />
<br />
<source lang="xml"><br />
<stream:stream xmlns:stream='http://etherx.jabber.org/streams' xmlns='jabber:server' xmlns:db='jabber:server:dialback'><br />
</source><br />
<br />
:注意: 'to'和'from'属性在流的根元素是可选的(OPTIONAL). 其中包含的xmlns:db名字空间向接收服务器声明了发起服务器支持回拨. 如果名字空间不正确,接收实体必须(MUST)生成一个<invalid-namespace/>流错误条件并且终止XML流和相应的TCP连接.<br />
<br />
:3. 接收服务器应该(SHOULD)回送一个流头信息给发起服务器,为这次交互生成一个唯一性的ID :<br />
<br />
<source lang="xml"><br />
<stream:stream xmlns:stream='http://etherx.jabber.org/streams' xmlns='jabber:server' xmlns:db='jabber:server:dialback' id='457F9224A0...'><br />
</source><br />
<br />
:注意: 'to'和'from'属性在流的根元素是可选的(OPTIONAL). 如果名字空间不正确,发起服务器必须生成一个<invalid-namespace/>流错误条件并且终止XML流和相应的TCP连接.也要注意,在这里接收服务器应该(SHOULD)应答但是可以(MAY)出于安全策略考虑只是悄悄地终止XML流和TCP连接;无论如何,如果接收服务器希望继续,它必须(MUST)回送一个流头信息给发起服务器.<br />
<br />
:4. 发起服务器发送一个回拨密钥给接收服务器:<br />
<br />
<source lang="xml"><br />
<db:result to='Receiving Server' from='Originating Server'><br />
98AF014EDC0...<br />
</db:result><br />
</source><br />
<br />
:注意: 这个密钥不由接收服务器检查,因为接收服务器在会话之间(between sessions)不保存发起服务器的信息. 这个由发起服务器生成的密钥必须(MUST)是基于接收服务器在上一步骤中提供的ID值,以及发起服务器与授权服务器共享的安全机制生成的。 如果 'to' 地址的值和接收服务器知道的主机名不匹配,接收服务器必须(MUST)生成一个<host-unknown/>流错误条件并且终止XML流和相应的TCP连接. 如果 'from' 地址和接收服务器已经建立的连接的域名相吻合,接收服务器必须(MUST)维护这个已经存在的连接,直到证明这个新的连接是合法的为止;另外,接收实体可以(MAY)选择生成一个<not-authorized/> 流错误条件给这个新的连接并且终止和新连接申请相关的XML流及相应的TCP连接.<br />
<br />
:5. 接收服务器向发起服务器声明的那个域建立一个 TCP 连接,作为结果它连接到授权服务器. (注意: 为了优化性能, 在这里一个实现可以(MAY)重用现有的连接.)<br />
<br />
:6. 接收服务器发送一个流头信息给授权服务器:<br />
<br />
<source lang="xml"><br />
<stream:stream xmlns:stream='http://etherx.jabber.org/streams' xmlns='jabber:server' xmlns:db='jabber:server:dialback'><br />
</source><br />
<br />
:注意: 'to'和'from'属性在流的根元素是可选的(OPTIONAL). 如果名字空间不正确,授权服务器必须生成一个<invalid-namespace/>流错误条件并且终止XML流和相应的TCP连接. <br />
<br />
:7. 授权服务器发送流头信息给接收服务器:<br />
<br />
<source lang="xml"><br />
<stream:stream xmlns:stream='http://etherx.jabber.org/streams' xmlns='jabber:server' xmlns:db='jabber:server:dialback' id='1251A342B...'><br />
</source><br />
<br />
:注意: 如果名字空间不正确,接收服务器必须生成一个<invalid-namespace/>流错误条件并且终止它和授权服务器之间的XML流和相应的TCP连接. 如果一个流错误发生在接收服务器和 '''授权服务器''' 之间,接收服务器必须(MUST)生成一个 <remote-connection-failed/> 流错误条件并且终止它和 '''发起服务器''' 之间的XML流和相应的TCP连接.<br />
<br />
:8. 接收服务器发送一个密钥检查请求给授权服务器:<br />
<br />
<source lang="xml"><br />
<db:verify from='Receiving Server' to='Originating Server' id='457F9224A0...'><br />
98AF014EDC0...<br />
</db:verify><br />
</source><br />
<br />
:注意: 现在这里已经有了主机名,第三步中接收服务器发送给发起服务器的ID,第四步中发起服务器发送给接收服务器的密钥. 基于这些信息, 加上授权服务器网络共享的安全信息, 这个密钥被证实了.任何可用于验证的办法都可以(MAY)用于生成密钥. 如果 'to' 地址的值和授权服务器知道的主机名不匹配,授权服务器必须(MUST)生成一个<host-unknown/>流错误条件并且终止XML流和相应的TCP连接. 打开这个连接时,如果 'from' 地址和接收服务器声明的主机名(或任何合法的域,如验证过的接收服务器的子域名或寄宿在接收服务器上的其他经过验证的域)不符,授权服务器必须(MUST)生成一个<invalid-from/>流错误条件并且终止XML流和相应的TCP连接.<br />
<br />
:9. 授权服务器检查密钥是否合法:<br />
<br />
<source lang="xml"><br />
<db:verify from='Originating Server' to='Receiving Server' type='valid' id='457F9224A0...'/><br />
</source><br />
<br />
::或<br />
<br />
<source lang="xml"><br />
<db:verify from='Originating Server' to='Receiving Server' type='invalid' id='457F9224A0...'/><br />
</source><br />
<br />
:注意: 如果 ID 和第三步中接收服务器提供的不符,接收服务器必须(MUST)生成一个<invalid-id/>流错误条件并且终止XML流和相应的TCP连接. 如果 'to' 地址的值和接收服务器知道的主机名不匹配,接收服务器必须(MUST)生成一个<host-unknown/>流错误条件并且终止XML流和相应的TCP连接. 打开这个连接时,如果 'from' 地址和发起服务器声明的主机名(或任何合法的域,如验证过的发起服务器的子域名或寄宿在发起服务器上的其他经过验证的域)不符,接收服务器必须(MUST)生成一个<invalid-from/>流错误条件并且终止XML流和相应的TCP连接. 在返回验证信息给接收服务器之后,授权服务器应该(SHOULD)终止它们之间的流.<br />
<br />
:10. 接收服务器通知发起服务器结果:<br />
<br />
<source lang="xml"><br />
<db:result from='Receiving Server'to='Originating Server' type='valid'/><br />
</source><br />
<br />
:注意: 在这一个点上, 连接已经由 type='valid' 确认验证是通过了,还是没通过. 如果连接是非法的,接收服务器必须(MUST)终止XML流和相应的TCP连接. 如果连接是合法的, 数据可以从发起服务器发送由接收服务器读取;在此之前,所有发送给接收服务器的XML节应该(SHOULD)被丢弃.<br />
<br />
:进一步的结果是,接收服务器已经验证了发起服务器的ID,所以通过初始化流("initial stream",例如从发起服务器到接收服务器的流)发起服务器可以发送,接收服务器可以接受XML节. 为了使用应答流("response stream",例如从接收服务器到发起服务器的流)验证实体ID,回拨必须(MUST)在相对的两个方向上都完成.<br />
<br />
:在成功的回拨协商之后, 接收服务器应该(SHOULD)接受接下来发起服务器通过当前的合法连接发送的 <db:result/> 包 (例如, 发送给子域或其他寄宿在接收服务器上的主机名的验证请求); 这在单一方向上激活了原始合法连接的 "piggybacking" .<br />
<br />
:即使回拨协商成功了, 服务器仍然必须(MUST)检查从其他服务器接收的所有XML节的'from'和'to'属性; 如果一个节不符合这些限定, 收到这些节的服务器必须(MUST)生成一个<improper-addressing/> 流错误条件并终止XML流和相应的TCP连接. 而且, 一个服务器也必须(MUST)检查从其他的有合法域名的服务器的流中收到的节的'from'属性; 如果一个节不符合这一限定, 接收节的服务器必须(MUST)生成一个 <invalid-from/> 流错误条件并终止XML流和相应的TCP连接. 所有这些检查都用来帮助防止特定的节伪造行为.<br />
<br />
==XML节==<br />
<br />
:在 TLS 协商(第五章) (如果想要), SASL 协商(第六章), 和资源绑定(第七章)(如果需要)之后, XML节就可以通过流发送了. 在'jabber:client'和'jabber:server'名字空间中定义了三种XML节: <message/>, <presence/>, 和 <iq/>. 另外, 这三种节有五种通用的属性. 这些通用属性, 加上三种节的术语,在这里定义; 更多关于和即时消息及出席信息应用相关的XML节语法详细信息在[XMPP-IM|XMPP文档列表/XMPP正式RFC标准/RFC3921]中提供.<br />
<br />
===通用属性===<br />
<br />
:以下五种属性通用于 message, presence, 和 IQ 节:<br />
<br />
====to====<br />
<br />
:'to' 属性表示节的预期接收者的JID.<br />
<br />
:在'jabber:client'名字空间中, 一个节应该(SHOULD)处理一个'to'属性, 尽管由服务器处理的从客户端发给服务器的节(如, 发送给服务器用于广播给其他实体的出席信息) 应该不(SHOULD NOT)处理'to'属性.<br />
<br />
:在'jabber:server'名字空间中, 一个节必须(MUST)处理一个'to'属性; 如果一个服务器收到一个不符合此限定的节, 它必须(MUST)生成一个<improper-addressing/>流错误条件并终止和这个非法服务器的XML流和相应的TCP连接.<br />
<br />
:如果'to'属性的值非法或无法联络, 发现这个事实的实体(通常是发送者或接收者的服务器)必须(MUST)返回一个适当的错误给发送者, 错误节的'from'属性设置成非法节的提供的'to'属性的值.<br />
<br />
====from====<br />
<br />
:'from' 属性表示发送者的 JID .<br />
<br />
:当一个服务器接收了一个符合'jabber:client'名字空间的合法流的XML节, 它必须(MUST)做以下步骤中的一步:<br />
<br />
:# 验证客户端提供的'from'属性值就是那个相关实体连接的资源<br />
:# 为生成这个节的已连接的资源增加一个'from'地址(由服务器决定是纯JID或全JID)(参见 地址的决定 Determination of Addresses (第三章第五节))<br />
:# 如果一个客户端试图发送一个XML节,而它的'from'属性和这个实体已连接的资源不符, 服务器应该(SHOULD)返回一个<invalid-from/>流错误条件给客户端. 如果一个客户端试图通过一个尚未验证的流发送一个XML节, 服务器应该(SHOULD)返回一个<not-authorized/>流错误条件给客户端. 如果生成了, 所有这些条件必须(MUST)导致流的关闭和相应的TCP连接的终止; 这有助于防止不诚实的客户的拒绝服务攻击.<br />
<br />
:当一个服务器从服务器自身生成一个节用于一个已连接的客户端的信息发布(例如, 在服务器为客户端提供数据存储服务的情况下), 这个节必须(MUST) (1) 不包含 'from' 属性 或 (2) 包含一个'from'属性,它的值是这个账号的纯 JID (<node@domain>) 或 客户端的全 JID (<node@domain/resource>). 如果节不是由服务器自身生成的,那么一个服务器不能(MUST NOT)发送不带'from'属性的节. 当一个客户端接收到一个不包含'from'属性的节, 它必须(MUST)认为这个节是从客户端连接的服务器发来的.<br />
<br />
:在'jabber:server'名字空间, 一个节必须(MUST)处理一个'from'属性; 如果一个服务器接收到一个不符合此限定的节, 它必须(MUST)生成一个<improper-addressing/>流错误条件. 而且, 'from'属性的 JID值的域名ID部分必须(MUST)和以SASL协商连接或以回拨协商连接的发送服务器的主机名(或任何合法的域,如发送服务器主机名的合法子域,或其他寄宿在发送服务器上的合法域)吻合; 如果一个服务器接收到的节不符合此限定, 它必须(MUST)生成一个<invalid-from/>流错误条件. 所有这些条件都必须(MUST)导致流的关闭和相应的TCP连接的终止; 这有助于防止不诚实的客户端发起的拒绝服务攻击.<br />
<br />
====id====<br />
<br />
:可选的'id' 属性可以(MAY)用于为节的内部跟踪发送实体,从IQ节 语义来讲,就是通过发送和接收这些节来跟踪“请求-应答”型的交互行为。这个可选的(OPTIONAL)'id'属性值在一个域或一个流中是全局唯一的。IQ节语义学中对此有附加限定;见IQ Semantics (第九章第二节第三小节)。<br />
<br />
====type====<br />
<br />
:'type' 属性指明消息、出席信息或IQ节的意图或上下文的详细信息。'type'属性所允许的值依据节的类型是消息、出席信息还是IQ而有很大不同; 用于消息和出席信息节的值定义在即时消息和出席信息应用中,所以在[XMPP-IM|XMPP文档列表/XMPP正式RFC标准/RFC3921]中定义,反之用于IQ节的值定义了在一个 请求-应答 的“会话”中IQ节的角色,所以定义在IQ语义学中(第九章第二节第三小节)。 所有三种节的通用'type'值是"error";见Stanza Errors (第九章第三节)。<br />
<br />
====xml:lang====<br />
<br />
:如果一个节包含用于显示给人human user看的XML字符数据(在RFC 2277中有所解释[CHARSET],"internationalization is for humans"),这个节应该(SHOULD)处理一个'xml:lang'属性(定义在第二章第十二节[XML])。 'xml:lang'属性的值指明任何一个人类可读的XML字符数据的缺省语言, 它可以(MAY)被特定的子元素的'xml:lang'值重载。 如果一个节不处理一个'xml:lang'属性,一个实现必须(MUST)认为缺省的语言就是流属性中定义的语言(第四章第四节). 'xml:lang'属性值必须(MUST)是一个 NMTOKEN 并且必须(MUST)遵守 RFC 3066 [LANGTAGS]中定义的格式. <br />
<br />
===基本语义学===<br />
<br />
====消息语义学====<br />
<br />
:<message/>节类型可以被看作是一个"push"机制用于一个实体推送信息给另一个实体,类似发生在email系统中的通信. 所有消息节应该(SHOULD)处理一个表明预定的消息接收者的'to'属性;接收了这样一个节之后,一个服务器应该(SHOULD)路由或递送它给预定的接收者(见 Server Rules for Handling XML Stanzas (第十章)的XML节相关的通用路由和递送规则).<br />
<br />
====出席信息语义学====<br />
<br />
:<presence/> 元素可以被看作一个基本的广播或“出版-订阅”机制,用于多个实体接收某个已订阅的实体的信息(在这里,是网络可用性信息). 通常,一个发行实体应该(SHOULD)不带'to'属性发送一个出席信息,这时这个实体所连接的服务器应该(SHOULD)广播或多播(multiplex?)那个节给所有订阅的实体.无论如何,一个发行实体也可以(MAY)带'to'属性发送一个出席信息节,这时服务器应该(SHOULD)路由或递送这个节给预定的接收者.见 Server Rules for Handling XML Stanzas (第十章)的XML节相关的通用路由和递送规则,以及[XMPP-IM|XMPP文档列表/XMPP正式RFC标准/RFC3921]中即时消息和出席信息应用中出席信息的特定规则.<br />
<br />
====IQ语义学====<br />
<br />
:信息/查询(Info/Query),或曰IQ,是一个 请求-回应 机制,某些情况下类似[HTTP].IQ语义学使一个实体能够向另一个实体做出请求并做出应答. 请求和应答所包含的数据定义在IQ元素的一个直接的子元素的名字空间声明中, 并且由请求实体用'id'属性来跟踪这一交互行为. 因而,IQ交互伴随着一个结构化的数据交换的通用模式例如 get/result 或 set/result (尽管有时候会以一个错误信息应答某个请求):<br />
<br />
:以下是IQ的流程图,参见附件iq.png<br />
<br />
{image:img=iq}<br />
<br />
:为了强制执行这些语义学,要应用以下规则:<br />
<br />
:1. 对于IQ节来说'id'属性是必需的(REQUIRED).<br />
:2. 对于IQ节来说'type'属性是必需的(REQUIRED). 它的值必须(MUST)是以下之一:<br />
::* get -- 这个节是一个对信息或需求的请求.<br />
::* set -- 这个节提供需要的数据, 设置新的值, 或取代现有的值.<br />
::* result -- 这个节是一个对一个成功的 get 或 set 请求的应答.<br />
::* error -- 发生了一个错误,关于处理或递送上次发送的 get 或 set的(参见 节错误 Stanza Errors(第九章第三节)).<br />
:3. 一个接收到"get" 或 "set" 类型的IQ请求的实体必须(MUST)回复一个"result"或"error"类型的IQ应答(这个应答必须(MUST)保留相关请求的'id'属性).<br />
:4. 一个接收到"result"或"error"类型的IQ节的实体不能(MUST NOT)再发送更多的"result"或"error"类型的IQ应答; 无论如何, 如上所述, 请求实体可以(MAY)发送另一个请求(如, 一个"set"类型的IQ,通过get/result对提供查询(discovery)所需的信息).<br />
:5. 一个"get" 或 "set" 类型的IQ节必须(MUST)包含并只包含一个子元素指明特定请求或应答的语义.<br />
:6. 一个"result"类型的IQ节必须(MUST)包含零或一个子元素.<br />
:7. 一个"error"类型的IQ节应该(SHOULD)包含和"get"或"set"相关联的那个子元素并且必须(MUST)包含一个<error/>子元素;详细信息,见Stanza Errors (第九章第三节).<br />
<br />
===节错误===<br />
<br />
:节相关的错误的处理方式类似流错误(第四章第七节). 无论如何, 不像流错误, 节错误是可恢复的;所以错误节包含了暗示原来的发送者可以采取什么行动来补救这个错误.<br />
<br />
====规则====<br />
<br />
:以下规则适用于节相关的错误:<br />
<br />
:* 接收或处理实体察觉到一个节相关的错误条件时应该(MUST)返回给发送实体一个同类型的节(消息,出席信息,或IQ),这个节的'type'属性值则设置为"error"(这里这样的节称之为"error stanza").<br />
<br />
:* 生成一个错误节的实体应该(SHOULD)包含原来发送的XML,这样发送者可以检查它,并且如果必要,在尝试重新发送之前纠正它.<br />
<br />
:* 一个错误节必须(MUST)包含一个<error/>子元素.<br />
<br />
:* 如果'type'属性值不是"error"(或没有"type"属性),节不能(MUST NOT)包含一个<error/>子元素.<br />
<br />
:* 接收到一个错误节的实体不能(MUST NOT)应答这个节更多的错误节; 这有助于防止死循环.<br />
<br />
====语法====<br />
<br />
:节相关错误的语法如下:<br />
<br />
<source lang="xml"><br />
<stanza-kind to='sender' type='error'><br />
[RECOMMENDED to include sender XML here]<br />
<error type='error-type'><br />
<defined-condition xmlns='urn:ietf:params:xml:ns:xmpp-stanzas'/><br />
<text xmlns='urn:ietf:params:xml:ns:xmpp-stanzas' xml:lang='langcode'><br />
OPTIONAL descriptive text<br />
</text><br />
[OPTIONAL application-specific condition element]<br />
</error><br />
</stanza-kind><br />
</source><br />
<br />
:stanza-kind 是 message, presence, 或 iq 中的一个.<br />
<br />
:<error/> 元素的'type'属性值必须(MUST)是以下之一:<br />
<br />
:* cancel -- 不重试(这个错误是不可恢复的)<br />
<br />
:* continue -- 继续进行(这个条件只是一个警告)<br />
<br />
:* modify -- 改变数据之后重试<br />
<br />
:* auth -- 提供证书之后重试<br />
<br />
:* wait -- 等待之后重试(错误是暂时的)<br />
<br />
:<error/>元素:<br />
<br />
:* 必须(MUST)包含一个子元素,符合以下定义的节错误条件之一;这个元素(MUST)符合'urn:ietf:params:xml:ns:xmpp-stanzas'名字空间.<br />
<br />
:* 可以(MAY)包含一个<text/>子元素容纳XML字符数据用来描述错误的更多细节;这个元素必须(MUST)符合'urn:ietf:params:xml:ns:xmpp-stanzas'名字空间并且应该(SHOULD)处理'xml:lang'属性.<br />
<br />
:* 可以(MAY)包含一个应用程序定义的错误条件子元素;这个元素必须(MUST)符合一个应用程序定义的名字空间,并且它的结构由这个名字空间定义.<br />
<br />
:<text/>元素是可选的(OPTIONAL).如果包含它,它应该(SHOULD)仅用于提供描述或诊断信息以补充一个已定义的条件或应用程序定义的条件. 它不应(SHOULD NOT)被应用程序认为是一个程序性的. 它不应(SHOULD NOT)被用作向一个使用者展示的错误信息,但是可以(MAY)展示除条件元素(或元素们)相关的错误信息之外的信息.<br />
<br />
:最后,为了维护向后兼容性, 这个schema (定义在[XMPP-IM|XMPP文档列表/XMPP正式RFC标准/RFC3921])允许可选的在<error/>元素中包含一个("code")属性.<br />
<br />
====已定义的条件====<br />
<br />
:以下条件定义用于节错误.<br />
<br />
:* <bad-request/> -- 发送者发送的XML是不规范的或不能被处理(例如 一个IQ节包含了一个未被承认的'type'属性值); 相关的错误类型应该(SHOULD)是"modify".<br />
<br />
:* <conflict/> -- 不同意访问,因为相同的名字或地址已存在一个资源或会话;相关的错误类型应该( SHOULD)是"cancel".<br />
<br />
:* <feature-not-implemented/> -- 请求的特性未被接收者或服务器实现所以不能处理;相关的错误类型应该(SHOULD)是"cancel".<br />
<br />
:* <forbidden/> -- 请求实体没有必需的许可来执行这一动作;相关的错误类型应该(SHOULD)是"auth".<br />
<br />
:* <gone/> -- 接收者或服务器无法再以这个地址进行联系(错误节可以(MAY)在<gone/>元素的XML字符数据中包含一个新的地址);相关的错误类型应该(SHOULD)是"modify".<br />
<br />
:* <internal-server-error/> -- 服务器不能处理节,因为错误的配置或其他未定义的内部服务器错误;相关的错误类型应该(SHOULD)是"wait".<br />
<br />
:* <item-not-found/> -- JID地址或申请的条目无法找到;相关的错误类型应该(SHOULD)是"cancel".<br />
<br />
:* <jid-malformed/> -- 发送的实体提供的XMPP地址或与之通信的某个XMPP地址(如一个'to'属性值)或这个XMPP地址中的一部分(如一个资源ID)不符合寻址方案的语法(第三章);相关的错误类型应该(SHOULD)是"modify".<br />
<br />
:* <not-acceptable/> -- 接收者或服务器理解这个请求但是拒绝处理,因为它不符合某些接收者或服务器定义的标准(例如,一个关于消息中可接收的单词的本地策略);相关错误类型应该(SHOULD)是"modify".<br />
<br />
:* <not-allowed/> -- 接收者或服务器不允许任何实体执行这个动作;相关错误类型应该(SHOULD)是"cancel".<br />
<br />
:* <not-authorized/> -- 在被允许执行某个动作之前发送者必须提供适当的证书,或已提供了不正确的证书;相关错误类型应该(SHOULD)是"auth".<br />
<br />
:* <payment-required/> -- 请求实体未被授权访问请求的服务,因为需要付费;相关错误类型应该(SHOULD)是"auth".<br />
<br />
:* <recipient-unavailable/> -- 预定的接收者暂时不可用;相关错误类型应该(SHOULD)是"wait"(注意: 如果这样做会导致泄露预定接收者的网络可用性给一个未被授权了解此信息的实体,应用程序不应该(MUST NOT)返回这个错误).<br />
<br />
:* <redirect/> -- 接收者或服务器重定向这个请求信息到另一个实体,通常是暂时的(这个错误节应该 (SHOULD)在<redirect/>元素的XML字符数据中包含一个预备的地址,它必须(MUST)是一个合法的JID); 相关的错误类型应该(SHOULD)是"modify".<br />
<br />
:* <registration-required/> -- 请求实体未被授权访问请求的服务,因为需要注册;相关错误类型应该(SHOULD)是"auth".<br />
<br />
:* <remote-server-not-found/> -- 在预定的接收者的全部或部分JID中的一个远程服务器或服务不存在;相关错误类型应该(SHOULD)是"cancel".<br />
<br />
:* <remote-server-timeout/> -- 在预定的接收者(或需要完成的一个申请)的全部或部分JID中的一个远程服务器或服务无法在合理的时间内联系到;相关错误类型应该(SHOULD)是"wait".<br />
<br />
:* <resource-constraint/> -- 服务器或接收者缺乏足够的系统资源来服务请求;相关错误类型应该(SHOULD)是"wait".<br />
<br />
:* <service-unavailable/> -- 服务器或接收者目前无法提供被请求的服务;相关错误类型应该(SHOULD)是"cancel".<br />
<br />
:* <subscription-required/> -- 请求实体未被授权访问能请求的服务,因为需要订阅;相关错误类型应该(SHOULD)是"auth".<br />
<br />
:* <undefined-condition/> -- 错误条件不是本列表中定于的其他条件之一;任何错误类型可能和这个条件有关,并且它应该(SHOULD)仅用于关联一个应用程序定义的条件.<br />
<br />
:* <unexpected-request/> -- 接收者或服务器理解这个请求但是不希望是在这个时间(比如,请求的顺序颠倒);相关错误类型应该(SHOULD)是"wait".<br />
<br />
====应用程序定义条件====<br />
<br />
:大家知道,一个应用程序可以(MAY)通过在错误元素里包含一个适当名字空间的字元素来提供应用程序定义的节错误信息. 应用程序定义的元素应该(SHOULD)补充或进一步限定一个已定义的元素. 因而,<error/>元素将包含两个或三个子元素:<br />
<br />
<source lang="xml"><br />
<iq type='error' id='some-id'><br />
<error type='modify'><br />
<bad-request xmlns='urn:ietf:params:xml:ns:xmpp-stanzas'/><br />
<too-many-parameters xmlns='application-ns'/><br />
</error><br />
</iq><br />
<message type='error' id='another-id'><br />
<error type='modify'><br />
<undefined-condition xmlns='urn:ietf:params:xml:ns:xmpp-stanzas'/><br />
<text xml:lang='en' xmlns='urn:ietf:params:xml:ns:xmpp-stanzas'><br />
Some special application diagnostic information...<br />
</text><br />
<special-application-condition xmlns='application-ns'/><br />
</error><br />
</message><br />
</source><br />
<br />
==服务器处理XML节的规则==<br />
<br />
:兼容的服务器实现必须(MUST)确保两个实体之间的XML节按次序处理.<br />
<br />
:在按次序处理的需求之外, 每个服务器实现将包含它自己的递送树"delivery tree"以处理它接收到的节.这个树决定一个节是否需要路由到其他域, 在内部处理, 还是递送到和一个已连接的节点相关的资源. 以下规则适用:<br />
<br />
===没有'to'地址===<br />
<br />
:如果这个节没有'to'属性, 服务器应该(SHOULD)为发送它的实体处理这个节. 因为所有从其他服务器收到的节必须(MUST)拥有'to'属性, 这个规则仅适用于从一个连接到这台服务器的已注册实体(如一个客户端)收到的节.如果这个服务器收到一个没有'to'属性的出席信息节, 服务器应该(SHOULD)向那些订阅了这个发送实体的出席信息的所有实体广播它, 如果可能的话(即时消息和出席信息应用程序中出席信息广播的语义定义在[XMPP-IM|XMPP文档列表/XMPP正式RFC标准/RFC3921]). 如果服务器接收到一个类型为"get" 或 "set" 的没有'to'属性的节并且它理解这个节的名字空间下的内容, 它必须(MUST)为这个发送实体处理节(在这里"process"的含义是由相关的名字空间的语义所决定的)或返回一个错误给发送实体.<br />
<br />
===外部域===<br />
<br />
:如果'to'属性中的JID的域ID部分的主机名和服务器自身或其子域配置的主机名不匹配, 服务器应该(SHOULD)路由这个节到外部域(取决于本地服务规定或安全策略关于域间通信的规定).有两种可能的情况:<br />
<br />
::- 一个服务器之间的流已经存在于两个域之间: 发送者的服务器通过这个已存在的流为这个外部域路由这个节到授权服务器<br />
<br />
::- 两个域之间不存在服务器间的流: 发送者服务器 (1) 解析这个外部域的主机名(定义在服务器间的通信Server-to-Server Communications (第十四章第四节)), (2) 在两个域之间进行服务器到服务器的流协商(定义在 Use of TLS (第五章) 和 Use of SASL (第六章)), 然后 (3) 通过这个新建的流为外部域路由这个节到授权服务器<br />
<br />
:如果路由到接收者的服务器不成功, 发送者的服务器必须(MUST)返回一个错误给发送者; 如果接收者的服务器联系上了但是从接收者的服务器递送到接收者不成功, 接收者服务器必须(MUST)通过发送者的服务器返回一个错误给发送者.<br />
<br />
===子域===<br />
<br />
:如果'to'属性中的JID的域ID部分的主机名和服务器自身配置的主机名的一个子域名匹配,服务器必须(MUST)自己处理这个节或路由这个节到专门负责这个子域的特定服务(如果子域被配置了),或者返回一个错误给发送者(如果子域没有配置).<br />
<br />
===纯粹的域或特定的资源===<br />
<br />
:如果'to'属性中的JID的域ID部分的主机名和服务器自身配置的主机名本身匹配,并且'to'属性中的JID类型是<domain> 或 <domain/resource>, 服务器(或其中定于的资源)必须(MUST)根据节的类型适当的处理这个节或返回一个错误节给发送者.<br />
<br />
===同一域中的节点===<br />
<br />
:如果'to'属性中的JID的域ID部分的主机名和服务器自身配置的主机名本身匹配,并且'to'属性中的JID类型是<node@domain> 或 <node@domain/resource>, 服务器应该(SHOULD)递送这个节到节的'to'属性中的JID所指明的预定的接收者. 以下规则适用:<br />
<br />
:# 如果这个JID包含一个资源ID(例如, 格式是<node@domain/resource>)并且存在一个连接的资源符合这个全JID, 接收者服务器应该(SHOULD)递送这个节给正确符合这个资源ID的流或会话.<br />
:# 如果这个JID包含一个资源ID(例如, 格式是<node@domain/resource>)并且不存在一个连接的资源符合这个全JID, 接收者服务器应该(SHOULD)返回一个<service-unavailable/> 节错误给发送者.<br />
:# 如果这个JID的格式是<node@domain>并且存在至少一个此节点的连接资源, 接收服务器应该( SHOULD)递送这个节给至少其中一个已连接的资源, 依据应用程序定义的规则(一系列即时消息和出席信息应用程序的递送规则定义在[XMPP-IM|XMPP文档列表/XMPP正式RFC标准/RFC3921]).<br />
<br />
==XMPP中的XML用法==<br />
<br />
===限制===<br />
<br />
:XMPP是一个简单的流式XML元素的专用协议用于接近实时地交换结构化信息. 因为XMPP不需要任意的解析和所有的XML文档, 所以XMPP不需要支持[XML]的所有功能. 特殊的, 适用以下限制.<br />
<br />
:关于XML生成, 一个XMPP实现不能(MUST NOT)在XML流中注入以下任何东西:<br />
<br />
:* 注释 (第二章第五节[XML])<br />
<br />
:* 处理指示(第二章第六节 同上)<br />
<br />
:* 内部或外部的 DTD 子集 (第二章第八节 同上)<br />
<br />
:* 内部或外部的实体参考 (第四章第二节 同上) 除了预定实体以外(第四章第六节 同上)<br />
<br />
:* 字符数据或属性值包含和预定实体列表中吻合的未逃逸的unescaped字符(第四章第六节 同上); 这些字符必须(MUST)逃逸<br />
<br />
:关于XML处理, 如果一个XMPP实现接收到这些受限的XML数据,它必须(MUST)忽略这些数据.<br />
<br />
===XML 名字空间的名字和前缀===<br />
<br />
:XML名字空间[XML-NAMES]为所有XMPP兼容的XML建立数据所有权的严格界限. 这个名字空间的基本功能是把结构上混合在一起的XML元素区分出不同的词汇. 确保XMPP兼容的XML有名字空间的感知能力使得任何允许的XML可以被结构化的混合到任何XMPP数据元素中. XML名字空间的名字和前缀的规则在下一小节中.<br />
<br />
====流名字空间====<br />
<br />
:在所有的XML流头中必须声明一个流名字空间. 流名字空间必须(MUST)是 'http://etherx.jabber.org/streams'. 元素名<stream/>和它的<features/>和<error/>子元素必须(MUST)在所有实例中符合这个流名字空间前缀. 一个实现应该(SHOULD)只为这些元素生成'stream:'前缀, 并且由于历史原因可以(MAY)只接受'stream:'前缀.<br />
<br />
====缺省名字空间====<br />
<br />
:在所有的XML流中必须声明一个缺省的流名字空间用于定义允许的流根元素的一级子元素. 这个名字空间声明对于初始化流和应答流必须(MUST)是相同的使得双方的流都是合格一致的. 缺省的名字空间声明适用于流和所有在流中发送的节(除非由流名字空间或回拨名字空间的前缀显式的符合另一个名字空间).<br />
<br />
:一个服务器实现必须(MUST)支持以下两个缺省名字空间(由于历史原因, 一些实现可能(MAY)只支持这两个缺省名字空间):<br />
<br />
:* jabber:client -- 当流用于客户端和服务器的通信时声明这个缺省名字空间<br />
<br />
:* jabber:server -- 当流用于两个服务器间的通信时声明这个缺省名字空间<br />
<br />
:一个客户端实现必须(MUST)支持'jabber:client'缺省名字空间,并且由于历史原因可以(MAY)只支持这个缺省名字空间.<br />
<br />
:如果缺省名字空间是'jabber:client'或'jabber:server',一个实施不能(MUST NOT)在这个名字空间下为元素生成名字空间前缀. 一个实现不应该(SHOULD NOT)按照元素的内容(可能和流相反)生成不同于'jabber:client'和'jabber:server'名字空间前缀.<br />
<br />
:注意: 'jabber:client' 和 'jabber:server' 名字空间接近于相同但是用于不同的上下文(客户端服务器通信用'jabber:client' 而服务器间通信用'jabber:server'). 这两者之间仅有的不同在于在'jabber:client'中被发送的节中'to'和'from'属性是可选的(OPTIONAL),而在'jabber:server'中被发送的节中它们是必需的(REQUIRED). 如果兼容的实施接受一个符合'jabber:client'或'jabber:server'名字空间的流, 它必须(MUST)支持通用属性(第九章第一节)和三个核心节类型(message, presence, 和IQ)的基本语义(第九章第二节).<br />
<br />
====回拨名字空间====<br />
<br />
:所有用于服务器回拨的(第八章)元素都必须声明一个回拨名字空间. 回拨名字空间的名字必须(MUST)是'jabber:server:dialback'. 所有符合此名字空间的元素必须(MUST)有前缀. 一个实现应该(SHOULD)只为这些元素生成'db:'前缀并且只可以(MAY)接受'db:'前缀.<br />
<br />
===确认===<br />
<br />
:除了注意'jabber:server'名字空间中关于节中'to'和'from'地址的规定,一个服务器不需要为转发到客户端或其他服务器负责检查XML元素;一个实现可以(MAY)选择仅提供有效数据元素但这是可选的(OPTIONAL)(尽管一个实现不能(MUST NOT)接受不规范的XML). 客户端不应该(SHOULD NOT)滥用发送不符合schema的数据的能力, 并且应该(SHOULD)忽略接收到的XML流中任何和schema不一致的元素或属性值. XML流和节的有效性确认是可选的(OPTIONAL),并且在这里提到的schemas仅用于描述的用途.<br />
<br />
===文本声明的包含===<br />
<br />
:实现应该(SHOULD)在发送一个流头信息之前发送一个文本声明. 应用程序必须(MUST)遵守[XML]中关于环境(那里对文本声明做了规定)的规则.<br />
<br />
===字符编码===<br />
<br />
:实现必须(MUST)支持通用字符集Universal Character Set (ISO/IEC 10646-1 [UCS2])字符到UTF-8(RFC 3629 [UTF-8])的转换, 必须符合 RFC 2277 [CHARSET]. 实现不能(MUST NOT)试图使用任何其他的编码.<br />
<br />
==核心的兼容性要求==<br />
<br />
:本章总结了可扩展的消息和出席信息协议中的某些方面,为了实施的兼容性,它们必须(MUST)被服务器和客户端支持,当然协议的其他方面也应该(SHOULD)被支持. 为了兼容的目的, 我们在核心协议(它必须(MUST)被任何服务器或客户端支持, 无论是什么特定的应用)和即时消息协议(仅仅是在核心协议之上的即时消息和出席信息应用必须(MUST)支持它)之间划了一个级别. 在本章中定义了所有服务器和客户端的兼容性要求; 即时消息服务器和客户端的兼容性要求在[XMPP-IM|XMPP文档列表/XMPP正式RFC标准/RFC3921]的相关章节中定义.<br />
<br />
===服务器===<br />
<br />
:除了所有已定义的关于安全, XML使用, 和国际化的要求之外, 一个服务器还必须(MUST)支持以下核心协议以保证兼容性:<br />
<br />
:* 在地址中应用[STRINGPREP] 的 [NAMEPREP], Nodeprep (附录 A),和 Resourceprep (附录 B) profiles (包括确保域ID是[IDNA]中定义的国际化域名)<br />
<br />
:* XML流(第四章), 包括Use of TLS(第五章), Use of SASL(第六章), 和Resource Binding (第七章)<br />
<br />
:* 三个在stanza semantics(第九章第二节)中已定义的节类型(即,<message/>, <presence/>, 和<iq/>)的基本语义<br />
<br />
:* 生成错误的语法及相关的流, TLS, SASL, 和 XML节的语义<br />
<br />
:另外, 一个服务器可以(MAY)支持以下核心协议:<br />
<br />
:* 服务器回拨 (第八章)<br />
<br />
===客户端===<br />
<br />
:一个客户端必须(MUST)支持以下核心协议以满足兼容性:<br />
<br />
:* XML流(第四章), 包括Use of TLS(第五章), Use of SASL(第六章), 和Resource Binding (第七章)<br />
<br />
:* 三个在stanza semantics(第九章第二节)中已定义的节类型(即,<message/>, <presence/>, 和<iq/>)的基本语义<br />
<br />
:* 处理(并且, 如果可能, 生成) 错误的语法及相关的流, TLS, SASL, 和 XML节的语义<br />
<br />
:另外, 一个客户端应该(SHOULD)支持以下核心协议:<br />
<br />
:* 地址的生成应用[STRINGPREP] 的 [NAMEPREP], Nodeprep (附录 A),和 Resourceprep (附录 B) profiles <br />
<br />
==国际化事项==<br />
<br />
:XML流在Character Encoding(第十一章第五节)中定义为必须(MUST)被编码成UTF-8. 在Stream Attributes(第四章第四节)中特别定义了, 一个XML流应该(SHOULD)包含一个'xml:lang'属性,它被认为是通过这个用于人类用户解读的流发送的任何XML字符数据的缺省语言. 在 xml:lang (第九章第一节第五小节)特别定义了, 如果一个XML节是用来给人类用户解读,这个节应该(SHOULD)包含一个'xml:lang'属性. 服务器在为连接的实体路由或递送节的时候应该(SHOULD)应用缺省的'xml:lang'属性, 并且不能(MUST NOT)修改或删除它从其他实体收到的节的'xml:lang'属性.<br />
<br />
==安全性事项==<br />
<br />
===高安全性===<br />
<br />
:为了XMPP通信的目的(客户端-服务器 和 服务器-服务器), "高安全性"条款谈的是相互验证和完整性检查安全性技术的使用; 特别是, 当使用基于证书的验证来提供高安全性, 应该( SHOULD)建立一个带外的信任链,尽管一个共享签名证书可能允许以前不知道的证书在带内建立信任关系. 参见以下第十四章第二节关于证书确认程序.<br />
<br />
:实施必须(MUST)支持高安全性. 服务提供者应该(SHOULD)基于本地安全策略使用高安全性.<br />
<br />
===证书确认===<br />
<br />
:当一个XMPP点和另一个XMPP点安全的地通信, 它必须(MUST)确认对方终端的证书.有三种可能的情况:<br />
<br />
:情形 #1: 点包含一个终端实体证书,以根证书的证书链中一环出现(见[X509]中的第六章第一节).<br />
<br />
:情形 #2: 点的证书由一个对方不知道的证书授权.<br />
<br />
:情形 #3: 点的证书由自己签名.<br />
<br />
:在情形#1, 确认方必须(MUST)做以下两条之一:<br />
<br />
:# 根据[X509]的规则确认对方证书.然后证书应该(SHOULD)被对方接下来在[HTTP-TLS]中描述的规则反向确认预期的身份。但如果"xmpp"是subjectAltName扩展类型,则必须(MUST)使用证书中的显示的身份。如果这两项检查之一失败,用户导向的客户端必须(MUST)通知用户(客户端可以(MAY)给用户机会继续连接)或以一个坏证书的错误终止连接。自动客户端应该(SHOULD)终止连接(以一个坏证书错误)并在适当的日志中记录这个错误。自动客户端可以(MAY)提供一个配置设置成禁止检查,但同时必须(MUST)提供一个激活检查的配置。<br />
:# 点应该(SHOULD)出示证书给一个用户用于批准,包括完整的证书链.点必须(MUST)缓存这个证书(或一些其他不会忘记的表达方式比如一个哈希值).在将来的连接中,点必须(MUST)展示相同的证书并且如果改变了证书必须(MUST)通知用户.<br />
<br />
:在情形#2 和情形#3, 实现应该(SHOULD)执行上述第二条.<br />
<br />
===客户端-服务器通信===<br />
<br />
:一个兼容的客户端实现必须(MUST)支持TLS和SASL用于连接到服务器.<br />
<br />
:用于加密XML流的TLS协议(在 Use of TLS(第五章)定义)提供可信的机制帮助确保机密性和实体之间数据交换的完整性.<br />
<br />
:用于验证XML流的SASL协议(在 Use of SASL(第六章)定义)提供可靠的机制用于确认一个连接到服务器的客户端确实是它自己所声明的那个客户端.<br />
<br />
:服务器宣称的DNS主机名被解析之前,客户端-服务器通信不能(MUST NOT)继续进行。应该首先尝试解析[SRV]记录,其服务名为"xmpp-client",协议名为"tcp",整个资源记录类似"_xmpp-client._tcp.example.com."(使用字符"xmpp-client"表示服务ID是经过IANA注册).如果SRV查找失败,退而求其次,将查找一个正规的IPv4/IPv6地址记录来决定IP地址,使用"xmpp-client"端口5222,这个端口是在IANA注册了的。<br />
<br />
:客户端的IP地址和访问方法不能(MUST NOT)被服务器公开, 也不能被被任何原始服务器之外的服务器索取。这帮助保护客户端的服务器避免受到直接攻击(译者注:似乎应该是客户避免受到直接攻击,但原文如此)或被第三方知道它的身份。<br />
<br />
===服务器-服务器通信===<br />
<br />
:一个兼容的服务器实现必须(MUST)支持TLS和SASL,用于域间的通信.因为历史原因,一个兼容的实施也应该(SHOULD)支持服务器回拨(第八章).<br />
<br />
:因为服务提供者是一个策略问题,对于任何给定域和其他域的通信中,它是可选的(OPTIONAL),服务器之间的通信可以(MAY)被任何特定部署的管理员禁止。如果一个特殊的域允许域间的通信,它应该(SHOULD)允许高安全性。<br />
<br />
:管理员可能想在服务器间使用SASL来通信,以确保双方的验证和保密性(比如在机构的私有网络).兼容实施应该(SHOULD)为这个目的支持SASL.<br />
<br />
:服务器宣称的DNS主机名被解析之前,服务器-服务器通信不能(MUST NOT)继续进行。应该首先尝试解析[SRV]记录,其服务名为"xmpp-server",协议名为"tcp",整个资源记录类似"_xmpp-server._tcp.example.com."(使用字符"xmpp-server"表示服务ID是经过IANA注册的,注意要用"xmpp-server"取代以前用的"jabber",因为以前的用法不符合[SRV]标准;希望保持向后兼容的实现可以继续查找或应答"jabber"服务ID).如果SRV查找失败,退而求其次,将查找一个正规的IPv4/IPv6地址记录来决定IP地址,使用"xmpp-server"端口5269,这个端口是在IANA注册了的。<br />
<br />
:服务器回拨防止域欺骗,从而使得伪造XML节更为困难.它和SASL和TLS不一样,它不是一个用于验证、安全或加密服务器之间的流的机制, 所以只是服务器身份的微弱确认而已。而且除非它使用了DNSSec [DNSSEC]否则它 容易受到DNS中毒攻击,即使DNS信息是正确的,如果攻击者劫持了远程域,回拨也不能防止它的攻击.需要健壮的安全性的域应该(SHOULD)使用TLS和SASL.如果服务器间的验证使用了SASL,回拨就不应该(SHOULD NOT)使用了,因为它是多余的.<br />
<br />
===层的次序===<br />
<br />
:协议中的层的次序必须(MUST)如下堆积:<br />
<br />
:# TCP<br />
:# TLS<br />
:# SASL<br />
:# XMPP<br />
<br />
:这个次序的原理是,[TCP]是基于连接的层,被所有使用,所以处于最上层, [TLS]经常是由操作系统层提供,[SASL]经常由应用程序层提供, XMPP则是应用程序本身.<br />
<br />
===缺乏绑定到TLS的SASL通道===<br />
<br />
:SASL构架不提供一个机制来绑定SASL验证到一个提供机密性和完整性保护的安全层。这一通道绑定"channel binding"的缺乏阻碍了SASL确认低层安全性所绑定的源和目标终端和SASL所验证的结果是否一致。如果终端不一致, 低层安全性不能被信任用来保护SASL验证的实体之间的数据传输。在这种情况下,一个SASL安全层进行握手的时候应该有效的忽略低层安全性的存在。<br />
<br />
===强制实现的技术===<br />
<br />
:最低要求, 所有实现必须(MUST)支持以下机制:<br />
<br />
::对于验证: SASL [DIGEST-MD5] 机制<br />
<br />
::对于机密性: TLS (使用 TLS_RSA_WITH_3DES_EDE_CBC_SHA 密码)<br />
<br />
::对于两者: TLS 加 SASL EXTERNAL(使用 TLS_RSA_WITH_3DES_EDE_CBC_SHA 密码支持客户端证书)<br />
<br />
===防火墙===<br />
<br />
:使用XMPP通信通常是通过[TCP]连接到5222端口(客户端-服务器)或5269端口(服务器-服务器), 正如在IANA注册的那样(见 IANA Considerations (第十五章)). 使用这些广为人知的端口允许管理员很容易的通过一般的防火墙来激活或禁止XMPP活动.<br />
<br />
===在SASL中使用base64===<br />
<br />
:客户端和服务器都必须(MUST)确认在SASL协商中收到的任何[BASE64]数据. 一个实现必须(MUST)拒绝(不是忽略)任何非显式允许base64字母的字符串; 这有助于预防建立隐蔽通道泄漏信息的行为。一个实现不能(MUST NOT)在非法输入处中断,如果那个('=')被包含在一些和最后的数据字符(如, "=AAA" or "BBBB=CCC")不同的东西里面,必须(MUST)拒绝接下来的任何包含('=')的base64字符;这有助于防止对这个实现的缓存溢出攻击和其他攻击。Base 64编码从外表看隐藏了容易辨认的信息,例如密码,但是不提供任何算法机密性。Base 64编码必须(MUST)按照RFC 3548[BASE64]第三章的定义执行。<br />
<br />
===Stringprep Profiles===<br />
<br />
:为了处理域ID,XMPP使用了[STRINGPREP]中的[NAMEPREP] profile; 和Nameprep有关的安全性考虑, 参考[NAMEPREP]中的相关章节.<br />
<br />
:另外, XMPP 定义了两个[STRINGPREP]的 profiles: 用于node identifiers的Nodeprep(附录 A)和用于resource identifiers的Resourceprep(附录 B).<br />
<br />
:Unicode 和 ISO/IEC 10646 集有许多字符看起来相似. 在许多时候, 安全协议的使用者可能看起来吻合,比如当比较信任的第三方的名字的时候. 因为没有很多上下文的时候不可能映射看起来相似的字符,比如知道所用的字符集, stringprep不匹配相似字符串,也不因为一些字符串象看起来象别的字符串而禁止它们.<br />
<br />
:一个节点ID可能被作为一个实体的XMPP地址的一部分. 一个通常的用途是作为一个即时消息用户的用户名;另一个用途是作为一个多用途聊天室的名字; 很多其他种类的实体可能使用节点ID作为他们的地址的一部分。 这些服务的安全性可能会受到国际化节点ID的不同表达的威胁;例如, 一个用户键入一个单独的国际化的节点ID可能访问了另一个用户的帐号信息, 或一个用户可能获得访问一个受限的聊天室或服务的访问权限.<br />
<br />
:一个资源ID可能被作为一个实体的XMPP地址的一部分。一个通常的用户是即时消息用户所连接的资源(激活的会话)的名字; 另一个是作为多用户聊天室的某用户的昵称; 许多其他种类的实体可能使用资源ID作为他们地址的一部分.这些服务的安全性可能会受到国际化资源ID的不同表达的威胁;例如, 一个用户可能尝试以同一个名字初始化多个会话,或一个用户可能发送一个消息给多用户聊天室的一个人但实际上发给了另外一个人.<br />
<br />
==IANA 事项==<br />
<br />
===用于TLS数据的XML名字空间名===<br />
<br />
:XMPP中用于TLS相关数据的 URN 子名字空间定义如下. (这个名字空间的名字遵守The IETF XML Registry [XML-REG]定义的格式.)<br />
<br />
::URI: urn:ietf:params:xml:ns:xmpp-tls<br />
<br />
::Specification: RFC 3920<br />
<br />
::Description: This is the XML namespace name for TLS-related data in the Extensible Messaging and Presence Protocol (XMPP) as defined by RFC 3920.<br />
<br />
::Registrant Contact: IETF, XMPP Working Group, <xmppwg@jabber.org><br />
<br />
===用于SASL数据的XML名字空间名===<br />
<br />
:XMPP中用于SASL相关数据的 URN 子名字空间定义如下. (这个名字空间的名字遵守The IETF XML Registry [XML-REG]定义的格式.)<br />
<br />
::URI: urn:ietf:params:xml:ns:xmpp-sasl<br />
<br />
::Specification: RFC 3920<br />
<br />
::Description: This is the XML namespace name for SASL-related data in the Extensible Messaging and Presence Protocol (XMPP) as defined by RFC 3920.<br />
<br />
::Registrant Contact: IETF, XMPP Working Group, <xmppwg@jabber.org><br />
<br />
===用于流错误的XML名字空间名===<br />
<br />
:XMPP中用于流相关错误的 URN 子名字空间定义如下. (这个名字空间的名字遵守The IETF XML Registry [XML-REG]定义的格式.)<br />
<br />
::URI: urn:ietf:params:xml:ns:xmpp-streams<br />
<br />
::Specification: RFC 3920<br />
<br />
:Description: This is the XML namespace name for stream-related error data in the Extensible Messaging and Presence Protocol (XMPP) as defined by RFC 3920.<br />
<br />
::Registrant Contact: IETF, XMPP Working Group, <xmppwg@jabber.org><br />
<br />
===用于资源绑定的XML名字空间名===<br />
<br />
:XMPP中用于资源绑定的 URN 子名字空间定义如下. (这个名字空间的名字遵守The IETF XML Registry [XML-REG]定义的格式.)<br />
<br />
::URI: urn:ietf:params:xml:ns:xmpp-bind<br />
<br />
::Specification: RFC 3920<br />
<br />
::Description: This is the XML namespace name for resource binding in the Extensible Messaging and Presence Protocol (XMPP) as defined by RFC 3920.<br />
<br />
::Registrant Contact: IETF, XMPP Working Group, <xmppwg@jabber.org><br />
<br />
===用于节错误的XML名字空间名===<br />
<br />
:XMPP中用于节相关错误数据的 URN 子名字空间定义如下. (这个名字空间的名字遵守The IETF XML Registry [XML-REG]定义的格式.)<br />
<br />
::URI: urn:ietf:params:xml:ns:xmpp-stanzas<br />
<br />
::Specification: RFC 3920<br />
<br />
::Description: This is the XML namespace name for stanza-related error data in the Extensible Messaging and Presence Protocol (XMPP) as defined by RFC 3920.<br />
<br />
::Registrant Contact: IETF, XMPP Working Group, <xmppwg@jabber.org><br />
<br />
===Nodeprep Profile of Stringprep===<br />
<br />
:The Nodeprep profile of stringprep是在Nodeprep(附录 A)定义的. IANA已经在stringprep profile registry中注册了 Nodeprep.<br />
<br />
::Name of this profile:<br />
<br />
:::Nodeprep<br />
<br />
::RFC in which the profile is defined:<br />
<br />
:::RFC 3920<br />
<br />
::Indicator whether or not this is the newest version of the profile:<br />
<br />
:::This is the first version of Nodeprep<br />
<br />
===Resourceprep Profile of Stringprep===<br />
<br />
:The Resourceprep profile of stringprep是在Resourceprep(附录 B)定义的. IANA已经在stringprep profile registry中注册了Resourceprep.<br />
<br />
::Name of this profile:<br />
<br />
:::Resourceprep<br />
<br />
::RFC in which the profile is defined:<br />
<br />
:::RFC 3920<br />
<br />
::Indicator whether or not this is the newest version of the profile:<br />
<br />
:::This is the first version of Resourceprep<br />
<br />
===GSSAPI 服务名===<br />
<br />
:IANA已经注册了 "xmpp" 作为一个 GSSAPI [GSS-API] 服务名, 在SASL Definition (第六章第三节)定义了.<br />
<br />
===端口号===<br />
<br />
:IANA已经注册了"xmpp-client" 和 "xmpp-server" 作为[TCP]端口号5222和5269的关键字.<br />
<br />
:这些端口应该(SHOULD)用于客户端-服务器 和 服务器-服务器通信,但它们的使用是可选的(OPTIONAL).<br />
<br />
==参考==<br />
<br />
===标准化参考===<br />
<br />
:[ABNF] Crocker, D. and P. Overell, "Augmented BNF for Syntax Specifications: ABNF", RFC 2234, November 1997.<br />
<br />
:[BASE64] Josefsson, S., "The Base16, Base32, and Base64 Data Encodings", RFC 3548, July 2003.<br />
<br />
:[CHARSET] Alvestrand, H., "IETF Policy on Character Sets and Languages", BCP 18, RFC 2277, January 1998.<br />
<br />
:[DIGEST-MD5] Leach, P. and C. Newman, "Using Digest Authentication as a SASL Mechanism", RFC 2831, May 2000.<br />
<br />
:[DNS] Mockapetris, P., "Domain names - implementation and specification", STD 13, RFC 1035, November 1987.<br />
<br />
:[GSS-API] Linn, J., "Generic Security Service Application Program Interface Version 2, Update 1", RFC 2743, January 2000.<br />
<br />
:[HTTP-TLS] Rescorla, E., "HTTP Over TLS", RFC 2818, May 2000.<br />
<br />
:[IDNA] Faltstrom, P., Hoffman, P., and A. Costello, "Internationalizing Domain Names in Applications (IDNA)", RFC 3490, March 2003.<br />
<br />
:[IPv6] Hinden, R. and S. Deering, "Internet Protocol Version 6 (IPv6) Addressing Architecture", RFC 3513, April 2003.<br />
<br />
:[LANGTAGS] Alvestrand, H., "Tags for the Identification of Languages", BCP 47, RFC 3066, January 2001.<br />
<br />
:[NAMEPREP] Hoffman, P. and M. Blanchet, "Nameprep: A Stringprep Profile for Internationalized Domain Names (IDN)", RFC 3491, March 2003.<br />
<br />
:[RANDOM] Eastlake 3rd, D., Crocker, S., and J. Schiller, "Randomness Recommendations for Security", RFC 1750, December 1994.<br />
<br />
:[SASL] Myers, J., "Simple Authentication and Security Layer (SASL)", RFC 2222, October 1997.<br />
<br />
:[SRV] Gulbrandsen, A., Vixie, P., and L. Esibov, "A DNS RR for specifying the location of services (DNS SRV)", RFC 2782, February 2000.<br />
<br />
:[STRINGPREP] Hoffman, P. and M. Blanchet, "Preparation of Internationalized Strings ("stringprep")", RFC 3454, December 2002.<br />
<br />
:[TCP] Postel, J., "Transmission Control Protocol", STD 7, RFC 793, September 1981.<br />
<br />
:[TERMS] Bradner, S., "Key words for use in RFCs to Indicate Requirement Levels", BCP 14, RFC 2119, March 1997.<br />
<br />
:[TLS] Dierks, T. and C. Allen, "The TLS Protocol Version 1.0", RFC 2246, January 1999.<br />
<br />
:[UCS2] International Organization for Standardization, "Information Technology - Universal Multiple-octet coded Character Set (UCS) - Amendment 2: UCS Transformation Format 8 (UTF-8)", ISO Standard 10646-1 Addendum 2, October 1996.<br />
<br />
:[UTF-8] Yergeau, F., "UTF-8, a transformation format of ISO 10646", STD 63, RFC 3629, November 2003.<br />
<br />
:[X509] Housley, R., Polk, W., Ford, W., and D. Solo, "Internet X.509 Public Key Infrastructure Certificate and Certificate Revocation List (CRL) Profile", RFC 3280, April 2002.<br />
<br />
:[XML] Bray, T., Paoli, J., Sperberg-McQueen, C., and E. Maler, "Extensible Markup Language (XML) 1.0 (2nd ed)", W3C REC-xml, October 2000, <http://www.w3.org/TR/REC-xml>.<br />
<br />
:[XML-NAMES] Bray, T., Hollander, D., and A. Layman, "Namespaces in XML", W3C REC-xml-names, January 1999, <http://www.w3.org/TR/REC-xml-names>.<br />
<br />
===信息参考===<br />
<br />
:[ACAP] Newman, C. and J. Myers, "ACAP -- Application Configuration Access Protocol", RFC 2244, November 1997.<br />
<br />
:[ASN.1] CCITT, "Recommendation X.208: Specification of Abstract Syntax Notation One (ASN.1)", 1988.<br />
<br />
<br />
:[DNSSEC] Eastlake 3rd, D., "Domain Name System Security Extensions", RFC 2535, March 1999.<br />
<br />
:[HTTP] Fielding, R., Gettys, J., Mogul, J., Frystyk, H., Masinter, L., Leach, P., and T. Berners-Lee, "Hypertext Transfer Protocol -- HTTP/1.1", RFC 2616, June 1999.<br />
<br />
:[IMAP] Crispin, M., "INTERNET MESSAGE ACCESS PROTOCOL - VERSION 4rev1", RFC 3501, March 2003.<br />
<br />
:[IMP-REQS] Day, M., Aggarwal, S., Mohr, G., and J. Vincent, "Instant Messaging \/ Presence Protocol Requirements", RFC 2779, February 2000.<br />
<br />
:[IRC] Oikarinen, J. and D. Reed, "Internet Relay Chat Protocol", RFC 1459, May 1993.<br />
<br />
:[JEP-0029] Kaes, C., "Definition of Jabber Identifiers (JIDs)", JSF JEP 0029, October 2003.<br />
<br />
:[JEP-0078] Saint-Andre, P., "Non-SASL Authentication", JSF JEP 0078, July 2004.<br />
<br />
[JEP-0086] Norris, R. and P. Saint-Andre, "Error Condition Mappings", JSF JEP 0086, February 2004.<br />
<br />
:[JSF] Jabber Software Foundation, "Jabber Software Foundation", <http://www.jabber.org/>.<br />
<br />
:[POP3] Myers, J. and M. Rose, "Post Office Protocol - Version 3", STD 53, RFC 1939, May 1996.<br />
<br />
:[SIMPLE] SIMPLE Working Group, "SIMPLE WG", <http://www.ietf.org/html.charters/simple-charter.html>.<br />
<br />
:[SMTP] Klensin, J., "Simple Mail Transfer Protocol", RFC 2821, April 2001.<br />
<br />
:[URI] Berners-Lee, T., Fielding, R., and L. Masinter, "Uniform Resource Identifiers (URI): Generic Syntax", RFC 2396, August 1998.<br />
<br />
:[USINGTLS] Newman, C., "Using TLS with IMAP, POP3 and ACAP", RFC 2595, June 1999.<br />
<br />
:[XML-REG] Mealling, M., "The IETF XML Registry", BCP 81, RFC 3688, January 2004.<br />
<br />
:[[RFC3921]] Saint-Andre, P., Ed., "Extensible Messaging and Presence Protocol (XMPP): Instant Messaging and Presence", RFC 3921, October 2004.<br />
<br />
<br />
==附录 A. Nodeprep==<br />
<br />
===A.1. 介绍===<br />
<br />
:这个附录定义了 "Nodeprep" profile of [STRINGPREP]. 它定义了处理规则让用户能够在XMPP中输入国际化节点标识符并尽可能正确的获取正确的字符内容. (一个XMPP节点标识符是XMPP地址的可选部分,它在域名标识符和那个'@'分隔符之前;它经常但不是专门用来关联一个即时消息用户名)这些处理规则仅仅适用于XMPP节点标识符但不适用于任意文本或任何XMPP的其他方面.<br />
<br />
:这个脚本定义了以下这些, 正如 [STRINGPREP]要求的:<br />
<br />
:* 脚本预期的适用性: XMPP的国际化节点标识符<br />
<br />
:* 用于stringprep的输入输出字符集: Unicode 3.2, 定义在本附录的第二章<br />
<br />
:* 使用的映射: 定义在第三章<br />
<br />
:* Unicode正规化使用: 定义在第四章<br />
<br />
:* 禁止输出的字符串: 定义在第五章<br />
<br />
:* 双字节字符处理: 定义在第六章<br />
<br />
===A.2. 字符集===<br />
<br />
:本脚本使用Unicode 3.2的未分配编码列表,指向 Table A.1, 也定义在 [STRINGPREP]的附录 A 中.<br />
<br />
===A.3. 映射===<br />
<br />
:本脚本指定使用[STRINGPREP]的以下表:<br />
<br />
::Table B.1<br />
<br />
::Table B.2<br />
<br />
===A.4. 正规化===<br />
<br />
:本脚本指定 Unicode正规化使用 form KC, 定义在 [STRINGPREP]中.<br />
<br />
===A.5. 禁止输出===<br />
<br />
:本脚本指定使用以下的[STRINGPREP]表禁止输出.<br />
<br />
::Table C.1.1<br />
<br />
::Table C.1.2<br />
<br />
::Table C.2.1<br />
<br />
::Table C.2.2<br />
<br />
::Table C.3<br />
<br />
::Table C.4<br />
<br />
::Table C.5<br />
<br />
::Table C.6<br />
<br />
::Table C.7<br />
<br />
::Table C.8<br />
<br />
::Table C.9<br />
<br />
:另外, 以下Unicode字符也被禁止:<br />
<br />
: #x22 (")<br />
<br />
: #x26 (&)<br />
<br />
: #x27 (')<br />
<br />
: #x2F (/)<br />
<br />
: #x3A (:)<br />
<br />
: #x3C (<)<br />
<br />
: #x3E (>)<br />
<br />
: #x40 (@)<br />
<br />
===A.6. 双字节===<br />
<br />
:本脚本指定按照[STRINGPREP]第六章检查双字节.<br />
<br />
==附录 B. Resourceprep==<br />
<br />
===B.1. 介绍===<br />
<br />
:这个附录定义了 "Resourceprep" profile of [STRINGPREP]. 它定义了处理规则让用户能够在XMPP中输入国际化资源标识符并尽可能正确的获取正确的字符内容. (一个XMPP资源标识符是XMPP地址的可选部分,它在域名标识符和'/@'分隔符之后;它经常但不是专门用来关联一个即时消息会话名)这些处理规则仅仅适用于XMPP资源标识符但不适用于任意文本或任何XMPP的其他方面.<br />
<br />
:这个脚本定义了以下这些, 正如 [STRINGPREP]要求的:<br />
<br />
:* 脚本预期的适用性: XMPP的国际化节点标识符<br />
<br />
:* 用于stringprep的输入输出字符集: Unicode 3.2, 定义在本附录的第二章<br />
<br />
:* 使用的映射: 定义在第三章<br />
<br />
:* Unicode正规化使用: 定义在第四章<br />
<br />
:* 禁止输出的字符串: 定义在第五章<br />
<br />
:* 双字节字符处理: 定义在第六章<br />
<br />
===B.2. 字符集===<br />
<br />
:本脚本使用Unicode 3.2的未分配编码列表,指向 Table A.1, 也定义在 [STRINGPREP]的附录<br />
<br />
===B.3. 映射===<br />
<br />
:本脚本指定使用[STRINGPREP]的以下表:<br />
<br />
::Table B.1<br />
<br />
===B.4. 正规化===<br />
<br />
:本脚本指定使用 Unicode normalization form KC, 定义在 [STRINGPREP]中.<br />
<br />
===B.5. 禁止输出===<br />
<br />
:本脚本指定使用以下的[STRINGPREP]表禁止输出.<br />
<br />
::Table C.1.2<br />
<br />
::Table C.2.1<br />
<br />
::Table C.2.2<br />
<br />
::Table C.3<br />
<br />
::Table C.4<br />
<br />
::Table C.5<br />
<br />
::Table C.6<br />
<br />
::Table C.7<br />
<br />
::Table C.8<br />
<br />
::Table C.9<br />
<br />
===B.6. 双字节===<br />
<br />
:本脚本指定按照[STRINGPREP]第六章检查双字节.<br />
<br />
==附录 C. XML 规划==<br />
<br />
:以下 XML schemas 是描述性的, 不是标准的. 'jabber:client' 和 'jabber:server' 名字空间的标准定义, 参照 [[RFC3921]].<br />
<br />
===C.1. Streams namespace===<br />
<br />
<source lang="xml"><br />
<?xml version='1.0' encoding='UTF-8'?><br />
<br />
<xs:schema<br />
xmlns:xs='http://www.w3.org/2001/XMLSchema'<br />
targetNamespace='http://etherx.jabber.org/streams'<br />
xmlns='http://etherx.jabber.org/streams'<br />
elementFormDefault='unqualified'><br />
<br />
<xs:element name='stream'><br />
<xs:complexType><br />
<xs:sequence xmlns:client='jabber:client'<br />
xmlns:server='jabber:server'<br />
xmlns:db='jabber:server:dialback'><br />
<xs:element ref='features' minOccurs='0' maxOccurs='1'/><br />
<xs:any namespace='urn:ietf:params:xml:ns:xmpp-tls'<br />
minOccurs='0'<br />
maxOccurs='unbounded'/><br />
<xs:any namespace='urn:ietf:params:xml:ns:xmpp-sasl'<br />
minOccurs='0'<br />
maxOccurs='unbounded'/><br />
<xs:choice minOccurs='0' maxOccurs='1'><br />
<xs:choice minOccurs='0' maxOccurs='unbounded'><br />
<xs:element ref='client:message'/><br />
<xs:element ref='client:presence'/><br />
<xs:element ref='client:iq'/><br />
</xs:choice><br />
<xs:choice minOccurs='0' maxOccurs='unbounded'><br />
<xs:element ref='server:message'/><br />
<xs:element ref='server:presence'/><br />
<xs:element ref='server:iq'/><br />
<xs:element ref='db:result'/><br />
<xs:element ref='db:verify'/><br />
</xs:choice><br />
</xs:choice><br />
<xs:element ref='error' minOccurs='0' maxOccurs='1'/><br />
</xs:sequence><br />
<xs:attribute name='from' type='xs:string' use='optional'/><br />
<xs:attribute name='id' type='xs:NMTOKEN' use='optional'/><br />
<xs:attribute name='to' type='xs:string' use='optional'/><br />
<xs:attribute name='version' type='xs:decimal' use='optional'/><br />
<xs:attribute ref='xml:lang' use='optional'/><br />
</xs:complexType><br />
</xs:element><br />
<br />
<xs:element name='features'><br />
<xs:complexType><br />
<xs:all xmlns:tls='urn:ietf:params:xml:ns:xmpp-tls'<br />
xmlns:sasl='urn:ietf:params:xml:ns:xmpp-sasl'<br />
xmlns:bind='urn:ietf:params:xml:ns:xmpp-bind'<br />
xmlns:sess='urn:ietf:params:xml:ns:xmpp-session'><br />
<xs:element ref='tls:starttls' minOccurs='0'/><br />
<xs:element ref='sasl:mechanisms' minOccurs='0'/><br />
<xs:element ref='bind:bind' minOccurs='0'/><br />
<xs:elemnt ref='sess:session' minOccurs='0'/><br />
</xs:all><br />
</xs:complexType><br />
</xs:element><br />
<br />
<xs:element name='error'><br />
<xs:complexType><br />
<xs:sequence xmlns:err='urn:ietf:params:xml:ns:xmpp-streams'><br />
<xs:group ref='err:streamErrorGroup'/><br />
<xs:element ref='err:text'<br />
minOccurs='0'<br />
maxOccurs='1'/><br />
</xs:sequence><br />
</xs:complexType><br />
</xs:element><br />
<br />
</xs:schema><br />
</source><br />
<br />
===C.2. Stream error namespace===<br />
<br />
<source lang="xml"><br />
<?xml version='1.0' encoding='UTF-8'?><br />
<br />
<xs:schema<br />
xmlns:xs='http://www.w3.org/2001/XMLSchema'<br />
targetNamespace='urn:ietf:params:xml:ns:xmpp-streams'<br />
xmlns='urn:ietf:params:xml:ns:xmpp-streams'<br />
elementFormDefault='qualified'><br />
<br />
<xs:element name='bad-format' type='empty'/><br />
<xs:element name='bad-namespace-prefix' type='empty'/><br />
<xs:element name='conflict' type='empty'/><br />
<xs:element name='connection-timeout' type='empty'/><br />
<xs:element name='host-gone' type='empty'/><br />
<xs:element name='host-unknown' type='empty'/><br />
<xs:element name='improper-addressing' type='empty'/><br />
<xs:element name='internal-server-error' type='empty'/><br />
<xs:element name='invalid-from' type='empty'/><br />
<xs:element name='invalid-id' type='empty'/><br />
<xs:element name='invalid-namespace' type='empty'/><br />
<xs:element name='invalid-xml' type='empty'/><br />
<xs:element name='not-authorized' type='empty'/><br />
<xs:element name='policy-violation' type='empty'/><br />
<xs:element name='remote-connection-failed' type='empty'/><br />
<xs:element name='resource-constraint' type='empty'/><br />
<xs:element name='restricted-xml' type='empty'/><br />
<xs:element name='see-other-host' type='xs:string'/><br />
<xs:element name='system-shutdown' type='empty'/><br />
<xs:element name='undefined-condition' type='empty'/><br />
<xs:element name='unsupported-encoding' type='empty'/><br />
<xs:element name='unsupported-stanza-type' type='empty'/><br />
<xs:element name='unsupported-version' type='empty'/><br />
<xs:element name='xml-not-well-formed' type='empty'/><br />
<br />
<xs:group name='streamErrorGroup'><br />
<xs:choice><br />
<xs:element ref='bad-format'/><br />
<xs:element ref='bad-namespace-prefix'/><br />
<xs:element ref='conflict'/><br />
<xs:element ref='connection-timeout'/><br />
<xs:element ref='host-gone'/><br />
<xs:element ref='host-unknown'/><br />
<xs:element ref='improper-addressing'/><br />
<xs:element ref='internal-server-error'/><br />
<xs:element ref='invalid-from'/><br />
<xs:element ref='invalid-id'/><br />
<xs:element ref='invalid-namespace'/><br />
<xs:element ref='invalid-xml'/><br />
<xs:element ref='not-authorized'/><br />
<xs:element ref='policy-violation'/><br />
<xs:element ref='remote-connection-failed'/><br />
<xs:element ref='resource-constraint'/><br />
<xs:element ref='restricted-xml'/><br />
<xs:element ref='see-other-host'/><br />
<xs:element ref='system-shutdown'/><br />
<xs:element ref='undefined-condition'/><br />
<xs:element ref='unsupported-encoding'/><br />
<xs:element ref='unsupported-stanza-type'/><br />
<xs:element ref='unsupported-version'/><br />
<xs:element ref='xml-not-well-formed'/><br />
</xs:choice><br />
</xs:group><br />
<br />
<xs:element name='text'><br />
<xs:complexType><br />
<xs:simpleContent><br />
<xs:extension base='xs:string'><br />
<xs:attribute ref='xml:lang' use='optional'/><br />
</xs:extension><br />
</xs:simpleContent><br />
</xs:complexType><br />
</xs:element><br />
<br />
<xs:simpleType name='empty'><br />
<xs:restriction base='xs:string'><br />
<xs:enumeration value=''/><br />
</xs:restriction><br />
</xs:simpleType><br />
<br />
</xs:schema><br />
</source><br />
<br />
===C.3. TLS namespace===<br />
<br />
<source lang="xml"><br />
<?xml version='1.0' encoding='UTF-8'?><br />
<br />
<xs:schema<br />
xmlns:xs='http://www.w3.org/2001/XMLSchema'<br />
targetNamespace='urn:ietf:params:xml:ns:xmpp-tls'<br />
xmlns='urn:ietf:params:xml:ns:xmpp-tls'<br />
elementFormDefault='qualified'><br />
<br />
<xs:element name='starttls'><br />
<xs:complexType><br />
<xs:sequence><br />
<xs:element<br />
name='required'<br />
minOccurs='0'<br />
maxOccurs='1'<br />
type='empty'/><br />
</xs:sequence><br />
</xs:complexType><br />
</xs:element><br />
<br />
<xs:element name='proceed' type='empty'/><br />
<xs:element name='failure' type='empty'/><br />
<br />
<xs:simpleType name='empty'><br />
<xs:restriction base='xs:string'><br />
<xs:enumeration value=''/><br />
</xs:restriction><br />
</xs:simpleType><br />
<br />
</xs:schema><br />
</source><br />
<br />
===C.4. SASL namespace===<br />
<br />
<source lang="xml"><br />
<?xml version='1.0' encoding='UTF-8'?><br />
<br />
<xs:schema<br />
xmlns:xs='http://www.w3.org/2001/XMLSchema'<br />
targetNamespace='urn:ietf:params:xml:ns:xmpp-sasl'<br />
xmlns='urn:ietf:params:xml:ns:xmpp-sasl'<br />
elementFormDefault='qualified'><br />
<br />
<xs:element name='mechanisms'><br />
<xs:complexType><br />
<xs:sequence><br />
<xs:element name='mechanism'<br />
maxOccurs='unbounded'<br />
type='xs:string'/><br />
</xs:sequence><br />
</xs:complexType><br />
</xs:element><br />
<br />
<xs:element name='auth'><br />
<xs:complexType><br />
<xs:simpleContent><br />
<xs:extension base='empty'><br />
<xs:attribute name='mechanism'<br />
type='xs:string'<br />
use='optional'/><br />
</xs:extension><br />
</xs:simpleContent><br />
</xs:complexType><br />
</xs:element><br />
<br />
<xs:element name='challenge' type='xs:string'/><br />
<xs:element name='response' type='xs:string'/><br />
<xs:element name='abort' type='empty'/><br />
<xs:element name='success' type='empty'/><br />
<br />
<xs:element name='failure'><br />
<xs:complexType><br />
<xs:choice minOccurs='0'><br />
<xs:element name='aborted' type='empty'/><br />
<xs:element name='incorrect-encoding' type='empty'/><br />
<xs:element name='invalid-authzid' type='empty'/><br />
<xs:element name='invalid-mechanism' type='empty'/><br />
<xs:element name='mechanism-too-weak' type='empty'/><br />
<xs:element name='not-authorized' type='empty'/><br />
<xs:element name='temporary-auth-failure' type='empty'/><br />
</xs:choice><br />
</xs:complexType><br />
</xs:element><br />
<xs:simpleType name='empty'><br />
<xs:restriction base='xs:string'><br />
<xs:enumeration value=''/><br />
</xs:restriction><br />
</xs:simpleType><br />
<br />
</xs:schema><br />
</source><br />
<br />
===C.5. Resource binding namespace===<br />
<br />
<source lang="xml"><br />
<?xml version='1.0' encoding='UTF-8'?><br />
<br />
<xs:schema<br />
xmlns:xs='http://www.w3.org/2001/XMLSchema'<br />
targetNamespace='urn:ietf:params:xml:ns:xmpp-bind'<br />
xmlns='urn:ietf:params:xml:ns:xmpp-bind'<br />
elementFormDefault='qualified'><br />
<br />
<xs:element name='bind'><br />
<xs:complexType><br />
<xs:choice minOccurs='0' maxOccurs='1'><br />
<xs:element name='resource' type='xs:string'/><br />
<xs:element name='jid' type='xs:string'/><br />
</xs:choice><br />
</xs:complexType><br />
</xs:element><br />
<br />
</xs:schema><br />
</source><br />
<br />
===C.6. Dialback namespace===<br />
<br />
<source lang="xml"><br />
<?xml version='1.0' encoding='UTF-8'?><br />
<br />
<xs:schema<br />
xmlns:xs='http://www.w3.org/2001/XMLSchema'<br />
targetNamespace='jabber:server:dialback'<br />
xmlns='jabber:server:dialback'<br />
elementFormDefault='qualified'><br />
<br />
<xs:element name='result'><br />
<xs:complexType><br />
<xs:simpleContent><br />
<xs:extension base='xs:token'><br />
<xs:attribute name='from' type='xs:string' use='required'/><br />
<xs:attribute name='to' type='xs:string' use='required'/><br />
<xs:attribute name='type' use='optional'><br />
<xs:simpleType><br />
<xs:restriction base='xs:NCName'><br />
<xs:enumeration value='invalid'/><br />
<xs:enumeration value='valid'/><br />
</xs:restriction><br />
</xs:simpleType><br />
</xs:attribute><br />
</xs:extension><br />
</xs:simpleContent><br />
</xs:complexType><br />
</xs:element><br />
<br />
<xs:element name='verify'><br />
<xs:complexType><br />
<xs:simpleContent><br />
<xs:extension base='xs:token'><br />
<xs:attribute name='from' type='xs:string' use='required'/><br />
<xs:attribute name='id' type='xs:NMTOKEN' use='required'/><br />
<xs:attribute name='to' type='xs:string' use='required'/><br />
<xs:attribute name='type' use='optional'><br />
<xs:simpleType><br />
<xs:restriction base='xs:NCName'><br />
<xs:enumeration value='invalid'/><br />
<xs:enumeration value='valid'/><br />
</xs:restriction><br />
</xs:simpleType><br />
</xs:attribute><br />
</xs:extension><br />
</xs:simpleContent><br />
</xs:complexType><br />
</xs:element><br />
<br />
</xs:schema><br />
</source><br />
<br />
===C.7. Stanza error namespace===<br />
<br />
<source lang="xml"><br />
<?xml version='1.0' encoding='UTF-8'?><br />
<br />
<xs:schema<br />
xmlns:xs='http://www.w3.org/2001/XMLSchema'<br />
targetNamespace='urn:ietf:params:xml:ns:xmpp-stanzas'<br />
xmlns='urn:ietf:params:xml:ns:xmpp-stanzas'<br />
elementFormDefault='qualified'><br />
<br />
<xs:element name='bad-request' type='empty'/><br />
<xs:element name='conflict' type='empty'/><br />
<xs:element name='feature-not-implemented' type='empty'/><br />
<xs:element name='forbidden' type='empty'/><br />
<xs:element name='gone' type='xs:string'/><br />
<xs:element name='internal-server-error' type='empty'/><br />
<xs:element name='item-not-found' type='empty'/><br />
<xs:element name='jid-malformed' type='empty'/><br />
<xs:element name='not-acceptable' type='empty'/><br />
<xs:element name='not-allowed' type='empty'/><br />
<xs:element name='payment-required' type='empty'/><br />
<xs:element name='recipient-unavailable' type='empty'/><br />
<xs:element name='redirect' type='xs:string'/><br />
<xs:element name='registration-required' type='empty'/><br />
<xs:element name='remote-server-not-found' type='empty'/><br />
<xs:element name='remote-server-timeout' type='empty'/><br />
<xs:element name='resource-constraint' type='empty'/><br />
<xs:element name='service-unavailable' type='empty'/><br />
<xs:element name='subscription-required' type='empty'/><br />
<xs:element name='undefined-condition' type='empty'/><br />
<xs:element name='unexpected-request' type='empty'/><br />
<br />
<xs:group name='stanzaErrorGroup'><br />
<xs:choice><br />
<xs:element ref='bad-request'/><br />
<xs:element ref='conflict'/><br />
<xs:element ref='feature-not-implemented'/><br />
<xs:element ref='forbidden'/><br />
<xs:element ref='gone'/><br />
<xs:element ref='internal-server-error'/><br />
<xs:element ref='item-not-found'/><br />
<xs:element ref='jid-malformed'/><br />
<xs:element ref='not-acceptable'/><br />
<xs:element ref='not-allowed'/><br />
<xs:element ref='payment-required'/><br />
<xs:element ref='recipient-unavailable'/><br />
<xs:element ref='redirect'/><br />
<xs:element ref='registration-required'/><br />
<xs:element ref='remote-server-not-found'/><br />
<xs:element ref='remote-server-timeout'/><br />
<xs:element ref='resource-constraint'/><br />
<xs:element ref='service-unavailable'/><br />
<xs:element ref='subscription-required'/><br />
<xs:element ref='undefined-condition'/><br />
<xs:element ref='unexpected-request'/><br />
</xs:choice><br />
</xs:group><br />
<br />
<xs:element name='text'><br />
<xs:complexType><br />
<xs:simpleContent><br />
<xs:extension base='xs:string'><br />
<xs:attribute ref='xml:lang' use='optional'/><br />
</xs:extension><br />
</xs:simpleContent><br />
</xs:complexType><br />
</xs:element><br />
<br />
<xs:simpleType name='empty'><br />
<xs:restriction base='xs:string'><br />
<xs:enumeration value=''/><br />
</xs:restriction><br />
</xs:simpleType><br />
<br />
</xs:schema><br />
</source><br />
<br />
==附录 D. 核心Jabber协议和XMPP的不同==<br />
<br />
:本章是非标准的.<br />
<br />
::译者注:附录D对于新接触XMPP的人没有什么意义,就不翻译了,免得浪费时间。因为现在RFC公布已经很久了,以前的Jabber实现很多都进化到XMPP了。<br />
<br />
:XMPP has been adapted from the protocols originally developed in the Jabber open-source community, which can be thought of as "XMPP 0.9". Because there exists a large installed base of Jabber implementations and deployments, it may be helpful to specify the key differences between the relevant Jabber protocols and XMPP in order to expedite and encourage upgrades of those implementations and deployments to XMPP. This section summarizes the core differences, while the corresponding section of [[RFC3921]] summarizes the differences that relate specifically to instant messaging and presence applications.<br />
<br />
===D.1. Channel Encryption===<br />
<br />
:It was common practice in the Jabber community to use SSL for channel encryption on ports other than 5222 and 5269 (the convention is to use ports 5223 and 5270). XMPP uses TLS over the IANA-registered ports for channel encryption, as defined under Use of TLS (Section 5) herein.<br />
<br />
===D.2. Authentication===<br />
<br />
:The client-server authentication protocol developed in the Jabber community used a basic IQ interaction qualified by the 'jabber:iq:auth' namespace (documentation of this protocol is contained in [JEP-0078], published by the Jabber Software Foundation [JSF]). XMPP uses SASL for authentication, as defined under Use of SASL (Section 6) herein.<br />
<br />
:The Jabber community did not develop an authentication protocol for server-to-server communications, only the Server Dialback (Section 8) protocol to prevent server poofing. XMPP supersedes Server Dialback with a true server-to-server authentication protocol, as defined under Use of SASL (Section 6) herein.<br />
<br />
===D.3. Resource Binding===<br />
<br />
:Resource binding in the Jabber community was handled via the 'jabber:iq:auth' namespace (which was also used for client authentication with a server). XMPP defines a dedicated namespace for resource binding as well as the ability for a server to generate a resource identifier on behalf of a client, as defined under Resource Binding (Section 7).<br />
<br />
===D.4. JID Processing===<br />
<br />
:JID processing was somewhat loosely defined by the Jabber community (documentation of forbidden characters and case handling is contained in [JEP-0029], published by the Jabber Software Foundation [JSF]). XMPP specifies the use of [NAMEPREP] for domain identifiers and supplements Nameprep with two additional [STRINGPREP] profiles for JID processing: Nodeprep (Appendix A) for node identifiers and Resourceprep (Appendix B) for resource identifiers.<br />
<br />
===D.5. Error Handling===<br />
<br />
:Stream-related errors were handled in the Jabber community via XML character data text in a <stream:error/> element. In XMPP, stream-related errors are handled via an extensible mechanism defined under Stream Errors (Section 4.7) herein. Stanza-related errors were handled in the Jabber community via HTTP-style error codes. In XMPP, stanza-related errors are handled via an extensible mechanism defined under Stanza Errors (Section 9.3) herein. (Documentation of a mapping between Jabber and XMPP error handling mechanisms is contained in [JEP-0086], published by the Jabber Software Foundation [JSF].)<br />
<br />
===D.6. Internationalization===<br />
<br />
:Although use of UTF-8 has always been standard practice within the Jabber community, the community did not define mechanisms for specifying the language of human-readable text provided in XML character data. XMPP specifies the use of the 'xml:lang' attribute in such contexts, as defined under Stream Attributes (Section 4.4) and xml:lang (Section 9.1.5) herein.<br />
<br />
===D.7. Stream Version Attribute===<br />
<br />
:The Jabber community did not include a 'version' attribute in stream headers. XMPP specifies inclusion of that attribute as a way to signal support for the stream features (authentication, encryption, etc.) defined under Version Support (Section 4.4.1) herein.<br />
<br />
==贡献者==<br />
<br />
:XMPP的大部分核心方面是由1999年开始的Jabber开源社区开发的. 这个社区是由 Jeremie Miller建立的, 他于1999年1月发布了最初版的jabber server源代码. 主要的基础协议的早期贡献者还包括 Ryan Eatmon, Peter Millard, Thomas Muldowney,和 Dave Smith. XMPP工作组的工作主要集中在安全性和国际化方面; 在这些领域, 使用 TLS 和 SASL 的协议最初是由 Rob Norris贡献的, stringprep profiles 最初是由 Joe Hildebrand贡献的. The error code syntax 是由Lisa Dusseault建议的.<br />
<br />
==致谢==<br />
<br />
:感谢许多在贡献者名单之外的人们. 尽管很难提供一个完整的名单, 以下个人对于定义协议或评论标准提供了很多帮助:<br />
<br />
:Thomas Charron, Richard Dobson, Sam Hartman, Schuyler Heath, Jonathan Hogg, Cullen Jennings, Craig Kaes, Jacek Konieczny, Alexey Melnikov, Keith Minkler, Julian Missig, Pete Resnick, Marshall Rose, Alexey Shchepin, Jean-Louis Seguineau, Iain Shigeoka, Greg Troxel, and David Waite. <br />
<br />
:也感谢 XMPP工作组的成员和 IETF 社区在本文的成文过程中一直提供的评论和反馈。<br />
<br />
<br />
==作者地址==<br />
<br />
:Peter Saint-Andre (editor)<br />
<br />
:Jabber Software Foundation<br />
<br />
:EMail: stpeter@jabber.org<br />
<br />
==完整的版权声明==<br />
<br />
:Copyright (C) The Internet Society (2004).<br />
<br />
:This document is subject to the rights, licenses and restrictions contained in BCP 78, and except as set forth therein, the authors retain all their rights. This document and the information contained herein are provided on an "AS IS" basis and THE CONTRIBUTOR, THE ORGANIZATION HE/S HE REPRESENTS OR IS SPONSORED BY (IF ANY), THE INTERNET SOCIETY AND THE INTERNET ENGINEERING TASK FORCE DISCLAIM ALL WARRANTIES, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO ANY WARRANTY THAT THE USE OF THE INFORMATION HEREIN WILL NOT INFRINGE ANY RIGHTS OR ANY IMPLIED WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE.<br />
<br />
==Intellectual Property==<br />
<br />
:The IETF takes no position regarding the validity or scope of any Intellectual Property Rights or other rights that might be claimed to pertain to the implementation or use of the technology described in this document or the extent to which any license under such rights might or might not be available; nor does it represent that it has made any independent effort to identify any such rights. Information on the IETF's procedures with respect to rights in IETF Documents can be found in BCP 78 and BCP 79. Copies of IPR disclosures made to the IETF Secretariat and any assurances of licenses to be made available, or the result of an attempt made to obtain a general license or permission for the use of such proprietary rights by implementers or users of this specification can be obtained from the IETF on-line IPR repository at http://www.ietf.org/ipr. The IETF invites any interested party to bring to its attention any copyrights, patents or patent applications, or other proprietary rights that may cover technology that may be required to implement this standard. Please address the information to the IETF at ietf-ipr@ietf.org.<br />
<br />
==感谢==<br />
<br />
:目前为RFC编辑活动提供资金的Internet Society.</div>
Snowqiang
http://wiki.jabbercn.org/RFC3920
RFC3920
2011-05-18T10:54:59Z
<p>Snowqiang: 格式错误</p>
<hr />
<div>[[Category:XMPP正式RFC标准]]<br />
[[Category:已翻译]]<br />
<br />
"本文的英文原文来自[http://www.ietf.org/rfc/rfc3920.txt RFC 3920]<br />
<br />
{|<br />
|网络工作组 || P. Saint-Andre, Ed.<br />
|-<br />
|申请讨论: 3920 || Jabber软件基金会<br />
|-<br />
|类别: 标准跟踪 || 2004年10月<br />
|}<br />
<br />
<br />
<br />
:::'''可扩展的消息和出席信息协议 (XMPP): 核心协议'''<br />
<br />
'''关于本文的说明'''<br />
<br />
:本文为互联网社区定义了一个互联网标准跟踪协议,并且申请讨论协议和提出了改进的建议。请参照“互联网官方协议标准”的最新版本(STD 1)获得这个协议的标准化进程和状态。本文可以不受限制的分发。<br />
<br />
'''版权声明'''<br />
<br />
:本文版权属于互联网社区 (C) The Internet Society (2004).<br />
<br />
'''摘要'''<br />
<br />
:本文定义了可扩展消息和出席信息协议(XMPP)的核心功能,这个协议采用XML流实现在任意两个网络终端接近实时的交换结构化信息。XMPP提供一个通用的可扩展的框架来交换XML数据,它主要用来建立即时消息和出席信息应用以实现 RFC 2779 的需求。 <br />
<br />
==绪论==<br />
<br />
===概览===<br />
<br />
:XMPP是一个开放式的XML协议,设计用于准实时消息和出席信息以及请求-响应服务。其基本的语法和语义最初主要是由Jabber开放源代码社区于1999年开发的。2002年,XMPP工作组被授权接手开发和改编Jabber协议以适应IETF的即时消息和出席信息技术。作为XMPP工作组的成果,本文定义了 XMPP 1.0 的核心功能;在 RFC 2779 [IMP-REQS] 中指定的提供即时消息和出席信息功能的扩展,定义在 XMPP-IM 协议 [the Extensible Messaging and Presence Protocol (XMPP): Instant Messaging and Presence] 中。<br />
<br />
===术语===<br />
<br />
:本文中大写的关键字 "MUST(必须)", "MUST NOT(不能)", "REQUIRED(必需)", "SHALL(将会)", "SHALL NOT(将不会)", "SHOULD(应该)", "SHOULD NOT(不应该)", "RECOMMENDED(建议)", "MAY(可以)", 和 "OPTIONAL(可选)" 的确切含义符合 BCP 14, RFC 2119 \[TERMS\].<br />
<br />
==通用的架构==<br />
<br />
===概览===<br />
<br />
:尽管XMPP没有指定任何特定的网络结构,但它通常是采用客户-服务器 架构进行实现,其中客户端通过TCP方式使用XMPP访问服务器,服务器之间也采用TCP方式进行通信。<br />
<br />
:以下是这一架构的抽象的示意图 (这里 "-" 表示使用 XMPP 通讯, "=" 表示可使用任何协议通讯)。<br />
<br />
<br />
::C1----S1---S2---C3<br />
<br />
::::|<br />
<br />
::C2----+---G1===FN1===FC1<br />
<br />
:符号的含义如下:<br />
<br />
::* C1, C2, C3 = XMPP 客户端<br />
<br />
::* S1, S2 = XMPP 服务器<br />
<br />
::* G1 = 一个XMPP和外部(非XMPP)消息网络之间进行“翻译”的网关<br />
<br />
::* FN1 = 一个外部消息网络<br />
<br />
::* FC1 = 外部消息网络上的一个客户端<br />
<br />
===服务器===<br />
<br />
:服务器充当XMPP通信的一个智能抽象层,它主要负责:<br />
<br />
:* 对受验证的客户端,服务器以及其他实体之间以XML流形式的连接和会话进行管理。<br />
<br />
:* 在这些实体间使用XML流对合理编址的XML节(第九章)进行路由<br />
<br />
:大部分 XMPP 兼容的服务器也负责存储客户端使用的数据 (比如基于XMPP协议的及时消息应用中的联系人名单); 在这种情况下, XML 数据直接服务器来处理,而不需要转发到其他实体。<br />
<br />
===客户端===<br />
<br />
:大部分客户端通过 TCP 连接直接连到服务器,并通过XMPP获得由服务器以及联合服务器所提供的全部功能。多个不同资源(比如不同的设备和地点)的客户端'''可以'''同时登陆并且并发的连接到一个服务器,每个不同资源的客户端通过XMPP地址的资源标识符来区分(比如<node@domain/ home> 和 <node@domain/work>),参见地址空间(第三章)。'''建议'''的客户端和服务器连接的端口是 5222 ,这个端口已经在 IANA(在第十五章第九节查阅端口号码) 注册了。<br />
<br />
===网关===<br />
<br />
:网关是一个特殊用途的服务器端的服务,主要功能是把 XMPP 翻译成外部(非XMPP)消息系统,并把返回的消息翻译成 XMPP 。例如到 email(参见 [SMTP] ),IRC(参见 [IRC] ),SIMPLE(参见 [SIMPLE] ),SMS 的网关;还有和别的消息服务的网关,比如AIM,ICQ,MSN Messenger,Yahoo! Instant Messenger。网关和服务器之间的通信,网关和外部消息系统的通信,不在本文描述范围之内。<br />
<br />
===网络===<br />
<br />
:因为每个服务器都是由一个网络地址来标识的并且服务器之间的通信是 客户-服务器 协议的直接扩展,实际上整个系统是由很多互通的服务器构成的。例如,<juliet@example.com> 可以和 <romeo@example.net> 交换消息,出席信息和其他信息。这种模式常见于那些需要使网络地址标准化的协议(比如 SMTP )。任意两个服务器之间的通信是可选(OPTIONAL)的。如果被激活,那么这种通信应该(SHOULD)通过 XML 流绑定到 TCP 连接上进行。建议的(RECOMMENDED)服务器之间的连接端口为 5269 ,这个端口号已经在 IANA (在第十五章第九节查阅端口号码)注册了。<br />
<br />
==地址空间==<br />
<br />
===概览===<br />
<br />
:一个实体可以是任何一个被认为是一个网络端点的东西(例如网络上的一个 ID ),而且它是通过XMPP进行通信的。所有这些实体都有一个具有唯一性的地址,并符合 RFC 2396 [URI]规范要求的格式。由于历史原因,一个 XMPP 实体的地址被称为 Jabber Identifier 或 JID 。一个合法的 JID 包括一组排列好的元素,包括域名(domain identifier),节点名(node identifier),和资源名(resource identifier)。<br />
<br />
:JID的语法定义,使用 [ABNF] 中的 Augmented Backus-Naur 格式。(IPv4 地址和 IPv6地址规则在 附录B 中的 [IPv6] 中定义;确定节点规则的合法字符顺序由 附录A 的 [STRINGPREP] 的 Nodeprep 部分来定义;确定资源规则的合法字符顺序由 附录B 的 [STRINGPREP] 的Resourceprep 部分来定义;子域名规则参考 [IDNA] 中关于国际域名标签的描述。)。<br />
<br />
::jid = [ node "@" ] domain [ "/" resource ]<br />
<br />
::domain = fqdn / address-literal<br />
<br />
::fqdn = (sub-domain 1*("." sub-domain))<br />
<br />
::sub-domain = (internationalized domain label)<br />
<br />
::address-literal = IPv4address / IPv6address<br />
<br />
:所有 JID 都是基于上述的结构。类似 <user@host/resource> 这种结构,最常用来标识一个即时消息用户,这个用户所连接的服务器,以及这个用户用于连接的资源(比如特定类型的客户端软件)。不过,节点类型不是客户端也是有可能的,比如一个用来提供多用户聊天服务的特定的聊天室,地址可以是 <room@service> (这里 “room“ 是聊天室的名字而 ”service“ 是多用户聊天服务的主机名),而加入了这个聊天室的某个特定的用户的地址则是 <room@service/nick> (这里 ”nick“ 是用户在聊天室的昵称)。许多其他的 JID 类型都是可能的(例如 <domain/resource> 可能是一个服务器端的脚本或服务)。<br />
<br />
:一个 JID 的每个合法部分(节点名,域名,资源名)的长度不能(MUST NOT)超过 1023 字节。也就是整体长度(包括 '@' 和 '/' )不能超过 3071 字节。<br />
<br />
===域名===<br />
<br />
:域名是一个主要的ID并且是 JID 中唯一必需(REQUIRED)的元素(一个纯粹的域名也是一个合法的 JID)。它通常代表网络的网关或者“主”服务器,其他实体通过连接它来实现 XML 转发和数据管理功能。然而,由一个域名标识引用的实体,并非总是一个服务器,它也可能是一个服务器的子域地址,提供额外的功能(比如多用户聊天服务,用户目录,或一个到外部消息系统的网关)。<br />
<br />
:每个服务器或者服务的域名,可以(MAY)是一个 IP 地址,但应该(SHOULD)是一个完全合法的域名(参见 [DNS]).一个域名ID必须(MUST)是 [IANA] 里定义的“国际化域名”,并且按 [STRINGPREP]中的 [NAMEPREP] profile进行成功的字符转换。在比较两个域名ID之前,服务器必须(MUST),客户端应该(SHOULD)首先按照Nameprep profile(定义在[IANA]中) 来转换每个域名的字符。<br />
<br />
===节点名===<br />
<br />
:节点名是一个可选(OPTIONAL)的第二 ID,放在域名之前并用符号"@"分开.它通常表示一个向服务器或网关请求和使用网络服务的实体(比如一个客户端),当然它也能够表示其他的实体(比如在多用户聊天系统中的一个房间). 节点名所代表的实体,它的地址依赖于一个特定的域名;在 XMPP 的即时消息和出席信息应用系统中,这个地址是“纯 JID” <node@domain> 中的一部分。<br />
<br />
:一个节点名必须按 \[STRINGPREP\] 中的 Nodeprep profile 进行成功的字符转换。在比较两个节点ID之前,服务器必须(MUST),客户端应该(SHOULD)首先按 Nodeprep profile 转换每个ID的字符。<br />
<br />
===资源名===<br />
<br />
:资源名是一个可选的第三 ID,它放在域名的后面并由符号"/"分开。资源名可以跟在 <node@domain>后面也可以跟在 <domain> 后面。它通常表示一个特定的会话,连接(比如设备或者所在位置),或者一个附属于某个节点ID实体相关实体的对象(比如多用户聊天室中的一个参加者)。对于服务器和和其他客户端来说,资源名是不透明的。当它提供必需的信息以完成资源绑定(参见第七章)的时候,通常是由客户端来实现的(尽管可以由客户端向服务器请求完成),然后显示为“已连接的资源”。一个实体可以(MAY)并发维护多个已连接的资源。每个已连接的资源由不同的资源ID来区分。<br />
<br />
:一个资源名必须(MUST)按 \[STRINGPREP\] 中的 Resourceprep profile 进行成功的格式化。在比较两个资源ID之前,服务器必须(MUST),客户端应该(SHOULD)首先按 Resourceprep profile 转换每个ID的字符。<br />
<br />
===地址的确认===<br />
<br />
:在 SASL (见第六章)握手之后(如果必要的话,也在资源绑定(见第七章)之后),正在接收流信息的实体必须(MUST)确认初始实体的 ID 。<br />
<br />
:对于服务器间的通信,在 SASL 握手时,如果没有指明授权的ID,这个初始的实体应该(SHOULD)是经过认证实体(参见 简单认证和安全层协议 \[SASL\] 中的定义)授权的ID(见第六章)。<br />
<br />
:对于客户端和服务器的通信,在 SASL 握手时,如果没有指明授权的ID,“纯 JID” (<node@domain>)应该(SHOULD)是经过认证实体(参见 [SASL] 中的定义)授权的ID,“全 JID” (<node@domain/resource>)的资源ID部分应该(SHOULD)是由客户端和服务器在资源绑定的时候商定的(参见第七章)。<br />
<br />
:接收的实体必须(MUST)确保结果JID(包括节点名,域名,资源名以及分隔符)与本章前面部分描述的规则和格式相一致;为了满足这些约束条件,接收实体可能(MAY)需要把初始实体的发送方 JID 替换成接收实体认可的规范 JID。<br />
<br />
==XML流==<br />
<br />
===概览===<br />
<br />
:两个基本概念,XML流和XML节,使得在出席信息已知的实体之间,异步交换低负载的结构化信息成为可能。这两个术语定义如下:<br />
<br />
:XML流的定义:一个XML流是一个容器,包含了两个实体之间通过网络交换的XML元素。一个XML流是由一个XML打开标签 <stream> (包含适当的属性和名字空间声明)开始的,流的结尾则是一个XML关闭L标签 </stream> 。在流的整个生命周期,初始化它的实体可以通过流发送大量的XML元素,用于流的握手(例如 TLS 握手(第五章) 或 SASL 握手(第六章))或XML节(在这里指符合缺省名字空间的元素,包括<message/>,<presence/>, 或 <iq/> 元素)。“初始的流”由初始化实体(通常是一个客户端或服务器)和接收实体(通常是一个服务器)握手,从接收实体来看,它就是那个初始实体的"会话".初始化流允许从初始化实体到接收实体的单向通信;为了使接收实体能够和初始实体交换信息,接收实体必须发起一个反向的握手(应答流).<br />
<br />
:XML节的定义: 一个XML节是一个实体通过 XML 流向另一个实体发送的结构化信息中的一个离散的语义单位。一个XML节直接存在于根元素<stream/>的下一级,这样可以说是很好的匹配了[XML](译者注:在标准参考一节)的第43条.任何XML节都是从一个XML流的下一级的某个打开标签(如 <presence>)开始,到相应的关闭标签(如 </presence>)。一个XML节可以(MAY)包含子元素(相关的属性,元素, 和 XML 字符数据等) 以表达完整的信息.在这里定义的XML节仅限于<message/>, <presence/>, 和 <iq/> 元素,具体描述间见 XML Stanzas(第九章);为TLS握手(第五章)、SASL握手(第六章)、服务器回拨(第八章)的需要而发送的XML元素,不被认为是一个XML节。<br />
<br />
:设想一个客户端和服务器会话的例子。为了连接一个服务器,一个客户端必须(MUST)发送一个打开标签<stream>给服务器,初始化一个XML流,也可选择(OPTIONAL)在这之前发送一段文本声明XML版本和支持的字符集(参见文本声明的内容(第十一章第四节); 也可看字符编码(第十一章第五节))。视本地化策略和提供的服务而定,服务器应该(SHOULD)回复一个XML流给客户端,同样的,也可选择在这之前发送一段文本声明。一旦客户端完成了SASL握手(第六章),客户端可以(MAY)通过流发送不限量的XML节给网络中的任何接收者。当客户端想关闭这个流,它只需要简单的发送一个关闭标签</stream>给服务器(或者作为另一个选择,可能由服务器关闭这个流)。然后,客户端和服务器都应该(SHOULD)彻底地终止这个连接(通常是一个TCP连接)。<br />
<br />
:那些习惯认为XML是一个以文本为中心风格的人可能希望看看一个与服务器连接的客户端会话,包含两个 打开-关闭 XML文档:一个是从客户端到服务器,一个是从服务器到客户端。下图中,根元素<stream/> 可以被认为是每个“文档”的文档实体,这两个“文档”通过累积那些在XML上传输的XML节来搭建的。无论如何,下图只是方便理解;实际上XMPP并不处理文档而是处理XML流和XML节。<br />
<br />
:基本上,一个XML流相当于一个会话期间所有XML节的一个信封。我们可以简单的把它描述成下图:<br />
<br />
::|----------------------------<br />
<br />
::| <stream><br />
<br />
::|----------------------------<br />
<br />
::| <presence> <br />
<br />
::| <show/> <br />
<br />
::| </presence><br />
<br />
::|----------------------------<br />
<br />
::| <message to='foo'> <br />
<br />
::| <body/> <br />
<br />
::| </message> <br />
<br />
::|----------------------------<br />
<br />
::| <iq to='bar'><br />
<br />
::| <query/> <br />
<br />
::| </iq> <br />
<br />
::|----------------------------<br />
<br />
::| ... <br />
<br />
::|----------------------------<br />
<br />
::| </stream> <br />
<br />
::|----------------------------<br />
<br />
===绑定到TCP===<br />
<br />
:虽然有很多非必需的连接使用XML流来绑定\[TCP\]连接(两个实体可以通过别的机制来互联,比如通过\[HTPP\]连接轮询),本规范只定义了 XMPP 到 TCP 的绑定。在客户和服务器通信的过程中,服务器必须(MUST)允许客户端共享一个TCP连接来传输XML节,包括从客户端传到服务器和从服务器传到客户端。在服务器之间的通信过程中,服务器必须(MUST)用一个 TCP连接 向对方发送 XML节,另一个 TCP连接(由对方初始化)接收对方的XML节,一共两个 TCP连接。<br />
<br />
===流的安全===<br />
<br />
:在XMPP 1.0中,当XML流开始握手时,TLS应该(SHOULD)按 第五章:TLS的使用 中的规定来使用,SASL必须(MUST)按 第六章:SASL的使用 中的规定来使用。尽管可能(MAY)存在某种共有的机制能够保证双向安全,但是“初始化流”(比如从初始化实体发给接收实体的流)和“应答流”(比如从接收实体发给初始化实体的流)还是必须(MUST)安全的分开。在流被验证之间,实体不应该(SHOULD NOT) 尝试通过流发送XML节(第九章);就算它这样做了,对方的实体也不能(MUST NOT)接受这些XML节,并且应该(SHOULD)返回一个 <not-authorized/> 的流错误信息并且终止当前TCP连接上双方的XML流;注意,这仅仅是针对XML节(包含在缺省命名空间中的 <message/>, <presence/>, 和 <iq/> 元素),而不是指那些用于 TLS握手(第五章)、SASL握手(第六章)握手的流。<br />
<br />
===stream 属性===<br />
<br />
:stream 元素的属性如下:<br />
<br />
:* to -- 'to' 属性应(SHOULD)仅出现在初始化实体发给接收实体的 XML 流的头当中,并且它的值必须(MUST)是接收实体所在的主机名。在接收实体发送给初始化实体的 XML 流的头中不应该(SHOULD NOT)出现 'to' 属性。若 'to' 属性出现在应答流中,则初始化实体应(SHOULD)忽略它。<br />
<br />
:* from -- 'from' 属性应(SHOULD)仅出现在接收实体发给初始化实体的 XML 流的头当中,并且它的值必须(MUST)是为当前初始化实体授权的接收实体所在的主机名。注意,不应该(SHOULD NOT)有 'from'属性出现在初始实体发送给接收实体的 XML流的头中;无论如何,如果'from'属性出现在初始化流中,接收实体应该(SHOULD)忽略它。<br />
<br />
:* id -- 'id'属性应该(SHOULD)仅用于接收实体发送给初始化实体 XML流的头。这个属性是一个由接收实体创建的具有唯一性的ID,一个初始实体和接收实体之间的会话ID,并且它在接收方的应用程序中(通常是一个服务器)必须(MUST)是唯一的。注意,这个流 ID 必须是足够安全的,所以它必须是不可预知的和不可重复的(参见[RANDOM] 了解如何获得随机性以保证安全性)。不应该(SHOULD NOT)有 'id'属性出现在初始实体发送给接收实体的 XML流的头中;无论如何,如果'id'属性出现在初始化流中,接收实体应该(SHOULD)忽略它。<br />
<br />
:* xml:lang -- 'xml:lang'属性(定义在\[XML\]中的第二章第十二节)应该(SHOULD)包含在初始化实体发给接收实体的 XML流的头中,以指定在流中传输的可读XML字符所使用的缺省语言。如果这个属性出现了,接收实体应该(SHOULD)记住它的值,作为初始化流和应答流的缺省属性;如果这个属性没有出现,接收实体应该(SHOULD)用一个可配置的缺省值用于双方的流,这个属性值必须(MUST)在应答流的头中传达。对于所有初始化流中传输的节,如果初始实体没有提供'xml:lang'属性,接收实体应该(SHOULD)应用缺省值;如果初始实体提供了'xml:lang'属性,接收实体不能(MUST NOT)修改或删除它(参见第九章第一节第五小节 xml:lang)。'xml:lang'属性的值必须(MUST)是一个 NMTOKEN (定义在\[XML\]的第二章第三节) 并且必须(MUST)遵守 RFC 3066 \[LANGTAGS\] 规定的格式。<br />
<br />
:* version -- version属性(最少需要"1.0")为本规范中和流相关的协议提供了支持。关于这个属性的生成和处理的详细规则将在下文中定义。<br />
<br />
:我们现在可以总结如下:<br />
<br />
{|border="1" cellspacing="0" <br />
! !! 初始化方发给接收方 !! 接收方发给初始化方<br />
|-<br />
|to || 接收方的主机名 || 忽略<br />
|-<br />
|from || 忽略 || 接收方的主机名<br />
|-<br />
|id || 忽略 || 会话键值<br />
|-<br />
|xml:lang || 缺省语言 || 缺省语言<br />
|-<br />
|version || 支持XMPP 1.0 || 支持XMPP 1.0<br />
|}<br />
<br />
====版本支持====<br />
<br />
:在这里XMPP的版本是"1.0";准确地说,这里囊括了和流相关的所有协议(TLS的使用 (第五章),SASL的使用(第六章), 和流错误(第四章第七节)),以及三个定义好的XML节类型(<message/>,<presence/>,和 <iq/>)。XMPP版本号的编号顺序是“<主版本号>.<副版本号>”。主版本和副版本号必须(MUST)是独立的整数并且每个号码可以(MAY)单独以阿拉伯数字增长。这样,"XMPP 2.4"的版本将比"XMPP 2.13"更低。号码前面 的“0”(比如XMPP 6.01)必须(MUST)被接收方忽略并且不能(MUST NOT)被发送出去.<br />
<br />
:如果流和节的格式或者必需的处理方式有了显著的改变,以至于老版本的实体如果只是简单的忽略它不理解的节和属性并且继续像老版本一样的处理方式,会使得老版本的实体不能够和新版本的实体交互,只有在这时候主版本号才应该(SHOULD)增加。副版本号显示新的性能,它必须(MUST)被副版本号更低的实体忽略,但被高(副)版本号的实体用于了解信息。例如,一个副版本号显示处理某种新定义的"type"属性的值(用于message,presence或IQ节)的能力;副版本号高的实体将会了解到与之通信的对方不能够理解这个"type"属性的值,所以将不会发送它。<br />
<br />
:以下规则是用于'版本'属性在实现流的头信息时如何生成和处理:<br />
<br />
:# 初始化实体必须(MUST)在初始化流的头信息中把'版本'的值设置成它所支持的最高版本。(比如,如果最高版本支持就是本规范,那么它必须(MUST)设置成"1.0").<br />
:# 接收实体必须(MUST)在应答流的头信息中把'版本'的值设置成初始化实体所提供的版本或它所支持的最高版本,取其中版本号较低的那一个。接收实体必须(MUST)把主版本号和副版本号作为数字来比较,而不是对"主版本号.副版本号"这个字符串进行比较.<br />
:# 如果在应答流的头信息的版本号中至少有一个主版本号低于初始化流的头信息的版本号,并且如前所述,新版本的实体不能够和旧版本实体交互,初始化实体应该(SHUOULD)生成一个<unsupported-version/>的流错误信息并终止XML流和它的TCP连接。<br />
:# 如果一个实体收到一个头信息中没有'version'属性的流,这个实体必须(MUST)把对方实体的'version'当成'0.0'并且在它发送的应答流的头中也不应该(SHOULD NOT)包含'version'属性.<br />
<br />
===名字空间声明===<br />
<br />
:流的元素必须(MUST)同时满足一个流名字空间声明和一个缺省名字空间声明("名字空间声明"定义在 XML 名字空间定义 \[XML-NAMES\]中).关于流名字空间和缺省名字空间的详细信息,参考 名字空间的名字和前缀(第十一章第二节).<br />
<br />
===流的特性===<br />
<br />
:如果初始化的实体在初始化流的头信息中设置'version'属性的信息为"1.0",接收实体必须(MUST)向初始化实体发送一个 <features/> 子元素以声明任何可供协商的流一级的特性(或者其他需要声明的能力).目前,这仅用于声明本文中定义的 TLS的使用(第五章),SASL的使用(第六章)和资源绑定(第七章),以及 [XMPP-IM|XMPP文档列表/XMPP正式RFC标准/RFC3921] 中定义的会话的建立;无论如何,流特性这一功能将来可以用于声明任何可协商的特性.如果一个实体不理解或支持安全特性,它应该(SHOULD)忽略它.如果要在一个非安全相关的特性(比如资源绑定)被提议之前,完成一个或多个安全特性(比如TLS和SASL)的协商,这个非安全相关的特性不应该(SHOULD NOT)在相应的安全特性协商完毕之前被声明.<br />
<br />
===流错误===<br />
<br />
:流的根元素可以(MAY)包含一个 <error/> 子元素,由流的名字空间前缀作为它的前缀。这个"错误"子元素必须(MUST)由感知到发生了流级别错误的实体发送(通常是一个服务器而不是一个客户端)。<br />
<br />
====规则====<br />
<br />
:以下规则适用于流级别的错误:<br />
<br />
:* 它假定所有流级别的错误都是不可恢复的;所以,如果一个错误发生在流级别,发现这个错误的实体必须(MUST)发送一个流错误信息给另一个实体,发送一个关闭标签 </stream>,并终止这个流所在的TCP连接。<br />
<br />
:* 如果这个错误发生在流刚开始设置的时候,接收实体必须(MUST)仍然发送一个开放标签 <stream> ,并在流元素中包含一个<error/>的子元素,然后发送一个关闭标签 </stream>,最后终止相应的TCP连接。在这种情况下,如果初始化实体在 'to' 属性中提供了一个未知的主机名,服务器应该(SHOULD)在终止之前,先在流的头信息的 'from' 属性中提供一个服务器认证的主机名.<br />
<br />
====语法====<br />
<br />
:流错误的语法如下:<br />
<br />
<source lang="xml"><br />
<stream:error><br />
<defined-condition xmlns='urn:ietf:params:xml:ns:xmpp-streams'/><br />
<text xmlns='urn:ietf:params:xml:ns:xmpp-streams' xml:lang='langcode'><br />
OPTIONAL descriptive text<br />
</text><br />
[OPTIONAL application-specific condition element]<br />
</stream:error><br />
</source><br />
<br />
:<error/>元素:<br />
:* 必须(MUST)包含一个子元素以描述一个下文定义的节错误条件;这个子元素必须(MUST)符合'urn:ietf:params:xml:ns:xmpp-streams'名字空间.<br />
<br />
:* 可以(MAY)包含一个 <text/> 子元素,用XML字符数据描述错误的细节;这个元素必须(MUST)符合'urn:ietf:params:xml:ns:xmpp-streams'名字空间并且应该(SHOULD)拥有一个'xml:lang'属性表明XML字符数据的自然语言。<br />
<br />
:* 可以(MAY)包含一个子元素用于描述一个明确的应用程序错误条件;这个元素必须(MUST)符合一个应用程序定义的名字空间,并且它的结构是由那个名字空间定义的。<br />
<br />
: <text/> 元素是可选的(OPTIONAL)。如果有这个元素,它应该(SHOULD)仅用于提供描述或调试信息以补充一个已定义的条件或应用程序定义的条件。它不应该(SHOULD NOT)被一个应用程序当成一个可编程的信息。它不应该(SHOULD NOT)被用于向用户表达错误信息,但是可以(MAY)作为和条件元素相关的错误信息之外的附加说明。<br />
<br />
====已定义的条件====<br />
<br />
:以下流级别的错误条件是已定义的:<br />
<br />
:* <bad-format/> -- 实体已经发送XML但是不能被处理;这个错误可以(可以)被更多特定的XML相关的错误替换,比如 <bad-namespace-prefix/>, <invalid-xml/>, <restricted-xml/>, <unsupported-encoding/>, 以及 <xml-not-well-formed/>,尽管更多特定的错误是首选的。 <br />
<br />
:* <bad-namespace-prefix/> -- 实体发送的名字空间前缀不被支持,或者在一个需要某种前缀的元素中没有发送一个名字空间前缀(参见 XML Namespace Names and Prefixes (第十一章第二节)).<br />
<br />
:* <conflict/> -- 服务器正在关闭为这个实体激活的流,因为一个和已经存在的流有冲突的新的流已经被初始化。<br />
<br />
:* <connection-timeout/> -- 实体已经很长时间没有通过这个流发生任何通信流量(可由一个本地服务策略来配置).<br />
<br />
:* <host-gone/> -- 初始化实体在流的头信息中提供的'to'属性的值所指定的主机已经不再由这台服务器提供<br />
<br />
:* <host-unknown/> -- 由初始化实体在流的头信息中提供的 'to' 属性的值和由服务器提供的主机名不一致.<br />
<br />
:* <improper-addressing/> -- 一个在两台服务器之间传送的节缺少 'to' 或 'from' 属性(或者这个属性没有值).<br />
<br />
:* <internal-server-error/> -- 服务器配置错误或者其他未定义的内部错误,使得服务器无法提供流服务.<br />
<br />
:* <invalid-from/> -- 在'from'属性中提供的 JID 或 主机名地址,和认证的 JID不匹配 或服务器之间无法通过SASL(或回拨)协商出合法的域名,或客户端和服务器之间无法通过它进行认证和资源绑定。<br />
<br />
:* <invalid-id/> -- 流 ID 或回拨 ID 是非法的或和以前提供的 ID 不一致.<br />
<br />
:* <invalid-namespace/> -- 流名字空间和 "http://etherx.jabber.org/streams" 不相同或回拨名字空间和 "jabber:server:dialback" 不相同.(参考 XML Namespace Names and Prefixes (第十一章第二节)).<br />
<br />
:* <invalid-xml/> -- 实体通过流发送了一个非法的XML给执行验证的服务器 (参考 Validation (第十一章第三节)).<br />
<br />
:* <not-authorized/> -- 实体试图在流被验证之前发送数据或不被许可执行一个和流协商有关的动作,接收实体在发送错误信息之前不允许(MUST NOT)处理厌恶的节。<br />
<br />
:* <policy-violation/> -- 实体违反了某些本地服务策略;服务器可以(MAY)选择在 <text/> 元素或应用程序定义的错误条件(元素)中详细说明策略。<br />
<br />
:* <remote-connection-failed/> -- 服务器无法正确连接到用于验证或授权的远程实体。<br />
<br />
:* <resource-constraint/> -- 服务器缺乏必要的系统资源为流服务。<br />
<br />
:* <restricted-xml/> -- 实体试图发送受限的XML特性,比如一个注释,处理指示,DTD,实体参考,或保留的字符(参考 Restrictions (第十一章第一节)).<br />
<br />
:* <see-other-host/> -- 服务器将不提供服务给初始化实体但是把它重定向到另一台主机;服务器应该(SHOULD)在<see-other-host/>元素的XML字符数据中指明替代服务器名或IP地址(它必须(必须)是合法的域名标识)。<br />
<br />
:* <system-shutdown/> -- 服务器正在关机并且所有激活的流正在被关闭。<br />
<br />
:* <undefined-condition/> -- 错误条件不在本文已定义的错误条件列表之中;这个错误条件应该(SHOULD)仅用于"应用程序定义条件"元素.<br />
<br />
:* <unsupported-encoding/> -- 初始化实体以一个服务器不不支持的编码方式编码了一个流(参照Character Encoding (第十一章第五节)).<br />
<br />
:* <unsupported-stanza-type/> -- 初始化实体发送了一个流的一级子元素但是服务器不支持.<br />
<br />
:* <unsupported-version/> -- 由初始化实体在流的头信息中指定的'version'属性的值所指定的版本不被服务器支持;服务器可以(MAY)在<text/>元素中指定一个它支持的版本号.<br />
<br />
:* <xml-not-well-formed/> -- 初始化实体发送了一个不规范的XML(参考[XML]).<br />
<br />
====应用程序定义条件====<br />
<br />
:大家知道,应用程序可以(MAY)在error元素中包含一个适当名字空间的子元素来提供一个应用程序定义流错误信息."应用程序定义"元素应该(SHOULD)补充或甚至限定一个已定义的元素.所以 <error/> 元素将包含两个或三个子元素:<br />
<br />
<source lang="xml"><br />
<stream:error><br />
<xml-not-well-formed xmlns='urn:ietf:params:xml:ns:xmpp-streams'/><br />
<text xml:lang='en' xmlns='urn:ietf:params:xml:ns:xmpp-streams'><br />
Some special application diagnostic information!<br />
</text><br />
<escape-your-data xmlns='application-ns'/><br />
</stream:error><br />
</stream:stream><br />
</source><br />
<br />
===简化的流示例===<br />
<br />
:这里包含两个简化的例子,描述了基于流的客户端在服务器上的“会话”(这里"C"表示从客户端发给服务器,"S"表示从服务器发给客户端);这些例子只是用于举例说明原理.<br />
<br />
:一个基本的 "会话":<br />
<br />
<source lang="xml"><br />
C: <?xml version='1.0'?><br />
<stream:stream to='example.com' xmlns='jabber:client' xmlns:stream='http://etherx.jabber.org/streams' version='1.0'><br />
<br />
S: <?xml version='1.0'?><br />
<stream:stream from='example.com' id='someid' xmlns='jabber:client' xmlns:stream='http://etherx.jabber.org/streams' version='1.0'><br />
... encryption, authentication, and resource binding ...<br />
<br />
C: <message from='juliet@example.com' to='romeo@example.net' xml:lang='en'><br />
<br />
C: <body>Art thou not Romeo, and a Montague?</body><br />
<br />
C: </message><br />
<br />
S: <message from='romeo@example.net' to='juliet@example.com' xml:lang='en'><br />
<br />
S: <body>Neither, fair saint, if either thee dislike.</body><br />
<br />
S: </message><br />
<br />
C: </stream:stream><br />
<br />
S: </stream:stream><br />
</source><br />
<br />
<br />
:一个不成功的 "会话" :<br />
<br />
<source lang="xml"><br />
C: <?xml version='1.0'?><br />
<stream:stream to='example.com' xmlns='jabber:client' xmlns:stream='http://etherx.jabber.org/streams' version='1.0'><br />
<br />
S: <?xml version='1.0'?><br />
<stream:stream from='example.com' id='someid' xmlns='jabber:client' xmlns:stream='http://etherx.jabber.org/streams' version='1.0'><br />
... encryption, authentication, and resource binding ...<br />
<br />
C: <message xml:lang='en'><br />
<body>Bad XML, no closing body tag!<br />
</message><br />
<br />
S: <stream:error><br />
<xml-not-well-formed xmlns='urn:ietf:params:xml:ns:xmpp-streams'/><br />
</stream:error><br />
<br />
S: </stream:stream><br />
</source><br />
<br />
==TLS 的使用==<br />
<br />
===概览===<br />
<br />
:XMPP包含的一个保证流安全的方法来防止篡改和偷听.这个传输层安全协议[TLS]的频道加密方法, 模拟了类似的其他"STARTTLS"(见RFC 2595 [USINGTLS])的扩展,如 IMAP [IMAP], POP3 [POP3], and ACAP [ACAP]."STARTTLS"的扩展名字空间是'urn:ietf:params:xml:ns:xmpp-tls'.<br />
<br />
:一个给定域的管理员可以(MAY)要求客户端和服务器通信以及服务器之间通信时使用TLS,或者两者都要求。客户端应该(SHOULD)在尝试完成 SASL (第六章)握手之前使用 TLS,服务器应该(SHOULD)在两个域之间使用 TLS 以保证服务器间通信的安全。<br />
<br />
:以下是使用规则:<br />
<br />
::# 一个遵守本协议的初始化实体必须(MUST)在初始化流的头信息中包含一个'version'属性并把值设为“1.0”。<br />
::# 如果TLS握手发生在两个服务器之间,除非服务器声称的DNS主机名已经被解析(见第十四章第四节 Server-to-Server Communications),通信不能(MUST NOT)继续进行。<br />
::# 当一个遵守本协议的接收实体接收了一个初始化流(它的头信息中包含一个'version'属性并且值设为“1.0”),在发送应答流的的头信息(其中包含版本标记)之后,它必须发送(MUST)<starttls/>元素(名字空间为 'urn:ietf:params:xml:ns:xmpp-tls')以及其他它支持的流特性 。<br />
::# 如果初始化实体选择使用TLS,TLS握手必须在SASL握手之前完成;这个顺序用于帮助保护SASL握手时发送的认证信息的安全,同时可以在必要的时候在TLS握手之前为SASL外部机制提供证书。<br />
::# TLS握手期间,一个实体不能(MUST NOT)在流的根元素中发送任何空格符号作为元素的分隔符(在下面的TLS示例中的任何空格符都仅仅是为了便于阅读);这个禁令用来帮助确保安全层字节精度。<br />
::# 接收实体必须(MUST)在发送<proceed/> 元素的关闭符号">" 之后立刻开始TLS协商。初始化实体必须(MUST)在从接收实体接收到<proceed/> 元素的关闭符号">" 之后立刻开始TLS协商。<br />
::# 初始化实体必须(MUST)验证接收实体出示的证书;关于证书验证流程参见Certificate Validation ( 第十四章第二节)。<br />
::# 证书必须(MUST)检查初始化实体(比如一个用户)提供的主机名;而不是通过DNS系统解析出来的主机名;例如,如果用户指定一个主机名"example.com"而一个DNS SRV [SRV]查询返回"im.example.com",证书必须(MUST)检查"example.com".如果任何种类的XMPP实体(例如客户端或服务器)的JID出现在一个证书里,它必须(MUST)表现为一个别名实体里面的UTF8字符串,存在于subjectAltName之中。如何使用 [ASN.1] 对象标识符 "id-on-xmppAddr" 定义在本文的第五章第一节第一小节。<br />
::# 如果 TLS 握手成功了,接收实体必须(MUST) 丢弃TLS 生效之前从初始化实体得到的任何不可靠的信息.<br />
::# 如果 TLS 握手成功了,初始化实体必须(MUST) 丢弃TLS 生效之前从接收实体得到的任何不可靠的信息. <br />
::# 如果 TLS 握手成功了,接收实体不能(MUST NOT)在流重新开始的时候通过提供其他的流特性来向初始化实体提供 STARTTLS 扩展.<br />
::# 如果 TLS 握手成功了,初始化实体必须(MUST)继续进行SASL握手。<br />
::# 如果 TLS 握手失败了,接收实体必须(MUST)终止XML流和相应的TCP连接。<br />
::# 关于必须(MUST)支持的机制,参照 Mandatory-to-Implement Technologies (第十四章第七节) 。<br />
<br />
====用于 XMPP 地址的 ASN.1 对象标识符====<br />
<br />
:上文提到的[ASN.1] 对象标识符 "id-on-xmppAddr"定义如下:<br />
<br />
::id-pkix OBJECT IDENTIFIER ::= { iso(1) identified-organization(3)<br />
<br />
::dod(6) internet(1) security(5) mechanisms(5) pkix(7) }<br />
<br />
::id-on OBJECT IDENTIFIER ::= { id-pkix 8 } \-\- other name forms<br />
<br />
::id-on-xmppAddr OBJECT IDENTIFIER ::= { id-on 5 }<br />
<br />
::XmppAddr ::= UTF8String<br />
<br />
:对象标识符也可以(MAY)使用点分隔的格式,如 "1.3.6.1.5.5.7.8.5".<br />
<br />
===叙述===<br />
<br />
:当一个初始化实体用TLS保护一个和接收实体之间的流,其步骤如下:<br />
<br />
::# 初始化实体打开一个TCP连接,发送一个打开的XML流头信息(其'version'属性设置为"1.0")给接收实体以初始化一个流。<br />
::# 接收实体打开一个TCP连接,发送一个XML流头信息(其'version'属性设置为"1.0")给初始化实体作为应答。<br />
::# 接收实体向初始化实体提议STARTTLS范围(包括其他支持的流特性),如果TLS对于和接收实体交互是必需的,它应该(SHOULD)在<starttls/>元素中包含子元素<required/>.<br />
::# 初始化实体发出STARTTLS命令(例如, 一个符合'urn:ietf:params:xml:ns:xmpp-tls'名字空间的 <starttls/> 元素) 以通知接收实体它希望开始一个TLS握手来保护流。<br />
::# 接收实体必须(MUST)以'urn:ietf:params:xml:ns:xmpp-tls'名字空间中的<proceed/>元素或<failure/>元素应答。如果失败,接收实体必须(MUST)终止XML流和相应的TCP连接。如果继续进行,接收实体必须(MUST)尝试通过TCP连接完成TLS握手并且在TLS握手完成之前不能(MUST NOT)发送任何其他XML数据。<br />
::# 初始化实体和接收实体尝试完成TLS握手。(要符合\[TLS\]规范)<br />
::# 如果 TLS 握手不成功, 接收实体必须(MUST)终止 TCP 连接. 如果 TLS 握手成功, 初始化实体必须(MUST)发送给接收实体一个打开的XML流头信息来初始化一个新的流(先发送一个关闭标签</stream>是不必要的,因为接收实体和初始化实体必须(MUST)确保原来的流在TLS握手成功之后被关闭) 。<br />
::# 在从初始化实体收到新的流头信息之后,接收实体必须(MUST)发送一个新的XML流头信息给初始化实体作为应答,其中应包含可用的特性但不包含STATRTTLS特性。<br />
<br />
===客户端-服务器 示例===<br />
<br />
:以下例子展示一个客户端使用STARTTLS保护数据流 (注意: 以下步骤举例说明协议中的失败案例;在这个例子中它们并不详尽并且也不是必须被数据传输触发的).<br />
<br />
:步骤 1: 客户端初始化流给服务器:<br />
<br />
<source lang="xml"><br />
<stream:stream xmlns='jabber:client' xmlns:stream='http://etherx.jabber.org/streams' to='example.com' version='1.0'><br />
</source><br />
<br />
:步骤 2: 服务器发送一个流标签给客户端作为应答:<br />
<br />
<source lang="xml"><br />
<stream:stream xmlns='jabber:client' xmlns:stream='http://etherx.jabber.org/streams' id='c2s_123' from='example.com' version='1.0'><br />
</source><br />
<br />
:步骤 3: 服务器发送 STARTTLS 范围给客户端(包括验证机制和任何其他流特性):<br />
<br />
<source lang="xml"><br />
<stream:features><br />
<starttls xmlns='urn:ietf:params:xml:ns:xmpp-tls'><br />
<required/><br />
</starttls><br />
<mechanisms xmlns='urn:ietf:params:xml:ns:xmpp-sasl'><br />
<mechanism>DIGEST-MD5</mechanism><br />
<mechanism>PLAIN</mechanism><br />
</mechanisms><br />
</stream:features><br />
</source><br />
<br />
:步骤 4: 客户端发送 STARTTLS 命令给服务器:<br />
<br />
<source lang="xml"><br />
<starttls xmlns='urn:ietf:params:xml:ns:xmpp-tls'/><br />
</source><br />
<br />
:步骤 5: 服务器通知客户端可以继续进行:<br />
<br />
<source lang="xml"><br />
<proceed xmlns='urn:ietf:params:xml:ns:xmpp-tls'/><br />
</source><br />
<br />
:步骤 5 (或者): 服务器通知客户端 TLS 握手失败并关闭流和TCP连接:<br />
<br />
<source lang="xml"><br />
<failure xmlns='urn:ietf:params:xml:ns:xmpp-tls'/><br />
</stream:stream><br />
</source><br />
<br />
:步骤 6: 客户端和服务器尝试通过已有的TCP连接完成 TLS 握手.<br />
<br />
:步骤 7: 如果 TLS 握手成功, 客户端初始化一个新的流给服务器:<br />
<br />
<source lang="xml"><br />
<stream:stream xmlns='jabber:client' xmlns:stream='http://etherx.jabber.org/streams' to='example.com' version='1.0'><br />
</source><br />
<br />
:步骤 7 (或者): 如果 TLS 握手不成功, 服务器关闭 TCP 连接.<br />
<br />
:步骤 8: 服务器发送一个流头信息应答客户端,其中包括任何可用的流特性:<br />
<br />
<source lang="xml"><br />
<stream:stream xmlns='jabber:client' xmlns:stream='http://etherx.jabber.org/streams' from='example.com' id='c2s_234' version='1.0'><br />
<stream:features><br />
<mechanisms xmlns='urn:ietf:params:xml:ns:xmpp-sasl'><br />
<mechanism>DIGEST-MD5</mechanism><br />
<mechanism>PLAIN</mechanism><br />
<mechanism>EXTERNAL</mechanism><br />
</mechanisms><br />
</stream:features><br />
</source><br />
<br />
:步骤 9: 客户端继续 SASL 握手 (第六章).<br />
<br />
===服务器-服务器示例===<br />
<br />
:以下例子展示两个服务器之间使用STARTTLS保护数据流 (注意: 以下步骤举例说明协议中的失败案例;在这个例子中它们并不详尽并且也不是必须被数据传输触发的).<br />
<br />
:步骤 1: Server1 初始化流给 Server2:<br />
<br />
<source lang="xml"><br />
<stream:stream xmlns='jabber:server' xmlns:stream='http://etherx.jabber.org/streams' to='example.com' version='1.0'><br />
</source><br />
<br />
:步骤 2: Server2 发送一个流标签给 Server1 作为应答:<br />
<br />
<source lang="xml"><br />
<stream:stream xmlns='jabber:server' xmlns:stream='http://etherx.jabber.org/streams' from='example.com' id='s2s_123' version='1.0'><br />
</source><br />
<br />
:步骤 3: Server2 发送 STARTTLS 范围给 Server1 ,包括验证机制和任何其他流特性:<br />
<br />
<source lang="xml"><br />
<stream:features><br />
<starttls xmlns='urn:ietf:params:xml:ns:xmpp-tls'><br />
<required/><br />
</starttls><br />
<mechanisms xmlns='urn:ietf:params:xml:ns:xmpp-sasl'><br />
<mechanism>DIGEST-MD5</mechanism><br />
<mechanism>KERBEROS_V4</mechanism><br />
</mechanisms><br />
</stream:features><br />
</source><br />
<br />
:步骤 4: Server1 发送 STARTTLS 命令给 Server2:<br />
<br />
<source lang="xml"><br />
<starttls xmlns='urn:ietf:params:xml:ns:xmpp-tls'/><br />
</source><br />
<br />
:步骤 5: Server2 通知 Server1 允许继续进行:<br />
<br />
<source lang="xml"><br />
<proceed xmlns='urn:ietf:params:xml:ns:xmpp-tls'/><br />
</source><br />
<br />
:步骤 5 (或者): Server2 通知 Server1 TLS握手失败并关闭流:<br />
<br />
<source lang="xml"><br />
<failure xmlns='urn:ietf:params:xml:ns:xmpp-tls'/><br />
</stream:stream><br />
</source><br />
<br />
:步骤 6: Server1 和 Server2 尝试通过 TCP 完成 TLS 握手.<br />
<br />
:步骤 7: 如果 TLS 握手成功, Server1 初始化一个新的流给 Server2:<br />
<br />
<source lang="xml"><br />
<stream:stream xmlns='jabber:server' xmlns:stream='http://etherx.jabber.org/streams' to='example.com' version='1.0'><br />
</source><br />
<br />
:步骤 7 (或者): 如果 TLS 握手不成功, Server2 关闭 TCP 连接.<br />
<br />
:步骤 8: Server2 发送一个包含任何可用流特性的流头信息给 Server1 :<br />
<br />
<source lang="xml"><br />
<stream:stream xmlns='jabber:server' xmlns:stream='http://etherx.jabber.org/streams' from='example.com' id='s2s_234' version='1.0'><br />
<stream:features><br />
<mechanisms xmlns='urn:ietf:params:xml:ns:xmpp-sasl'><br />
<mechanism>DIGEST-MD5</mechanism><br />
<mechanism>KERBEROS_V4</mechanism><br />
<mechanism>EXTERNAL</mechanism><br />
</mechanisms><br />
</stream:features><br />
</source><br />
<br />
:步骤 9: Server1 继续进行 SASL 握手(第六章).<br />
<br />
==SASL 的使用==<br />
<br />
===概览===<br />
<br />
:XMPP 有一个验证流的方法,即XMPP特定的SASL(简单验证和安全层)[SASL]。SASL提供了一个通用的方法为基于连接的协议增加验证支持,而XMPP使用了一个普通的XML名字空间来满足SASL的需要。<br />
<br />
:以下规则应用于:<br />
<br />
:# 如果SASL协商发生在两台服务器之间,除非服务器宣称的DNS主机名得到解析,否则不能(MUST NOT)进行通信。(参见 服务器间的通信(第十四章第四节)).<br />
:# 如果初始化实体有能力使用 SASL 协商, 它必须(MUST)在初始化流的头信息中包含一个值为"1.0"的属性'version'。<br />
:# 如果接收实体有能力使用 SASL 协商, 它必须(MUST)在应答从初始化实体收到的打开流标签时(如果打开的流标签包含一个值为"1.0"的'version'属性),通过'urn:ietf:params:xml:ns:xmpp-sasl'名字空间中的<mechanisms/>元素声明一个或多个验证机制.<br />
:# 当 SASL 协商时, 一个实体不能(MUST NOT)在流的根元素中发送任何空格符号(匹配 production [3] content of [XML])作为元素之间的分隔符(在以下的SASL例子中任何空格符号的出现仅仅是为了增加可读性); 这条禁令帮助确保安全层字节的精确度。<br />
:# 当SASL握手时,在XML元素中使用的任何 XML 字符数据必须被编码成 base64, 编码遵循 RFC 3548 第三章的规定。<br />
:# 如果一个 简单名字"simple username" 规范被选定的SASL机制所支持,(比如, 这被 DIGEST-MD5 和 CRAM-MD5 机制支持但不被 EXTERNAL 和 GSSAPI 机制支持), 验证的时候初始化实体应该(SHOULD)在服务器间通信时提供 简单名字 自身的发送域(IP地址或包含在一个域标识符中的域名全称),在客户端与服务器之间通信时提供注册用户名(包含在一个XMPP节点标识符中的用户或节点名)。<br />
:# 如果初始化实体希望以另一个实体的身份出现并且SASL机制支持授权ID的传输,初始化实体在SASL握手时必须(MUST)提供一个授权ID。如果初始化实体不希望以另一个实体的身份出现,初始化实体在SASL握手时不能(MUST NOT)提供一个授权ID。在 [SASL] 的定义中,除非授权ID不同于从验证ID(详见[SASL])中得到的缺省的授权ID,初始化实体不能(MUST NOT)提供授权ID。如果提供了,这个授权ID的值必须(MUST)是<domain>的格式(对于服务器来说)或<node@domain>的格式(对于客户端来说). <br />
:# 在成功进行包括安全层的SASL握手之后,接收实体必须(MUST)丢弃任何从初始化实体得到的而不是从SASL协商本身获得的信息。<br />
:# 在成功进行包括安全层的SASL握手之后,初始化实体必须(MUST)丢弃任何从接收实体得到的而不是从SASL协商本身获得的信息。<br />
:# 参看 强制执行的技术 (第十四章第七节) ,了解关于必须(MUST)支持的机制.<br />
<br />
===叙述===<br />
<br />
:一个初始化实体使用SASL和接收实体做验证的步骤如下:<br />
<br />
:# 初始化实体请求SASL验证,它发送一个打开的XML流头信息给接收实体,其'version'属性的值为"1.0".<br />
:# 在发送一个XML流头回复之后,接收实体声明一个可用的SASL验证机制清单;每个机制作为一个<mechanism/>元素,作为子元素包含在<mechanisms/>容器元素(其名字空间为'urn:ietf:params:xml:ns:xmpp-sasl')中,而<mechanisms/>则包含在流名字空间中的<features/>元素中。如果在使用任何验证机制之前需要使用TLS(见第五章),接收实体不能(MUST NOT)在TLS握手之前提供可用的SASL验证机制清单。如果初始化实体在优先的TLS协商过程中呈现了一个合法的证书,接收实体应该(SHOULD)在SASL握手中提出一个SASL外部机制给初始化实体,尽管这个外部机制可以(MAY)在其它环境下提供。<br />
:# 初始化实体发送一个符合'urn:ietf:params:xml:ns:xmpp-sasl'名字空间的<auth/>元素(其中包含了适当的'mechanism'属性值)给接收实体,以选择一个机制。如果这个机制支持或需要,这个元素可以(MAY)包含XML字符数据(在SASL术语中,即“初始化应答”);如果初始化实体需要发送一个零字节的初始化应答,它必须(MUST)传输一个单独的等号作为应答,这表示应答有效但不包含数据。<br />
:# 如果必要,接收实体向初始化实体发送一个符合'urn:ietf:params:xml:ns:xmpp-sasl'名字空间的<challenge/>元素来发出挑战;这个元素可以(MAY)包含XML字符数据(必须按照初始化实体选择的SASL机制进行一致性运算)。<br />
:# 初始化实体向接收实体发送符合'urn:ietf:params:xml:ns:xmpp-sasl'名字空间的<response/>元素作为应答;这个元素可以(MAY)包含XML字符数据(必须按照初始化实体选择的SASL机制进行一致性运算)。<br />
:# 如果必要,接收实体发送更多的挑战给初始化实体,初始化实体发送更多的回应。<br />
<br />
:这一系列的 挑战/应答 组,持续进行直到发生以下三件事中的一件为止:<br />
<br />
:# 初始化实体向接收实体发送符合'urn:ietf:params:xml:ns:xmpp-sasl'名字空间的<abort/>元素以中止握手。在接收到<abort/>元素之后,接收实体应该(SHOULD)允许一个可配置的但是合理的重试次数(至少2次),然后它必须(MUST)终止TCP连接;这使得初始化实体(如一个最终用户客户端)能够容忍可能不正确的credentials(如密码输入错误)而不用强制重新连接。<br />
:# 接收实体向初始化实体发送符合'urn:ietf:params:xml:ns:xmpp-sasl'名字空间的<failure/>元素以报告握手失败(详细的失败原因应该在<failure/>的一个适当的子元素中沟通,在第六章第四节中的SASL Errors中定义)。如果失败的情况发生了,接收实体应该(SHOULD)允许一个可配置的但是合理的重试次数(至少2次), 然后它必须(MUST)终止TCP连接;这使得初始化实体(如一个最终用户客户端)能够容忍可能不正确的credentials(如密码输入错误)而不用强制重新连接。<br />
:# 接收实体向初始化实体发送符合'urn:ietf:params:xml:ns:xmpp-sasl'名字空间的<success/>元素以报告握手成功;如果所选择的SASL机制要求,这个元素可以(MAY)包含XML字符数据(见SASL术语,“成功的额外数据”)。接收到<success/> 元素之后,初始化实体必须(MUST)发送一个打开的XML流头信息给接收实体以发起一个新的的流(不需要先发送一个 </stream>标签,因为在发送和接收到<success/>元素之后,接收实体和初始化实体必须确认原来的流被关闭了)。从初始化实体接收到新的流头信息之后,接收实体必须(MUST)发送一个新的流头信息给初始化实体作为回应,附上任何可用的特性(但不包括 STARTTLS 和 SASL 特性)或一个空的 <features/> 元素(这表示没有更多的特性可用);任何没有在本文定义的附加特性必须(MUST)在XMPP的相关扩展中定义。<br />
<br />
===SASL 定义===<br />
<br />
:[SASL]的必要条件要求通过协议定义来提供以下信息:<br />
<br />
::service name(服务名): "xmpp"<br />
<br />
::initiation sequence(开始序列): 当初始化实体提供一个打开的XML流头信息并且接收实体善意回应之后,接收实体提供一个可接受的验证方法清单。初始化实体从这个清单中选择一个方法,把它作为 <auth/> 元素的 'mechanism' 属性的值发送给接收实体,也可以选择发送一个初始化应答以避免循环。<br />
<br />
::exchange sequence(交换序列): 挑战和回应的交换,从接收实体发送给初始化实体的 <challenge/> 元素和从初始化实体发送给接收实体的 <response/> 元素信息。接收实体通过发送 <failure/>元素报告失败,发送<success/>元素报告成功;初始化实体通过发送<abort/> 元素中止交换。成功的协商之后,两边都认为原来的XML流已经关闭并且都开始发送新的流头信息。<br />
<br />
::security layer negotiation(安全层协商): 安全层在接收实体发送 <success/> 元素的关闭字符">"之后立刻生效,在初始化实体发送 <success/> 元素的关闭字符">"之后也立刻生效。层的顺序是 \[TCP\],\[TLS\],然后是 \[SASL\],然后是 \[XMPP\]。<br />
<br />
::use of the authorization identity(授权ID的使用): 授权ID可在xmpp中用于表示一个客户端的非缺省的<node@domain>,或一个服务器的<domain> 。<br />
<br />
===SASL 错误===<br />
<br />
:SASL相关的错误条件定义如下:<br />
<br />
::* <aborted/> -- 接收实体认可由初始化实体发送的<abort/>元素;在回应一个<abort/>元素时发送。<br />
<br />
::* <incorrect-encoding/> -- 由初始化实体提供的数据无法处理,因为[BASE64]编码不正确(例如,因为编码不符合[BASE64]的第三章); 在回应一个包含初始化响应数据的<response/> 元素或<auth/>元素时发送.<br />
<br />
::* <invalid-authzid/> -- 由初始化实体提供的授权id是非法的,因为它的格式不正确或初始化实体无权给那个ID授权;在回应一个包含初始化响应数据的<response/> 元素或<auth/>元素时发送。<br />
<br />
::* <invalid-mechanism/> -- 初始化实体不能提供一个机制活、或请求一个不被接受实体支持的机制;在回应一个<auth/>元素时发送。<br />
<br />
::* <mechanism-too-weak/> -- 初始化实体请求的机制比服务器策略对它的要求弱;在回应一个包含初始化响应数据的<response/> 元素或<auth/>元素时发送。<br />
<br />
::* <not-authorized/> -- 验证失败,因为初始化实体没有提供合法的credentials(这包括但不限于未知用户名等情形);在回应一个包含初始化响应数据的<response/> 元素或<auth/>元素时发送。<br />
<br />
::* <temporary-auth-failure/> -- 验证失败,因为接收实体出现了临时的错误;在回应一个<response/> 元素或<auth/>元素时发送。<br />
<br />
===客户端-服务器 示例===<br />
<br />
:以下例子展示了一个客户端和一个服务器使用SASL作验证的数据流,通常是在成功的TLS握手之后(注意:以下显示的替代步骤仅用于举例说明协议的失败情形;它们不够详尽也不需要由例子中的数据传送来触发)。<br />
<br />
:步骤 1: 客户端初始化流给服务器:<br />
<br />
<source lang="xml"><br />
<stream:stream xmlns='jabber:client' xmlns:stream='http://etherx.jabber.org/streams' to='example.com' version='1.0'><br />
</source><br />
<br />
:步骤 2: 服务器向客户端发送流标签作为应答:<br />
<br />
<source lang="xml"><br />
<stream:stream xmlns='jabber:client' xmlns:stream='http://etherx.jabber.org/streams' id='c2s_234' from='example.com' version='1.0'><br />
</source><br />
<br />
:步骤 3: 服务器通知客户端可用的验证机制:<br />
<br />
<source lang="xml"><br />
<stream:features><br />
<mechanisms xmlns='urn:ietf:params:xml:ns:xmpp-sasl'><br />
<mechanism>DIGEST-MD5</mechanism><br />
<mechanism>PLAIN</mechanism><br />
</mechanisms><br />
</stream:features><br />
</source><br />
<br />
:步骤 4: 客户端选择一个验证机制:<br />
<br />
<source lang="xml"><br />
<auth xmlns='urn:ietf:params:xml:ns:xmpp-sasl' mechanism='DIGEST-MD5'/><br />
</source><br />
<br />
:步骤 5: 服务器发送一个 \[BASE64\] 编码的挑战给客户端:<br />
<br />
<source lang="xml"><br />
<challenge xmlns='urn:ietf:params:xml:ns:xmpp-sasl'><br />
cmVhbG09InNvbWVyZWFsbSIsbm9uY2U9Ik9BNk1HOXRFUUdtMmhoIixxb3A9ImF1dGgi<br />
LGNoYXJzZXQ9dXRmLTgsYWxnb3JpdGhtPW1kNS1zZXNzCg==<br />
</challenge><br />
</source><br />
<br />
:解码后的挑战信息是:<br />
<br />
<source lang="xml"><br />
realm="somerealm",nonce="OA6MG9tEQGm2hh",\<br />
qop="auth",charset=utf-8,algorithm=md5-sess<br />
</source><br />
<br />
:步骤 5 (替代): 服务器返回一个错误给客户端:<br />
<br />
<source lang="xml"><br />
<failure xmlns='urn:ietf:params:xml:ns:xmpp-sasl'><br />
<incorrect-encoding/><br />
</failure><br />
</stream:stream><br />
</source><br />
<br />
:步骤 6: 客户端发送一个\[BASE64\]编码的回应这个挑战:<br />
<br />
<source lang="xml"><br />
<response xmlns='urn:ietf:params:xml:ns:xmpp-sasl'><br />
dXNlcm5hbWU9InNvbWVub2RlIixyZWFsbT0ic29tZXJlYWxtIixub25jZT0i<br />
T0E2TUc5dEVRR20yaGgiLGNub25jZT0iT0E2TUhYaDZWcVRyUmsiLG5jPTAw<br />
MDAwMDAxLHFvcD1hdXRoLGRpZ2VzdC11cmk9InhtcHAvZXhhbXBsZS5jb20i<br />
LHJlc3BvbnNlPWQzODhkYWQ5MGQ0YmJkNzYwYTE1MjMyMWYyMTQzYWY3LGNo<br />
YXJzZXQ9dXRmLTgK<br />
</response><br />
</source><br />
<br />
:解码后的回应信息是:<br />
<br />
<source lang="xml"><br />
username="somenode",realm="somerealm",\<br />
nonce="OA6MG9tEQGm2hh",cnonce="OA6MHXh6VqTrRk",\<br />
nc=00000001,qop=auth,digest-uri="xmpp/example.com",\<br />
response=d388dad90d4bbd760a152321f2143af7,charset=utf-8<br />
</source><br />
<br />
:步骤 7: 服务器发送另一个\[BASE64\]编码的挑战给客户端:<br />
<br />
<source lang="xml"><br />
<challenge xmlns='urn:ietf:params:xml:ns:xmpp-sasl'><br />
cnNwYXV0aD1lYTQwZjYwMzM1YzQyN2I1NTI3Yjg0ZGJhYmNkZmZmZAo=<br />
</challenge><br />
</source><br />
<br />
:解码后的挑战信息是:<br />
<br />
<source lang="xml"><br />
rspauth=ea40f60335c427b5527b84dbabcdfffd<br />
</source><br />
<br />
:步骤 7 (或者): 服务器返回一个错误给客户端:<br />
<br />
<source lang="xml"><br />
<failure xmlns='urn:ietf:params:xml:ns:xmpp-sasl'><br />
<temporary-auth-failure/><br />
</failure><br />
</stream:stream><br />
</source><br />
<br />
:步骤 8: 客户端应答这个挑战:<br />
<br />
<source lang="xml"><br />
<response xmlns='urn:ietf:params:xml:ns:xmpp-sasl'/><br />
</source><br />
<br />
:步骤 9: 服务器通知客户端验证成功:<br />
<br />
<source lang="xml"><br />
<success xmlns='urn:ietf:params:xml:ns:xmpp-sasl'/><br />
</source><br />
<br />
:步骤 9 (或者): 服务器通知客户端验证失败:<br />
<br />
<source lang="xml"><br />
<failure xmlns='urn:ietf:params:xml:ns:xmpp-sasl'><br />
<temporary-auth-failure/><br />
</failure><br />
</stream:stream><br />
</source><br />
<br />
:步骤 10: 客户端发起一个新的流给服务器:<br />
<br />
<source lang="xml"><br />
<stream:stream xmlns='jabber:client' xmlns:stream='http://etherx.jabber.org/streams' to='example.com' version='1.0'><br />
</source><br />
<br />
:步骤 11: 服务器发送一个流头信息回应客户端,并附上任何可用的特性(或空的features元素):<br />
<br />
<source lang="xml"><br />
<stream:stream xmlns='jabber:client' xmlns:stream='http://etherx.jabber.org/streams' id='c2s_345' from='example.com' version='1.0'><br />
<stream:features><br />
<bind xmlns='urn:ietf:params:xml:ns:xmpp-bind'/><br />
<session xmlns='urn:ietf:params:xml:ns:xmpp-session'/><br />
</stream:features><br />
</source><br />
<br />
===服务器-服务器 示例===<br />
<br />
:以下例子展示了一个服务器和另一个服务器使用SASL作验证的数据流,通常是在成功的TLS握手之后(注意:以下显示的替代步骤仅用于举例说明协议的失败情形;它们不够详尽也不需要由例子中的数据传送来触发)。<br />
<br />
:步骤 1: 服务器1 发起一个流给 服务器2 :<br />
<br />
<source lang="xml"><br />
<stream:stream xmlns='jabber:server' xmlns:stream='http://etherx.jabber.org/streams' to='example.com' version='1.0'><br />
</source><br />
<br />
:步骤 2: 服务器2 回应一个流标签给 服务器1:<br />
<br />
<source lang="xml"><br />
<stream:stream xmlns='jabber:server' xmlns:stream='http://etherx.jabber.org/streams' from='example.com' id='s2s_234' version='1.0'><br />
</source><br />
<br />
:步骤 3: 服务器2 通知 服务器1 可用的验证机制:<br />
<br />
<source lang="xml"><br />
<stream:features><br />
<mechanisms xmlns='urn:ietf:params:xml:ns:xmpp-sasl'><br />
<mechanism>DIGEST-MD5</mechanism><br />
<mechanism>KERBEROS_V4</mechanism><br />
</mechanisms><br />
</stream:features><br />
</source><br />
<br />
:步骤 4: 服务器1 选择一个验证机制:<br />
<br />
<source lang="xml"><br />
<auth xmlns='urn:ietf:params:xml:ns:xmpp-sasl' mechanism='DIGEST-MD5'/><br />
</source><br />
<br />
:步骤 5: 服务器2 发送一个\[BASE64\]编码的挑战给 服务器1:<br />
<br />
<source lang="xml"><br />
<challenge xmlns='urn:ietf:params:xml:ns:xmpp-sasl'><br />
cmVhbG09InNvbWVyZWFsbSIsbm9uY2U9Ik9BNk1HOXRFUUdtMmhoIixxb3A9<br />
ImF1dGgiLGNoYXJzZXQ9dXRmLTgsYWxnb3JpdGhtPW1kNS1zZXNz<br />
</challenge><br />
</source><br />
<br />
:解码后的挑战信息是:<br />
<br />
<source lang="xml"><br />
realm="somerealm",nonce="OA6MG9tEQGm2hh",\<br />
qop="auth",charset=utf-8,algorithm=md5-sess<br />
</source><br />
<br />
:步骤 5 (替代): 服务器2 返回一个错误给 服务器1:<br />
<br />
<source lang="xml"><br />
<failure xmlns='urn:ietf:params:xml:ns:xmpp-sasl'><br />
<incorrect-encoding/><br />
</failure><br />
</stream:stream><br />
</source><br />
<br />
:步骤 6: 服务器1 发送一个\[BASE64\]编码的回应这个挑战:<br />
<br />
<source lang="xml"><br />
<response xmlns='urn:ietf:params:xml:ns:xmpp-sasl'><br />
dXNlcm5hbWU9ImV4YW1wbGUub3JnIixyZWFsbT0ic29tZXJlYWxtIixub25j<br />
ZT0iT0E2TUc5dEVRR20yaGgiLGNub25jZT0iT0E2TUhYaDZWcVRyUmsiLG5j<br />
PTAwMDAwMDAxLHFvcD1hdXRoLGRpZ2VzdC11cmk9InhtcHAvZXhhbXBsZS5v<br />
cmciLHJlc3BvbnNlPWQzODhkYWQ5MGQ0YmJkNzYwYTE1MjMyMWYyMTQzYWY3<br />
LGNoYXJzZXQ9dXRmLTgK<br />
</response><br />
</source><br />
<br />
:解码后的应答信息是:<br />
<br />
<source lang="xml"><br />
username="example.org",realm="somerealm",\<br />
nonce="OA6MG9tEQGm2hh",cnonce="OA6MHXh6VqTrRk",\<br />
nc=00000001,qop=auth,digest-uri="xmpp/example.org",\<br />
response=d388dad90d4bbd760a152321f2143af7,charset=utf-8<br />
</source><br />
<br />
:步骤 7: 服务器2 发送另外一个\[BASE64\]编码的挑战给 服务器1:<br />
<br />
<source lang="xml"><br />
<challenge xmlns='urn:ietf:params:xml:ns:xmpp-sasl'><br />
cnNwYXV0aD1lYTQwZjYwMzM1YzQyN2I1NTI3Yjg0ZGJhYmNkZmZmZAo=<br />
</challenge><br />
</source><br />
<br />
:解码后的挑战信息是:<br />
<br />
<source lang="xml"><br />
rspauth=ea40f60335c427b5527b84dbabcdfffd<br />
</source><br />
<br />
:步骤 7 (或者): 服务器2 返回一个错误给 服务器1:<br />
<br />
<source lang="xml"><br />
<failure xmlns='urn:ietf:params:xml:ns:xmpp-sasl'><br />
<invalid-authzid/><br />
</failure><br />
</stream:stream><br />
</source><br />
<br />
:步骤 8: 服务器1 回应挑战:<br />
<br />
<source lang="xml"><br />
<response xmlns='urn:ietf:params:xml:ns:xmpp-sasl'/><br />
</source><br />
<br />
:步骤 8 (或者): 服务器1 中止协商:<br />
<br />
<source lang="xml"><br />
<abort xmlns='urn:ietf:params:xml:ns:xmpp-sasl'/><br />
</source><br />
<br />
:步骤 9: 服务器2 通知 服务器1 验证成功:<br />
<br />
<source lang="xml"><br />
<success xmlns='urn:ietf:params:xml:ns:xmpp-sasl'/><br />
</source><br />
<br />
:步骤 9 (或者): 服务器2 通知 服务器1 验证失败:<br />
<br />
<source lang="xml"><br />
<failure xmlns='urn:ietf:params:xml:ns:xmpp-sasl'><br />
<aborted/><br />
</failure><br />
</stream:stream><br />
</source><br />
<br />
:步骤 10: 服务器1 重新发起一个新的流给 服务器2:<br />
<br />
<source lang="xml"><br />
<stream:stream xmlns='jabber:server' xmlns:stream='http://etherx.jabber.org/streams' to='example.com' version='1.0'><br />
</source><br />
<br />
:步骤 11: 服务器2 发送一个流头信息应答 服务器1 ,并附上任何可用的特性(或一个空的features元素).:<br />
<br />
<source lang="xml"><br />
<stream:stream xmlns='jabber:client' xmlns:stream='http://etherx.jabber.org/streams' from='example.com' id='s2s_345' version='1.0'><br />
<stream:features/><br />
</source><br />
<br />
==资源绑定==<br />
<br />
:在和接收实体完成 SASL 协商(第六章)之后,初始化实体可能(MAY)想要或者需要绑定一个特定的资源到流上.通常这仅适用于客户端: 为了满足本文定义的寻址格式(第三章)和节传输规则(第十章),客户端<node@domain>必须(MUST)拥有一个相关的资源ID(由服务器生成或由客户端程序提供);以确保在流上使用的地址是一个“全JID”(<node@domain/resource>)。<br />
<br />
:接收到一个成功的SASL握手之后,客户端必须(MUST)发送一个新的流头信息给服务器,服务器必须(MUST)返回一个包含可用的流特性列表的头信息。特别是,在成功的SASL握手之后如果服务器需要客户端绑定一个资源,它必须(MUST)在握手成功之后(而不是之前)发送给客户端的应答流特性中包含一个空的符合'urn:ietf:params:xml:ns:xmpp-bind'名字空间的<bind/>元素。:<br />
<br />
:服务器向客户端声明资源绑定特性:<br />
<br />
<source lang="xml"><br />
<stream:stream xmlns='jabber:client' xmlns:stream='http://etherx.jabber.org/streams' id='c2s_345' from='example.com' version='1.0'><br />
<stream:features><br />
<bind xmlns='urn:ietf:params:xml:ns:xmpp-bind'/><br />
</stream:features><br />
</source><br />
<br />
:收到要求资源绑定的通知后,客户端必须(MUST)通过发送一个符合'urn:ietf:params:xml:ns:xmpp-bind'名字空间的“set”类型的IQ节(参见 IQ 语义 (第九章第二节第三小节))给服务器来绑定一个资源到流中。<br />
<br />
:如果客户端端希望允许服务器给自己生成一个资源ID,它可以发送一个包含空的<bind/>元素的“set”类型的IQ节。:<br />
<br />
:客户端请求服务器绑定资源:<br />
<br />
<source lang="xml"><br />
<iq type='set' id='bind_1'><br />
<bind xmlns='urn:ietf:params:xml:ns:xmpp-bind'/><br />
</iq><br />
</source><br />
<br />
:一个支持资源绑定的服务器必须(MUST)自动生成一个资源ID给客户端。一个由服务器生成的资源ID对于那个<node@domain>必须(MUST)是唯一的。<br />
<br />
:如果客户端希望指定资源ID,它发送一个包含期望资源ID的“set”类型的 IQ节,把资源ID作为<bind/>元素下的<resource/>子元素的XML字符数据:<br />
<br />
:客户端绑定一个资源:<br />
<br />
<source lang="xml"><br />
<iq type='set' id='bind_2'><br />
<bind xmlns='urn:ietf:params:xml:ns:xmpp-bind'><br />
<resource>someresource</resource><br />
</bind><br />
</iq><br />
</source><br />
<br />
:一旦服务器为客户端生成了一个资源ID或接受了客户端自己提供的资源ID,它必须(MUST)返回一个“result”类型的 IQ 节给客户端,这个节必须包含一个指明全JID的<jid/>子元素表示服务器决定连接的资源:<br />
<br />
:服务器通知客户端资源绑定成功:<br />
<br />
<source lang="xml"><br />
<iq type='result' id='bind_2'><br />
<bind xmlns='urn:ietf:params:xml:ns:xmpp-bind'><br />
<jid>somenode@example.com/someresource</jid><br />
</bind><br />
</iq><br />
</source><br />
<br />
:一个服务器应该(SHOULD)接受客户端提供的资源ID,但是可以(MAY)用服务器生成的资源ID覆盖它;在这种情况下,服务器不应该(SHOULD NOT)返回一个错误信息一个(如<forbidden/>)给客户端,而应该(SHOULD)在上文所述的 IQ result 中返回生成的资源ID。<br />
<br />
:当一个客户端自行提供资源ID时,可能发生以下的节错误(参见 Stanza Errors (第九章第三节)):<br />
<br />
::- 提供的资源ID服务器无法处理,因为不符合资源字符规范Resourceprep(附录B)。<br />
<br />
::- 客户端不被允许绑定一个资源(如节点或用户已经达到允许连接的资源数限制)。<br />
<br />
::- 提供的资源ID已经被使用但是服务器不允许以同一个资源ID绑定多个连接。<br />
<br />
:协议对这些错误条件规定如下.<br />
<br />
::资源ID不能处理:<br />
<br />
<source lang="xml"><br />
<iq type='error' id='bind_2'><br />
<bind xmlns='urn:ietf:params:xml:ns:xmpp-bind'><br />
<resource>someresource</resource><br />
</bind><br />
<error type='modify'><br />
<bad-request xmlns='urn:ietf:params:xml:ns:xmpp-stanzas'/><br />
</error><br />
</iq><br />
</source><br />
<br />
::客户端不允许绑定一个资源:<br />
<br />
<source lang="xml"><br />
<iq type='error' id='bind_2'><br />
<bind xmlns='urn:ietf:params:xml:ns:xmpp-bind'><br />
<resource>someresource</resource><br />
</bind><br />
<error type='cancel'><br />
<not-allowed xmlns='urn:ietf:params:xml:ns:xmpp-stanzas'/><br />
</error><br />
</iq><br />
</source><br />
<br />
::资源ID已经在使用:<br />
<br />
<source lang="xml"><br />
<iq type='error' id='bind_2'><br />
<bind xmlns='urn:ietf:params:xml:ns:xmpp-bind'><br />
<resource>someresource</resource><br />
</bind><br />
<error type='cancel'><br />
<conflict xmlns='urn:ietf:params:xml:ns:xmpp-stanzas'/><br />
</error><br />
</iq><br />
</source><br />
<br />
:如果,在完成资源绑定步骤之前,客户端试图以符合'urn:ietf:params:xml:ns:xmpp-bind'名字空间的<bind/>子元素发送一个非IQ类型的XML节,服务器不能(MUST NOT)处理这个节,而应该(SHOULD)返回一个<not-authorized/>节错误信息给客户端.<br />
<br />
==服务器回拨==<br />
<br />
===概览===<br />
<br />
:Jabber协议接受的来自XMPP的包括“服务器回拨”方法,用于防治域名欺骗,使得欺骗XML节更为困难。服务器回拨不是一个安全机制,并且它的服务器身份认证结果很弱(参见服务器之间的通信(第十四章第四节)中关于这个方法的安全特性)。需要健壮的安全性的域名应该(SHOULD)使用TLS或SASL;细节参见服务器间的通信(第十四章第四节)。如果SASL用于服务器间通信,回拨就不需要用了(SHOULD NOT)。本文描述回拨的好处在于向后兼容现存的实现和部署。<br />
<br />
:服务器回拨方法由现存的DNS系统的存在而成为可能,因为一个服务器(通常)可以查询给定域的授权服务器。由于服务器回拨依赖于DNS,除非服务器宣称的DNS主机得到解析,域之间的通信无法进行(参见服务器间的通信(第十四章第四节))。<br />
<br />
:服务器回拨是单向性的,可在单一方向上对一个流进行(微弱的)身份验证.因为服务器回拨不是一个验证机制,通过回拨获得相互的认证是不可能的.因此,为了使得服务器之间的双向通信,服务器回拨必须(MUST)在每个方向上完成。<br />
<br />
:在服务器回拨中生成和检验密钥的方法必须(MUST)考虑计算被使用的主机名,由接收服务器生成的流ID,和只有授权服务器网络才知道的秘密。在服务器回拨中流ID是安全性的关键所以必须(MUST)是不可预知的和不可重复的(见\[RANDOM\]中关于使用随机数获得安全性的建议).<br />
<br />
:任何回拨协商过程中发生的错误必须(MUST)被当成一个流错误,并导致流以及相关的TCP连接的终止.可能发生的错误情况协议中描述如下.<br />
<br />
:以下术语适用:<br />
<br />
:* 发起服务器 -- 尝试在两个域之间建立连接的那个服务器.<br />
<br />
:* 接收服务器 -- 尝试验证发起服务期声称的域名的那台服务器.<br />
<br />
:* 授权(权威?Authoritative) 服务器 -- 回答发起服务器声称的DNS主机名的服务器;基本上这应该是那台发起服务器,但是它也可能是一个在发起服务器网络中独立的服务器。<br />
<br />
===事件顺序===<br />
<br />
:以下是回拨中的事件顺序的简介:<br />
<br />
:# 发起服务器和接收服务器建立一个连接。<br />
:# 发起服务器通过到连接发送一个 'key' 值给接收服务期。<br />
:# 接收服务器建立一个连接到授权服务器。<br />
:# 接收服务器发送一个相同的 'key' 值给授权服务器。<br />
:# 授权服务器回答这个key是否合法。<br />
:# 接收服务器通知发起服务器是否被验证通过。<br />
<br />
:我们用用以下图形展示这个事件流程(见附件s2s.png):<br />
<br />
{image:img=s2s}<br />
<br />
发起服务器 接收服务器<br />
----------- ---------<br />
| |<br />
| 建立连接 |<br />
| ----------------------> |<br />
| |<br />
| 发stream头 |<br />
| ----------------------> |<br />
| |<br />
| 发stream头 |<br />
| <---------------------- |<br />
| | <br />
| 发回拨key | 授权服务器<br />
| ----------------------> | -------------<br />
| | |<br />
| 建立连接 |<br />
| ----------------------> |<br />
| |<br />
| 发stream头 |<br />
| ----------------------> |<br />
| |<br />
| 发stream头 |<br />
| <---------------------- |<br />
| |<br />
| 发验证请求 |<br />
| ----------------------> |<br />
| |<br />
| 发验证响应 |<br />
| <---------------------- |<br />
|<br />
| 报告回拨结果 |<br />
| <---------------------- |<br />
| |<br />
<br />
===协议===<br />
<br />
:服务器之间互动的细节协议如下:<br />
<br />
:1. 发起服务器和接受服务器建立TCP连接.<br />
<br />
:2. 发起服务器发送流头信息给接收服务器:<br />
<br />
<source lang="xml"><br />
<stream:stream xmlns:stream='http://etherx.jabber.org/streams' xmlns='jabber:server' xmlns:db='jabber:server:dialback'><br />
</source><br />
<br />
:注意: 'to'和'from'属性在流的根元素是可选的(OPTIONAL). 其中包含的xmlns:db名字空间向接收服务器声明了发起服务器支持回拨. 如果名字空间不正确,接收实体必须(MUST)生成一个<invalid-namespace/>流错误条件并且终止XML流和相应的TCP连接.<br />
<br />
:3. 接收服务器应该(SHOULD)回送一个流头信息给发起服务器,为这次交互生成一个唯一性的ID :<br />
<br />
<source lang="xml"><br />
<stream:stream xmlns:stream='http://etherx.jabber.org/streams' xmlns='jabber:server' xmlns:db='jabber:server:dialback' id='457F9224A0...'><br />
</source><br />
<br />
:注意: 'to'和'from'属性在流的根元素是可选的(OPTIONAL). 如果名字空间不正确,发起服务器必须生成一个<invalid-namespace/>流错误条件并且终止XML流和相应的TCP连接.也要注意,在这里接收服务器应该(SHOULD)应答但是可以(MAY)出于安全策略考虑只是悄悄地终止XML流和TCP连接;无论如何,如果接收服务器希望继续,它必须(MUST)回送一个流头信息给发起服务器.<br />
<br />
:4. 发起服务器发送一个回拨密钥给接收服务器:<br />
<br />
<source lang="xml"><br />
<db:result to='Receiving Server' from='Originating Server'><br />
98AF014EDC0...<br />
</db:result><br />
</source><br />
<br />
:注意: 这个密钥不由接收服务器检查,因为接收服务器在会话之间(between sessions)不保存发起服务器的信息. 这个由发起服务器生成的密钥必须(MUST)是基于接收服务器在上一步骤中提供的ID值,以及发起服务器与授权服务器共享的安全机制生成的。 如果 'to' 地址的值和接收服务器知道的主机名不匹配,接收服务器必须(MUST)生成一个<host-unknown/>流错误条件并且终止XML流和相应的TCP连接. 如果 'from' 地址和接收服务器已经建立的连接的域名相吻合,接收服务器必须(MUST)维护这个已经存在的连接,直到证明这个新的连接是合法的为止;另外,接收实体可以(MAY)选择生成一个<not-authorized/> 流错误条件给这个新的连接并且终止和新连接申请相关的XML流及相应的TCP连接.<br />
<br />
:5. 接收服务器向发起服务器声明的那个域建立一个 TCP 连接,作为结果它连接到授权服务器. (注意: 为了优化性能, 在这里一个实现可以(MAY)重用现有的连接.)<br />
<br />
:6. 接收服务器发送一个流头信息给授权服务器:<br />
<br />
<source lang="xml"><br />
<stream:stream xmlns:stream='http://etherx.jabber.org/streams' xmlns='jabber:server' xmlns:db='jabber:server:dialback'><br />
</source><br />
<br />
:注意: 'to'和'from'属性在流的根元素是可选的(OPTIONAL). 如果名字空间不正确,授权服务器必须生成一个<invalid-namespace/>流错误条件并且终止XML流和相应的TCP连接. <br />
<br />
:7. 授权服务器发送流头信息给接收服务器:<br />
<br />
<source lang="xml"><br />
<stream:stream xmlns:stream='http://etherx.jabber.org/streams' xmlns='jabber:server' xmlns:db='jabber:server:dialback' id='1251A342B...'><br />
</source><br />
<br />
:注意: 如果名字空间不正确,接收服务器必须生成一个<invalid-namespace/>流错误条件并且终止它和授权服务器之间的XML流和相应的TCP连接. 如果一个流错误发生在接收服务器和 '''授权服务器''' 之间,接收服务器必须(MUST)生成一个 <remote-connection-failed/> 流错误条件并且终止它和 '''发起服务器''' 之间的XML流和相应的TCP连接.<br />
<br />
:8. 接收服务器发送一个密钥检查请求给授权服务器:<br />
<br />
<source lang="xml"><br />
<db:verify from='Receiving Server' to='Originating Server' id='457F9224A0...'><br />
98AF014EDC0...<br />
</db:verify><br />
</source><br />
<br />
:注意: 现在这里已经有了主机名,第三步中接收服务器发送给发起服务器的ID,第四步中发起服务器发送给接收服务器的密钥. 基于这些信息, 加上授权服务器网络共享的安全信息, 这个密钥被证实了.任何可用于验证的办法都可以(MAY)用于生成密钥. 如果 'to' 地址的值和授权服务器知道的主机名不匹配,授权服务器必须(MUST)生成一个<host-unknown/>流错误条件并且终止XML流和相应的TCP连接. 打开这个连接时,如果 'from' 地址和接收服务器声明的主机名(或任何合法的域,如验证过的接收服务器的子域名或寄宿在接收服务器上的其他经过验证的域)不符,授权服务器必须(MUST)生成一个<invalid-from/>流错误条件并且终止XML流和相应的TCP连接.<br />
<br />
:9. 授权服务器检查密钥是否合法:<br />
<br />
<source lang="xml"><br />
<db:verify from='Originating Server' to='Receiving Server' type='valid' id='457F9224A0...'/><br />
</source><br />
<br />
::或<br />
<br />
<source lang="xml"><br />
<db:verify from='Originating Server' to='Receiving Server' type='invalid' id='457F9224A0...'/><br />
</source><br />
<br />
:注意: 如果 ID 和第三步中接收服务器提供的不符,接收服务器必须(MUST)生成一个<invalid-id/>流错误条件并且终止XML流和相应的TCP连接. 如果 'to' 地址的值和接收服务器知道的主机名不匹配,接收服务器必须(MUST)生成一个<host-unknown/>流错误条件并且终止XML流和相应的TCP连接. 打开这个连接时,如果 'from' 地址和发起服务器声明的主机名(或任何合法的域,如验证过的发起服务器的子域名或寄宿在发起服务器上的其他经过验证的域)不符,接收服务器必须(MUST)生成一个<invalid-from/>流错误条件并且终止XML流和相应的TCP连接. 在返回验证信息给接收服务器之后,授权服务器应该(SHOULD)终止它们之间的流.<br />
<br />
:10. 接收服务器通知发起服务器结果:<br />
<br />
<source lang="xml"><br />
<db:result from='Receiving Server'to='Originating Server' type='valid'/><br />
</source><br />
<br />
:注意: 在这一个点上, 连接已经由 type='valid' 确认验证是通过了,还是没通过. 如果连接是非法的,接收服务器必须(MUST)终止XML流和相应的TCP连接. 如果连接是合法的, 数据可以从发起服务器发送由接收服务器读取;在此之前,所有发送给接收服务器的XML节应该(SHOULD)被丢弃.<br />
<br />
:进一步的结果是,接收服务器已经验证了发起服务器的ID,所以通过初始化流("initial stream",例如从发起服务器到接收服务器的流)发起服务器可以发送,接收服务器可以接受XML节. 为了使用应答流("response stream",例如从接收服务器到发起服务器的流)验证实体ID,回拨必须(MUST)在相对的两个方向上都完成.<br />
<br />
:在成功的回拨协商之后, 接收服务器应该(SHOULD)接受接下来发起服务器通过当前的合法连接发送的 <db:result/> 包 (例如, 发送给子域或其他寄宿在接收服务器上的主机名的验证请求); 这在单一方向上激活了原始合法连接的 "piggybacking" .<br />
<br />
:即使回拨协商成功了, 服务器仍然必须(MUST)检查从其他服务器接收的所有XML节的'from'和'to'属性; 如果一个节不符合这些限定, 收到这些节的服务器必须(MUST)生成一个<improper-addressing/> 流错误条件并终止XML流和相应的TCP连接. 而且, 一个服务器也必须(MUST)检查从其他的有合法域名的服务器的流中收到的节的'from'属性; 如果一个节不符合这一限定, 接收节的服务器必须(MUST)生成一个 <invalid-from/> 流错误条件并终止XML流和相应的TCP连接. 所有这些检查都用来帮助防止特定的节伪造行为.<br />
<br />
==XML节==<br />
<br />
:在 TLS 协商(第五章) (如果想要), SASL 协商(第六章), 和资源绑定(第七章)(如果需要)之后, XML节就可以通过流发送了. 在'jabber:client'和'jabber:server'名字空间中定义了三种XML节: <message/>, <presence/>, 和 <iq/>. 另外, 这三种节有五种通用的属性. 这些通用属性, 加上三种节的术语,在这里定义; 更多关于和即时消息及出席信息应用相关的XML节语法详细信息在[XMPP-IM|XMPP文档列表/XMPP正式RFC标准/RFC3921]中提供.<br />
<br />
===通用属性===<br />
<br />
:以下五种属性通用于 message, presence, 和 IQ 节:<br />
<br />
====to====<br />
<br />
:'to' 属性表示节的预期接收者的JID.<br />
<br />
:在'jabber:client'名字空间中, 一个节应该(SHOULD)处理一个'to'属性, 尽管由服务器处理的从客户端发给服务器的节(如, 发送给服务器用于广播给其他实体的出席信息) 应该不(SHOULD NOT)处理'to'属性.<br />
<br />
:在'jabber:server'名字空间中, 一个节必须(MUST)处理一个'to'属性; 如果一个服务器收到一个不符合此限定的节, 它必须(MUST)生成一个<improper-addressing/>流错误条件并终止和这个非法服务器的XML流和相应的TCP连接.<br />
<br />
:如果'to'属性的值非法或无法联络, 发现这个事实的实体(通常是发送者或接收者的服务器)必须(MUST)返回一个适当的错误给发送者, 错误节的'from'属性设置成非法节的提供的'to'属性的值.<br />
<br />
====from====<br />
<br />
:'from' 属性表示发送者的 JID .<br />
<br />
:当一个服务器接收了一个符合'jabber:client'名字空间的合法流的XML节, 它必须(MUST)做以下步骤中的一步:<br />
<br />
:# 验证客户端提供的'from'属性值就是那个相关实体连接的资源<br />
:# 为生成这个节的已连接的资源增加一个'from'地址(由服务器决定是纯JID或全JID)(参见 地址的决定 Determination of Addresses (第三章第五节))<br />
:# 如果一个客户端试图发送一个XML节,而它的'from'属性和这个实体已连接的资源不符, 服务器应该(SHOULD)返回一个<invalid-from/>流错误条件给客户端. 如果一个客户端试图通过一个尚未验证的流发送一个XML节, 服务器应该(SHOULD)返回一个<not-authorized/>流错误条件给客户端. 如果生成了, 所有这些条件必须(MUST)导致流的关闭和相应的TCP连接的终止; 这有助于防止不诚实的客户的拒绝服务攻击.<br />
<br />
:当一个服务器从服务器自身生成一个节用于一个已连接的客户端的信息发布(例如, 在服务器为客户端提供数据存储服务的情况下), 这个节必须(MUST) (1) 不包含 'from' 属性 或 (2) 包含一个'from'属性,它的值是这个账号的纯 JID (<node@domain>) 或 客户端的全 JID (<node@domain/resource>). 如果节不是由服务器自身生成的,那么一个服务器不能(MUST NOT)发送不带'from'属性的节. 当一个客户端接收到一个不包含'from'属性的节, 它必须(MUST)认为这个节是从客户端连接的服务器发来的.<br />
<br />
:在'jabber:server'名字空间, 一个节必须(MUST)处理一个'from'属性; 如果一个服务器接收到一个不符合此限定的节, 它必须(MUST)生成一个<improper-addressing/>流错误条件. 而且, 'from'属性的 JID值的域名ID部分必须(MUST)和以SASL协商连接或以回拨协商连接的发送服务器的主机名(或任何合法的域,如发送服务器主机名的合法子域,或其他寄宿在发送服务器上的合法域)吻合; 如果一个服务器接收到的节不符合此限定, 它必须(MUST)生成一个<invalid-from/>流错误条件. 所有这些条件都必须(MUST)导致流的关闭和相应的TCP连接的终止; 这有助于防止不诚实的客户端发起的拒绝服务攻击.<br />
<br />
====id====<br />
<br />
:可选的'id' 属性可以(MAY)用于为节的内部跟踪发送实体,从IQ节 语义来讲,就是通过发送和接收这些节来跟踪“请求-应答”型的交互行为。这个可选的(OPTIONAL)'id'属性值在一个域或一个流中是全局唯一的。IQ节语义学中对此有附加限定;见IQ Semantics (第九章第二节第三小节)。<br />
<br />
====type====<br />
<br />
:'type' 属性指明消息、出席信息或IQ节的意图或上下文的详细信息。'type'属性所允许的值依据节的类型是消息、出席信息还是IQ而有很大不同; 用于消息和出席信息节的值定义在即时消息和出席信息应用中,所以在[XMPP-IM|XMPP文档列表/XMPP正式RFC标准/RFC3921]中定义,反之用于IQ节的值定义了在一个 请求\-应答 的“会话”中IQ节的角色,所以定义在IQ语义学中(第九章第二节第三小节)。 所有三种节的通用'type'值是"error";见Stanza Errors (第九章第三节)。<br />
<br />
====xml:lang====<br />
<br />
:如果一个节包含用于显示给人human user看的XML字符数据(在RFC 2277中有所解释\[CHARSET\],"internationalization is for humans"),这个节应该(SHOULD)处理一个'xml:lang'属性(定义在第二章第十二节\[XML\])。 'xml:lang'属性的值指明任何一个人类可读的XML字符数据的缺省语言, 它可以(MAY)被特定的子元素的'xml:lang'值重载。 如果一个节不处理一个'xml:lang'属性,一个实现必须(MUST)认为缺省的语言就是流属性中定义的语言(第四章第四节). 'xml:lang'属性值必须(MUST)是一个 NMTOKEN 并且必须(MUST)遵守 RFC 3066 \[LANGTAGS\]中定义的格式. <br />
<br />
===基本语义学===<br />
<br />
====消息语义学====<br />
<br />
:<message/>节类型可以被看作是一个"push"机制用于一个实体推送信息给另一个实体,类似发生在email系统中的通信. 所有消息节应该(SHOULD)处理一个表明预定的消息接收者的'to'属性;接收了这样一个节之后,一个服务器应该(SHOULD)路由或递送它给预定的接收者(见 Server Rules for Handling XML Stanzas (第十章)的XML节相关的通用路由和递送规则).<br />
<br />
====出席信息语义学====<br />
<br />
:<presence/> 元素可以被看作一个基本的广播或“出版-订阅”机制,用于多个实体接收某个已订阅的实体的信息(在这里,是网络可用性信息). 通常,一个发行实体应该(SHOULD)不带'to'属性发送一个出席信息,这时这个实体所连接的服务器应该(SHOULD)广播或多播(multiplex?)那个节给所有订阅的实体.无论如何,一个发行实体也可以(MAY)带'to'属性发送一个出席信息节,这时服务器应该(SHOULD)路由或递送这个节给预定的接收者.见 Server Rules for Handling XML Stanzas (第十章)的XML节相关的通用路由和递送规则,以及[XMPP-IM|XMPP文档列表/XMPP正式RFC标准/RFC3921]中即时消息和出席信息应用中出席信息的特定规则.<br />
<br />
====IQ语义学====<br />
<br />
:信息/查询(Info/Query),或曰IQ,是一个 请求-回应 机制,某些情况下类似\[HTTP\].IQ语义学使一个实体能够向另一个实体做出请求并做出应答. 请求和应答所包含的数据定义在IQ元素的一个直接的子元素的名字空间声明中, 并且由请求实体用'id'属性来跟踪这一交互行为. 因而,IQ交互伴随着一个结构化的数据交换的通用模式例如 get/result 或 set/result (尽管有时候会以一个错误信息应答某个请求):<br />
<br />
:以下是IQ的流程图,参见附件iq.png<br />
<br />
{image:img=iq}<br />
<br />
:为了强制执行这些语义学,要应用以下规则:<br />
<br />
:1. 对于IQ节来说'id'属性是必需的(REQUIRED).<br />
:2. 对于IQ节来说'type'属性是必需的(REQUIRED). 它的值必须(MUST)是以下之一:<br />
::* get -- 这个节是一个对信息或需求的请求.<br />
::* set -- 这个节提供需要的数据, 设置新的值, 或取代现有的值.<br />
::* result -- 这个节是一个对一个成功的 get 或 set 请求的应答.<br />
::* error -- 发生了一个错误,关于处理或递送上次发送的 get 或 set的(参见 节错误 Stanza Errors(第九章第三节)).<br />
:3. 一个接收到"get" 或 "set" 类型的IQ请求的实体必须(MUST)回复一个"result"或"error"类型的IQ应答(这个应答必须(MUST)保留相关请求的'id'属性).<br />
:4. 一个接收到"result"或"error"类型的IQ节的实体不能(MUST NOT)再发送更多的"result"或"error"类型的IQ应答; 无论如何, 如上所述, 请求实体可以(MAY)发送另一个请求(如, 一个"set"类型的IQ,通过get/result对提供查询(discovery)所需的信息).<br />
:5. 一个"get" 或 "set" 类型的IQ节必须(MUST)包含并只包含一个子元素指明特定请求或应答的语义.<br />
:6. 一个"result"类型的IQ节必须(MUST)包含零或一个子元素.<br />
:7. 一个"error"类型的IQ节应该(SHOULD)包含和"get"或"set"相关联的那个子元素并且必须(MUST)包含一个<error/>子元素;详细信息,见Stanza Errors (第九章第三节).<br />
<br />
===节错误===<br />
<br />
:节相关的错误的处理方式类似流错误(第四章第七节). 无论如何, 不像流错误, 节错误是可恢复的;所以错误节包含了暗示原来的发送者可以采取什么行动来补救这个错误.<br />
<br />
====规则====<br />
<br />
:以下规则适用于节相关的错误:<br />
<br />
:* 接收或处理实体察觉到一个节相关的错误条件时应该(MUST)返回给发送实体一个同类型的节(消息,出席信息,或IQ),这个节的'type'属性值则设置为"error"(这里这样的节称之为"error stanza").<br />
<br />
:* 生成一个错误节的实体应该(SHOULD)包含原来发送的XML,这样发送者可以检查它,并且如果必要,在尝试重新发送之前纠正它.<br />
<br />
:* 一个错误节必须(MUST)包含一个<error/>子元素.<br />
<br />
:* 如果'type'属性值不是"error"(或没有"type"属性),节不能(MUST NOT)包含一个<error/>子元素.<br />
<br />
:* 接收到一个错误节的实体不能(MUST NOT)应答这个节更多的错误节; 这有助于防止死循环.<br />
<br />
====语法====<br />
<br />
:节相关错误的语法如下:<br />
<br />
<source lang="xml"><br />
<stanza-kind to='sender' type='error'><br />
[RECOMMENDED to include sender XML here]<br />
<error type='error-type'><br />
<defined-condition xmlns='urn:ietf:params:xml:ns:xmpp-stanzas'/><br />
<text xmlns='urn:ietf:params:xml:ns:xmpp-stanzas' xml:lang='langcode'><br />
OPTIONAL descriptive text<br />
</text><br />
[OPTIONAL application-specific condition element]<br />
</error><br />
</stanza-kind><br />
</source><br />
<br />
:stanza-kind 是 message, presence, 或 iq 中的一个.<br />
<br />
:<error/> 元素的'type'属性值必须(MUST)是以下之一:<br />
<br />
:* cancel \-\- 不重试(这个错误是不可恢复的)<br />
<br />
:* continue \-\- 继续进行(这个条件只是一个警告)<br />
<br />
:* modify \-\- 改变数据之后重试<br />
<br />
:* auth \-\- 提供证书之后重试<br />
<br />
:* wait \-\- 等待之后重试(错误是暂时的)<br />
<br />
:<error/>元素:<br />
<br />
:* 必须(MUST)包含一个子元素,符合以下定义的节错误条件之一;这个元素(MUST)符合'urn:ietf:params:xml:ns:xmpp-stanzas'名字空间.<br />
<br />
:* 可以(MAY)包含一个<text/>子元素容纳XML字符数据用来描述错误的更多细节;这个元素必须(MUST)符合'urn:ietf:params:xml:ns:xmpp-stanzas'名字空间并且应该(SHOULD)处理'xml:lang'属性.<br />
<br />
:* 可以(MAY)包含一个应用程序定义的错误条件子元素;这个元素必须(MUST)符合一个应用程序定义的名字空间,并且它的结构由这个名字空间定义.<br />
<br />
:<text/>元素是可选的(OPTIONAL).如果包含它,它应该(SHOULD)仅用于提供描述或诊断信息以补充一个已定义的条件或应用程序定义的条件. 它不应(SHOULD NOT)被应用程序认为是一个程序性的. 它不应(SHOULD NOT)被用作向一个使用者展示的错误信息,但是可以(MAY)展示除条件元素(或元素们)相关的错误信息之外的信息.<br />
<br />
:最后,为了维护向后兼容性, 这个schema (定义在[XMPP-IM|XMPP文档列表/XMPP正式RFC标准/RFC3921])允许可选的在<error/>元素中包含一个("code")属性.<br />
<br />
====已定义的条件====<br />
<br />
:以下条件定义用于节错误.<br />
<br />
:* <bad-request/> -- 发送者发送的XML是不规范的或不能被处理(例如 一个IQ节包含了一个未被承认的'type'属性值); 相关的错误类型应该(SHOULD)是"modify".<br />
<br />
:* <conflict/> -- 不同意访问,因为相同的名字或地址已存在一个资源或会话;相关的错误类型应该( SHOULD)是"cancel".<br />
<br />
:* <feature-not-implemented/> -- 请求的特性未被接收者或服务器实现所以不能处理;相关的错误类型应该(SHOULD)是"cancel".<br />
<br />
:* <forbidden/> -- 请求实体没有必需的许可来执行这一动作;相关的错误类型应该(SHOULD)是"auth".<br />
<br />
:* <gone/> -- 接收者或服务器无法再以这个地址进行联系(错误节可以(MAY)在<gone/>元素的XML字符数据中包含一个新的地址);相关的错误类型应该(SHOULD)是"modify".<br />
<br />
:* <internal-server-error/> -- 服务器不能处理节,因为错误的配置或其他未定义的内部服务器错误;相关的错误类型应该(SHOULD)是"wait".<br />
<br />
:* <item-not-found/> -- JID地址或申请的条目无法找到;相关的错误类型应该(SHOULD)是"cancel".<br />
<br />
:* <jid-malformed/> -- 发送的实体提供的XMPP地址或与之通信的某个XMPP地址(如一个'to'属性值)或这个XMPP地址中的一部分(如一个资源ID)不符合寻址方案的语法(第三章);相关的错误类型应该(SHOULD)是"modify".<br />
<br />
:* <not-acceptable/> -- 接收者或服务器理解这个请求但是拒绝处理,因为它不符合某些接收者或服务器定义的标准(例如,一个关于消息中可接收的单词的本地策略);相关错误类型应该(SHOULD)是"modify".<br />
<br />
:* <not-allowed/> -- 接收者或服务器不允许任何实体执行这个动作;相关错误类型应该(SHOULD)是"cancel".<br />
<br />
:* <not-authorized/> -- 在被允许执行某个动作之前发送者必须提供适当的证书,或已提供了不正确的证书;相关错误类型应该(SHOULD)是"auth".<br />
<br />
:* <payment-required/> -- 请求实体未被授权访问请求的服务,因为需要付费;相关错误类型应该(SHOULD)是"auth".<br />
<br />
:* <recipient-unavailable/> -- 预定的接收者暂时不可用;相关错误类型应该(SHOULD)是"wait"(注意: 如果这样做会导致泄露预定接收者的网络可用性给一个未被授权了解此信息的实体,应用程序不应该(MUST NOT)返回这个错误).<br />
<br />
:* <redirect/> -- 接收者或服务器重定向这个请求信息到另一个实体,通常是暂时的(这个错误节应该 (SHOULD)在<redirect/>元素的XML字符数据中包含一个预备的地址,它必须(MUST)是一个合法的JID); 相关的错误类型应该(SHOULD)是"modify".<br />
<br />
:* <registration-required/> -- 请求实体未被授权访问请求的服务,因为需要注册;相关错误类型应该(SHOULD)是"auth".<br />
<br />
:* <remote-server-not-found/> -- 在预定的接收者的全部或部分JID中的一个远程服务器或服务不存在;相关错误类型应该(SHOULD)是"cancel".<br />
<br />
:* <remote-server-timeout/> -- 在预定的接收者(或需要完成的一个申请)的全部或部分JID中的一个远程服务器或服务无法在合理的时间内联系到;相关错误类型应该(SHOULD)是"wait".<br />
<br />
:* <resource-constraint/> -- 服务器或接收者缺乏足够的系统资源来服务请求;相关错误类型应该(SHOULD)是"wait".<br />
<br />
:* <service-unavailable/> -- 服务器或接收者目前无法提供被请求的服务;相关错误类型应该(SHOULD)是"cancel".<br />
<br />
:* <subscription-required/> -- 请求实体未被授权访问能请求的服务,因为需要订阅;相关错误类型应该(SHOULD)是"auth".<br />
<br />
:* <undefined-condition/> -- 错误条件不是本列表中定于的其他条件之一;任何错误类型可能和这个条件有关,并且它应该(SHOULD)仅用于关联一个应用程序定义的条件.<br />
<br />
:* <unexpected-request/> -- 接收者或服务器理解这个请求但是不希望是在这个时间(比如,请求的顺序颠倒);相关错误类型应该(SHOULD)是"wait".<br />
<br />
====应用程序定义条件====<br />
<br />
:大家知道,一个应用程序可以(MAY)通过在错误元素里包含一个适当名字空间的字元素来提供应用程序定义的节错误信息. 应用程序定义的元素应该(SHOULD)补充或进一步限定一个已定义的元素. 因而,<error/>元素将包含两个或三个子元素:<br />
<br />
<source lang="xml"><br />
<iq type='error' id='some-id'><br />
<error type='modify'><br />
<bad-request xmlns='urn:ietf:params:xml:ns:xmpp-stanzas'/><br />
<too-many-parameters xmlns='application-ns'/><br />
</error><br />
</iq><br />
<message type='error' id='another-id'><br />
<error type='modify'><br />
<undefined-condition xmlns='urn:ietf:params:xml:ns:xmpp-stanzas'/><br />
<text xml:lang='en' xmlns='urn:ietf:params:xml:ns:xmpp-stanzas'><br />
Some special application diagnostic information...<br />
</text><br />
<special-application-condition xmlns='application-ns'/><br />
</error><br />
</message><br />
</source><br />
<br />
==服务器处理XML节的规则==<br />
<br />
:兼容的服务器实现必须(MUST)确保两个实体之间的XML节按次序处理.<br />
<br />
:在按次序处理的需求之外, 每个服务器实现将包含它自己的递送树"delivery tree"以处理它接收到的节.这个树决定一个节是否需要路由到其他域, 在内部处理, 还是递送到和一个已连接的节点相关的资源. 以下规则适用:<br />
<br />
===没有'to'地址===<br />
<br />
:如果这个节没有'to'属性, 服务器应该(SHOULD)为发送它的实体处理这个节. 因为所有从其他服务器收到的节必须(MUST)拥有'to'属性, 这个规则仅适用于从一个连接到这台服务器的已注册实体(如一个客户端)收到的节.如果这个服务器收到一个没有'to'属性的出席信息节, 服务器应该(SHOULD)向那些订阅了这个发送实体的出席信息的所有实体广播它, 如果可能的话(即时消息和出席信息应用程序中出席信息广播的语义定义在[XMPP-IM|XMPP文档列表/XMPP正式RFC标准/RFC3921]). 如果服务器接收到一个类型为"get" 或 "set" 的没有'to'属性的节并且它理解这个节的名字空间下的内容, 它必须(MUST)为这个发送实体处理节(在这里"process"的含义是由相关的名字空间的语义所决定的)或返回一个错误给发送实体.<br />
<br />
===外部域===<br />
<br />
:如果'to'属性中的JID的域ID部分的主机名和服务器自身或其子域配置的主机名不匹配, 服务器应该(SHOULD)路由这个节到外部域(取决于本地服务规定或安全策略关于域间通信的规定).有两种可能的情况:<br />
<br />
::- 一个服务器之间的流已经存在于两个域之间: 发送者的服务器通过这个已存在的流为这个外部域路由这个节到授权服务器<br />
<br />
::- 两个域之间不存在服务器间的流: 发送者服务器 (1) 解析这个外部域的主机名(定义在服务器间的通信Server-to-Server Communications (第十四章第四节)), (2) 在两个域之间进行服务器到服务器的流协商(定义在 Use of TLS (第五章) 和 Use of SASL (第六章)), 然后 (3) 通过这个新建的流为外部域路由这个节到授权服务器<br />
<br />
:如果路由到接收者的服务器不成功, 发送者的服务器必须(MUST)返回一个错误给发送者; 如果接收者的服务器联系上了但是从接收者的服务器递送到接收者不成功, 接收者服务器必须(MUST)通过发送者的服务器返回一个错误给发送者.<br />
<br />
===子域===<br />
<br />
:如果'to'属性中的JID的域ID部分的主机名和服务器自身配置的主机名的一个子域名匹配,服务器必须(MUST)自己处理这个节或路由这个节到专门负责这个子域的特定服务(如果子域被配置了),或者返回一个错误给发送者(如果子域没有配置).<br />
<br />
===纯粹的域或特定的资源===<br />
<br />
:如果'to'属性中的JID的域ID部分的主机名和服务器自身配置的主机名本身匹配,并且'to'属性中的JID类型是<domain> 或 <domain/resource>, 服务器(或其中定于的资源)必须(MUST)根据节的类型适当的处理这个节或返回一个错误节给发送者.<br />
<br />
===同一域中的节点===<br />
<br />
:如果'to'属性中的JID的域ID部分的主机名和服务器自身配置的主机名本身匹配,并且'to'属性中的JID类型是<node@domain> 或 <node@domain/resource>, 服务器应该(SHOULD)递送这个节到节的'to'属性中的JID所指明的预定的接收者. 以下规则适用:<br />
<br />
:# 如果这个JID包含一个资源ID(例如, 格式是<node@domain/resource>)并且存在一个连接的资源符合这个全JID, 接收者服务器应该(SHOULD)递送这个节给正确符合这个资源ID的流或会话.<br />
:# 如果这个JID包含一个资源ID(例如, 格式是<node@domain/resource>)并且不存在一个连接的资源符合这个全JID, 接收者服务器应该(SHOULD)返回一个<service-unavailable/> 节错误给发送者.<br />
:# 如果这个JID的格式是<node@domain>并且存在至少一个此节点的连接资源, 接收服务器应该( SHOULD)递送这个节给至少其中一个已连接的资源, 依据应用程序定义的规则(一系列即时消息和出席信息应用程序的递送规则定义在[XMPP-IM|XMPP文档列表/XMPP正式RFC标准/RFC3921]).<br />
<br />
==XMPP中的XML用法==<br />
<br />
===限制===<br />
<br />
:XMPP是一个简单的流式XML元素的专用协议用于接近实时地交换结构化信息. 因为XMPP不需要任意的解析和所有的XML文档, 所以XMPP不需要支持\[XML\]的所有功能. 特殊的, 适用以下限制.<br />
<br />
:关于XML生成, 一个XMPP实现不能(MUST NOT)在XML流中注入以下任何东西:<br />
<br />
:* 注释 (第二章第五节[XML])<br />
<br />
:* 处理指示(第二章第六节 同上)<br />
<br />
:* 内部或外部的 DTD 子集 (第二章第八节 同上)<br />
<br />
:* 内部或外部的实体参考 (第四章第二节 同上) 除了预定实体以外(第四章第六节 同上)<br />
<br />
:* 字符数据或属性值包含和预定实体列表中吻合的未逃逸的unescaped字符(第四章第六节 同上); 这些字符必须(MUST)逃逸<br />
<br />
:关于XML处理, 如果一个XMPP实现接收到这些受限的XML数据,它必须(MUST)忽略这些数据.<br />
<br />
===XML 名字空间的名字和前缀===<br />
<br />
:XML名字空间\[XML-NAMES\]为所有XMPP兼容的XML建立数据所有权的严格界限. 这个名字空间的基本功能是把结构上混合在一起的XML元素区分出不同的词汇. 确保XMPP兼容的XML有名字空间的感知能力使得任何允许的XML可以被结构化的混合到任何XMPP数据元素中. XML名字空间的名字和前缀的规则在下一小节中.<br />
<br />
====流名字空间====<br />
<br />
:在所有的XML流头中必须声明一个流名字空间. 流名字空间必须(MUST)是 'http://etherx.jabber.org/streams'. 元素名<stream/>和它的<features/>和<error/>子元素必须(MUST)在所有实例中符合这个流名字空间前缀. 一个实现应该(SHOULD)只为这些元素生成'stream:'前缀, 并且由于历史原因可以(MAY)只接受'stream:'前缀.<br />
<br />
====缺省名字空间====<br />
<br />
:在所有的XML流中必须声明一个缺省的流名字空间用于定义允许的流根元素的一级子元素. 这个名字空间声明对于初始化流和应答流必须(MUST)是相同的使得双方的流都是合格一致的. 缺省的名字空间声明适用于流和所有在流中发送的节(除非由流名字空间或回拨名字空间的前缀显式的符合另一个名字空间).<br />
<br />
:一个服务器实现必须(MUST)支持以下两个缺省名字空间(由于历史原因, 一些实现可能(MAY)只支持这两个缺省名字空间):<br />
<br />
:* jabber:client -- 当流用于客户端和服务器的通信时声明这个缺省名字空间<br />
<br />
:* jabber:server -- 当流用于两个服务器间的通信时声明这个缺省名字空间<br />
<br />
:一个客户端实现必须(MUST)支持'jabber:client'缺省名字空间,并且由于历史原因可以(MAY)只支持这个缺省名字空间.<br />
<br />
:如果缺省名字空间是'jabber:client'或'jabber:server',一个实施不能(MUST NOT)在这个名字空间下为元素生成名字空间前缀. 一个实现不应该(SHOULD NOT)按照元素的内容(可能和流相反)生成不同于'jabber:client'和'jabber:server'名字空间前缀.<br />
<br />
:注意: 'jabber:client' 和 'jabber:server' 名字空间接近于相同但是用于不同的上下文(客户端服务器通信用'jabber:client' 而服务器间通信用'jabber:server'). 这两者之间仅有的不同在于在'jabber:client'中被发送的节中'to'和'from'属性是可选的(OPTIONAL),而在'jabber:server'中被发送的节中它们是必需的(REQUIRED). 如果兼容的实施接受一个符合'jabber:client'或'jabber:server'名字空间的流, 它必须(MUST)支持通用属性(第九章第一节)和三个核心节类型(message, presence, 和IQ)的基本语义(第九章第二节).<br />
<br />
====回拨名字空间====<br />
<br />
:所有用于服务器回拨的(第八章)元素都必须声明一个回拨名字空间. 回拨名字空间的名字必须(MUST)是'jabber:server:dialback'. 所有符合此名字空间的元素必须(MUST)有前缀. 一个实现应该(SHOULD)只为这些元素生成'db:'前缀并且只可以(MAY)接受'db:'前缀.<br />
<br />
===确认===<br />
<br />
:除了注意'jabber:server'名字空间中关于节中'to'和'from'地址的规定,一个服务器不需要为转发到客户端或其他服务器负责检查XML元素;一个实现可以(MAY)选择仅提供有效数据元素但这是可选的(OPTIONAL)(尽管一个实现不能(MUST NOT)接受不规范的XML). 客户端不应该(SHOULD NOT)滥用发送不符合schema的数据的能力, 并且应该(SHOULD)忽略接收到的XML流中任何和schema不一致的元素或属性值. XML流和节的有效性确认是可选的(OPTIONAL),并且在这里提到的schemas仅用于描述的用途.<br />
<br />
===文本声明的包含===<br />
<br />
:实现应该(SHOULD)在发送一个流头信息之前发送一个文本声明. 应用程序必须(MUST)遵守\[XML\]中关于环境(那里对文本声明做了规定)的规则.<br />
<br />
===字符编码===<br />
<br />
:实现必须(MUST)支持通用字符集Universal Character Set (ISO/IEC 10646-1 \[UCS2\])字符到UTF\-8(RFC 3629 \[UTF\-8\])的转换, 必须符合 RFC 2277 \[CHARSET\]. 实现不能(MUST NOT)试图使用任何其他的编码.<br />
<br />
==核心的兼容性要求==<br />
<br />
:本章总结了可扩展的消息和出席信息协议中的某些方面,为了实施的兼容性,它们必须(MUST)被服务器和客户端支持,当然协议的其他方面也应该(SHOULD)被支持. 为了兼容的目的, 我们在核心协议(它必须(MUST)被任何服务器或客户端支持, 无论是什么特定的应用)和即时消息协议(仅仅是在核心协议之上的即时消息和出席信息应用必须(MUST)支持它)之间划了一个级别. 在本章中定义了所有服务器和客户端的兼容性要求; 即时消息服务器和客户端的兼容性要求在[XMPP-IM|XMPP文档列表/XMPP正式RFC标准/RFC3921]的相关章节中定义.<br />
<br />
===服务器===<br />
<br />
:除了所有已定义的关于安全, XML使用, 和国际化的要求之外, 一个服务器还必须(MUST)支持以下核心协议以保证兼容性:<br />
<br />
:* 在地址中应用\[STRINGPREP\] 的 \[NAMEPREP\], Nodeprep (附录 A),和 Resourceprep (附录 B) profiles (包括确保域ID是\[IDNA\]中定义的国际化域名)<br />
<br />
:* XML流(第四章), 包括Use of TLS(第五章), Use of SASL(第六章), 和Resource Binding (第七章)<br />
<br />
:* 三个在stanza semantics(第九章第二节)中已定义的节类型(即,<message/>, <presence/>, 和<iq/>)的基本语义<br />
<br />
:* 生成错误的语法及相关的流, TLS, SASL, 和 XML节的语义<br />
<br />
:另外, 一个服务器可以(MAY)支持以下核心协议:<br />
<br />
:* 服务器回拨 (第八章)<br />
<br />
===客户端===<br />
<br />
:一个客户端必须(MUST)支持以下核心协议以满足兼容性:<br />
<br />
:* XML流(第四章), 包括Use of TLS(第五章), Use of SASL(第六章), 和Resource Binding (第七章)<br />
<br />
:* 三个在stanza semantics(第九章第二节)中已定义的节类型(即,<message/>, <presence/>, 和<iq/>)的基本语义<br />
<br />
:* 处理(并且, 如果可能, 生成) 错误的语法及相关的流, TLS, SASL, 和 XML节的语义<br />
<br />
:另外, 一个客户端应该(SHOULD)支持以下核心协议:<br />
<br />
:* 地址的生成应用\[STRINGPREP\] 的 \[NAMEPREP\], Nodeprep (附录 A),和 Resourceprep (附录 B) profiles <br />
<br />
==国际化事项==<br />
<br />
:XML流在Character Encoding(第十一章第五节)中定义为必须(MUST)被编码成UTF\-8. 在Stream Attributes(第四章第四节)中特别定义了, 一个XML流应该(SHOULD)包含一个'xml:lang'属性,它被认为是通过这个用于人类用户解读的流发送的任何XML字符数据的缺省语言. 在 xml:lang (第九章第一节第五小节)特别定义了, 如果一个XML节是用来给人类用户解读,这个节应该(SHOULD)包含一个'xml:lang'属性. 服务器在为连接的实体路由或递送节的时候应该(SHOULD)应用缺省的'xml:lang'属性, 并且不能(MUST NOT)修改或删除它从其他实体收到的节的'xml:lang'属性.<br />
<br />
==安全性事项==<br />
<br />
===高安全性===<br />
<br />
:为了XMPP通信的目的(客户端-服务器 和 服务器-服务器), "高安全性"条款谈的是相互验证和完整性检查安全性技术的使用; 特别是, 当使用基于证书的验证来提供高安全性, 应该( SHOULD)建立一个带外的信任链,尽管一个共享签名证书可能允许以前不知道的证书在带内建立信任关系. 参见以下第十四章第二节关于证书确认程序.<br />
<br />
:实施必须(MUST)支持高安全性. 服务提供者应该(SHOULD)基于本地安全策略使用高安全性.<br />
<br />
===证书确认===<br />
<br />
:当一个XMPP点和另一个XMPP点安全的地通信, 它必须(MUST)确认对方终端的证书.有三种可能的情况:<br />
<br />
:情形 #1: 点包含一个终端实体证书,以根证书的证书链中一环出现(见\[X509\]中的第六章第一节).<br />
<br />
:情形 #2: 点的证书由一个对方不知道的证书授权.<br />
<br />
:情形 #3: 点的证书由自己签名.<br />
<br />
:在情形#1, 确认方必须(MUST)做以下两条之一:<br />
<br />
:# 根据\[X509\]的规则确认对方证书.然后证书应该(SHOULD)被对方接下来在\[HTTP-TLS\]中描述的规则反向确认预期的身份。但如果"xmpp"是subjectAltName扩展类型,则必须(MUST)使用证书中的显示的身份。如果这两项检查之一失败,用户导向的客户端必须(MUST)通知用户(客户端可以(MAY)给用户机会继续连接)或以一个坏证书的错误终止连接。自动客户端应该(SHOULD)终止连接(以一个坏证书错误)并在适当的日志中记录这个错误。自动客户端可以(MAY)提供一个配置设置成禁止检查,但同时必须(MUST)提供一个激活检查的配置。<br />
:# 点应该(SHOULD)出示证书给一个用户用于批准,包括完整的证书链.点必须(MUST)缓存这个证书(或一些其他不会忘记的表达方式比如一个哈希值).在将来的连接中,点必须(MUST)展示相同的证书并且如果改变了证书必须(MUST)通知用户.<br />
<br />
:在情形#2 和情形#3, 实现应该(SHOULD)执行上述第二条.<br />
<br />
===客户端-服务器通信===<br />
<br />
:一个兼容的客户端实现必须(MUST)支持TLS和SASL用于连接到服务器.<br />
<br />
:用于加密XML流的TLS协议(在 Use of TLS(第五章)定义)提供可信的机制帮助确保机密性和实体之间数据交换的完整性.<br />
<br />
:用于验证XML流的SASL协议(在 Use of SASL(第六章)定义)提供可靠的机制用于确认一个连接到服务器的客户端确实是它自己所声明的那个客户端.<br />
<br />
:服务器宣称的DNS主机名被解析之前,客户端-服务器通信不能(MUST NOT)继续进行。应该首先尝试解析\[SRV\]记录,其服务名为"xmpp-client",协议名为"tcp",整个资源记录类似"_xmpp-client._tcp.example.com."(使用字符"xmpp-client"表示服务ID是经过IANA注册).如果SRV查找失败,退而求其次,将查找一个正规的IPv4/IPv6地址记录来决定IP地址,使用"xmpp-client"端口5222,这个端口是在IANA注册了的。<br />
<br />
:客户端的IP地址和访问方法不能(MUST NOT)被服务器公开, 也不能被被任何原始服务器之外的服务器索取。这帮助保护客户端的服务器避免受到直接攻击(译者注:似乎应该是客户避免受到直接攻击,但原文如此)或被第三方知道它的身份。<br />
<br />
===服务器-服务器通信===<br />
<br />
:一个兼容的服务器实现必须(MUST)支持TLS和SASL,用于域间的通信.因为历史原因,一个兼容的实施也应该(SHOULD)支持服务器回拨(第八章).<br />
<br />
:因为服务提供者是一个策略问题,对于任何给定域和其他域的通信中,它是可选的(OPTIONAL),服务器之间的通信可以(MAY)被任何特定部署的管理员禁止。如果一个特殊的域允许域间的通信,它应该(SHOULD)允许高安全性。<br />
<br />
:管理员可能想在服务器间使用SASL来通信,以确保双方的验证和保密性(比如在机构的私有网络).兼容实施应该(SHOULD)为这个目的支持SASL.<br />
<br />
:服务器宣称的DNS主机名被解析之前,服务器-服务器通信不能(MUST NOT)继续进行。应该首先尝试解析\[SRV\]记录,其服务名为"xmpp-server",协议名为"tcp",整个资源记录类似"_xmpp-server._tcp.example.com."(使用字符"xmpp-server"表示服务ID是经过IANA注册的,注意要用"xmpp-server"取代以前用的"jabber",因为以前的用法不符合[SRV]标准;希望保持向后兼容的实现可以继续查找或应答"jabber"服务ID).如果SRV查找失败,退而求其次,将查找一个正规的IPv4/IPv6地址记录来决定IP地址,使用"xmpp-server"端口5269,这个端口是在IANA注册了的。<br />
<br />
:服务器回拨防止域欺骗,从而使得伪造XML节更为困难.它和SASL和TLS不一样,它不是一个用于验证、安全或加密服务器之间的流的机制, 所以只是服务器身份的微弱确认而已。而且除非它使用了DNSSec \[DNSSEC\]否则它 容易受到DNS中毒攻击,即使DNS信息是正确的,如果攻击者劫持了远程域,回拨也不能防止它的攻击.需要健壮的安全性的域应该(SHOULD)使用TLS和SASL.如果服务器间的验证使用了SASL,回拨就不应该(SHOULD NOT)使用了,因为它是多余的.<br />
<br />
===层的次序===<br />
<br />
:协议中的层的次序必须(MUST)如下堆积:<br />
<br />
:# TCP<br />
:# TLS<br />
:# SASL<br />
:# XMPP<br />
<br />
:这个次序的原理是,[TCP]是基于连接的层,被所有使用,所以处于最上层, [TLS]经常是由操作系统层提供,[SASL]经常由应用程序层提供, XMPP则是应用程序本身.<br />
<br />
===缺乏绑定到TLS的SASL通道===<br />
<br />
:SASL构架不提供一个机制来绑定SASL验证到一个提供机密性和完整性保护的安全层。这一通道绑定"channel binding"的缺乏阻碍了SASL确认低层安全性所绑定的源和目标终端和SASL所验证的结果是否一致。如果终端不一致, 低层安全性不能被信任用来保护SASL验证的实体之间的数据传输。在这种情况下,一个SASL安全层进行握手的时候应该有效的忽略低层安全性的存在。<br />
<br />
===强制实现的技术===<br />
<br />
:最低要求, 所有实现必须(MUST)支持以下机制:<br />
<br />
::对于验证: SASL [DIGEST-MD5] 机制<br />
<br />
::对于机密性: TLS (使用 TLS_RSA_WITH_3DES_EDE_CBC_SHA 密码)<br />
<br />
::对于两者: TLS 加 SASL EXTERNAL(使用 TLS_RSA_WITH_3DES_EDE_CBC_SHA 密码支持客户端证书)<br />
<br />
===防火墙===<br />
<br />
:使用XMPP通信通常是通过\[TCP\]连接到5222端口(客户端-服务器)或5269端口(服务器-服务器), 正如在IANA注册的那样(见 IANA Considerations (第十五章)). 使用这些广为人知的端口允许管理员很容易的通过一般的防火墙来激活或禁止XMPP活动.<br />
<br />
===在SASL中使用base64===<br />
<br />
:客户端和服务器都必须(MUST)确认在SASL协商中收到的任何\[BASE64\]数据. 一个实现必须(MUST)拒绝(不是忽略)任何非显式允许base64字母的字符串; 这有助于预防建立隐蔽通道泄漏信息的行为。一个实现不能(MUST NOT)在非法输入处中断,如果那个('=')被包含在一些和最后的数据字符(如, "=AAA" or "BBBB=CCC")不同的东西里面,必须(MUST)拒绝接下来的任何包含('=')的base64字符;这有助于防止对这个实现的缓存溢出攻击和其他攻击。Base 64编码从外表看隐藏了容易辨认的信息,例如密码,但是不提供任何算法机密性。Base 64编码必须(MUST)按照RFC 3548\[BASE64\]第三章的定义执行。<br />
<br />
===Stringprep Profiles===<br />
<br />
:为了处理域ID,XMPP使用了\[STRINGPREP\]中的\[NAMEPREP\] profile; 和Nameprep有关的安全性考虑, 参考\[NAMEPREP\]中的相关章节.<br />
<br />
:另外, XMPP 定义了两个\[STRINGPREP\]的 profiles: 用于node identifiers的Nodeprep(附录 A)和用于resource identifiers的Resourceprep(附录 B).<br />
<br />
:Unicode 和 ISO/IEC 10646 集有许多字符看起来相似. 在许多时候, 安全协议的使用者可能看起来吻合,比如当比较信任的第三方的名字的时候. 因为没有很多上下文的时候不可能映射看起来相似的字符,比如知道所用的字符集, stringprep不匹配相似字符串,也不因为一些字符串象看起来象别的字符串而禁止它们.<br />
<br />
:一个节点ID可能被作为一个实体的XMPP地址的一部分. 一个通常的用途是作为一个即时消息用户的用户名;另一个用途是作为一个多用途聊天室的名字; 很多其他种类的实体可能使用节点ID作为他们的地址的一部分。 这些服务的安全性可能会受到国际化节点ID的不同表达的威胁;例如, 一个用户键入一个单独的国际化的节点ID可能访问了另一个用户的帐号信息, 或一个用户可能获得访问一个受限的聊天室或服务的访问权限.<br />
<br />
:一个资源ID可能被作为一个实体的XMPP地址的一部分。一个通常的用户是即时消息用户所连接的资源(激活的会话)的名字; 另一个是作为多用户聊天室的某用户的昵称; 许多其他种类的实体可能使用资源ID作为他们地址的一部分.这些服务的安全性可能会受到国际化资源ID的不同表达的威胁;例如, 一个用户可能尝试以同一个名字初始化多个会话,或一个用户可能发送一个消息给多用户聊天室的一个人但实际上发给了另外一个人.<br />
<br />
==IANA 事项==<br />
<br />
===用于TLS数据的XML名字空间名===<br />
<br />
:XMPP中用于TLS相关数据的 URN 子名字空间定义如下. (这个名字空间的名字遵守The IETF XML Registry [XML-REG]定义的格式.)<br />
<br />
::URI: urn:ietf:params:xml:ns:xmpp-tls<br />
<br />
::Specification: RFC 3920<br />
<br />
::Description: This is the XML namespace name for TLS-related data in the Extensible Messaging and Presence Protocol (XMPP) as defined by RFC 3920.<br />
<br />
::Registrant Contact: IETF, XMPP Working Group, <xmppwg@jabber.org><br />
<br />
===用于SASL数据的XML名字空间名===<br />
<br />
:XMPP中用于SASL相关数据的 URN 子名字空间定义如下. (这个名字空间的名字遵守The IETF XML Registry \[XML-REG\]定义的格式.)<br />
<br />
::URI: urn:ietf:params:xml:ns:xmpp-sasl<br />
<br />
::Specification: RFC 3920<br />
<br />
::Description: This is the XML namespace name for SASL-related data in the Extensible Messaging and Presence Protocol (XMPP) as defined by RFC 3920.<br />
<br />
::Registrant Contact: IETF, XMPP Working Group, <xmppwg@jabber.org><br />
<br />
===用于流错误的XML名字空间名===<br />
<br />
:XMPP中用于流相关错误的 URN 子名字空间定义如下. (这个名字空间的名字遵守The IETF XML Registry [XML-REG]定义的格式.)<br />
<br />
::URI: urn:ietf:params:xml:ns:xmpp-streams<br />
<br />
::Specification: RFC 3920<br />
<br />
:Description: This is the XML namespace name for stream-related error data in the Extensible Messaging and Presence Protocol (XMPP) as defined by RFC 3920.<br />
<br />
::Registrant Contact: IETF, XMPP Working Group, <xmppwg@jabber.org><br />
<br />
===用于资源绑定的XML名字空间名===<br />
<br />
:XMPP中用于资源绑定的 URN 子名字空间定义如下. (这个名字空间的名字遵守The IETF XML Registry [XML-REG]定义的格式.)<br />
<br />
::URI: urn:ietf:params:xml:ns:xmpp-bind<br />
<br />
::Specification: RFC 3920<br />
<br />
::Description: This is the XML namespace name for resource binding in the Extensible Messaging and Presence Protocol (XMPP) as defined by RFC 3920.<br />
<br />
::Registrant Contact: IETF, XMPP Working Group, <xmppwg@jabber.org><br />
<br />
===用于节错误的XML名字空间名===<br />
<br />
:XMPP中用于节相关错误数据的 URN 子名字空间定义如下. (这个名字空间的名字遵守The IETF XML Registry \[XML-REG\]定义的格式.)<br />
<br />
::URI: urn:ietf:params:xml:ns:xmpp-stanzas<br />
<br />
::Specification: RFC 3920<br />
<br />
::Description: This is the XML namespace name for stanza-related error data in the Extensible Messaging and Presence Protocol (XMPP) as defined by RFC 3920.<br />
<br />
::Registrant Contact: IETF, XMPP Working Group, <xmppwg@jabber.org><br />
<br />
===Nodeprep Profile of Stringprep===<br />
<br />
:The Nodeprep profile of stringprep是在Nodeprep(附录 A)定义的. IANA已经在stringprep profile registry中注册了 Nodeprep.<br />
<br />
::Name of this profile:<br />
<br />
:::Nodeprep<br />
<br />
::RFC in which the profile is defined:<br />
<br />
:::RFC 3920<br />
<br />
::Indicator whether or not this is the newest version of the profile:<br />
<br />
:::This is the first version of Nodeprep<br />
<br />
===Resourceprep Profile of Stringprep===<br />
<br />
:The Resourceprep profile of stringprep是在Resourceprep(附录 B)定义的. IANA已经在stringprep profile registry中注册了Resourceprep.<br />
<br />
::Name of this profile:<br />
<br />
:::Resourceprep<br />
<br />
::RFC in which the profile is defined:<br />
<br />
:::RFC 3920<br />
<br />
::Indicator whether or not this is the newest version of the profile:<br />
<br />
:::This is the first version of Resourceprep<br />
<br />
===GSSAPI 服务名===<br />
<br />
:IANA已经注册了 "xmpp" 作为一个 GSSAPI \[GSS-API\] 服务名, 在SASL Definition (第六章第三节)定义了.<br />
<br />
===端口号===<br />
<br />
:IANA已经注册了"xmpp-client" 和 "xmpp-server" 作为\[TCP\]端口号5222和5269的关键字.<br />
<br />
:这些端口应该(SHOULD)用于客户端-服务器 和 服务器-服务器通信,但它们的使用是可选的(OPTIONAL).<br />
<br />
==参考==<br />
<br />
===标准化参考===<br />
<br />
:[ABNF] Crocker, D. and P. Overell, "Augmented BNF for Syntax Specifications: ABNF", RFC 2234, November 1997.<br />
<br />
:[BASE64] Josefsson, S., "The Base16, Base32, and Base64 Data Encodings", RFC 3548, July 2003.<br />
<br />
:[CHARSET] Alvestrand, H., "IETF Policy on Character Sets and Languages", BCP 18, RFC 2277, January 1998.<br />
<br />
:[DIGEST-MD5] Leach, P. and C. Newman, "Using Digest Authentication as a SASL Mechanism", RFC 2831, May 2000.<br />
<br />
:[DNS] Mockapetris, P., "Domain names \- implementation and specification", STD 13, RFC 1035, November 1987.<br />
<br />
:[GSS-API] Linn, J., "Generic Security Service Application Program Interface Version 2, Update 1", RFC 2743, January 2000.<br />
<br />
:[HTTP-TLS] Rescorla, E., "HTTP Over TLS", RFC 2818, May 2000.<br />
<br />
:[IDNA] Faltstrom, P., Hoffman, P., and A. Costello, "Internationalizing Domain Names in Applications (IDNA)", RFC 3490, March 2003.<br />
<br />
:[IPv6] Hinden, R. and S. Deering, "Internet Protocol Version 6 (IPv6) Addressing Architecture", RFC 3513, April 2003.<br />
<br />
:[LANGTAGS] Alvestrand, H., "Tags for the Identification of Languages", BCP 47, RFC 3066, January 2001.<br />
<br />
:[NAMEPREP] Hoffman, P. and M. Blanchet, "Nameprep: A Stringprep Profile for Internationalized Domain Names (IDN)", RFC 3491, March 2003.<br />
<br />
:[RANDOM] Eastlake 3rd, D., Crocker, S., and J. Schiller, "Randomness Recommendations for Security", RFC 1750, December 1994.<br />
<br />
:[SASL] Myers, J., "Simple Authentication and Security Layer (SASL)", RFC 2222, October 1997.<br />
<br />
:[SRV] Gulbrandsen, A., Vixie, P., and L. Esibov, "A DNS RR for specifying the location of services (DNS SRV)", RFC 2782, February 2000.<br />
<br />
:[STRINGPREP] Hoffman, P. and M. Blanchet, "Preparation of Internationalized Strings ("stringprep")", RFC 3454, December 2002.<br />
<br />
:[TCP] Postel, J., "Transmission Control Protocol", STD 7, RFC 793, September 1981.<br />
<br />
:[TERMS] Bradner, S., "Key words for use in RFCs to Indicate Requirement Levels", BCP 14, RFC 2119, March 1997.<br />
<br />
:[TLS] Dierks, T. and C. Allen, "The TLS Protocol Version 1.0", RFC 2246, January 1999.<br />
<br />
:[UCS2] International Organization for Standardization, "Information Technology \- Universal Multiple-octet coded Character Set (UCS) - Amendment 2: UCS Transformation Format 8 (UTF-8)", ISO Standard 10646-1 Addendum 2, October 1996.<br />
<br />
:[UTF-8] Yergeau, F., "UTF-8, a transformation format of ISO 10646", STD 63, RFC 3629, November 2003.<br />
<br />
:[X509] Housley, R., Polk, W., Ford, W., and D. Solo, "Internet X.509 Public Key Infrastructure Certificate and Certificate Revocation List (CRL) Profile", RFC 3280, April 2002.<br />
<br />
:[XML] Bray, T., Paoli, J., Sperberg-McQueen, C., and E. Maler, "Extensible Markup Language (XML) 1.0 (2nd ed)", W3C REC-xml, October 2000, <http://www.w3.org/TR/REC-xml>.<br />
<br />
:[XML-NAMES] Bray, T., Hollander, D., and A. Layman, "Namespaces in XML", W3C REC-xml-names, January 1999, <http://www.w3.org/TR/REC-xml-names>.<br />
<br />
===信息参考===<br />
<br />
:[ACAP] Newman, C. and J. Myers, "ACAP \-\- Application Configuration Access Protocol", RFC 2244, November 1997.<br />
<br />
:[ASN.1] CCITT, "Recommendation X.208: Specification of Abstract Syntax Notation One (ASN.1)", 1988.<br />
<br />
<br />
:[DNSSEC] Eastlake 3rd, D., "Domain Name System Security Extensions", RFC 2535, March 1999.<br />
<br />
:[HTTP] Fielding, R., Gettys, J., Mogul, J., Frystyk, H., Masinter, L., Leach, P., and T. Berners-Lee, "Hypertext Transfer Protocol -- HTTP/1.1", RFC 2616, June 1999.<br />
<br />
:[IMAP] Crispin, M., "INTERNET MESSAGE ACCESS PROTOCOL - VERSION 4rev1", RFC 3501, March 2003.<br />
<br />
:[IMP-REQS] Day, M., Aggarwal, S., Mohr, G., and J. Vincent, "Instant Messaging \/ Presence Protocol Requirements", RFC 2779, February 2000.<br />
<br />
:[IRC] Oikarinen, J. and D. Reed, "Internet Relay Chat Protocol", RFC 1459, May 1993.<br />
<br />
:[JEP-0029] Kaes, C., "Definition of Jabber Identifiers (JIDs)", JSF JEP 0029, October 2003.<br />
<br />
:[JEP-0078] Saint-Andre, P., "Non-SASL Authentication", JSF JEP 0078, July 2004.<br />
<br />
[JEP-0086] Norris, R. and P. Saint-Andre, "Error Condition Mappings", JSF JEP 0086, February 2004.<br />
<br />
:[JSF] Jabber Software Foundation, "Jabber Software Foundation", <http://www.jabber.org/>.<br />
<br />
:[POP3] Myers, J. and M. Rose, "Post Office Protocol - Version 3", STD 53, RFC 1939, May 1996.<br />
<br />
:[SIMPLE] SIMPLE Working Group, "SIMPLE WG", <http://www.ietf.org/html.charters/simple-charter.html>.<br />
<br />
:[SMTP] Klensin, J., "Simple Mail Transfer Protocol", RFC 2821, April 2001.<br />
<br />
:[URI] Berners-Lee, T., Fielding, R., and L. Masinter, "Uniform Resource Identifiers (URI): Generic Syntax", RFC 2396, August 1998.<br />
<br />
:[USINGTLS] Newman, C., "Using TLS with IMAP, POP3 and ACAP", RFC 2595, June 1999.<br />
<br />
:[XML-REG] Mealling, M., "The IETF XML Registry", BCP 81, RFC 3688, January 2004.<br />
<br />
:[[RFC3921]] Saint-Andre, P., Ed., "Extensible Messaging and Presence Protocol (XMPP): Instant Messaging and Presence", RFC 3921, October 2004.<br />
<br />
<br />
==附录 A. Nodeprep==<br />
<br />
===A.1. 介绍===<br />
<br />
:这个附录定义了 "Nodeprep" profile of [STRINGPREP]. 它定义了处理规则让用户能够在XMPP中输入国际化节点标识符并尽可能正确的获取正确的字符内容. (一个XMPP节点标识符是XMPP地址的可选部分,它在域名标识符和那个'@'分隔符之前;它经常但不是专门用来关联一个即时消息用户名)这些处理规则仅仅适用于XMPP节点标识符但不适用于任意文本或任何XMPP的其他方面.<br />
<br />
:这个脚本定义了以下这些, 正如 [STRINGPREP]要求的:<br />
<br />
:* 脚本预期的适用性: XMPP的国际化节点标识符<br />
<br />
:* 用于stringprep的输入输出字符集: Unicode 3.2, 定义在本附录的第二章<br />
<br />
:* 使用的映射: 定义在第三章<br />
<br />
:* Unicode正规化使用: 定义在第四章<br />
<br />
:* 禁止输出的字符串: 定义在第五章<br />
<br />
:* 双字节字符处理: 定义在第六章<br />
<br />
===A.2. 字符集===<br />
<br />
:本脚本使用Unicode 3.2的未分配编码列表,指向 Table A.1, 也定义在 [STRINGPREP]的附录 A 中.<br />
<br />
===A.3. 映射===<br />
<br />
:本脚本指定使用[STRINGPREP]的以下表:<br />
<br />
::Table B.1<br />
<br />
::Table B.2<br />
<br />
===A.4. 正规化===<br />
<br />
:本脚本指定 Unicode正规化使用 form KC, 定义在 [STRINGPREP]中.<br />
<br />
===A.5. 禁止输出===<br />
<br />
:本脚本指定使用以下的[STRINGPREP]表禁止输出.<br />
<br />
::Table C.1.1<br />
<br />
::Table C.1.2<br />
<br />
::Table C.2.1<br />
<br />
::Table C.2.2<br />
<br />
::Table C.3<br />
<br />
::Table C.4<br />
<br />
::Table C.5<br />
<br />
::Table C.6<br />
<br />
::Table C.7<br />
<br />
::Table C.8<br />
<br />
::Table C.9<br />
<br />
:另外, 以下Unicode字符也被禁止:<br />
<br />
: #x22 (")<br />
<br />
: #x26 (&)<br />
<br />
: #x27 (')<br />
<br />
: #x2F (/)<br />
<br />
: #x3A (:)<br />
<br />
: #x3C (<)<br />
<br />
: #x3E (>)<br />
<br />
: #x40 (@)<br />
<br />
===A.6. 双字节===<br />
<br />
:本脚本指定按照[STRINGPREP]第六章检查双字节.<br />
<br />
==附录 B. Resourceprep==<br />
<br />
===B.1. 介绍===<br />
<br />
:这个附录定义了 "Resourceprep" profile of \[STRINGPREP\]. 它定义了处理规则让用户能够在XMPP中输入国际化资源标识符并尽可能正确的获取正确的字符内容. (一个XMPP资源标识符是XMPP地址的可选部分,它在域名标识符和'/@'分隔符之后;它经常但不是专门用来关联一个即时消息会话名)这些处理规则仅仅适用于XMPP资源标识符但不适用于任意文本或任何XMPP的其他方面.<br />
<br />
:这个脚本定义了以下这些, 正如 [STRINGPREP]要求的:<br />
<br />
:* 脚本预期的适用性: XMPP的国际化节点标识符<br />
<br />
:* 用于stringprep的输入输出字符集: Unicode 3.2, 定义在本附录的第二章<br />
<br />
:* 使用的映射: 定义在第三章<br />
<br />
:* Unicode正规化使用: 定义在第四章<br />
<br />
:* 禁止输出的字符串: 定义在第五章<br />
<br />
:* 双字节字符处理: 定义在第六章<br />
<br />
===B.2. 字符集===<br />
<br />
:本脚本使用Unicode 3.2的未分配编码列表,指向 Table A.1, 也定义在 [STRINGPREP]的附录<br />
<br />
===B.3. 映射===<br />
<br />
:本脚本指定使用[STRINGPREP]的以下表:<br />
<br />
::Table B.1<br />
<br />
===B.4. 正规化===<br />
<br />
:本脚本指定使用 Unicode normalization form KC, 定义在 [STRINGPREP]中.<br />
<br />
===B.5. 禁止输出===<br />
<br />
:本脚本指定使用以下的[STRINGPREP]表禁止输出.<br />
<br />
::Table C.1.2<br />
<br />
::Table C.2.1<br />
<br />
::Table C.2.2<br />
<br />
::Table C.3<br />
<br />
::Table C.4<br />
<br />
::Table C.5<br />
<br />
::Table C.6<br />
<br />
::Table C.7<br />
<br />
::Table C.8<br />
<br />
::Table C.9<br />
<br />
===B.6. 双字节===<br />
<br />
:本脚本指定按照[STRINGPREP]第六章检查双字节.<br />
<br />
==附录 C. XML 规划==<br />
<br />
:以下 XML schemas 是描述性的, 不是标准的. 'jabber:client' 和 'jabber:server' 名字空间的标准定义, 参照 [[RFC3921]].<br />
<br />
===C.1. Streams namespace===<br />
<br />
<source lang="xml"><br />
<?xml version='1.0' encoding='UTF-8'?><br />
<br />
<xs:schema<br />
xmlns:xs='http://www.w3.org/2001/XMLSchema'<br />
targetNamespace='http://etherx.jabber.org/streams'<br />
xmlns='http://etherx.jabber.org/streams'<br />
elementFormDefault='unqualified'><br />
<br />
<xs:element name='stream'><br />
<xs:complexType><br />
<xs:sequence xmlns:client='jabber:client'<br />
xmlns:server='jabber:server'<br />
xmlns:db='jabber:server:dialback'><br />
<xs:element ref='features' minOccurs='0' maxOccurs='1'/><br />
<xs:any namespace='urn:ietf:params:xml:ns:xmpp-tls'<br />
minOccurs='0'<br />
maxOccurs='unbounded'/><br />
<xs:any namespace='urn:ietf:params:xml:ns:xmpp-sasl'<br />
minOccurs='0'<br />
maxOccurs='unbounded'/><br />
<xs:choice minOccurs='0' maxOccurs='1'><br />
<xs:choice minOccurs='0' maxOccurs='unbounded'><br />
<xs:element ref='client:message'/><br />
<xs:element ref='client:presence'/><br />
<xs:element ref='client:iq'/><br />
</xs:choice><br />
<xs:choice minOccurs='0' maxOccurs='unbounded'><br />
<xs:element ref='server:message'/><br />
<xs:element ref='server:presence'/><br />
<xs:element ref='server:iq'/><br />
<xs:element ref='db:result'/><br />
<xs:element ref='db:verify'/><br />
</xs:choice><br />
</xs:choice><br />
<xs:element ref='error' minOccurs='0' maxOccurs='1'/><br />
</xs:sequence><br />
<xs:attribute name='from' type='xs:string' use='optional'/><br />
<xs:attribute name='id' type='xs:NMTOKEN' use='optional'/><br />
<xs:attribute name='to' type='xs:string' use='optional'/><br />
<xs:attribute name='version' type='xs:decimal' use='optional'/><br />
<xs:attribute ref='xml:lang' use='optional'/><br />
</xs:complexType><br />
</xs:element><br />
<br />
<xs:element name='features'><br />
<xs:complexType><br />
<xs:all xmlns:tls='urn:ietf:params:xml:ns:xmpp-tls'<br />
xmlns:sasl='urn:ietf:params:xml:ns:xmpp-sasl'<br />
xmlns:bind='urn:ietf:params:xml:ns:xmpp-bind'<br />
xmlns:sess='urn:ietf:params:xml:ns:xmpp-session'><br />
<xs:element ref='tls:starttls' minOccurs='0'/><br />
<xs:element ref='sasl:mechanisms' minOccurs='0'/><br />
<xs:element ref='bind:bind' minOccurs='0'/><br />
<xs:elemnt ref='sess:session' minOccurs='0'/><br />
</xs:all><br />
</xs:complexType><br />
</xs:element><br />
<br />
<xs:element name='error'><br />
<xs:complexType><br />
<xs:sequence xmlns:err='urn:ietf:params:xml:ns:xmpp-streams'><br />
<xs:group ref='err:streamErrorGroup'/><br />
<xs:element ref='err:text'<br />
minOccurs='0'<br />
maxOccurs='1'/><br />
</xs:sequence><br />
</xs:complexType><br />
</xs:element><br />
<br />
</xs:schema><br />
</source><br />
<br />
===C.2. Stream error namespace===<br />
<br />
<source lang="xml"><br />
<?xml version='1.0' encoding='UTF-8'?><br />
<br />
<xs:schema<br />
xmlns:xs='http://www.w3.org/2001/XMLSchema'<br />
targetNamespace='urn:ietf:params:xml:ns:xmpp-streams'<br />
xmlns='urn:ietf:params:xml:ns:xmpp-streams'<br />
elementFormDefault='qualified'><br />
<br />
<xs:element name='bad-format' type='empty'/><br />
<xs:element name='bad-namespace-prefix' type='empty'/><br />
<xs:element name='conflict' type='empty'/><br />
<xs:element name='connection-timeout' type='empty'/><br />
<xs:element name='host-gone' type='empty'/><br />
<xs:element name='host-unknown' type='empty'/><br />
<xs:element name='improper-addressing' type='empty'/><br />
<xs:element name='internal-server-error' type='empty'/><br />
<xs:element name='invalid-from' type='empty'/><br />
<xs:element name='invalid-id' type='empty'/><br />
<xs:element name='invalid-namespace' type='empty'/><br />
<xs:element name='invalid-xml' type='empty'/><br />
<xs:element name='not-authorized' type='empty'/><br />
<xs:element name='policy-violation' type='empty'/><br />
<xs:element name='remote-connection-failed' type='empty'/><br />
<xs:element name='resource-constraint' type='empty'/><br />
<xs:element name='restricted-xml' type='empty'/><br />
<xs:element name='see-other-host' type='xs:string'/><br />
<xs:element name='system-shutdown' type='empty'/><br />
<xs:element name='undefined-condition' type='empty'/><br />
<xs:element name='unsupported-encoding' type='empty'/><br />
<xs:element name='unsupported-stanza-type' type='empty'/><br />
<xs:element name='unsupported-version' type='empty'/><br />
<xs:element name='xml-not-well-formed' type='empty'/><br />
<br />
<xs:group name='streamErrorGroup'><br />
<xs:choice><br />
<xs:element ref='bad-format'/><br />
<xs:element ref='bad-namespace-prefix'/><br />
<xs:element ref='conflict'/><br />
<xs:element ref='connection-timeout'/><br />
<xs:element ref='host-gone'/><br />
<xs:element ref='host-unknown'/><br />
<xs:element ref='improper-addressing'/><br />
<xs:element ref='internal-server-error'/><br />
<xs:element ref='invalid-from'/><br />
<xs:element ref='invalid-id'/><br />
<xs:element ref='invalid-namespace'/><br />
<xs:element ref='invalid-xml'/><br />
<xs:element ref='not-authorized'/><br />
<xs:element ref='policy-violation'/><br />
<xs:element ref='remote-connection-failed'/><br />
<xs:element ref='resource-constraint'/><br />
<xs:element ref='restricted-xml'/><br />
<xs:element ref='see-other-host'/><br />
<xs:element ref='system-shutdown'/><br />
<xs:element ref='undefined-condition'/><br />
<xs:element ref='unsupported-encoding'/><br />
<xs:element ref='unsupported-stanza-type'/><br />
<xs:element ref='unsupported-version'/><br />
<xs:element ref='xml-not-well-formed'/><br />
</xs:choice><br />
</xs:group><br />
<br />
<xs:element name='text'><br />
<xs:complexType><br />
<xs:simpleContent><br />
<xs:extension base='xs:string'><br />
<xs:attribute ref='xml:lang' use='optional'/><br />
</xs:extension><br />
</xs:simpleContent><br />
</xs:complexType><br />
</xs:element><br />
<br />
<xs:simpleType name='empty'><br />
<xs:restriction base='xs:string'><br />
<xs:enumeration value=''/><br />
</xs:restriction><br />
</xs:simpleType><br />
<br />
</xs:schema><br />
</source><br />
<br />
===C.3. TLS namespace===<br />
<br />
<source lang="xml"><br />
<?xml version='1.0' encoding='UTF-8'?><br />
<br />
<xs:schema<br />
xmlns:xs='http://www.w3.org/2001/XMLSchema'<br />
targetNamespace='urn:ietf:params:xml:ns:xmpp-tls'<br />
xmlns='urn:ietf:params:xml:ns:xmpp-tls'<br />
elementFormDefault='qualified'><br />
<br />
<xs:element name='starttls'><br />
<xs:complexType><br />
<xs:sequence><br />
<xs:element<br />
name='required'<br />
minOccurs='0'<br />
maxOccurs='1'<br />
type='empty'/><br />
</xs:sequence><br />
</xs:complexType><br />
</xs:element><br />
<br />
<xs:element name='proceed' type='empty'/><br />
<xs:element name='failure' type='empty'/><br />
<br />
<xs:simpleType name='empty'><br />
<xs:restriction base='xs:string'><br />
<xs:enumeration value=''/><br />
</xs:restriction><br />
</xs:simpleType><br />
<br />
</xs:schema><br />
</source><br />
<br />
===C.4. SASL namespace===<br />
<br />
<source lang="xml"><br />
<?xml version='1.0' encoding='UTF-8'?><br />
<br />
<xs:schema<br />
xmlns:xs='http://www.w3.org/2001/XMLSchema'<br />
targetNamespace='urn:ietf:params:xml:ns:xmpp-sasl'<br />
xmlns='urn:ietf:params:xml:ns:xmpp-sasl'<br />
elementFormDefault='qualified'><br />
<br />
<xs:element name='mechanisms'><br />
<xs:complexType><br />
<xs:sequence><br />
<xs:element name='mechanism'<br />
maxOccurs='unbounded'<br />
type='xs:string'/><br />
</xs:sequence><br />
</xs:complexType><br />
</xs:element><br />
<br />
<xs:element name='auth'><br />
<xs:complexType><br />
<xs:simpleContent><br />
<xs:extension base='empty'><br />
<xs:attribute name='mechanism'<br />
type='xs:string'<br />
use='optional'/><br />
</xs:extension><br />
</xs:simpleContent><br />
</xs:complexType><br />
</xs:element><br />
<br />
<xs:element name='challenge' type='xs:string'/><br />
<xs:element name='response' type='xs:string'/><br />
<xs:element name='abort' type='empty'/><br />
<xs:element name='success' type='empty'/><br />
<br />
<xs:element name='failure'><br />
<xs:complexType><br />
<xs:choice minOccurs='0'><br />
<xs:element name='aborted' type='empty'/><br />
<xs:element name='incorrect-encoding' type='empty'/><br />
<xs:element name='invalid-authzid' type='empty'/><br />
<xs:element name='invalid-mechanism' type='empty'/><br />
<xs:element name='mechanism-too-weak' type='empty'/><br />
<xs:element name='not-authorized' type='empty'/><br />
<xs:element name='temporary-auth-failure' type='empty'/><br />
</xs:choice><br />
</xs:complexType><br />
</xs:element><br />
<xs:simpleType name='empty'><br />
<xs:restriction base='xs:string'><br />
<xs:enumeration value=''/><br />
</xs:restriction><br />
</xs:simpleType><br />
<br />
</xs:schema><br />
</source><br />
<br />
===C.5. Resource binding namespace===<br />
<br />
<source lang="xml"><br />
<?xml version='1.0' encoding='UTF-8'?><br />
<br />
<xs:schema<br />
xmlns:xs='http://www.w3.org/2001/XMLSchema'<br />
targetNamespace='urn:ietf:params:xml:ns:xmpp-bind'<br />
xmlns='urn:ietf:params:xml:ns:xmpp-bind'<br />
elementFormDefault='qualified'><br />
<br />
<xs:element name='bind'><br />
<xs:complexType><br />
<xs:choice minOccurs='0' maxOccurs='1'><br />
<xs:element name='resource' type='xs:string'/><br />
<xs:element name='jid' type='xs:string'/><br />
</xs:choice><br />
</xs:complexType><br />
</xs:element><br />
<br />
</xs:schema><br />
</source><br />
<br />
===C.6. Dialback namespace===<br />
<br />
<source lang="xml"><br />
<?xml version='1.0' encoding='UTF-8'?><br />
<br />
<xs:schema<br />
xmlns:xs='http://www.w3.org/2001/XMLSchema'<br />
targetNamespace='jabber:server:dialback'<br />
xmlns='jabber:server:dialback'<br />
elementFormDefault='qualified'><br />
<br />
<xs:element name='result'><br />
<xs:complexType><br />
<xs:simpleContent><br />
<xs:extension base='xs:token'><br />
<xs:attribute name='from' type='xs:string' use='required'/><br />
<xs:attribute name='to' type='xs:string' use='required'/><br />
<xs:attribute name='type' use='optional'><br />
<xs:simpleType><br />
<xs:restriction base='xs:NCName'><br />
<xs:enumeration value='invalid'/><br />
<xs:enumeration value='valid'/><br />
</xs:restriction><br />
</xs:simpleType><br />
</xs:attribute><br />
</xs:extension><br />
</xs:simpleContent><br />
</xs:complexType><br />
</xs:element><br />
<br />
<xs:element name='verify'><br />
<xs:complexType><br />
<xs:simpleContent><br />
<xs:extension base='xs:token'><br />
<xs:attribute name='from' type='xs:string' use='required'/><br />
<xs:attribute name='id' type='xs:NMTOKEN' use='required'/><br />
<xs:attribute name='to' type='xs:string' use='required'/><br />
<xs:attribute name='type' use='optional'><br />
<xs:simpleType><br />
<xs:restriction base='xs:NCName'><br />
<xs:enumeration value='invalid'/><br />
<xs:enumeration value='valid'/><br />
</xs:restriction><br />
</xs:simpleType><br />
</xs:attribute><br />
</xs:extension><br />
</xs:simpleContent><br />
</xs:complexType><br />
</xs:element><br />
<br />
</xs:schema><br />
</source><br />
<br />
===C.7. Stanza error namespace===<br />
<br />
<source lang="xml"><br />
<?xml version='1.0' encoding='UTF-8'?><br />
<br />
<xs:schema<br />
xmlns:xs='http://www.w3.org/2001/XMLSchema'<br />
targetNamespace='urn:ietf:params:xml:ns:xmpp-stanzas'<br />
xmlns='urn:ietf:params:xml:ns:xmpp-stanzas'<br />
elementFormDefault='qualified'><br />
<br />
<xs:element name='bad-request' type='empty'/><br />
<xs:element name='conflict' type='empty'/><br />
<xs:element name='feature-not-implemented' type='empty'/><br />
<xs:element name='forbidden' type='empty'/><br />
<xs:element name='gone' type='xs:string'/><br />
<xs:element name='internal-server-error' type='empty'/><br />
<xs:element name='item-not-found' type='empty'/><br />
<xs:element name='jid-malformed' type='empty'/><br />
<xs:element name='not-acceptable' type='empty'/><br />
<xs:element name='not-allowed' type='empty'/><br />
<xs:element name='payment-required' type='empty'/><br />
<xs:element name='recipient-unavailable' type='empty'/><br />
<xs:element name='redirect' type='xs:string'/><br />
<xs:element name='registration-required' type='empty'/><br />
<xs:element name='remote-server-not-found' type='empty'/><br />
<xs:element name='remote-server-timeout' type='empty'/><br />
<xs:element name='resource-constraint' type='empty'/><br />
<xs:element name='service-unavailable' type='empty'/><br />
<xs:element name='subscription-required' type='empty'/><br />
<xs:element name='undefined-condition' type='empty'/><br />
<xs:element name='unexpected-request' type='empty'/><br />
<br />
<xs:group name='stanzaErrorGroup'><br />
<xs:choice><br />
<xs:element ref='bad-request'/><br />
<xs:element ref='conflict'/><br />
<xs:element ref='feature-not-implemented'/><br />
<xs:element ref='forbidden'/><br />
<xs:element ref='gone'/><br />
<xs:element ref='internal-server-error'/><br />
<xs:element ref='item-not-found'/><br />
<xs:element ref='jid-malformed'/><br />
<xs:element ref='not-acceptable'/><br />
<xs:element ref='not-allowed'/><br />
<xs:element ref='payment-required'/><br />
<xs:element ref='recipient-unavailable'/><br />
<xs:element ref='redirect'/><br />
<xs:element ref='registration-required'/><br />
<xs:element ref='remote-server-not-found'/><br />
<xs:element ref='remote-server-timeout'/><br />
<xs:element ref='resource-constraint'/><br />
<xs:element ref='service-unavailable'/><br />
<xs:element ref='subscription-required'/><br />
<xs:element ref='undefined-condition'/><br />
<xs:element ref='unexpected-request'/><br />
</xs:choice><br />
</xs:group><br />
<br />
<xs:element name='text'><br />
<xs:complexType><br />
<xs:simpleContent><br />
<xs:extension base='xs:string'><br />
<xs:attribute ref='xml:lang' use='optional'/><br />
</xs:extension><br />
</xs:simpleContent><br />
</xs:complexType><br />
</xs:element><br />
<br />
<xs:simpleType name='empty'><br />
<xs:restriction base='xs:string'><br />
<xs:enumeration value=''/><br />
</xs:restriction><br />
</xs:simpleType><br />
<br />
</xs:schema><br />
</source><br />
<br />
==附录 D. 核心Jabber协议和XMPP的不同==<br />
<br />
:本章是非标准的.<br />
<br />
::译者注:附录D对于新接触XMPP的人没有什么意义,就不翻译了,免得浪费时间。因为现在RFC公布已经很久了,以前的Jabber实现很多都进化到XMPP了。<br />
<br />
:XMPP has been adapted from the protocols originally developed in the Jabber open-source community, which can be thought of as "XMPP 0.9". Because there exists a large installed base of Jabber implementations and deployments, it may be helpful to specify the key differences between the relevant Jabber protocols and XMPP in order to expedite and encourage upgrades of those implementations and deployments to XMPP. This section summarizes the core differences, while the corresponding section of [[RFC3921]] summarizes the differences that relate specifically to instant messaging and presence applications.<br />
<br />
===D.1. Channel Encryption===<br />
<br />
:It was common practice in the Jabber community to use SSL for channel encryption on ports other than 5222 and 5269 (the convention is to use ports 5223 and 5270). XMPP uses TLS over the IANA-registered ports for channel encryption, as defined under Use of TLS (Section 5) herein.<br />
<br />
===D.2. Authentication===<br />
<br />
:The client-server authentication protocol developed in the Jabber community used a basic IQ interaction qualified by the 'jabber:iq:auth' namespace (documentation of this protocol is contained in \[JEP-0078\], published by the Jabber Software Foundation [JSF]). XMPP uses SASL for authentication, as defined under Use of SASL (Section 6) herein.<br />
<br />
:The Jabber community did not develop an authentication protocol for server-to-server communications, only the Server Dialback (Section 8) protocol to prevent server poofing. XMPP supersedes Server Dialback with a true server-to-server authentication protocol, as defined under Use of SASL (Section 6) herein.<br />
<br />
===D.3. Resource Binding===<br />
<br />
:Resource binding in the Jabber community was handled via the 'jabber:iq:auth' namespace (which was also used for client authentication with a server). XMPP defines a dedicated namespace for resource binding as well as the ability for a server to generate a resource identifier on behalf of a client, as defined under Resource Binding (Section 7).<br />
<br />
===D.4. JID Processing===<br />
<br />
:JID processing was somewhat loosely defined by the Jabber community (documentation of forbidden characters and case handling is contained in [JEP-0029], published by the Jabber Software Foundation [JSF]). XMPP specifies the use of \[NAMEPREP\] for domain identifiers and supplements Nameprep with two additional [STRINGPREP] profiles for JID processing: Nodeprep (Appendix A) for node identifiers and Resourceprep (Appendix B) for resource identifiers.<br />
<br />
===D.5. Error Handling===<br />
<br />
:Stream-related errors were handled in the Jabber community via XML character data text in a <stream:error/> element. In XMPP, stream-related errors are handled via an extensible mechanism defined under Stream Errors (Section 4.7) herein. Stanza-related errors were handled in the Jabber community via HTTP-style error codes. In XMPP, stanza-related errors are handled via an extensible mechanism defined under Stanza Errors (Section 9.3) herein. (Documentation of a mapping between Jabber and XMPP error handling mechanisms is contained in \[JEP-0086\], published by the Jabber Software Foundation [JSF].)<br />
<br />
===D.6. Internationalization===<br />
<br />
:Although use of UTF-8 has always been standard practice within the Jabber community, the community did not define mechanisms for specifying the language of human-readable text provided in XML character data. XMPP specifies the use of the 'xml:lang' attribute in such contexts, as defined under Stream Attributes (Section 4.4) and xml:lang (Section 9.1.5) herein.<br />
<br />
===D.7. Stream Version Attribute===<br />
<br />
:The Jabber community did not include a 'version' attribute in stream headers. XMPP specifies inclusion of that attribute as a way to signal support for the stream features (authentication, encryption, etc.) defined under Version Support (Section 4.4.1) herein.<br />
<br />
==贡献者==<br />
<br />
:XMPP的大部分核心方面是由1999年开始的Jabber开源社区开发的. 这个社区是由 Jeremie Miller建立的, 他于1999年1月发布了最初版的jabber server源代码. 主要的基础协议的早期贡献者还包括 Ryan Eatmon, Peter Millard, Thomas Muldowney,和 Dave Smith. XMPP工作组的工作主要集中在安全性和国际化方面; 在这些领域, 使用 TLS 和 SASL 的协议最初是由 Rob Norris贡献的, stringprep profiles 最初是由 Joe Hildebrand贡献的. The error code syntax 是由Lisa Dusseault建议的.<br />
<br />
==致谢==<br />
<br />
:感谢许多在贡献者名单之外的人们. 尽管很难提供一个完整的名单, 以下个人对于定义协议或评论标准提供了很多帮助:<br />
<br />
:Thomas Charron, Richard Dobson, Sam Hartman, Schuyler Heath, Jonathan Hogg, Cullen Jennings, Craig Kaes, Jacek Konieczny, Alexey Melnikov, Keith Minkler, Julian Missig, Pete Resnick, Marshall Rose, Alexey Shchepin, Jean-Louis Seguineau, Iain Shigeoka, Greg Troxel, and David Waite. <br />
<br />
:也感谢 XMPP工作组的成员和 IETF 社区在本文的成文过程中一直提供的评论和反馈。<br />
<br />
<br />
==作者地址==<br />
<br />
:Peter Saint-Andre (editor)<br />
<br />
:Jabber Software Foundation<br />
<br />
:EMail: stpeter@jabber.org<br />
<br />
==完整的版权声明==<br />
<br />
:Copyright (C) The Internet Society (2004).<br />
<br />
:This document is subject to the rights, licenses and restrictions contained in BCP 78, and except as set forth therein, the authors retain all their rights. This document and the information contained herein are provided on an "AS IS" basis and THE CONTRIBUTOR, THE ORGANIZATION HE/S HE REPRESENTS OR IS SPONSORED BY (IF ANY), THE INTERNET SOCIETY AND THE INTERNET ENGINEERING TASK FORCE DISCLAIM ALL WARRANTIES, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO ANY WARRANTY THAT THE USE OF THE INFORMATION HEREIN WILL NOT INFRINGE ANY RIGHTS OR ANY IMPLIED WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE.<br />
<br />
==Intellectual Property==<br />
<br />
:The IETF takes no position regarding the validity or scope of any Intellectual Property Rights or other rights that might be claimed to pertain to the implementation or use of the technology described in this document or the extent to which any license under such rights might or might not be available; nor does it represent that it has made any independent effort to identify any such rights. Information on the IETF's procedures with respect to rights in IETF Documents can be found in BCP 78 and BCP 79. Copies of IPR disclosures made to the IETF Secretariat and any assurances of licenses to be made available, or the result of an attempt made to obtain a general license or permission for the use of such proprietary rights by implementers or users of this specification can be obtained from the IETF on-line IPR repository at http://www.ietf.org/ipr. The IETF invites any interested party to bring to its attention any copyrights, patents or patent applications, or other proprietary rights that may cover technology that may be required to implement this standard. Please address the information to the IETF at ietf-ipr@ietf.org.<br />
<br />
==感谢==<br />
<br />
:目前为RFC编辑活动提供资金的Internet Society.</div>
Snowqiang
http://wiki.jabbercn.org/RFC3920
RFC3920
2011-05-18T10:43:32Z
<p>Snowqiang: /* 事件顺序 */</p>
<hr />
<div>[[Category:XMPP正式RFC标准]]<br />
[[Category:已翻译]]<br />
<br />
"本文的英文原文来自[http://www.ietf.org/rfc/rfc3920.txt RFC 3920]<br />
<br />
{|<br />
|网络工作组 || P. Saint-Andre, Ed.<br />
|-<br />
|申请讨论: 3920 || Jabber软件基金会<br />
|-<br />
|类别: 标准跟踪 || 2004年10月<br />
|}<br />
<br />
<br />
<br />
:::'''可扩展的消息和出席信息协议 (XMPP): 核心协议'''<br />
<br />
'''关于本文的说明'''<br />
<br />
:本文为互联网社区定义了一个互联网标准跟踪协议,并且申请讨论协议和提出了改进的建议。请参照“互联网官方协议标准”的最新版本(STD 1)获得这个协议的标准化进程和状态。本文可以不受限制的分发。<br />
<br />
'''版权声明'''<br />
<br />
:本文版权属于互联网社区 (C) The Internet Society (2004).<br />
<br />
'''摘要'''<br />
<br />
:本文定义了可扩展消息和出席信息协议(XMPP)的核心功能,这个协议采用XML流实现在任意两个网络终端接近实时的交换结构化信息。XMPP提供一个通用的可扩展的框架来交换XML数据,它主要用来建立即时消息和出席信息应用以实现 RFC 2779 的需求。 <br />
<br />
==绪论==<br />
<br />
===概览===<br />
<br />
:XMPP是一个开放式的XML协议,设计用于准实时消息和出席信息以及请求-响应服务。其基本的语法和语义最初主要是由Jabber开放源代码社区于1999年开发的。2002年,XMPP工作组被授权接手开发和改编Jabber协议以适应IETF的即时消息和出席信息技术。作为XMPP工作组的成果,本文定义了 XMPP 1.0 的核心功能;在 RFC 2779 [IMP-REQS] 中指定的提供即时消息和出席信息功能的扩展,定义在 XMPP-IM 协议 [the Extensible Messaging and Presence Protocol (XMPP): Instant Messaging and Presence] 中。<br />
<br />
===术语===<br />
<br />
:本文中大写的关键字 "MUST(必须)", "MUST NOT(不能)", "REQUIRED(必需)", "SHALL(将会)", "SHALL NOT(将不会)", "SHOULD(应该)", "SHOULD NOT(不应该)", "RECOMMENDED(建议)", "MAY(可以)", 和 "OPTIONAL(可选)" 的确切含义符合 BCP 14, RFC 2119 \[TERMS\].<br />
<br />
==通用的架构==<br />
<br />
===概览===<br />
<br />
:尽管XMPP没有指定任何特定的网络结构,但它通常是采用客户-服务器 架构进行实现,其中客户端通过TCP方式使用XMPP访问服务器,服务器之间也采用TCP方式进行通信。<br />
<br />
:以下是这一架构的抽象的示意图 (这里 "-" 表示使用 XMPP 通讯, "=" 表示可使用任何协议通讯)。<br />
<br />
<br />
::C1----S1---S2---C3<br />
<br />
::::|<br />
<br />
::C2----+---G1===FN1===FC1<br />
<br />
:符号的含义如下:<br />
<br />
::* C1, C2, C3 = XMPP 客户端<br />
<br />
::* S1, S2 = XMPP 服务器<br />
<br />
::* G1 = 一个XMPP和外部(非XMPP)消息网络之间进行“翻译”的网关<br />
<br />
::* FN1 = 一个外部消息网络<br />
<br />
::* FC1 = 外部消息网络上的一个客户端<br />
<br />
===服务器===<br />
<br />
:服务器充当XMPP通信的一个智能抽象层,它主要负责:<br />
<br />
:* 对受验证的客户端,服务器以及其他实体之间以XML流形式的连接和会话进行管理。<br />
<br />
:* 在这些实体间使用XML流对合理编址的XML节(第九章)进行路由<br />
<br />
:大部分 XMPP 兼容的服务器也负责存储客户端使用的数据 (比如基于XMPP协议的及时消息应用中的联系人名单); 在这种情况下, XML 数据直接服务器来处理,而不需要转发到其他实体。<br />
<br />
===客户端===<br />
<br />
:大部分客户端通过 TCP 连接直接连到服务器,并通过XMPP获得由服务器以及联合服务器所提供的全部功能。多个不同资源(比如不同的设备和地点)的客户端'''可以'''同时登陆并且并发的连接到一个服务器,每个不同资源的客户端通过XMPP地址的资源标识符来区分(比如<node@domain/ home> 和 <node@domain/work>),参见地址空间(第三章)。'''建议'''的客户端和服务器连接的端口是 5222 ,这个端口已经在 IANA(在第十五章第九节查阅端口号码) 注册了。<br />
<br />
===网关===<br />
<br />
:网关是一个特殊用途的服务器端的服务,主要功能是把 XMPP 翻译成外部(非XMPP)消息系统,并把返回的消息翻译成 XMPP 。例如到 email(参见 [SMTP] ),IRC(参见 [IRC] ),SIMPLE(参见 [SIMPLE] ),SMS 的网关;还有和别的消息服务的网关,比如AIM,ICQ,MSN Messenger,Yahoo! Instant Messenger。网关和服务器之间的通信,网关和外部消息系统的通信,不在本文描述范围之内。<br />
<br />
===网络===<br />
<br />
:因为每个服务器都是由一个网络地址来标识的并且服务器之间的通信是 客户-服务器 协议的直接扩展,实际上整个系统是由很多互通的服务器构成的。例如,<juliet@example.com> 可以和 <romeo@example.net> 交换消息,出席信息和其他信息。这种模式常见于那些需要使网络地址标准化的协议(比如 SMTP )。任意两个服务器之间的通信是可选(OPTIONAL)的。如果被激活,那么这种通信应该(SHOULD)通过 XML 流绑定到 TCP 连接上进行。建议的(RECOMMENDED)服务器之间的连接端口为 5269 ,这个端口号已经在 IANA (在第十五章第九节查阅端口号码)注册了。<br />
<br />
==地址空间==<br />
<br />
===概览===<br />
<br />
:一个实体可以是任何一个被认为是一个网络端点的东西(例如网络上的一个 ID ),而且它是通过XMPP进行通信的。所有这些实体都有一个具有唯一性的地址,并符合 RFC 2396 [URI]规范要求的格式。由于历史原因,一个 XMPP 实体的地址被称为 Jabber Identifier 或 JID 。一个合法的 JID 包括一组排列好的元素,包括域名(domain identifier),节点名(node identifier),和资源名(resource identifier)。<br />
<br />
:JID的语法定义,使用 [ABNF] 中的 Augmented Backus-Naur 格式。(IPv4 地址和 IPv6地址规则在 附录B 中的 [IPv6] 中定义;确定节点规则的合法字符顺序由 附录A 的 [STRINGPREP] 的 Nodeprep 部分来定义;确定资源规则的合法字符顺序由 附录B 的 [STRINGPREP] 的Resourceprep 部分来定义;子域名规则参考 [IDNA] 中关于国际域名标签的描述。)。<br />
<br />
::jid = [ node "@" ] domain [ "/" resource ]<br />
<br />
::domain = fqdn / address-literal<br />
<br />
::fqdn = (sub-domain 1*("." sub-domain))<br />
<br />
::sub-domain = (internationalized domain label)<br />
<br />
::address-literal = IPv4address / IPv6address<br />
<br />
:所有 JID 都是基于上述的结构。类似 <user@host/resource> 这种结构,最常用来标识一个即时消息用户,这个用户所连接的服务器,以及这个用户用于连接的资源(比如特定类型的客户端软件)。不过,节点类型不是客户端也是有可能的,比如一个用来提供多用户聊天服务的特定的聊天室,地址可以是 <room@service> (这里 “room“ 是聊天室的名字而 ”service“ 是多用户聊天服务的主机名),而加入了这个聊天室的某个特定的用户的地址则是 <room@service/nick> (这里 ”nick“ 是用户在聊天室的昵称)。许多其他的 JID 类型都是可能的(例如 <domain/resource> 可能是一个服务器端的脚本或服务)。<br />
<br />
:一个 JID 的每个合法部分(节点名,域名,资源名)的长度不能(MUST NOT)超过 1023 字节。也就是整体长度(包括 '@' 和 '/' )不能超过 3071 字节。<br />
<br />
===域名===<br />
<br />
:域名是一个主要的ID并且是 JID 中唯一必需(REQUIRED)的元素(一个纯粹的域名也是一个合法的 JID)。它通常代表网络的网关或者“主”服务器,其他实体通过连接它来实现 XML 转发和数据管理功能。然而,由一个域名标识引用的实体,并非总是一个服务器,它也可能是一个服务器的子域地址,提供额外的功能(比如多用户聊天服务,用户目录,或一个到外部消息系统的网关)。<br />
<br />
:每个服务器或者服务的域名,可以(MAY)是一个 IP 地址,但应该(SHOULD)是一个完全合法的域名(参见 [DNS]).一个域名ID必须(MUST)是 [IANA] 里定义的“国际化域名”,并且按 [STRINGPREP]中的 [NAMEPREP] profile进行成功的字符转换。在比较两个域名ID之前,服务器必须(MUST),客户端应该(SHOULD)首先按照Nameprep profile(定义在[IANA]中) 来转换每个域名的字符。<br />
<br />
===节点名===<br />
<br />
:节点名是一个可选(OPTIONAL)的第二 ID,放在域名之前并用符号"@"分开.它通常表示一个向服务器或网关请求和使用网络服务的实体(比如一个客户端),当然它也能够表示其他的实体(比如在多用户聊天系统中的一个房间). 节点名所代表的实体,它的地址依赖于一个特定的域名;在 XMPP 的即时消息和出席信息应用系统中,这个地址是“纯 JID” <node@domain> 中的一部分。<br />
<br />
:一个节点名必须按 \[STRINGPREP\] 中的 Nodeprep profile 进行成功的字符转换。在比较两个节点ID之前,服务器必须(MUST),客户端应该(SHOULD)首先按 Nodeprep profile 转换每个ID的字符。<br />
<br />
===资源名===<br />
<br />
:资源名是一个可选的第三 ID,它放在域名的后面并由符号"/"分开。资源名可以跟在 <node@domain>后面也可以跟在 <domain> 后面。它通常表示一个特定的会话,连接(比如设备或者所在位置),或者一个附属于某个节点ID实体相关实体的对象(比如多用户聊天室中的一个参加者)。对于服务器和和其他客户端来说,资源名是不透明的。当它提供必需的信息以完成资源绑定(参见第七章)的时候,通常是由客户端来实现的(尽管可以由客户端向服务器请求完成),然后显示为“已连接的资源”。一个实体可以(MAY)并发维护多个已连接的资源。每个已连接的资源由不同的资源ID来区分。<br />
<br />
:一个资源名必须(MUST)按 \[STRINGPREP\] 中的 Resourceprep profile 进行成功的格式化。在比较两个资源ID之前,服务器必须(MUST),客户端应该(SHOULD)首先按 Resourceprep profile 转换每个ID的字符。<br />
<br />
===地址的确认===<br />
<br />
:在 SASL (见第六章)握手之后(如果必要的话,也在资源绑定(见第七章)之后),正在接收流信息的实体必须(MUST)确认初始实体的 ID 。<br />
<br />
:对于服务器间的通信,在 SASL 握手时,如果没有指明授权的ID,这个初始的实体应该(SHOULD)是经过认证实体(参见 简单认证和安全层协议 \[SASL\] 中的定义)授权的ID(见第六章)。<br />
<br />
:对于客户端和服务器的通信,在 SASL 握手时,如果没有指明授权的ID,“纯 JID” (<node@domain>)应该(SHOULD)是经过认证实体(参见 [SASL] 中的定义)授权的ID,“全 JID” (<node@domain/resource>)的资源ID部分应该(SHOULD)是由客户端和服务器在资源绑定的时候商定的(参见第七章)。<br />
<br />
:接收的实体必须(MUST)确保结果JID(包括节点名,域名,资源名以及分隔符)与本章前面部分描述的规则和格式相一致;为了满足这些约束条件,接收实体可能(MAY)需要把初始实体的发送方 JID 替换成接收实体认可的规范 JID。<br />
<br />
==XML流==<br />
<br />
===概览===<br />
<br />
:两个基本概念,XML流和XML节,使得在出席信息已知的实体之间,异步交换低负载的结构化信息成为可能。这两个术语定义如下:<br />
<br />
:XML流的定义:一个XML流是一个容器,包含了两个实体之间通过网络交换的XML元素。一个XML流是由一个XML打开标签 <stream> (包含适当的属性和名字空间声明)开始的,流的结尾则是一个XML关闭L标签 </stream> 。在流的整个生命周期,初始化它的实体可以通过流发送大量的XML元素,用于流的握手(例如 TLS 握手(第五章) 或 SASL 握手(第六章))或XML节(在这里指符合缺省名字空间的元素,包括<message/>,<presence/>, 或 <iq/> 元素)。“初始的流”由初始化实体(通常是一个客户端或服务器)和接收实体(通常是一个服务器)握手,从接收实体来看,它就是那个初始实体的"会话".初始化流允许从初始化实体到接收实体的单向通信;为了使接收实体能够和初始实体交换信息,接收实体必须发起一个反向的握手(应答流).<br />
<br />
:XML节的定义: 一个XML节是一个实体通过 XML 流向另一个实体发送的结构化信息中的一个离散的语义单位。一个XML节直接存在于根元素<stream/>的下一级,这样可以说是很好的匹配了[XML](译者注:在标准参考一节)的第43条.任何XML节都是从一个XML流的下一级的某个打开标签(如 <presence>)开始,到相应的关闭标签(如 </presence>)。一个XML节可以(MAY)包含子元素(相关的属性,元素, 和 XML 字符数据等) 以表达完整的信息.在这里定义的XML节仅限于<message/>, <presence/>, 和 <iq/> 元素,具体描述间见 XML Stanzas(第九章);为TLS握手(第五章)、SASL握手(第六章)、服务器回拨(第八章)的需要而发送的XML元素,不被认为是一个XML节。<br />
<br />
:设想一个客户端和服务器会话的例子。为了连接一个服务器,一个客户端必须(MUST)发送一个打开标签<stream>给服务器,初始化一个XML流,也可选择(OPTIONAL)在这之前发送一段文本声明XML版本和支持的字符集(参见文本声明的内容(第十一章第四节); 也可看字符编码(第十一章第五节))。视本地化策略和提供的服务而定,服务器应该(SHOULD)回复一个XML流给客户端,同样的,也可选择在这之前发送一段文本声明。一旦客户端完成了SASL握手(第六章),客户端可以(MAY)通过流发送不限量的XML节给网络中的任何接收者。当客户端想关闭这个流,它只需要简单的发送一个关闭标签</stream>给服务器(或者作为另一个选择,可能由服务器关闭这个流)。然后,客户端和服务器都应该(SHOULD)彻底地终止这个连接(通常是一个TCP连接)。<br />
<br />
:那些习惯认为XML是一个以文本为中心风格的人可能希望看看一个与服务器连接的客户端会话,包含两个 打开-关闭 XML文档:一个是从客户端到服务器,一个是从服务器到客户端。下图中,根元素<stream/> 可以被认为是每个“文档”的文档实体,这两个“文档”通过累积那些在XML上传输的XML节来搭建的。无论如何,下图只是方便理解;实际上XMPP并不处理文档而是处理XML流和XML节。<br />
<br />
:基本上,一个XML流相当于一个会话期间所有XML节的一个信封。我们可以简单的把它描述成下图:<br />
<br />
::|----------------------------<br />
<br />
::| <stream><br />
<br />
::|----------------------------<br />
<br />
::| <presence> <br />
<br />
::| <show/> <br />
<br />
::| </presence><br />
<br />
::|----------------------------<br />
<br />
::| <message to='foo'> <br />
<br />
::| <body/> <br />
<br />
::| </message> <br />
<br />
::|----------------------------<br />
<br />
::| <iq to='bar'><br />
<br />
::| <query/> <br />
<br />
::| </iq> <br />
<br />
::|----------------------------<br />
<br />
::| ... <br />
<br />
::|----------------------------<br />
<br />
::| </stream> <br />
<br />
::|----------------------------<br />
<br />
===绑定到TCP===<br />
<br />
:虽然有很多非必需的连接使用XML流来绑定\[TCP\]连接(两个实体可以通过别的机制来互联,比如通过\[HTPP\]连接轮询),本规范只定义了 XMPP 到 TCP 的绑定。在客户和服务器通信的过程中,服务器必须(MUST)允许客户端共享一个TCP连接来传输XML节,包括从客户端传到服务器和从服务器传到客户端。在服务器之间的通信过程中,服务器必须(MUST)用一个 TCP连接 向对方发送 XML节,另一个 TCP连接(由对方初始化)接收对方的XML节,一共两个 TCP连接。<br />
<br />
===流的安全===<br />
<br />
:在XMPP 1.0中,当XML流开始握手时,TLS应该(SHOULD)按 第五章:TLS的使用 中的规定来使用,SASL必须(MUST)按 第六章:SASL的使用 中的规定来使用。尽管可能(MAY)存在某种共有的机制能够保证双向安全,但是“初始化流”(比如从初始化实体发给接收实体的流)和“应答流”(比如从接收实体发给初始化实体的流)还是必须(MUST)安全的分开。在流被验证之间,实体不应该(SHOULD NOT) 尝试通过流发送XML节(第九章);就算它这样做了,对方的实体也不能(MUST NOT)接受这些XML节,并且应该(SHOULD)返回一个 <not-authorized/> 的流错误信息并且终止当前TCP连接上双方的XML流;注意,这仅仅是针对XML节(包含在缺省命名空间中的 <message/>, <presence/>, 和 <iq/> 元素),而不是指那些用于 TLS握手(第五章)、SASL握手(第六章)握手的流。<br />
<br />
===stream 属性===<br />
<br />
:stream 元素的属性如下:<br />
<br />
:* to -- 'to' 属性应(SHOULD)仅出现在初始化实体发给接收实体的 XML 流的头当中,并且它的值必须(MUST)是接收实体所在的主机名。在接收实体发送给初始化实体的 XML 流的头中不应该(SHOULD NOT)出现 'to' 属性。若 'to' 属性出现在应答流中,则初始化实体应(SHOULD)忽略它。<br />
<br />
:* from -- 'from' 属性应(SHOULD)仅出现在接收实体发给初始化实体的 XML 流的头当中,并且它的值必须(MUST)是为当前初始化实体授权的接收实体所在的主机名。注意,不应该(SHOULD NOT)有 'from'属性出现在初始实体发送给接收实体的 XML流的头中;无论如何,如果'from'属性出现在初始化流中,接收实体应该(SHOULD)忽略它。<br />
<br />
:* id -- 'id'属性应该(SHOULD)仅用于接收实体发送给初始化实体 XML流的头。这个属性是一个由接收实体创建的具有唯一性的ID,一个初始实体和接收实体之间的会话ID,并且它在接收方的应用程序中(通常是一个服务器)必须(MUST)是唯一的。注意,这个流 ID 必须是足够安全的,所以它必须是不可预知的和不可重复的(参见[RANDOM] 了解如何获得随机性以保证安全性)。不应该(SHOULD NOT)有 'id'属性出现在初始实体发送给接收实体的 XML流的头中;无论如何,如果'id'属性出现在初始化流中,接收实体应该(SHOULD)忽略它。<br />
<br />
:* xml:lang -- 'xml:lang'属性(定义在\[XML\]中的第二章第十二节)应该(SHOULD)包含在初始化实体发给接收实体的 XML流的头中,以指定在流中传输的可读XML字符所使用的缺省语言。如果这个属性出现了,接收实体应该(SHOULD)记住它的值,作为初始化流和应答流的缺省属性;如果这个属性没有出现,接收实体应该(SHOULD)用一个可配置的缺省值用于双方的流,这个属性值必须(MUST)在应答流的头中传达。对于所有初始化流中传输的节,如果初始实体没有提供'xml:lang'属性,接收实体应该(SHOULD)应用缺省值;如果初始实体提供了'xml:lang'属性,接收实体不能(MUST NOT)修改或删除它(参见第九章第一节第五小节 xml:lang)。'xml:lang'属性的值必须(MUST)是一个 NMTOKEN (定义在\[XML\]的第二章第三节) 并且必须(MUST)遵守 RFC 3066 \[LANGTAGS\] 规定的格式。<br />
<br />
:* version -- version属性(最少需要"1.0")为本规范中和流相关的协议提供了支持。关于这个属性的生成和处理的详细规则将在下文中定义。<br />
<br />
:我们现在可以总结如下:<br />
<br />
{|border="1" cellspacing="0" <br />
! !! 初始化方发给接收方 !! 接收方发给初始化方<br />
|-<br />
|to || 接收方的主机名 || 忽略<br />
|-<br />
|from || 忽略 || 接收方的主机名<br />
|-<br />
|id || 忽略 || 会话键值<br />
|-<br />
|xml:lang || 缺省语言 || 缺省语言<br />
|-<br />
|version || 支持XMPP 1.0 || 支持XMPP 1.0<br />
|}<br />
<br />
====版本支持====<br />
<br />
:在这里XMPP的版本是"1.0";准确地说,这里囊括了和流相关的所有协议(TLS的使用 (第五章),SASL的使用(第六章), 和流错误(第四章第七节)),以及三个定义好的XML节类型(<message/>,<presence/>,和 <iq/>)。XMPP版本号的编号顺序是“<主版本号>.<副版本号>”。主版本和副版本号必须(MUST)是独立的整数并且每个号码可以(MAY)单独以阿拉伯数字增长。这样,"XMPP 2.4"的版本将比"XMPP 2.13"更低。号码前面 的“0”(比如XMPP 6.01)必须(MUST)被接收方忽略并且不能(MUST NOT)被发送出去.<br />
<br />
:如果流和节的格式或者必需的处理方式有了显著的改变,以至于老版本的实体如果只是简单的忽略它不理解的节和属性并且继续像老版本一样的处理方式,会使得老版本的实体不能够和新版本的实体交互,只有在这时候主版本号才应该(SHOULD)增加。副版本号显示新的性能,它必须(MUST)被副版本号更低的实体忽略,但被高(副)版本号的实体用于了解信息。例如,一个副版本号显示处理某种新定义的"type"属性的值(用于message,presence或IQ节)的能力;副版本号高的实体将会了解到与之通信的对方不能够理解这个"type"属性的值,所以将不会发送它。<br />
<br />
:以下规则是用于'版本'属性在实现流的头信息时如何生成和处理:<br />
<br />
:# 初始化实体必须(MUST)在初始化流的头信息中把'版本'的值设置成它所支持的最高版本。(比如,如果最高版本支持就是本规范,那么它必须(MUST)设置成"1.0").<br />
:# 接收实体必须(MUST)在应答流的头信息中把'版本'的值设置成初始化实体所提供的版本或它所支持的最高版本,取其中版本号较低的那一个。接收实体必须(MUST)把主版本号和副版本号作为数字来比较,而不是对"主版本号.副版本号"这个字符串进行比较.<br />
:# 如果在应答流的头信息的版本号中至少有一个主版本号低于初始化流的头信息的版本号,并且如前所述,新版本的实体不能够和旧版本实体交互,初始化实体应该(SHUOULD)生成一个<unsupported-version/>的流错误信息并终止XML流和它的TCP连接。<br />
:# 如果一个实体收到一个头信息中没有'version'属性的流,这个实体必须(MUST)把对方实体的'version'当成'0.0'并且在它发送的应答流的头中也不应该(SHOULD NOT)包含'version'属性.<br />
<br />
===名字空间声明===<br />
<br />
:流的元素必须(MUST)同时满足一个流名字空间声明和一个缺省名字空间声明("名字空间声明"定义在 XML 名字空间定义 \[XML-NAMES\]中).关于流名字空间和缺省名字空间的详细信息,参考 名字空间的名字和前缀(第十一章第二节).<br />
<br />
===流的特性===<br />
<br />
:如果初始化的实体在初始化流的头信息中设置'version'属性的信息为"1.0",接收实体必须(MUST)向初始化实体发送一个 <features/> 子元素以声明任何可供协商的流一级的特性(或者其他需要声明的能力).目前,这仅用于声明本文中定义的 TLS的使用(第五章),SASL的使用(第六章)和资源绑定(第七章),以及 [XMPP-IM|XMPP文档列表/XMPP正式RFC标准/RFC3921] 中定义的会话的建立;无论如何,流特性这一功能将来可以用于声明任何可协商的特性.如果一个实体不理解或支持安全特性,它应该(SHOULD)忽略它.如果要在一个非安全相关的特性(比如资源绑定)被提议之前,完成一个或多个安全特性(比如TLS和SASL)的协商,这个非安全相关的特性不应该(SHOULD NOT)在相应的安全特性协商完毕之前被声明.<br />
<br />
===流错误===<br />
<br />
:流的根元素可以(MAY)包含一个 <error/> 子元素,由流的名字空间前缀作为它的前缀。这个"错误"子元素必须(MUST)由感知到发生了流级别错误的实体发送(通常是一个服务器而不是一个客户端)。<br />
<br />
====规则====<br />
<br />
:以下规则适用于流级别的错误:<br />
<br />
:* 它假定所有流级别的错误都是不可恢复的;所以,如果一个错误发生在流级别,发现这个错误的实体必须(MUST)发送一个流错误信息给另一个实体,发送一个关闭标签 </stream>,并终止这个流所在的TCP连接。<br />
<br />
:* 如果这个错误发生在流刚开始设置的时候,接收实体必须(MUST)仍然发送一个开放标签 <stream> ,并在流元素中包含一个<error/>的子元素,然后发送一个关闭标签 </stream>,最后终止相应的TCP连接。在这种情况下,如果初始化实体在 'to' 属性中提供了一个未知的主机名,服务器应该(SHOULD)在终止之前,先在流的头信息的 'from' 属性中提供一个服务器认证的主机名.<br />
<br />
====语法====<br />
<br />
:流错误的语法如下:<br />
<br />
<source lang="xml"><br />
<stream:error><br />
<defined-condition xmlns='urn:ietf:params:xml:ns:xmpp-streams'/><br />
<text xmlns='urn:ietf:params:xml:ns:xmpp-streams' xml:lang='langcode'><br />
OPTIONAL descriptive text<br />
</text><br />
[OPTIONAL application-specific condition element]<br />
</stream:error><br />
</source><br />
<br />
:<error/>元素:<br />
:* 必须(MUST)包含一个子元素以描述一个下文定义的节错误条件;这个子元素必须(MUST)符合'urn:ietf:params:xml:ns:xmpp-streams'名字空间.<br />
<br />
:* 可以(MAY)包含一个 <text/> 子元素,用XML字符数据描述错误的细节;这个元素必须(MUST)符合'urn:ietf:params:xml:ns:xmpp-streams'名字空间并且应该(SHOULD)拥有一个'xml:lang'属性表明XML字符数据的自然语言。<br />
<br />
:* 可以(MAY)包含一个子元素用于描述一个明确的应用程序错误条件;这个元素必须(MUST)符合一个应用程序定义的名字空间,并且它的结构是由那个名字空间定义的。<br />
<br />
: <text/> 元素是可选的(OPTIONAL)。如果有这个元素,它应该(SHOULD)仅用于提供描述或调试信息以补充一个已定义的条件或应用程序定义的条件。它不应该(SHOULD NOT)被一个应用程序当成一个可编程的信息。它不应该(SHOULD NOT)被用于向用户表达错误信息,但是可以(MAY)作为和条件元素相关的错误信息之外的附加说明。<br />
<br />
====已定义的条件====<br />
<br />
:以下流级别的错误条件是已定义的:<br />
<br />
:* <bad-format/> -- 实体已经发送XML但是不能被处理;这个错误可以(可以)被更多特定的XML相关的错误替换,比如 <bad-namespace-prefix/>, <invalid-xml/>, <restricted-xml/>, <unsupported-encoding/>, 以及 <xml-not-well-formed/>,尽管更多特定的错误是首选的。 <br />
<br />
:* <bad-namespace-prefix/> -- 实体发送的名字空间前缀不被支持,或者在一个需要某种前缀的元素中没有发送一个名字空间前缀(参见 XML Namespace Names and Prefixes (第十一章第二节)).<br />
<br />
:* <conflict/> -- 服务器正在关闭为这个实体激活的流,因为一个和已经存在的流有冲突的新的流已经被初始化。<br />
<br />
:* <connection-timeout/> -- 实体已经很长时间没有通过这个流发生任何通信流量(可由一个本地服务策略来配置).<br />
<br />
:* <host-gone/> -- 初始化实体在流的头信息中提供的'to'属性的值所指定的主机已经不再由这台服务器提供<br />
<br />
:* <host-unknown/> -- 由初始化实体在流的头信息中提供的 'to' 属性的值和由服务器提供的主机名不一致.<br />
<br />
:* <improper-addressing/> -- 一个在两台服务器之间传送的节缺少 'to' 或 'from' 属性(或者这个属性没有值).<br />
<br />
:* <internal-server-error/> -- 服务器配置错误或者其他未定义的内部错误,使得服务器无法提供流服务.<br />
<br />
:* <invalid-from/> -- 在'from'属性中提供的 JID 或 主机名地址,和认证的 JID不匹配 或服务器之间无法通过SASL(或回拨)协商出合法的域名,或客户端和服务器之间无法通过它进行认证和资源绑定。<br />
<br />
:* <invalid-id/> -- 流 ID 或回拨 ID 是非法的或和以前提供的 ID 不一致.<br />
<br />
:* <invalid-namespace/> -- 流名字空间和 "http://etherx.jabber.org/streams" 不相同或回拨名字空间和 "jabber:server:dialback" 不相同.(参考 XML Namespace Names and Prefixes (第十一章第二节)).<br />
<br />
:* <invalid-xml/> -- 实体通过流发送了一个非法的XML给执行验证的服务器 (参考 Validation (第十一章第三节)).<br />
<br />
:* <not-authorized/> -- 实体试图在流被验证之前发送数据或不被许可执行一个和流协商有关的动作,接收实体在发送错误信息之前不允许(MUST NOT)处理厌恶的节。<br />
<br />
:* <policy-violation/> -- 实体违反了某些本地服务策略;服务器可以(MAY)选择在 <text/> 元素或应用程序定义的错误条件(元素)中详细说明策略。<br />
<br />
:* <remote-connection-failed/> -- 服务器无法正确连接到用于验证或授权的远程实体。<br />
<br />
:* <resource-constraint/> -- 服务器缺乏必要的系统资源为流服务。<br />
<br />
:* <restricted-xml/> -- 实体试图发送受限的XML特性,比如一个注释,处理指示,DTD,实体参考,或保留的字符(参考 Restrictions (第十一章第一节)).<br />
<br />
:* <see-other-host/> -- 服务器将不提供服务给初始化实体但是把它重定向到另一台主机;服务器应该(SHOULD)在<see-other-host/>元素的XML字符数据中指明替代服务器名或IP地址(它必须(必须)是合法的域名标识)。<br />
<br />
:* <system-shutdown/> -- 服务器正在关机并且所有激活的流正在被关闭。<br />
<br />
:* <undefined-condition/> -- 错误条件不在本文已定义的错误条件列表之中;这个错误条件应该(SHOULD)仅用于"应用程序定义条件"元素.<br />
<br />
:* <unsupported-encoding/> -- 初始化实体以一个服务器不不支持的编码方式编码了一个流(参照Character Encoding (第十一章第五节)).<br />
<br />
:* <unsupported-stanza-type/> -- 初始化实体发送了一个流的一级子元素但是服务器不支持.<br />
<br />
:* <unsupported-version/> -- 由初始化实体在流的头信息中指定的'version'属性的值所指定的版本不被服务器支持;服务器可以(MAY)在<text/>元素中指定一个它支持的版本号.<br />
<br />
:* <xml-not-well-formed/> -- 初始化实体发送了一个不规范的XML(参考[XML]).<br />
<br />
====应用程序定义条件====<br />
<br />
:大家知道,应用程序可以(MAY)在error元素中包含一个适当名字空间的子元素来提供一个应用程序定义流错误信息."应用程序定义"元素应该(SHOULD)补充或甚至限定一个已定义的元素.所以 <error/> 元素将包含两个或三个子元素:<br />
<br />
<source lang="xml"><br />
<stream:error><br />
<xml-not-well-formed xmlns='urn:ietf:params:xml:ns:xmpp-streams'/><br />
<text xml:lang='en' xmlns='urn:ietf:params:xml:ns:xmpp-streams'><br />
Some special application diagnostic information!<br />
</text><br />
<escape-your-data xmlns='application-ns'/><br />
</stream:error><br />
</stream:stream><br />
</source><br />
<br />
===简化的流示例===<br />
<br />
:这里包含两个简化的例子,描述了基于流的客户端在服务器上的“会话”(这里"C"表示从客户端发给服务器,"S"表示从服务器发给客户端);这些例子只是用于举例说明原理.<br />
<br />
:一个基本的 "会话":<br />
<br />
<source lang="xml"><br />
C: <?xml version='1.0'?><br />
<stream:stream to='example.com' xmlns='jabber:client' xmlns:stream='http://etherx.jabber.org/streams' version='1.0'><br />
<br />
S: <?xml version='1.0'?><br />
<stream:stream from='example.com' id='someid' xmlns='jabber:client' xmlns:stream='http://etherx.jabber.org/streams' version='1.0'><br />
... encryption, authentication, and resource binding ...<br />
<br />
C: <message from='juliet@example.com' to='romeo@example.net' xml:lang='en'><br />
<br />
C: <body>Art thou not Romeo, and a Montague?</body><br />
<br />
C: </message><br />
<br />
S: <message from='romeo@example.net' to='juliet@example.com' xml:lang='en'><br />
<br />
S: <body>Neither, fair saint, if either thee dislike.</body><br />
<br />
S: </message><br />
<br />
C: </stream:stream><br />
<br />
S: </stream:stream><br />
</source><br />
<br />
<br />
:一个不成功的 "会话" :<br />
<br />
<source lang="xml"><br />
C: <?xml version='1.0'?><br />
<stream:stream to='example.com' xmlns='jabber:client' xmlns:stream='http://etherx.jabber.org/streams' version='1.0'><br />
<br />
S: <?xml version='1.0'?><br />
<stream:stream from='example.com' id='someid' xmlns='jabber:client' xmlns:stream='http://etherx.jabber.org/streams' version='1.0'><br />
... encryption, authentication, and resource binding ...<br />
<br />
C: <message xml:lang='en'><br />
<body>Bad XML, no closing body tag!<br />
</message><br />
<br />
S: <stream:error><br />
<xml-not-well-formed xmlns='urn:ietf:params:xml:ns:xmpp-streams'/><br />
</stream:error><br />
<br />
S: </stream:stream><br />
</source><br />
<br />
==TLS 的使用==<br />
<br />
===概览===<br />
<br />
:XMPP包含的一个保证流安全的方法来防止篡改和偷听.这个传输层安全协议[TLS]的频道加密方法, 模拟了类似的其他"STARTTLS"(见RFC 2595 [USINGTLS])的扩展,如 IMAP [IMAP], POP3 [POP3], and ACAP [ACAP]."STARTTLS"的扩展名字空间是'urn:ietf:params:xml:ns:xmpp-tls'.<br />
<br />
:一个给定域的管理员可以(MAY)要求客户端和服务器通信以及服务器之间通信时使用TLS,或者两者都要求。客户端应该(SHOULD)在尝试完成 SASL (第六章)握手之前使用 TLS,服务器应该(SHOULD)在两个域之间使用 TLS 以保证服务器间通信的安全。<br />
<br />
:以下是使用规则:<br />
<br />
::# 一个遵守本协议的初始化实体必须(MUST)在初始化流的头信息中包含一个'version'属性并把值设为“1.0”。<br />
::# 如果TLS握手发生在两个服务器之间,除非服务器声称的DNS主机名已经被解析(见第十四章第四节 Server-to-Server Communications),通信不能(MUST NOT)继续进行。<br />
::# 当一个遵守本协议的接收实体接收了一个初始化流(它的头信息中包含一个'version'属性并且值设为“1.0”),在发送应答流的的头信息(其中包含版本标记)之后,它必须发送(MUST)<starttls/>元素(名字空间为 'urn:ietf:params:xml:ns:xmpp-tls')以及其他它支持的流特性 。<br />
::# 如果初始化实体选择使用TLS,TLS握手必须在SASL握手之前完成;这个顺序用于帮助保护SASL握手时发送的认证信息的安全,同时可以在必要的时候在TLS握手之前为SASL外部机制提供证书。<br />
::# TLS握手期间,一个实体不能(MUST NOT)在流的根元素中发送任何空格符号作为元素的分隔符(在下面的TLS示例中的任何空格符都仅仅是为了便于阅读);这个禁令用来帮助确保安全层字节精度。<br />
::# 接收实体必须(MUST)在发送<proceed/> 元素的关闭符号">" 之后立刻开始TLS协商。初始化实体必须(MUST)在从接收实体接收到<proceed/> 元素的关闭符号">" 之后立刻开始TLS协商。<br />
::# 初始化实体必须(MUST)验证接收实体出示的证书;关于证书验证流程参见Certificate Validation ( 第十四章第二节)。<br />
::# 证书必须(MUST)检查初始化实体(比如一个用户)提供的主机名;而不是通过DNS系统解析出来的主机名;例如,如果用户指定一个主机名"example.com"而一个DNS SRV [SRV]查询返回"im.example.com",证书必须(MUST)检查"example.com".如果任何种类的XMPP实体(例如客户端或服务器)的JID出现在一个证书里,它必须(MUST)表现为一个别名实体里面的UTF8字符串,存在于subjectAltName之中。如何使用 [ASN.1] 对象标识符 "id-on-xmppAddr" 定义在本文的第五章第一节第一小节。<br />
::# 如果 TLS 握手成功了,接收实体必须(MUST) 丢弃TLS 生效之前从初始化实体得到的任何不可靠的信息.<br />
::# 如果 TLS 握手成功了,初始化实体必须(MUST) 丢弃TLS 生效之前从接收实体得到的任何不可靠的信息. <br />
::# 如果 TLS 握手成功了,接收实体不能(MUST NOT)在流重新开始的时候通过提供其他的流特性来向初始化实体提供 STARTTLS 扩展.<br />
::# 如果 TLS 握手成功了,初始化实体必须(MUST)继续进行SASL握手。<br />
::# 如果 TLS 握手失败了,接收实体必须(MUST)终止XML流和相应的TCP连接。<br />
::# 关于必须(MUST)支持的机制,参照 Mandatory-to-Implement Technologies (第十四章第七节) 。<br />
<br />
====用于 XMPP 地址的 ASN.1 对象标识符====<br />
<br />
:上文提到的[ASN.1] 对象标识符 "id-on-xmppAddr"定义如下:<br />
<br />
::id-pkix OBJECT IDENTIFIER ::= { iso(1) identified-organization(3)<br />
<br />
::dod(6) internet(1) security(5) mechanisms(5) pkix(7) }<br />
<br />
::id-on OBJECT IDENTIFIER ::= { id-pkix 8 } \-\- other name forms<br />
<br />
::id-on-xmppAddr OBJECT IDENTIFIER ::= { id-on 5 }<br />
<br />
::XmppAddr ::= UTF8String<br />
<br />
:对象标识符也可以(MAY)使用点分隔的格式,如 "1.3.6.1.5.5.7.8.5".<br />
<br />
===叙述===<br />
<br />
:当一个初始化实体用TLS保护一个和接收实体之间的流,其步骤如下:<br />
<br />
::# 初始化实体打开一个TCP连接,发送一个打开的XML流头信息(其'version'属性设置为"1.0")给接收实体以初始化一个流。<br />
::# 接收实体打开一个TCP连接,发送一个XML流头信息(其'version'属性设置为"1.0")给初始化实体作为应答。<br />
::# 接收实体向初始化实体提议STARTTLS范围(包括其他支持的流特性),如果TLS对于和接收实体交互是必需的,它应该(SHOULD)在<starttls/>元素中包含子元素<required/>.<br />
::# 初始化实体发出STARTTLS命令(例如, 一个符合'urn:ietf:params:xml:ns:xmpp-tls'名字空间的 <starttls/> 元素) 以通知接收实体它希望开始一个TLS握手来保护流。<br />
::# 接收实体必须(MUST)以'urn:ietf:params:xml:ns:xmpp-tls'名字空间中的<proceed/>元素或<failure/>元素应答。如果失败,接收实体必须(MUST)终止XML流和相应的TCP连接。如果继续进行,接收实体必须(MUST)尝试通过TCP连接完成TLS握手并且在TLS握手完成之前不能(MUST NOT)发送任何其他XML数据。<br />
::# 初始化实体和接收实体尝试完成TLS握手。(要符合\[TLS\]规范)<br />
::# 如果 TLS 握手不成功, 接收实体必须(MUST)终止 TCP 连接. 如果 TLS 握手成功, 初始化实体必须(MUST)发送给接收实体一个打开的XML流头信息来初始化一个新的流(先发送一个关闭标签</stream>是不必要的,因为接收实体和初始化实体必须(MUST)确保原来的流在TLS握手成功之后被关闭) 。<br />
::# 在从初始化实体收到新的流头信息之后,接收实体必须(MUST)发送一个新的XML流头信息给初始化实体作为应答,其中应包含可用的特性但不包含STATRTTLS特性。<br />
<br />
===客户端-服务器 示例===<br />
<br />
:以下例子展示一个客户端使用STARTTLS保护数据流 (注意: 以下步骤举例说明协议中的失败案例;在这个例子中它们并不详尽并且也不是必须被数据传输触发的).<br />
<br />
:步骤 1: 客户端初始化流给服务器:<br />
<br />
<source lang="xml"><br />
<stream:stream xmlns='jabber:client' xmlns:stream='http://etherx.jabber.org/streams' to='example.com' version='1.0'><br />
</source><br />
<br />
:步骤 2: 服务器发送一个流标签给客户端作为应答:<br />
<br />
<source lang="xml"><br />
<stream:stream xmlns='jabber:client' xmlns:stream='http://etherx.jabber.org/streams' id='c2s_123' from='example.com' version='1.0'><br />
</source><br />
<br />
:步骤 3: 服务器发送 STARTTLS 范围给客户端(包括验证机制和任何其他流特性):<br />
<br />
<source lang="xml"><br />
<stream:features><br />
<starttls xmlns='urn:ietf:params:xml:ns:xmpp-tls'><br />
<required/><br />
</starttls><br />
<mechanisms xmlns='urn:ietf:params:xml:ns:xmpp-sasl'><br />
<mechanism>DIGEST-MD5</mechanism><br />
<mechanism>PLAIN</mechanism><br />
</mechanisms><br />
</stream:features><br />
</source><br />
<br />
:步骤 4: 客户端发送 STARTTLS 命令给服务器:<br />
<br />
<source lang="xml"><br />
<starttls xmlns='urn:ietf:params:xml:ns:xmpp-tls'/><br />
</source><br />
<br />
:步骤 5: 服务器通知客户端可以继续进行:<br />
<br />
<source lang="xml"><br />
<proceed xmlns='urn:ietf:params:xml:ns:xmpp-tls'/><br />
</source><br />
<br />
:步骤 5 (或者): 服务器通知客户端 TLS 握手失败并关闭流和TCP连接:<br />
<br />
<source lang="xml"><br />
<failure xmlns='urn:ietf:params:xml:ns:xmpp-tls'/><br />
</stream:stream><br />
</source><br />
<br />
:步骤 6: 客户端和服务器尝试通过已有的TCP连接完成 TLS 握手.<br />
<br />
:步骤 7: 如果 TLS 握手成功, 客户端初始化一个新的流给服务器:<br />
<br />
<source lang="xml"><br />
<stream:stream xmlns='jabber:client' xmlns:stream='http://etherx.jabber.org/streams' to='example.com' version='1.0'><br />
</source><br />
<br />
:步骤 7 (或者): 如果 TLS 握手不成功, 服务器关闭 TCP 连接.<br />
<br />
:步骤 8: 服务器发送一个流头信息应答客户端,其中包括任何可用的流特性:<br />
<br />
<source lang="xml"><br />
<stream:stream xmlns='jabber:client' xmlns:stream='http://etherx.jabber.org/streams' from='example.com' id='c2s_234' version='1.0'><br />
<stream:features><br />
<mechanisms xmlns='urn:ietf:params:xml:ns:xmpp-sasl'><br />
<mechanism>DIGEST-MD5</mechanism><br />
<mechanism>PLAIN</mechanism><br />
<mechanism>EXTERNAL</mechanism><br />
</mechanisms><br />
</stream:features><br />
</source><br />
<br />
:步骤 9: 客户端继续 SASL 握手 (第六章).<br />
<br />
===服务器-服务器示例===<br />
<br />
:以下例子展示两个服务器之间使用STARTTLS保护数据流 (注意: 以下步骤举例说明协议中的失败案例;在这个例子中它们并不详尽并且也不是必须被数据传输触发的).<br />
<br />
:步骤 1: Server1 初始化流给 Server2:<br />
<br />
<source lang="xml"><br />
<stream:stream xmlns='jabber:server' xmlns:stream='http://etherx.jabber.org/streams' to='example.com' version='1.0'><br />
</source><br />
<br />
:步骤 2: Server2 发送一个流标签给 Server1 作为应答:<br />
<br />
<source lang="xml"><br />
<stream:stream xmlns='jabber:server' xmlns:stream='http://etherx.jabber.org/streams' from='example.com' id='s2s_123' version='1.0'><br />
</source><br />
<br />
:步骤 3: Server2 发送 STARTTLS 范围给 Server1 ,包括验证机制和任何其他流特性:<br />
<br />
<source lang="xml"><br />
<stream:features><br />
<starttls xmlns='urn:ietf:params:xml:ns:xmpp-tls'><br />
<required/><br />
</starttls><br />
<mechanisms xmlns='urn:ietf:params:xml:ns:xmpp-sasl'><br />
<mechanism>DIGEST-MD5</mechanism><br />
<mechanism>KERBEROS_V4</mechanism><br />
</mechanisms><br />
</stream:features><br />
</source><br />
<br />
:步骤 4: Server1 发送 STARTTLS 命令给 Server2:<br />
<br />
<source lang="xml"><br />
<starttls xmlns='urn:ietf:params:xml:ns:xmpp-tls'/><br />
</source><br />
<br />
:步骤 5: Server2 通知 Server1 允许继续进行:<br />
<br />
<source lang="xml"><br />
<proceed xmlns='urn:ietf:params:xml:ns:xmpp-tls'/><br />
</source><br />
<br />
:步骤 5 (或者): Server2 通知 Server1 TLS握手失败并关闭流:<br />
<br />
<source lang="xml"><br />
<failure xmlns='urn:ietf:params:xml:ns:xmpp-tls'/><br />
</stream:stream><br />
</source><br />
<br />
:步骤 6: Server1 和 Server2 尝试通过 TCP 完成 TLS 握手.<br />
<br />
:步骤 7: 如果 TLS 握手成功, Server1 初始化一个新的流给 Server2:<br />
<br />
<source lang="xml"><br />
<stream:stream xmlns='jabber:server' xmlns:stream='http://etherx.jabber.org/streams' to='example.com' version='1.0'><br />
</source><br />
<br />
:步骤 7 (或者): 如果 TLS 握手不成功, Server2 关闭 TCP 连接.<br />
<br />
:步骤 8: Server2 发送一个包含任何可用流特性的流头信息给 Server1 :<br />
<br />
<source lang="xml"><br />
<stream:stream xmlns='jabber:server' xmlns:stream='http://etherx.jabber.org/streams' from='example.com' id='s2s_234' version='1.0'><br />
<stream:features><br />
<mechanisms xmlns='urn:ietf:params:xml:ns:xmpp-sasl'><br />
<mechanism>DIGEST-MD5</mechanism><br />
<mechanism>KERBEROS_V4</mechanism><br />
<mechanism>EXTERNAL</mechanism><br />
</mechanisms><br />
</stream:features><br />
</source><br />
<br />
:步骤 9: Server1 继续进行 SASL 握手(第六章).<br />
<br />
==SASL 的使用==<br />
<br />
===概览===<br />
<br />
:XMPP 有一个验证流的方法,即XMPP特定的SASL(简单验证和安全层)[SASL]。SASL提供了一个通用的方法为基于连接的协议增加验证支持,而XMPP使用了一个普通的XML名字空间来满足SASL的需要。<br />
<br />
:以下规则应用于:<br />
<br />
:# 如果SASL协商发生在两台服务器之间,除非服务器宣称的DNS主机名得到解析,否则不能(MUST NOT)进行通信。(参见 服务器间的通信(第十四章第四节)).<br />
:# 如果初始化实体有能力使用 SASL 协商, 它必须(MUST)在初始化流的头信息中包含一个值为"1.0"的属性'version'。<br />
:# 如果接收实体有能力使用 SASL 协商, 它必须(MUST)在应答从初始化实体收到的打开流标签时(如果打开的流标签包含一个值为"1.0"的'version'属性),通过'urn:ietf:params:xml:ns:xmpp-sasl'名字空间中的<mechanisms/>元素声明一个或多个验证机制.<br />
:# 当 SASL 协商时, 一个实体不能(MUST NOT)在流的根元素中发送任何空格符号(匹配 production [3] content of [XML])作为元素之间的分隔符(在以下的SASL例子中任何空格符号的出现仅仅是为了增加可读性); 这条禁令帮助确保安全层字节的精确度。<br />
:# 当SASL握手时,在XML元素中使用的任何 XML 字符数据必须被编码成 base64, 编码遵循 RFC 3548 第三章的规定。<br />
:# 如果一个 简单名字"simple username" 规范被选定的SASL机制所支持,(比如, 这被 DIGEST-MD5 和 CRAM-MD5 机制支持但不被 EXTERNAL 和 GSSAPI 机制支持), 验证的时候初始化实体应该(SHOULD)在服务器间通信时提供 简单名字 自身的发送域(IP地址或包含在一个域标识符中的域名全称),在客户端与服务器之间通信时提供注册用户名(包含在一个XMPP节点标识符中的用户或节点名)。<br />
:# 如果初始化实体希望以另一个实体的身份出现并且SASL机制支持授权ID的传输,初始化实体在SASL握手时必须(MUST)提供一个授权ID。如果初始化实体不希望以另一个实体的身份出现,初始化实体在SASL握手时不能(MUST NOT)提供一个授权ID。在 [SASL] 的定义中,除非授权ID不同于从验证ID(详见[SASL])中得到的缺省的授权ID,初始化实体不能(MUST NOT)提供授权ID。如果提供了,这个授权ID的值必须(MUST)是<domain>的格式(对于服务器来说)或<node@domain>的格式(对于客户端来说). <br />
:# 在成功进行包括安全层的SASL握手之后,接收实体必须(MUST)丢弃任何从初始化实体得到的而不是从SASL协商本身获得的信息。<br />
:# 在成功进行包括安全层的SASL握手之后,初始化实体必须(MUST)丢弃任何从接收实体得到的而不是从SASL协商本身获得的信息。<br />
:# 参看 强制执行的技术 (第十四章第七节) ,了解关于必须(MUST)支持的机制.<br />
<br />
===叙述===<br />
<br />
:一个初始化实体使用SASL和接收实体做验证的步骤如下:<br />
<br />
:# 初始化实体请求SASL验证,它发送一个打开的XML流头信息给接收实体,其'version'属性的值为"1.0".<br />
:# 在发送一个XML流头回复之后,接收实体声明一个可用的SASL验证机制清单;每个机制作为一个<mechanism/>元素,作为子元素包含在<mechanisms/>容器元素(其名字空间为'urn:ietf:params:xml:ns:xmpp-sasl')中,而<mechanisms/>则包含在流名字空间中的<features/>元素中。如果在使用任何验证机制之前需要使用TLS(见第五章),接收实体不能(MUST NOT)在TLS握手之前提供可用的SASL验证机制清单。如果初始化实体在优先的TLS协商过程中呈现了一个合法的证书,接收实体应该(SHOULD)在SASL握手中提出一个SASL外部机制给初始化实体,尽管这个外部机制可以(MAY)在其它环境下提供。<br />
:# 初始化实体发送一个符合'urn:ietf:params:xml:ns:xmpp-sasl'名字空间的<auth/>元素(其中包含了适当的'mechanism'属性值)给接收实体,以选择一个机制。如果这个机制支持或需要,这个元素可以(MAY)包含XML字符数据(在SASL术语中,即“初始化应答”);如果初始化实体需要发送一个零字节的初始化应答,它必须(MUST)传输一个单独的等号作为应答,这表示应答有效但不包含数据。<br />
:# 如果必要,接收实体向初始化实体发送一个符合'urn:ietf:params:xml:ns:xmpp-sasl'名字空间的<challenge/>元素来发出挑战;这个元素可以(MAY)包含XML字符数据(必须按照初始化实体选择的SASL机制进行一致性运算)。<br />
:# 初始化实体向接收实体发送符合'urn:ietf:params:xml:ns:xmpp-sasl'名字空间的<response/>元素作为应答;这个元素可以(MAY)包含XML字符数据(必须按照初始化实体选择的SASL机制进行一致性运算)。<br />
:# 如果必要,接收实体发送更多的挑战给初始化实体,初始化实体发送更多的回应。<br />
<br />
:这一系列的 挑战/应答 组,持续进行直到发生以下三件事中的一件为止:<br />
<br />
:# 初始化实体向接收实体发送符合'urn:ietf:params:xml:ns:xmpp-sasl'名字空间的<abort/>元素以中止握手。在接收到<abort/>元素之后,接收实体应该(SHOULD)允许一个可配置的但是合理的重试次数(至少2次),然后它必须(MUST)终止TCP连接;这使得初始化实体(如一个最终用户客户端)能够容忍可能不正确的credentials(如密码输入错误)而不用强制重新连接。<br />
:# 接收实体向初始化实体发送符合'urn:ietf:params:xml:ns:xmpp-sasl'名字空间的<failure/>元素以报告握手失败(详细的失败原因应该在<failure/>的一个适当的子元素中沟通,在第六章第四节中的SASL Errors中定义)。如果失败的情况发生了,接收实体应该(SHOULD)允许一个可配置的但是合理的重试次数(至少2次), 然后它必须(MUST)终止TCP连接;这使得初始化实体(如一个最终用户客户端)能够容忍可能不正确的credentials(如密码输入错误)而不用强制重新连接。<br />
:# 接收实体向初始化实体发送符合'urn:ietf:params:xml:ns:xmpp-sasl'名字空间的<success/>元素以报告握手成功;如果所选择的SASL机制要求,这个元素可以(MAY)包含XML字符数据(见SASL术语,“成功的额外数据”)。接收到<success/> 元素之后,初始化实体必须(MUST)发送一个打开的XML流头信息给接收实体以发起一个新的的流(不需要先发送一个 </stream>标签,因为在发送和接收到<success/>元素之后,接收实体和初始化实体必须确认原来的流被关闭了)。从初始化实体接收到新的流头信息之后,接收实体必须(MUST)发送一个新的流头信息给初始化实体作为回应,附上任何可用的特性(但不包括 STARTTLS 和 SASL 特性)或一个空的 <features/> 元素(这表示没有更多的特性可用);任何没有在本文定义的附加特性必须(MUST)在XMPP的相关扩展中定义。<br />
<br />
===SASL 定义===<br />
<br />
:[SASL]的必要条件要求通过协议定义来提供以下信息:<br />
<br />
::service name(服务名): "xmpp"<br />
<br />
::initiation sequence(开始序列): 当初始化实体提供一个打开的XML流头信息并且接收实体善意回应之后,接收实体提供一个可接受的验证方法清单。初始化实体从这个清单中选择一个方法,把它作为 <auth/> 元素的 'mechanism' 属性的值发送给接收实体,也可以选择发送一个初始化应答以避免循环。<br />
<br />
::exchange sequence(交换序列): 挑战和回应的交换,从接收实体发送给初始化实体的 <challenge/> 元素和从初始化实体发送给接收实体的 <response/> 元素信息。接收实体通过发送 <failure/>元素报告失败,发送<success/>元素报告成功;初始化实体通过发送<abort/> 元素中止交换。成功的协商之后,两边都认为原来的XML流已经关闭并且都开始发送新的流头信息。<br />
<br />
::security layer negotiation(安全层协商): 安全层在接收实体发送 <success/> 元素的关闭字符">"之后立刻生效,在初始化实体发送 <success/> 元素的关闭字符">"之后也立刻生效。层的顺序是 \[TCP\],\[TLS\],然后是 \[SASL\],然后是 \[XMPP\]。<br />
<br />
::use of the authorization identity(授权ID的使用): 授权ID可在xmpp中用于表示一个客户端的非缺省的<node@domain>,或一个服务器的<domain> 。<br />
<br />
===SASL 错误===<br />
<br />
:SASL相关的错误条件定义如下:<br />
<br />
::* <aborted/> -- 接收实体认可由初始化实体发送的<abort/>元素;在回应一个<abort/>元素时发送。<br />
<br />
::* <incorrect-encoding/> -- 由初始化实体提供的数据无法处理,因为[BASE64]编码不正确(例如,因为编码不符合[BASE64]的第三章); 在回应一个包含初始化响应数据的<response/> 元素或<auth/>元素时发送.<br />
<br />
::* <invalid-authzid/> -- 由初始化实体提供的授权id是非法的,因为它的格式不正确或初始化实体无权给那个ID授权;在回应一个包含初始化响应数据的<response/> 元素或<auth/>元素时发送。<br />
<br />
::* <invalid-mechanism/> -- 初始化实体不能提供一个机制活、或请求一个不被接受实体支持的机制;在回应一个<auth/>元素时发送。<br />
<br />
::* <mechanism-too-weak/> -- 初始化实体请求的机制比服务器策略对它的要求弱;在回应一个包含初始化响应数据的<response/> 元素或<auth/>元素时发送。<br />
<br />
::* <not-authorized/> -- 验证失败,因为初始化实体没有提供合法的credentials(这包括但不限于未知用户名等情形);在回应一个包含初始化响应数据的<response/> 元素或<auth/>元素时发送。<br />
<br />
::* <temporary-auth-failure/> -- 验证失败,因为接收实体出现了临时的错误;在回应一个<response/> 元素或<auth/>元素时发送。<br />
<br />
===客户端-服务器 示例===<br />
<br />
:以下例子展示了一个客户端和一个服务器使用SASL作验证的数据流,通常是在成功的TLS握手之后(注意:以下显示的替代步骤仅用于举例说明协议的失败情形;它们不够详尽也不需要由例子中的数据传送来触发)。<br />
<br />
:步骤 1: 客户端初始化流给服务器:<br />
<br />
<source lang="xml"><br />
<stream:stream xmlns='jabber:client' xmlns:stream='http://etherx.jabber.org/streams' to='example.com' version='1.0'><br />
</source><br />
<br />
:步骤 2: 服务器向客户端发送流标签作为应答:<br />
<br />
<source lang="xml"><br />
<stream:stream xmlns='jabber:client' xmlns:stream='http://etherx.jabber.org/streams' id='c2s_234' from='example.com' version='1.0'><br />
</source><br />
<br />
:步骤 3: 服务器通知客户端可用的验证机制:<br />
<br />
<source lang="xml"><br />
<stream:features><br />
<mechanisms xmlns='urn:ietf:params:xml:ns:xmpp-sasl'><br />
<mechanism>DIGEST-MD5</mechanism><br />
<mechanism>PLAIN</mechanism><br />
</mechanisms><br />
</stream:features><br />
</source><br />
<br />
:步骤 4: 客户端选择一个验证机制:<br />
<br />
<source lang="xml"><br />
<auth xmlns='urn:ietf:params:xml:ns:xmpp-sasl' mechanism='DIGEST-MD5'/><br />
</source><br />
<br />
:步骤 5: 服务器发送一个 \[BASE64\] 编码的挑战给客户端:<br />
<br />
<source lang="xml"><br />
<challenge xmlns='urn:ietf:params:xml:ns:xmpp-sasl'><br />
cmVhbG09InNvbWVyZWFsbSIsbm9uY2U9Ik9BNk1HOXRFUUdtMmhoIixxb3A9ImF1dGgi<br />
LGNoYXJzZXQ9dXRmLTgsYWxnb3JpdGhtPW1kNS1zZXNzCg==<br />
</challenge><br />
</source><br />
<br />
:解码后的挑战信息是:<br />
<br />
<source lang="xml"><br />
realm="somerealm",nonce="OA6MG9tEQGm2hh",\<br />
qop="auth",charset=utf-8,algorithm=md5-sess<br />
</source><br />
<br />
:步骤 5 (替代): 服务器返回一个错误给客户端:<br />
<br />
<source lang="xml"><br />
<failure xmlns='urn:ietf:params:xml:ns:xmpp-sasl'><br />
<incorrect-encoding/><br />
</failure><br />
</stream:stream><br />
</source><br />
<br />
:步骤 6: 客户端发送一个\[BASE64\]编码的回应这个挑战:<br />
<br />
<source lang="xml"><br />
<response xmlns='urn:ietf:params:xml:ns:xmpp-sasl'><br />
dXNlcm5hbWU9InNvbWVub2RlIixyZWFsbT0ic29tZXJlYWxtIixub25jZT0i<br />
T0E2TUc5dEVRR20yaGgiLGNub25jZT0iT0E2TUhYaDZWcVRyUmsiLG5jPTAw<br />
MDAwMDAxLHFvcD1hdXRoLGRpZ2VzdC11cmk9InhtcHAvZXhhbXBsZS5jb20i<br />
LHJlc3BvbnNlPWQzODhkYWQ5MGQ0YmJkNzYwYTE1MjMyMWYyMTQzYWY3LGNo<br />
YXJzZXQ9dXRmLTgK<br />
</response><br />
</source><br />
<br />
:解码后的回应信息是:<br />
<br />
<source lang="xml"><br />
username="somenode",realm="somerealm",\<br />
nonce="OA6MG9tEQGm2hh",cnonce="OA6MHXh6VqTrRk",\<br />
nc=00000001,qop=auth,digest-uri="xmpp/example.com",\<br />
response=d388dad90d4bbd760a152321f2143af7,charset=utf-8<br />
</source><br />
<br />
:步骤 7: 服务器发送另一个\[BASE64\]编码的挑战给客户端:<br />
<br />
<source lang="xml"><br />
<challenge xmlns='urn:ietf:params:xml:ns:xmpp-sasl'><br />
cnNwYXV0aD1lYTQwZjYwMzM1YzQyN2I1NTI3Yjg0ZGJhYmNkZmZmZAo=<br />
</challenge><br />
</source><br />
<br />
:解码后的挑战信息是:<br />
<br />
<source lang="xml"><br />
rspauth=ea40f60335c427b5527b84dbabcdfffd<br />
</source><br />
<br />
:步骤 7 (或者): 服务器返回一个错误给客户端:<br />
<br />
<source lang="xml"><br />
<failure xmlns='urn:ietf:params:xml:ns:xmpp-sasl'><br />
<temporary-auth-failure/><br />
</failure><br />
</stream:stream><br />
</source><br />
<br />
:步骤 8: 客户端应答这个挑战:<br />
<br />
<source lang="xml"><br />
<response xmlns='urn:ietf:params:xml:ns:xmpp-sasl'/><br />
</source><br />
<br />
:步骤 9: 服务器通知客户端验证成功:<br />
<br />
<source lang="xml"><br />
<success xmlns='urn:ietf:params:xml:ns:xmpp-sasl'/><br />
</source><br />
<br />
:步骤 9 (或者): 服务器通知客户端验证失败:<br />
<br />
<source lang="xml"><br />
<failure xmlns='urn:ietf:params:xml:ns:xmpp-sasl'><br />
<temporary-auth-failure/><br />
</failure><br />
</stream:stream><br />
</source><br />
<br />
:步骤 10: 客户端发起一个新的流给服务器:<br />
<br />
<source lang="xml"><br />
<stream:stream xmlns='jabber:client' xmlns:stream='http://etherx.jabber.org/streams' to='example.com' version='1.0'><br />
</source><br />
<br />
:步骤 11: 服务器发送一个流头信息回应客户端,并附上任何可用的特性(或空的features元素):<br />
<br />
<source lang="xml"><br />
<stream:stream xmlns='jabber:client' xmlns:stream='http://etherx.jabber.org/streams' id='c2s_345' from='example.com' version='1.0'><br />
<stream:features><br />
<bind xmlns='urn:ietf:params:xml:ns:xmpp-bind'/><br />
<session xmlns='urn:ietf:params:xml:ns:xmpp-session'/><br />
</stream:features><br />
</source><br />
<br />
===服务器-服务器 示例===<br />
<br />
:以下例子展示了一个服务器和另一个服务器使用SASL作验证的数据流,通常是在成功的TLS握手之后(注意:以下显示的替代步骤仅用于举例说明协议的失败情形;它们不够详尽也不需要由例子中的数据传送来触发)。<br />
<br />
:步骤 1: 服务器1 发起一个流给 服务器2 :<br />
<br />
<source lang="xml"><br />
<stream:stream xmlns='jabber:server' xmlns:stream='http://etherx.jabber.org/streams' to='example.com' version='1.0'><br />
</source><br />
<br />
:步骤 2: 服务器2 回应一个流标签给 服务器1:<br />
<br />
<source lang="xml"><br />
<stream:stream xmlns='jabber:server' xmlns:stream='http://etherx.jabber.org/streams' from='example.com' id='s2s_234' version='1.0'><br />
</source><br />
<br />
:步骤 3: 服务器2 通知 服务器1 可用的验证机制:<br />
<br />
<source lang="xml"><br />
<stream:features><br />
<mechanisms xmlns='urn:ietf:params:xml:ns:xmpp-sasl'><br />
<mechanism>DIGEST-MD5</mechanism><br />
<mechanism>KERBEROS_V4</mechanism><br />
</mechanisms><br />
</stream:features><br />
</source><br />
<br />
:步骤 4: 服务器1 选择一个验证机制:<br />
<br />
<source lang="xml"><br />
<auth xmlns='urn:ietf:params:xml:ns:xmpp-sasl' mechanism='DIGEST-MD5'/><br />
</source><br />
<br />
:步骤 5: 服务器2 发送一个\[BASE64\]编码的挑战给 服务器1:<br />
<br />
<source lang="xml"><br />
<challenge xmlns='urn:ietf:params:xml:ns:xmpp-sasl'><br />
cmVhbG09InNvbWVyZWFsbSIsbm9uY2U9Ik9BNk1HOXRFUUdtMmhoIixxb3A9<br />
ImF1dGgiLGNoYXJzZXQ9dXRmLTgsYWxnb3JpdGhtPW1kNS1zZXNz<br />
</challenge><br />
</source><br />
<br />
:解码后的挑战信息是:<br />
<br />
<source lang="xml"><br />
realm="somerealm",nonce="OA6MG9tEQGm2hh",\<br />
qop="auth",charset=utf-8,algorithm=md5-sess<br />
</source><br />
<br />
:步骤 5 (替代): 服务器2 返回一个错误给 服务器1:<br />
<br />
<source lang="xml"><br />
<failure xmlns='urn:ietf:params:xml:ns:xmpp-sasl'><br />
<incorrect-encoding/><br />
</failure><br />
</stream:stream><br />
</source><br />
<br />
:步骤 6: 服务器1 发送一个\[BASE64\]编码的回应这个挑战:<br />
<br />
<source lang="xml"><br />
<response xmlns='urn:ietf:params:xml:ns:xmpp-sasl'><br />
dXNlcm5hbWU9ImV4YW1wbGUub3JnIixyZWFsbT0ic29tZXJlYWxtIixub25j<br />
ZT0iT0E2TUc5dEVRR20yaGgiLGNub25jZT0iT0E2TUhYaDZWcVRyUmsiLG5j<br />
PTAwMDAwMDAxLHFvcD1hdXRoLGRpZ2VzdC11cmk9InhtcHAvZXhhbXBsZS5v<br />
cmciLHJlc3BvbnNlPWQzODhkYWQ5MGQ0YmJkNzYwYTE1MjMyMWYyMTQzYWY3<br />
LGNoYXJzZXQ9dXRmLTgK<br />
</response><br />
</source><br />
<br />
:解码后的应答信息是:<br />
<br />
<source lang="xml"><br />
username="example.org",realm="somerealm",\<br />
nonce="OA6MG9tEQGm2hh",cnonce="OA6MHXh6VqTrRk",\<br />
nc=00000001,qop=auth,digest-uri="xmpp/example.org",\<br />
response=d388dad90d4bbd760a152321f2143af7,charset=utf-8<br />
</source><br />
<br />
:步骤 7: 服务器2 发送另外一个\[BASE64\]编码的挑战给 服务器1:<br />
<br />
<source lang="xml"><br />
<challenge xmlns='urn:ietf:params:xml:ns:xmpp-sasl'><br />
cnNwYXV0aD1lYTQwZjYwMzM1YzQyN2I1NTI3Yjg0ZGJhYmNkZmZmZAo=<br />
</challenge><br />
</source><br />
<br />
:解码后的挑战信息是:<br />
<br />
<source lang="xml"><br />
rspauth=ea40f60335c427b5527b84dbabcdfffd<br />
</source><br />
<br />
:步骤 7 (或者): 服务器2 返回一个错误给 服务器1:<br />
<br />
<source lang="xml"><br />
<failure xmlns='urn:ietf:params:xml:ns:xmpp-sasl'><br />
<invalid-authzid/><br />
</failure><br />
</stream:stream><br />
</source><br />
<br />
:步骤 8: 服务器1 回应挑战:<br />
<br />
<source lang="xml"><br />
<response xmlns='urn:ietf:params:xml:ns:xmpp-sasl'/><br />
</source><br />
<br />
:步骤 8 (或者): 服务器1 中止协商:<br />
<br />
<source lang="xml"><br />
<abort xmlns='urn:ietf:params:xml:ns:xmpp-sasl'/><br />
</source><br />
<br />
:步骤 9: 服务器2 通知 服务器1 验证成功:<br />
<br />
<source lang="xml"><br />
<success xmlns='urn:ietf:params:xml:ns:xmpp-sasl'/><br />
</source><br />
<br />
:步骤 9 (或者): 服务器2 通知 服务器1 验证失败:<br />
<br />
<source lang="xml"><br />
<failure xmlns='urn:ietf:params:xml:ns:xmpp-sasl'><br />
<aborted/><br />
</failure><br />
</stream:stream><br />
</source><br />
<br />
:步骤 10: 服务器1 重新发起一个新的流给 服务器2:<br />
<br />
<source lang="xml"><br />
<stream:stream xmlns='jabber:server' xmlns:stream='http://etherx.jabber.org/streams' to='example.com' version='1.0'><br />
</source><br />
<br />
:步骤 11: 服务器2 发送一个流头信息应答 服务器1 ,并附上任何可用的特性(或一个空的features元素).:<br />
<br />
<source lang="xml"><br />
<stream:stream xmlns='jabber:client' xmlns:stream='http://etherx.jabber.org/streams' from='example.com' id='s2s_345' version='1.0'><br />
<stream:features/><br />
</source><br />
<br />
==资源绑定==<br />
<br />
:在和接收实体完成 SASL 协商(第六章)之后,初始化实体可能(MAY)想要或者需要绑定一个特定的资源到流上.通常这仅适用于客户端: 为了满足本文定义的寻址格式(第三章)和节传输规则(第十章),客户端<node@domain>必须(MUST)拥有一个相关的资源ID(由服务器生成或由客户端程序提供);以确保在流上使用的地址是一个“全JID”(<node@domain/resource>)。<br />
<br />
:接收到一个成功的SASL握手之后,客户端必须(MUST)发送一个新的流头信息给服务器,服务器必须(MUST)返回一个包含可用的流特性列表的头信息。特别是,在成功的SASL握手之后如果服务器需要客户端绑定一个资源,它必须(MUST)在握手成功之后(而不是之前)发送给客户端的应答流特性中包含一个空的符合'urn:ietf:params:xml:ns:xmpp-bind'名字空间的<bind/>元素。:<br />
<br />
:服务器向客户端声明资源绑定特性:<br />
<br />
<source lang="xml"><br />
<stream:stream xmlns='jabber:client' xmlns:stream='http://etherx.jabber.org/streams' id='c2s_345' from='example.com' version='1.0'><br />
<stream:features><br />
<bind xmlns='urn:ietf:params:xml:ns:xmpp-bind'/><br />
</stream:features><br />
</source><br />
<br />
:收到要求资源绑定的通知后,客户端必须(MUST)通过发送一个符合'urn:ietf:params:xml:ns:xmpp-bind'名字空间的“set”类型的IQ节(参见 IQ 语义 (第九章第二节第三小节))给服务器来绑定一个资源到流中。<br />
<br />
:如果客户端端希望允许服务器给自己生成一个资源ID,它可以发送一个包含空的<bind/>元素的“set”类型的IQ节。:<br />
<br />
:客户端请求服务器绑定资源:<br />
<br />
<source lang="xml"><br />
<iq type='set' id='bind_1'><br />
<bind xmlns='urn:ietf:params:xml:ns:xmpp-bind'/><br />
</iq><br />
</source><br />
<br />
:一个支持资源绑定的服务器必须(MUST)自动生成一个资源ID给客户端。一个由服务器生成的资源ID对于那个<node@domain>必须(MUST)是唯一的。<br />
<br />
:如果客户端希望指定资源ID,它发送一个包含期望资源ID的“set”类型的 IQ节,把资源ID作为<bind/>元素下的<resource/>子元素的XML字符数据:<br />
<br />
:客户端绑定一个资源:<br />
<br />
<source lang="xml"><br />
<iq type='set' id='bind_2'><br />
<bind xmlns='urn:ietf:params:xml:ns:xmpp-bind'><br />
<resource>someresource</resource><br />
</bind><br />
</iq><br />
</source><br />
<br />
:一旦服务器为客户端生成了一个资源ID或接受了客户端自己提供的资源ID,它必须(MUST)返回一个“result”类型的 IQ 节给客户端,这个节必须包含一个指明全JID的<jid/>子元素表示服务器决定连接的资源:<br />
<br />
:服务器通知客户端资源绑定成功:<br />
<br />
<source lang="xml"><br />
<iq type='result' id='bind_2'><br />
<bind xmlns='urn:ietf:params:xml:ns:xmpp-bind'><br />
<jid>somenode@example.com/someresource</jid><br />
</bind><br />
</iq><br />
</source><br />
<br />
:一个服务器应该(SHOULD)接受客户端提供的资源ID,但是可以(MAY)用服务器生成的资源ID覆盖它;在这种情况下,服务器不应该(SHOULD NOT)返回一个错误信息一个(如<forbidden/>)给客户端,而应该(SHOULD)在上文所述的 IQ result 中返回生成的资源ID。<br />
<br />
:当一个客户端自行提供资源ID时,可能发生以下的节错误(参见 Stanza Errors (第九章第三节)):<br />
<br />
::- 提供的资源ID服务器无法处理,因为不符合资源字符规范Resourceprep(附录B)。<br />
<br />
::- 客户端不被允许绑定一个资源(如节点或用户已经达到允许连接的资源数限制)。<br />
<br />
::- 提供的资源ID已经被使用但是服务器不允许以同一个资源ID绑定多个连接。<br />
<br />
:协议对这些错误条件规定如下.<br />
<br />
::资源ID不能处理:<br />
<br />
<source lang="xml"><br />
<iq type='error' id='bind_2'><br />
<bind xmlns='urn:ietf:params:xml:ns:xmpp-bind'><br />
<resource>someresource</resource><br />
</bind><br />
<error type='modify'><br />
<bad-request xmlns='urn:ietf:params:xml:ns:xmpp-stanzas'/><br />
</error><br />
</iq><br />
</source><br />
<br />
::客户端不允许绑定一个资源:<br />
<br />
<source lang="xml"><br />
<iq type='error' id='bind_2'><br />
<bind xmlns='urn:ietf:params:xml:ns:xmpp-bind'><br />
<resource>someresource</resource><br />
</bind><br />
<error type='cancel'><br />
<not-allowed xmlns='urn:ietf:params:xml:ns:xmpp-stanzas'/><br />
</error><br />
</iq><br />
</source><br />
<br />
::资源ID已经在使用:<br />
<br />
<source lang="xml"><br />
<iq type='error' id='bind_2'><br />
<bind xmlns='urn:ietf:params:xml:ns:xmpp-bind'><br />
<resource>someresource</resource><br />
</bind><br />
<error type='cancel'><br />
<conflict xmlns='urn:ietf:params:xml:ns:xmpp-stanzas'/><br />
</error><br />
</iq><br />
</source><br />
<br />
:如果,在完成资源绑定步骤之前,客户端试图以符合'urn:ietf:params:xml:ns:xmpp-bind'名字空间的<bind/>子元素发送一个非IQ类型的XML节,服务器不能(MUST NOT)处理这个节,而应该(SHOULD)返回一个<not-authorized/>节错误信息给客户端.<br />
<br />
==服务器回拨==<br />
<br />
===概览===<br />
<br />
:Jabber协议接受的来自XMPP的包括“服务器回拨”方法,用于防治域名欺骗,使得欺骗XML节更为困难。服务器回拨不是一个安全机制,并且它的服务器身份认证结果很弱(参见服务器之间的通信(第十四章第四节)中关于这个方法的安全特性)。需要健壮的安全性的域名应该(SHOULD)使用TLS或SASL;细节参见服务器间的通信(第十四章第四节)。如果SASL用于服务器间通信,回拨就不需要用了(SHOULD NOT)。本文描述回拨的好处在于向后兼容现存的实现和部署。<br />
<br />
:服务器回拨方法由现存的DNS系统的存在而成为可能,因为一个服务器(通常)可以查询给定域的授权服务器。由于服务器回拨依赖于DNS,除非服务器宣称的DNS主机得到解析,域之间的通信无法进行(参见服务器间的通信(第十四章第四节))。<br />
<br />
:服务器回拨是单向性的,可在单一方向上对一个流进行(微弱的)身份验证.因为服务器回拨不是一个验证机制,通过回拨获得相互的认证是不可能的.因此,为了使得服务器之间的双向通信,服务器回拨必须(MUST)在每个方向上完成。<br />
<br />
:在服务器回拨中生成和检验密钥的方法必须(MUST)考虑计算被使用的主机名,由接收服务器生成的流ID,和只有授权服务器网络才知道的秘密。在服务器回拨中流ID是安全性的关键所以必须(MUST)是不可预知的和不可重复的(见\[RANDOM\]中关于使用随机数获得安全性的建议).<br />
<br />
:任何回拨协商过程中发生的错误必须(MUST)被当成一个流错误,并导致流以及相关的TCP连接的终止.可能发生的错误情况协议中描述如下.<br />
<br />
:以下术语适用:<br />
<br />
:* 发起服务器 -- 尝试在两个域之间建立连接的那个服务器.<br />
<br />
:* 接收服务器 -- 尝试验证发起服务期声称的域名的那台服务器.<br />
<br />
:* 授权(权威?Authoritative) 服务器 -- 回答发起服务器声称的DNS主机名的服务器;基本上这应该是那台发起服务器,但是它也可能是一个在发起服务器网络中独立的服务器。<br />
<br />
===事件顺序===<br />
<br />
:以下是回拨中的事件顺序的简介:<br />
<br />
:# 发起服务器和接收服务器建立一个连接。<br />
:# 发起服务器通过到连接发送一个 'key' 值给接收服务期。<br />
:# 接收服务器建立一个连接到授权服务器。<br />
:# 接收服务器发送一个相同的 'key' 值给授权服务器。<br />
:# 授权服务器回答这个key是否合法。<br />
:# 接收服务器通知发起服务器是否被验证通过。<br />
<br />
:我们用用以下图形展示这个事件流程(见附件s2s.png):<br />
<br />
{image:img=s2s}<br />
<br />
发起服务器 接收服务器<br />
----------- ---------<br />
| |<br />
| 建立连接 |<br />
| ----------------------> |<br />
| |<br />
| 发stream头 |<br />
| ----------------------> |<br />
| |<br />
| 发stream头 |<br />
| <---------------------- |<br />
| | <br />
| 发回拨key | 授权服务器<br />
| ----------------------> | -------------<br />
| | |<br />
| 建立连接 |<br />
| ----------------------> |<br />
| |<br />
| 发stream头 |<br />
| ----------------------> |<br />
| |<br />
| 发stream头 |<br />
| <---------------------- |<br />
| |<br />
| 发验证请求 |<br />
| ----------------------> |<br />
| |<br />
| 发验证响应 |<br />
| <---------------------- |<br />
|<br />
| 报告回拨结果 |<br />
| <---------------------- |<br />
| |<br />
<br />
===协议===<br />
<br />
:服务器之间互动的细节协议如下:<br />
<br />
:1. 发起服务器和接受服务器建立TCP连接.<br />
<br />
:2. 发起服务器发送流头信息给接收服务器:<br />
<br />
<source lang="xml"><br />
<stream:stream xmlns:stream='http://etherx.jabber.org/streams' xmlns='jabber:server' xmlns:db='jabber:server:dialback'><br />
</source><br />
<br />
:注意: 'to'和'from'属性在流的根元素是可选的(OPTIONAL). 其中包含的xmlns:db名字空间向接收服务器声明了发起服务器支持回拨. 如果名字空间不正确,接收实体必须(MUST)生成一个<invalid-namespace/>流错误条件并且终止XML流和相应的TCP连接.<br />
<br />
:3. 接收服务器应该(SHOULD)回送一个流头信息给发起服务器,为这次交互生成一个唯一性的ID :<br />
<br />
<source lang="xml"><br />
<stream:stream xmlns:stream='http://etherx.jabber.org/streams' xmlns='jabber:server' xmlns:db='jabber:server:dialback' id='457F9224A0...'><br />
</source><br />
<br />
:注意: 'to'和'from'属性在流的根元素是可选的(OPTIONAL). 如果名字空间不正确,发起服务器必须生成一个<invalid-namespace/>流错误条件并且终止XML流和相应的TCP连接.也要注意,在这里接收服务器应该(SHOULD)应答但是可以(MAY)出于安全策略考虑只是悄悄地终止XML流和TCP连接;无论如何,如果接收服务器希望继续,它必须(MUST)回送一个流头信息给发起服务器.<br />
<br />
:4. 发起服务器发送一个回拨密钥给接收服务器:<br />
<br />
<source lang="xml"><br />
<db:result to='Receiving Server' from='Originating Server'><br />
98AF014EDC0...<br />
</db:result><br />
</source><br />
<br />
:注意: 这个密钥不由接收服务器检查,因为接收服务器在会话之间(between sessions)不保存发起服务器的信息. 这个由发起服务器生成的密钥必须(MUST)是基于接收服务器在上一步骤中提供的ID值,以及发起服务器与授权服务器共享的安全机制生成的。 如果 'to' 地址的值和接收服务器知道的主机名不匹配,接收服务器必须(MUST)生成一个<host-unknown/>流错误条件并且终止XML流和相应的TCP连接. 如果 'from' 地址和接收服务器已经建立的连接的域名相吻合,接收服务器必须(MUST)维护这个已经存在的连接,直到证明这个新的连接是合法的为止;另外,接收实体可以(MAY)选择生成一个<not-authorized/> 流错误条件给这个新的连接并且终止和新连接申请相关的XML流及相应的TCP连接.<br />
<br />
:5. 接收服务器向发起服务器声明的那个域建立一个 TCP 连接,作为结果它连接到授权服务器. (注意: 为了优化性能, 在这里一个实现可以(MAY)重用现有的连接.)<br />
<br />
:6. 接收服务器发送一个流头信息给授权服务器:<br />
<br />
<source lang="xml"><br />
<stream:stream xmlns:stream='http://etherx.jabber.org/streams' xmlns='jabber:server' xmlns:db='jabber:server:dialback'><br />
</source><br />
<br />
:注意: 'to'和'from'属性在流的根元素是可选的(OPTIONAL). 如果名字空间不正确,授权服务器必须生成一个<invalid-namespace/>流错误条件并且终止XML流和相应的TCP连接. <br />
<br />
:7. 授权服务器发送流头信息给接收服务器:<br />
<br />
<source lang="xml"><br />
<stream:stream xmlns:stream='http://etherx.jabber.org/streams' xmlns='jabber:server' xmlns:db='jabber:server:dialback' id='1251A342B...'><br />
</source><br />
<br />
:注意: 如果名字空间不正确,接收服务器必须生成一个<invalid-namespace/>流错误条件并且终止它和授权服务器之间的XML流和相应的TCP连接. 如果一个流错误发生在接收服务器和 '''授权服务器''' 之间,接收服务器必须(MUST)生成一个 <remote-connection-failed/> 流错误条件并且终止它和 '''发起服务器''' 之间的XML流和相应的TCP连接.<br />
<br />
:8. 接收服务器发送一个密钥检查请求给授权服务器:<br />
<br />
<source lang="xml"><br />
<db:verify from='Receiving Server' to='Originating Server' id='457F9224A0...'><br />
98AF014EDC0...<br />
</db:verify><br />
</source><br />
<br />
:注意: 现在这里已经有了主机名,第三步中接收服务器发送给发起服务器的ID,第四步中发起服务器发送给接收服务器的密钥. 基于这些信息, 加上授权服务器网络共享的安全信息, 这个密钥被证实了.任何可用于验证的办法都可以(MAY)用于生成密钥. 如果 'to' 地址的值和授权服务器知道的主机名不匹配,授权服务器必须(MUST)生成一个<host-unknown/>流错误条件并且终止XML流和相应的TCP连接. 打开这个连接时,如果 'from' 地址和接收服务器声明的主机名(或任何合法的域,如验证过的接收服务器的子域名或寄宿在接收服务器上的其他经过验证的域)不符,授权服务器必须(MUST)生成一个<invalid-from/>流错误条件并且终止XML流和相应的TCP连接.<br />
<br />
:9. 授权服务器检查密钥是否合法:<br />
<br />
<source lang="xml"><br />
<db:verify from='Originating Server' to='Receiving Server' type='valid' id='457F9224A0...'/><br />
</source><br />
<br />
::或<br />
<br />
<source lang="xml"><br />
<db:verify from='Originating Server' to='Receiving Server' type='invalid' id='457F9224A0...'/><br />
</source><br />
<br />
:注意: 如果 ID 和第三步中接收服务器提供的不符,接收服务器必须(MUST)生成一个<invalid-id/>流错误条件并且终止XML流和相应的TCP连接. 如果 'to' 地址的值和接收服务器知道的主机名不匹配,接收服务器必须(MUST)生成一个<host-unknown/>流错误条件并且终止XML流和相应的TCP连接. 打开这个连接时,如果 'from' 地址和发起服务器声明的主机名(或任何合法的域,如验证过的发起服务器的子域名或寄宿在发起服务器上的其他经过验证的域)不符,接收服务器必须(MUST)生成一个<invalid-from/>流错误条件并且终止XML流和相应的TCP连接. 在返回验证信息给接收服务器之后,授权服务器应该(SHOULD)终止它们之间的流.<br />
<br />
:10. 接收服务器通知发起服务器结果:<br />
<br />
<source lang="xml"><br />
<db:result from='Receiving Server'to='Originating Server' type='valid'/><br />
</source><br />
<br />
:注意: 在这一个点上, 连接已经由 type='valid' 确认验证是通过了,还是没通过. 如果连接是非法的,接收服务器必须(MUST)终止XML流和相应的TCP连接. 如果连接是合法的, 数据可以从发起服务器发送由接收服务器读取;在此之前,所有发送给接收服务器的XML节应该(SHOULD)被丢弃.<br />
<br />
:进一步的结果是,接收服务器已经验证了发起服务器的ID,所以通过初始化流("initial stream",例如从发起服务器到接收服务器的流)发起服务器可以发送,接收服务器可以接受XML节. 为了使用应答流("response stream",例如从接收服务器到发起服务器的流)验证实体ID,回拨必须(MUST)在相对的两个方向上都完成.<br />
<br />
:在成功的回拨协商之后, 接收服务器应该(SHOULD)接受接下来发起服务器通过当前的合法连接发送的 <db:result/> 包 (例如, 发送给子域或其他寄宿在接收服务器上的主机名的验证请求); 这在单一方向上激活了原始合法连接的 "piggybacking" .<br />
<br />
:即使回拨协商成功了, 服务器仍然必须(MUST)检查从其他服务器接收的所有XML节的'from'和'to'属性; 如果一个节不符合这些限定, 收到这些节的服务器必须(MUST)生成一个<improper-addressing/> 流错误条件并终止XML流和相应的TCP连接. 而且, 一个服务器也必须(MUST)检查从其他的有合法域名的服务器的流中收到的节的'from'属性; 如果一个节不符合这一限定, 接收节的服务器必须(MUST)生成一个 <invalid-from/> 流错误条件并终止XML流和相应的TCP连接. 所有这些检查都用来帮助防止特定的节伪造行为.<br />
<br />
==XML节==<br />
<br />
:在 TLS 协商(第五章) (如果想要), SASL 协商(第六章), 和资源绑定(第七章)(如果需要)之后, XML节就可以通过流发送了. 在'jabber:client'和'jabber:server'名字空间中定义了三种XML节: <message/>, <presence/>, 和 <iq/>. 另外, 这三种节有五种通用的属性. 这些通用属性, 加上三种节的术语,在这里定义; 更多关于和即时消息及出席信息应用相关的XML节语法详细信息在[XMPP-IM|XMPP文档列表/XMPP正式RFC标准/RFC3921]中提供.<br />
<br />
===通用属性===<br />
<br />
:以下五种属性通用于 message, presence, 和 IQ 节:<br />
<br />
====to====<br />
<br />
:'to' 属性表示节的预期接收者的JID.<br />
<br />
:在'jabber:client'名字空间中, 一个节应该(SHOULD)处理一个'to'属性, 尽管由服务器处理的从客户端发给服务器的节(如, 发送给服务器用于广播给其他实体的出席信息) 应该不(SHOULD NOT)处理'to'属性.<br />
<br />
:在'jabber:server'名字空间中, 一个节必须(MUST)处理一个'to'属性; 如果一个服务器收到一个不符合此限定的节, 它必须(MUST)生成一个<improper-addressing/>流错误条件并终止和这个非法服务器的XML流和相应的TCP连接.<br />
<br />
:如果'to'属性的值非法或无法联络, 发现这个事实的实体(通常是发送者或接收者的服务器)必须(MUST)返回一个适当的错误给发送者, 错误节的'from'属性设置成非法节的提供的'to'属性的值.<br />
<br />
====from====<br />
<br />
:'from' 属性表示发送者的 JID .<br />
<br />
:当一个服务器接收了一个符合'jabber:client'名字空间的合法流的XML节, 它必须(MUST)做以下步骤中的一步:<br />
<br />
:# 验证客户端提供的'from'属性值就是那个相关实体连接的资源<br />
:# 为生成这个节的已连接的资源增加一个'from'地址(由服务器决定是纯JID或全JID)(参见 地址的决定 Determination of Addresses (第三章第五节))<br />
:# 如果一个客户端试图发送一个XML节,而它的'from'属性和这个实体已连接的资源不符, 服务器应该(SHOULD)返回一个<invalid-from/>流错误条件给客户端. 如果一个客户端试图通过一个尚未验证的流发送一个XML节, 服务器应该(SHOULD)返回一个<not-authorized/>流错误条件给客户端. 如果生成了, 所有这些条件必须(MUST)导致流的关闭和相应的TCP连接的终止; 这有助于防止不诚实的客户的拒绝服务攻击.<br />
<br />
:当一个服务器从服务器自身生成一个节用于一个已连接的客户端的信息发布(例如, 在服务器为客户端提供数据存储服务的情况下), 这个节必须(MUST) (1) 不包含 'from' 属性 或 (2) 包含一个'from'属性,它的值是这个账号的纯 JID (<node@domain>) 或 客户端的全 JID (<node@domain/resource>). 如果节不是由服务器自身生成的,那么一个服务器不能(MUST NOT)发送不带'from'属性的节. 当一个客户端接收到一个不包含'from'属性的节, 它必须(MUST)认为这个节是从客户端连接的服务器发来的.<br />
<br />
:在'jabber:server'名字空间, 一个节必须(MUST)处理一个'from'属性; 如果一个服务器接收到一个不符合此限定的节, 它必须(MUST)生成一个<improper-addressing/>流错误条件. 而且, 'from'属性的 JID值的域名ID部分必须(MUST)和以SASL协商连接或以回拨协商连接的发送服务器的主机名(或任何合法的域,如发送服务器主机名的合法子域,或其他寄宿在发送服务器上的合法域)吻合; 如果一个服务器接收到的节不符合此限定, 它必须(MUST)生成一个<invalid-from/>流错误条件. 所有这些条件都必须(MUST)导致流的关闭和相应的TCP连接的终止; 这有助于防止不诚实的客户端发起的拒绝服务攻击.<br />
<br />
====id====<br />
<br />
:可选的'id' 属性可以(MAY)用于为节的内部跟踪发送实体,从IQ节 语义来讲,就是通过发送和接收这些节来跟踪“请求-应答”型的交互行为。这个可选的(OPTIONAL)'id'属性值在一个域或一个流中是全局唯一的。IQ节语义学中对此有附加限定;见IQ Semantics (第九章第二节第三小节)。<br />
<br />
====type====<br />
<br />
:'type' 属性指明消息、出席信息或IQ节的意图或上下文的详细信息。'type'属性所允许的值依据节的类型是消息、出席信息还是IQ而有很大不同; 用于消息和出席信息节的值定义在即时消息和出席信息应用中,所以在[XMPP-IM|XMPP文档列表/XMPP正式RFC标准/RFC3921]中定义,反之用于IQ节的值定义了在一个 请求\-应答 的“会话”中IQ节的角色,所以定义在IQ语义学中(第九章第二节第三小节)。 所有三种节的通用'type'值是"error";见Stanza Errors (第九章第三节)。<br />
<br />
====xml:lang====<br />
<br />
:如果一个节包含用于显示给人human user看的XML字符数据(在RFC 2277中有所解释\[CHARSET\],"internationalization is for humans"),这个节应该(SHOULD)处理一个'xml:lang'属性(定义在第二章第十二节\[XML\])。 'xml:lang'属性的值指明任何一个人类可读的XML字符数据的缺省语言, 它可以(MAY)被特定的子元素的'xml:lang'值重载。 如果一个节不处理一个'xml:lang'属性,一个实现必须(MUST)认为缺省的语言就是流属性中定义的语言(第四章第四节). 'xml:lang'属性值必须(MUST)是一个 NMTOKEN 并且必须(MUST)遵守 RFC 3066 \[LANGTAGS\]中定义的格式. <br />
<br />
===基本语义学===<br />
<br />
====消息语义学====<br />
<br />
:<message/>节类型可以被看作是一个"push"机制用于一个实体推送信息给另一个实体,类似发生在email系统中的通信. 所有消息节应该(SHOULD)处理一个表明预定的消息接收者的'to'属性;接收了这样一个节之后,一个服务器应该(SHOULD)路由或递送它给预定的接收者(见 Server Rules for Handling XML Stanzas (第十章)的XML节相关的通用路由和递送规则).<br />
<br />
====出席信息语义学====<br />
<br />
:<presence/> 元素可以被看作一个基本的广播或“出版-订阅”机制,用于多个实体接收某个已订阅的实体的信息(在这里,是网络可用性信息). 通常,一个发行实体应该(SHOULD)不带'to'属性发送一个出席信息,这时这个实体所连接的服务器应该(SHOULD)广播或多播(multiplex?)那个节给所有订阅的实体.无论如何,一个发行实体也可以(MAY)带'to'属性发送一个出席信息节,这时服务器应该(SHOULD)路由或递送这个节给预定的接收者.见 Server Rules for Handling XML Stanzas (第十章)的XML节相关的通用路由和递送规则,以及[XMPP-IM|XMPP文档列表/XMPP正式RFC标准/RFC3921]中即时消息和出席信息应用中出席信息的特定规则.<br />
<br />
====IQ语义学====<br />
<br />
:信息/查询(Info/Query),或曰IQ,是一个 请求-回应 机制,某些情况下类似\[HTTP\].IQ语义学使一个实体能够向另一个实体做出请求并做出应答. 请求和应答所包含的数据定义在IQ元素的一个直接的子元素的名字空间声明中, 并且由请求实体用'id'属性来跟踪这一交互行为. 因而,IQ交互伴随着一个结构化的数据交换的通用模式例如 get/result 或 set/result (尽管有时候会以一个错误信息应答某个请求):<br />
<br />
:以下是IQ的流程图,参见附件iq.png<br />
<br />
{image:img=iq}<br />
<br />
:为了强制执行这些语义学,要应用以下规则:<br />
<br />
:1. 对于IQ节来说'id'属性是必需的(REQUIRED).<br />
:2. 对于IQ节来说'type'属性是必需的(REQUIRED). 它的值必须(MUST)是以下之一:<br />
::* get -- 这个节是一个对信息或需求的请求.<br />
::* set -- 这个节提供需要的数据, 设置新的值, 或取代现有的值.<br />
::* result -- 这个节是一个对一个成功的 get 或 set 请求的应答.<br />
::* error -- 发生了一个错误,关于处理或递送上次发送的 get 或 set的(参见 节错误 Stanza Errors(第九章第三节)).<br />
:3. 一个接收到"get" 或 "set" 类型的IQ请求的实体必须(MUST)回复一个"result"或"error"类型的IQ应答(这个应答必须(MUST)保留相关请求的'id'属性).<br />
:4. 一个接收到"result"或"error"类型的IQ节的实体不能(MUST NOT)再发送更多的"result"或"error"类型的IQ应答; 无论如何, 如上所述, 请求实体可以(MAY)发送另一个请求(如, 一个"set"类型的IQ,通过get/result对提供查询(discovery)所需的信息).<br />
:5. 一个"get" 或 "set" 类型的IQ节必须(MUST)包含并只包含一个子元素指明特定请求或应答的语义.<br />
:6. 一个"result"类型的IQ节必须(MUST)包含零或一个子元素.<br />
:7. 一个"error"类型的IQ节应该(SHOULD)包含和"get"或"set"相关联的那个子元素并且必须(MUST)包含一个<error/>子元素;详细信息,见Stanza Errors (第九章第三节).<br />
<br />
===节错误===<br />
<br />
:节相关的错误的处理方式类似流错误(第四章第七节). 无论如何, 不像流错误, 节错误是可恢复的;所以错误节包含了暗示原来的发送者可以采取什么行动来补救这个错误.<br />
<br />
====规则====<br />
<br />
:以下规则适用于节相关的错误:<br />
<br />
:* 接收或处理实体察觉到一个节相关的错误条件时应该(MUST)返回给发送实体一个同类型的节(消息,出席信息,或IQ),这个节的'type'属性值则设置为"error"(这里这样的节称之为"error stanza").<br />
<br />
:* 生成一个错误节的实体应该(SHOULD)包含原来发送的XML,这样发送者可以检查它,并且如果必要,在尝试重新发送之前纠正它.<br />
<br />
:* 一个错误节必须(MUST)包含一个<error/>子元素.<br />
<br />
:* 如果'type'属性值不是"error"(或没有"type"属性),节不能(MUST NOT)包含一个<error/>子元素.<br />
<br />
:* 接收到一个错误节的实体不能(MUST NOT)应答这个节更多的错误节; 这有助于防止死循环.<br />
<br />
====语法====<br />
<br />
:节相关错误的语法如下:<br />
<br />
<source lang="xml"><br />
<stanza-kind to='sender' type='error'><br />
[RECOMMENDED to include sender XML here]<br />
<error type='error-type'><br />
<defined-condition xmlns='urn:ietf:params:xml:ns:xmpp-stanzas'/><br />
<text xmlns='urn:ietf:params:xml:ns:xmpp-stanzas' xml:lang='langcode'><br />
OPTIONAL descriptive text<br />
</text><br />
[OPTIONAL application-specific condition element]<br />
</error><br />
</stanza-kind><br />
</source><br />
<br />
:stanza-kind 是 message, presence, 或 iq 中的一个.<br />
<br />
:<error/> 元素的'type'属性值必须(MUST)是以下之一:<br />
<br />
:* cancel \-\- 不重试(这个错误是不可恢复的)<br />
<br />
:* continue \-\- 继续进行(这个条件只是一个警告)<br />
<br />
:* modify \-\- 改变数据之后重试<br />
<br />
:* auth \-\- 提供证书之后重试<br />
<br />
:* wait \-\- 等待之后重试(错误是暂时的)<br />
<br />
:<error/>元素:<br />
<br />
:* 必须(MUST)包含一个子元素,符合以下定义的节错误条件之一;这个元素(MUST)符合'urn:ietf:params:xml:ns:xmpp-stanzas'名字空间.<br />
<br />
:* 可以(MAY)包含一个<text/>子元素容纳XML字符数据用来描述错误的更多细节;这个元素必须(MUST)符合'urn:ietf:params:xml:ns:xmpp-stanzas'名字空间并且应该(SHOULD)处理'xml:lang'属性.<br />
<br />
:* 可以(MAY)包含一个应用程序定义的错误条件子元素;这个元素必须(MUST)符合一个应用程序定义的名字空间,并且它的结构由这个名字空间定义.<br />
<br />
:<text/>元素是可选的(OPTIONAL).如果包含它,它应该(SHOULD)仅用于提供描述或诊断信息以补充一个已定义的条件或应用程序定义的条件. 它不应(SHOULD NOT)被应用程序认为是一个程序性的. 它不应(SHOULD NOT)被用作向一个使用者展示的错误信息,但是可以(MAY)展示除条件元素(或元素们)相关的错误信息之外的信息.<br />
<br />
:最后,为了维护向后兼容性, 这个schema (定义在[XMPP-IM|XMPP文档列表/XMPP正式RFC标准/RFC3921])允许可选的在<error/>元素中包含一个("code")属性.<br />
<br />
====已定义的条件====<br />
<br />
:以下条件定义用于节错误.<br />
<br />
:* <bad-request/> -- 发送者发送的XML是不规范的或不能被处理(例如 一个IQ节包含了一个未被承认的'type'属性值); 相关的错误类型应该(SHOULD)是"modify".<br />
<br />
:* <conflict/> -- 不同意访问,因为相同的名字或地址已存在一个资源或会话;相关的错误类型应该( SHOULD)是"cancel".<br />
<br />
:* <feature-not-implemented/> -- 请求的特性未被接收者或服务器实现所以不能处理;相关的错误类型应该(SHOULD)是"cancel".<br />
<br />
:* <forbidden/> -- 请求实体没有必需的许可来执行这一动作;相关的错误类型应该(SHOULD)是"auth".<br />
<br />
:* <gone/> -- 接收者或服务器无法再以这个地址进行联系(错误节可以(MAY)在<gone/>元素的XML字符数据中包含一个新的地址);相关的错误类型应该(SHOULD)是"modify".<br />
<br />
:* <internal-server-error/> -- 服务器不能处理节,因为错误的配置或其他未定义的内部服务器错误;相关的错误类型应该(SHOULD)是"wait".<br />
<br />
:* <item-not-found/> -- JID地址或申请的条目无法找到;相关的错误类型应该(SHOULD)是"cancel".<br />
<br />
:* <jid-malformed/> -- 发送的实体提供的XMPP地址或与之通信的某个XMPP地址(如一个'to'属性值)或这个XMPP地址中的一部分(如一个资源ID)不符合寻址方案的语法(第三章);相关的错误类型应该(SHOULD)是"modify".<br />
<br />
:* <not-acceptable/> -- 接收者或服务器理解这个请求但是拒绝处理,因为它不符合某些接收者或服务器定义的标准(例如,一个关于消息中可接收的单词的本地策略);相关错误类型应该(SHOULD)是"modify".<br />
<br />
:* <not-allowed/> -- 接收者或服务器不允许任何实体执行这个动作;相关错误类型应该(SHOULD)是"cancel".<br />
<br />
:* <not-authorized/> -- 在被允许执行某个动作之前发送者必须提供适当的证书,或已提供了不正确的证书;相关错误类型应该(SHOULD)是"auth".<br />
<br />
:* <payment-required/> -- 请求实体未被授权访问请求的服务,因为需要付费;相关错误类型应该(SHOULD)是"auth".<br />
<br />
:* <recipient-unavailable/> -- 预定的接收者暂时不可用;相关错误类型应该(SHOULD)是"wait"(注意: 如果这样做会导致泄露预定接收者的网络可用性给一个未被授权了解此信息的实体,应用程序不应该(MUST NOT)返回这个错误).<br />
<br />
:* <redirect/> -- 接收者或服务器重定向这个请求信息到另一个实体,通常是暂时的(这个错误节应该 (SHOULD)在<redirect/>元素的XML字符数据中包含一个预备的地址,它必须(MUST)是一个合法的JID); 相关的错误类型应该(SHOULD)是"modify".<br />
<br />
:* <registration-required/> -- 请求实体未被授权访问请求的服务,因为需要注册;相关错误类型应该(SHOULD)是"auth".<br />
<br />
:* <remote-server-not-found/> -- 在预定的接收者的全部或部分JID中的一个远程服务器或服务不存在;相关错误类型应该(SHOULD)是"cancel".<br />
<br />
:* <remote-server-timeout/> -- 在预定的接收者(或需要完成的一个申请)的全部或部分JID中的一个远程服务器或服务无法在合理的时间内联系到;相关错误类型应该(SHOULD)是"wait".<br />
<br />
:* <resource-constraint/> -- 服务器或接收者缺乏足够的系统资源来服务请求;相关错误类型应该(SHOULD)是"wait".<br />
<br />
:* <service-unavailable/> -- 服务器或接收者目前无法提供被请求的服务;相关错误类型应该(SHOULD)是"cancel".<br />
<br />
:* <subscription-required/> -- 请求实体未被授权访问能请求的服务,因为需要订阅;相关错误类型应该(SHOULD)是"auth".<br />
<br />
:* <undefined-condition/> -- 错误条件不是本列表中定于的其他条件之一;任何错误类型可能和这个条件有关,并且它应该(SHOULD)仅用于关联一个应用程序定义的条件.<br />
<br />
:* <unexpected-request/> -- 接收者或服务器理解这个请求但是不希望是在这个时间(比如,请求的顺序颠倒);相关错误类型应该(SHOULD)是"wait".<br />
<br />
====应用程序定义条件====<br />
<br />
:大家知道,一个应用程序可以(MAY)通过在错误元素里包含一个适当名字空间的字元素来提供应用程序定义的节错误信息. 应用程序定义的元素应该(SHOULD)补充或进一步限定一个已定义的元素. 因而,<error/>元素将包含两个或三个子元素:<br />
<br />
<source lang="xml"><br />
<iq type='error' id='some-id'><br />
<error type='modify'><br />
<bad-request xmlns='urn:ietf:params:xml:ns:xmpp-stanzas'/><br />
<too-many-parameters xmlns='application-ns'/><br />
</error><br />
</iq><br />
<message type='error' id='another-id'><br />
<error type='modify'><br />
<undefined-condition xmlns='urn:ietf:params:xml:ns:xmpp-stanzas'/><br />
<text xml:lang='en' xmlns='urn:ietf:params:xml:ns:xmpp-stanzas'><br />
Some special application diagnostic information...<br />
</text><br />
<special-application-condition xmlns='application-ns'/><br />
</error><br />
</message><br />
</source><br />
<br />
==服务器处理XML节的规则==<br />
<br />
:兼容的服务器实现必须(MUST)确保两个实体之间的XML节按次序处理.<br />
<br />
:在按次序处理的需求之外, 每个服务器实现将包含它自己的递送树"delivery tree"以处理它接收到的节.这个树决定一个节是否需要路由到其他域, 在内部处理, 还是递送到和一个已连接的节点相关的资源. 以下规则适用:<br />
<br />
===没有'to'地址===<br />
<br />
:如果这个节没有'to'属性, 服务器应该(SHOULD)为发送它的实体处理这个节. 因为所有从其他服务器收到的节必须(MUST)拥有'to'属性, 这个规则仅适用于从一个连接到这台服务器的已注册实体(如一个客户端)收到的节.如果这个服务器收到一个没有'to'属性的出席信息节, 服务器应该(SHOULD)向那些订阅了这个发送实体的出席信息的所有实体广播它, 如果可能的话(即时消息和出席信息应用程序中出席信息广播的语义定义在[XMPP-IM|XMPP文档列表/XMPP正式RFC标准/RFC3921]). 如果服务器接收到一个类型为"get" 或 "set" 的没有'to'属性的节并且它理解这个节的名字空间下的内容, 它必须(MUST)为这个发送实体处理节(在这里"process"的含义是由相关的名字空间的语义所决定的)或返回一个错误给发送实体.<br />
<br />
===外部域===<br />
<br />
:如果'to'属性中的JID的域ID部分的主机名和服务器自身或其子域配置的主机名不匹配, 服务器应该(SHOULD)路由这个节到外部域(取决于本地服务规定或安全策略关于域间通信的规定).有两种可能的情况:<br />
<br />
::- 一个服务器之间的流已经存在于两个域之间: 发送者的服务器通过这个已存在的流为这个外部域路由这个节到授权服务器<br />
<br />
::- 两个域之间不存在服务器间的流: 发送者服务器 (1) 解析这个外部域的主机名(定义在服务器间的通信Server-to-Server Communications (第十四章第四节)), (2) 在两个域之间进行服务器到服务器的流协商(定义在 Use of TLS (第五章) 和 Use of SASL (第六章)), 然后 (3) 通过这个新建的流为外部域路由这个节到授权服务器<br />
<br />
:如果路由到接收者的服务器不成功, 发送者的服务器必须(MUST)返回一个错误给发送者; 如果接收者的服务器联系上了但是从接收者的服务器递送到接收者不成功, 接收者服务器必须(MUST)通过发送者的服务器返回一个错误给发送者.<br />
<br />
===子域===<br />
<br />
:如果'to'属性中的JID的域ID部分的主机名和服务器自身配置的主机名的一个子域名匹配,服务器必须(MUST)自己处理这个节或路由这个节到专门负责这个子域的特定服务(如果子域被配置了),或者返回一个错误给发送者(如果子域没有配置).<br />
<br />
===纯粹的域或特定的资源===<br />
<br />
:如果'to'属性中的JID的域ID部分的主机名和服务器自身配置的主机名本身匹配,并且'to'属性中的JID类型是<domain> 或 <domain/resource>, 服务器(或其中定于的资源)必须(MUST)根据节的类型适当的处理这个节或返回一个错误节给发送者.<br />
<br />
===同一域中的节点===<br />
<br />
:如果'to'属性中的JID的域ID部分的主机名和服务器自身配置的主机名本身匹配,并且'to'属性中的JID类型是<node@domain> 或 <node@domain/resource>, 服务器应该(SHOULD)递送这个节到节的'to'属性中的JID所指明的预定的接收者. 以下规则适用:<br />
<br />
:# 如果这个JID包含一个资源ID(例如, 格式是<node@domain/resource>)并且存在一个连接的资源符合这个全JID, 接收者服务器应该(SHOULD)递送这个节给正确符合这个资源ID的流或会话.<br />
:# 如果这个JID包含一个资源ID(例如, 格式是<node@domain/resource>)并且不存在一个连接的资源符合这个全JID, 接收者服务器应该(SHOULD)返回一个<service-unavailable/> 节错误给发送者.<br />
:# 如果这个JID的格式是<node@domain>并且存在至少一个此节点的连接资源, 接收服务器应该( SHOULD)递送这个节给至少其中一个已连接的资源, 依据应用程序定义的规则(一系列即时消息和出席信息应用程序的递送规则定义在[XMPP-IM|XMPP文档列表/XMPP正式RFC标准/RFC3921]).<br />
<br />
==XMPP中的XML用法==<br />
<br />
===限制===<br />
<br />
:XMPP是一个简单的流式XML元素的专用协议用于接近实时地交换结构化信息. 因为XMPP不需要任意的解析和所有的XML文档, 所以XMPP不需要支持\[XML\]的所有功能. 特殊的, 适用以下限制.<br />
<br />
:关于XML生成, 一个XMPP实现不能(MUST NOT)在XML流中注入以下任何东西:<br />
<br />
:* 注释 (第二章第五节[XML])<br />
<br />
:* 处理指示(第二章第六节 同上)<br />
<br />
:* 内部或外部的 DTD 子集 (第二章第八节 同上)<br />
<br />
:* 内部或外部的实体参考 (第四章第二节 同上) 除了预定实体以外(第四章第六节 同上)<br />
<br />
:* 字符数据或属性值包含和预定实体列表中吻合的未逃逸的unescaped字符(第四章第六节 同上); 这些字符必须(MUST)逃逸<br />
<br />
:关于XML处理, 如果一个XMPP实现接收到这些受限的XML数据,它必须(MUST)忽略这些数据.<br />
<br />
===XML 名字空间的名字和前缀===<br />
<br />
:XML名字空间\[XML-NAMES\]为所有XMPP兼容的XML建立数据所有权的严格界限. 这个名字空间的基本功能是把结构上混合在一起的XML元素区分出不同的词汇. 确保XMPP兼容的XML有名字空间的感知能力使得任何允许的XML可以被结构化的混合到任何XMPP数据元素中. XML名字空间的名字和前缀的规则在下一小节中.<br />
<br />
====流名字空间====<br />
<br />
:在所有的XML流头中必须声明一个流名字空间. 流名字空间必须(MUST)是 'http://etherx.jabber.org/streams'. 元素名<stream/>和它的<features/>和<error/>子元素必须(MUST)在所有实例中符合这个流名字空间前缀. 一个实现应该(SHOULD)只为这些元素生成'stream:'前缀, 并且由于历史原因可以(MAY)只接受'stream:'前缀.<br />
<br />
====缺省名字空间====<br />
<br />
:在所有的XML流中必须声明一个缺省的流名字空间用于定义允许的流根元素的一级子元素. 这个名字空间声明对于初始化流和应答流必须(MUST)是相同的使得双方的流都是合格一致的. 缺省的名字空间声明适用于流和所有在流中发送的节(除非由流名字空间或回拨名字空间的前缀显式的符合另一个名字空间).<br />
<br />
:一个服务器实现必须(MUST)支持以下两个缺省名字空间(由于历史原因, 一些实现可能(MAY)只支持这两个缺省名字空间):<br />
<br />
:* jabber:client -- 当流用于客户端和服务器的通信时声明这个缺省名字空间<br />
<br />
:* jabber:server -- 当流用于两个服务器间的通信时声明这个缺省名字空间<br />
<br />
:一个客户端实现必须(MUST)支持'jabber:client'缺省名字空间,并且由于历史原因可以(MAY)只支持这个缺省名字空间.<br />
<br />
:如果缺省名字空间是'jabber:client'或'jabber:server',一个实施不能(MUST NOT)在这个名字空间下为元素生成名字空间前缀. 一个实现不应该(SHOULD NOT)按照元素的内容(可能和流相反)生成不同于'jabber:client'和'jabber:server'名字空间前缀.<br />
<br />
:注意: 'jabber:client' 和 'jabber:server' 名字空间接近于相同但是用于不同的上下文(客户端服务器通信用'jabber:client' 而服务器间通信用'jabber:server'). 这两者之间仅有的不同在于在'jabber:client'中被发送的节中'to'和'from'属性是可选的(OPTIONAL),而在'jabber:server'中被发送的节中它们是必需的(REQUIRED). 如果兼容的实施接受一个符合'jabber:client'或'jabber:server'名字空间的流, 它必须(MUST)支持通用属性(第九章第一节)和三个核心节类型(message, presence, 和IQ)的基本语义(第九章第二节).<br />
<br />
====回拨名字空间====<br />
<br />
:所有用于服务器回拨的(第八章)元素都必须声明一个回拨名字空间. 回拨名字空间的名字必须(MUST)是'jabber:server:dialback'. 所有符合此名字空间的元素必须(MUST)有前缀. 一个实现应该(SHOULD)只为这些元素生成'db:'前缀并且只可以(MAY)接受'db:'前缀.<br />
<br />
===确认===<br />
<br />
:除了注意'jabber:server'名字空间中关于节中'to'和'from'地址的规定,一个服务器不需要为转发到客户端或其他服务器负责检查XML元素;一个实现可以(MAY)选择仅提供有效数据元素但这是可选的(OPTIONAL)(尽管一个实现不能(MUST NOT)接受不规范的XML). 客户端不应该(SHOULD NOT)滥用发送不符合schema的数据的能力, 并且应该(SHOULD)忽略接收到的XML流中任何和schema不一致的元素或属性值. XML流和节的有效性确认是可选的(OPTIONAL),并且在这里提到的schemas仅用于描述的用途.<br />
<br />
===文本声明的包含===<br />
<br />
:实现应该(SHOULD)在发送一个流头信息之前发送一个文本声明. 应用程序必须(MUST)遵守\[XML\]中关于环境(那里对文本声明做了规定)的规则.<br />
<br />
===字符编码===<br />
<br />
:实现必须(MUST)支持通用字符集Universal Character Set (ISO/IEC 10646-1 \[UCS2\])字符到UTF\-8(RFC 3629 \[UTF\-8\])的转换, 必须符合 RFC 2277 \[CHARSET\]. 实现不能(MUST NOT)试图使用任何其他的编码.<br />
<br />
==核心的兼容性要求==<br />
<br />
:本章总结了可扩展的消息和出席信息协议中的某些方面,为了实施的兼容性,它们必须(MUST)被服务器和客户端支持,当然协议的其他方面也应该(SHOULD)被支持. 为了兼容的目的, 我们在核心协议(它必须(MUST)被任何服务器或客户端支持, 无论是什么特定的应用)和即时消息协议(仅仅是在核心协议之上的即时消息和出席信息应用必须(MUST)支持它)之间划了一个级别. 在本章中定义了所有服务器和客户端的兼容性要求; 即时消息服务器和客户端的兼容性要求在[XMPP-IM|XMPP文档列表/XMPP正式RFC标准/RFC3921]的相关章节中定义.<br />
<br />
===服务器===<br />
<br />
:除了所有已定义的关于安全, XML使用, 和国际化的要求之外, 一个服务器还必须(MUST)支持以下核心协议以保证兼容性:<br />
<br />
:* 在地址中应用\[STRINGPREP\] 的 \[NAMEPREP\], Nodeprep (附录 A),和 Resourceprep (附录 B) profiles (包括确保域ID是\[IDNA\]中定义的国际化域名)<br />
<br />
:* XML流(第四章), 包括Use of TLS(第五章), Use of SASL(第六章), 和Resource Binding (第七章)<br />
<br />
:* 三个在stanza semantics(第九章第二节)中已定义的节类型(即,<message/>, <presence/>, 和<iq/>)的基本语义<br />
<br />
:* 生成错误的语法及相关的流, TLS, SASL, 和 XML节的语义<br />
<br />
:另外, 一个服务器可以(MAY)支持以下核心协议:<br />
<br />
:* 服务器回拨 (第八章)<br />
<br />
===客户端===<br />
<br />
:一个客户端必须(MUST)支持以下核心协议以满足兼容性:<br />
<br />
:* XML流(第四章), 包括Use of TLS(第五章), Use of SASL(第六章), 和Resource Binding (第七章)<br />
<br />
:* 三个在stanza semantics(第九章第二节)中已定义的节类型(即,<message/>, <presence/>, 和<iq/>)的基本语义<br />
<br />
:* 处理(并且, 如果可能, 生成) 错误的语法及相关的流, TLS, SASL, 和 XML节的语义<br />
<br />
:另外, 一个客户端应该(SHOULD)支持以下核心协议:<br />
<br />
:* 地址的生成应用\[STRINGPREP\] 的 \[NAMEPREP\], Nodeprep (附录 A),和 Resourceprep (附录 B) profiles <br />
<br />
==国际化事项==<br />
<br />
:XML流在Character Encoding(第十一章第五节)中定义为必须(MUST)被编码成UTF\-8. 在Stream Attributes(第四章第四节)中特别定义了, 一个XML流应该(SHOULD)包含一个'xml:lang'属性,它被认为是通过这个用于人类用户解读的流发送的任何XML字符数据的缺省语言. 在 xml:lang (第九章第一节第五小节)特别定义了, 如果一个XML节是用来给人类用户解读,这个节应该(SHOULD)包含一个'xml:lang'属性. 服务器在为连接的实体路由或递送节的时候应该(SHOULD)应用缺省的'xml:lang'属性, 并且不能(MUST NOT)修改或删除它从其他实体收到的节的'xml:lang'属性.<br />
<br />
==安全性事项==<br />
<br />
===高安全性===<br />
<br />
:为了XMPP通信的目的(客户端-服务器 和 服务器-服务器), "高安全性"条款谈的是相互验证和完整性检查安全性技术的使用; 特别是, 当使用基于证书的验证来提供高安全性, 应该( SHOULD)建立一个带外的信任链,尽管一个共享签名证书可能允许以前不知道的证书在带内建立信任关系. 参见以下第十四章第二节关于证书确认程序.<br />
<br />
:实施必须(MUST)支持高安全性. 服务提供者应该(SHOULD)基于本地安全策略使用高安全性.<br />
<br />
===证书确认===<br />
<br />
:当一个XMPP点和另一个XMPP点安全的地通信, 它必须(MUST)确认对方终端的证书.有三种可能的情况:<br />
<br />
:情形 #1: 点包含一个终端实体证书,以根证书的证书链中一环出现(见\[X509\]中的第六章第一节).<br />
<br />
:情形 #2: 点的证书由一个对方不知道的证书授权.<br />
<br />
:情形 #3: 点的证书由自己签名.<br />
<br />
:在情形#1, 确认方必须(MUST)做以下两条之一:<br />
<br />
:# 根据\[X509\]的规则确认对方证书.然后证书应该(SHOULD)被对方接下来在\[HTTP-TLS\]中描述的规则反向确认预期的身份。但如果"xmpp"是subjectAltName扩展类型,则必须(MUST)使用证书中的显示的身份。如果这两项检查之一失败,用户导向的客户端必须(MUST)通知用户(客户端可以(MAY)给用户机会继续连接)或以一个坏证书的错误终止连接。自动客户端应该(SHOULD)终止连接(以一个坏证书错误)并在适当的日志中记录这个错误。自动客户端可以(MAY)提供一个配置设置成禁止检查,但同时必须(MUST)提供一个激活检查的配置。<br />
:# 点应该(SHOULD)出示证书给一个用户用于批准,包括完整的证书链.点必须(MUST)缓存这个证书(或一些其他不会忘记的表达方式比如一个哈希值).在将来的连接中,点必须(MUST)展示相同的证书并且如果改变了证书必须(MUST)通知用户.<br />
<br />
:在情形#2 和情形#3, 实现应该(SHOULD)执行上述第二条.<br />
<br />
===客户端-服务器通信===<br />
<br />
:一个兼容的客户端实现必须(MUST)支持TLS和SASL用于连接到服务器.<br />
<br />
:用于加密XML流的TLS协议(在 Use of TLS(第五章)定义)提供可信的机制帮助确保机密性和实体之间数据交换的完整性.<br />
<br />
:用于验证XML流的SASL协议(在 Use of SASL(第六章)定义)提供可靠的机制用于确认一个连接到服务器的客户端确实是它自己所声明的那个客户端.<br />
<br />
:服务器宣称的DNS主机名被解析之前,客户端-服务器通信不能(MUST NOT)继续进行。应该首先尝试解析\[SRV\]记录,其服务名为"xmpp-client",协议名为"tcp",整个资源记录类似"_xmpp-client._tcp.example.com."(使用字符"xmpp-client"表示服务ID是经过IANA注册).如果SRV查找失败,退而求其次,将查找一个正规的IPv4/IPv6地址记录来决定IP地址,使用"xmpp-client"端口5222,这个端口是在IANA注册了的。<br />
<br />
:客户端的IP地址和访问方法不能(MUST NOT)被服务器公开, 也不能被被任何原始服务器之外的服务器索取。这帮助保护客户端的服务器避免受到直接攻击(译者注:似乎应该是客户避免受到直接攻击,但原文如此)或被第三方知道它的身份。<br />
<br />
===服务器-服务器通信===<br />
<br />
:一个兼容的服务器实现必须(MUST)支持TLS和SASL,用于域间的通信.因为历史原因,一个兼容的实施也应该(SHOULD)支持服务器回拨(第八章).<br />
<br />
:因为服务提供者是一个策略问题,对于任何给定域和其他域的通信中,它是可选的(OPTIONAL),服务器之间的通信可以(MAY)被任何特定部署的管理员禁止。如果一个特殊的域允许域间的通信,它应该(SHOULD)允许高安全性。<br />
<br />
:管理员可能想在服务器间使用SASL来通信,以确保双方的验证和保密性(比如在机构的私有网络).兼容实施应该(SHOULD)为这个目的支持SASL.<br />
<br />
:服务器宣称的DNS主机名被解析之前,服务器-服务器通信不能(MUST NOT)继续进行。应该首先尝试解析\[SRV\]记录,其服务名为"xmpp-server",协议名为"tcp",整个资源记录类似"_xmpp-server._tcp.example.com."(使用字符"xmpp-server"表示服务ID是经过IANA注册的,注意要用"xmpp-server"取代以前用的"jabber",因为以前的用法不符合[SRV]标准;希望保持向后兼容的实现可以继续查找或应答"jabber"服务ID).如果SRV查找失败,退而求其次,将查找一个正规的IPv4/IPv6地址记录来决定IP地址,使用"xmpp-server"端口5269,这个端口是在IANA注册了的。<br />
<br />
:服务器回拨防止域欺骗,从而使得伪造XML节更为困难.它和SASL和TLS不一样,它不是一个用于验证、安全或加密服务器之间的流的机制, 所以只是服务器身份的微弱确认而已。而且除非它使用了DNSSec \[DNSSEC\]否则它 容易受到DNS中毒攻击,即使DNS信息是正确的,如果攻击者劫持了远程域,回拨也不能防止它的攻击.需要健壮的安全性的域应该(SHOULD)使用TLS和SASL.如果服务器间的验证使用了SASL,回拨就不应该(SHOULD NOT)使用了,因为它是多余的.<br />
<br />
===层的次序===<br />
<br />
:协议中的层的次序必须(MUST)如下堆积:<br />
<br />
:# TCP<br />
:# TLS<br />
:# SASL<br />
:# XMPP<br />
<br />
:这个次序的原理是,[TCP]是基于连接的层,被所有使用,所以处于最上层, [TLS]经常是由操作系统层提供,[SASL]经常由应用程序层提供, XMPP则是应用程序本身.<br />
<br />
===缺乏绑定到TLS的SASL通道===<br />
<br />
:SASL构架不提供一个机制来绑定SASL验证到一个提供机密性和完整性保护的安全层。这一通道绑定"channel binding"的缺乏阻碍了SASL确认低层安全性所绑定的源和目标终端和SASL所验证的结果是否一致。如果终端不一致, 低层安全性不能被信任用来保护SASL验证的实体之间的数据传输。在这种情况下,一个SASL安全层进行握手的时候应该有效的忽略低层安全性的存在。<br />
<br />
===强制实现的技术===<br />
<br />
:最低要求, 所有实现必须(MUST)支持以下机制:<br />
<br />
::对于验证: SASL [DIGEST-MD5] 机制<br />
<br />
::对于机密性: TLS (使用 TLS_RSA_WITH_3DES_EDE_CBC_SHA 密码)<br />
<br />
::对于两者: TLS 加 SASL EXTERNAL(使用 TLS_RSA_WITH_3DES_EDE_CBC_SHA 密码支持客户端证书)<br />
<br />
===防火墙===<br />
<br />
:使用XMPP通信通常是通过\[TCP\]连接到5222端口(客户端-服务器)或5269端口(服务器-服务器), 正如在IANA注册的那样(见 IANA Considerations (第十五章)). 使用这些广为人知的端口允许管理员很容易的通过一般的防火墙来激活或禁止XMPP活动.<br />
<br />
===在SASL中使用base64===<br />
<br />
:客户端和服务器都必须(MUST)确认在SASL协商中收到的任何\[BASE64\]数据. 一个实现必须(MUST)拒绝(不是忽略)任何非显式允许base64字母的字符串; 这有助于预防建立隐蔽通道泄漏信息的行为。一个实现不能(MUST NOT)在非法输入处中断,如果那个('=')被包含在一些和最后的数据字符(如, "=AAA" or "BBBB=CCC")不同的东西里面,必须(MUST)拒绝接下来的任何包含('=')的base64字符;这有助于防止对这个实现的缓存溢出攻击和其他攻击。Base 64编码从外表看隐藏了容易辨认的信息,例如密码,但是不提供任何算法机密性。Base 64编码必须(MUST)按照RFC 3548\[BASE64\]第三章的定义执行。<br />
<br />
===Stringprep Profiles===<br />
<br />
:为了处理域ID,XMPP使用了\[STRINGPREP\]中的\[NAMEPREP\] profile; 和Nameprep有关的安全性考虑, 参考\[NAMEPREP\]中的相关章节.<br />
<br />
:另外, XMPP 定义了两个\[STRINGPREP\]的 profiles: 用于node identifiers的Nodeprep(附录 A)和用于resource identifiers的Resourceprep(附录 B).<br />
<br />
:Unicode 和 ISO/IEC 10646 集有许多字符看起来相似. 在许多时候, 安全协议的使用者可能看起来吻合,比如当比较信任的第三方的名字的时候. 因为没有很多上下文的时候不可能映射看起来相似的字符,比如知道所用的字符集, stringprep不匹配相似字符串,也不因为一些字符串象看起来象别的字符串而禁止它们.<br />
<br />
:一个节点ID可能被作为一个实体的XMPP地址的一部分. 一个通常的用途是作为一个即时消息用户的用户名;另一个用途是作为一个多用途聊天室的名字; 很多其他种类的实体可能使用节点ID作为他们的地址的一部分。 这些服务的安全性可能会受到国际化节点ID的不同表达的威胁;例如, 一个用户键入一个单独的国际化的节点ID可能访问了另一个用户的帐号信息, 或一个用户可能获得访问一个受限的聊天室或服务的访问权限.<br />
<br />
:一个资源ID可能被作为一个实体的XMPP地址的一部分。一个通常的用户是即时消息用户所连接的资源(激活的会话)的名字; 另一个是作为多用户聊天室的某用户的昵称; 许多其他种类的实体可能使用资源ID作为他们地址的一部分.这些服务的安全性可能会受到国际化资源ID的不同表达的威胁;例如, 一个用户可能尝试以同一个名字初始化多个会话,或一个用户可能发送一个消息给多用户聊天室的一个人但实际上发给了另外一个人.<br />
<br />
==IANA 事项==<br />
<br />
===用于TLS数据的XML名字空间名===<br />
<br />
:XMPP中用于TLS相关数据的 URN 子名字空间定义如下. (这个名字空间的名字遵守The IETF XML Registry [XML-REG]定义的格式.)<br />
<br />
::URI: urn:ietf:params:xml:ns:xmpp-tls<br />
<br />
::Specification: RFC 3920<br />
<br />
::Description: This is the XML namespace name for TLS-related data in the Extensible Messaging and Presence Protocol (XMPP) as defined by RFC 3920.<br />
<br />
::Registrant Contact: IETF, XMPP Working Group, <xmppwg@jabber.org><br />
<br />
===用于SASL数据的XML名字空间名===<br />
<br />
:XMPP中用于SASL相关数据的 URN 子名字空间定义如下. (这个名字空间的名字遵守The IETF XML Registry \[XML-REG\]定义的格式.)<br />
<br />
::URI: urn:ietf:params:xml:ns:xmpp-sasl<br />
<br />
::Specification: RFC 3920<br />
<br />
::Description: This is the XML namespace name for SASL-related data in the Extensible Messaging and Presence Protocol (XMPP) as defined by RFC 3920.<br />
<br />
::Registrant Contact: IETF, XMPP Working Group, <xmppwg@jabber.org><br />
<br />
===用于流错误的XML名字空间名===<br />
<br />
:XMPP中用于流相关错误的 URN 子名字空间定义如下. (这个名字空间的名字遵守The IETF XML Registry [XML-REG]定义的格式.)<br />
<br />
::URI: urn:ietf:params:xml:ns:xmpp-streams<br />
<br />
::Specification: RFC 3920<br />
<br />
:Description: This is the XML namespace name for stream-related error data in the Extensible Messaging and Presence Protocol (XMPP) as defined by RFC 3920.<br />
<br />
::Registrant Contact: IETF, XMPP Working Group, <xmppwg@jabber.org><br />
<br />
===用于资源绑定的XML名字空间名===<br />
<br />
:XMPP中用于资源绑定的 URN 子名字空间定义如下. (这个名字空间的名字遵守The IETF XML Registry [XML-REG]定义的格式.)<br />
<br />
::URI: urn:ietf:params:xml:ns:xmpp-bind<br />
<br />
::Specification: RFC 3920<br />
<br />
::Description: This is the XML namespace name for resource binding in the Extensible Messaging and Presence Protocol (XMPP) as defined by RFC 3920.<br />
<br />
::Registrant Contact: IETF, XMPP Working Group, <xmppwg@jabber.org><br />
<br />
===用于节错误的XML名字空间名===<br />
<br />
:XMPP中用于节相关错误数据的 URN 子名字空间定义如下. (这个名字空间的名字遵守The IETF XML Registry \[XML-REG\]定义的格式.)<br />
<br />
::URI: urn:ietf:params:xml:ns:xmpp-stanzas<br />
<br />
::Specification: RFC 3920<br />
<br />
::Description: This is the XML namespace name for stanza-related error data in the Extensible Messaging and Presence Protocol (XMPP) as defined by RFC 3920.<br />
<br />
::Registrant Contact: IETF, XMPP Working Group, <xmppwg@jabber.org><br />
<br />
===Nodeprep Profile of Stringprep===<br />
<br />
:The Nodeprep profile of stringprep是在Nodeprep(附录 A)定义的. IANA已经在stringprep profile registry中注册了 Nodeprep.<br />
<br />
::Name of this profile:<br />
<br />
:::Nodeprep<br />
<br />
::RFC in which the profile is defined:<br />
<br />
:::RFC 3920<br />
<br />
::Indicator whether or not this is the newest version of the profile:<br />
<br />
:::This is the first version of Nodeprep<br />
<br />
===Resourceprep Profile of Stringprep===<br />
<br />
:The Resourceprep profile of stringprep是在Resourceprep(附录 B)定义的. IANA已经在stringprep profile registry中注册了Resourceprep.<br />
<br />
::Name of this profile:<br />
<br />
:::Resourceprep<br />
<br />
::RFC in which the profile is defined:<br />
<br />
:::RFC 3920<br />
<br />
::Indicator whether or not this is the newest version of the profile:<br />
<br />
:::This is the first version of Resourceprep<br />
<br />
===GSSAPI 服务名===<br />
<br />
:IANA已经注册了 "xmpp" 作为一个 GSSAPI \[GSS-API\] 服务名, 在SASL Definition (第六章第三节)定义了.<br />
<br />
===端口号===<br />
<br />
:IANA已经注册了"xmpp-client" 和 "xmpp-server" 作为\[TCP\]端口号5222和5269的关键字.<br />
<br />
:这些端口应该(SHOULD)用于客户端-服务器 和 服务器-服务器通信,但它们的使用是可选的(OPTIONAL).<br />
<br />
==参考==<br />
<br />
===标准化参考===<br />
<br />
:[ABNF] Crocker, D. and P. Overell, "Augmented BNF for Syntax Specifications: ABNF", RFC 2234, November 1997.<br />
<br />
:[BASE64] Josefsson, S., "The Base16, Base32, and Base64 Data Encodings", RFC 3548, July 2003.<br />
<br />
:[CHARSET] Alvestrand, H., "IETF Policy on Character Sets and Languages", BCP 18, RFC 2277, January 1998.<br />
<br />
:[DIGEST-MD5] Leach, P. and C. Newman, "Using Digest Authentication as a SASL Mechanism", RFC 2831, May 2000.<br />
<br />
:[DNS] Mockapetris, P., "Domain names \- implementation and specification", STD 13, RFC 1035, November 1987.<br />
<br />
:[GSS-API] Linn, J., "Generic Security Service Application Program Interface Version 2, Update 1", RFC 2743, January 2000.<br />
<br />
:[HTTP-TLS] Rescorla, E., "HTTP Over TLS", RFC 2818, May 2000.<br />
<br />
:[IDNA] Faltstrom, P., Hoffman, P., and A. Costello, "Internationalizing Domain Names in Applications (IDNA)", RFC 3490, March 2003.<br />
<br />
:[IPv6] Hinden, R. and S. Deering, "Internet Protocol Version 6 (IPv6) Addressing Architecture", RFC 3513, April 2003.<br />
<br />
:[LANGTAGS] Alvestrand, H., "Tags for the Identification of Languages", BCP 47, RFC 3066, January 2001.<br />
<br />
:[NAMEPREP] Hoffman, P. and M. Blanchet, "Nameprep: A Stringprep Profile for Internationalized Domain Names (IDN)", RFC 3491, March 2003.<br />
<br />
:[RANDOM] Eastlake 3rd, D., Crocker, S., and J. Schiller, "Randomness Recommendations for Security", RFC 1750, December 1994.<br />
<br />
:[SASL] Myers, J., "Simple Authentication and Security Layer (SASL)", RFC 2222, October 1997.<br />
<br />
:[SRV] Gulbrandsen, A., Vixie, P., and L. Esibov, "A DNS RR for specifying the location of services (DNS SRV)", RFC 2782, February 2000.<br />
<br />
:[STRINGPREP] Hoffman, P. and M. Blanchet, "Preparation of Internationalized Strings ("stringprep")", RFC 3454, December 2002.<br />
<br />
:[TCP] Postel, J., "Transmission Control Protocol", STD 7, RFC 793, September 1981.<br />
<br />
:[TERMS] Bradner, S., "Key words for use in RFCs to Indicate Requirement Levels", BCP 14, RFC 2119, March 1997.<br />
<br />
:[TLS] Dierks, T. and C. Allen, "The TLS Protocol Version 1.0", RFC 2246, January 1999.<br />
<br />
:[UCS2] International Organization for Standardization, "Information Technology \- Universal Multiple-octet coded Character Set (UCS) - Amendment 2: UCS Transformation Format 8 (UTF-8)", ISO Standard 10646-1 Addendum 2, October 1996.<br />
<br />
:[UTF-8] Yergeau, F., "UTF-8, a transformation format of ISO 10646", STD 63, RFC 3629, November 2003.<br />
<br />
:[X509] Housley, R., Polk, W., Ford, W., and D. Solo, "Internet X.509 Public Key Infrastructure Certificate and Certificate Revocation List (CRL) Profile", RFC 3280, April 2002.<br />
<br />
:[XML] Bray, T., Paoli, J., Sperberg-McQueen, C., and E. Maler, "Extensible Markup Language (XML) 1.0 (2nd ed)", W3C REC-xml, October 2000, <http://www.w3.org/TR/REC-xml>.<br />
<br />
:[XML-NAMES] Bray, T., Hollander, D., and A. Layman, "Namespaces in XML", W3C REC-xml-names, January 1999, <http://www.w3.org/TR/REC-xml-names>.<br />
<br />
===信息参考===<br />
<br />
:[ACAP] Newman, C. and J. Myers, "ACAP \-\- Application Configuration Access Protocol", RFC 2244, November 1997.<br />
<br />
:[ASN.1] CCITT, "Recommendation X.208: Specification of Abstract Syntax Notation One (ASN.1)", 1988.<br />
<br />
<br />
:[DNSSEC] Eastlake 3rd, D., "Domain Name System Security Extensions", RFC 2535, March 1999.<br />
<br />
:[HTTP] Fielding, R., Gettys, J., Mogul, J., Frystyk, H., Masinter, L., Leach, P., and T. Berners-Lee, "Hypertext Transfer Protocol -- HTTP/1.1", RFC 2616, June 1999.<br />
<br />
:[IMAP] Crispin, M., "INTERNET MESSAGE ACCESS PROTOCOL - VERSION 4rev1", RFC 3501, March 2003.<br />
<br />
:[IMP-REQS] Day, M., Aggarwal, S., Mohr, G., and J. Vincent, "Instant Messaging \/ Presence Protocol Requirements", RFC 2779, February 2000.<br />
<br />
:[IRC] Oikarinen, J. and D. Reed, "Internet Relay Chat Protocol", RFC 1459, May 1993.<br />
<br />
:[JEP-0029] Kaes, C., "Definition of Jabber Identifiers (JIDs)", JSF JEP 0029, October 2003.<br />
<br />
:[JEP-0078] Saint-Andre, P., "Non-SASL Authentication", JSF JEP 0078, July 2004.<br />
<br />
[JEP-0086] Norris, R. and P. Saint-Andre, "Error Condition Mappings", JSF JEP 0086, February 2004.<br />
<br />
:[JSF] Jabber Software Foundation, "Jabber Software Foundation", <http://www.jabber.org/>.<br />
<br />
:[POP3] Myers, J. and M. Rose, "Post Office Protocol - Version 3", STD 53, RFC 1939, May 1996.<br />
<br />
:[SIMPLE] SIMPLE Working Group, "SIMPLE WG", <http://www.ietf.org/html.charters/simple-charter.html>.<br />
<br />
:[SMTP] Klensin, J., "Simple Mail Transfer Protocol", RFC 2821, April 2001.<br />
<br />
:[URI] Berners-Lee, T., Fielding, R., and L. Masinter, "Uniform Resource Identifiers (URI): Generic Syntax", RFC 2396, August 1998.<br />
<br />
:[USINGTLS] Newman, C., "Using TLS with IMAP, POP3 and ACAP", RFC 2595, June 1999.<br />
<br />
:[XML-REG] Mealling, M., "The IETF XML Registry", BCP 81, RFC 3688, January 2004.<br />
<br />
:[[RFC3921]] Saint-Andre, P., Ed., "Extensible Messaging and Presence Protocol (XMPP): Instant Messaging and Presence", RFC 3921, October 2004.<br />
<br />
<br />
==附录 A. Nodeprep==<br />
<br />
===A.1. 介绍===<br />
<br />
:这个附录定义了 "Nodeprep" profile of [STRINGPREP]. 它定义了处理规则让用户能够在XMPP中输入国际化节点标识符并尽可能正确的获取正确的字符内容. (一个XMPP节点标识符是XMPP地址的可选部分,它在域名标识符和那个'@'分隔符之前;它经常但不是专门用来关联一个即时消息用户名)这些处理规则仅仅适用于XMPP节点标识符但不适用于任意文本或任何XMPP的其他方面.<br />
<br />
:这个脚本定义了以下这些, 正如 [STRINGPREP]要求的:<br />
<br />
:* 脚本预期的适用性: XMPP的国际化节点标识符<br />
<br />
:* 用于stringprep的输入输出字符集: Unicode 3.2, 定义在本附录的第二章<br />
<br />
:* 使用的映射: 定义在第三章<br />
<br />
:* Unicode正规化使用: 定义在第四章<br />
<br />
:* 禁止输出的字符串: 定义在第五章<br />
<br />
:* 双字节字符处理: 定义在第六章<br />
<br />
===A.2. 字符集===<br />
<br />
:本脚本使用Unicode 3.2的未分配编码列表,指向 Table A.1, 也定义在 [STRINGPREP]的附录 A 中.<br />
<br />
===A.3. 映射===<br />
<br />
:本脚本指定使用[STRINGPREP]的以下表:<br />
<br />
::Table B.1<br />
<br />
::Table B.2<br />
<br />
===A.4. 正规化===<br />
<br />
:本脚本指定 Unicode正规化使用 form KC, 定义在 [STRINGPREP]中.<br />
<br />
===A.5. 禁止输出===<br />
<br />
:本脚本指定使用以下的[STRINGPREP]表禁止输出.<br />
<br />
::Table C.1.1<br />
<br />
::Table C.1.2<br />
<br />
::Table C.2.1<br />
<br />
::Table C.2.2<br />
<br />
::Table C.3<br />
<br />
::Table C.4<br />
<br />
::Table C.5<br />
<br />
::Table C.6<br />
<br />
::Table C.7<br />
<br />
::Table C.8<br />
<br />
::Table C.9<br />
<br />
:另外, 以下Unicode字符也被禁止:<br />
<br />
: #x22 (")<br />
<br />
: #x26 (&)<br />
<br />
: #x27 (')<br />
<br />
: #x2F (/)<br />
<br />
: #x3A (:)<br />
<br />
: #x3C (<)<br />
<br />
: #x3E (>)<br />
<br />
: #x40 (@)<br />
<br />
===A.6. 双字节===<br />
<br />
:本脚本指定按照[STRINGPREP]第六章检查双字节.<br />
<br />
==附录 B. Resourceprep==<br />
<br />
===B.1. 介绍===<br />
<br />
:这个附录定义了 "Resourceprep" profile of \[STRINGPREP\]. 它定义了处理规则让用户能够在XMPP中输入国际化资源标识符并尽可能正确的获取正确的字符内容. (一个XMPP资源标识符是XMPP地址的可选部分,它在域名标识符和'/@'分隔符之后;它经常但不是专门用来关联一个即时消息会话名)这些处理规则仅仅适用于XMPP资源标识符但不适用于任意文本或任何XMPP的其他方面.<br />
<br />
:这个脚本定义了以下这些, 正如 [STRINGPREP]要求的:<br />
<br />
:* 脚本预期的适用性: XMPP的国际化节点标识符<br />
<br />
:* 用于stringprep的输入输出字符集: Unicode 3.2, 定义在本附录的第二章<br />
<br />
:* 使用的映射: 定义在第三章<br />
<br />
:* Unicode正规化使用: 定义在第四章<br />
<br />
:* 禁止输出的字符串: 定义在第五章<br />
<br />
:* 双字节字符处理: 定义在第六章<br />
<br />
===B.2. 字符集===<br />
<br />
:本脚本使用Unicode 3.2的未分配编码列表,指向 Table A.1, 也定义在 [STRINGPREP]的附录<br />
<br />
===B.3. 映射===<br />
<br />
:本脚本指定使用[STRINGPREP]的以下表:<br />
<br />
::Table B.1<br />
<br />
===B.4. 正规化===<br />
<br />
:本脚本指定使用 Unicode normalization form KC, 定义在 [STRINGPREP]中.<br />
<br />
===B.5. 禁止输出===<br />
<br />
:本脚本指定使用以下的[STRINGPREP]表禁止输出.<br />
<br />
::Table C.1.2<br />
<br />
::Table C.2.1<br />
<br />
::Table C.2.2<br />
<br />
::Table C.3<br />
<br />
::Table C.4<br />
<br />
::Table C.5<br />
<br />
::Table C.6<br />
<br />
::Table C.7<br />
<br />
::Table C.8<br />
<br />
::Table C.9<br />
<br />
===B.6. 双字节===<br />
<br />
:本脚本指定按照[STRINGPREP]第六章检查双字节.<br />
<br />
==附录 C. XML 规划==<br />
<br />
:以下 XML schemas 是描述性的, 不是标准的. 'jabber:client' 和 'jabber:server' 名字空间的标准定义, 参照 [[RFC3921]].<br />
<br />
===C.1. Streams namespace===<br />
<br />
<source lang="xml"><br />
<?xml version='1.0' encoding='UTF-8'?><br />
<br />
<xs:schema<br />
xmlns:xs='http://www.w3.org/2001/XMLSchema'<br />
targetNamespace='http://etherx.jabber.org/streams'<br />
xmlns='http://etherx.jabber.org/streams'<br />
elementFormDefault='unqualified'><br />
<br />
<xs:element name='stream'><br />
<xs:complexType><br />
<xs:sequence xmlns:client='jabber:client'<br />
xmlns:server='jabber:server'<br />
xmlns:db='jabber:server:dialback'><br />
<xs:element ref='features' minOccurs='0' maxOccurs='1'/><br />
<xs:any namespace='urn:ietf:params:xml:ns:xmpp-tls'<br />
minOccurs='0'<br />
maxOccurs='unbounded'/><br />
<xs:any namespace='urn:ietf:params:xml:ns:xmpp-sasl'<br />
minOccurs='0'<br />
maxOccurs='unbounded'/><br />
<xs:choice minOccurs='0' maxOccurs='1'><br />
<xs:choice minOccurs='0' maxOccurs='unbounded'><br />
<xs:element ref='client:message'/><br />
<xs:element ref='client:presence'/><br />
<xs:element ref='client:iq'/><br />
</xs:choice><br />
<xs:choice minOccurs='0' maxOccurs='unbounded'><br />
<xs:element ref='server:message'/><br />
<xs:element ref='server:presence'/><br />
<xs:element ref='server:iq'/><br />
<xs:element ref='db:result'/><br />
<xs:element ref='db:verify'/><br />
</xs:choice><br />
</xs:choice><br />
<xs:element ref='error' minOccurs='0' maxOccurs='1'/><br />
</xs:sequence><br />
<xs:attribute name='from' type='xs:string' use='optional'/><br />
<xs:attribute name='id' type='xs:NMTOKEN' use='optional'/><br />
<xs:attribute name='to' type='xs:string' use='optional'/><br />
<xs:attribute name='version' type='xs:decimal' use='optional'/><br />
<xs:attribute ref='xml:lang' use='optional'/><br />
</xs:complexType><br />
</xs:element><br />
<br />
<xs:element name='features'><br />
<xs:complexType><br />
<xs:all xmlns:tls='urn:ietf:params:xml:ns:xmpp-tls'<br />
xmlns:sasl='urn:ietf:params:xml:ns:xmpp-sasl'<br />
xmlns:bind='urn:ietf:params:xml:ns:xmpp-bind'<br />
xmlns:sess='urn:ietf:params:xml:ns:xmpp-session'><br />
<xs:element ref='tls:starttls' minOccurs='0'/><br />
<xs:element ref='sasl:mechanisms' minOccurs='0'/><br />
<xs:element ref='bind:bind' minOccurs='0'/><br />
<xs:elemnt ref='sess:session' minOccurs='0'/><br />
</xs:all><br />
</xs:complexType><br />
</xs:element><br />
<br />
<xs:element name='error'><br />
<xs:complexType><br />
<xs:sequence xmlns:err='urn:ietf:params:xml:ns:xmpp-streams'><br />
<xs:group ref='err:streamErrorGroup'/><br />
<xs:element ref='err:text'<br />
minOccurs='0'<br />
maxOccurs='1'/><br />
</xs:sequence><br />
</xs:complexType><br />
</xs:element><br />
<br />
</xs:schema><br />
</source><br />
<br />
===C.2. Stream error namespace===<br />
<br />
<source lang="xml"><br />
<?xml version='1.0' encoding='UTF-8'?><br />
<br />
<xs:schema<br />
xmlns:xs='http://www.w3.org/2001/XMLSchema'<br />
targetNamespace='urn:ietf:params:xml:ns:xmpp-streams'<br />
xmlns='urn:ietf:params:xml:ns:xmpp-streams'<br />
elementFormDefault='qualified'><br />
<br />
<xs:element name='bad-format' type='empty'/><br />
<xs:element name='bad-namespace-prefix' type='empty'/><br />
<xs:element name='conflict' type='empty'/><br />
<xs:element name='connection-timeout' type='empty'/><br />
<xs:element name='host-gone' type='empty'/><br />
<xs:element name='host-unknown' type='empty'/><br />
<xs:element name='improper-addressing' type='empty'/><br />
<xs:element name='internal-server-error' type='empty'/><br />
<xs:element name='invalid-from' type='empty'/><br />
<xs:element name='invalid-id' type='empty'/><br />
<xs:element name='invalid-namespace' type='empty'/><br />
<xs:element name='invalid-xml' type='empty'/><br />
<xs:element name='not-authorized' type='empty'/><br />
<xs:element name='policy-violation' type='empty'/><br />
<xs:element name='remote-connection-failed' type='empty'/><br />
<xs:element name='resource-constraint' type='empty'/><br />
<xs:element name='restricted-xml' type='empty'/><br />
<xs:element name='see-other-host' type='xs:string'/><br />
<xs:element name='system-shutdown' type='empty'/><br />
<xs:element name='undefined-condition' type='empty'/><br />
<xs:element name='unsupported-encoding' type='empty'/><br />
<xs:element name='unsupported-stanza-type' type='empty'/><br />
<xs:element name='unsupported-version' type='empty'/><br />
<xs:element name='xml-not-well-formed' type='empty'/><br />
<br />
<xs:group name='streamErrorGroup'><br />
<xs:choice><br />
<xs:element ref='bad-format'/><br />
<xs:element ref='bad-namespace-prefix'/><br />
<xs:element ref='conflict'/><br />
<xs:element ref='connection-timeout'/><br />
<xs:element ref='host-gone'/><br />
<xs:element ref='host-unknown'/><br />
<xs:element ref='improper-addressing'/><br />
<xs:element ref='internal-server-error'/><br />
<xs:element ref='invalid-from'/><br />
<xs:element ref='invalid-id'/><br />
<xs:element ref='invalid-namespace'/><br />
<xs:element ref='invalid-xml'/><br />
<xs:element ref='not-authorized'/><br />
<xs:element ref='policy-violation'/><br />
<xs:element ref='remote-connection-failed'/><br />
<xs:element ref='resource-constraint'/><br />
<xs:element ref='restricted-xml'/><br />
<xs:element ref='see-other-host'/><br />
<xs:element ref='system-shutdown'/><br />
<xs:element ref='undefined-condition'/><br />
<xs:element ref='unsupported-encoding'/><br />
<xs:element ref='unsupported-stanza-type'/><br />
<xs:element ref='unsupported-version'/><br />
<xs:element ref='xml-not-well-formed'/><br />
</xs:choice><br />
</xs:group><br />
<br />
<xs:element name='text'><br />
<xs:complexType><br />
<xs:simpleContent><br />
<xs:extension base='xs:string'><br />
<xs:attribute ref='xml:lang' use='optional'/><br />
</xs:extension><br />
</xs:simpleContent><br />
</xs:complexType><br />
</xs:element><br />
<br />
<xs:simpleType name='empty'><br />
<xs:restriction base='xs:string'><br />
<xs:enumeration value=''/><br />
</xs:restriction><br />
</xs:simpleType><br />
<br />
</xs:schema><br />
</source><br />
<br />
===C.3. TLS namespace==<br />
<br />
<source lang="xml"><br />
<?xml version='1.0' encoding='UTF-8'?><br />
<br />
<xs:schema<br />
xmlns:xs='http://www.w3.org/2001/XMLSchema'<br />
targetNamespace='urn:ietf:params:xml:ns:xmpp-tls'<br />
xmlns='urn:ietf:params:xml:ns:xmpp-tls'<br />
elementFormDefault='qualified'><br />
<br />
<xs:element name='starttls'><br />
<xs:complexType><br />
<xs:sequence><br />
<xs:element<br />
name='required'<br />
minOccurs='0'<br />
maxOccurs='1'<br />
type='empty'/><br />
</xs:sequence><br />
</xs:complexType><br />
</xs:element><br />
<br />
<xs:element name='proceed' type='empty'/><br />
<xs:element name='failure' type='empty'/><br />
<br />
<xs:simpleType name='empty'><br />
<xs:restriction base='xs:string'><br />
<xs:enumeration value=''/><br />
</xs:restriction><br />
</xs:simpleType><br />
<br />
</xs:schema><br />
</source><br />
<br />
===C.4. SASL namespace===<br />
<br />
<source lang="xml"><br />
<?xml version='1.0' encoding='UTF-8'?><br />
<br />
<xs:schema<br />
xmlns:xs='http://www.w3.org/2001/XMLSchema'<br />
targetNamespace='urn:ietf:params:xml:ns:xmpp-sasl'<br />
xmlns='urn:ietf:params:xml:ns:xmpp-sasl'<br />
elementFormDefault='qualified'><br />
<br />
<xs:element name='mechanisms'><br />
<xs:complexType><br />
<xs:sequence><br />
<xs:element name='mechanism'<br />
maxOccurs='unbounded'<br />
type='xs:string'/><br />
</xs:sequence><br />
</xs:complexType><br />
</xs:element><br />
<br />
<xs:element name='auth'><br />
<xs:complexType><br />
<xs:simpleContent><br />
<xs:extension base='empty'><br />
<xs:attribute name='mechanism'<br />
type='xs:string'<br />
use='optional'/><br />
</xs:extension><br />
</xs:simpleContent><br />
</xs:complexType><br />
</xs:element><br />
<br />
<xs:element name='challenge' type='xs:string'/><br />
<xs:element name='response' type='xs:string'/><br />
<xs:element name='abort' type='empty'/><br />
<xs:element name='success' type='empty'/><br />
<br />
<xs:element name='failure'><br />
<xs:complexType><br />
<xs:choice minOccurs='0'><br />
<xs:element name='aborted' type='empty'/><br />
<xs:element name='incorrect-encoding' type='empty'/><br />
<xs:element name='invalid-authzid' type='empty'/><br />
<xs:element name='invalid-mechanism' type='empty'/><br />
<xs:element name='mechanism-too-weak' type='empty'/><br />
<xs:element name='not-authorized' type='empty'/><br />
<xs:element name='temporary-auth-failure' type='empty'/><br />
</xs:choice><br />
</xs:complexType><br />
</xs:element><br />
<xs:simpleType name='empty'><br />
<xs:restriction base='xs:string'><br />
<xs:enumeration value=''/><br />
</xs:restriction><br />
</xs:simpleType><br />
<br />
</xs:schema><br />
</source><br />
<br />
===C.5. Resource binding namespace===<br />
<br />
<source lang="xml"><br />
<?xml version='1.0' encoding='UTF-8'?><br />
<br />
<xs:schema<br />
xmlns:xs='http://www.w3.org/2001/XMLSchema'<br />
targetNamespace='urn:ietf:params:xml:ns:xmpp-bind'<br />
xmlns='urn:ietf:params:xml:ns:xmpp-bind'<br />
elementFormDefault='qualified'><br />
<br />
<xs:element name='bind'><br />
<xs:complexType><br />
<xs:choice minOccurs='0' maxOccurs='1'><br />
<xs:element name='resource' type='xs:string'/><br />
<xs:element name='jid' type='xs:string'/><br />
</xs:choice><br />
</xs:complexType><br />
</xs:element><br />
<br />
</xs:schema><br />
</source><br />
<br />
===C.6. Dialback namespace===<br />
<br />
<source lang="xml"><br />
<?xml version='1.0' encoding='UTF-8'?><br />
<br />
<xs:schema<br />
xmlns:xs='http://www.w3.org/2001/XMLSchema'<br />
targetNamespace='jabber:server:dialback'<br />
xmlns='jabber:server:dialback'<br />
elementFormDefault='qualified'><br />
<br />
<xs:element name='result'><br />
<xs:complexType><br />
<xs:simpleContent><br />
<xs:extension base='xs:token'><br />
<xs:attribute name='from' type='xs:string' use='required'/><br />
<xs:attribute name='to' type='xs:string' use='required'/><br />
<xs:attribute name='type' use='optional'><br />
<xs:simpleType><br />
<xs:restriction base='xs:NCName'><br />
<xs:enumeration value='invalid'/><br />
<xs:enumeration value='valid'/><br />
</xs:restriction><br />
</xs:simpleType><br />
</xs:attribute><br />
</xs:extension><br />
</xs:simpleContent><br />
</xs:complexType><br />
</xs:element><br />
<br />
<xs:element name='verify'><br />
<xs:complexType><br />
<xs:simpleContent><br />
<xs:extension base='xs:token'><br />
<xs:attribute name='from' type='xs:string' use='required'/><br />
<xs:attribute name='id' type='xs:NMTOKEN' use='required'/><br />
<xs:attribute name='to' type='xs:string' use='required'/><br />
<xs:attribute name='type' use='optional'><br />
<xs:simpleType><br />
<xs:restriction base='xs:NCName'><br />
<xs:enumeration value='invalid'/><br />
<xs:enumeration value='valid'/><br />
</xs:restriction><br />
</xs:simpleType><br />
</xs:attribute><br />
</xs:extension><br />
</xs:simpleContent><br />
</xs:complexType><br />
</xs:element><br />
<br />
</xs:schema><br />
</source><br />
<br />
===C.7. Stanza error namespace===<br />
<br />
<source lang="xml"><br />
<?xml version='1.0' encoding='UTF-8'?><br />
<br />
<xs:schema<br />
xmlns:xs='http://www.w3.org/2001/XMLSchema'<br />
targetNamespace='urn:ietf:params:xml:ns:xmpp-stanzas'<br />
xmlns='urn:ietf:params:xml:ns:xmpp-stanzas'<br />
elementFormDefault='qualified'><br />
<br />
<xs:element name='bad-request' type='empty'/><br />
<xs:element name='conflict' type='empty'/><br />
<xs:element name='feature-not-implemented' type='empty'/><br />
<xs:element name='forbidden' type='empty'/><br />
<xs:element name='gone' type='xs:string'/><br />
<xs:element name='internal-server-error' type='empty'/><br />
<xs:element name='item-not-found' type='empty'/><br />
<xs:element name='jid-malformed' type='empty'/><br />
<xs:element name='not-acceptable' type='empty'/><br />
<xs:element name='not-allowed' type='empty'/><br />
<xs:element name='payment-required' type='empty'/><br />
<xs:element name='recipient-unavailable' type='empty'/><br />
<xs:element name='redirect' type='xs:string'/><br />
<xs:element name='registration-required' type='empty'/><br />
<xs:element name='remote-server-not-found' type='empty'/><br />
<xs:element name='remote-server-timeout' type='empty'/><br />
<xs:element name='resource-constraint' type='empty'/><br />
<xs:element name='service-unavailable' type='empty'/><br />
<xs:element name='subscription-required' type='empty'/><br />
<xs:element name='undefined-condition' type='empty'/><br />
<xs:element name='unexpected-request' type='empty'/><br />
<br />
<xs:group name='stanzaErrorGroup'><br />
<xs:choice><br />
<xs:element ref='bad-request'/><br />
<xs:element ref='conflict'/><br />
<xs:element ref='feature-not-implemented'/><br />
<xs:element ref='forbidden'/><br />
<xs:element ref='gone'/><br />
<xs:element ref='internal-server-error'/><br />
<xs:element ref='item-not-found'/><br />
<xs:element ref='jid-malformed'/><br />
<xs:element ref='not-acceptable'/><br />
<xs:element ref='not-allowed'/><br />
<xs:element ref='payment-required'/><br />
<xs:element ref='recipient-unavailable'/><br />
<xs:element ref='redirect'/><br />
<xs:element ref='registration-required'/><br />
<xs:element ref='remote-server-not-found'/><br />
<xs:element ref='remote-server-timeout'/><br />
<xs:element ref='resource-constraint'/><br />
<xs:element ref='service-unavailable'/><br />
<xs:element ref='subscription-required'/><br />
<xs:element ref='undefined-condition'/><br />
<xs:element ref='unexpected-request'/><br />
</xs:choice><br />
</xs:group><br />
<br />
<xs:element name='text'><br />
<xs:complexType><br />
<xs:simpleContent><br />
<xs:extension base='xs:string'><br />
<xs:attribute ref='xml:lang' use='optional'/><br />
</xs:extension><br />
</xs:simpleContent><br />
</xs:complexType><br />
</xs:element><br />
<br />
<xs:simpleType name='empty'><br />
<xs:restriction base='xs:string'><br />
<xs:enumeration value=''/><br />
</xs:restriction><br />
</xs:simpleType><br />
<br />
</xs:schema><br />
</source><br />
<br />
==附录 D. 核心Jabber协议和XMPP的不同==<br />
<br />
:本章是非标准的.<br />
<br />
::译者注:附录D对于新接触XMPP的人没有什么意义,就不翻译了,免得浪费时间。因为现在RFC公布已经很久了,以前的Jabber实现很多都进化到XMPP了。<br />
<br />
:XMPP has been adapted from the protocols originally developed in the Jabber open-source community, which can be thought of as "XMPP 0.9". Because there exists a large installed base of Jabber implementations and deployments, it may be helpful to specify the key differences between the relevant Jabber protocols and XMPP in order to expedite and encourage upgrades of those implementations and deployments to XMPP. This section summarizes the core differences, while the corresponding section of [[RFC3921]] summarizes the differences that relate specifically to instant messaging and presence applications.<br />
<br />
===D.1. Channel Encryption===<br />
<br />
:It was common practice in the Jabber community to use SSL for channel encryption on ports other than 5222 and 5269 (the convention is to use ports 5223 and 5270). XMPP uses TLS over the IANA-registered ports for channel encryption, as defined under Use of TLS (Section 5) herein.<br />
<br />
===D.2. Authentication===<br />
<br />
:The client-server authentication protocol developed in the Jabber community used a basic IQ interaction qualified by the 'jabber:iq:auth' namespace (documentation of this protocol is contained in \[JEP-0078\], published by the Jabber Software Foundation [JSF]). XMPP uses SASL for authentication, as defined under Use of SASL (Section 6) herein.<br />
<br />
:The Jabber community did not develop an authentication protocol for server-to-server communications, only the Server Dialback (Section 8) protocol to prevent server poofing. XMPP supersedes Server Dialback with a true server-to-server authentication protocol, as defined under Use of SASL (Section 6) herein.<br />
<br />
===D.3. Resource Binding===<br />
<br />
:Resource binding in the Jabber community was handled via the 'jabber:iq:auth' namespace (which was also used for client authentication with a server). XMPP defines a dedicated namespace for resource binding as well as the ability for a server to generate a resource identifier on behalf of a client, as defined under Resource Binding (Section 7).<br />
<br />
===D.4. JID Processing===<br />
<br />
:JID processing was somewhat loosely defined by the Jabber community (documentation of forbidden characters and case handling is contained in [JEP-0029], published by the Jabber Software Foundation [JSF]). XMPP specifies the use of \[NAMEPREP\] for domain identifiers and supplements Nameprep with two additional [STRINGPREP] profiles for JID processing: Nodeprep (Appendix A) for node identifiers and Resourceprep (Appendix B) for resource identifiers.<br />
<br />
===D.5. Error Handling===<br />
<br />
:Stream-related errors were handled in the Jabber community via XML character data text in a <stream:error/> element. In XMPP, stream-related errors are handled via an extensible mechanism defined under Stream Errors (Section 4.7) herein. Stanza-related errors were handled in the Jabber community via HTTP-style error codes. In XMPP, stanza-related errors are handled via an extensible mechanism defined under Stanza Errors (Section 9.3) herein. (Documentation of a mapping between Jabber and XMPP error handling mechanisms is contained in \[JEP-0086\], published by the Jabber Software Foundation [JSF].)<br />
<br />
===D.6. Internationalization===<br />
<br />
:Although use of UTF-8 has always been standard practice within the Jabber community, the community did not define mechanisms for specifying the language of human-readable text provided in XML character data. XMPP specifies the use of the 'xml:lang' attribute in such contexts, as defined under Stream Attributes (Section 4.4) and xml:lang (Section 9.1.5) herein.<br />
<br />
===D.7. Stream Version Attribute===<br />
<br />
:The Jabber community did not include a 'version' attribute in stream headers. XMPP specifies inclusion of that attribute as a way to signal support for the stream features (authentication, encryption, etc.) defined under Version Support (Section 4.4.1) herein.<br />
<br />
==贡献者==<br />
<br />
:XMPP的大部分核心方面是由1999年开始的Jabber开源社区开发的. 这个社区是由 Jeremie Miller建立的, 他于1999年1月发布了最初版的jabber server源代码. 主要的基础协议的早期贡献者还包括 Ryan Eatmon, Peter Millard, Thomas Muldowney,和 Dave Smith. XMPP工作组的工作主要集中在安全性和国际化方面; 在这些领域, 使用 TLS 和 SASL 的协议最初是由 Rob Norris贡献的, stringprep profiles 最初是由 Joe Hildebrand贡献的. The error code syntax 是由Lisa Dusseault建议的.<br />
<br />
==致谢==<br />
<br />
:感谢许多在贡献者名单之外的人们. 尽管很难提供一个完整的名单, 以下个人对于定义协议或评论标准提供了很多帮助:<br />
<br />
:Thomas Charron, Richard Dobson, Sam Hartman, Schuyler Heath, Jonathan Hogg, Cullen Jennings, Craig Kaes, Jacek Konieczny, Alexey Melnikov, Keith Minkler, Julian Missig, Pete Resnick, Marshall Rose, Alexey Shchepin, Jean-Louis Seguineau, Iain Shigeoka, Greg Troxel, and David Waite. <br />
<br />
:也感谢 XMPP工作组的成员和 IETF 社区在本文的成文过程中一直提供的评论和反馈。<br />
<br />
<br />
==作者地址==<br />
<br />
:Peter Saint-Andre (editor)<br />
<br />
:Jabber Software Foundation<br />
<br />
:EMail: stpeter@jabber.org<br />
<br />
==完整的版权声明==<br />
<br />
:Copyright (C) The Internet Society (2004).<br />
<br />
:This document is subject to the rights, licenses and restrictions contained in BCP 78, and except as set forth therein, the authors retain all their rights. This document and the information contained herein are provided on an "AS IS" basis and THE CONTRIBUTOR, THE ORGANIZATION HE/S HE REPRESENTS OR IS SPONSORED BY (IF ANY), THE INTERNET SOCIETY AND THE INTERNET ENGINEERING TASK FORCE DISCLAIM ALL WARRANTIES, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO ANY WARRANTY THAT THE USE OF THE INFORMATION HEREIN WILL NOT INFRINGE ANY RIGHTS OR ANY IMPLIED WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE.<br />
<br />
==Intellectual Property==<br />
<br />
:The IETF takes no position regarding the validity or scope of any Intellectual Property Rights or other rights that might be claimed to pertain to the implementation or use of the technology described in this document or the extent to which any license under such rights might or might not be available; nor does it represent that it has made any independent effort to identify any such rights. Information on the IETF's procedures with respect to rights in IETF Documents can be found in BCP 78 and BCP 79. Copies of IPR disclosures made to the IETF Secretariat and any assurances of licenses to be made available, or the result of an attempt made to obtain a general license or permission for the use of such proprietary rights by implementers or users of this specification can be obtained from the IETF on-line IPR repository at http://www.ietf.org/ipr. The IETF invites any interested party to bring to its attention any copyrights, patents or patent applications, or other proprietary rights that may cover technology that may be required to implement this standard. Please address the information to the IETF at ietf-ipr@ietf.org.<br />
<br />
==感谢==<br />
<br />
:目前为RFC编辑活动提供资金的Internet Society.</div>
Snowqiang
http://wiki.jabbercn.org/RFC3920
RFC3920
2011-05-18T10:40:44Z
<p>Snowqiang: 添补事件流程</p>
<hr />
<div>[[Category:XMPP正式RFC标准]]<br />
[[Category:已翻译]]<br />
<br />
"本文的英文原文来自[http://www.ietf.org/rfc/rfc3920.txt RFC 3920]<br />
<br />
{|<br />
|网络工作组 || P. Saint-Andre, Ed.<br />
|-<br />
|申请讨论: 3920 || Jabber软件基金会<br />
|-<br />
|类别: 标准跟踪 || 2004年10月<br />
|}<br />
<br />
<br />
<br />
:::'''可扩展的消息和出席信息协议 (XMPP): 核心协议'''<br />
<br />
'''关于本文的说明'''<br />
<br />
:本文为互联网社区定义了一个互联网标准跟踪协议,并且申请讨论协议和提出了改进的建议。请参照“互联网官方协议标准”的最新版本(STD 1)获得这个协议的标准化进程和状态。本文可以不受限制的分发。<br />
<br />
'''版权声明'''<br />
<br />
:本文版权属于互联网社区 (C) The Internet Society (2004).<br />
<br />
'''摘要'''<br />
<br />
:本文定义了可扩展消息和出席信息协议(XMPP)的核心功能,这个协议采用XML流实现在任意两个网络终端接近实时的交换结构化信息。XMPP提供一个通用的可扩展的框架来交换XML数据,它主要用来建立即时消息和出席信息应用以实现 RFC 2779 的需求。 <br />
<br />
==绪论==<br />
<br />
===概览===<br />
<br />
:XMPP是一个开放式的XML协议,设计用于准实时消息和出席信息以及请求-响应服务。其基本的语法和语义最初主要是由Jabber开放源代码社区于1999年开发的。2002年,XMPP工作组被授权接手开发和改编Jabber协议以适应IETF的即时消息和出席信息技术。作为XMPP工作组的成果,本文定义了 XMPP 1.0 的核心功能;在 RFC 2779 [IMP-REQS] 中指定的提供即时消息和出席信息功能的扩展,定义在 XMPP-IM 协议 [the Extensible Messaging and Presence Protocol (XMPP): Instant Messaging and Presence] 中。<br />
<br />
===术语===<br />
<br />
:本文中大写的关键字 "MUST(必须)", "MUST NOT(不能)", "REQUIRED(必需)", "SHALL(将会)", "SHALL NOT(将不会)", "SHOULD(应该)", "SHOULD NOT(不应该)", "RECOMMENDED(建议)", "MAY(可以)", 和 "OPTIONAL(可选)" 的确切含义符合 BCP 14, RFC 2119 \[TERMS\].<br />
<br />
==通用的架构==<br />
<br />
===概览===<br />
<br />
:尽管XMPP没有指定任何特定的网络结构,但它通常是采用客户-服务器 架构进行实现,其中客户端通过TCP方式使用XMPP访问服务器,服务器之间也采用TCP方式进行通信。<br />
<br />
:以下是这一架构的抽象的示意图 (这里 "-" 表示使用 XMPP 通讯, "=" 表示可使用任何协议通讯)。<br />
<br />
<br />
::C1----S1---S2---C3<br />
<br />
::::|<br />
<br />
::C2----+---G1===FN1===FC1<br />
<br />
:符号的含义如下:<br />
<br />
::* C1, C2, C3 = XMPP 客户端<br />
<br />
::* S1, S2 = XMPP 服务器<br />
<br />
::* G1 = 一个XMPP和外部(非XMPP)消息网络之间进行“翻译”的网关<br />
<br />
::* FN1 = 一个外部消息网络<br />
<br />
::* FC1 = 外部消息网络上的一个客户端<br />
<br />
===服务器===<br />
<br />
:服务器充当XMPP通信的一个智能抽象层,它主要负责:<br />
<br />
:* 对受验证的客户端,服务器以及其他实体之间以XML流形式的连接和会话进行管理。<br />
<br />
:* 在这些实体间使用XML流对合理编址的XML节(第九章)进行路由<br />
<br />
:大部分 XMPP 兼容的服务器也负责存储客户端使用的数据 (比如基于XMPP协议的及时消息应用中的联系人名单); 在这种情况下, XML 数据直接服务器来处理,而不需要转发到其他实体。<br />
<br />
===客户端===<br />
<br />
:大部分客户端通过 TCP 连接直接连到服务器,并通过XMPP获得由服务器以及联合服务器所提供的全部功能。多个不同资源(比如不同的设备和地点)的客户端'''可以'''同时登陆并且并发的连接到一个服务器,每个不同资源的客户端通过XMPP地址的资源标识符来区分(比如<node@domain/ home> 和 <node@domain/work>),参见地址空间(第三章)。'''建议'''的客户端和服务器连接的端口是 5222 ,这个端口已经在 IANA(在第十五章第九节查阅端口号码) 注册了。<br />
<br />
===网关===<br />
<br />
:网关是一个特殊用途的服务器端的服务,主要功能是把 XMPP 翻译成外部(非XMPP)消息系统,并把返回的消息翻译成 XMPP 。例如到 email(参见 [SMTP] ),IRC(参见 [IRC] ),SIMPLE(参见 [SIMPLE] ),SMS 的网关;还有和别的消息服务的网关,比如AIM,ICQ,MSN Messenger,Yahoo! Instant Messenger。网关和服务器之间的通信,网关和外部消息系统的通信,不在本文描述范围之内。<br />
<br />
===网络===<br />
<br />
:因为每个服务器都是由一个网络地址来标识的并且服务器之间的通信是 客户-服务器 协议的直接扩展,实际上整个系统是由很多互通的服务器构成的。例如,<juliet@example.com> 可以和 <romeo@example.net> 交换消息,出席信息和其他信息。这种模式常见于那些需要使网络地址标准化的协议(比如 SMTP )。任意两个服务器之间的通信是可选(OPTIONAL)的。如果被激活,那么这种通信应该(SHOULD)通过 XML 流绑定到 TCP 连接上进行。建议的(RECOMMENDED)服务器之间的连接端口为 5269 ,这个端口号已经在 IANA (在第十五章第九节查阅端口号码)注册了。<br />
<br />
==地址空间==<br />
<br />
===概览===<br />
<br />
:一个实体可以是任何一个被认为是一个网络端点的东西(例如网络上的一个 ID ),而且它是通过XMPP进行通信的。所有这些实体都有一个具有唯一性的地址,并符合 RFC 2396 [URI]规范要求的格式。由于历史原因,一个 XMPP 实体的地址被称为 Jabber Identifier 或 JID 。一个合法的 JID 包括一组排列好的元素,包括域名(domain identifier),节点名(node identifier),和资源名(resource identifier)。<br />
<br />
:JID的语法定义,使用 [ABNF] 中的 Augmented Backus-Naur 格式。(IPv4 地址和 IPv6地址规则在 附录B 中的 [IPv6] 中定义;确定节点规则的合法字符顺序由 附录A 的 [STRINGPREP] 的 Nodeprep 部分来定义;确定资源规则的合法字符顺序由 附录B 的 [STRINGPREP] 的Resourceprep 部分来定义;子域名规则参考 [IDNA] 中关于国际域名标签的描述。)。<br />
<br />
::jid = [ node "@" ] domain [ "/" resource ]<br />
<br />
::domain = fqdn / address-literal<br />
<br />
::fqdn = (sub-domain 1*("." sub-domain))<br />
<br />
::sub-domain = (internationalized domain label)<br />
<br />
::address-literal = IPv4address / IPv6address<br />
<br />
:所有 JID 都是基于上述的结构。类似 <user@host/resource> 这种结构,最常用来标识一个即时消息用户,这个用户所连接的服务器,以及这个用户用于连接的资源(比如特定类型的客户端软件)。不过,节点类型不是客户端也是有可能的,比如一个用来提供多用户聊天服务的特定的聊天室,地址可以是 <room@service> (这里 “room“ 是聊天室的名字而 ”service“ 是多用户聊天服务的主机名),而加入了这个聊天室的某个特定的用户的地址则是 <room@service/nick> (这里 ”nick“ 是用户在聊天室的昵称)。许多其他的 JID 类型都是可能的(例如 <domain/resource> 可能是一个服务器端的脚本或服务)。<br />
<br />
:一个 JID 的每个合法部分(节点名,域名,资源名)的长度不能(MUST NOT)超过 1023 字节。也就是整体长度(包括 '@' 和 '/' )不能超过 3071 字节。<br />
<br />
===域名===<br />
<br />
:域名是一个主要的ID并且是 JID 中唯一必需(REQUIRED)的元素(一个纯粹的域名也是一个合法的 JID)。它通常代表网络的网关或者“主”服务器,其他实体通过连接它来实现 XML 转发和数据管理功能。然而,由一个域名标识引用的实体,并非总是一个服务器,它也可能是一个服务器的子域地址,提供额外的功能(比如多用户聊天服务,用户目录,或一个到外部消息系统的网关)。<br />
<br />
:每个服务器或者服务的域名,可以(MAY)是一个 IP 地址,但应该(SHOULD)是一个完全合法的域名(参见 [DNS]).一个域名ID必须(MUST)是 [IANA] 里定义的“国际化域名”,并且按 [STRINGPREP]中的 [NAMEPREP] profile进行成功的字符转换。在比较两个域名ID之前,服务器必须(MUST),客户端应该(SHOULD)首先按照Nameprep profile(定义在[IANA]中) 来转换每个域名的字符。<br />
<br />
===节点名===<br />
<br />
:节点名是一个可选(OPTIONAL)的第二 ID,放在域名之前并用符号"@"分开.它通常表示一个向服务器或网关请求和使用网络服务的实体(比如一个客户端),当然它也能够表示其他的实体(比如在多用户聊天系统中的一个房间). 节点名所代表的实体,它的地址依赖于一个特定的域名;在 XMPP 的即时消息和出席信息应用系统中,这个地址是“纯 JID” <node@domain> 中的一部分。<br />
<br />
:一个节点名必须按 \[STRINGPREP\] 中的 Nodeprep profile 进行成功的字符转换。在比较两个节点ID之前,服务器必须(MUST),客户端应该(SHOULD)首先按 Nodeprep profile 转换每个ID的字符。<br />
<br />
===资源名===<br />
<br />
:资源名是一个可选的第三 ID,它放在域名的后面并由符号"/"分开。资源名可以跟在 <node@domain>后面也可以跟在 <domain> 后面。它通常表示一个特定的会话,连接(比如设备或者所在位置),或者一个附属于某个节点ID实体相关实体的对象(比如多用户聊天室中的一个参加者)。对于服务器和和其他客户端来说,资源名是不透明的。当它提供必需的信息以完成资源绑定(参见第七章)的时候,通常是由客户端来实现的(尽管可以由客户端向服务器请求完成),然后显示为“已连接的资源”。一个实体可以(MAY)并发维护多个已连接的资源。每个已连接的资源由不同的资源ID来区分。<br />
<br />
:一个资源名必须(MUST)按 \[STRINGPREP\] 中的 Resourceprep profile 进行成功的格式化。在比较两个资源ID之前,服务器必须(MUST),客户端应该(SHOULD)首先按 Resourceprep profile 转换每个ID的字符。<br />
<br />
===地址的确认===<br />
<br />
:在 SASL (见第六章)握手之后(如果必要的话,也在资源绑定(见第七章)之后),正在接收流信息的实体必须(MUST)确认初始实体的 ID 。<br />
<br />
:对于服务器间的通信,在 SASL 握手时,如果没有指明授权的ID,这个初始的实体应该(SHOULD)是经过认证实体(参见 简单认证和安全层协议 \[SASL\] 中的定义)授权的ID(见第六章)。<br />
<br />
:对于客户端和服务器的通信,在 SASL 握手时,如果没有指明授权的ID,“纯 JID” (<node@domain>)应该(SHOULD)是经过认证实体(参见 [SASL] 中的定义)授权的ID,“全 JID” (<node@domain/resource>)的资源ID部分应该(SHOULD)是由客户端和服务器在资源绑定的时候商定的(参见第七章)。<br />
<br />
:接收的实体必须(MUST)确保结果JID(包括节点名,域名,资源名以及分隔符)与本章前面部分描述的规则和格式相一致;为了满足这些约束条件,接收实体可能(MAY)需要把初始实体的发送方 JID 替换成接收实体认可的规范 JID。<br />
<br />
==XML流==<br />
<br />
===概览===<br />
<br />
:两个基本概念,XML流和XML节,使得在出席信息已知的实体之间,异步交换低负载的结构化信息成为可能。这两个术语定义如下:<br />
<br />
:XML流的定义:一个XML流是一个容器,包含了两个实体之间通过网络交换的XML元素。一个XML流是由一个XML打开标签 <stream> (包含适当的属性和名字空间声明)开始的,流的结尾则是一个XML关闭L标签 </stream> 。在流的整个生命周期,初始化它的实体可以通过流发送大量的XML元素,用于流的握手(例如 TLS 握手(第五章) 或 SASL 握手(第六章))或XML节(在这里指符合缺省名字空间的元素,包括<message/>,<presence/>, 或 <iq/> 元素)。“初始的流”由初始化实体(通常是一个客户端或服务器)和接收实体(通常是一个服务器)握手,从接收实体来看,它就是那个初始实体的"会话".初始化流允许从初始化实体到接收实体的单向通信;为了使接收实体能够和初始实体交换信息,接收实体必须发起一个反向的握手(应答流).<br />
<br />
:XML节的定义: 一个XML节是一个实体通过 XML 流向另一个实体发送的结构化信息中的一个离散的语义单位。一个XML节直接存在于根元素<stream/>的下一级,这样可以说是很好的匹配了[XML](译者注:在标准参考一节)的第43条.任何XML节都是从一个XML流的下一级的某个打开标签(如 <presence>)开始,到相应的关闭标签(如 </presence>)。一个XML节可以(MAY)包含子元素(相关的属性,元素, 和 XML 字符数据等) 以表达完整的信息.在这里定义的XML节仅限于<message/>, <presence/>, 和 <iq/> 元素,具体描述间见 XML Stanzas(第九章);为TLS握手(第五章)、SASL握手(第六章)、服务器回拨(第八章)的需要而发送的XML元素,不被认为是一个XML节。<br />
<br />
:设想一个客户端和服务器会话的例子。为了连接一个服务器,一个客户端必须(MUST)发送一个打开标签<stream>给服务器,初始化一个XML流,也可选择(OPTIONAL)在这之前发送一段文本声明XML版本和支持的字符集(参见文本声明的内容(第十一章第四节); 也可看字符编码(第十一章第五节))。视本地化策略和提供的服务而定,服务器应该(SHOULD)回复一个XML流给客户端,同样的,也可选择在这之前发送一段文本声明。一旦客户端完成了SASL握手(第六章),客户端可以(MAY)通过流发送不限量的XML节给网络中的任何接收者。当客户端想关闭这个流,它只需要简单的发送一个关闭标签</stream>给服务器(或者作为另一个选择,可能由服务器关闭这个流)。然后,客户端和服务器都应该(SHOULD)彻底地终止这个连接(通常是一个TCP连接)。<br />
<br />
:那些习惯认为XML是一个以文本为中心风格的人可能希望看看一个与服务器连接的客户端会话,包含两个 打开-关闭 XML文档:一个是从客户端到服务器,一个是从服务器到客户端。下图中,根元素<stream/> 可以被认为是每个“文档”的文档实体,这两个“文档”通过累积那些在XML上传输的XML节来搭建的。无论如何,下图只是方便理解;实际上XMPP并不处理文档而是处理XML流和XML节。<br />
<br />
:基本上,一个XML流相当于一个会话期间所有XML节的一个信封。我们可以简单的把它描述成下图:<br />
<br />
::|----------------------------<br />
<br />
::| <stream><br />
<br />
::|----------------------------<br />
<br />
::| <presence> <br />
<br />
::| <show/> <br />
<br />
::| </presence><br />
<br />
::|----------------------------<br />
<br />
::| <message to='foo'> <br />
<br />
::| <body/> <br />
<br />
::| </message> <br />
<br />
::|----------------------------<br />
<br />
::| <iq to='bar'><br />
<br />
::| <query/> <br />
<br />
::| </iq> <br />
<br />
::|----------------------------<br />
<br />
::| ... <br />
<br />
::|----------------------------<br />
<br />
::| </stream> <br />
<br />
::|----------------------------<br />
<br />
===绑定到TCP===<br />
<br />
:虽然有很多非必需的连接使用XML流来绑定\[TCP\]连接(两个实体可以通过别的机制来互联,比如通过\[HTPP\]连接轮询),本规范只定义了 XMPP 到 TCP 的绑定。在客户和服务器通信的过程中,服务器必须(MUST)允许客户端共享一个TCP连接来传输XML节,包括从客户端传到服务器和从服务器传到客户端。在服务器之间的通信过程中,服务器必须(MUST)用一个 TCP连接 向对方发送 XML节,另一个 TCP连接(由对方初始化)接收对方的XML节,一共两个 TCP连接。<br />
<br />
===流的安全===<br />
<br />
:在XMPP 1.0中,当XML流开始握手时,TLS应该(SHOULD)按 第五章:TLS的使用 中的规定来使用,SASL必须(MUST)按 第六章:SASL的使用 中的规定来使用。尽管可能(MAY)存在某种共有的机制能够保证双向安全,但是“初始化流”(比如从初始化实体发给接收实体的流)和“应答流”(比如从接收实体发给初始化实体的流)还是必须(MUST)安全的分开。在流被验证之间,实体不应该(SHOULD NOT) 尝试通过流发送XML节(第九章);就算它这样做了,对方的实体也不能(MUST NOT)接受这些XML节,并且应该(SHOULD)返回一个 <not-authorized/> 的流错误信息并且终止当前TCP连接上双方的XML流;注意,这仅仅是针对XML节(包含在缺省命名空间中的 <message/>, <presence/>, 和 <iq/> 元素),而不是指那些用于 TLS握手(第五章)、SASL握手(第六章)握手的流。<br />
<br />
===stream 属性===<br />
<br />
:stream 元素的属性如下:<br />
<br />
:* to -- 'to' 属性应(SHOULD)仅出现在初始化实体发给接收实体的 XML 流的头当中,并且它的值必须(MUST)是接收实体所在的主机名。在接收实体发送给初始化实体的 XML 流的头中不应该(SHOULD NOT)出现 'to' 属性。若 'to' 属性出现在应答流中,则初始化实体应(SHOULD)忽略它。<br />
<br />
:* from -- 'from' 属性应(SHOULD)仅出现在接收实体发给初始化实体的 XML 流的头当中,并且它的值必须(MUST)是为当前初始化实体授权的接收实体所在的主机名。注意,不应该(SHOULD NOT)有 'from'属性出现在初始实体发送给接收实体的 XML流的头中;无论如何,如果'from'属性出现在初始化流中,接收实体应该(SHOULD)忽略它。<br />
<br />
:* id -- 'id'属性应该(SHOULD)仅用于接收实体发送给初始化实体 XML流的头。这个属性是一个由接收实体创建的具有唯一性的ID,一个初始实体和接收实体之间的会话ID,并且它在接收方的应用程序中(通常是一个服务器)必须(MUST)是唯一的。注意,这个流 ID 必须是足够安全的,所以它必须是不可预知的和不可重复的(参见[RANDOM] 了解如何获得随机性以保证安全性)。不应该(SHOULD NOT)有 'id'属性出现在初始实体发送给接收实体的 XML流的头中;无论如何,如果'id'属性出现在初始化流中,接收实体应该(SHOULD)忽略它。<br />
<br />
:* xml:lang -- 'xml:lang'属性(定义在\[XML\]中的第二章第十二节)应该(SHOULD)包含在初始化实体发给接收实体的 XML流的头中,以指定在流中传输的可读XML字符所使用的缺省语言。如果这个属性出现了,接收实体应该(SHOULD)记住它的值,作为初始化流和应答流的缺省属性;如果这个属性没有出现,接收实体应该(SHOULD)用一个可配置的缺省值用于双方的流,这个属性值必须(MUST)在应答流的头中传达。对于所有初始化流中传输的节,如果初始实体没有提供'xml:lang'属性,接收实体应该(SHOULD)应用缺省值;如果初始实体提供了'xml:lang'属性,接收实体不能(MUST NOT)修改或删除它(参见第九章第一节第五小节 xml:lang)。'xml:lang'属性的值必须(MUST)是一个 NMTOKEN (定义在\[XML\]的第二章第三节) 并且必须(MUST)遵守 RFC 3066 \[LANGTAGS\] 规定的格式。<br />
<br />
:* version -- version属性(最少需要"1.0")为本规范中和流相关的协议提供了支持。关于这个属性的生成和处理的详细规则将在下文中定义。<br />
<br />
:我们现在可以总结如下:<br />
<br />
{|border="1" cellspacing="0" <br />
! !! 初始化方发给接收方 !! 接收方发给初始化方<br />
|-<br />
|to || 接收方的主机名 || 忽略<br />
|-<br />
|from || 忽略 || 接收方的主机名<br />
|-<br />
|id || 忽略 || 会话键值<br />
|-<br />
|xml:lang || 缺省语言 || 缺省语言<br />
|-<br />
|version || 支持XMPP 1.0 || 支持XMPP 1.0<br />
|}<br />
<br />
====版本支持====<br />
<br />
:在这里XMPP的版本是"1.0";准确地说,这里囊括了和流相关的所有协议(TLS的使用 (第五章),SASL的使用(第六章), 和流错误(第四章第七节)),以及三个定义好的XML节类型(<message/>,<presence/>,和 <iq/>)。XMPP版本号的编号顺序是“<主版本号>.<副版本号>”。主版本和副版本号必须(MUST)是独立的整数并且每个号码可以(MAY)单独以阿拉伯数字增长。这样,"XMPP 2.4"的版本将比"XMPP 2.13"更低。号码前面 的“0”(比如XMPP 6.01)必须(MUST)被接收方忽略并且不能(MUST NOT)被发送出去.<br />
<br />
:如果流和节的格式或者必需的处理方式有了显著的改变,以至于老版本的实体如果只是简单的忽略它不理解的节和属性并且继续像老版本一样的处理方式,会使得老版本的实体不能够和新版本的实体交互,只有在这时候主版本号才应该(SHOULD)增加。副版本号显示新的性能,它必须(MUST)被副版本号更低的实体忽略,但被高(副)版本号的实体用于了解信息。例如,一个副版本号显示处理某种新定义的"type"属性的值(用于message,presence或IQ节)的能力;副版本号高的实体将会了解到与之通信的对方不能够理解这个"type"属性的值,所以将不会发送它。<br />
<br />
:以下规则是用于'版本'属性在实现流的头信息时如何生成和处理:<br />
<br />
:# 初始化实体必须(MUST)在初始化流的头信息中把'版本'的值设置成它所支持的最高版本。(比如,如果最高版本支持就是本规范,那么它必须(MUST)设置成"1.0").<br />
:# 接收实体必须(MUST)在应答流的头信息中把'版本'的值设置成初始化实体所提供的版本或它所支持的最高版本,取其中版本号较低的那一个。接收实体必须(MUST)把主版本号和副版本号作为数字来比较,而不是对"主版本号.副版本号"这个字符串进行比较.<br />
:# 如果在应答流的头信息的版本号中至少有一个主版本号低于初始化流的头信息的版本号,并且如前所述,新版本的实体不能够和旧版本实体交互,初始化实体应该(SHUOULD)生成一个<unsupported-version/>的流错误信息并终止XML流和它的TCP连接。<br />
:# 如果一个实体收到一个头信息中没有'version'属性的流,这个实体必须(MUST)把对方实体的'version'当成'0.0'并且在它发送的应答流的头中也不应该(SHOULD NOT)包含'version'属性.<br />
<br />
===名字空间声明===<br />
<br />
:流的元素必须(MUST)同时满足一个流名字空间声明和一个缺省名字空间声明("名字空间声明"定义在 XML 名字空间定义 \[XML-NAMES\]中).关于流名字空间和缺省名字空间的详细信息,参考 名字空间的名字和前缀(第十一章第二节).<br />
<br />
===流的特性===<br />
<br />
:如果初始化的实体在初始化流的头信息中设置'version'属性的信息为"1.0",接收实体必须(MUST)向初始化实体发送一个 <features/> 子元素以声明任何可供协商的流一级的特性(或者其他需要声明的能力).目前,这仅用于声明本文中定义的 TLS的使用(第五章),SASL的使用(第六章)和资源绑定(第七章),以及 [XMPP-IM|XMPP文档列表/XMPP正式RFC标准/RFC3921] 中定义的会话的建立;无论如何,流特性这一功能将来可以用于声明任何可协商的特性.如果一个实体不理解或支持安全特性,它应该(SHOULD)忽略它.如果要在一个非安全相关的特性(比如资源绑定)被提议之前,完成一个或多个安全特性(比如TLS和SASL)的协商,这个非安全相关的特性不应该(SHOULD NOT)在相应的安全特性协商完毕之前被声明.<br />
<br />
===流错误===<br />
<br />
:流的根元素可以(MAY)包含一个 <error/> 子元素,由流的名字空间前缀作为它的前缀。这个"错误"子元素必须(MUST)由感知到发生了流级别错误的实体发送(通常是一个服务器而不是一个客户端)。<br />
<br />
====规则====<br />
<br />
:以下规则适用于流级别的错误:<br />
<br />
:* 它假定所有流级别的错误都是不可恢复的;所以,如果一个错误发生在流级别,发现这个错误的实体必须(MUST)发送一个流错误信息给另一个实体,发送一个关闭标签 </stream>,并终止这个流所在的TCP连接。<br />
<br />
:* 如果这个错误发生在流刚开始设置的时候,接收实体必须(MUST)仍然发送一个开放标签 <stream> ,并在流元素中包含一个<error/>的子元素,然后发送一个关闭标签 </stream>,最后终止相应的TCP连接。在这种情况下,如果初始化实体在 'to' 属性中提供了一个未知的主机名,服务器应该(SHOULD)在终止之前,先在流的头信息的 'from' 属性中提供一个服务器认证的主机名.<br />
<br />
====语法====<br />
<br />
:流错误的语法如下:<br />
<br />
<source lang="xml"><br />
<stream:error><br />
<defined-condition xmlns='urn:ietf:params:xml:ns:xmpp-streams'/><br />
<text xmlns='urn:ietf:params:xml:ns:xmpp-streams' xml:lang='langcode'><br />
OPTIONAL descriptive text<br />
</text><br />
[OPTIONAL application-specific condition element]<br />
</stream:error><br />
</source><br />
<br />
:<error/>元素:<br />
:* 必须(MUST)包含一个子元素以描述一个下文定义的节错误条件;这个子元素必须(MUST)符合'urn:ietf:params:xml:ns:xmpp-streams'名字空间.<br />
<br />
:* 可以(MAY)包含一个 <text/> 子元素,用XML字符数据描述错误的细节;这个元素必须(MUST)符合'urn:ietf:params:xml:ns:xmpp-streams'名字空间并且应该(SHOULD)拥有一个'xml:lang'属性表明XML字符数据的自然语言。<br />
<br />
:* 可以(MAY)包含一个子元素用于描述一个明确的应用程序错误条件;这个元素必须(MUST)符合一个应用程序定义的名字空间,并且它的结构是由那个名字空间定义的。<br />
<br />
: <text/> 元素是可选的(OPTIONAL)。如果有这个元素,它应该(SHOULD)仅用于提供描述或调试信息以补充一个已定义的条件或应用程序定义的条件。它不应该(SHOULD NOT)被一个应用程序当成一个可编程的信息。它不应该(SHOULD NOT)被用于向用户表达错误信息,但是可以(MAY)作为和条件元素相关的错误信息之外的附加说明。<br />
<br />
====已定义的条件====<br />
<br />
:以下流级别的错误条件是已定义的:<br />
<br />
:* <bad-format/> -- 实体已经发送XML但是不能被处理;这个错误可以(可以)被更多特定的XML相关的错误替换,比如 <bad-namespace-prefix/>, <invalid-xml/>, <restricted-xml/>, <unsupported-encoding/>, 以及 <xml-not-well-formed/>,尽管更多特定的错误是首选的。 <br />
<br />
:* <bad-namespace-prefix/> -- 实体发送的名字空间前缀不被支持,或者在一个需要某种前缀的元素中没有发送一个名字空间前缀(参见 XML Namespace Names and Prefixes (第十一章第二节)).<br />
<br />
:* <conflict/> -- 服务器正在关闭为这个实体激活的流,因为一个和已经存在的流有冲突的新的流已经被初始化。<br />
<br />
:* <connection-timeout/> -- 实体已经很长时间没有通过这个流发生任何通信流量(可由一个本地服务策略来配置).<br />
<br />
:* <host-gone/> -- 初始化实体在流的头信息中提供的'to'属性的值所指定的主机已经不再由这台服务器提供<br />
<br />
:* <host-unknown/> -- 由初始化实体在流的头信息中提供的 'to' 属性的值和由服务器提供的主机名不一致.<br />
<br />
:* <improper-addressing/> -- 一个在两台服务器之间传送的节缺少 'to' 或 'from' 属性(或者这个属性没有值).<br />
<br />
:* <internal-server-error/> -- 服务器配置错误或者其他未定义的内部错误,使得服务器无法提供流服务.<br />
<br />
:* <invalid-from/> -- 在'from'属性中提供的 JID 或 主机名地址,和认证的 JID不匹配 或服务器之间无法通过SASL(或回拨)协商出合法的域名,或客户端和服务器之间无法通过它进行认证和资源绑定。<br />
<br />
:* <invalid-id/> -- 流 ID 或回拨 ID 是非法的或和以前提供的 ID 不一致.<br />
<br />
:* <invalid-namespace/> -- 流名字空间和 "http://etherx.jabber.org/streams" 不相同或回拨名字空间和 "jabber:server:dialback" 不相同.(参考 XML Namespace Names and Prefixes (第十一章第二节)).<br />
<br />
:* <invalid-xml/> -- 实体通过流发送了一个非法的XML给执行验证的服务器 (参考 Validation (第十一章第三节)).<br />
<br />
:* <not-authorized/> -- 实体试图在流被验证之前发送数据或不被许可执行一个和流协商有关的动作,接收实体在发送错误信息之前不允许(MUST NOT)处理厌恶的节。<br />
<br />
:* <policy-violation/> -- 实体违反了某些本地服务策略;服务器可以(MAY)选择在 <text/> 元素或应用程序定义的错误条件(元素)中详细说明策略。<br />
<br />
:* <remote-connection-failed/> -- 服务器无法正确连接到用于验证或授权的远程实体。<br />
<br />
:* <resource-constraint/> -- 服务器缺乏必要的系统资源为流服务。<br />
<br />
:* <restricted-xml/> -- 实体试图发送受限的XML特性,比如一个注释,处理指示,DTD,实体参考,或保留的字符(参考 Restrictions (第十一章第一节)).<br />
<br />
:* <see-other-host/> -- 服务器将不提供服务给初始化实体但是把它重定向到另一台主机;服务器应该(SHOULD)在<see-other-host/>元素的XML字符数据中指明替代服务器名或IP地址(它必须(必须)是合法的域名标识)。<br />
<br />
:* <system-shutdown/> -- 服务器正在关机并且所有激活的流正在被关闭。<br />
<br />
:* <undefined-condition/> -- 错误条件不在本文已定义的错误条件列表之中;这个错误条件应该(SHOULD)仅用于"应用程序定义条件"元素.<br />
<br />
:* <unsupported-encoding/> -- 初始化实体以一个服务器不不支持的编码方式编码了一个流(参照Character Encoding (第十一章第五节)).<br />
<br />
:* <unsupported-stanza-type/> -- 初始化实体发送了一个流的一级子元素但是服务器不支持.<br />
<br />
:* <unsupported-version/> -- 由初始化实体在流的头信息中指定的'version'属性的值所指定的版本不被服务器支持;服务器可以(MAY)在<text/>元素中指定一个它支持的版本号.<br />
<br />
:* <xml-not-well-formed/> -- 初始化实体发送了一个不规范的XML(参考[XML]).<br />
<br />
====应用程序定义条件====<br />
<br />
:大家知道,应用程序可以(MAY)在error元素中包含一个适当名字空间的子元素来提供一个应用程序定义流错误信息."应用程序定义"元素应该(SHOULD)补充或甚至限定一个已定义的元素.所以 <error/> 元素将包含两个或三个子元素:<br />
<br />
<source lang="xml"><br />
<stream:error><br />
<xml-not-well-formed xmlns='urn:ietf:params:xml:ns:xmpp-streams'/><br />
<text xml:lang='en' xmlns='urn:ietf:params:xml:ns:xmpp-streams'><br />
Some special application diagnostic information!<br />
</text><br />
<escape-your-data xmlns='application-ns'/><br />
</stream:error><br />
</stream:stream><br />
</source><br />
<br />
===简化的流示例===<br />
<br />
:这里包含两个简化的例子,描述了基于流的客户端在服务器上的“会话”(这里"C"表示从客户端发给服务器,"S"表示从服务器发给客户端);这些例子只是用于举例说明原理.<br />
<br />
:一个基本的 "会话":<br />
<br />
<source lang="xml"><br />
C: <?xml version='1.0'?><br />
<stream:stream to='example.com' xmlns='jabber:client' xmlns:stream='http://etherx.jabber.org/streams' version='1.0'><br />
<br />
S: <?xml version='1.0'?><br />
<stream:stream from='example.com' id='someid' xmlns='jabber:client' xmlns:stream='http://etherx.jabber.org/streams' version='1.0'><br />
... encryption, authentication, and resource binding ...<br />
<br />
C: <message from='juliet@example.com' to='romeo@example.net' xml:lang='en'><br />
<br />
C: <body>Art thou not Romeo, and a Montague?</body><br />
<br />
C: </message><br />
<br />
S: <message from='romeo@example.net' to='juliet@example.com' xml:lang='en'><br />
<br />
S: <body>Neither, fair saint, if either thee dislike.</body><br />
<br />
S: </message><br />
<br />
C: </stream:stream><br />
<br />
S: </stream:stream><br />
</source><br />
<br />
<br />
:一个不成功的 "会话" :<br />
<br />
<source lang="xml"><br />
C: <?xml version='1.0'?><br />
<stream:stream to='example.com' xmlns='jabber:client' xmlns:stream='http://etherx.jabber.org/streams' version='1.0'><br />
<br />
S: <?xml version='1.0'?><br />
<stream:stream from='example.com' id='someid' xmlns='jabber:client' xmlns:stream='http://etherx.jabber.org/streams' version='1.0'><br />
... encryption, authentication, and resource binding ...<br />
<br />
C: <message xml:lang='en'><br />
<body>Bad XML, no closing body tag!<br />
</message><br />
<br />
S: <stream:error><br />
<xml-not-well-formed xmlns='urn:ietf:params:xml:ns:xmpp-streams'/><br />
</stream:error><br />
<br />
S: </stream:stream><br />
</source><br />
<br />
==TLS 的使用==<br />
<br />
===概览===<br />
<br />
:XMPP包含的一个保证流安全的方法来防止篡改和偷听.这个传输层安全协议[TLS]的频道加密方法, 模拟了类似的其他"STARTTLS"(见RFC 2595 [USINGTLS])的扩展,如 IMAP [IMAP], POP3 [POP3], and ACAP [ACAP]."STARTTLS"的扩展名字空间是'urn:ietf:params:xml:ns:xmpp-tls'.<br />
<br />
:一个给定域的管理员可以(MAY)要求客户端和服务器通信以及服务器之间通信时使用TLS,或者两者都要求。客户端应该(SHOULD)在尝试完成 SASL (第六章)握手之前使用 TLS,服务器应该(SHOULD)在两个域之间使用 TLS 以保证服务器间通信的安全。<br />
<br />
:以下是使用规则:<br />
<br />
::# 一个遵守本协议的初始化实体必须(MUST)在初始化流的头信息中包含一个'version'属性并把值设为“1.0”。<br />
::# 如果TLS握手发生在两个服务器之间,除非服务器声称的DNS主机名已经被解析(见第十四章第四节 Server-to-Server Communications),通信不能(MUST NOT)继续进行。<br />
::# 当一个遵守本协议的接收实体接收了一个初始化流(它的头信息中包含一个'version'属性并且值设为“1.0”),在发送应答流的的头信息(其中包含版本标记)之后,它必须发送(MUST)<starttls/>元素(名字空间为 'urn:ietf:params:xml:ns:xmpp-tls')以及其他它支持的流特性 。<br />
::# 如果初始化实体选择使用TLS,TLS握手必须在SASL握手之前完成;这个顺序用于帮助保护SASL握手时发送的认证信息的安全,同时可以在必要的时候在TLS握手之前为SASL外部机制提供证书。<br />
::# TLS握手期间,一个实体不能(MUST NOT)在流的根元素中发送任何空格符号作为元素的分隔符(在下面的TLS示例中的任何空格符都仅仅是为了便于阅读);这个禁令用来帮助确保安全层字节精度。<br />
::# 接收实体必须(MUST)在发送<proceed/> 元素的关闭符号">" 之后立刻开始TLS协商。初始化实体必须(MUST)在从接收实体接收到<proceed/> 元素的关闭符号">" 之后立刻开始TLS协商。<br />
::# 初始化实体必须(MUST)验证接收实体出示的证书;关于证书验证流程参见Certificate Validation ( 第十四章第二节)。<br />
::# 证书必须(MUST)检查初始化实体(比如一个用户)提供的主机名;而不是通过DNS系统解析出来的主机名;例如,如果用户指定一个主机名"example.com"而一个DNS SRV [SRV]查询返回"im.example.com",证书必须(MUST)检查"example.com".如果任何种类的XMPP实体(例如客户端或服务器)的JID出现在一个证书里,它必须(MUST)表现为一个别名实体里面的UTF8字符串,存在于subjectAltName之中。如何使用 [ASN.1] 对象标识符 "id-on-xmppAddr" 定义在本文的第五章第一节第一小节。<br />
::# 如果 TLS 握手成功了,接收实体必须(MUST) 丢弃TLS 生效之前从初始化实体得到的任何不可靠的信息.<br />
::# 如果 TLS 握手成功了,初始化实体必须(MUST) 丢弃TLS 生效之前从接收实体得到的任何不可靠的信息. <br />
::# 如果 TLS 握手成功了,接收实体不能(MUST NOT)在流重新开始的时候通过提供其他的流特性来向初始化实体提供 STARTTLS 扩展.<br />
::# 如果 TLS 握手成功了,初始化实体必须(MUST)继续进行SASL握手。<br />
::# 如果 TLS 握手失败了,接收实体必须(MUST)终止XML流和相应的TCP连接。<br />
::# 关于必须(MUST)支持的机制,参照 Mandatory-to-Implement Technologies (第十四章第七节) 。<br />
<br />
====用于 XMPP 地址的 ASN.1 对象标识符====<br />
<br />
:上文提到的[ASN.1] 对象标识符 "id-on-xmppAddr"定义如下:<br />
<br />
::id-pkix OBJECT IDENTIFIER ::= { iso(1) identified-organization(3)<br />
<br />
::dod(6) internet(1) security(5) mechanisms(5) pkix(7) }<br />
<br />
::id-on OBJECT IDENTIFIER ::= { id-pkix 8 } \-\- other name forms<br />
<br />
::id-on-xmppAddr OBJECT IDENTIFIER ::= { id-on 5 }<br />
<br />
::XmppAddr ::= UTF8String<br />
<br />
:对象标识符也可以(MAY)使用点分隔的格式,如 "1.3.6.1.5.5.7.8.5".<br />
<br />
===叙述===<br />
<br />
:当一个初始化实体用TLS保护一个和接收实体之间的流,其步骤如下:<br />
<br />
::# 初始化实体打开一个TCP连接,发送一个打开的XML流头信息(其'version'属性设置为"1.0")给接收实体以初始化一个流。<br />
::# 接收实体打开一个TCP连接,发送一个XML流头信息(其'version'属性设置为"1.0")给初始化实体作为应答。<br />
::# 接收实体向初始化实体提议STARTTLS范围(包括其他支持的流特性),如果TLS对于和接收实体交互是必需的,它应该(SHOULD)在<starttls/>元素中包含子元素<required/>.<br />
::# 初始化实体发出STARTTLS命令(例如, 一个符合'urn:ietf:params:xml:ns:xmpp-tls'名字空间的 <starttls/> 元素) 以通知接收实体它希望开始一个TLS握手来保护流。<br />
::# 接收实体必须(MUST)以'urn:ietf:params:xml:ns:xmpp-tls'名字空间中的<proceed/>元素或<failure/>元素应答。如果失败,接收实体必须(MUST)终止XML流和相应的TCP连接。如果继续进行,接收实体必须(MUST)尝试通过TCP连接完成TLS握手并且在TLS握手完成之前不能(MUST NOT)发送任何其他XML数据。<br />
::# 初始化实体和接收实体尝试完成TLS握手。(要符合\[TLS\]规范)<br />
::# 如果 TLS 握手不成功, 接收实体必须(MUST)终止 TCP 连接. 如果 TLS 握手成功, 初始化实体必须(MUST)发送给接收实体一个打开的XML流头信息来初始化一个新的流(先发送一个关闭标签</stream>是不必要的,因为接收实体和初始化实体必须(MUST)确保原来的流在TLS握手成功之后被关闭) 。<br />
::# 在从初始化实体收到新的流头信息之后,接收实体必须(MUST)发送一个新的XML流头信息给初始化实体作为应答,其中应包含可用的特性但不包含STATRTTLS特性。<br />
<br />
===客户端-服务器 示例===<br />
<br />
:以下例子展示一个客户端使用STARTTLS保护数据流 (注意: 以下步骤举例说明协议中的失败案例;在这个例子中它们并不详尽并且也不是必须被数据传输触发的).<br />
<br />
:步骤 1: 客户端初始化流给服务器:<br />
<br />
<source lang="xml"><br />
<stream:stream xmlns='jabber:client' xmlns:stream='http://etherx.jabber.org/streams' to='example.com' version='1.0'><br />
</source><br />
<br />
:步骤 2: 服务器发送一个流标签给客户端作为应答:<br />
<br />
<source lang="xml"><br />
<stream:stream xmlns='jabber:client' xmlns:stream='http://etherx.jabber.org/streams' id='c2s_123' from='example.com' version='1.0'><br />
</source><br />
<br />
:步骤 3: 服务器发送 STARTTLS 范围给客户端(包括验证机制和任何其他流特性):<br />
<br />
<source lang="xml"><br />
<stream:features><br />
<starttls xmlns='urn:ietf:params:xml:ns:xmpp-tls'><br />
<required/><br />
</starttls><br />
<mechanisms xmlns='urn:ietf:params:xml:ns:xmpp-sasl'><br />
<mechanism>DIGEST-MD5</mechanism><br />
<mechanism>PLAIN</mechanism><br />
</mechanisms><br />
</stream:features><br />
</source><br />
<br />
:步骤 4: 客户端发送 STARTTLS 命令给服务器:<br />
<br />
<source lang="xml"><br />
<starttls xmlns='urn:ietf:params:xml:ns:xmpp-tls'/><br />
</source><br />
<br />
:步骤 5: 服务器通知客户端可以继续进行:<br />
<br />
<source lang="xml"><br />
<proceed xmlns='urn:ietf:params:xml:ns:xmpp-tls'/><br />
</source><br />
<br />
:步骤 5 (或者): 服务器通知客户端 TLS 握手失败并关闭流和TCP连接:<br />
<br />
<source lang="xml"><br />
<failure xmlns='urn:ietf:params:xml:ns:xmpp-tls'/><br />
</stream:stream><br />
</source><br />
<br />
:步骤 6: 客户端和服务器尝试通过已有的TCP连接完成 TLS 握手.<br />
<br />
:步骤 7: 如果 TLS 握手成功, 客户端初始化一个新的流给服务器:<br />
<br />
<source lang="xml"><br />
<stream:stream xmlns='jabber:client' xmlns:stream='http://etherx.jabber.org/streams' to='example.com' version='1.0'><br />
</source><br />
<br />
:步骤 7 (或者): 如果 TLS 握手不成功, 服务器关闭 TCP 连接.<br />
<br />
:步骤 8: 服务器发送一个流头信息应答客户端,其中包括任何可用的流特性:<br />
<br />
<source lang="xml"><br />
<stream:stream xmlns='jabber:client' xmlns:stream='http://etherx.jabber.org/streams' from='example.com' id='c2s_234' version='1.0'><br />
<stream:features><br />
<mechanisms xmlns='urn:ietf:params:xml:ns:xmpp-sasl'><br />
<mechanism>DIGEST-MD5</mechanism><br />
<mechanism>PLAIN</mechanism><br />
<mechanism>EXTERNAL</mechanism><br />
</mechanisms><br />
</stream:features><br />
</source><br />
<br />
:步骤 9: 客户端继续 SASL 握手 (第六章).<br />
<br />
===服务器-服务器示例===<br />
<br />
:以下例子展示两个服务器之间使用STARTTLS保护数据流 (注意: 以下步骤举例说明协议中的失败案例;在这个例子中它们并不详尽并且也不是必须被数据传输触发的).<br />
<br />
:步骤 1: Server1 初始化流给 Server2:<br />
<br />
<source lang="xml"><br />
<stream:stream xmlns='jabber:server' xmlns:stream='http://etherx.jabber.org/streams' to='example.com' version='1.0'><br />
</source><br />
<br />
:步骤 2: Server2 发送一个流标签给 Server1 作为应答:<br />
<br />
<source lang="xml"><br />
<stream:stream xmlns='jabber:server' xmlns:stream='http://etherx.jabber.org/streams' from='example.com' id='s2s_123' version='1.0'><br />
</source><br />
<br />
:步骤 3: Server2 发送 STARTTLS 范围给 Server1 ,包括验证机制和任何其他流特性:<br />
<br />
<source lang="xml"><br />
<stream:features><br />
<starttls xmlns='urn:ietf:params:xml:ns:xmpp-tls'><br />
<required/><br />
</starttls><br />
<mechanisms xmlns='urn:ietf:params:xml:ns:xmpp-sasl'><br />
<mechanism>DIGEST-MD5</mechanism><br />
<mechanism>KERBEROS_V4</mechanism><br />
</mechanisms><br />
</stream:features><br />
</source><br />
<br />
:步骤 4: Server1 发送 STARTTLS 命令给 Server2:<br />
<br />
<source lang="xml"><br />
<starttls xmlns='urn:ietf:params:xml:ns:xmpp-tls'/><br />
</source><br />
<br />
:步骤 5: Server2 通知 Server1 允许继续进行:<br />
<br />
<source lang="xml"><br />
<proceed xmlns='urn:ietf:params:xml:ns:xmpp-tls'/><br />
</source><br />
<br />
:步骤 5 (或者): Server2 通知 Server1 TLS握手失败并关闭流:<br />
<br />
<source lang="xml"><br />
<failure xmlns='urn:ietf:params:xml:ns:xmpp-tls'/><br />
</stream:stream><br />
</source><br />
<br />
:步骤 6: Server1 和 Server2 尝试通过 TCP 完成 TLS 握手.<br />
<br />
:步骤 7: 如果 TLS 握手成功, Server1 初始化一个新的流给 Server2:<br />
<br />
<source lang="xml"><br />
<stream:stream xmlns='jabber:server' xmlns:stream='http://etherx.jabber.org/streams' to='example.com' version='1.0'><br />
</source><br />
<br />
:步骤 7 (或者): 如果 TLS 握手不成功, Server2 关闭 TCP 连接.<br />
<br />
:步骤 8: Server2 发送一个包含任何可用流特性的流头信息给 Server1 :<br />
<br />
<source lang="xml"><br />
<stream:stream xmlns='jabber:server' xmlns:stream='http://etherx.jabber.org/streams' from='example.com' id='s2s_234' version='1.0'><br />
<stream:features><br />
<mechanisms xmlns='urn:ietf:params:xml:ns:xmpp-sasl'><br />
<mechanism>DIGEST-MD5</mechanism><br />
<mechanism>KERBEROS_V4</mechanism><br />
<mechanism>EXTERNAL</mechanism><br />
</mechanisms><br />
</stream:features><br />
</source><br />
<br />
:步骤 9: Server1 继续进行 SASL 握手(第六章).<br />
<br />
==SASL 的使用==<br />
<br />
===概览===<br />
<br />
:XMPP 有一个验证流的方法,即XMPP特定的SASL(简单验证和安全层)[SASL]。SASL提供了一个通用的方法为基于连接的协议增加验证支持,而XMPP使用了一个普通的XML名字空间来满足SASL的需要。<br />
<br />
:以下规则应用于:<br />
<br />
:# 如果SASL协商发生在两台服务器之间,除非服务器宣称的DNS主机名得到解析,否则不能(MUST NOT)进行通信。(参见 服务器间的通信(第十四章第四节)).<br />
:# 如果初始化实体有能力使用 SASL 协商, 它必须(MUST)在初始化流的头信息中包含一个值为"1.0"的属性'version'。<br />
:# 如果接收实体有能力使用 SASL 协商, 它必须(MUST)在应答从初始化实体收到的打开流标签时(如果打开的流标签包含一个值为"1.0"的'version'属性),通过'urn:ietf:params:xml:ns:xmpp-sasl'名字空间中的<mechanisms/>元素声明一个或多个验证机制.<br />
:# 当 SASL 协商时, 一个实体不能(MUST NOT)在流的根元素中发送任何空格符号(匹配 production [3] content of [XML])作为元素之间的分隔符(在以下的SASL例子中任何空格符号的出现仅仅是为了增加可读性); 这条禁令帮助确保安全层字节的精确度。<br />
:# 当SASL握手时,在XML元素中使用的任何 XML 字符数据必须被编码成 base64, 编码遵循 RFC 3548 第三章的规定。<br />
:# 如果一个 简单名字"simple username" 规范被选定的SASL机制所支持,(比如, 这被 DIGEST-MD5 和 CRAM-MD5 机制支持但不被 EXTERNAL 和 GSSAPI 机制支持), 验证的时候初始化实体应该(SHOULD)在服务器间通信时提供 简单名字 自身的发送域(IP地址或包含在一个域标识符中的域名全称),在客户端与服务器之间通信时提供注册用户名(包含在一个XMPP节点标识符中的用户或节点名)。<br />
:# 如果初始化实体希望以另一个实体的身份出现并且SASL机制支持授权ID的传输,初始化实体在SASL握手时必须(MUST)提供一个授权ID。如果初始化实体不希望以另一个实体的身份出现,初始化实体在SASL握手时不能(MUST NOT)提供一个授权ID。在 [SASL] 的定义中,除非授权ID不同于从验证ID(详见[SASL])中得到的缺省的授权ID,初始化实体不能(MUST NOT)提供授权ID。如果提供了,这个授权ID的值必须(MUST)是<domain>的格式(对于服务器来说)或<node@domain>的格式(对于客户端来说). <br />
:# 在成功进行包括安全层的SASL握手之后,接收实体必须(MUST)丢弃任何从初始化实体得到的而不是从SASL协商本身获得的信息。<br />
:# 在成功进行包括安全层的SASL握手之后,初始化实体必须(MUST)丢弃任何从接收实体得到的而不是从SASL协商本身获得的信息。<br />
:# 参看 强制执行的技术 (第十四章第七节) ,了解关于必须(MUST)支持的机制.<br />
<br />
===叙述===<br />
<br />
:一个初始化实体使用SASL和接收实体做验证的步骤如下:<br />
<br />
:# 初始化实体请求SASL验证,它发送一个打开的XML流头信息给接收实体,其'version'属性的值为"1.0".<br />
:# 在发送一个XML流头回复之后,接收实体声明一个可用的SASL验证机制清单;每个机制作为一个<mechanism/>元素,作为子元素包含在<mechanisms/>容器元素(其名字空间为'urn:ietf:params:xml:ns:xmpp-sasl')中,而<mechanisms/>则包含在流名字空间中的<features/>元素中。如果在使用任何验证机制之前需要使用TLS(见第五章),接收实体不能(MUST NOT)在TLS握手之前提供可用的SASL验证机制清单。如果初始化实体在优先的TLS协商过程中呈现了一个合法的证书,接收实体应该(SHOULD)在SASL握手中提出一个SASL外部机制给初始化实体,尽管这个外部机制可以(MAY)在其它环境下提供。<br />
:# 初始化实体发送一个符合'urn:ietf:params:xml:ns:xmpp-sasl'名字空间的<auth/>元素(其中包含了适当的'mechanism'属性值)给接收实体,以选择一个机制。如果这个机制支持或需要,这个元素可以(MAY)包含XML字符数据(在SASL术语中,即“初始化应答”);如果初始化实体需要发送一个零字节的初始化应答,它必须(MUST)传输一个单独的等号作为应答,这表示应答有效但不包含数据。<br />
:# 如果必要,接收实体向初始化实体发送一个符合'urn:ietf:params:xml:ns:xmpp-sasl'名字空间的<challenge/>元素来发出挑战;这个元素可以(MAY)包含XML字符数据(必须按照初始化实体选择的SASL机制进行一致性运算)。<br />
:# 初始化实体向接收实体发送符合'urn:ietf:params:xml:ns:xmpp-sasl'名字空间的<response/>元素作为应答;这个元素可以(MAY)包含XML字符数据(必须按照初始化实体选择的SASL机制进行一致性运算)。<br />
:# 如果必要,接收实体发送更多的挑战给初始化实体,初始化实体发送更多的回应。<br />
<br />
:这一系列的 挑战/应答 组,持续进行直到发生以下三件事中的一件为止:<br />
<br />
:# 初始化实体向接收实体发送符合'urn:ietf:params:xml:ns:xmpp-sasl'名字空间的<abort/>元素以中止握手。在接收到<abort/>元素之后,接收实体应该(SHOULD)允许一个可配置的但是合理的重试次数(至少2次),然后它必须(MUST)终止TCP连接;这使得初始化实体(如一个最终用户客户端)能够容忍可能不正确的credentials(如密码输入错误)而不用强制重新连接。<br />
:# 接收实体向初始化实体发送符合'urn:ietf:params:xml:ns:xmpp-sasl'名字空间的<failure/>元素以报告握手失败(详细的失败原因应该在<failure/>的一个适当的子元素中沟通,在第六章第四节中的SASL Errors中定义)。如果失败的情况发生了,接收实体应该(SHOULD)允许一个可配置的但是合理的重试次数(至少2次), 然后它必须(MUST)终止TCP连接;这使得初始化实体(如一个最终用户客户端)能够容忍可能不正确的credentials(如密码输入错误)而不用强制重新连接。<br />
:# 接收实体向初始化实体发送符合'urn:ietf:params:xml:ns:xmpp-sasl'名字空间的<success/>元素以报告握手成功;如果所选择的SASL机制要求,这个元素可以(MAY)包含XML字符数据(见SASL术语,“成功的额外数据”)。接收到<success/> 元素之后,初始化实体必须(MUST)发送一个打开的XML流头信息给接收实体以发起一个新的的流(不需要先发送一个 </stream>标签,因为在发送和接收到<success/>元素之后,接收实体和初始化实体必须确认原来的流被关闭了)。从初始化实体接收到新的流头信息之后,接收实体必须(MUST)发送一个新的流头信息给初始化实体作为回应,附上任何可用的特性(但不包括 STARTTLS 和 SASL 特性)或一个空的 <features/> 元素(这表示没有更多的特性可用);任何没有在本文定义的附加特性必须(MUST)在XMPP的相关扩展中定义。<br />
<br />
===SASL 定义===<br />
<br />
:[SASL]的必要条件要求通过协议定义来提供以下信息:<br />
<br />
::service name(服务名): "xmpp"<br />
<br />
::initiation sequence(开始序列): 当初始化实体提供一个打开的XML流头信息并且接收实体善意回应之后,接收实体提供一个可接受的验证方法清单。初始化实体从这个清单中选择一个方法,把它作为 <auth/> 元素的 'mechanism' 属性的值发送给接收实体,也可以选择发送一个初始化应答以避免循环。<br />
<br />
::exchange sequence(交换序列): 挑战和回应的交换,从接收实体发送给初始化实体的 <challenge/> 元素和从初始化实体发送给接收实体的 <response/> 元素信息。接收实体通过发送 <failure/>元素报告失败,发送<success/>元素报告成功;初始化实体通过发送<abort/> 元素中止交换。成功的协商之后,两边都认为原来的XML流已经关闭并且都开始发送新的流头信息。<br />
<br />
::security layer negotiation(安全层协商): 安全层在接收实体发送 <success/> 元素的关闭字符">"之后立刻生效,在初始化实体发送 <success/> 元素的关闭字符">"之后也立刻生效。层的顺序是 \[TCP\],\[TLS\],然后是 \[SASL\],然后是 \[XMPP\]。<br />
<br />
::use of the authorization identity(授权ID的使用): 授权ID可在xmpp中用于表示一个客户端的非缺省的<node@domain>,或一个服务器的<domain> 。<br />
<br />
===SASL 错误===<br />
<br />
:SASL相关的错误条件定义如下:<br />
<br />
::* <aborted/> -- 接收实体认可由初始化实体发送的<abort/>元素;在回应一个<abort/>元素时发送。<br />
<br />
::* <incorrect-encoding/> -- 由初始化实体提供的数据无法处理,因为[BASE64]编码不正确(例如,因为编码不符合[BASE64]的第三章); 在回应一个包含初始化响应数据的<response/> 元素或<auth/>元素时发送.<br />
<br />
::* <invalid-authzid/> -- 由初始化实体提供的授权id是非法的,因为它的格式不正确或初始化实体无权给那个ID授权;在回应一个包含初始化响应数据的<response/> 元素或<auth/>元素时发送。<br />
<br />
::* <invalid-mechanism/> -- 初始化实体不能提供一个机制活、或请求一个不被接受实体支持的机制;在回应一个<auth/>元素时发送。<br />
<br />
::* <mechanism-too-weak/> -- 初始化实体请求的机制比服务器策略对它的要求弱;在回应一个包含初始化响应数据的<response/> 元素或<auth/>元素时发送。<br />
<br />
::* <not-authorized/> -- 验证失败,因为初始化实体没有提供合法的credentials(这包括但不限于未知用户名等情形);在回应一个包含初始化响应数据的<response/> 元素或<auth/>元素时发送。<br />
<br />
::* <temporary-auth-failure/> -- 验证失败,因为接收实体出现了临时的错误;在回应一个<response/> 元素或<auth/>元素时发送。<br />
<br />
===客户端-服务器 示例===<br />
<br />
:以下例子展示了一个客户端和一个服务器使用SASL作验证的数据流,通常是在成功的TLS握手之后(注意:以下显示的替代步骤仅用于举例说明协议的失败情形;它们不够详尽也不需要由例子中的数据传送来触发)。<br />
<br />
:步骤 1: 客户端初始化流给服务器:<br />
<br />
<source lang="xml"><br />
<stream:stream xmlns='jabber:client' xmlns:stream='http://etherx.jabber.org/streams' to='example.com' version='1.0'><br />
</source><br />
<br />
:步骤 2: 服务器向客户端发送流标签作为应答:<br />
<br />
<source lang="xml"><br />
<stream:stream xmlns='jabber:client' xmlns:stream='http://etherx.jabber.org/streams' id='c2s_234' from='example.com' version='1.0'><br />
</source><br />
<br />
:步骤 3: 服务器通知客户端可用的验证机制:<br />
<br />
<source lang="xml"><br />
<stream:features><br />
<mechanisms xmlns='urn:ietf:params:xml:ns:xmpp-sasl'><br />
<mechanism>DIGEST-MD5</mechanism><br />
<mechanism>PLAIN</mechanism><br />
</mechanisms><br />
</stream:features><br />
</source><br />
<br />
:步骤 4: 客户端选择一个验证机制:<br />
<br />
<source lang="xml"><br />
<auth xmlns='urn:ietf:params:xml:ns:xmpp-sasl' mechanism='DIGEST-MD5'/><br />
</source><br />
<br />
:步骤 5: 服务器发送一个 \[BASE64\] 编码的挑战给客户端:<br />
<br />
<source lang="xml"><br />
<challenge xmlns='urn:ietf:params:xml:ns:xmpp-sasl'><br />
cmVhbG09InNvbWVyZWFsbSIsbm9uY2U9Ik9BNk1HOXRFUUdtMmhoIixxb3A9ImF1dGgi<br />
LGNoYXJzZXQ9dXRmLTgsYWxnb3JpdGhtPW1kNS1zZXNzCg==<br />
</challenge><br />
</source><br />
<br />
:解码后的挑战信息是:<br />
<br />
<source lang="xml"><br />
realm="somerealm",nonce="OA6MG9tEQGm2hh",\<br />
qop="auth",charset=utf-8,algorithm=md5-sess<br />
</source><br />
<br />
:步骤 5 (替代): 服务器返回一个错误给客户端:<br />
<br />
<source lang="xml"><br />
<failure xmlns='urn:ietf:params:xml:ns:xmpp-sasl'><br />
<incorrect-encoding/><br />
</failure><br />
</stream:stream><br />
</source><br />
<br />
:步骤 6: 客户端发送一个\[BASE64\]编码的回应这个挑战:<br />
<br />
<source lang="xml"><br />
<response xmlns='urn:ietf:params:xml:ns:xmpp-sasl'><br />
dXNlcm5hbWU9InNvbWVub2RlIixyZWFsbT0ic29tZXJlYWxtIixub25jZT0i<br />
T0E2TUc5dEVRR20yaGgiLGNub25jZT0iT0E2TUhYaDZWcVRyUmsiLG5jPTAw<br />
MDAwMDAxLHFvcD1hdXRoLGRpZ2VzdC11cmk9InhtcHAvZXhhbXBsZS5jb20i<br />
LHJlc3BvbnNlPWQzODhkYWQ5MGQ0YmJkNzYwYTE1MjMyMWYyMTQzYWY3LGNo<br />
YXJzZXQ9dXRmLTgK<br />
</response><br />
</source><br />
<br />
:解码后的回应信息是:<br />
<br />
<source lang="xml"><br />
username="somenode",realm="somerealm",\<br />
nonce="OA6MG9tEQGm2hh",cnonce="OA6MHXh6VqTrRk",\<br />
nc=00000001,qop=auth,digest-uri="xmpp/example.com",\<br />
response=d388dad90d4bbd760a152321f2143af7,charset=utf-8<br />
</source><br />
<br />
:步骤 7: 服务器发送另一个\[BASE64\]编码的挑战给客户端:<br />
<br />
<source lang="xml"><br />
<challenge xmlns='urn:ietf:params:xml:ns:xmpp-sasl'><br />
cnNwYXV0aD1lYTQwZjYwMzM1YzQyN2I1NTI3Yjg0ZGJhYmNkZmZmZAo=<br />
</challenge><br />
</source><br />
<br />
:解码后的挑战信息是:<br />
<br />
<source lang="xml"><br />
rspauth=ea40f60335c427b5527b84dbabcdfffd<br />
</source><br />
<br />
:步骤 7 (或者): 服务器返回一个错误给客户端:<br />
<br />
<source lang="xml"><br />
<failure xmlns='urn:ietf:params:xml:ns:xmpp-sasl'><br />
<temporary-auth-failure/><br />
</failure><br />
</stream:stream><br />
</source><br />
<br />
:步骤 8: 客户端应答这个挑战:<br />
<br />
<source lang="xml"><br />
<response xmlns='urn:ietf:params:xml:ns:xmpp-sasl'/><br />
</source><br />
<br />
:步骤 9: 服务器通知客户端验证成功:<br />
<br />
<source lang="xml"><br />
<success xmlns='urn:ietf:params:xml:ns:xmpp-sasl'/><br />
</source><br />
<br />
:步骤 9 (或者): 服务器通知客户端验证失败:<br />
<br />
<source lang="xml"><br />
<failure xmlns='urn:ietf:params:xml:ns:xmpp-sasl'><br />
<temporary-auth-failure/><br />
</failure><br />
</stream:stream><br />
</source><br />
<br />
:步骤 10: 客户端发起一个新的流给服务器:<br />
<br />
<source lang="xml"><br />
<stream:stream xmlns='jabber:client' xmlns:stream='http://etherx.jabber.org/streams' to='example.com' version='1.0'><br />
</source><br />
<br />
:步骤 11: 服务器发送一个流头信息回应客户端,并附上任何可用的特性(或空的features元素):<br />
<br />
<source lang="xml"><br />
<stream:stream xmlns='jabber:client' xmlns:stream='http://etherx.jabber.org/streams' id='c2s_345' from='example.com' version='1.0'><br />
<stream:features><br />
<bind xmlns='urn:ietf:params:xml:ns:xmpp-bind'/><br />
<session xmlns='urn:ietf:params:xml:ns:xmpp-session'/><br />
</stream:features><br />
</source><br />
<br />
===服务器-服务器 示例===<br />
<br />
:以下例子展示了一个服务器和另一个服务器使用SASL作验证的数据流,通常是在成功的TLS握手之后(注意:以下显示的替代步骤仅用于举例说明协议的失败情形;它们不够详尽也不需要由例子中的数据传送来触发)。<br />
<br />
:步骤 1: 服务器1 发起一个流给 服务器2 :<br />
<br />
<source lang="xml"><br />
<stream:stream xmlns='jabber:server' xmlns:stream='http://etherx.jabber.org/streams' to='example.com' version='1.0'><br />
</source><br />
<br />
:步骤 2: 服务器2 回应一个流标签给 服务器1:<br />
<br />
<source lang="xml"><br />
<stream:stream xmlns='jabber:server' xmlns:stream='http://etherx.jabber.org/streams' from='example.com' id='s2s_234' version='1.0'><br />
</source><br />
<br />
:步骤 3: 服务器2 通知 服务器1 可用的验证机制:<br />
<br />
<source lang="xml"><br />
<stream:features><br />
<mechanisms xmlns='urn:ietf:params:xml:ns:xmpp-sasl'><br />
<mechanism>DIGEST-MD5</mechanism><br />
<mechanism>KERBEROS_V4</mechanism><br />
</mechanisms><br />
</stream:features><br />
</source><br />
<br />
:步骤 4: 服务器1 选择一个验证机制:<br />
<br />
<source lang="xml"><br />
<auth xmlns='urn:ietf:params:xml:ns:xmpp-sasl' mechanism='DIGEST-MD5'/><br />
</source><br />
<br />
:步骤 5: 服务器2 发送一个\[BASE64\]编码的挑战给 服务器1:<br />
<br />
<source lang="xml"><br />
<challenge xmlns='urn:ietf:params:xml:ns:xmpp-sasl'><br />
cmVhbG09InNvbWVyZWFsbSIsbm9uY2U9Ik9BNk1HOXRFUUdtMmhoIixxb3A9<br />
ImF1dGgiLGNoYXJzZXQ9dXRmLTgsYWxnb3JpdGhtPW1kNS1zZXNz<br />
</challenge><br />
</source><br />
<br />
:解码后的挑战信息是:<br />
<br />
<source lang="xml"><br />
realm="somerealm",nonce="OA6MG9tEQGm2hh",\<br />
qop="auth",charset=utf-8,algorithm=md5-sess<br />
</source><br />
<br />
:步骤 5 (替代): 服务器2 返回一个错误给 服务器1:<br />
<br />
<source lang="xml"><br />
<failure xmlns='urn:ietf:params:xml:ns:xmpp-sasl'><br />
<incorrect-encoding/><br />
</failure><br />
</stream:stream><br />
</source><br />
<br />
:步骤 6: 服务器1 发送一个\[BASE64\]编码的回应这个挑战:<br />
<br />
<source lang="xml"><br />
<response xmlns='urn:ietf:params:xml:ns:xmpp-sasl'><br />
dXNlcm5hbWU9ImV4YW1wbGUub3JnIixyZWFsbT0ic29tZXJlYWxtIixub25j<br />
ZT0iT0E2TUc5dEVRR20yaGgiLGNub25jZT0iT0E2TUhYaDZWcVRyUmsiLG5j<br />
PTAwMDAwMDAxLHFvcD1hdXRoLGRpZ2VzdC11cmk9InhtcHAvZXhhbXBsZS5v<br />
cmciLHJlc3BvbnNlPWQzODhkYWQ5MGQ0YmJkNzYwYTE1MjMyMWYyMTQzYWY3<br />
LGNoYXJzZXQ9dXRmLTgK<br />
</response><br />
</source><br />
<br />
:解码后的应答信息是:<br />
<br />
<source lang="xml"><br />
username="example.org",realm="somerealm",\<br />
nonce="OA6MG9tEQGm2hh",cnonce="OA6MHXh6VqTrRk",\<br />
nc=00000001,qop=auth,digest-uri="xmpp/example.org",\<br />
response=d388dad90d4bbd760a152321f2143af7,charset=utf-8<br />
</source><br />
<br />
:步骤 7: 服务器2 发送另外一个\[BASE64\]编码的挑战给 服务器1:<br />
<br />
<source lang="xml"><br />
<challenge xmlns='urn:ietf:params:xml:ns:xmpp-sasl'><br />
cnNwYXV0aD1lYTQwZjYwMzM1YzQyN2I1NTI3Yjg0ZGJhYmNkZmZmZAo=<br />
</challenge><br />
</source><br />
<br />
:解码后的挑战信息是:<br />
<br />
<source lang="xml"><br />
rspauth=ea40f60335c427b5527b84dbabcdfffd<br />
</source><br />
<br />
:步骤 7 (或者): 服务器2 返回一个错误给 服务器1:<br />
<br />
<source lang="xml"><br />
<failure xmlns='urn:ietf:params:xml:ns:xmpp-sasl'><br />
<invalid-authzid/><br />
</failure><br />
</stream:stream><br />
</source><br />
<br />
:步骤 8: 服务器1 回应挑战:<br />
<br />
<source lang="xml"><br />
<response xmlns='urn:ietf:params:xml:ns:xmpp-sasl'/><br />
</source><br />
<br />
:步骤 8 (或者): 服务器1 中止协商:<br />
<br />
<source lang="xml"><br />
<abort xmlns='urn:ietf:params:xml:ns:xmpp-sasl'/><br />
</source><br />
<br />
:步骤 9: 服务器2 通知 服务器1 验证成功:<br />
<br />
<source lang="xml"><br />
<success xmlns='urn:ietf:params:xml:ns:xmpp-sasl'/><br />
</source><br />
<br />
:步骤 9 (或者): 服务器2 通知 服务器1 验证失败:<br />
<br />
<source lang="xml"><br />
<failure xmlns='urn:ietf:params:xml:ns:xmpp-sasl'><br />
<aborted/><br />
</failure><br />
</stream:stream><br />
</source><br />
<br />
:步骤 10: 服务器1 重新发起一个新的流给 服务器2:<br />
<br />
<source lang="xml"><br />
<stream:stream xmlns='jabber:server' xmlns:stream='http://etherx.jabber.org/streams' to='example.com' version='1.0'><br />
</source><br />
<br />
:步骤 11: 服务器2 发送一个流头信息应答 服务器1 ,并附上任何可用的特性(或一个空的features元素).:<br />
<br />
<source lang="xml"><br />
<stream:stream xmlns='jabber:client' xmlns:stream='http://etherx.jabber.org/streams' from='example.com' id='s2s_345' version='1.0'><br />
<stream:features/><br />
</source><br />
<br />
==资源绑定==<br />
<br />
:在和接收实体完成 SASL 协商(第六章)之后,初始化实体可能(MAY)想要或者需要绑定一个特定的资源到流上.通常这仅适用于客户端: 为了满足本文定义的寻址格式(第三章)和节传输规则(第十章),客户端<node@domain>必须(MUST)拥有一个相关的资源ID(由服务器生成或由客户端程序提供);以确保在流上使用的地址是一个“全JID”(<node@domain/resource>)。<br />
<br />
:接收到一个成功的SASL握手之后,客户端必须(MUST)发送一个新的流头信息给服务器,服务器必须(MUST)返回一个包含可用的流特性列表的头信息。特别是,在成功的SASL握手之后如果服务器需要客户端绑定一个资源,它必须(MUST)在握手成功之后(而不是之前)发送给客户端的应答流特性中包含一个空的符合'urn:ietf:params:xml:ns:xmpp-bind'名字空间的<bind/>元素。:<br />
<br />
:服务器向客户端声明资源绑定特性:<br />
<br />
<source lang="xml"><br />
<stream:stream xmlns='jabber:client' xmlns:stream='http://etherx.jabber.org/streams' id='c2s_345' from='example.com' version='1.0'><br />
<stream:features><br />
<bind xmlns='urn:ietf:params:xml:ns:xmpp-bind'/><br />
</stream:features><br />
</source><br />
<br />
:收到要求资源绑定的通知后,客户端必须(MUST)通过发送一个符合'urn:ietf:params:xml:ns:xmpp-bind'名字空间的“set”类型的IQ节(参见 IQ 语义 (第九章第二节第三小节))给服务器来绑定一个资源到流中。<br />
<br />
:如果客户端端希望允许服务器给自己生成一个资源ID,它可以发送一个包含空的<bind/>元素的“set”类型的IQ节。:<br />
<br />
:客户端请求服务器绑定资源:<br />
<br />
<source lang="xml"><br />
<iq type='set' id='bind_1'><br />
<bind xmlns='urn:ietf:params:xml:ns:xmpp-bind'/><br />
</iq><br />
</source><br />
<br />
:一个支持资源绑定的服务器必须(MUST)自动生成一个资源ID给客户端。一个由服务器生成的资源ID对于那个<node@domain>必须(MUST)是唯一的。<br />
<br />
:如果客户端希望指定资源ID,它发送一个包含期望资源ID的“set”类型的 IQ节,把资源ID作为<bind/>元素下的<resource/>子元素的XML字符数据:<br />
<br />
:客户端绑定一个资源:<br />
<br />
<source lang="xml"><br />
<iq type='set' id='bind_2'><br />
<bind xmlns='urn:ietf:params:xml:ns:xmpp-bind'><br />
<resource>someresource</resource><br />
</bind><br />
</iq><br />
</source><br />
<br />
:一旦服务器为客户端生成了一个资源ID或接受了客户端自己提供的资源ID,它必须(MUST)返回一个“result”类型的 IQ 节给客户端,这个节必须包含一个指明全JID的<jid/>子元素表示服务器决定连接的资源:<br />
<br />
:服务器通知客户端资源绑定成功:<br />
<br />
<source lang="xml"><br />
<iq type='result' id='bind_2'><br />
<bind xmlns='urn:ietf:params:xml:ns:xmpp-bind'><br />
<jid>somenode@example.com/someresource</jid><br />
</bind><br />
</iq><br />
</source><br />
<br />
:一个服务器应该(SHOULD)接受客户端提供的资源ID,但是可以(MAY)用服务器生成的资源ID覆盖它;在这种情况下,服务器不应该(SHOULD NOT)返回一个错误信息一个(如<forbidden/>)给客户端,而应该(SHOULD)在上文所述的 IQ result 中返回生成的资源ID。<br />
<br />
:当一个客户端自行提供资源ID时,可能发生以下的节错误(参见 Stanza Errors (第九章第三节)):<br />
<br />
::- 提供的资源ID服务器无法处理,因为不符合资源字符规范Resourceprep(附录B)。<br />
<br />
::- 客户端不被允许绑定一个资源(如节点或用户已经达到允许连接的资源数限制)。<br />
<br />
::- 提供的资源ID已经被使用但是服务器不允许以同一个资源ID绑定多个连接。<br />
<br />
:协议对这些错误条件规定如下.<br />
<br />
::资源ID不能处理:<br />
<br />
<source lang="xml"><br />
<iq type='error' id='bind_2'><br />
<bind xmlns='urn:ietf:params:xml:ns:xmpp-bind'><br />
<resource>someresource</resource><br />
</bind><br />
<error type='modify'><br />
<bad-request xmlns='urn:ietf:params:xml:ns:xmpp-stanzas'/><br />
</error><br />
</iq><br />
</source><br />
<br />
::客户端不允许绑定一个资源:<br />
<br />
<source lang="xml"><br />
<iq type='error' id='bind_2'><br />
<bind xmlns='urn:ietf:params:xml:ns:xmpp-bind'><br />
<resource>someresource</resource><br />
</bind><br />
<error type='cancel'><br />
<not-allowed xmlns='urn:ietf:params:xml:ns:xmpp-stanzas'/><br />
</error><br />
</iq><br />
</source><br />
<br />
::资源ID已经在使用:<br />
<br />
<source lang="xml"><br />
<iq type='error' id='bind_2'><br />
<bind xmlns='urn:ietf:params:xml:ns:xmpp-bind'><br />
<resource>someresource</resource><br />
</bind><br />
<error type='cancel'><br />
<conflict xmlns='urn:ietf:params:xml:ns:xmpp-stanzas'/><br />
</error><br />
</iq><br />
</source><br />
<br />
:如果,在完成资源绑定步骤之前,客户端试图以符合'urn:ietf:params:xml:ns:xmpp-bind'名字空间的<bind/>子元素发送一个非IQ类型的XML节,服务器不能(MUST NOT)处理这个节,而应该(SHOULD)返回一个<not-authorized/>节错误信息给客户端.<br />
<br />
==服务器回拨==<br />
<br />
===概览===<br />
<br />
:Jabber协议接受的来自XMPP的包括“服务器回拨”方法,用于防治域名欺骗,使得欺骗XML节更为困难。服务器回拨不是一个安全机制,并且它的服务器身份认证结果很弱(参见服务器之间的通信(第十四章第四节)中关于这个方法的安全特性)。需要健壮的安全性的域名应该(SHOULD)使用TLS或SASL;细节参见服务器间的通信(第十四章第四节)。如果SASL用于服务器间通信,回拨就不需要用了(SHOULD NOT)。本文描述回拨的好处在于向后兼容现存的实现和部署。<br />
<br />
:服务器回拨方法由现存的DNS系统的存在而成为可能,因为一个服务器(通常)可以查询给定域的授权服务器。由于服务器回拨依赖于DNS,除非服务器宣称的DNS主机得到解析,域之间的通信无法进行(参见服务器间的通信(第十四章第四节))。<br />
<br />
:服务器回拨是单向性的,可在单一方向上对一个流进行(微弱的)身份验证.因为服务器回拨不是一个验证机制,通过回拨获得相互的认证是不可能的.因此,为了使得服务器之间的双向通信,服务器回拨必须(MUST)在每个方向上完成。<br />
<br />
:在服务器回拨中生成和检验密钥的方法必须(MUST)考虑计算被使用的主机名,由接收服务器生成的流ID,和只有授权服务器网络才知道的秘密。在服务器回拨中流ID是安全性的关键所以必须(MUST)是不可预知的和不可重复的(见\[RANDOM\]中关于使用随机数获得安全性的建议).<br />
<br />
:任何回拨协商过程中发生的错误必须(MUST)被当成一个流错误,并导致流以及相关的TCP连接的终止.可能发生的错误情况协议中描述如下.<br />
<br />
:以下术语适用:<br />
<br />
:* 发起服务器 -- 尝试在两个域之间建立连接的那个服务器.<br />
<br />
:* 接收服务器 -- 尝试验证发起服务期声称的域名的那台服务器.<br />
<br />
:* 授权(权威?Authoritative) 服务器 -- 回答发起服务器声称的DNS主机名的服务器;基本上这应该是那台发起服务器,但是它也可能是一个在发起服务器网络中独立的服务器。<br />
<br />
===事件顺序===<br />
<br />
:以下是回拨中的事件顺序的简介:<br />
<br />
:# 发起服务器和接收服务器建立一个连接。<br />
:# 发起服务器通过到连接发送一个 'key' 值给接收服务期。<br />
:# 接收服务器建立一个连接到授权服务器。<br />
:# 接收服务器发送一个相同的 'key' 值给授权服务器。<br />
:# 授权服务器回答这个key是否合法。<br />
:# 接收服务器通知发起服务器是否被验证通过。<br />
<br />
:我们用用以下图形展示这个事件流程(见附件s2s.png):<br />
<br />
{image:img=s2s}<br />
<br />
发起服务器 接收服务器<br />
----------- ---------<br />
| |<br />
| 建立连接 |<br />
| ----------------------> |<br />
| |<br />
| 发stream头 |<br />
| ----------------------> |<br />
| |<br />
| 发stream头 |<br />
| <---------------------- |<br />
| | <br />
| 发回拨key | 认证服务器<br />
| ----------------------> | -------------<br />
| | |<br />
| 建立连接 |<br />
| ----------------------> |<br />
| |<br />
| 发stream头 |<br />
| ----------------------> |<br />
| |<br />
| 发stream头 |<br />
| <---------------------- |<br />
| |<br />
| 发验证请求 |<br />
| ----------------------> |<br />
| |<br />
| 发验证响应 |<br />
| <---------------------- |<br />
|<br />
| 报告回拨结果 |<br />
| <---------------------- |<br />
| |<br />
<br />
===协议===<br />
<br />
:服务器之间互动的细节协议如下:<br />
<br />
:1. 发起服务器和接受服务器建立TCP连接.<br />
<br />
:2. 发起服务器发送流头信息给接收服务器:<br />
<br />
<source lang="xml"><br />
<stream:stream xmlns:stream='http://etherx.jabber.org/streams' xmlns='jabber:server' xmlns:db='jabber:server:dialback'><br />
</source><br />
<br />
:注意: 'to'和'from'属性在流的根元素是可选的(OPTIONAL). 其中包含的xmlns:db名字空间向接收服务器声明了发起服务器支持回拨. 如果名字空间不正确,接收实体必须(MUST)生成一个<invalid-namespace/>流错误条件并且终止XML流和相应的TCP连接.<br />
<br />
:3. 接收服务器应该(SHOULD)回送一个流头信息给发起服务器,为这次交互生成一个唯一性的ID :<br />
<br />
<source lang="xml"><br />
<stream:stream xmlns:stream='http://etherx.jabber.org/streams' xmlns='jabber:server' xmlns:db='jabber:server:dialback' id='457F9224A0...'><br />
</source><br />
<br />
:注意: 'to'和'from'属性在流的根元素是可选的(OPTIONAL). 如果名字空间不正确,发起服务器必须生成一个<invalid-namespace/>流错误条件并且终止XML流和相应的TCP连接.也要注意,在这里接收服务器应该(SHOULD)应答但是可以(MAY)出于安全策略考虑只是悄悄地终止XML流和TCP连接;无论如何,如果接收服务器希望继续,它必须(MUST)回送一个流头信息给发起服务器.<br />
<br />
:4. 发起服务器发送一个回拨密钥给接收服务器:<br />
<br />
<source lang="xml"><br />
<db:result to='Receiving Server' from='Originating Server'><br />
98AF014EDC0...<br />
</db:result><br />
</source><br />
<br />
:注意: 这个密钥不由接收服务器检查,因为接收服务器在会话之间(between sessions)不保存发起服务器的信息. 这个由发起服务器生成的密钥必须(MUST)是基于接收服务器在上一步骤中提供的ID值,以及发起服务器与授权服务器共享的安全机制生成的。 如果 'to' 地址的值和接收服务器知道的主机名不匹配,接收服务器必须(MUST)生成一个<host-unknown/>流错误条件并且终止XML流和相应的TCP连接. 如果 'from' 地址和接收服务器已经建立的连接的域名相吻合,接收服务器必须(MUST)维护这个已经存在的连接,直到证明这个新的连接是合法的为止;另外,接收实体可以(MAY)选择生成一个<not-authorized/> 流错误条件给这个新的连接并且终止和新连接申请相关的XML流及相应的TCP连接.<br />
<br />
:5. 接收服务器向发起服务器声明的那个域建立一个 TCP 连接,作为结果它连接到授权服务器. (注意: 为了优化性能, 在这里一个实现可以(MAY)重用现有的连接.)<br />
<br />
:6. 接收服务器发送一个流头信息给授权服务器:<br />
<br />
<source lang="xml"><br />
<stream:stream xmlns:stream='http://etherx.jabber.org/streams' xmlns='jabber:server' xmlns:db='jabber:server:dialback'><br />
</source><br />
<br />
:注意: 'to'和'from'属性在流的根元素是可选的(OPTIONAL). 如果名字空间不正确,授权服务器必须生成一个<invalid-namespace/>流错误条件并且终止XML流和相应的TCP连接. <br />
<br />
:7. 授权服务器发送流头信息给接收服务器:<br />
<br />
<source lang="xml"><br />
<stream:stream xmlns:stream='http://etherx.jabber.org/streams' xmlns='jabber:server' xmlns:db='jabber:server:dialback' id='1251A342B...'><br />
</source><br />
<br />
:注意: 如果名字空间不正确,接收服务器必须生成一个<invalid-namespace/>流错误条件并且终止它和授权服务器之间的XML流和相应的TCP连接. 如果一个流错误发生在接收服务器和 '''授权服务器''' 之间,接收服务器必须(MUST)生成一个 <remote-connection-failed/> 流错误条件并且终止它和 '''发起服务器''' 之间的XML流和相应的TCP连接.<br />
<br />
:8. 接收服务器发送一个密钥检查请求给授权服务器:<br />
<br />
<source lang="xml"><br />
<db:verify from='Receiving Server' to='Originating Server' id='457F9224A0...'><br />
98AF014EDC0...<br />
</db:verify><br />
</source><br />
<br />
:注意: 现在这里已经有了主机名,第三步中接收服务器发送给发起服务器的ID,第四步中发起服务器发送给接收服务器的密钥. 基于这些信息, 加上授权服务器网络共享的安全信息, 这个密钥被证实了.任何可用于验证的办法都可以(MAY)用于生成密钥. 如果 'to' 地址的值和授权服务器知道的主机名不匹配,授权服务器必须(MUST)生成一个<host-unknown/>流错误条件并且终止XML流和相应的TCP连接. 打开这个连接时,如果 'from' 地址和接收服务器声明的主机名(或任何合法的域,如验证过的接收服务器的子域名或寄宿在接收服务器上的其他经过验证的域)不符,授权服务器必须(MUST)生成一个<invalid-from/>流错误条件并且终止XML流和相应的TCP连接.<br />
<br />
:9. 授权服务器检查密钥是否合法:<br />
<br />
<source lang="xml"><br />
<db:verify from='Originating Server' to='Receiving Server' type='valid' id='457F9224A0...'/><br />
</source><br />
<br />
::或<br />
<br />
<source lang="xml"><br />
<db:verify from='Originating Server' to='Receiving Server' type='invalid' id='457F9224A0...'/><br />
</source><br />
<br />
:注意: 如果 ID 和第三步中接收服务器提供的不符,接收服务器必须(MUST)生成一个<invalid-id/>流错误条件并且终止XML流和相应的TCP连接. 如果 'to' 地址的值和接收服务器知道的主机名不匹配,接收服务器必须(MUST)生成一个<host-unknown/>流错误条件并且终止XML流和相应的TCP连接. 打开这个连接时,如果 'from' 地址和发起服务器声明的主机名(或任何合法的域,如验证过的发起服务器的子域名或寄宿在发起服务器上的其他经过验证的域)不符,接收服务器必须(MUST)生成一个<invalid-from/>流错误条件并且终止XML流和相应的TCP连接. 在返回验证信息给接收服务器之后,授权服务器应该(SHOULD)终止它们之间的流.<br />
<br />
:10. 接收服务器通知发起服务器结果:<br />
<br />
<source lang="xml"><br />
<db:result from='Receiving Server'to='Originating Server' type='valid'/><br />
</source><br />
<br />
:注意: 在这一个点上, 连接已经由 type='valid' 确认验证是通过了,还是没通过. 如果连接是非法的,接收服务器必须(MUST)终止XML流和相应的TCP连接. 如果连接是合法的, 数据可以从发起服务器发送由接收服务器读取;在此之前,所有发送给接收服务器的XML节应该(SHOULD)被丢弃.<br />
<br />
:进一步的结果是,接收服务器已经验证了发起服务器的ID,所以通过初始化流("initial stream",例如从发起服务器到接收服务器的流)发起服务器可以发送,接收服务器可以接受XML节. 为了使用应答流("response stream",例如从接收服务器到发起服务器的流)验证实体ID,回拨必须(MUST)在相对的两个方向上都完成.<br />
<br />
:在成功的回拨协商之后, 接收服务器应该(SHOULD)接受接下来发起服务器通过当前的合法连接发送的 <db:result/> 包 (例如, 发送给子域或其他寄宿在接收服务器上的主机名的验证请求); 这在单一方向上激活了原始合法连接的 "piggybacking" .<br />
<br />
:即使回拨协商成功了, 服务器仍然必须(MUST)检查从其他服务器接收的所有XML节的'from'和'to'属性; 如果一个节不符合这些限定, 收到这些节的服务器必须(MUST)生成一个<improper-addressing/> 流错误条件并终止XML流和相应的TCP连接. 而且, 一个服务器也必须(MUST)检查从其他的有合法域名的服务器的流中收到的节的'from'属性; 如果一个节不符合这一限定, 接收节的服务器必须(MUST)生成一个 <invalid-from/> 流错误条件并终止XML流和相应的TCP连接. 所有这些检查都用来帮助防止特定的节伪造行为.<br />
<br />
==XML节==<br />
<br />
:在 TLS 协商(第五章) (如果想要), SASL 协商(第六章), 和资源绑定(第七章)(如果需要)之后, XML节就可以通过流发送了. 在'jabber:client'和'jabber:server'名字空间中定义了三种XML节: <message/>, <presence/>, 和 <iq/>. 另外, 这三种节有五种通用的属性. 这些通用属性, 加上三种节的术语,在这里定义; 更多关于和即时消息及出席信息应用相关的XML节语法详细信息在[XMPP-IM|XMPP文档列表/XMPP正式RFC标准/RFC3921]中提供.<br />
<br />
===通用属性===<br />
<br />
:以下五种属性通用于 message, presence, 和 IQ 节:<br />
<br />
====to====<br />
<br />
:'to' 属性表示节的预期接收者的JID.<br />
<br />
:在'jabber:client'名字空间中, 一个节应该(SHOULD)处理一个'to'属性, 尽管由服务器处理的从客户端发给服务器的节(如, 发送给服务器用于广播给其他实体的出席信息) 应该不(SHOULD NOT)处理'to'属性.<br />
<br />
:在'jabber:server'名字空间中, 一个节必须(MUST)处理一个'to'属性; 如果一个服务器收到一个不符合此限定的节, 它必须(MUST)生成一个<improper-addressing/>流错误条件并终止和这个非法服务器的XML流和相应的TCP连接.<br />
<br />
:如果'to'属性的值非法或无法联络, 发现这个事实的实体(通常是发送者或接收者的服务器)必须(MUST)返回一个适当的错误给发送者, 错误节的'from'属性设置成非法节的提供的'to'属性的值.<br />
<br />
====from====<br />
<br />
:'from' 属性表示发送者的 JID .<br />
<br />
:当一个服务器接收了一个符合'jabber:client'名字空间的合法流的XML节, 它必须(MUST)做以下步骤中的一步:<br />
<br />
:# 验证客户端提供的'from'属性值就是那个相关实体连接的资源<br />
:# 为生成这个节的已连接的资源增加一个'from'地址(由服务器决定是纯JID或全JID)(参见 地址的决定 Determination of Addresses (第三章第五节))<br />
:# 如果一个客户端试图发送一个XML节,而它的'from'属性和这个实体已连接的资源不符, 服务器应该(SHOULD)返回一个<invalid-from/>流错误条件给客户端. 如果一个客户端试图通过一个尚未验证的流发送一个XML节, 服务器应该(SHOULD)返回一个<not-authorized/>流错误条件给客户端. 如果生成了, 所有这些条件必须(MUST)导致流的关闭和相应的TCP连接的终止; 这有助于防止不诚实的客户的拒绝服务攻击.<br />
<br />
:当一个服务器从服务器自身生成一个节用于一个已连接的客户端的信息发布(例如, 在服务器为客户端提供数据存储服务的情况下), 这个节必须(MUST) (1) 不包含 'from' 属性 或 (2) 包含一个'from'属性,它的值是这个账号的纯 JID (<node@domain>) 或 客户端的全 JID (<node@domain/resource>). 如果节不是由服务器自身生成的,那么一个服务器不能(MUST NOT)发送不带'from'属性的节. 当一个客户端接收到一个不包含'from'属性的节, 它必须(MUST)认为这个节是从客户端连接的服务器发来的.<br />
<br />
:在'jabber:server'名字空间, 一个节必须(MUST)处理一个'from'属性; 如果一个服务器接收到一个不符合此限定的节, 它必须(MUST)生成一个<improper-addressing/>流错误条件. 而且, 'from'属性的 JID值的域名ID部分必须(MUST)和以SASL协商连接或以回拨协商连接的发送服务器的主机名(或任何合法的域,如发送服务器主机名的合法子域,或其他寄宿在发送服务器上的合法域)吻合; 如果一个服务器接收到的节不符合此限定, 它必须(MUST)生成一个<invalid-from/>流错误条件. 所有这些条件都必须(MUST)导致流的关闭和相应的TCP连接的终止; 这有助于防止不诚实的客户端发起的拒绝服务攻击.<br />
<br />
====id====<br />
<br />
:可选的'id' 属性可以(MAY)用于为节的内部跟踪发送实体,从IQ节 语义来讲,就是通过发送和接收这些节来跟踪“请求-应答”型的交互行为。这个可选的(OPTIONAL)'id'属性值在一个域或一个流中是全局唯一的。IQ节语义学中对此有附加限定;见IQ Semantics (第九章第二节第三小节)。<br />
<br />
====type====<br />
<br />
:'type' 属性指明消息、出席信息或IQ节的意图或上下文的详细信息。'type'属性所允许的值依据节的类型是消息、出席信息还是IQ而有很大不同; 用于消息和出席信息节的值定义在即时消息和出席信息应用中,所以在[XMPP-IM|XMPP文档列表/XMPP正式RFC标准/RFC3921]中定义,反之用于IQ节的值定义了在一个 请求\-应答 的“会话”中IQ节的角色,所以定义在IQ语义学中(第九章第二节第三小节)。 所有三种节的通用'type'值是"error";见Stanza Errors (第九章第三节)。<br />
<br />
====xml:lang====<br />
<br />
:如果一个节包含用于显示给人human user看的XML字符数据(在RFC 2277中有所解释\[CHARSET\],"internationalization is for humans"),这个节应该(SHOULD)处理一个'xml:lang'属性(定义在第二章第十二节\[XML\])。 'xml:lang'属性的值指明任何一个人类可读的XML字符数据的缺省语言, 它可以(MAY)被特定的子元素的'xml:lang'值重载。 如果一个节不处理一个'xml:lang'属性,一个实现必须(MUST)认为缺省的语言就是流属性中定义的语言(第四章第四节). 'xml:lang'属性值必须(MUST)是一个 NMTOKEN 并且必须(MUST)遵守 RFC 3066 \[LANGTAGS\]中定义的格式. <br />
<br />
===基本语义学===<br />
<br />
====消息语义学====<br />
<br />
:<message/>节类型可以被看作是一个"push"机制用于一个实体推送信息给另一个实体,类似发生在email系统中的通信. 所有消息节应该(SHOULD)处理一个表明预定的消息接收者的'to'属性;接收了这样一个节之后,一个服务器应该(SHOULD)路由或递送它给预定的接收者(见 Server Rules for Handling XML Stanzas (第十章)的XML节相关的通用路由和递送规则).<br />
<br />
====出席信息语义学====<br />
<br />
:<presence/> 元素可以被看作一个基本的广播或“出版-订阅”机制,用于多个实体接收某个已订阅的实体的信息(在这里,是网络可用性信息). 通常,一个发行实体应该(SHOULD)不带'to'属性发送一个出席信息,这时这个实体所连接的服务器应该(SHOULD)广播或多播(multiplex?)那个节给所有订阅的实体.无论如何,一个发行实体也可以(MAY)带'to'属性发送一个出席信息节,这时服务器应该(SHOULD)路由或递送这个节给预定的接收者.见 Server Rules for Handling XML Stanzas (第十章)的XML节相关的通用路由和递送规则,以及[XMPP-IM|XMPP文档列表/XMPP正式RFC标准/RFC3921]中即时消息和出席信息应用中出席信息的特定规则.<br />
<br />
====IQ语义学====<br />
<br />
:信息/查询(Info/Query),或曰IQ,是一个 请求-回应 机制,某些情况下类似\[HTTP\].IQ语义学使一个实体能够向另一个实体做出请求并做出应答. 请求和应答所包含的数据定义在IQ元素的一个直接的子元素的名字空间声明中, 并且由请求实体用'id'属性来跟踪这一交互行为. 因而,IQ交互伴随着一个结构化的数据交换的通用模式例如 get/result 或 set/result (尽管有时候会以一个错误信息应答某个请求):<br />
<br />
:以下是IQ的流程图,参见附件iq.png<br />
<br />
{image:img=iq}<br />
<br />
:为了强制执行这些语义学,要应用以下规则:<br />
<br />
:1. 对于IQ节来说'id'属性是必需的(REQUIRED).<br />
:2. 对于IQ节来说'type'属性是必需的(REQUIRED). 它的值必须(MUST)是以下之一:<br />
::* get -- 这个节是一个对信息或需求的请求.<br />
::* set -- 这个节提供需要的数据, 设置新的值, 或取代现有的值.<br />
::* result -- 这个节是一个对一个成功的 get 或 set 请求的应答.<br />
::* error -- 发生了一个错误,关于处理或递送上次发送的 get 或 set的(参见 节错误 Stanza Errors(第九章第三节)).<br />
:3. 一个接收到"get" 或 "set" 类型的IQ请求的实体必须(MUST)回复一个"result"或"error"类型的IQ应答(这个应答必须(MUST)保留相关请求的'id'属性).<br />
:4. 一个接收到"result"或"error"类型的IQ节的实体不能(MUST NOT)再发送更多的"result"或"error"类型的IQ应答; 无论如何, 如上所述, 请求实体可以(MAY)发送另一个请求(如, 一个"set"类型的IQ,通过get/result对提供查询(discovery)所需的信息).<br />
:5. 一个"get" 或 "set" 类型的IQ节必须(MUST)包含并只包含一个子元素指明特定请求或应答的语义.<br />
:6. 一个"result"类型的IQ节必须(MUST)包含零或一个子元素.<br />
:7. 一个"error"类型的IQ节应该(SHOULD)包含和"get"或"set"相关联的那个子元素并且必须(MUST)包含一个<error/>子元素;详细信息,见Stanza Errors (第九章第三节).<br />
<br />
===节错误===<br />
<br />
:节相关的错误的处理方式类似流错误(第四章第七节). 无论如何, 不像流错误, 节错误是可恢复的;所以错误节包含了暗示原来的发送者可以采取什么行动来补救这个错误.<br />
<br />
====规则====<br />
<br />
:以下规则适用于节相关的错误:<br />
<br />
:* 接收或处理实体察觉到一个节相关的错误条件时应该(MUST)返回给发送实体一个同类型的节(消息,出席信息,或IQ),这个节的'type'属性值则设置为"error"(这里这样的节称之为"error stanza").<br />
<br />
:* 生成一个错误节的实体应该(SHOULD)包含原来发送的XML,这样发送者可以检查它,并且如果必要,在尝试重新发送之前纠正它.<br />
<br />
:* 一个错误节必须(MUST)包含一个<error/>子元素.<br />
<br />
:* 如果'type'属性值不是"error"(或没有"type"属性),节不能(MUST NOT)包含一个<error/>子元素.<br />
<br />
:* 接收到一个错误节的实体不能(MUST NOT)应答这个节更多的错误节; 这有助于防止死循环.<br />
<br />
====语法====<br />
<br />
:节相关错误的语法如下:<br />
<br />
<source lang="xml"><br />
<stanza-kind to='sender' type='error'><br />
[RECOMMENDED to include sender XML here]<br />
<error type='error-type'><br />
<defined-condition xmlns='urn:ietf:params:xml:ns:xmpp-stanzas'/><br />
<text xmlns='urn:ietf:params:xml:ns:xmpp-stanzas' xml:lang='langcode'><br />
OPTIONAL descriptive text<br />
</text><br />
[OPTIONAL application-specific condition element]<br />
</error><br />
</stanza-kind><br />
</source><br />
<br />
:stanza-kind 是 message, presence, 或 iq 中的一个.<br />
<br />
:<error/> 元素的'type'属性值必须(MUST)是以下之一:<br />
<br />
:* cancel \-\- 不重试(这个错误是不可恢复的)<br />
<br />
:* continue \-\- 继续进行(这个条件只是一个警告)<br />
<br />
:* modify \-\- 改变数据之后重试<br />
<br />
:* auth \-\- 提供证书之后重试<br />
<br />
:* wait \-\- 等待之后重试(错误是暂时的)<br />
<br />
:<error/>元素:<br />
<br />
:* 必须(MUST)包含一个子元素,符合以下定义的节错误条件之一;这个元素(MUST)符合'urn:ietf:params:xml:ns:xmpp-stanzas'名字空间.<br />
<br />
:* 可以(MAY)包含一个<text/>子元素容纳XML字符数据用来描述错误的更多细节;这个元素必须(MUST)符合'urn:ietf:params:xml:ns:xmpp-stanzas'名字空间并且应该(SHOULD)处理'xml:lang'属性.<br />
<br />
:* 可以(MAY)包含一个应用程序定义的错误条件子元素;这个元素必须(MUST)符合一个应用程序定义的名字空间,并且它的结构由这个名字空间定义.<br />
<br />
:<text/>元素是可选的(OPTIONAL).如果包含它,它应该(SHOULD)仅用于提供描述或诊断信息以补充一个已定义的条件或应用程序定义的条件. 它不应(SHOULD NOT)被应用程序认为是一个程序性的. 它不应(SHOULD NOT)被用作向一个使用者展示的错误信息,但是可以(MAY)展示除条件元素(或元素们)相关的错误信息之外的信息.<br />
<br />
:最后,为了维护向后兼容性, 这个schema (定义在[XMPP-IM|XMPP文档列表/XMPP正式RFC标准/RFC3921])允许可选的在<error/>元素中包含一个("code")属性.<br />
<br />
====已定义的条件====<br />
<br />
:以下条件定义用于节错误.<br />
<br />
:* <bad-request/> -- 发送者发送的XML是不规范的或不能被处理(例如 一个IQ节包含了一个未被承认的'type'属性值); 相关的错误类型应该(SHOULD)是"modify".<br />
<br />
:* <conflict/> -- 不同意访问,因为相同的名字或地址已存在一个资源或会话;相关的错误类型应该( SHOULD)是"cancel".<br />
<br />
:* <feature-not-implemented/> -- 请求的特性未被接收者或服务器实现所以不能处理;相关的错误类型应该(SHOULD)是"cancel".<br />
<br />
:* <forbidden/> -- 请求实体没有必需的许可来执行这一动作;相关的错误类型应该(SHOULD)是"auth".<br />
<br />
:* <gone/> -- 接收者或服务器无法再以这个地址进行联系(错误节可以(MAY)在<gone/>元素的XML字符数据中包含一个新的地址);相关的错误类型应该(SHOULD)是"modify".<br />
<br />
:* <internal-server-error/> -- 服务器不能处理节,因为错误的配置或其他未定义的内部服务器错误;相关的错误类型应该(SHOULD)是"wait".<br />
<br />
:* <item-not-found/> -- JID地址或申请的条目无法找到;相关的错误类型应该(SHOULD)是"cancel".<br />
<br />
:* <jid-malformed/> -- 发送的实体提供的XMPP地址或与之通信的某个XMPP地址(如一个'to'属性值)或这个XMPP地址中的一部分(如一个资源ID)不符合寻址方案的语法(第三章);相关的错误类型应该(SHOULD)是"modify".<br />
<br />
:* <not-acceptable/> -- 接收者或服务器理解这个请求但是拒绝处理,因为它不符合某些接收者或服务器定义的标准(例如,一个关于消息中可接收的单词的本地策略);相关错误类型应该(SHOULD)是"modify".<br />
<br />
:* <not-allowed/> -- 接收者或服务器不允许任何实体执行这个动作;相关错误类型应该(SHOULD)是"cancel".<br />
<br />
:* <not-authorized/> -- 在被允许执行某个动作之前发送者必须提供适当的证书,或已提供了不正确的证书;相关错误类型应该(SHOULD)是"auth".<br />
<br />
:* <payment-required/> -- 请求实体未被授权访问请求的服务,因为需要付费;相关错误类型应该(SHOULD)是"auth".<br />
<br />
:* <recipient-unavailable/> -- 预定的接收者暂时不可用;相关错误类型应该(SHOULD)是"wait"(注意: 如果这样做会导致泄露预定接收者的网络可用性给一个未被授权了解此信息的实体,应用程序不应该(MUST NOT)返回这个错误).<br />
<br />
:* <redirect/> -- 接收者或服务器重定向这个请求信息到另一个实体,通常是暂时的(这个错误节应该 (SHOULD)在<redirect/>元素的XML字符数据中包含一个预备的地址,它必须(MUST)是一个合法的JID); 相关的错误类型应该(SHOULD)是"modify".<br />
<br />
:* <registration-required/> -- 请求实体未被授权访问请求的服务,因为需要注册;相关错误类型应该(SHOULD)是"auth".<br />
<br />
:* <remote-server-not-found/> -- 在预定的接收者的全部或部分JID中的一个远程服务器或服务不存在;相关错误类型应该(SHOULD)是"cancel".<br />
<br />
:* <remote-server-timeout/> -- 在预定的接收者(或需要完成的一个申请)的全部或部分JID中的一个远程服务器或服务无法在合理的时间内联系到;相关错误类型应该(SHOULD)是"wait".<br />
<br />
:* <resource-constraint/> -- 服务器或接收者缺乏足够的系统资源来服务请求;相关错误类型应该(SHOULD)是"wait".<br />
<br />
:* <service-unavailable/> -- 服务器或接收者目前无法提供被请求的服务;相关错误类型应该(SHOULD)是"cancel".<br />
<br />
:* <subscription-required/> -- 请求实体未被授权访问能请求的服务,因为需要订阅;相关错误类型应该(SHOULD)是"auth".<br />
<br />
:* <undefined-condition/> -- 错误条件不是本列表中定于的其他条件之一;任何错误类型可能和这个条件有关,并且它应该(SHOULD)仅用于关联一个应用程序定义的条件.<br />
<br />
:* <unexpected-request/> -- 接收者或服务器理解这个请求但是不希望是在这个时间(比如,请求的顺序颠倒);相关错误类型应该(SHOULD)是"wait".<br />
<br />
====应用程序定义条件====<br />
<br />
:大家知道,一个应用程序可以(MAY)通过在错误元素里包含一个适当名字空间的字元素来提供应用程序定义的节错误信息. 应用程序定义的元素应该(SHOULD)补充或进一步限定一个已定义的元素. 因而,<error/>元素将包含两个或三个子元素:<br />
<br />
<source lang="xml"><br />
<iq type='error' id='some-id'><br />
<error type='modify'><br />
<bad-request xmlns='urn:ietf:params:xml:ns:xmpp-stanzas'/><br />
<too-many-parameters xmlns='application-ns'/><br />
</error><br />
</iq><br />
<message type='error' id='another-id'><br />
<error type='modify'><br />
<undefined-condition xmlns='urn:ietf:params:xml:ns:xmpp-stanzas'/><br />
<text xml:lang='en' xmlns='urn:ietf:params:xml:ns:xmpp-stanzas'><br />
Some special application diagnostic information...<br />
</text><br />
<special-application-condition xmlns='application-ns'/><br />
</error><br />
</message><br />
</source><br />
<br />
==服务器处理XML节的规则==<br />
<br />
:兼容的服务器实现必须(MUST)确保两个实体之间的XML节按次序处理.<br />
<br />
:在按次序处理的需求之外, 每个服务器实现将包含它自己的递送树"delivery tree"以处理它接收到的节.这个树决定一个节是否需要路由到其他域, 在内部处理, 还是递送到和一个已连接的节点相关的资源. 以下规则适用:<br />
<br />
===没有'to'地址===<br />
<br />
:如果这个节没有'to'属性, 服务器应该(SHOULD)为发送它的实体处理这个节. 因为所有从其他服务器收到的节必须(MUST)拥有'to'属性, 这个规则仅适用于从一个连接到这台服务器的已注册实体(如一个客户端)收到的节.如果这个服务器收到一个没有'to'属性的出席信息节, 服务器应该(SHOULD)向那些订阅了这个发送实体的出席信息的所有实体广播它, 如果可能的话(即时消息和出席信息应用程序中出席信息广播的语义定义在[XMPP-IM|XMPP文档列表/XMPP正式RFC标准/RFC3921]). 如果服务器接收到一个类型为"get" 或 "set" 的没有'to'属性的节并且它理解这个节的名字空间下的内容, 它必须(MUST)为这个发送实体处理节(在这里"process"的含义是由相关的名字空间的语义所决定的)或返回一个错误给发送实体.<br />
<br />
===外部域===<br />
<br />
:如果'to'属性中的JID的域ID部分的主机名和服务器自身或其子域配置的主机名不匹配, 服务器应该(SHOULD)路由这个节到外部域(取决于本地服务规定或安全策略关于域间通信的规定).有两种可能的情况:<br />
<br />
::- 一个服务器之间的流已经存在于两个域之间: 发送者的服务器通过这个已存在的流为这个外部域路由这个节到授权服务器<br />
<br />
::- 两个域之间不存在服务器间的流: 发送者服务器 (1) 解析这个外部域的主机名(定义在服务器间的通信Server-to-Server Communications (第十四章第四节)), (2) 在两个域之间进行服务器到服务器的流协商(定义在 Use of TLS (第五章) 和 Use of SASL (第六章)), 然后 (3) 通过这个新建的流为外部域路由这个节到授权服务器<br />
<br />
:如果路由到接收者的服务器不成功, 发送者的服务器必须(MUST)返回一个错误给发送者; 如果接收者的服务器联系上了但是从接收者的服务器递送到接收者不成功, 接收者服务器必须(MUST)通过发送者的服务器返回一个错误给发送者.<br />
<br />
===子域===<br />
<br />
:如果'to'属性中的JID的域ID部分的主机名和服务器自身配置的主机名的一个子域名匹配,服务器必须(MUST)自己处理这个节或路由这个节到专门负责这个子域的特定服务(如果子域被配置了),或者返回一个错误给发送者(如果子域没有配置).<br />
<br />
===纯粹的域或特定的资源===<br />
<br />
:如果'to'属性中的JID的域ID部分的主机名和服务器自身配置的主机名本身匹配,并且'to'属性中的JID类型是<domain> 或 <domain/resource>, 服务器(或其中定于的资源)必须(MUST)根据节的类型适当的处理这个节或返回一个错误节给发送者.<br />
<br />
===同一域中的节点===<br />
<br />
:如果'to'属性中的JID的域ID部分的主机名和服务器自身配置的主机名本身匹配,并且'to'属性中的JID类型是<node@domain> 或 <node@domain/resource>, 服务器应该(SHOULD)递送这个节到节的'to'属性中的JID所指明的预定的接收者. 以下规则适用:<br />
<br />
:# 如果这个JID包含一个资源ID(例如, 格式是<node@domain/resource>)并且存在一个连接的资源符合这个全JID, 接收者服务器应该(SHOULD)递送这个节给正确符合这个资源ID的流或会话.<br />
:# 如果这个JID包含一个资源ID(例如, 格式是<node@domain/resource>)并且不存在一个连接的资源符合这个全JID, 接收者服务器应该(SHOULD)返回一个<service-unavailable/> 节错误给发送者.<br />
:# 如果这个JID的格式是<node@domain>并且存在至少一个此节点的连接资源, 接收服务器应该( SHOULD)递送这个节给至少其中一个已连接的资源, 依据应用程序定义的规则(一系列即时消息和出席信息应用程序的递送规则定义在[XMPP-IM|XMPP文档列表/XMPP正式RFC标准/RFC3921]).<br />
<br />
==XMPP中的XML用法==<br />
<br />
===限制===<br />
<br />
:XMPP是一个简单的流式XML元素的专用协议用于接近实时地交换结构化信息. 因为XMPP不需要任意的解析和所有的XML文档, 所以XMPP不需要支持\[XML\]的所有功能. 特殊的, 适用以下限制.<br />
<br />
:关于XML生成, 一个XMPP实现不能(MUST NOT)在XML流中注入以下任何东西:<br />
<br />
:* 注释 (第二章第五节[XML])<br />
<br />
:* 处理指示(第二章第六节 同上)<br />
<br />
:* 内部或外部的 DTD 子集 (第二章第八节 同上)<br />
<br />
:* 内部或外部的实体参考 (第四章第二节 同上) 除了预定实体以外(第四章第六节 同上)<br />
<br />
:* 字符数据或属性值包含和预定实体列表中吻合的未逃逸的unescaped字符(第四章第六节 同上); 这些字符必须(MUST)逃逸<br />
<br />
:关于XML处理, 如果一个XMPP实现接收到这些受限的XML数据,它必须(MUST)忽略这些数据.<br />
<br />
===XML 名字空间的名字和前缀===<br />
<br />
:XML名字空间\[XML-NAMES\]为所有XMPP兼容的XML建立数据所有权的严格界限. 这个名字空间的基本功能是把结构上混合在一起的XML元素区分出不同的词汇. 确保XMPP兼容的XML有名字空间的感知能力使得任何允许的XML可以被结构化的混合到任何XMPP数据元素中. XML名字空间的名字和前缀的规则在下一小节中.<br />
<br />
====流名字空间====<br />
<br />
:在所有的XML流头中必须声明一个流名字空间. 流名字空间必须(MUST)是 'http://etherx.jabber.org/streams'. 元素名<stream/>和它的<features/>和<error/>子元素必须(MUST)在所有实例中符合这个流名字空间前缀. 一个实现应该(SHOULD)只为这些元素生成'stream:'前缀, 并且由于历史原因可以(MAY)只接受'stream:'前缀.<br />
<br />
====缺省名字空间====<br />
<br />
:在所有的XML流中必须声明一个缺省的流名字空间用于定义允许的流根元素的一级子元素. 这个名字空间声明对于初始化流和应答流必须(MUST)是相同的使得双方的流都是合格一致的. 缺省的名字空间声明适用于流和所有在流中发送的节(除非由流名字空间或回拨名字空间的前缀显式的符合另一个名字空间).<br />
<br />
:一个服务器实现必须(MUST)支持以下两个缺省名字空间(由于历史原因, 一些实现可能(MAY)只支持这两个缺省名字空间):<br />
<br />
:* jabber:client -- 当流用于客户端和服务器的通信时声明这个缺省名字空间<br />
<br />
:* jabber:server -- 当流用于两个服务器间的通信时声明这个缺省名字空间<br />
<br />
:一个客户端实现必须(MUST)支持'jabber:client'缺省名字空间,并且由于历史原因可以(MAY)只支持这个缺省名字空间.<br />
<br />
:如果缺省名字空间是'jabber:client'或'jabber:server',一个实施不能(MUST NOT)在这个名字空间下为元素生成名字空间前缀. 一个实现不应该(SHOULD NOT)按照元素的内容(可能和流相反)生成不同于'jabber:client'和'jabber:server'名字空间前缀.<br />
<br />
:注意: 'jabber:client' 和 'jabber:server' 名字空间接近于相同但是用于不同的上下文(客户端服务器通信用'jabber:client' 而服务器间通信用'jabber:server'). 这两者之间仅有的不同在于在'jabber:client'中被发送的节中'to'和'from'属性是可选的(OPTIONAL),而在'jabber:server'中被发送的节中它们是必需的(REQUIRED). 如果兼容的实施接受一个符合'jabber:client'或'jabber:server'名字空间的流, 它必须(MUST)支持通用属性(第九章第一节)和三个核心节类型(message, presence, 和IQ)的基本语义(第九章第二节).<br />
<br />
====回拨名字空间====<br />
<br />
:所有用于服务器回拨的(第八章)元素都必须声明一个回拨名字空间. 回拨名字空间的名字必须(MUST)是'jabber:server:dialback'. 所有符合此名字空间的元素必须(MUST)有前缀. 一个实现应该(SHOULD)只为这些元素生成'db:'前缀并且只可以(MAY)接受'db:'前缀.<br />
<br />
===确认===<br />
<br />
:除了注意'jabber:server'名字空间中关于节中'to'和'from'地址的规定,一个服务器不需要为转发到客户端或其他服务器负责检查XML元素;一个实现可以(MAY)选择仅提供有效数据元素但这是可选的(OPTIONAL)(尽管一个实现不能(MUST NOT)接受不规范的XML). 客户端不应该(SHOULD NOT)滥用发送不符合schema的数据的能力, 并且应该(SHOULD)忽略接收到的XML流中任何和schema不一致的元素或属性值. XML流和节的有效性确认是可选的(OPTIONAL),并且在这里提到的schemas仅用于描述的用途.<br />
<br />
===文本声明的包含===<br />
<br />
:实现应该(SHOULD)在发送一个流头信息之前发送一个文本声明. 应用程序必须(MUST)遵守\[XML\]中关于环境(那里对文本声明做了规定)的规则.<br />
<br />
===字符编码===<br />
<br />
:实现必须(MUST)支持通用字符集Universal Character Set (ISO/IEC 10646-1 \[UCS2\])字符到UTF\-8(RFC 3629 \[UTF\-8\])的转换, 必须符合 RFC 2277 \[CHARSET\]. 实现不能(MUST NOT)试图使用任何其他的编码.<br />
<br />
==核心的兼容性要求==<br />
<br />
:本章总结了可扩展的消息和出席信息协议中的某些方面,为了实施的兼容性,它们必须(MUST)被服务器和客户端支持,当然协议的其他方面也应该(SHOULD)被支持. 为了兼容的目的, 我们在核心协议(它必须(MUST)被任何服务器或客户端支持, 无论是什么特定的应用)和即时消息协议(仅仅是在核心协议之上的即时消息和出席信息应用必须(MUST)支持它)之间划了一个级别. 在本章中定义了所有服务器和客户端的兼容性要求; 即时消息服务器和客户端的兼容性要求在[XMPP-IM|XMPP文档列表/XMPP正式RFC标准/RFC3921]的相关章节中定义.<br />
<br />
===服务器===<br />
<br />
:除了所有已定义的关于安全, XML使用, 和国际化的要求之外, 一个服务器还必须(MUST)支持以下核心协议以保证兼容性:<br />
<br />
:* 在地址中应用\[STRINGPREP\] 的 \[NAMEPREP\], Nodeprep (附录 A),和 Resourceprep (附录 B) profiles (包括确保域ID是\[IDNA\]中定义的国际化域名)<br />
<br />
:* XML流(第四章), 包括Use of TLS(第五章), Use of SASL(第六章), 和Resource Binding (第七章)<br />
<br />
:* 三个在stanza semantics(第九章第二节)中已定义的节类型(即,<message/>, <presence/>, 和<iq/>)的基本语义<br />
<br />
:* 生成错误的语法及相关的流, TLS, SASL, 和 XML节的语义<br />
<br />
:另外, 一个服务器可以(MAY)支持以下核心协议:<br />
<br />
:* 服务器回拨 (第八章)<br />
<br />
===客户端===<br />
<br />
:一个客户端必须(MUST)支持以下核心协议以满足兼容性:<br />
<br />
:* XML流(第四章), 包括Use of TLS(第五章), Use of SASL(第六章), 和Resource Binding (第七章)<br />
<br />
:* 三个在stanza semantics(第九章第二节)中已定义的节类型(即,<message/>, <presence/>, 和<iq/>)的基本语义<br />
<br />
:* 处理(并且, 如果可能, 生成) 错误的语法及相关的流, TLS, SASL, 和 XML节的语义<br />
<br />
:另外, 一个客户端应该(SHOULD)支持以下核心协议:<br />
<br />
:* 地址的生成应用\[STRINGPREP\] 的 \[NAMEPREP\], Nodeprep (附录 A),和 Resourceprep (附录 B) profiles <br />
<br />
==国际化事项==<br />
<br />
:XML流在Character Encoding(第十一章第五节)中定义为必须(MUST)被编码成UTF\-8. 在Stream Attributes(第四章第四节)中特别定义了, 一个XML流应该(SHOULD)包含一个'xml:lang'属性,它被认为是通过这个用于人类用户解读的流发送的任何XML字符数据的缺省语言. 在 xml:lang (第九章第一节第五小节)特别定义了, 如果一个XML节是用来给人类用户解读,这个节应该(SHOULD)包含一个'xml:lang'属性. 服务器在为连接的实体路由或递送节的时候应该(SHOULD)应用缺省的'xml:lang'属性, 并且不能(MUST NOT)修改或删除它从其他实体收到的节的'xml:lang'属性.<br />
<br />
==安全性事项==<br />
<br />
===高安全性===<br />
<br />
:为了XMPP通信的目的(客户端-服务器 和 服务器-服务器), "高安全性"条款谈的是相互验证和完整性检查安全性技术的使用; 特别是, 当使用基于证书的验证来提供高安全性, 应该( SHOULD)建立一个带外的信任链,尽管一个共享签名证书可能允许以前不知道的证书在带内建立信任关系. 参见以下第十四章第二节关于证书确认程序.<br />
<br />
:实施必须(MUST)支持高安全性. 服务提供者应该(SHOULD)基于本地安全策略使用高安全性.<br />
<br />
===证书确认===<br />
<br />
:当一个XMPP点和另一个XMPP点安全的地通信, 它必须(MUST)确认对方终端的证书.有三种可能的情况:<br />
<br />
:情形 #1: 点包含一个终端实体证书,以根证书的证书链中一环出现(见\[X509\]中的第六章第一节).<br />
<br />
:情形 #2: 点的证书由一个对方不知道的证书授权.<br />
<br />
:情形 #3: 点的证书由自己签名.<br />
<br />
:在情形#1, 确认方必须(MUST)做以下两条之一:<br />
<br />
:# 根据\[X509\]的规则确认对方证书.然后证书应该(SHOULD)被对方接下来在\[HTTP-TLS\]中描述的规则反向确认预期的身份。但如果"xmpp"是subjectAltName扩展类型,则必须(MUST)使用证书中的显示的身份。如果这两项检查之一失败,用户导向的客户端必须(MUST)通知用户(客户端可以(MAY)给用户机会继续连接)或以一个坏证书的错误终止连接。自动客户端应该(SHOULD)终止连接(以一个坏证书错误)并在适当的日志中记录这个错误。自动客户端可以(MAY)提供一个配置设置成禁止检查,但同时必须(MUST)提供一个激活检查的配置。<br />
:# 点应该(SHOULD)出示证书给一个用户用于批准,包括完整的证书链.点必须(MUST)缓存这个证书(或一些其他不会忘记的表达方式比如一个哈希值).在将来的连接中,点必须(MUST)展示相同的证书并且如果改变了证书必须(MUST)通知用户.<br />
<br />
:在情形#2 和情形#3, 实现应该(SHOULD)执行上述第二条.<br />
<br />
===客户端-服务器通信===<br />
<br />
:一个兼容的客户端实现必须(MUST)支持TLS和SASL用于连接到服务器.<br />
<br />
:用于加密XML流的TLS协议(在 Use of TLS(第五章)定义)提供可信的机制帮助确保机密性和实体之间数据交换的完整性.<br />
<br />
:用于验证XML流的SASL协议(在 Use of SASL(第六章)定义)提供可靠的机制用于确认一个连接到服务器的客户端确实是它自己所声明的那个客户端.<br />
<br />
:服务器宣称的DNS主机名被解析之前,客户端-服务器通信不能(MUST NOT)继续进行。应该首先尝试解析\[SRV\]记录,其服务名为"xmpp-client",协议名为"tcp",整个资源记录类似"_xmpp-client._tcp.example.com."(使用字符"xmpp-client"表示服务ID是经过IANA注册).如果SRV查找失败,退而求其次,将查找一个正规的IPv4/IPv6地址记录来决定IP地址,使用"xmpp-client"端口5222,这个端口是在IANA注册了的。<br />
<br />
:客户端的IP地址和访问方法不能(MUST NOT)被服务器公开, 也不能被被任何原始服务器之外的服务器索取。这帮助保护客户端的服务器避免受到直接攻击(译者注:似乎应该是客户避免受到直接攻击,但原文如此)或被第三方知道它的身份。<br />
<br />
===服务器-服务器通信===<br />
<br />
:一个兼容的服务器实现必须(MUST)支持TLS和SASL,用于域间的通信.因为历史原因,一个兼容的实施也应该(SHOULD)支持服务器回拨(第八章).<br />
<br />
:因为服务提供者是一个策略问题,对于任何给定域和其他域的通信中,它是可选的(OPTIONAL),服务器之间的通信可以(MAY)被任何特定部署的管理员禁止。如果一个特殊的域允许域间的通信,它应该(SHOULD)允许高安全性。<br />
<br />
:管理员可能想在服务器间使用SASL来通信,以确保双方的验证和保密性(比如在机构的私有网络).兼容实施应该(SHOULD)为这个目的支持SASL.<br />
<br />
:服务器宣称的DNS主机名被解析之前,服务器-服务器通信不能(MUST NOT)继续进行。应该首先尝试解析\[SRV\]记录,其服务名为"xmpp-server",协议名为"tcp",整个资源记录类似"_xmpp-server._tcp.example.com."(使用字符"xmpp-server"表示服务ID是经过IANA注册的,注意要用"xmpp-server"取代以前用的"jabber",因为以前的用法不符合[SRV]标准;希望保持向后兼容的实现可以继续查找或应答"jabber"服务ID).如果SRV查找失败,退而求其次,将查找一个正规的IPv4/IPv6地址记录来决定IP地址,使用"xmpp-server"端口5269,这个端口是在IANA注册了的。<br />
<br />
:服务器回拨防止域欺骗,从而使得伪造XML节更为困难.它和SASL和TLS不一样,它不是一个用于验证、安全或加密服务器之间的流的机制, 所以只是服务器身份的微弱确认而已。而且除非它使用了DNSSec \[DNSSEC\]否则它 容易受到DNS中毒攻击,即使DNS信息是正确的,如果攻击者劫持了远程域,回拨也不能防止它的攻击.需要健壮的安全性的域应该(SHOULD)使用TLS和SASL.如果服务器间的验证使用了SASL,回拨就不应该(SHOULD NOT)使用了,因为它是多余的.<br />
<br />
===层的次序===<br />
<br />
:协议中的层的次序必须(MUST)如下堆积:<br />
<br />
:# TCP<br />
:# TLS<br />
:# SASL<br />
:# XMPP<br />
<br />
:这个次序的原理是,[TCP]是基于连接的层,被所有使用,所以处于最上层, [TLS]经常是由操作系统层提供,[SASL]经常由应用程序层提供, XMPP则是应用程序本身.<br />
<br />
===缺乏绑定到TLS的SASL通道===<br />
<br />
:SASL构架不提供一个机制来绑定SASL验证到一个提供机密性和完整性保护的安全层。这一通道绑定"channel binding"的缺乏阻碍了SASL确认低层安全性所绑定的源和目标终端和SASL所验证的结果是否一致。如果终端不一致, 低层安全性不能被信任用来保护SASL验证的实体之间的数据传输。在这种情况下,一个SASL安全层进行握手的时候应该有效的忽略低层安全性的存在。<br />
<br />
===强制实现的技术===<br />
<br />
:最低要求, 所有实现必须(MUST)支持以下机制:<br />
<br />
::对于验证: SASL [DIGEST-MD5] 机制<br />
<br />
::对于机密性: TLS (使用 TLS_RSA_WITH_3DES_EDE_CBC_SHA 密码)<br />
<br />
::对于两者: TLS 加 SASL EXTERNAL(使用 TLS_RSA_WITH_3DES_EDE_CBC_SHA 密码支持客户端证书)<br />
<br />
===防火墙===<br />
<br />
:使用XMPP通信通常是通过\[TCP\]连接到5222端口(客户端-服务器)或5269端口(服务器-服务器), 正如在IANA注册的那样(见 IANA Considerations (第十五章)). 使用这些广为人知的端口允许管理员很容易的通过一般的防火墙来激活或禁止XMPP活动.<br />
<br />
===在SASL中使用base64===<br />
<br />
:客户端和服务器都必须(MUST)确认在SASL协商中收到的任何\[BASE64\]数据. 一个实现必须(MUST)拒绝(不是忽略)任何非显式允许base64字母的字符串; 这有助于预防建立隐蔽通道泄漏信息的行为。一个实现不能(MUST NOT)在非法输入处中断,如果那个('=')被包含在一些和最后的数据字符(如, "=AAA" or "BBBB=CCC")不同的东西里面,必须(MUST)拒绝接下来的任何包含('=')的base64字符;这有助于防止对这个实现的缓存溢出攻击和其他攻击。Base 64编码从外表看隐藏了容易辨认的信息,例如密码,但是不提供任何算法机密性。Base 64编码必须(MUST)按照RFC 3548\[BASE64\]第三章的定义执行。<br />
<br />
===Stringprep Profiles===<br />
<br />
:为了处理域ID,XMPP使用了\[STRINGPREP\]中的\[NAMEPREP\] profile; 和Nameprep有关的安全性考虑, 参考\[NAMEPREP\]中的相关章节.<br />
<br />
:另外, XMPP 定义了两个\[STRINGPREP\]的 profiles: 用于node identifiers的Nodeprep(附录 A)和用于resource identifiers的Resourceprep(附录 B).<br />
<br />
:Unicode 和 ISO/IEC 10646 集有许多字符看起来相似. 在许多时候, 安全协议的使用者可能看起来吻合,比如当比较信任的第三方的名字的时候. 因为没有很多上下文的时候不可能映射看起来相似的字符,比如知道所用的字符集, stringprep不匹配相似字符串,也不因为一些字符串象看起来象别的字符串而禁止它们.<br />
<br />
:一个节点ID可能被作为一个实体的XMPP地址的一部分. 一个通常的用途是作为一个即时消息用户的用户名;另一个用途是作为一个多用途聊天室的名字; 很多其他种类的实体可能使用节点ID作为他们的地址的一部分。 这些服务的安全性可能会受到国际化节点ID的不同表达的威胁;例如, 一个用户键入一个单独的国际化的节点ID可能访问了另一个用户的帐号信息, 或一个用户可能获得访问一个受限的聊天室或服务的访问权限.<br />
<br />
:一个资源ID可能被作为一个实体的XMPP地址的一部分。一个通常的用户是即时消息用户所连接的资源(激活的会话)的名字; 另一个是作为多用户聊天室的某用户的昵称; 许多其他种类的实体可能使用资源ID作为他们地址的一部分.这些服务的安全性可能会受到国际化资源ID的不同表达的威胁;例如, 一个用户可能尝试以同一个名字初始化多个会话,或一个用户可能发送一个消息给多用户聊天室的一个人但实际上发给了另外一个人.<br />
<br />
==IANA 事项==<br />
<br />
===用于TLS数据的XML名字空间名===<br />
<br />
:XMPP中用于TLS相关数据的 URN 子名字空间定义如下. (这个名字空间的名字遵守The IETF XML Registry [XML-REG]定义的格式.)<br />
<br />
::URI: urn:ietf:params:xml:ns:xmpp-tls<br />
<br />
::Specification: RFC 3920<br />
<br />
::Description: This is the XML namespace name for TLS-related data in the Extensible Messaging and Presence Protocol (XMPP) as defined by RFC 3920.<br />
<br />
::Registrant Contact: IETF, XMPP Working Group, <xmppwg@jabber.org><br />
<br />
===用于SASL数据的XML名字空间名===<br />
<br />
:XMPP中用于SASL相关数据的 URN 子名字空间定义如下. (这个名字空间的名字遵守The IETF XML Registry \[XML-REG\]定义的格式.)<br />
<br />
::URI: urn:ietf:params:xml:ns:xmpp-sasl<br />
<br />
::Specification: RFC 3920<br />
<br />
::Description: This is the XML namespace name for SASL-related data in the Extensible Messaging and Presence Protocol (XMPP) as defined by RFC 3920.<br />
<br />
::Registrant Contact: IETF, XMPP Working Group, <xmppwg@jabber.org><br />
<br />
===用于流错误的XML名字空间名===<br />
<br />
:XMPP中用于流相关错误的 URN 子名字空间定义如下. (这个名字空间的名字遵守The IETF XML Registry [XML-REG]定义的格式.)<br />
<br />
::URI: urn:ietf:params:xml:ns:xmpp-streams<br />
<br />
::Specification: RFC 3920<br />
<br />
:Description: This is the XML namespace name for stream-related error data in the Extensible Messaging and Presence Protocol (XMPP) as defined by RFC 3920.<br />
<br />
::Registrant Contact: IETF, XMPP Working Group, <xmppwg@jabber.org><br />
<br />
===用于资源绑定的XML名字空间名===<br />
<br />
:XMPP中用于资源绑定的 URN 子名字空间定义如下. (这个名字空间的名字遵守The IETF XML Registry [XML-REG]定义的格式.)<br />
<br />
::URI: urn:ietf:params:xml:ns:xmpp-bind<br />
<br />
::Specification: RFC 3920<br />
<br />
::Description: This is the XML namespace name for resource binding in the Extensible Messaging and Presence Protocol (XMPP) as defined by RFC 3920.<br />
<br />
::Registrant Contact: IETF, XMPP Working Group, <xmppwg@jabber.org><br />
<br />
===用于节错误的XML名字空间名===<br />
<br />
:XMPP中用于节相关错误数据的 URN 子名字空间定义如下. (这个名字空间的名字遵守The IETF XML Registry \[XML-REG\]定义的格式.)<br />
<br />
::URI: urn:ietf:params:xml:ns:xmpp-stanzas<br />
<br />
::Specification: RFC 3920<br />
<br />
::Description: This is the XML namespace name for stanza-related error data in the Extensible Messaging and Presence Protocol (XMPP) as defined by RFC 3920.<br />
<br />
::Registrant Contact: IETF, XMPP Working Group, <xmppwg@jabber.org><br />
<br />
===Nodeprep Profile of Stringprep===<br />
<br />
:The Nodeprep profile of stringprep是在Nodeprep(附录 A)定义的. IANA已经在stringprep profile registry中注册了 Nodeprep.<br />
<br />
::Name of this profile:<br />
<br />
:::Nodeprep<br />
<br />
::RFC in which the profile is defined:<br />
<br />
:::RFC 3920<br />
<br />
::Indicator whether or not this is the newest version of the profile:<br />
<br />
:::This is the first version of Nodeprep<br />
<br />
===Resourceprep Profile of Stringprep===<br />
<br />
:The Resourceprep profile of stringprep是在Resourceprep(附录 B)定义的. IANA已经在stringprep profile registry中注册了Resourceprep.<br />
<br />
::Name of this profile:<br />
<br />
:::Resourceprep<br />
<br />
::RFC in which the profile is defined:<br />
<br />
:::RFC 3920<br />
<br />
::Indicator whether or not this is the newest version of the profile:<br />
<br />
:::This is the first version of Resourceprep<br />
<br />
===GSSAPI 服务名===<br />
<br />
:IANA已经注册了 "xmpp" 作为一个 GSSAPI \[GSS-API\] 服务名, 在SASL Definition (第六章第三节)定义了.<br />
<br />
===端口号===<br />
<br />
:IANA已经注册了"xmpp-client" 和 "xmpp-server" 作为\[TCP\]端口号5222和5269的关键字.<br />
<br />
:这些端口应该(SHOULD)用于客户端-服务器 和 服务器-服务器通信,但它们的使用是可选的(OPTIONAL).<br />
<br />
==参考==<br />
<br />
===标准化参考===<br />
<br />
:[ABNF] Crocker, D. and P. Overell, "Augmented BNF for Syntax Specifications: ABNF", RFC 2234, November 1997.<br />
<br />
:[BASE64] Josefsson, S., "The Base16, Base32, and Base64 Data Encodings", RFC 3548, July 2003.<br />
<br />
:[CHARSET] Alvestrand, H., "IETF Policy on Character Sets and Languages", BCP 18, RFC 2277, January 1998.<br />
<br />
:[DIGEST-MD5] Leach, P. and C. Newman, "Using Digest Authentication as a SASL Mechanism", RFC 2831, May 2000.<br />
<br />
:[DNS] Mockapetris, P., "Domain names \- implementation and specification", STD 13, RFC 1035, November 1987.<br />
<br />
:[GSS-API] Linn, J., "Generic Security Service Application Program Interface Version 2, Update 1", RFC 2743, January 2000.<br />
<br />
:[HTTP-TLS] Rescorla, E., "HTTP Over TLS", RFC 2818, May 2000.<br />
<br />
:[IDNA] Faltstrom, P., Hoffman, P., and A. Costello, "Internationalizing Domain Names in Applications (IDNA)", RFC 3490, March 2003.<br />
<br />
:[IPv6] Hinden, R. and S. Deering, "Internet Protocol Version 6 (IPv6) Addressing Architecture", RFC 3513, April 2003.<br />
<br />
:[LANGTAGS] Alvestrand, H., "Tags for the Identification of Languages", BCP 47, RFC 3066, January 2001.<br />
<br />
:[NAMEPREP] Hoffman, P. and M. Blanchet, "Nameprep: A Stringprep Profile for Internationalized Domain Names (IDN)", RFC 3491, March 2003.<br />
<br />
:[RANDOM] Eastlake 3rd, D., Crocker, S., and J. Schiller, "Randomness Recommendations for Security", RFC 1750, December 1994.<br />
<br />
:[SASL] Myers, J., "Simple Authentication and Security Layer (SASL)", RFC 2222, October 1997.<br />
<br />
:[SRV] Gulbrandsen, A., Vixie, P., and L. Esibov, "A DNS RR for specifying the location of services (DNS SRV)", RFC 2782, February 2000.<br />
<br />
:[STRINGPREP] Hoffman, P. and M. Blanchet, "Preparation of Internationalized Strings ("stringprep")", RFC 3454, December 2002.<br />
<br />
:[TCP] Postel, J., "Transmission Control Protocol", STD 7, RFC 793, September 1981.<br />
<br />
:[TERMS] Bradner, S., "Key words for use in RFCs to Indicate Requirement Levels", BCP 14, RFC 2119, March 1997.<br />
<br />
:[TLS] Dierks, T. and C. Allen, "The TLS Protocol Version 1.0", RFC 2246, January 1999.<br />
<br />
:[UCS2] International Organization for Standardization, "Information Technology \- Universal Multiple-octet coded Character Set (UCS) - Amendment 2: UCS Transformation Format 8 (UTF-8)", ISO Standard 10646-1 Addendum 2, October 1996.<br />
<br />
:[UTF-8] Yergeau, F., "UTF-8, a transformation format of ISO 10646", STD 63, RFC 3629, November 2003.<br />
<br />
:[X509] Housley, R., Polk, W., Ford, W., and D. Solo, "Internet X.509 Public Key Infrastructure Certificate and Certificate Revocation List (CRL) Profile", RFC 3280, April 2002.<br />
<br />
:[XML] Bray, T., Paoli, J., Sperberg-McQueen, C., and E. Maler, "Extensible Markup Language (XML) 1.0 (2nd ed)", W3C REC-xml, October 2000, <http://www.w3.org/TR/REC-xml>.<br />
<br />
:[XML-NAMES] Bray, T., Hollander, D., and A. Layman, "Namespaces in XML", W3C REC-xml-names, January 1999, <http://www.w3.org/TR/REC-xml-names>.<br />
<br />
===信息参考===<br />
<br />
:[ACAP] Newman, C. and J. Myers, "ACAP \-\- Application Configuration Access Protocol", RFC 2244, November 1997.<br />
<br />
:[ASN.1] CCITT, "Recommendation X.208: Specification of Abstract Syntax Notation One (ASN.1)", 1988.<br />
<br />
<br />
:[DNSSEC] Eastlake 3rd, D., "Domain Name System Security Extensions", RFC 2535, March 1999.<br />
<br />
:[HTTP] Fielding, R., Gettys, J., Mogul, J., Frystyk, H., Masinter, L., Leach, P., and T. Berners-Lee, "Hypertext Transfer Protocol -- HTTP/1.1", RFC 2616, June 1999.<br />
<br />
:[IMAP] Crispin, M., "INTERNET MESSAGE ACCESS PROTOCOL - VERSION 4rev1", RFC 3501, March 2003.<br />
<br />
:[IMP-REQS] Day, M., Aggarwal, S., Mohr, G., and J. Vincent, "Instant Messaging \/ Presence Protocol Requirements", RFC 2779, February 2000.<br />
<br />
:[IRC] Oikarinen, J. and D. Reed, "Internet Relay Chat Protocol", RFC 1459, May 1993.<br />
<br />
:[JEP-0029] Kaes, C., "Definition of Jabber Identifiers (JIDs)", JSF JEP 0029, October 2003.<br />
<br />
:[JEP-0078] Saint-Andre, P., "Non-SASL Authentication", JSF JEP 0078, July 2004.<br />
<br />
[JEP-0086] Norris, R. and P. Saint-Andre, "Error Condition Mappings", JSF JEP 0086, February 2004.<br />
<br />
:[JSF] Jabber Software Foundation, "Jabber Software Foundation", <http://www.jabber.org/>.<br />
<br />
:[POP3] Myers, J. and M. Rose, "Post Office Protocol - Version 3", STD 53, RFC 1939, May 1996.<br />
<br />
:[SIMPLE] SIMPLE Working Group, "SIMPLE WG", <http://www.ietf.org/html.charters/simple-charter.html>.<br />
<br />
:[SMTP] Klensin, J., "Simple Mail Transfer Protocol", RFC 2821, April 2001.<br />
<br />
:[URI] Berners-Lee, T., Fielding, R., and L. Masinter, "Uniform Resource Identifiers (URI): Generic Syntax", RFC 2396, August 1998.<br />
<br />
:[USINGTLS] Newman, C., "Using TLS with IMAP, POP3 and ACAP", RFC 2595, June 1999.<br />
<br />
:[XML-REG] Mealling, M., "The IETF XML Registry", BCP 81, RFC 3688, January 2004.<br />
<br />
:[[RFC3921]] Saint-Andre, P., Ed., "Extensible Messaging and Presence Protocol (XMPP): Instant Messaging and Presence", RFC 3921, October 2004.<br />
<br />
<br />
==附录 A. Nodeprep==<br />
<br />
===A.1. 介绍===<br />
<br />
:这个附录定义了 "Nodeprep" profile of [STRINGPREP]. 它定义了处理规则让用户能够在XMPP中输入国际化节点标识符并尽可能正确的获取正确的字符内容. (一个XMPP节点标识符是XMPP地址的可选部分,它在域名标识符和那个'@'分隔符之前;它经常但不是专门用来关联一个即时消息用户名)这些处理规则仅仅适用于XMPP节点标识符但不适用于任意文本或任何XMPP的其他方面.<br />
<br />
:这个脚本定义了以下这些, 正如 [STRINGPREP]要求的:<br />
<br />
:* 脚本预期的适用性: XMPP的国际化节点标识符<br />
<br />
:* 用于stringprep的输入输出字符集: Unicode 3.2, 定义在本附录的第二章<br />
<br />
:* 使用的映射: 定义在第三章<br />
<br />
:* Unicode正规化使用: 定义在第四章<br />
<br />
:* 禁止输出的字符串: 定义在第五章<br />
<br />
:* 双字节字符处理: 定义在第六章<br />
<br />
===A.2. 字符集===<br />
<br />
:本脚本使用Unicode 3.2的未分配编码列表,指向 Table A.1, 也定义在 [STRINGPREP]的附录 A 中.<br />
<br />
===A.3. 映射===<br />
<br />
:本脚本指定使用[STRINGPREP]的以下表:<br />
<br />
::Table B.1<br />
<br />
::Table B.2<br />
<br />
===A.4. 正规化===<br />
<br />
:本脚本指定 Unicode正规化使用 form KC, 定义在 [STRINGPREP]中.<br />
<br />
===A.5. 禁止输出===<br />
<br />
:本脚本指定使用以下的[STRINGPREP]表禁止输出.<br />
<br />
::Table C.1.1<br />
<br />
::Table C.1.2<br />
<br />
::Table C.2.1<br />
<br />
::Table C.2.2<br />
<br />
::Table C.3<br />
<br />
::Table C.4<br />
<br />
::Table C.5<br />
<br />
::Table C.6<br />
<br />
::Table C.7<br />
<br />
::Table C.8<br />
<br />
::Table C.9<br />
<br />
:另外, 以下Unicode字符也被禁止:<br />
<br />
: #x22 (")<br />
<br />
: #x26 (&)<br />
<br />
: #x27 (')<br />
<br />
: #x2F (/)<br />
<br />
: #x3A (:)<br />
<br />
: #x3C (<)<br />
<br />
: #x3E (>)<br />
<br />
: #x40 (@)<br />
<br />
===A.6. 双字节===<br />
<br />
:本脚本指定按照[STRINGPREP]第六章检查双字节.<br />
<br />
==附录 B. Resourceprep==<br />
<br />
===B.1. 介绍===<br />
<br />
:这个附录定义了 "Resourceprep" profile of \[STRINGPREP\]. 它定义了处理规则让用户能够在XMPP中输入国际化资源标识符并尽可能正确的获取正确的字符内容. (一个XMPP资源标识符是XMPP地址的可选部分,它在域名标识符和'/@'分隔符之后;它经常但不是专门用来关联一个即时消息会话名)这些处理规则仅仅适用于XMPP资源标识符但不适用于任意文本或任何XMPP的其他方面.<br />
<br />
:这个脚本定义了以下这些, 正如 [STRINGPREP]要求的:<br />
<br />
:* 脚本预期的适用性: XMPP的国际化节点标识符<br />
<br />
:* 用于stringprep的输入输出字符集: Unicode 3.2, 定义在本附录的第二章<br />
<br />
:* 使用的映射: 定义在第三章<br />
<br />
:* Unicode正规化使用: 定义在第四章<br />
<br />
:* 禁止输出的字符串: 定义在第五章<br />
<br />
:* 双字节字符处理: 定义在第六章<br />
<br />
===B.2. 字符集===<br />
<br />
:本脚本使用Unicode 3.2的未分配编码列表,指向 Table A.1, 也定义在 [STRINGPREP]的附录<br />
<br />
===B.3. 映射===<br />
<br />
:本脚本指定使用[STRINGPREP]的以下表:<br />
<br />
::Table B.1<br />
<br />
===B.4. 正规化===<br />
<br />
:本脚本指定使用 Unicode normalization form KC, 定义在 [STRINGPREP]中.<br />
<br />
===B.5. 禁止输出===<br />
<br />
:本脚本指定使用以下的[STRINGPREP]表禁止输出.<br />
<br />
::Table C.1.2<br />
<br />
::Table C.2.1<br />
<br />
::Table C.2.2<br />
<br />
::Table C.3<br />
<br />
::Table C.4<br />
<br />
::Table C.5<br />
<br />
::Table C.6<br />
<br />
::Table C.7<br />
<br />
::Table C.8<br />
<br />
::Table C.9<br />
<br />
===B.6. 双字节===<br />
<br />
:本脚本指定按照[STRINGPREP]第六章检查双字节.<br />
<br />
==附录 C. XML 规划==<br />
<br />
:以下 XML schemas 是描述性的, 不是标准的. 'jabber:client' 和 'jabber:server' 名字空间的标准定义, 参照 [[RFC3921]].<br />
<br />
===C.1. Streams namespace===<br />
<br />
<source lang="xml"><br />
<?xml version='1.0' encoding='UTF-8'?><br />
<br />
<xs:schema<br />
xmlns:xs='http://www.w3.org/2001/XMLSchema'<br />
targetNamespace='http://etherx.jabber.org/streams'<br />
xmlns='http://etherx.jabber.org/streams'<br />
elementFormDefault='unqualified'><br />
<br />
<xs:element name='stream'><br />
<xs:complexType><br />
<xs:sequence xmlns:client='jabber:client'<br />
xmlns:server='jabber:server'<br />
xmlns:db='jabber:server:dialback'><br />
<xs:element ref='features' minOccurs='0' maxOccurs='1'/><br />
<xs:any namespace='urn:ietf:params:xml:ns:xmpp-tls'<br />
minOccurs='0'<br />
maxOccurs='unbounded'/><br />
<xs:any namespace='urn:ietf:params:xml:ns:xmpp-sasl'<br />
minOccurs='0'<br />
maxOccurs='unbounded'/><br />
<xs:choice minOccurs='0' maxOccurs='1'><br />
<xs:choice minOccurs='0' maxOccurs='unbounded'><br />
<xs:element ref='client:message'/><br />
<xs:element ref='client:presence'/><br />
<xs:element ref='client:iq'/><br />
</xs:choice><br />
<xs:choice minOccurs='0' maxOccurs='unbounded'><br />
<xs:element ref='server:message'/><br />
<xs:element ref='server:presence'/><br />
<xs:element ref='server:iq'/><br />
<xs:element ref='db:result'/><br />
<xs:element ref='db:verify'/><br />
</xs:choice><br />
</xs:choice><br />
<xs:element ref='error' minOccurs='0' maxOccurs='1'/><br />
</xs:sequence><br />
<xs:attribute name='from' type='xs:string' use='optional'/><br />
<xs:attribute name='id' type='xs:NMTOKEN' use='optional'/><br />
<xs:attribute name='to' type='xs:string' use='optional'/><br />
<xs:attribute name='version' type='xs:decimal' use='optional'/><br />
<xs:attribute ref='xml:lang' use='optional'/><br />
</xs:complexType><br />
</xs:element><br />
<br />
<xs:element name='features'><br />
<xs:complexType><br />
<xs:all xmlns:tls='urn:ietf:params:xml:ns:xmpp-tls'<br />
xmlns:sasl='urn:ietf:params:xml:ns:xmpp-sasl'<br />
xmlns:bind='urn:ietf:params:xml:ns:xmpp-bind'<br />
xmlns:sess='urn:ietf:params:xml:ns:xmpp-session'><br />
<xs:element ref='tls:starttls' minOccurs='0'/><br />
<xs:element ref='sasl:mechanisms' minOccurs='0'/><br />
<xs:element ref='bind:bind' minOccurs='0'/><br />
<xs:elemnt ref='sess:session' minOccurs='0'/><br />
</xs:all><br />
</xs:complexType><br />
</xs:element><br />
<br />
<xs:element name='error'><br />
<xs:complexType><br />
<xs:sequence xmlns:err='urn:ietf:params:xml:ns:xmpp-streams'><br />
<xs:group ref='err:streamErrorGroup'/><br />
<xs:element ref='err:text'<br />
minOccurs='0'<br />
maxOccurs='1'/><br />
</xs:sequence><br />
</xs:complexType><br />
</xs:element><br />
<br />
</xs:schema><br />
</source><br />
<br />
===C.2. Stream error namespace===<br />
<br />
<source lang="xml"><br />
<?xml version='1.0' encoding='UTF-8'?><br />
<br />
<xs:schema<br />
xmlns:xs='http://www.w3.org/2001/XMLSchema'<br />
targetNamespace='urn:ietf:params:xml:ns:xmpp-streams'<br />
xmlns='urn:ietf:params:xml:ns:xmpp-streams'<br />
elementFormDefault='qualified'><br />
<br />
<xs:element name='bad-format' type='empty'/><br />
<xs:element name='bad-namespace-prefix' type='empty'/><br />
<xs:element name='conflict' type='empty'/><br />
<xs:element name='connection-timeout' type='empty'/><br />
<xs:element name='host-gone' type='empty'/><br />
<xs:element name='host-unknown' type='empty'/><br />
<xs:element name='improper-addressing' type='empty'/><br />
<xs:element name='internal-server-error' type='empty'/><br />
<xs:element name='invalid-from' type='empty'/><br />
<xs:element name='invalid-id' type='empty'/><br />
<xs:element name='invalid-namespace' type='empty'/><br />
<xs:element name='invalid-xml' type='empty'/><br />
<xs:element name='not-authorized' type='empty'/><br />
<xs:element name='policy-violation' type='empty'/><br />
<xs:element name='remote-connection-failed' type='empty'/><br />
<xs:element name='resource-constraint' type='empty'/><br />
<xs:element name='restricted-xml' type='empty'/><br />
<xs:element name='see-other-host' type='xs:string'/><br />
<xs:element name='system-shutdown' type='empty'/><br />
<xs:element name='undefined-condition' type='empty'/><br />
<xs:element name='unsupported-encoding' type='empty'/><br />
<xs:element name='unsupported-stanza-type' type='empty'/><br />
<xs:element name='unsupported-version' type='empty'/><br />
<xs:element name='xml-not-well-formed' type='empty'/><br />
<br />
<xs:group name='streamErrorGroup'><br />
<xs:choice><br />
<xs:element ref='bad-format'/><br />
<xs:element ref='bad-namespace-prefix'/><br />
<xs:element ref='conflict'/><br />
<xs:element ref='connection-timeout'/><br />
<xs:element ref='host-gone'/><br />
<xs:element ref='host-unknown'/><br />
<xs:element ref='improper-addressing'/><br />
<xs:element ref='internal-server-error'/><br />
<xs:element ref='invalid-from'/><br />
<xs:element ref='invalid-id'/><br />
<xs:element ref='invalid-namespace'/><br />
<xs:element ref='invalid-xml'/><br />
<xs:element ref='not-authorized'/><br />
<xs:element ref='policy-violation'/><br />
<xs:element ref='remote-connection-failed'/><br />
<xs:element ref='resource-constraint'/><br />
<xs:element ref='restricted-xml'/><br />
<xs:element ref='see-other-host'/><br />
<xs:element ref='system-shutdown'/><br />
<xs:element ref='undefined-condition'/><br />
<xs:element ref='unsupported-encoding'/><br />
<xs:element ref='unsupported-stanza-type'/><br />
<xs:element ref='unsupported-version'/><br />
<xs:element ref='xml-not-well-formed'/><br />
</xs:choice><br />
</xs:group><br />
<br />
<xs:element name='text'><br />
<xs:complexType><br />
<xs:simpleContent><br />
<xs:extension base='xs:string'><br />
<xs:attribute ref='xml:lang' use='optional'/><br />
</xs:extension><br />
</xs:simpleContent><br />
</xs:complexType><br />
</xs:element><br />
<br />
<xs:simpleType name='empty'><br />
<xs:restriction base='xs:string'><br />
<xs:enumeration value=''/><br />
</xs:restriction><br />
</xs:simpleType><br />
<br />
</xs:schema><br />
</source><br />
<br />
===C.3. TLS namespace==<br />
<br />
<source lang="xml"><br />
<?xml version='1.0' encoding='UTF-8'?><br />
<br />
<xs:schema<br />
xmlns:xs='http://www.w3.org/2001/XMLSchema'<br />
targetNamespace='urn:ietf:params:xml:ns:xmpp-tls'<br />
xmlns='urn:ietf:params:xml:ns:xmpp-tls'<br />
elementFormDefault='qualified'><br />
<br />
<xs:element name='starttls'><br />
<xs:complexType><br />
<xs:sequence><br />
<xs:element<br />
name='required'<br />
minOccurs='0'<br />
maxOccurs='1'<br />
type='empty'/><br />
</xs:sequence><br />
</xs:complexType><br />
</xs:element><br />
<br />
<xs:element name='proceed' type='empty'/><br />
<xs:element name='failure' type='empty'/><br />
<br />
<xs:simpleType name='empty'><br />
<xs:restriction base='xs:string'><br />
<xs:enumeration value=''/><br />
</xs:restriction><br />
</xs:simpleType><br />
<br />
</xs:schema><br />
</source><br />
<br />
===C.4. SASL namespace===<br />
<br />
<source lang="xml"><br />
<?xml version='1.0' encoding='UTF-8'?><br />
<br />
<xs:schema<br />
xmlns:xs='http://www.w3.org/2001/XMLSchema'<br />
targetNamespace='urn:ietf:params:xml:ns:xmpp-sasl'<br />
xmlns='urn:ietf:params:xml:ns:xmpp-sasl'<br />
elementFormDefault='qualified'><br />
<br />
<xs:element name='mechanisms'><br />
<xs:complexType><br />
<xs:sequence><br />
<xs:element name='mechanism'<br />
maxOccurs='unbounded'<br />
type='xs:string'/><br />
</xs:sequence><br />
</xs:complexType><br />
</xs:element><br />
<br />
<xs:element name='auth'><br />
<xs:complexType><br />
<xs:simpleContent><br />
<xs:extension base='empty'><br />
<xs:attribute name='mechanism'<br />
type='xs:string'<br />
use='optional'/><br />
</xs:extension><br />
</xs:simpleContent><br />
</xs:complexType><br />
</xs:element><br />
<br />
<xs:element name='challenge' type='xs:string'/><br />
<xs:element name='response' type='xs:string'/><br />
<xs:element name='abort' type='empty'/><br />
<xs:element name='success' type='empty'/><br />
<br />
<xs:element name='failure'><br />
<xs:complexType><br />
<xs:choice minOccurs='0'><br />
<xs:element name='aborted' type='empty'/><br />
<xs:element name='incorrect-encoding' type='empty'/><br />
<xs:element name='invalid-authzid' type='empty'/><br />
<xs:element name='invalid-mechanism' type='empty'/><br />
<xs:element name='mechanism-too-weak' type='empty'/><br />
<xs:element name='not-authorized' type='empty'/><br />
<xs:element name='temporary-auth-failure' type='empty'/><br />
</xs:choice><br />
</xs:complexType><br />
</xs:element><br />
<xs:simpleType name='empty'><br />
<xs:restriction base='xs:string'><br />
<xs:enumeration value=''/><br />
</xs:restriction><br />
</xs:simpleType><br />
<br />
</xs:schema><br />
</source><br />
<br />
===C.5. Resource binding namespace===<br />
<br />
<source lang="xml"><br />
<?xml version='1.0' encoding='UTF-8'?><br />
<br />
<xs:schema<br />
xmlns:xs='http://www.w3.org/2001/XMLSchema'<br />
targetNamespace='urn:ietf:params:xml:ns:xmpp-bind'<br />
xmlns='urn:ietf:params:xml:ns:xmpp-bind'<br />
elementFormDefault='qualified'><br />
<br />
<xs:element name='bind'><br />
<xs:complexType><br />
<xs:choice minOccurs='0' maxOccurs='1'><br />
<xs:element name='resource' type='xs:string'/><br />
<xs:element name='jid' type='xs:string'/><br />
</xs:choice><br />
</xs:complexType><br />
</xs:element><br />
<br />
</xs:schema><br />
</source><br />
<br />
===C.6. Dialback namespace===<br />
<br />
<source lang="xml"><br />
<?xml version='1.0' encoding='UTF-8'?><br />
<br />
<xs:schema<br />
xmlns:xs='http://www.w3.org/2001/XMLSchema'<br />
targetNamespace='jabber:server:dialback'<br />
xmlns='jabber:server:dialback'<br />
elementFormDefault='qualified'><br />
<br />
<xs:element name='result'><br />
<xs:complexType><br />
<xs:simpleContent><br />
<xs:extension base='xs:token'><br />
<xs:attribute name='from' type='xs:string' use='required'/><br />
<xs:attribute name='to' type='xs:string' use='required'/><br />
<xs:attribute name='type' use='optional'><br />
<xs:simpleType><br />
<xs:restriction base='xs:NCName'><br />
<xs:enumeration value='invalid'/><br />
<xs:enumeration value='valid'/><br />
</xs:restriction><br />
</xs:simpleType><br />
</xs:attribute><br />
</xs:extension><br />
</xs:simpleContent><br />
</xs:complexType><br />
</xs:element><br />
<br />
<xs:element name='verify'><br />
<xs:complexType><br />
<xs:simpleContent><br />
<xs:extension base='xs:token'><br />
<xs:attribute name='from' type='xs:string' use='required'/><br />
<xs:attribute name='id' type='xs:NMTOKEN' use='required'/><br />
<xs:attribute name='to' type='xs:string' use='required'/><br />
<xs:attribute name='type' use='optional'><br />
<xs:simpleType><br />
<xs:restriction base='xs:NCName'><br />
<xs:enumeration value='invalid'/><br />
<xs:enumeration value='valid'/><br />
</xs:restriction><br />
</xs:simpleType><br />
</xs:attribute><br />
</xs:extension><br />
</xs:simpleContent><br />
</xs:complexType><br />
</xs:element><br />
<br />
</xs:schema><br />
</source><br />
<br />
===C.7. Stanza error namespace===<br />
<br />
<source lang="xml"><br />
<?xml version='1.0' encoding='UTF-8'?><br />
<br />
<xs:schema<br />
xmlns:xs='http://www.w3.org/2001/XMLSchema'<br />
targetNamespace='urn:ietf:params:xml:ns:xmpp-stanzas'<br />
xmlns='urn:ietf:params:xml:ns:xmpp-stanzas'<br />
elementFormDefault='qualified'><br />
<br />
<xs:element name='bad-request' type='empty'/><br />
<xs:element name='conflict' type='empty'/><br />
<xs:element name='feature-not-implemented' type='empty'/><br />
<xs:element name='forbidden' type='empty'/><br />
<xs:element name='gone' type='xs:string'/><br />
<xs:element name='internal-server-error' type='empty'/><br />
<xs:element name='item-not-found' type='empty'/><br />
<xs:element name='jid-malformed' type='empty'/><br />
<xs:element name='not-acceptable' type='empty'/><br />
<xs:element name='not-allowed' type='empty'/><br />
<xs:element name='payment-required' type='empty'/><br />
<xs:element name='recipient-unavailable' type='empty'/><br />
<xs:element name='redirect' type='xs:string'/><br />
<xs:element name='registration-required' type='empty'/><br />
<xs:element name='remote-server-not-found' type='empty'/><br />
<xs:element name='remote-server-timeout' type='empty'/><br />
<xs:element name='resource-constraint' type='empty'/><br />
<xs:element name='service-unavailable' type='empty'/><br />
<xs:element name='subscription-required' type='empty'/><br />
<xs:element name='undefined-condition' type='empty'/><br />
<xs:element name='unexpected-request' type='empty'/><br />
<br />
<xs:group name='stanzaErrorGroup'><br />
<xs:choice><br />
<xs:element ref='bad-request'/><br />
<xs:element ref='conflict'/><br />
<xs:element ref='feature-not-implemented'/><br />
<xs:element ref='forbidden'/><br />
<xs:element ref='gone'/><br />
<xs:element ref='internal-server-error'/><br />
<xs:element ref='item-not-found'/><br />
<xs:element ref='jid-malformed'/><br />
<xs:element ref='not-acceptable'/><br />
<xs:element ref='not-allowed'/><br />
<xs:element ref='payment-required'/><br />
<xs:element ref='recipient-unavailable'/><br />
<xs:element ref='redirect'/><br />
<xs:element ref='registration-required'/><br />
<xs:element ref='remote-server-not-found'/><br />
<xs:element ref='remote-server-timeout'/><br />
<xs:element ref='resource-constraint'/><br />
<xs:element ref='service-unavailable'/><br />
<xs:element ref='subscription-required'/><br />
<xs:element ref='undefined-condition'/><br />
<xs:element ref='unexpected-request'/><br />
</xs:choice><br />
</xs:group><br />
<br />
<xs:element name='text'><br />
<xs:complexType><br />
<xs:simpleContent><br />
<xs:extension base='xs:string'><br />
<xs:attribute ref='xml:lang' use='optional'/><br />
</xs:extension><br />
</xs:simpleContent><br />
</xs:complexType><br />
</xs:element><br />
<br />
<xs:simpleType name='empty'><br />
<xs:restriction base='xs:string'><br />
<xs:enumeration value=''/><br />
</xs:restriction><br />
</xs:simpleType><br />
<br />
</xs:schema><br />
</source><br />
<br />
==附录 D. 核心Jabber协议和XMPP的不同==<br />
<br />
:本章是非标准的.<br />
<br />
::译者注:附录D对于新接触XMPP的人没有什么意义,就不翻译了,免得浪费时间。因为现在RFC公布已经很久了,以前的Jabber实现很多都进化到XMPP了。<br />
<br />
:XMPP has been adapted from the protocols originally developed in the Jabber open-source community, which can be thought of as "XMPP 0.9". Because there exists a large installed base of Jabber implementations and deployments, it may be helpful to specify the key differences between the relevant Jabber protocols and XMPP in order to expedite and encourage upgrades of those implementations and deployments to XMPP. This section summarizes the core differences, while the corresponding section of [[RFC3921]] summarizes the differences that relate specifically to instant messaging and presence applications.<br />
<br />
===D.1. Channel Encryption===<br />
<br />
:It was common practice in the Jabber community to use SSL for channel encryption on ports other than 5222 and 5269 (the convention is to use ports 5223 and 5270). XMPP uses TLS over the IANA-registered ports for channel encryption, as defined under Use of TLS (Section 5) herein.<br />
<br />
===D.2. Authentication===<br />
<br />
:The client-server authentication protocol developed in the Jabber community used a basic IQ interaction qualified by the 'jabber:iq:auth' namespace (documentation of this protocol is contained in \[JEP-0078\], published by the Jabber Software Foundation [JSF]). XMPP uses SASL for authentication, as defined under Use of SASL (Section 6) herein.<br />
<br />
:The Jabber community did not develop an authentication protocol for server-to-server communications, only the Server Dialback (Section 8) protocol to prevent server poofing. XMPP supersedes Server Dialback with a true server-to-server authentication protocol, as defined under Use of SASL (Section 6) herein.<br />
<br />
===D.3. Resource Binding===<br />
<br />
:Resource binding in the Jabber community was handled via the 'jabber:iq:auth' namespace (which was also used for client authentication with a server). XMPP defines a dedicated namespace for resource binding as well as the ability for a server to generate a resource identifier on behalf of a client, as defined under Resource Binding (Section 7).<br />
<br />
===D.4. JID Processing===<br />
<br />
:JID processing was somewhat loosely defined by the Jabber community (documentation of forbidden characters and case handling is contained in [JEP-0029], published by the Jabber Software Foundation [JSF]). XMPP specifies the use of \[NAMEPREP\] for domain identifiers and supplements Nameprep with two additional [STRINGPREP] profiles for JID processing: Nodeprep (Appendix A) for node identifiers and Resourceprep (Appendix B) for resource identifiers.<br />
<br />
===D.5. Error Handling===<br />
<br />
:Stream-related errors were handled in the Jabber community via XML character data text in a <stream:error/> element. In XMPP, stream-related errors are handled via an extensible mechanism defined under Stream Errors (Section 4.7) herein. Stanza-related errors were handled in the Jabber community via HTTP-style error codes. In XMPP, stanza-related errors are handled via an extensible mechanism defined under Stanza Errors (Section 9.3) herein. (Documentation of a mapping between Jabber and XMPP error handling mechanisms is contained in \[JEP-0086\], published by the Jabber Software Foundation [JSF].)<br />
<br />
===D.6. Internationalization===<br />
<br />
:Although use of UTF-8 has always been standard practice within the Jabber community, the community did not define mechanisms for specifying the language of human-readable text provided in XML character data. XMPP specifies the use of the 'xml:lang' attribute in such contexts, as defined under Stream Attributes (Section 4.4) and xml:lang (Section 9.1.5) herein.<br />
<br />
===D.7. Stream Version Attribute===<br />
<br />
:The Jabber community did not include a 'version' attribute in stream headers. XMPP specifies inclusion of that attribute as a way to signal support for the stream features (authentication, encryption, etc.) defined under Version Support (Section 4.4.1) herein.<br />
<br />
==贡献者==<br />
<br />
:XMPP的大部分核心方面是由1999年开始的Jabber开源社区开发的. 这个社区是由 Jeremie Miller建立的, 他于1999年1月发布了最初版的jabber server源代码. 主要的基础协议的早期贡献者还包括 Ryan Eatmon, Peter Millard, Thomas Muldowney,和 Dave Smith. XMPP工作组的工作主要集中在安全性和国际化方面; 在这些领域, 使用 TLS 和 SASL 的协议最初是由 Rob Norris贡献的, stringprep profiles 最初是由 Joe Hildebrand贡献的. The error code syntax 是由Lisa Dusseault建议的.<br />
<br />
==致谢==<br />
<br />
:感谢许多在贡献者名单之外的人们. 尽管很难提供一个完整的名单, 以下个人对于定义协议或评论标准提供了很多帮助:<br />
<br />
:Thomas Charron, Richard Dobson, Sam Hartman, Schuyler Heath, Jonathan Hogg, Cullen Jennings, Craig Kaes, Jacek Konieczny, Alexey Melnikov, Keith Minkler, Julian Missig, Pete Resnick, Marshall Rose, Alexey Shchepin, Jean-Louis Seguineau, Iain Shigeoka, Greg Troxel, and David Waite. <br />
<br />
:也感谢 XMPP工作组的成员和 IETF 社区在本文的成文过程中一直提供的评论和反馈。<br />
<br />
<br />
==作者地址==<br />
<br />
:Peter Saint-Andre (editor)<br />
<br />
:Jabber Software Foundation<br />
<br />
:EMail: stpeter@jabber.org<br />
<br />
==完整的版权声明==<br />
<br />
:Copyright (C) The Internet Society (2004).<br />
<br />
:This document is subject to the rights, licenses and restrictions contained in BCP 78, and except as set forth therein, the authors retain all their rights. This document and the information contained herein are provided on an "AS IS" basis and THE CONTRIBUTOR, THE ORGANIZATION HE/S HE REPRESENTS OR IS SPONSORED BY (IF ANY), THE INTERNET SOCIETY AND THE INTERNET ENGINEERING TASK FORCE DISCLAIM ALL WARRANTIES, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO ANY WARRANTY THAT THE USE OF THE INFORMATION HEREIN WILL NOT INFRINGE ANY RIGHTS OR ANY IMPLIED WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE.<br />
<br />
==Intellectual Property==<br />
<br />
:The IETF takes no position regarding the validity or scope of any Intellectual Property Rights or other rights that might be claimed to pertain to the implementation or use of the technology described in this document or the extent to which any license under such rights might or might not be available; nor does it represent that it has made any independent effort to identify any such rights. Information on the IETF's procedures with respect to rights in IETF Documents can be found in BCP 78 and BCP 79. Copies of IPR disclosures made to the IETF Secretariat and any assurances of licenses to be made available, or the result of an attempt made to obtain a general license or permission for the use of such proprietary rights by implementers or users of this specification can be obtained from the IETF on-line IPR repository at http://www.ietf.org/ipr. The IETF invites any interested party to bring to its attention any copyrights, patents or patent applications, or other proprietary rights that may cover technology that may be required to implement this standard. Please address the information to the IETF at ietf-ipr@ietf.org.<br />
<br />
==感谢==<br />
<br />
:目前为RFC编辑活动提供资金的Internet Society.</div>
Snowqiang
http://wiki.jabbercn.org/RFC3920
RFC3920
2011-05-18T09:25:01Z
<p>Snowqiang: </p>
<hr />
<div>[[Category:XMPP正式RFC标准]]<br />
[[Category:已翻译]]<br />
<br />
"本文的英文原文来自[http://www.ietf.org/rfc/rfc3920.txt RFC 3920]<br />
<br />
{|<br />
|网络工作组 || P. Saint-Andre, Ed.<br />
|-<br />
|申请讨论: 3920 || Jabber软件基金会<br />
|-<br />
|类别: 标准跟踪 || 2004年10月<br />
|}<br />
<br />
<br />
<br />
:::'''可扩展的消息和出席信息协议 (XMPP): 核心协议'''<br />
<br />
'''关于本文的说明'''<br />
<br />
:本文为互联网社区定义了一个互联网标准跟踪协议,并且申请讨论协议和提出了改进的建议。请参照“互联网官方协议标准”的最新版本(STD 1)获得这个协议的标准化进程和状态。本文可以不受限制的分发。<br />
<br />
'''版权声明'''<br />
<br />
:本文版权属于互联网社区 (C) The Internet Society (2004).<br />
<br />
'''摘要'''<br />
<br />
:本文定义了可扩展消息和出席信息协议(XMPP)的核心功能,这个协议采用XML流实现在任意两个网络终端接近实时的交换结构化信息。XMPP提供一个通用的可扩展的框架来交换XML数据,它主要用来建立即时消息和出席信息应用以实现 RFC 2779 的需求。 <br />
<br />
==绪论==<br />
<br />
===概览===<br />
<br />
:XMPP是一个开放式的XML协议,设计用于准实时消息和出席信息以及请求-响应服务。其基本的语法和语义最初主要是由Jabber开放源代码社区于1999年开发的。2002年,XMPP工作组被授权接手开发和改编Jabber协议以适应IETF的即时消息和出席信息技术。作为XMPP工作组的成果,本文定义了 XMPP 1.0 的核心功能;在 RFC 2779 [IMP-REQS] 中指定的提供即时消息和出席信息功能的扩展,定义在 XMPP-IM 协议 [the Extensible Messaging and Presence Protocol (XMPP): Instant Messaging and Presence] 中。<br />
<br />
===术语===<br />
<br />
:本文中大写的关键字 "MUST(必须)", "MUST NOT(不能)", "REQUIRED(必需)", "SHALL(将会)", "SHALL NOT(将不会)", "SHOULD(应该)", "SHOULD NOT(不应该)", "RECOMMENDED(建议)", "MAY(可以)", 和 "OPTIONAL(可选)" 的确切含义符合 BCP 14, RFC 2119 \[TERMS\].<br />
<br />
==通用的架构==<br />
<br />
===概览===<br />
<br />
:尽管XMPP没有指定任何特定的网络结构,但它通常是采用客户-服务器 架构进行实现,其中客户端通过TCP方式使用XMPP访问服务器,服务器之间也采用TCP方式进行通信。<br />
<br />
:以下是这一架构的抽象的示意图 (这里 "-" 表示使用 XMPP 通讯, "=" 表示可使用任何协议通讯)。<br />
<br />
<br />
::C1----S1---S2---C3<br />
<br />
::::|<br />
<br />
::C2----+---G1===FN1===FC1<br />
<br />
:符号的含义如下:<br />
<br />
::* C1, C2, C3 = XMPP 客户端<br />
<br />
::* S1, S2 = XMPP 服务器<br />
<br />
::* G1 = 一个XMPP和外部(非XMPP)消息网络之间进行“翻译”的网关<br />
<br />
::* FN1 = 一个外部消息网络<br />
<br />
::* FC1 = 外部消息网络上的一个客户端<br />
<br />
===服务器===<br />
<br />
:服务器充当XMPP通信的一个智能抽象层,它主要负责:<br />
<br />
:* 对受验证的客户端,服务器以及其他实体之间以XML流形式的连接和会话进行管理。<br />
<br />
:* 在这些实体间使用XML流对合理编址的XML节(第九章)进行路由<br />
<br />
:大部分 XMPP 兼容的服务器也负责存储客户端使用的数据 (比如基于XMPP协议的及时消息应用中的联系人名单); 在这种情况下, XML 数据直接服务器来处理,而不需要转发到其他实体。<br />
<br />
===客户端===<br />
<br />
:大部分客户端通过 TCP 连接直接连到服务器,并通过XMPP获得由服务器以及联合服务器所提供的全部功能。多个不同资源(比如不同的设备和地点)的客户端'''可以'''同时登陆并且并发的连接到一个服务器,每个不同资源的客户端通过XMPP地址的资源标识符来区分(比如<node@domain/ home> 和 <node@domain/work>),参见地址空间(第三章)。'''建议'''的客户端和服务器连接的端口是 5222 ,这个端口已经在 IANA(在第十五章第九节查阅端口号码) 注册了。<br />
<br />
===网关===<br />
<br />
:网关是一个特殊用途的服务器端的服务,主要功能是把 XMPP 翻译成外部(非XMPP)消息系统,并把返回的消息翻译成 XMPP 。例如到 email(参见 [SMTP] ),IRC(参见 [IRC] ),SIMPLE(参见 [SIMPLE] ),SMS 的网关;还有和别的消息服务的网关,比如AIM,ICQ,MSN Messenger,Yahoo! Instant Messenger。网关和服务器之间的通信,网关和外部消息系统的通信,不在本文描述范围之内。<br />
<br />
===网络===<br />
<br />
:因为每个服务器都是由一个网络地址来标识的并且服务器之间的通信是 客户-服务器 协议的直接扩展,实际上整个系统是由很多互通的服务器构成的。例如,<juliet@example.com> 可以和 <romeo@example.net> 交换消息,出席信息和其他信息。这种模式常见于那些需要使网络地址标准化的协议(比如 SMTP )。任意两个服务器之间的通信是可选(OPTIONAL)的。如果被激活,那么这种通信应该(SHOULD)通过 XML 流绑定到 TCP 连接上进行。建议的(RECOMMENDED)服务器之间的连接端口为 5269 ,这个端口号已经在 IANA (在第十五章第九节查阅端口号码)注册了。<br />
<br />
==地址空间==<br />
<br />
===概览===<br />
<br />
:一个实体可以是任何一个被认为是一个网络端点的东西(例如网络上的一个 ID ),而且它是通过XMPP进行通信的。所有这些实体都有一个具有唯一性的地址,并符合 RFC 2396 [URI]规范要求的格式。由于历史原因,一个 XMPP 实体的地址被称为 Jabber Identifier 或 JID 。一个合法的 JID 包括一组排列好的元素,包括域名(domain identifier),节点名(node identifier),和资源名(resource identifier)。<br />
<br />
:JID的语法定义,使用 [ABNF] 中的 Augmented Backus-Naur 格式。(IPv4 地址和 IPv6地址规则在 附录B 中的 [IPv6] 中定义;确定节点规则的合法字符顺序由 附录A 的 [STRINGPREP] 的 Nodeprep 部分来定义;确定资源规则的合法字符顺序由 附录B 的 [STRINGPREP] 的Resourceprep 部分来定义;子域名规则参考 [IDNA] 中关于国际域名标签的描述。)。<br />
<br />
::jid = [ node "@" ] domain [ "/" resource ]<br />
<br />
::domain = fqdn / address-literal<br />
<br />
::fqdn = (sub-domain 1*("." sub-domain))<br />
<br />
::sub-domain = (internationalized domain label)<br />
<br />
::address-literal = IPv4address / IPv6address<br />
<br />
:所有 JID 都是基于上述的结构。类似 <user@host/resource> 这种结构,最常用来标识一个即时消息用户,这个用户所连接的服务器,以及这个用户用于连接的资源(比如特定类型的客户端软件)。不过,节点类型不是客户端也是有可能的,比如一个用来提供多用户聊天服务的特定的聊天室,地址可以是 <room@service> (这里 “room“ 是聊天室的名字而 ”service“ 是多用户聊天服务的主机名),而加入了这个聊天室的某个特定的用户的地址则是 <room@service/nick> (这里 ”nick“ 是用户在聊天室的昵称)。许多其他的 JID 类型都是可能的(例如 <domain/resource> 可能是一个服务器端的脚本或服务)。<br />
<br />
:一个 JID 的每个合法部分(节点名,域名,资源名)的长度不能(MUST NOT)超过 1023 字节。也就是整体长度(包括 '@' 和 '/' )不能超过 3071 字节。<br />
<br />
===域名===<br />
<br />
:域名是一个主要的ID并且是 JID 中唯一必需(REQUIRED)的元素(一个纯粹的域名也是一个合法的 JID)。它通常代表网络的网关或者“主”服务器,其他实体通过连接它来实现 XML 转发和数据管理功能。然而,由一个域名标识引用的实体,并非总是一个服务器,它也可能是一个服务器的子域地址,提供额外的功能(比如多用户聊天服务,用户目录,或一个到外部消息系统的网关)。<br />
<br />
:每个服务器或者服务的域名,可以(MAY)是一个 IP 地址,但应该(SHOULD)是一个完全合法的域名(参见 [DNS]).一个域名ID必须(MUST)是 [IANA] 里定义的“国际化域名”,并且按 [STRINGPREP]中的 [NAMEPREP] profile进行成功的字符转换。在比较两个域名ID之前,服务器必须(MUST),客户端应该(SHOULD)首先按照Nameprep profile(定义在[IANA]中) 来转换每个域名的字符。<br />
<br />
===节点名===<br />
<br />
:节点名是一个可选(OPTIONAL)的第二 ID,放在域名之前并用符号"@"分开.它通常表示一个向服务器或网关请求和使用网络服务的实体(比如一个客户端),当然它也能够表示其他的实体(比如在多用户聊天系统中的一个房间). 节点名所代表的实体,它的地址依赖于一个特定的域名;在 XMPP 的即时消息和出席信息应用系统中,这个地址是“纯 JID” <node@domain> 中的一部分。<br />
<br />
:一个节点名必须按 \[STRINGPREP\] 中的 Nodeprep profile 进行成功的字符转换。在比较两个节点ID之前,服务器必须(MUST),客户端应该(SHOULD)首先按 Nodeprep profile 转换每个ID的字符。<br />
<br />
===资源名===<br />
<br />
:资源名是一个可选的第三 ID,它放在域名的后面并由符号"/"分开。资源名可以跟在 <node@domain>后面也可以跟在 <domain> 后面。它通常表示一个特定的会话,连接(比如设备或者所在位置),或者一个附属于某个节点ID实体相关实体的对象(比如多用户聊天室中的一个参加者)。对于服务器和和其他客户端来说,资源名是不透明的。当它提供必需的信息以完成资源绑定(参见第七章)的时候,通常是由客户端来实现的(尽管可以由客户端向服务器请求完成),然后显示为“已连接的资源”。一个实体可以(MAY)并发维护多个已连接的资源。每个已连接的资源由不同的资源ID来区分。<br />
<br />
:一个资源名必须(MUST)按 \[STRINGPREP\] 中的 Resourceprep profile 进行成功的格式化。在比较两个资源ID之前,服务器必须(MUST),客户端应该(SHOULD)首先按 Resourceprep profile 转换每个ID的字符。<br />
<br />
===地址的确认===<br />
<br />
:在 SASL (见第六章)握手之后(如果必要的话,也在资源绑定(见第七章)之后),正在接收流信息的实体必须(MUST)确认初始实体的 ID 。<br />
<br />
:对于服务器间的通信,在 SASL 握手时,如果没有指明授权的ID,这个初始的实体应该(SHOULD)是经过认证实体(参见 简单认证和安全层协议 \[SASL\] 中的定义)授权的ID(见第六章)。<br />
<br />
:对于客户端和服务器的通信,在 SASL 握手时,如果没有指明授权的ID,“纯 JID” (<node@domain>)应该(SHOULD)是经过认证实体(参见 [SASL] 中的定义)授权的ID,“全 JID” (<node@domain/resource>)的资源ID部分应该(SHOULD)是由客户端和服务器在资源绑定的时候商定的(参见第七章)。<br />
<br />
:接收的实体必须(MUST)确保结果JID(包括节点名,域名,资源名以及分隔符)与本章前面部分描述的规则和格式相一致;为了满足这些约束条件,接收实体可能(MAY)需要把初始实体的发送方 JID 替换成接收实体认可的规范 JID。<br />
<br />
==XML流==<br />
<br />
===概览===<br />
<br />
:两个基本概念,XML流和XML节,使得在出席信息已知的实体之间,异步交换低负载的结构化信息成为可能。这两个术语定义如下:<br />
<br />
:XML流的定义:一个XML流是一个容器,包含了两个实体之间通过网络交换的XML元素。一个XML流是由一个XML打开标签 <stream> (包含适当的属性和名字空间声明)开始的,流的结尾则是一个XML关闭L标签 </stream> 。在流的整个生命周期,初始化它的实体可以通过流发送大量的XML元素,用于流的握手(例如 TLS 握手(第五章) 或 SASL 握手(第六章))或XML节(在这里指符合缺省名字空间的元素,包括<message/>,<presence/>, 或 <iq/> 元素)。“初始的流”由初始化实体(通常是一个客户端或服务器)和接收实体(通常是一个服务器)握手,从接收实体来看,它就是那个初始实体的"会话".初始化流允许从初始化实体到接收实体的单向通信;为了使接收实体能够和初始实体交换信息,接收实体必须发起一个反向的握手(应答流).<br />
<br />
:XML节的定义: 一个XML节是一个实体通过 XML 流向另一个实体发送的结构化信息中的一个离散的语义单位。一个XML节直接存在于根元素<stream/>的下一级,这样可以说是很好的匹配了[XML](译者注:在标准参考一节)的第43条.任何XML节都是从一个XML流的下一级的某个打开标签(如 <presence>)开始,到相应的关闭标签(如 </presence>)。一个XML节可以(MAY)包含子元素(相关的属性,元素, 和 XML 字符数据等) 以表达完整的信息.在这里定义的XML节仅限于<message/>, <presence/>, 和 <iq/> 元素,具体描述间见 XML Stanzas(第九章);为TLS握手(第五章)、SASL握手(第六章)、服务器回拨(第八章)的需要而发送的XML元素,不被认为是一个XML节。<br />
<br />
:设想一个客户端和服务器会话的例子。为了连接一个服务器,一个客户端必须(MUST)发送一个打开标签<stream>给服务器,初始化一个XML流,也可选择(OPTIONAL)在这之前发送一段文本声明XML版本和支持的字符集(参见文本声明的内容(第十一章第四节); 也可看字符编码(第十一章第五节))。视本地化策略和提供的服务而定,服务器应该(SHOULD)回复一个XML流给客户端,同样的,也可选择在这之前发送一段文本声明。一旦客户端完成了SASL握手(第六章),客户端可以(MAY)通过流发送不限量的XML节给网络中的任何接收者。当客户端想关闭这个流,它只需要简单的发送一个关闭标签</stream>给服务器(或者作为另一个选择,可能由服务器关闭这个流)。然后,客户端和服务器都应该(SHOULD)彻底地终止这个连接(通常是一个TCP连接)。<br />
<br />
:那些习惯认为XML是一个以文本为中心风格的人可能希望看看一个与服务器连接的客户端会话,包含两个 打开-关闭 XML文档:一个是从客户端到服务器,一个是从服务器到客户端。下图中,根元素<stream/> 可以被认为是每个“文档”的文档实体,这两个“文档”通过累积那些在XML上传输的XML节来搭建的。无论如何,下图只是方便理解;实际上XMPP并不处理文档而是处理XML流和XML节。<br />
<br />
:基本上,一个XML流相当于一个会话期间所有XML节的一个信封。我们可以简单的把它描述成下图:<br />
<br />
::|----------------------------<br />
<br />
::| <stream><br />
<br />
::|----------------------------<br />
<br />
::| <presence> <br />
<br />
::| <show/> <br />
<br />
::| </presence><br />
<br />
::|----------------------------<br />
<br />
::| <message to='foo'> <br />
<br />
::| <body/> <br />
<br />
::| </message> <br />
<br />
::|----------------------------<br />
<br />
::| <iq to='bar'><br />
<br />
::| <query/> <br />
<br />
::| </iq> <br />
<br />
::|----------------------------<br />
<br />
::| ... <br />
<br />
::|----------------------------<br />
<br />
::| </stream> <br />
<br />
::|----------------------------<br />
<br />
===绑定到TCP===<br />
<br />
:虽然有很多非必需的连接使用XML流来绑定\[TCP\]连接(两个实体可以通过别的机制来互联,比如通过\[HTPP\]连接轮询),本规范只定义了 XMPP 到 TCP 的绑定。在客户和服务器通信的过程中,服务器必须(MUST)允许客户端共享一个TCP连接来传输XML节,包括从客户端传到服务器和从服务器传到客户端。在服务器之间的通信过程中,服务器必须(MUST)用一个 TCP连接 向对方发送 XML节,另一个 TCP连接(由对方初始化)接收对方的XML节,一共两个 TCP连接。<br />
<br />
===流的安全===<br />
<br />
:在XMPP 1.0中,当XML流开始握手时,TLS应该(SHOULD)按 第五章:TLS的使用 中的规定来使用,SASL必须(MUST)按 第六章:SASL的使用 中的规定来使用。尽管可能(MAY)存在某种共有的机制能够保证双向安全,但是“初始化流”(比如从初始化实体发给接收实体的流)和“应答流”(比如从接收实体发给初始化实体的流)还是必须(MUST)安全的分开。在流被验证之间,实体不应该(SHOULD NOT) 尝试通过流发送XML节(第九章);就算它这样做了,对方的实体也不能(MUST NOT)接受这些XML节,并且应该(SHOULD)返回一个 <not-authorized/> 的流错误信息并且终止当前TCP连接上双方的XML流;注意,这仅仅是针对XML节(包含在缺省命名空间中的 <message/>, <presence/>, 和 <iq/> 元素),而不是指那些用于 TLS握手(第五章)、SASL握手(第六章)握手的流。<br />
<br />
===stream 属性===<br />
<br />
:stream 元素的属性如下:<br />
<br />
:* to -- 'to' 属性应(SHOULD)仅出现在初始化实体发给接收实体的 XML 流的头当中,并且它的值必须(MUST)是接收实体所在的主机名。在接收实体发送给初始化实体的 XML 流的头中不应该(SHOULD NOT)出现 'to' 属性。若 'to' 属性出现在应答流中,则初始化实体应(SHOULD)忽略它。<br />
<br />
:* from -- 'from' 属性应(SHOULD)仅出现在接收实体发给初始化实体的 XML 流的头当中,并且它的值必须(MUST)是为当前初始化实体授权的接收实体所在的主机名。注意,不应该(SHOULD NOT)有 'from'属性出现在初始实体发送给接收实体的 XML流的头中;无论如何,如果'from'属性出现在初始化流中,接收实体应该(SHOULD)忽略它。<br />
<br />
:* id -- 'id'属性应该(SHOULD)仅用于接收实体发送给初始化实体 XML流的头。这个属性是一个由接收实体创建的具有唯一性的ID,一个初始实体和接收实体之间的会话ID,并且它在接收方的应用程序中(通常是一个服务器)必须(MUST)是唯一的。注意,这个流 ID 必须是足够安全的,所以它必须是不可预知的和不可重复的(参见[RANDOM] 了解如何获得随机性以保证安全性)。不应该(SHOULD NOT)有 'id'属性出现在初始实体发送给接收实体的 XML流的头中;无论如何,如果'id'属性出现在初始化流中,接收实体应该(SHOULD)忽略它。<br />
<br />
:* xml:lang -- 'xml:lang'属性(定义在\[XML\]中的第二章第十二节)应该(SHOULD)包含在初始化实体发给接收实体的 XML流的头中,以指定在流中传输的可读XML字符所使用的缺省语言。如果这个属性出现了,接收实体应该(SHOULD)记住它的值,作为初始化流和应答流的缺省属性;如果这个属性没有出现,接收实体应该(SHOULD)用一个可配置的缺省值用于双方的流,这个属性值必须(MUST)在应答流的头中传达。对于所有初始化流中传输的节,如果初始实体没有提供'xml:lang'属性,接收实体应该(SHOULD)应用缺省值;如果初始实体提供了'xml:lang'属性,接收实体不能(MUST NOT)修改或删除它(参见第九章第一节第五小节 xml:lang)。'xml:lang'属性的值必须(MUST)是一个 NMTOKEN (定义在\[XML\]的第二章第三节) 并且必须(MUST)遵守 RFC 3066 \[LANGTAGS\] 规定的格式。<br />
<br />
:* version -- version属性(最少需要"1.0")为本规范中和流相关的协议提供了支持。关于这个属性的生成和处理的详细规则将在下文中定义。<br />
<br />
:我们现在可以总结如下:<br />
<br />
{|border="1" cellspacing="0" <br />
! !! 初始化方发给接收方 !! 接收方发给初始化方<br />
|-<br />
|to || 接收方的主机名 || 忽略<br />
|-<br />
|from || 忽略 || 接收方的主机名<br />
|-<br />
|id || 忽略 || 会话键值<br />
|-<br />
|xml:lang || 缺省语言 || 缺省语言<br />
|-<br />
|version || 支持XMPP 1.0 || 支持XMPP 1.0<br />
|}<br />
<br />
====版本支持====<br />
<br />
:在这里XMPP的版本是"1.0";准确地说,这里囊括了和流相关的所有协议(TLS的使用 (第五章),SASL的使用(第六章), 和流错误(第四章第七节)),以及三个定义好的XML节类型(<message/>,<presence/>,和 <iq/>)。XMPP版本号的编号顺序是“<主版本号>.<副版本号>”。主版本和副版本号必须(MUST)是独立的整数并且每个号码可以(MAY)单独以阿拉伯数字增长。这样,"XMPP 2.4"的版本将比"XMPP 2.13"更低。号码前面 的“0”(比如XMPP 6.01)必须(MUST)被接收方忽略并且不能(MUST NOT)被发送出去.<br />
<br />
:如果流和节的格式或者必需的处理方式有了显著的改变,以至于老版本的实体如果只是简单的忽略它不理解的节和属性并且继续像老版本一样的处理方式,会使得老版本的实体不能够和新版本的实体交互,只有在这时候主版本号才应该(SHOULD)增加。副版本号显示新的性能,它必须(MUST)被副版本号更低的实体忽略,但被高(副)版本号的实体用于了解信息。例如,一个副版本号显示处理某种新定义的"type"属性的值(用于message,presence或IQ节)的能力;副版本号高的实体将会了解到与之通信的对方不能够理解这个"type"属性的值,所以将不会发送它。<br />
<br />
:以下规则是用于'版本'属性在实现流的头信息时如何生成和处理:<br />
<br />
:# 初始化实体必须(MUST)在初始化流的头信息中把'版本'的值设置成它所支持的最高版本。(比如,如果最高版本支持就是本规范,那么它必须(MUST)设置成"1.0").<br />
:# 接收实体必须(MUST)在应答流的头信息中把'版本'的值设置成初始化实体所提供的版本或它所支持的最高版本,取其中版本号较低的那一个。接收实体必须(MUST)把主版本号和副版本号作为数字来比较,而不是对"主版本号.副版本号"这个字符串进行比较.<br />
:# 如果在应答流的头信息的版本号中至少有一个主版本号低于初始化流的头信息的版本号,并且如前所述,新版本的实体不能够和旧版本实体交互,初始化实体应该(SHUOULD)生成一个<unsupported-version/>的流错误信息并终止XML流和它的TCP连接。<br />
:# 如果一个实体收到一个头信息中没有'version'属性的流,这个实体必须(MUST)把对方实体的'version'当成'0.0'并且在它发送的应答流的头中也不应该(SHOULD NOT)包含'version'属性.<br />
<br />
===名字空间声明===<br />
<br />
:流的元素必须(MUST)同时满足一个流名字空间声明和一个缺省名字空间声明("名字空间声明"定义在 XML 名字空间定义 \[XML-NAMES\]中).关于流名字空间和缺省名字空间的详细信息,参考 名字空间的名字和前缀(第十一章第二节).<br />
<br />
===流的特性===<br />
<br />
:如果初始化的实体在初始化流的头信息中设置'version'属性的信息为"1.0",接收实体必须(MUST)向初始化实体发送一个 <features/> 子元素以声明任何可供协商的流一级的特性(或者其他需要声明的能力).目前,这仅用于声明本文中定义的 TLS的使用(第五章),SASL的使用(第六章)和资源绑定(第七章),以及 [XMPP-IM|XMPP文档列表/XMPP正式RFC标准/RFC3921] 中定义的会话的建立;无论如何,流特性这一功能将来可以用于声明任何可协商的特性.如果一个实体不理解或支持安全特性,它应该(SHOULD)忽略它.如果要在一个非安全相关的特性(比如资源绑定)被提议之前,完成一个或多个安全特性(比如TLS和SASL)的协商,这个非安全相关的特性不应该(SHOULD NOT)在相应的安全特性协商完毕之前被声明.<br />
<br />
===流错误===<br />
<br />
:流的根元素可以(MAY)包含一个 <error/> 子元素,由流的名字空间前缀作为它的前缀。这个"错误"子元素必须(MUST)由感知到发生了流级别错误的实体发送(通常是一个服务器而不是一个客户端)。<br />
<br />
====规则====<br />
<br />
:以下规则适用于流级别的错误:<br />
<br />
:* 它假定所有流级别的错误都是不可恢复的;所以,如果一个错误发生在流级别,发现这个错误的实体必须(MUST)发送一个流错误信息给另一个实体,发送一个关闭标签 </stream>,并终止这个流所在的TCP连接。<br />
<br />
:* 如果这个错误发生在流刚开始设置的时候,接收实体必须(MUST)仍然发送一个开放标签 <stream> ,并在流元素中包含一个<error/>的子元素,然后发送一个关闭标签 </stream>,最后终止相应的TCP连接。在这种情况下,如果初始化实体在 'to' 属性中提供了一个未知的主机名,服务器应该(SHOULD)在终止之前,先在流的头信息的 'from' 属性中提供一个服务器认证的主机名.<br />
<br />
====语法====<br />
<br />
:流错误的语法如下:<br />
<br />
<source lang="xml"><br />
<stream:error><br />
<defined-condition xmlns='urn:ietf:params:xml:ns:xmpp-streams'/><br />
<text xmlns='urn:ietf:params:xml:ns:xmpp-streams' xml:lang='langcode'><br />
OPTIONAL descriptive text<br />
</text><br />
[OPTIONAL application-specific condition element]<br />
</stream:error><br />
</source><br />
<br />
:<error/>元素:<br />
:* 必须(MUST)包含一个子元素以描述一个下文定义的节错误条件;这个子元素必须(MUST)符合'urn:ietf:params:xml:ns:xmpp-streams'名字空间.<br />
<br />
:* 可以(MAY)包含一个 <text/> 子元素,用XML字符数据描述错误的细节;这个元素必须(MUST)符合'urn:ietf:params:xml:ns:xmpp-streams'名字空间并且应该(SHOULD)拥有一个'xml:lang'属性表明XML字符数据的自然语言。<br />
<br />
:* 可以(MAY)包含一个子元素用于描述一个明确的应用程序错误条件;这个元素必须(MUST)符合一个应用程序定义的名字空间,并且它的结构是由那个名字空间定义的。<br />
<br />
: <text/> 元素是可选的(OPTIONAL)。如果有这个元素,它应该(SHOULD)仅用于提供描述或调试信息以补充一个已定义的条件或应用程序定义的条件。它不应该(SHOULD NOT)被一个应用程序当成一个可编程的信息。它不应该(SHOULD NOT)被用于向用户表达错误信息,但是可以(MAY)作为和条件元素相关的错误信息之外的附加说明。<br />
<br />
====已定义的条件====<br />
<br />
:以下流级别的错误条件是已定义的:<br />
<br />
:* <bad-format/> -- 实体已经发送XML但是不能被处理;这个错误可以(可以)被更多特定的XML相关的错误替换,比如 <bad-namespace-prefix/>, <invalid-xml/>, <restricted-xml/>, <unsupported-encoding/>, 以及 <xml-not-well-formed/>,尽管更多特定的错误是首选的。 <br />
<br />
:* <bad-namespace-prefix/> -- 实体发送的名字空间前缀不被支持,或者在一个需要某种前缀的元素中没有发送一个名字空间前缀(参见 XML Namespace Names and Prefixes (第十一章第二节)).<br />
<br />
:* <conflict/> -- 服务器正在关闭为这个实体激活的流,因为一个和已经存在的流有冲突的新的流已经被初始化。<br />
<br />
:* <connection-timeout/> -- 实体已经很长时间没有通过这个流发生任何通信流量(可由一个本地服务策略来配置).<br />
<br />
:* <host-gone/> -- 初始化实体在流的头信息中提供的'to'属性的值所指定的主机已经不再由这台服务器提供<br />
<br />
:* <host-unknown/> -- 由初始化实体在流的头信息中提供的 'to' 属性的值和由服务器提供的主机名不一致.<br />
<br />
:* <improper-addressing/> -- 一个在两台服务器之间传送的节缺少 'to' 或 'from' 属性(或者这个属性没有值).<br />
<br />
:* <internal-server-error/> -- 服务器配置错误或者其他未定义的内部错误,使得服务器无法提供流服务.<br />
<br />
:* <invalid-from/> -- 在'from'属性中提供的 JID 或 主机名地址,和认证的 JID不匹配 或服务器之间无法通过SASL(或回拨)协商出合法的域名,或客户端和服务器之间无法通过它进行认证和资源绑定。<br />
<br />
:* <invalid-id/> -- 流 ID 或回拨 ID 是非法的或和以前提供的 ID 不一致.<br />
<br />
:* <invalid-namespace/> -- 流名字空间和 "http://etherx.jabber.org/streams" 不相同或回拨名字空间和 "jabber:server:dialback" 不相同.(参考 XML Namespace Names and Prefixes (第十一章第二节)).<br />
<br />
:* <invalid-xml/> -- 实体通过流发送了一个非法的XML给执行验证的服务器 (参考 Validation (第十一章第三节)).<br />
<br />
:* <not-authorized/> -- 实体试图在流被验证之前发送数据或不被许可执行一个和流协商有关的动作,接收实体在发送错误信息之前不允许(MUST NOT)处理厌恶的节。<br />
<br />
:* <policy-violation/> -- 实体违反了某些本地服务策略;服务器可以(MAY)选择在 <text/> 元素或应用程序定义的错误条件(元素)中详细说明策略。<br />
<br />
:* <remote-connection-failed/> -- 服务器无法正确连接到用于验证或授权的远程实体。<br />
<br />
:* <resource-constraint/> -- 服务器缺乏必要的系统资源为流服务。<br />
<br />
:* <restricted-xml/> -- 实体试图发送受限的XML特性,比如一个注释,处理指示,DTD,实体参考,或保留的字符(参考 Restrictions (第十一章第一节)).<br />
<br />
:* <see-other-host/> -- 服务器将不提供服务给初始化实体但是把它重定向到另一台主机;服务器应该(SHOULD)在<see-other-host/>元素的XML字符数据中指明替代服务器名或IP地址(它必须(必须)是合法的域名标识)。<br />
<br />
:* <system-shutdown/> -- 服务器正在关机并且所有激活的流正在被关闭。<br />
<br />
:* <undefined-condition/> -- 错误条件不在本文已定义的错误条件列表之中;这个错误条件应该(SHOULD)仅用于"应用程序定义条件"元素.<br />
<br />
:* <unsupported-encoding/> -- 初始化实体以一个服务器不不支持的编码方式编码了一个流(参照Character Encoding (第十一章第五节)).<br />
<br />
:* <unsupported-stanza-type/> -- 初始化实体发送了一个流的一级子元素但是服务器不支持.<br />
<br />
:* <unsupported-version/> -- 由初始化实体在流的头信息中指定的'version'属性的值所指定的版本不被服务器支持;服务器可以(MAY)在<text/>元素中指定一个它支持的版本号.<br />
<br />
:* <xml-not-well-formed/> -- 初始化实体发送了一个不规范的XML(参考[XML]).<br />
<br />
====应用程序定义条件====<br />
<br />
:大家知道,应用程序可以(MAY)在error元素中包含一个适当名字空间的子元素来提供一个应用程序定义流错误信息."应用程序定义"元素应该(SHOULD)补充或甚至限定一个已定义的元素.所以 <error/> 元素将包含两个或三个子元素:<br />
<br />
<source lang="xml"><br />
<stream:error><br />
<xml-not-well-formed xmlns='urn:ietf:params:xml:ns:xmpp-streams'/><br />
<text xml:lang='en' xmlns='urn:ietf:params:xml:ns:xmpp-streams'><br />
Some special application diagnostic information!<br />
</text><br />
<escape-your-data xmlns='application-ns'/><br />
</stream:error><br />
</stream:stream><br />
</source><br />
<br />
===简化的流示例===<br />
<br />
:这里包含两个简化的例子,描述了基于流的客户端在服务器上的“会话”(这里"C"表示从客户端发给服务器,"S"表示从服务器发给客户端);这些例子只是用于举例说明原理.<br />
<br />
:一个基本的 "会话":<br />
<br />
<source lang="xml"><br />
C: <?xml version='1.0'?><br />
<stream:stream to='example.com' xmlns='jabber:client' xmlns:stream='http://etherx.jabber.org/streams' version='1.0'><br />
<br />
S: <?xml version='1.0'?><br />
<stream:stream from='example.com' id='someid' xmlns='jabber:client' xmlns:stream='http://etherx.jabber.org/streams' version='1.0'><br />
... encryption, authentication, and resource binding ...<br />
<br />
C: <message from='juliet@example.com' to='romeo@example.net' xml:lang='en'><br />
<br />
C: <body>Art thou not Romeo, and a Montague?</body><br />
<br />
C: </message><br />
<br />
S: <message from='romeo@example.net' to='juliet@example.com' xml:lang='en'><br />
<br />
S: <body>Neither, fair saint, if either thee dislike.</body><br />
<br />
S: </message><br />
<br />
C: </stream:stream><br />
<br />
S: </stream:stream><br />
</source><br />
<br />
<br />
:一个不成功的 "会话" :<br />
<br />
<source lang="xml"><br />
C: <?xml version='1.0'?><br />
<stream:stream to='example.com' xmlns='jabber:client' xmlns:stream='http://etherx.jabber.org/streams' version='1.0'><br />
<br />
S: <?xml version='1.0'?><br />
<stream:stream from='example.com' id='someid' xmlns='jabber:client' xmlns:stream='http://etherx.jabber.org/streams' version='1.0'><br />
... encryption, authentication, and resource binding ...<br />
<br />
C: <message xml:lang='en'><br />
<body>Bad XML, no closing body tag!<br />
</message><br />
<br />
S: <stream:error><br />
<xml-not-well-formed xmlns='urn:ietf:params:xml:ns:xmpp-streams'/><br />
</stream:error><br />
<br />
S: </stream:stream><br />
</source><br />
<br />
==TLS 的使用==<br />
<br />
===概览===<br />
<br />
:XMPP包含的一个保证流安全的方法来防止篡改和偷听.这个传输层安全协议[TLS]的频道加密方法, 模拟了类似的其他"STARTTLS"(见RFC 2595 [USINGTLS])的扩展,如 IMAP [IMAP], POP3 [POP3], and ACAP [ACAP]."STARTTLS"的扩展名字空间是'urn:ietf:params:xml:ns:xmpp-tls'.<br />
<br />
:一个给定域的管理员可以(MAY)要求客户端和服务器通信以及服务器之间通信时使用TLS,或者两者都要求。客户端应该(SHOULD)在尝试完成 SASL (第六章)握手之前使用 TLS,服务器应该(SHOULD)在两个域之间使用 TLS 以保证服务器间通信的安全。<br />
<br />
:以下是使用规则:<br />
<br />
::# 一个遵守本协议的初始化实体必须(MUST)在初始化流的头信息中包含一个'version'属性并把值设为“1.0”。<br />
::# 如果TLS握手发生在两个服务器之间,除非服务器声称的DNS主机名已经被解析(见第十四章第四节 Server-to-Server Communications),通信不能(MUST NOT)继续进行。<br />
::# 当一个遵守本协议的接收实体接收了一个初始化流(它的头信息中包含一个'version'属性并且值设为“1.0”),在发送应答流的的头信息(其中包含版本标记)之后,它必须发送(MUST)<starttls/>元素(名字空间为 'urn:ietf:params:xml:ns:xmpp-tls')以及其他它支持的流特性 。<br />
::# 如果初始化实体选择使用TLS,TLS握手必须在SASL握手之前完成;这个顺序用于帮助保护SASL握手时发送的认证信息的安全,同时可以在必要的时候在TLS握手之前为SASL外部机制提供证书。<br />
::# TLS握手期间,一个实体不能(MUST NOT)在流的根元素中发送任何空格符号作为元素的分隔符(在下面的TLS示例中的任何空格符都仅仅是为了便于阅读);这个禁令用来帮助确保安全层字节精度。<br />
::# 接收实体必须(MUST)在发送<proceed/> 元素的关闭符号">" 之后立刻开始TLS协商。初始化实体必须(MUST)在从接收实体接收到<proceed/> 元素的关闭符号">" 之后立刻开始TLS协商。<br />
::# 初始化实体必须(MUST)验证接收实体出示的证书;关于证书验证流程参见Certificate Validation ( 第十四章第二节)。<br />
::# 证书必须(MUST)检查初始化实体(比如一个用户)提供的主机名;而不是通过DNS系统解析出来的主机名;例如,如果用户指定一个主机名"example.com"而一个DNS SRV [SRV]查询返回"im.example.com",证书必须(MUST)检查"example.com".如果任何种类的XMPP实体(例如客户端或服务器)的JID出现在一个证书里,它必须(MUST)表现为一个别名实体里面的UTF8字符串,存在于subjectAltName之中。如何使用 [ASN.1] 对象标识符 "id-on-xmppAddr" 定义在本文的第五章第一节第一小节。<br />
::# 如果 TLS 握手成功了,接收实体必须(MUST) 丢弃TLS 生效之前从初始化实体得到的任何不可靠的信息.<br />
::# 如果 TLS 握手成功了,初始化实体必须(MUST) 丢弃TLS 生效之前从接收实体得到的任何不可靠的信息. <br />
::# 如果 TLS 握手成功了,接收实体不能(MUST NOT)在流重新开始的时候通过提供其他的流特性来向初始化实体提供 STARTTLS 扩展.<br />
::# 如果 TLS 握手成功了,初始化实体必须(MUST)继续进行SASL握手。<br />
::# 如果 TLS 握手失败了,接收实体必须(MUST)终止XML流和相应的TCP连接。<br />
::# 关于必须(MUST)支持的机制,参照 Mandatory-to-Implement Technologies (第十四章第七节) 。<br />
<br />
====用于 XMPP 地址的 ASN.1 对象标识符====<br />
<br />
:上文提到的[ASN.1] 对象标识符 "id-on-xmppAddr"定义如下:<br />
<br />
::id-pkix OBJECT IDENTIFIER ::= { iso(1) identified-organization(3)<br />
<br />
::dod(6) internet(1) security(5) mechanisms(5) pkix(7) }<br />
<br />
::id-on OBJECT IDENTIFIER ::= { id-pkix 8 } \-\- other name forms<br />
<br />
::id-on-xmppAddr OBJECT IDENTIFIER ::= { id-on 5 }<br />
<br />
::XmppAddr ::= UTF8String<br />
<br />
:对象标识符也可以(MAY)使用点分隔的格式,如 "1.3.6.1.5.5.7.8.5".<br />
<br />
===叙述===<br />
<br />
:当一个初始化实体用TLS保护一个和接收实体之间的流,其步骤如下:<br />
<br />
::# 初始化实体打开一个TCP连接,发送一个打开的XML流头信息(其'version'属性设置为"1.0")给接收实体以初始化一个流。<br />
::# 接收实体打开一个TCP连接,发送一个XML流头信息(其'version'属性设置为"1.0")给初始化实体作为应答。<br />
::# 接收实体向初始化实体提议STARTTLS范围(包括其他支持的流特性),如果TLS对于和接收实体交互是必需的,它应该(SHOULD)在<starttls/>元素中包含子元素<required/>.<br />
::# 初始化实体发出STARTTLS命令(例如, 一个符合'urn:ietf:params:xml:ns:xmpp-tls'名字空间的 <starttls/> 元素) 以通知接收实体它希望开始一个TLS握手来保护流。<br />
::# 接收实体必须(MUST)以'urn:ietf:params:xml:ns:xmpp-tls'名字空间中的<proceed/>元素或<failure/>元素应答。如果失败,接收实体必须(MUST)终止XML流和相应的TCP连接。如果继续进行,接收实体必须(MUST)尝试通过TCP连接完成TLS握手并且在TLS握手完成之前不能(MUST NOT)发送任何其他XML数据。<br />
::# 初始化实体和接收实体尝试完成TLS握手。(要符合\[TLS\]规范)<br />
::# 如果 TLS 握手不成功, 接收实体必须(MUST)终止 TCP 连接. 如果 TLS 握手成功, 初始化实体必须(MUST)发送给接收实体一个打开的XML流头信息来初始化一个新的流(先发送一个关闭标签</stream>是不必要的,因为接收实体和初始化实体必须(MUST)确保原来的流在TLS握手成功之后被关闭) 。<br />
::# 在从初始化实体收到新的流头信息之后,接收实体必须(MUST)发送一个新的XML流头信息给初始化实体作为应答,其中应包含可用的特性但不包含STATRTTLS特性。<br />
<br />
===客户端-服务器 示例===<br />
<br />
:以下例子展示一个客户端使用STARTTLS保护数据流 (注意: 以下步骤举例说明协议中的失败案例;在这个例子中它们并不详尽并且也不是必须被数据传输触发的).<br />
<br />
:步骤 1: 客户端初始化流给服务器:<br />
<br />
<source lang="xml"><br />
<stream:stream xmlns='jabber:client' xmlns:stream='http://etherx.jabber.org/streams' to='example.com' version='1.0'><br />
</source><br />
<br />
:步骤 2: 服务器发送一个流标签给客户端作为应答:<br />
<br />
<source lang="xml"><br />
<stream:stream xmlns='jabber:client' xmlns:stream='http://etherx.jabber.org/streams' id='c2s_123' from='example.com' version='1.0'><br />
</source><br />
<br />
:步骤 3: 服务器发送 STARTTLS 范围给客户端(包括验证机制和任何其他流特性):<br />
<br />
<source lang="xml"><br />
<stream:features><br />
<starttls xmlns='urn:ietf:params:xml:ns:xmpp-tls'><br />
<required/><br />
</starttls><br />
<mechanisms xmlns='urn:ietf:params:xml:ns:xmpp-sasl'><br />
<mechanism>DIGEST-MD5</mechanism><br />
<mechanism>PLAIN</mechanism><br />
</mechanisms><br />
</stream:features><br />
</source><br />
<br />
:步骤 4: 客户端发送 STARTTLS 命令给服务器:<br />
<br />
<source lang="xml"><br />
<starttls xmlns='urn:ietf:params:xml:ns:xmpp-tls'/><br />
</source><br />
<br />
:步骤 5: 服务器通知客户端可以继续进行:<br />
<br />
<source lang="xml"><br />
<proceed xmlns='urn:ietf:params:xml:ns:xmpp-tls'/><br />
</source><br />
<br />
:步骤 5 (或者): 服务器通知客户端 TLS 握手失败并关闭流和TCP连接:<br />
<br />
<source lang="xml"><br />
<failure xmlns='urn:ietf:params:xml:ns:xmpp-tls'/><br />
</stream:stream><br />
</source><br />
<br />
:步骤 6: 客户端和服务器尝试通过已有的TCP连接完成 TLS 握手.<br />
<br />
:步骤 7: 如果 TLS 握手成功, 客户端初始化一个新的流给服务器:<br />
<br />
<source lang="xml"><br />
<stream:stream xmlns='jabber:client' xmlns:stream='http://etherx.jabber.org/streams' to='example.com' version='1.0'><br />
</source><br />
<br />
:步骤 7 (或者): 如果 TLS 握手不成功, 服务器关闭 TCP 连接.<br />
<br />
:步骤 8: 服务器发送一个流头信息应答客户端,其中包括任何可用的流特性:<br />
<br />
<source lang="xml"><br />
<stream:stream xmlns='jabber:client' xmlns:stream='http://etherx.jabber.org/streams' from='example.com' id='c2s_234' version='1.0'><br />
<stream:features><br />
<mechanisms xmlns='urn:ietf:params:xml:ns:xmpp-sasl'><br />
<mechanism>DIGEST-MD5</mechanism><br />
<mechanism>PLAIN</mechanism><br />
<mechanism>EXTERNAL</mechanism><br />
</mechanisms><br />
</stream:features><br />
</source><br />
<br />
:步骤 9: 客户端继续 SASL 握手 (第六章).<br />
<br />
===服务器-服务器示例===<br />
<br />
:以下例子展示两个服务器之间使用STARTTLS保护数据流 (注意: 以下步骤举例说明协议中的失败案例;在这个例子中它们并不详尽并且也不是必须被数据传输触发的).<br />
<br />
:步骤 1: Server1 初始化流给 Server2:<br />
<br />
<source lang="xml"><br />
<stream:stream xmlns='jabber:server' xmlns:stream='http://etherx.jabber.org/streams' to='example.com' version='1.0'><br />
</source><br />
<br />
:步骤 2: Server2 发送一个流标签给 Server1 作为应答:<br />
<br />
<source lang="xml"><br />
<stream:stream xmlns='jabber:server' xmlns:stream='http://etherx.jabber.org/streams' from='example.com' id='s2s_123' version='1.0'><br />
</source><br />
<br />
:步骤 3: Server2 发送 STARTTLS 范围给 Server1 ,包括验证机制和任何其他流特性:<br />
<br />
<source lang="xml"><br />
<stream:features><br />
<starttls xmlns='urn:ietf:params:xml:ns:xmpp-tls'><br />
<required/><br />
</starttls><br />
<mechanisms xmlns='urn:ietf:params:xml:ns:xmpp-sasl'><br />
<mechanism>DIGEST-MD5</mechanism><br />
<mechanism>KERBEROS_V4</mechanism><br />
</mechanisms><br />
</stream:features><br />
</source><br />
<br />
:步骤 4: Server1 发送 STARTTLS 命令给 Server2:<br />
<br />
<source lang="xml"><br />
<starttls xmlns='urn:ietf:params:xml:ns:xmpp-tls'/><br />
</source><br />
<br />
:步骤 5: Server2 通知 Server1 允许继续进行:<br />
<br />
<source lang="xml"><br />
<proceed xmlns='urn:ietf:params:xml:ns:xmpp-tls'/><br />
</source><br />
<br />
:步骤 5 (或者): Server2 通知 Server1 TLS握手失败并关闭流:<br />
<br />
<source lang="xml"><br />
<failure xmlns='urn:ietf:params:xml:ns:xmpp-tls'/><br />
</stream:stream><br />
</source><br />
<br />
:步骤 6: Server1 和 Server2 尝试通过 TCP 完成 TLS 握手.<br />
<br />
:步骤 7: 如果 TLS 握手成功, Server1 初始化一个新的流给 Server2:<br />
<br />
<source lang="xml"><br />
<stream:stream xmlns='jabber:server' xmlns:stream='http://etherx.jabber.org/streams' to='example.com' version='1.0'><br />
</source><br />
<br />
:步骤 7 (或者): 如果 TLS 握手不成功, Server2 关闭 TCP 连接.<br />
<br />
:步骤 8: Server2 发送一个包含任何可用流特性的流头信息给 Server1 :<br />
<br />
<source lang="xml"><br />
<stream:stream xmlns='jabber:server' xmlns:stream='http://etherx.jabber.org/streams' from='example.com' id='s2s_234' version='1.0'><br />
<stream:features><br />
<mechanisms xmlns='urn:ietf:params:xml:ns:xmpp-sasl'><br />
<mechanism>DIGEST-MD5</mechanism><br />
<mechanism>KERBEROS_V4</mechanism><br />
<mechanism>EXTERNAL</mechanism><br />
</mechanisms><br />
</stream:features><br />
</source><br />
<br />
:步骤 9: Server1 继续进行 SASL 握手(第六章).<br />
<br />
==SASL 的使用==<br />
<br />
===概览===<br />
<br />
:XMPP 有一个验证流的方法,即XMPP特定的SASL(简单验证和安全层)[SASL]。SASL提供了一个通用的方法为基于连接的协议增加验证支持,而XMPP使用了一个普通的XML名字空间来满足SASL的需要。<br />
<br />
:以下规则应用于:<br />
<br />
:# 如果SASL协商发生在两台服务器之间,除非服务器宣称的DNS主机名得到解析,否则不能(MUST NOT)进行通信。(参见 服务器间的通信(第十四章第四节)).<br />
:# 如果初始化实体有能力使用 SASL 协商, 它必须(MUST)在初始化流的头信息中包含一个值为"1.0"的属性'version'。<br />
:# 如果接收实体有能力使用 SASL 协商, 它必须(MUST)在应答从初始化实体收到的打开流标签时(如果打开的流标签包含一个值为"1.0"的'version'属性),通过'urn:ietf:params:xml:ns:xmpp-sasl'名字空间中的<mechanisms/>元素声明一个或多个验证机制.<br />
:# 当 SASL 协商时, 一个实体不能(MUST NOT)在流的根元素中发送任何空格符号(匹配 production [3] content of [XML])作为元素之间的分隔符(在以下的SASL例子中任何空格符号的出现仅仅是为了增加可读性); 这条禁令帮助确保安全层字节的精确度。<br />
:# 当SASL握手时,在XML元素中使用的任何 XML 字符数据必须被编码成 base64, 编码遵循 RFC 3548 第三章的规定。<br />
:# 如果一个 简单名字"simple username" 规范被选定的SASL机制所支持,(比如, 这被 DIGEST-MD5 和 CRAM-MD5 机制支持但不被 EXTERNAL 和 GSSAPI 机制支持), 验证的时候初始化实体应该(SHOULD)在服务器间通信时提供 简单名字 自身的发送域(IP地址或包含在一个域标识符中的域名全称),在客户端与服务器之间通信时提供注册用户名(包含在一个XMPP节点标识符中的用户或节点名)。<br />
:# 如果初始化实体希望以另一个实体的身份出现并且SASL机制支持授权ID的传输,初始化实体在SASL握手时必须(MUST)提供一个授权ID。如果初始化实体不希望以另一个实体的身份出现,初始化实体在SASL握手时不能(MUST NOT)提供一个授权ID。在 [SASL] 的定义中,除非授权ID不同于从验证ID(详见[SASL])中得到的缺省的授权ID,初始化实体不能(MUST NOT)提供授权ID。如果提供了,这个授权ID的值必须(MUST)是<domain>的格式(对于服务器来说)或<node@domain>的格式(对于客户端来说). <br />
:# 在成功进行包括安全层的SASL握手之后,接收实体必须(MUST)丢弃任何从初始化实体得到的而不是从SASL协商本身获得的信息。<br />
:# 在成功进行包括安全层的SASL握手之后,初始化实体必须(MUST)丢弃任何从接收实体得到的而不是从SASL协商本身获得的信息。<br />
:# 参看 强制执行的技术 (第十四章第七节) ,了解关于必须(MUST)支持的机制.<br />
<br />
===叙述===<br />
<br />
:一个初始化实体使用SASL和接收实体做验证的步骤如下:<br />
<br />
:# 初始化实体请求SASL验证,它发送一个打开的XML流头信息给接收实体,其'version'属性的值为"1.0".<br />
:# 在发送一个XML流头回复之后,接收实体声明一个可用的SASL验证机制清单;每个机制作为一个<mechanism/>元素,作为子元素包含在<mechanisms/>容器元素(其名字空间为'urn:ietf:params:xml:ns:xmpp-sasl')中,而<mechanisms/>则包含在流名字空间中的<features/>元素中。如果在使用任何验证机制之前需要使用TLS(见第五章),接收实体不能(MUST NOT)在TLS握手之前提供可用的SASL验证机制清单。如果初始化实体在优先的TLS协商过程中呈现了一个合法的证书,接收实体应该(SHOULD)在SASL握手中提出一个SASL外部机制给初始化实体,尽管这个外部机制可以(MAY)在其它环境下提供。<br />
:# 初始化实体发送一个符合'urn:ietf:params:xml:ns:xmpp-sasl'名字空间的<auth/>元素(其中包含了适当的'mechanism'属性值)给接收实体,以选择一个机制。如果这个机制支持或需要,这个元素可以(MAY)包含XML字符数据(在SASL术语中,即“初始化应答”);如果初始化实体需要发送一个零字节的初始化应答,它必须(MUST)传输一个单独的等号作为应答,这表示应答有效但不包含数据。<br />
:# 如果必要,接收实体向初始化实体发送一个符合'urn:ietf:params:xml:ns:xmpp-sasl'名字空间的<challenge/>元素来发出挑战;这个元素可以(MAY)包含XML字符数据(必须按照初始化实体选择的SASL机制进行一致性运算)。<br />
:# 初始化实体向接收实体发送符合'urn:ietf:params:xml:ns:xmpp-sasl'名字空间的<response/>元素作为应答;这个元素可以(MAY)包含XML字符数据(必须按照初始化实体选择的SASL机制进行一致性运算)。<br />
:# 如果必要,接收实体发送更多的挑战给初始化实体,初始化实体发送更多的回应。<br />
<br />
:这一系列的 挑战/应答 组,持续进行直到发生以下三件事中的一件为止:<br />
<br />
:# 初始化实体向接收实体发送符合'urn:ietf:params:xml:ns:xmpp-sasl'名字空间的<abort/>元素以中止握手。在接收到<abort/>元素之后,接收实体应该(SHOULD)允许一个可配置的但是合理的重试次数(至少2次),然后它必须(MUST)终止TCP连接;这使得初始化实体(如一个最终用户客户端)能够容忍可能不正确的credentials(如密码输入错误)而不用强制重新连接。<br />
:# 接收实体向初始化实体发送符合'urn:ietf:params:xml:ns:xmpp-sasl'名字空间的<failure/>元素以报告握手失败(详细的失败原因应该在<failure/>的一个适当的子元素中沟通,在第六章第四节中的SASL Errors中定义)。如果失败的情况发生了,接收实体应该(SHOULD)允许一个可配置的但是合理的重试次数(至少2次), 然后它必须(MUST)终止TCP连接;这使得初始化实体(如一个最终用户客户端)能够容忍可能不正确的credentials(如密码输入错误)而不用强制重新连接。<br />
:# 接收实体向初始化实体发送符合'urn:ietf:params:xml:ns:xmpp-sasl'名字空间的<success/>元素以报告握手成功;如果所选择的SASL机制要求,这个元素可以(MAY)包含XML字符数据(见SASL术语,“成功的额外数据”)。接收到<success/> 元素之后,初始化实体必须(MUST)发送一个打开的XML流头信息给接收实体以发起一个新的的流(不需要先发送一个 </stream>标签,因为在发送和接收到<success/>元素之后,接收实体和初始化实体必须确认原来的流被关闭了)。从初始化实体接收到新的流头信息之后,接收实体必须(MUST)发送一个新的流头信息给初始化实体作为回应,附上任何可用的特性(但不包括 STARTTLS 和 SASL 特性)或一个空的 <features/> 元素(这表示没有更多的特性可用);任何没有在本文定义的附加特性必须(MUST)在XMPP的相关扩展中定义。<br />
<br />
===SASL 定义===<br />
<br />
:[SASL]的必要条件要求通过协议定义来提供以下信息:<br />
<br />
::service name(服务名): "xmpp"<br />
<br />
::initiation sequence(开始序列): 当初始化实体提供一个打开的XML流头信息并且接收实体善意回应之后,接收实体提供一个可接受的验证方法清单。初始化实体从这个清单中选择一个方法,把它作为 <auth/> 元素的 'mechanism' 属性的值发送给接收实体,也可以选择发送一个初始化应答以避免循环。<br />
<br />
::exchange sequence(交换序列): 挑战和回应的交换,从接收实体发送给初始化实体的 <challenge/> 元素和从初始化实体发送给接收实体的 <response/> 元素信息。接收实体通过发送 <failure/>元素报告失败,发送<success/>元素报告成功;初始化实体通过发送<abort/> 元素中止交换。成功的协商之后,两边都认为原来的XML流已经关闭并且都开始发送新的流头信息。<br />
<br />
::security layer negotiation(安全层协商): 安全层在接收实体发送 <success/> 元素的关闭字符">"之后立刻生效,在初始化实体发送 <success/> 元素的关闭字符">"之后也立刻生效。层的顺序是 \[TCP\],\[TLS\],然后是 \[SASL\],然后是 \[XMPP\]。<br />
<br />
::use of the authorization identity(授权ID的使用): 授权ID可在xmpp中用于表示一个客户端的非缺省的<node@domain>,或一个服务器的<domain> 。<br />
<br />
===SASL 错误===<br />
<br />
:SASL相关的错误条件定义如下:<br />
<br />
::* <aborted/> -- 接收实体认可由初始化实体发送的<abort/>元素;在回应一个<abort/>元素时发送。<br />
<br />
::* <incorrect-encoding/> -- 由初始化实体提供的数据无法处理,因为[BASE64]编码不正确(例如,因为编码不符合[BASE64]的第三章); 在回应一个包含初始化响应数据的<response/> 元素或<auth/>元素时发送.<br />
<br />
::* <invalid-authzid/> -- 由初始化实体提供的授权id是非法的,因为它的格式不正确或初始化实体无权给那个ID授权;在回应一个包含初始化响应数据的<response/> 元素或<auth/>元素时发送。<br />
<br />
::* <invalid-mechanism/> -- 初始化实体不能提供一个机制活、或请求一个不被接受实体支持的机制;在回应一个<auth/>元素时发送。<br />
<br />
::* <mechanism-too-weak/> -- 初始化实体请求的机制比服务器策略对它的要求弱;在回应一个包含初始化响应数据的<response/> 元素或<auth/>元素时发送。<br />
<br />
::* <not-authorized/> -- 验证失败,因为初始化实体没有提供合法的credentials(这包括但不限于未知用户名等情形);在回应一个包含初始化响应数据的<response/> 元素或<auth/>元素时发送。<br />
<br />
::* <temporary-auth-failure/> -- 验证失败,因为接收实体出现了临时的错误;在回应一个<response/> 元素或<auth/>元素时发送。<br />
<br />
===客户端-服务器 示例===<br />
<br />
:以下例子展示了一个客户端和一个服务器使用SASL作验证的数据流,通常是在成功的TLS握手之后(注意:以下显示的替代步骤仅用于举例说明协议的失败情形;它们不够详尽也不需要由例子中的数据传送来触发)。<br />
<br />
:步骤 1: 客户端初始化流给服务器:<br />
<br />
<source lang="xml"><br />
<stream:stream xmlns='jabber:client' xmlns:stream='http://etherx.jabber.org/streams' to='example.com' version='1.0'><br />
</source><br />
<br />
:步骤 2: 服务器向客户端发送流标签作为应答:<br />
<br />
<source lang="xml"><br />
<stream:stream xmlns='jabber:client' xmlns:stream='http://etherx.jabber.org/streams' id='c2s_234' from='example.com' version='1.0'><br />
</source><br />
<br />
:步骤 3: 服务器通知客户端可用的验证机制:<br />
<br />
<source lang="xml"><br />
<stream:features><br />
<mechanisms xmlns='urn:ietf:params:xml:ns:xmpp-sasl'><br />
<mechanism>DIGEST-MD5</mechanism><br />
<mechanism>PLAIN</mechanism><br />
</mechanisms><br />
</stream:features><br />
</source><br />
<br />
:步骤 4: 客户端选择一个验证机制:<br />
<br />
<source lang="xml"><br />
<auth xmlns='urn:ietf:params:xml:ns:xmpp-sasl' mechanism='DIGEST-MD5'/><br />
</source><br />
<br />
:步骤 5: 服务器发送一个 \[BASE64\] 编码的挑战给客户端:<br />
<br />
<source lang="xml"><br />
<challenge xmlns='urn:ietf:params:xml:ns:xmpp-sasl'><br />
cmVhbG09InNvbWVyZWFsbSIsbm9uY2U9Ik9BNk1HOXRFUUdtMmhoIixxb3A9ImF1dGgi<br />
LGNoYXJzZXQ9dXRmLTgsYWxnb3JpdGhtPW1kNS1zZXNzCg==<br />
</challenge><br />
</source><br />
<br />
:解码后的挑战信息是:<br />
<br />
<source lang="xml"><br />
realm="somerealm",nonce="OA6MG9tEQGm2hh",\<br />
qop="auth",charset=utf-8,algorithm=md5-sess<br />
</source><br />
<br />
:步骤 5 (替代): 服务器返回一个错误给客户端:<br />
<br />
<source lang="xml"><br />
<failure xmlns='urn:ietf:params:xml:ns:xmpp-sasl'><br />
<incorrect-encoding/><br />
</failure><br />
</stream:stream><br />
</source><br />
<br />
:步骤 6: 客户端发送一个\[BASE64\]编码的回应这个挑战:<br />
<br />
<source lang="xml"><br />
<response xmlns='urn:ietf:params:xml:ns:xmpp-sasl'><br />
dXNlcm5hbWU9InNvbWVub2RlIixyZWFsbT0ic29tZXJlYWxtIixub25jZT0i<br />
T0E2TUc5dEVRR20yaGgiLGNub25jZT0iT0E2TUhYaDZWcVRyUmsiLG5jPTAw<br />
MDAwMDAxLHFvcD1hdXRoLGRpZ2VzdC11cmk9InhtcHAvZXhhbXBsZS5jb20i<br />
LHJlc3BvbnNlPWQzODhkYWQ5MGQ0YmJkNzYwYTE1MjMyMWYyMTQzYWY3LGNo<br />
YXJzZXQ9dXRmLTgK<br />
</response><br />
</source><br />
<br />
:解码后的回应信息是:<br />
<br />
<source lang="xml"><br />
username="somenode",realm="somerealm",\<br />
nonce="OA6MG9tEQGm2hh",cnonce="OA6MHXh6VqTrRk",\<br />
nc=00000001,qop=auth,digest-uri="xmpp/example.com",\<br />
response=d388dad90d4bbd760a152321f2143af7,charset=utf-8<br />
</source><br />
<br />
:步骤 7: 服务器发送另一个\[BASE64\]编码的挑战给客户端:<br />
<br />
<source lang="xml"><br />
<challenge xmlns='urn:ietf:params:xml:ns:xmpp-sasl'><br />
cnNwYXV0aD1lYTQwZjYwMzM1YzQyN2I1NTI3Yjg0ZGJhYmNkZmZmZAo=<br />
</challenge><br />
</source><br />
<br />
:解码后的挑战信息是:<br />
<br />
<source lang="xml"><br />
rspauth=ea40f60335c427b5527b84dbabcdfffd<br />
</source><br />
<br />
:步骤 7 (或者): 服务器返回一个错误给客户端:<br />
<br />
<source lang="xml"><br />
<failure xmlns='urn:ietf:params:xml:ns:xmpp-sasl'><br />
<temporary-auth-failure/><br />
</failure><br />
</stream:stream><br />
</source><br />
<br />
:步骤 8: 客户端应答这个挑战:<br />
<br />
<source lang="xml"><br />
<response xmlns='urn:ietf:params:xml:ns:xmpp-sasl'/><br />
</source><br />
<br />
:步骤 9: 服务器通知客户端验证成功:<br />
<br />
<source lang="xml"><br />
<success xmlns='urn:ietf:params:xml:ns:xmpp-sasl'/><br />
</source><br />
<br />
:步骤 9 (或者): 服务器通知客户端验证失败:<br />
<br />
<source lang="xml"><br />
<failure xmlns='urn:ietf:params:xml:ns:xmpp-sasl'><br />
<temporary-auth-failure/><br />
</failure><br />
</stream:stream><br />
</source><br />
<br />
:步骤 10: 客户端发起一个新的流给服务器:<br />
<br />
<source lang="xml"><br />
<stream:stream xmlns='jabber:client' xmlns:stream='http://etherx.jabber.org/streams' to='example.com' version='1.0'><br />
</source><br />
<br />
:步骤 11: 服务器发送一个流头信息回应客户端,并附上任何可用的特性(或空的features元素):<br />
<br />
<source lang="xml"><br />
<stream:stream xmlns='jabber:client' xmlns:stream='http://etherx.jabber.org/streams' id='c2s_345' from='example.com' version='1.0'><br />
<stream:features><br />
<bind xmlns='urn:ietf:params:xml:ns:xmpp-bind'/><br />
<session xmlns='urn:ietf:params:xml:ns:xmpp-session'/><br />
</stream:features><br />
</source><br />
<br />
===服务器-服务器 示例===<br />
<br />
:以下例子展示了一个服务器和另一个服务器使用SASL作验证的数据流,通常是在成功的TLS握手之后(注意:以下显示的替代步骤仅用于举例说明协议的失败情形;它们不够详尽也不需要由例子中的数据传送来触发)。<br />
<br />
:步骤 1: 服务器1 发起一个流给 服务器2 :<br />
<br />
<source lang="xml"><br />
<stream:stream xmlns='jabber:server' xmlns:stream='http://etherx.jabber.org/streams' to='example.com' version='1.0'><br />
</source><br />
<br />
:步骤 2: 服务器2 回应一个流标签给 服务器1:<br />
<br />
<source lang="xml"><br />
<stream:stream xmlns='jabber:server' xmlns:stream='http://etherx.jabber.org/streams' from='example.com' id='s2s_234' version='1.0'><br />
</source><br />
<br />
:步骤 3: 服务器2 通知 服务器1 可用的验证机制:<br />
<br />
<source lang="xml"><br />
<stream:features><br />
<mechanisms xmlns='urn:ietf:params:xml:ns:xmpp-sasl'><br />
<mechanism>DIGEST-MD5</mechanism><br />
<mechanism>KERBEROS_V4</mechanism><br />
</mechanisms><br />
</stream:features><br />
</source><br />
<br />
:步骤 4: 服务器1 选择一个验证机制:<br />
<br />
<source lang="xml"><br />
<auth xmlns='urn:ietf:params:xml:ns:xmpp-sasl' mechanism='DIGEST-MD5'/><br />
</source><br />
<br />
:步骤 5: 服务器2 发送一个\[BASE64\]编码的挑战给 服务器1:<br />
<br />
<source lang="xml"><br />
<challenge xmlns='urn:ietf:params:xml:ns:xmpp-sasl'><br />
cmVhbG09InNvbWVyZWFsbSIsbm9uY2U9Ik9BNk1HOXRFUUdtMmhoIixxb3A9<br />
ImF1dGgiLGNoYXJzZXQ9dXRmLTgsYWxnb3JpdGhtPW1kNS1zZXNz<br />
</challenge><br />
</source><br />
<br />
:解码后的挑战信息是:<br />
<br />
<source lang="xml"><br />
realm="somerealm",nonce="OA6MG9tEQGm2hh",\<br />
qop="auth",charset=utf-8,algorithm=md5-sess<br />
</source><br />
<br />
:步骤 5 (替代): 服务器2 返回一个错误给 服务器1:<br />
<br />
<source lang="xml"><br />
<failure xmlns='urn:ietf:params:xml:ns:xmpp-sasl'><br />
<incorrect-encoding/><br />
</failure><br />
</stream:stream><br />
</source><br />
<br />
:步骤 6: 服务器1 发送一个\[BASE64\]编码的回应这个挑战:<br />
<br />
<source lang="xml"><br />
<response xmlns='urn:ietf:params:xml:ns:xmpp-sasl'><br />
dXNlcm5hbWU9ImV4YW1wbGUub3JnIixyZWFsbT0ic29tZXJlYWxtIixub25j<br />
ZT0iT0E2TUc5dEVRR20yaGgiLGNub25jZT0iT0E2TUhYaDZWcVRyUmsiLG5j<br />
PTAwMDAwMDAxLHFvcD1hdXRoLGRpZ2VzdC11cmk9InhtcHAvZXhhbXBsZS5v<br />
cmciLHJlc3BvbnNlPWQzODhkYWQ5MGQ0YmJkNzYwYTE1MjMyMWYyMTQzYWY3<br />
LGNoYXJzZXQ9dXRmLTgK<br />
</response><br />
</source><br />
<br />
:解码后的应答信息是:<br />
<br />
<source lang="xml"><br />
username="example.org",realm="somerealm",\<br />
nonce="OA6MG9tEQGm2hh",cnonce="OA6MHXh6VqTrRk",\<br />
nc=00000001,qop=auth,digest-uri="xmpp/example.org",\<br />
response=d388dad90d4bbd760a152321f2143af7,charset=utf-8<br />
</source><br />
<br />
:步骤 7: 服务器2 发送另外一个\[BASE64\]编码的挑战给 服务器1:<br />
<br />
<source lang="xml"><br />
<challenge xmlns='urn:ietf:params:xml:ns:xmpp-sasl'><br />
cnNwYXV0aD1lYTQwZjYwMzM1YzQyN2I1NTI3Yjg0ZGJhYmNkZmZmZAo=<br />
</challenge><br />
</source><br />
<br />
:解码后的挑战信息是:<br />
<br />
<source lang="xml"><br />
rspauth=ea40f60335c427b5527b84dbabcdfffd<br />
</source><br />
<br />
:步骤 7 (或者): 服务器2 返回一个错误给 服务器1:<br />
<br />
<source lang="xml"><br />
<failure xmlns='urn:ietf:params:xml:ns:xmpp-sasl'><br />
<invalid-authzid/><br />
</failure><br />
</stream:stream><br />
</source><br />
<br />
:步骤 8: 服务器1 回应挑战:<br />
<br />
<source lang="xml"><br />
<response xmlns='urn:ietf:params:xml:ns:xmpp-sasl'/><br />
</source><br />
<br />
:步骤 8 (或者): 服务器1 中止协商:<br />
<br />
<source lang="xml"><br />
<abort xmlns='urn:ietf:params:xml:ns:xmpp-sasl'/><br />
</source><br />
<br />
:步骤 9: 服务器2 通知 服务器1 验证成功:<br />
<br />
<source lang="xml"><br />
<success xmlns='urn:ietf:params:xml:ns:xmpp-sasl'/><br />
</source><br />
<br />
:步骤 9 (或者): 服务器2 通知 服务器1 验证失败:<br />
<br />
<source lang="xml"><br />
<failure xmlns='urn:ietf:params:xml:ns:xmpp-sasl'><br />
<aborted/><br />
</failure><br />
</stream:stream><br />
</source><br />
<br />
:步骤 10: 服务器1 重新发起一个新的流给 服务器2:<br />
<br />
<source lang="xml"><br />
<stream:stream xmlns='jabber:server' xmlns:stream='http://etherx.jabber.org/streams' to='example.com' version='1.0'><br />
</source><br />
<br />
:步骤 11: 服务器2 发送一个流头信息应答 服务器1 ,并附上任何可用的特性(或一个空的features元素).:<br />
<br />
<source lang="xml"><br />
<stream:stream xmlns='jabber:client' xmlns:stream='http://etherx.jabber.org/streams' from='example.com' id='s2s_345' version='1.0'><br />
<stream:features/><br />
</source><br />
<br />
==资源绑定==<br />
<br />
:在和接收实体完成 SASL 协商(第六章)之后,初始化实体可能(MAY)想要或者需要绑定一个特定的资源到流上.通常这仅适用于客户端: 为了满足本文定义的寻址格式(第三章)和节传输规则(第十章),客户端<node@domain>必须(MUST)拥有一个相关的资源ID(由服务器生成或由客户端程序提供);以确保在流上使用的地址是一个“全JID”(<node@domain/resource>)。<br />
<br />
:接收到一个成功的SASL握手之后,客户端必须(MUST)发送一个新的流头信息给服务器,服务器必须(MUST)返回一个包含可用的流特性列表的头信息。特别是,在成功的SASL握手之后如果服务器需要客户端绑定一个资源,它必须(MUST)在握手成功之后(而不是之前)发送给客户端的应答流特性中包含一个空的符合'urn:ietf:params:xml:ns:xmpp-bind'名字空间的<bind/>元素。:<br />
<br />
:服务器向客户端声明资源绑定特性:<br />
<br />
<source lang="xml"><br />
<stream:stream xmlns='jabber:client' xmlns:stream='http://etherx.jabber.org/streams' id='c2s_345' from='example.com' version='1.0'><br />
<stream:features><br />
<bind xmlns='urn:ietf:params:xml:ns:xmpp-bind'/><br />
</stream:features><br />
</source><br />
<br />
:收到要求资源绑定的通知后,客户端必须(MUST)通过发送一个符合'urn:ietf:params:xml:ns:xmpp-bind'名字空间的“set”类型的IQ节(参见 IQ 语义 (第九章第二节第三小节))给服务器来绑定一个资源到流中。<br />
<br />
:如果客户端端希望允许服务器给自己生成一个资源ID,它可以发送一个包含空的<bind/>元素的“set”类型的IQ节。:<br />
<br />
:客户端请求服务器绑定资源:<br />
<br />
<source lang="xml"><br />
<iq type='set' id='bind_1'><br />
<bind xmlns='urn:ietf:params:xml:ns:xmpp-bind'/><br />
</iq><br />
</source><br />
<br />
:一个支持资源绑定的服务器必须(MUST)自动生成一个资源ID给客户端。一个由服务器生成的资源ID对于那个<node@domain>必须(MUST)是唯一的。<br />
<br />
:如果客户端希望指定资源ID,它发送一个包含期望资源ID的“set”类型的 IQ节,把资源ID作为<bind/>元素下的<resource/>子元素的XML字符数据:<br />
<br />
:客户端绑定一个资源:<br />
<br />
<source lang="xml"><br />
<iq type='set' id='bind_2'><br />
<bind xmlns='urn:ietf:params:xml:ns:xmpp-bind'><br />
<resource>someresource</resource><br />
</bind><br />
</iq><br />
</source><br />
<br />
:一旦服务器为客户端生成了一个资源ID或接受了客户端自己提供的资源ID,它必须(MUST)返回一个“result”类型的 IQ 节给客户端,这个节必须包含一个指明全JID的<jid/>子元素表示服务器决定连接的资源:<br />
<br />
:服务器通知客户端资源绑定成功:<br />
<br />
<source lang="xml"><br />
<iq type='result' id='bind_2'><br />
<bind xmlns='urn:ietf:params:xml:ns:xmpp-bind'><br />
<jid>somenode@example.com/someresource</jid><br />
</bind><br />
</iq><br />
</source><br />
<br />
:一个服务器应该(SHOULD)接受客户端提供的资源ID,但是可以(MAY)用服务器生成的资源ID覆盖它;在这种情况下,服务器不应该(SHOULD NOT)返回一个错误信息一个(如<forbidden/>)给客户端,而应该(SHOULD)在上文所述的 IQ result 中返回生成的资源ID。<br />
<br />
:当一个客户端自行提供资源ID时,可能发生以下的节错误(参见 Stanza Errors (第九章第三节)):<br />
<br />
::- 提供的资源ID服务器无法处理,因为不符合资源字符规范Resourceprep(附录B)。<br />
<br />
::- 客户端不被允许绑定一个资源(如节点或用户已经达到允许连接的资源数限制)。<br />
<br />
::- 提供的资源ID已经被使用但是服务器不允许以同一个资源ID绑定多个连接。<br />
<br />
:协议对这些错误条件规定如下.<br />
<br />
::资源ID不能处理:<br />
<br />
<source lang="xml"><br />
<iq type='error' id='bind_2'><br />
<bind xmlns='urn:ietf:params:xml:ns:xmpp-bind'><br />
<resource>someresource</resource><br />
</bind><br />
<error type='modify'><br />
<bad-request xmlns='urn:ietf:params:xml:ns:xmpp-stanzas'/><br />
</error><br />
</iq><br />
</source><br />
<br />
::客户端不允许绑定一个资源:<br />
<br />
<source lang="xml"><br />
<iq type='error' id='bind_2'><br />
<bind xmlns='urn:ietf:params:xml:ns:xmpp-bind'><br />
<resource>someresource</resource><br />
</bind><br />
<error type='cancel'><br />
<not-allowed xmlns='urn:ietf:params:xml:ns:xmpp-stanzas'/><br />
</error><br />
</iq><br />
</source><br />
<br />
::资源ID已经在使用:<br />
<br />
<source lang="xml"><br />
<iq type='error' id='bind_2'><br />
<bind xmlns='urn:ietf:params:xml:ns:xmpp-bind'><br />
<resource>someresource</resource><br />
</bind><br />
<error type='cancel'><br />
<conflict xmlns='urn:ietf:params:xml:ns:xmpp-stanzas'/><br />
</error><br />
</iq><br />
</source><br />
<br />
:如果,在完成资源绑定步骤之前,客户端试图以符合'urn:ietf:params:xml:ns:xmpp-bind'名字空间的<bind/>子元素发送一个非IQ类型的XML节,服务器不能(MUST NOT)处理这个节,而应该(SHOULD)返回一个<not-authorized/>节错误信息给客户端.<br />
<br />
==服务器回拨==<br />
<br />
===概览===<br />
<br />
:Jabber协议接受的来自XMPP的包括“服务器回拨”方法,用于防治域名欺骗,使得欺骗XML节更为困难。服务器回拨不是一个安全机制,并且它的服务器身份认证结果很弱(参见服务器之间的通信(第十四章第四节)中关于这个方法的安全特性)。需要健壮的安全性的域名应该(SHOULD)使用TLS或SASL;细节参见服务器间的通信(第十四章第四节)。如果SASL用于服务器间通信,回拨就不需要用了(SHOULD NOT)。本文描述回拨的好处在于向后兼容现存的实现和部署。<br />
<br />
:服务器回拨方法由现存的DNS系统的存在而成为可能,因为一个服务器(通常)可以查询给定域的授权服务器。由于服务器回拨依赖于DNS,除非服务器宣称的DNS主机得到解析,域之间的通信无法进行(参见服务器间的通信(第十四章第四节))。<br />
<br />
:服务器回拨是单向性的,可在单一方向上对一个流进行(微弱的)身份验证.因为服务器回拨不是一个验证机制,通过回拨获得相互的认证是不可能的.因此,为了使得服务器之间的双向通信,服务器回拨必须(MUST)在每个方向上完成。<br />
<br />
:在服务器回拨中生成和检验密钥的方法必须(MUST)考虑计算被使用的主机名,由接收服务器生成的流ID,和只有授权服务器网络才知道的秘密。在服务器回拨中流ID是安全性的关键所以必须(MUST)是不可预知的和不可重复的(见\[RANDOM\]中关于使用随机数获得安全性的建议).<br />
<br />
:任何回拨协商过程中发生的错误必须(MUST)被当成一个流错误,并导致流以及相关的TCP连接的终止.可能发生的错误情况协议中描述如下.<br />
<br />
:以下术语适用:<br />
<br />
:* 发起服务器 -- 尝试在两个域之间建立连接的那个服务器.<br />
<br />
:* 接收服务器 -- 尝试验证发起服务期声称的域名的那台服务器.<br />
<br />
:* 授权(权威?Authoritative) 服务器 -- 回答发起服务器声称的DNS主机名的服务器;基本上这应该是那台发起服务器,但是它也可能是一个在发起服务器网络中独立的服务器。<br />
<br />
===事件顺序===<br />
<br />
:以下是回拨中的事件顺序的简介:<br />
<br />
:# 发起服务器和接收服务器建立一个连接。<br />
:# 发起服务器通过到连接发送一个 'key' 值给接收服务期。<br />
:# 接收服务器建立一个连接到授权服务器。<br />
:# 接收服务器发送一个相同的 'key' 值给授权服务器。<br />
:# 授权服务器回答这个key是否合法。<br />
:# 接收服务器通知发起服务器是否被验证通过。<br />
<br />
:我们用用以下图形展示这个事件流程(见附件s2s.png):<br />
<br />
{image:img=s2s}<br />
<br />
===协议===<br />
<br />
:服务器之间互动的细节协议如下:<br />
<br />
:1. 发起服务器和接受服务器建立TCP连接.<br />
<br />
:2. 发起服务器发送流头信息给接收服务器:<br />
<br />
<source lang="xml"><br />
<stream:stream xmlns:stream='http://etherx.jabber.org/streams' xmlns='jabber:server' xmlns:db='jabber:server:dialback'><br />
</source><br />
<br />
:注意: 'to'和'from'属性在流的根元素是可选的(OPTIONAL). 其中包含的xmlns:db名字空间向接收服务器声明了发起服务器支持回拨. 如果名字空间不正确,接收实体必须(MUST)生成一个<invalid-namespace/>流错误条件并且终止XML流和相应的TCP连接.<br />
<br />
:3. 接收服务器应该(SHOULD)回送一个流头信息给发起服务器,为这次交互生成一个唯一性的ID :<br />
<br />
<source lang="xml"><br />
<stream:stream xmlns:stream='http://etherx.jabber.org/streams' xmlns='jabber:server' xmlns:db='jabber:server:dialback' id='457F9224A0...'><br />
</source><br />
<br />
:注意: 'to'和'from'属性在流的根元素是可选的(OPTIONAL). 如果名字空间不正确,发起服务器必须生成一个<invalid-namespace/>流错误条件并且终止XML流和相应的TCP连接.也要注意,在这里接收服务器应该(SHOULD)应答但是可以(MAY)出于安全策略考虑只是悄悄地终止XML流和TCP连接;无论如何,如果接收服务器希望继续,它必须(MUST)回送一个流头信息给发起服务器.<br />
<br />
:4. 发起服务器发送一个回拨密钥给接收服务器:<br />
<br />
<source lang="xml"><br />
<db:result to='Receiving Server' from='Originating Server'><br />
98AF014EDC0...<br />
</db:result><br />
</source><br />
<br />
:注意: 这个密钥不由接收服务器检查,因为接收服务器在会话之间(between sessions)不保存发起服务器的信息. 这个由发起服务器生成的密钥必须(MUST)是基于接收服务器在上一步骤中提供的ID值,以及发起服务器与授权服务器共享的安全机制生成的。 如果 'to' 地址的值和接收服务器知道的主机名不匹配,接收服务器必须(MUST)生成一个<host-unknown/>流错误条件并且终止XML流和相应的TCP连接. 如果 'from' 地址和接收服务器已经建立的连接的域名相吻合,接收服务器必须(MUST)维护这个已经存在的连接,直到证明这个新的连接是合法的为止;另外,接收实体可以(MAY)选择生成一个<not-authorized/> 流错误条件给这个新的连接并且终止和新连接申请相关的XML流及相应的TCP连接.<br />
<br />
:5. 接收服务器向发起服务器声明的那个域建立一个 TCP 连接,作为结果它连接到授权服务器. (注意: 为了优化性能, 在这里一个实现可以(MAY)重用现有的连接.)<br />
<br />
:6. 接收服务器发送一个流头信息给授权服务器:<br />
<br />
<source lang="xml"><br />
<stream:stream xmlns:stream='http://etherx.jabber.org/streams' xmlns='jabber:server' xmlns:db='jabber:server:dialback'><br />
</source><br />
<br />
:注意: 'to'和'from'属性在流的根元素是可选的(OPTIONAL). 如果名字空间不正确,授权服务器必须生成一个<invalid-namespace/>流错误条件并且终止XML流和相应的TCP连接. <br />
<br />
:7. 授权服务器发送流头信息给接收服务器:<br />
<br />
<source lang="xml"><br />
<stream:stream xmlns:stream='http://etherx.jabber.org/streams' xmlns='jabber:server' xmlns:db='jabber:server:dialback' id='1251A342B...'><br />
</source><br />
<br />
:注意: 如果名字空间不正确,接收服务器必须生成一个<invalid-namespace/>流错误条件并且终止它和授权服务器之间的XML流和相应的TCP连接. 如果一个流错误发生在接收服务器和 '''授权服务器''' 之间,接收服务器必须(MUST)生成一个 <remote-connection-failed/> 流错误条件并且终止它和 '''发起服务器''' 之间的XML流和相应的TCP连接.<br />
<br />
:8. 接收服务器发送一个密钥检查请求给授权服务器:<br />
<br />
<source lang="xml"><br />
<db:verify from='Receiving Server' to='Originating Server' id='457F9224A0...'><br />
98AF014EDC0...<br />
</db:verify><br />
</source><br />
<br />
:注意: 现在这里已经有了主机名,第三步中接收服务器发送给发起服务器的ID,第四步中发起服务器发送给接收服务器的密钥. 基于这些信息, 加上授权服务器网络共享的安全信息, 这个密钥被证实了.任何可用于验证的办法都可以(MAY)用于生成密钥. 如果 'to' 地址的值和授权服务器知道的主机名不匹配,授权服务器必须(MUST)生成一个<host-unknown/>流错误条件并且终止XML流和相应的TCP连接. 打开这个连接时,如果 'from' 地址和接收服务器声明的主机名(或任何合法的域,如验证过的接收服务器的子域名或寄宿在接收服务器上的其他经过验证的域)不符,授权服务器必须(MUST)生成一个<invalid-from/>流错误条件并且终止XML流和相应的TCP连接.<br />
<br />
:9. 授权服务器检查密钥是否合法:<br />
<br />
<source lang="xml"><br />
<db:verify from='Originating Server' to='Receiving Server' type='valid' id='457F9224A0...'/><br />
</source><br />
<br />
::或<br />
<br />
<source lang="xml"><br />
<db:verify from='Originating Server' to='Receiving Server' type='invalid' id='457F9224A0...'/><br />
</source><br />
<br />
:注意: 如果 ID 和第三步中接收服务器提供的不符,接收服务器必须(MUST)生成一个<invalid-id/>流错误条件并且终止XML流和相应的TCP连接. 如果 'to' 地址的值和接收服务器知道的主机名不匹配,接收服务器必须(MUST)生成一个<host-unknown/>流错误条件并且终止XML流和相应的TCP连接. 打开这个连接时,如果 'from' 地址和发起服务器声明的主机名(或任何合法的域,如验证过的发起服务器的子域名或寄宿在发起服务器上的其他经过验证的域)不符,接收服务器必须(MUST)生成一个<invalid-from/>流错误条件并且终止XML流和相应的TCP连接. 在返回验证信息给接收服务器之后,授权服务器应该(SHOULD)终止它们之间的流.<br />
<br />
:10. 接收服务器通知发起服务器结果:<br />
<br />
<source lang="xml"><br />
<db:result from='Receiving Server'to='Originating Server' type='valid'/><br />
</source><br />
<br />
:注意: 在这一个点上, 连接已经由 type='valid' 确认验证是通过了,还是没通过. 如果连接是非法的,接收服务器必须(MUST)终止XML流和相应的TCP连接. 如果连接是合法的, 数据可以从发起服务器发送由接收服务器读取;在此之前,所有发送给接收服务器的XML节应该(SHOULD)被丢弃.<br />
<br />
:进一步的结果是,接收服务器已经验证了发起服务器的ID,所以通过初始化流("initial stream",例如从发起服务器到接收服务器的流)发起服务器可以发送,接收服务器可以接受XML节. 为了使用应答流("response stream",例如从接收服务器到发起服务器的流)验证实体ID,回拨必须(MUST)在相对的两个方向上都完成.<br />
<br />
:在成功的回拨协商之后, 接收服务器应该(SHOULD)接受接下来发起服务器通过当前的合法连接发送的 <db:result/> 包 (例如, 发送给子域或其他寄宿在接收服务器上的主机名的验证请求); 这在单一方向上激活了原始合法连接的 "piggybacking" .<br />
<br />
:即使回拨协商成功了, 服务器仍然必须(MUST)检查从其他服务器接收的所有XML节的'from'和'to'属性; 如果一个节不符合这些限定, 收到这些节的服务器必须(MUST)生成一个<improper-addressing/> 流错误条件并终止XML流和相应的TCP连接. 而且, 一个服务器也必须(MUST)检查从其他的有合法域名的服务器的流中收到的节的'from'属性; 如果一个节不符合这一限定, 接收节的服务器必须(MUST)生成一个 <invalid-from/> 流错误条件并终止XML流和相应的TCP连接. 所有这些检查都用来帮助防止特定的节伪造行为.<br />
<br />
==XML节==<br />
<br />
:在 TLS 协商(第五章) (如果想要), SASL 协商(第六章), 和资源绑定(第七章)(如果需要)之后, XML节就可以通过流发送了. 在'jabber:client'和'jabber:server'名字空间中定义了三种XML节: <message/>, <presence/>, 和 <iq/>. 另外, 这三种节有五种通用的属性. 这些通用属性, 加上三种节的术语,在这里定义; 更多关于和即时消息及出席信息应用相关的XML节语法详细信息在[XMPP-IM|XMPP文档列表/XMPP正式RFC标准/RFC3921]中提供.<br />
<br />
===通用属性===<br />
<br />
:以下五种属性通用于 message, presence, 和 IQ 节:<br />
<br />
====to====<br />
<br />
:'to' 属性表示节的预期接收者的JID.<br />
<br />
:在'jabber:client'名字空间中, 一个节应该(SHOULD)处理一个'to'属性, 尽管由服务器处理的从客户端发给服务器的节(如, 发送给服务器用于广播给其他实体的出席信息) 应该不(SHOULD NOT)处理'to'属性.<br />
<br />
:在'jabber:server'名字空间中, 一个节必须(MUST)处理一个'to'属性; 如果一个服务器收到一个不符合此限定的节, 它必须(MUST)生成一个<improper-addressing/>流错误条件并终止和这个非法服务器的XML流和相应的TCP连接.<br />
<br />
:如果'to'属性的值非法或无法联络, 发现这个事实的实体(通常是发送者或接收者的服务器)必须(MUST)返回一个适当的错误给发送者, 错误节的'from'属性设置成非法节的提供的'to'属性的值.<br />
<br />
====from====<br />
<br />
:'from' 属性表示发送者的 JID .<br />
<br />
:当一个服务器接收了一个符合'jabber:client'名字空间的合法流的XML节, 它必须(MUST)做以下步骤中的一步:<br />
<br />
:# 验证客户端提供的'from'属性值就是那个相关实体连接的资源<br />
:# 为生成这个节的已连接的资源增加一个'from'地址(由服务器决定是纯JID或全JID)(参见 地址的决定 Determination of Addresses (第三章第五节))<br />
:# 如果一个客户端试图发送一个XML节,而它的'from'属性和这个实体已连接的资源不符, 服务器应该(SHOULD)返回一个<invalid-from/>流错误条件给客户端. 如果一个客户端试图通过一个尚未验证的流发送一个XML节, 服务器应该(SHOULD)返回一个<not-authorized/>流错误条件给客户端. 如果生成了, 所有这些条件必须(MUST)导致流的关闭和相应的TCP连接的终止; 这有助于防止不诚实的客户的拒绝服务攻击.<br />
<br />
:当一个服务器从服务器自身生成一个节用于一个已连接的客户端的信息发布(例如, 在服务器为客户端提供数据存储服务的情况下), 这个节必须(MUST) (1) 不包含 'from' 属性 或 (2) 包含一个'from'属性,它的值是这个账号的纯 JID (<node@domain>) 或 客户端的全 JID (<node@domain/resource>). 如果节不是由服务器自身生成的,那么一个服务器不能(MUST NOT)发送不带'from'属性的节. 当一个客户端接收到一个不包含'from'属性的节, 它必须(MUST)认为这个节是从客户端连接的服务器发来的.<br />
<br />
:在'jabber:server'名字空间, 一个节必须(MUST)处理一个'from'属性; 如果一个服务器接收到一个不符合此限定的节, 它必须(MUST)生成一个<improper-addressing/>流错误条件. 而且, 'from'属性的 JID值的域名ID部分必须(MUST)和以SASL协商连接或以回拨协商连接的发送服务器的主机名(或任何合法的域,如发送服务器主机名的合法子域,或其他寄宿在发送服务器上的合法域)吻合; 如果一个服务器接收到的节不符合此限定, 它必须(MUST)生成一个<invalid-from/>流错误条件. 所有这些条件都必须(MUST)导致流的关闭和相应的TCP连接的终止; 这有助于防止不诚实的客户端发起的拒绝服务攻击.<br />
<br />
====id====<br />
<br />
:可选的'id' 属性可以(MAY)用于为节的内部跟踪发送实体,从IQ节 语义来讲,就是通过发送和接收这些节来跟踪“请求-应答”型的交互行为。这个可选的(OPTIONAL)'id'属性值在一个域或一个流中是全局唯一的。IQ节语义学中对此有附加限定;见IQ Semantics (第九章第二节第三小节)。<br />
<br />
====type====<br />
<br />
:'type' 属性指明消息、出席信息或IQ节的意图或上下文的详细信息。'type'属性所允许的值依据节的类型是消息、出席信息还是IQ而有很大不同; 用于消息和出席信息节的值定义在即时消息和出席信息应用中,所以在[XMPP-IM|XMPP文档列表/XMPP正式RFC标准/RFC3921]中定义,反之用于IQ节的值定义了在一个 请求\-应答 的“会话”中IQ节的角色,所以定义在IQ语义学中(第九章第二节第三小节)。 所有三种节的通用'type'值是"error";见Stanza Errors (第九章第三节)。<br />
<br />
====xml:lang====<br />
<br />
:如果一个节包含用于显示给人human user看的XML字符数据(在RFC 2277中有所解释\[CHARSET\],"internationalization is for humans"),这个节应该(SHOULD)处理一个'xml:lang'属性(定义在第二章第十二节\[XML\])。 'xml:lang'属性的值指明任何一个人类可读的XML字符数据的缺省语言, 它可以(MAY)被特定的子元素的'xml:lang'值重载。 如果一个节不处理一个'xml:lang'属性,一个实现必须(MUST)认为缺省的语言就是流属性中定义的语言(第四章第四节). 'xml:lang'属性值必须(MUST)是一个 NMTOKEN 并且必须(MUST)遵守 RFC 3066 \[LANGTAGS\]中定义的格式. <br />
<br />
===基本语义学===<br />
<br />
====消息语义学====<br />
<br />
:<message/>节类型可以被看作是一个"push"机制用于一个实体推送信息给另一个实体,类似发生在email系统中的通信. 所有消息节应该(SHOULD)处理一个表明预定的消息接收者的'to'属性;接收了这样一个节之后,一个服务器应该(SHOULD)路由或递送它给预定的接收者(见 Server Rules for Handling XML Stanzas (第十章)的XML节相关的通用路由和递送规则).<br />
<br />
====出席信息语义学====<br />
<br />
:<presence/> 元素可以被看作一个基本的广播或“出版-订阅”机制,用于多个实体接收某个已订阅的实体的信息(在这里,是网络可用性信息). 通常,一个发行实体应该(SHOULD)不带'to'属性发送一个出席信息,这时这个实体所连接的服务器应该(SHOULD)广播或多播(multiplex?)那个节给所有订阅的实体.无论如何,一个发行实体也可以(MAY)带'to'属性发送一个出席信息节,这时服务器应该(SHOULD)路由或递送这个节给预定的接收者.见 Server Rules for Handling XML Stanzas (第十章)的XML节相关的通用路由和递送规则,以及[XMPP-IM|XMPP文档列表/XMPP正式RFC标准/RFC3921]中即时消息和出席信息应用中出席信息的特定规则.<br />
<br />
====IQ语义学====<br />
<br />
:信息/查询(Info/Query),或曰IQ,是一个 请求-回应 机制,某些情况下类似\[HTTP\].IQ语义学使一个实体能够向另一个实体做出请求并做出应答. 请求和应答所包含的数据定义在IQ元素的一个直接的子元素的名字空间声明中, 并且由请求实体用'id'属性来跟踪这一交互行为. 因而,IQ交互伴随着一个结构化的数据交换的通用模式例如 get/result 或 set/result (尽管有时候会以一个错误信息应答某个请求):<br />
<br />
:以下是IQ的流程图,参见附件iq.png<br />
<br />
{image:img=iq}<br />
<br />
:为了强制执行这些语义学,要应用以下规则:<br />
<br />
:1. 对于IQ节来说'id'属性是必需的(REQUIRED).<br />
:2. 对于IQ节来说'type'属性是必需的(REQUIRED). 它的值必须(MUST)是以下之一:<br />
::* get -- 这个节是一个对信息或需求的请求.<br />
::* set -- 这个节提供需要的数据, 设置新的值, 或取代现有的值.<br />
::* result -- 这个节是一个对一个成功的 get 或 set 请求的应答.<br />
::* error -- 发生了一个错误,关于处理或递送上次发送的 get 或 set的(参见 节错误 Stanza Errors(第九章第三节)).<br />
:3. 一个接收到"get" 或 "set" 类型的IQ请求的实体必须(MUST)回复一个"result"或"error"类型的IQ应答(这个应答必须(MUST)保留相关请求的'id'属性).<br />
:4. 一个接收到"result"或"error"类型的IQ节的实体不能(MUST NOT)再发送更多的"result"或"error"类型的IQ应答; 无论如何, 如上所述, 请求实体可以(MAY)发送另一个请求(如, 一个"set"类型的IQ,通过get/result对提供查询(discovery)所需的信息).<br />
:5. 一个"get" 或 "set" 类型的IQ节必须(MUST)包含并只包含一个子元素指明特定请求或应答的语义.<br />
:6. 一个"result"类型的IQ节必须(MUST)包含零或一个子元素.<br />
:7. 一个"error"类型的IQ节应该(SHOULD)包含和"get"或"set"相关联的那个子元素并且必须(MUST)包含一个<error/>子元素;详细信息,见Stanza Errors (第九章第三节).<br />
<br />
===节错误===<br />
<br />
:节相关的错误的处理方式类似流错误(第四章第七节). 无论如何, 不像流错误, 节错误是可恢复的;所以错误节包含了暗示原来的发送者可以采取什么行动来补救这个错误.<br />
<br />
====规则====<br />
<br />
:以下规则适用于节相关的错误:<br />
<br />
:* 接收或处理实体察觉到一个节相关的错误条件时应该(MUST)返回给发送实体一个同类型的节(消息,出席信息,或IQ),这个节的'type'属性值则设置为"error"(这里这样的节称之为"error stanza").<br />
<br />
:* 生成一个错误节的实体应该(SHOULD)包含原来发送的XML,这样发送者可以检查它,并且如果必要,在尝试重新发送之前纠正它.<br />
<br />
:* 一个错误节必须(MUST)包含一个<error/>子元素.<br />
<br />
:* 如果'type'属性值不是"error"(或没有"type"属性),节不能(MUST NOT)包含一个<error/>子元素.<br />
<br />
:* 接收到一个错误节的实体不能(MUST NOT)应答这个节更多的错误节; 这有助于防止死循环.<br />
<br />
====语法====<br />
<br />
:节相关错误的语法如下:<br />
<br />
<source lang="xml"><br />
<stanza-kind to='sender' type='error'><br />
[RECOMMENDED to include sender XML here]<br />
<error type='error-type'><br />
<defined-condition xmlns='urn:ietf:params:xml:ns:xmpp-stanzas'/><br />
<text xmlns='urn:ietf:params:xml:ns:xmpp-stanzas' xml:lang='langcode'><br />
OPTIONAL descriptive text<br />
</text><br />
[OPTIONAL application-specific condition element]<br />
</error><br />
</stanza-kind><br />
</source><br />
<br />
:stanza-kind 是 message, presence, 或 iq 中的一个.<br />
<br />
:<error/> 元素的'type'属性值必须(MUST)是以下之一:<br />
<br />
:* cancel \-\- 不重试(这个错误是不可恢复的)<br />
<br />
:* continue \-\- 继续进行(这个条件只是一个警告)<br />
<br />
:* modify \-\- 改变数据之后重试<br />
<br />
:* auth \-\- 提供证书之后重试<br />
<br />
:* wait \-\- 等待之后重试(错误是暂时的)<br />
<br />
:<error/>元素:<br />
<br />
:* 必须(MUST)包含一个子元素,符合以下定义的节错误条件之一;这个元素(MUST)符合'urn:ietf:params:xml:ns:xmpp-stanzas'名字空间.<br />
<br />
:* 可以(MAY)包含一个<text/>子元素容纳XML字符数据用来描述错误的更多细节;这个元素必须(MUST)符合'urn:ietf:params:xml:ns:xmpp-stanzas'名字空间并且应该(SHOULD)处理'xml:lang'属性.<br />
<br />
:* 可以(MAY)包含一个应用程序定义的错误条件子元素;这个元素必须(MUST)符合一个应用程序定义的名字空间,并且它的结构由这个名字空间定义.<br />
<br />
:<text/>元素是可选的(OPTIONAL).如果包含它,它应该(SHOULD)仅用于提供描述或诊断信息以补充一个已定义的条件或应用程序定义的条件. 它不应(SHOULD NOT)被应用程序认为是一个程序性的. 它不应(SHOULD NOT)被用作向一个使用者展示的错误信息,但是可以(MAY)展示除条件元素(或元素们)相关的错误信息之外的信息.<br />
<br />
:最后,为了维护向后兼容性, 这个schema (定义在[XMPP-IM|XMPP文档列表/XMPP正式RFC标准/RFC3921])允许可选的在<error/>元素中包含一个("code")属性.<br />
<br />
====已定义的条件====<br />
<br />
:以下条件定义用于节错误.<br />
<br />
:* <bad-request/> -- 发送者发送的XML是不规范的或不能被处理(例如 一个IQ节包含了一个未被承认的'type'属性值); 相关的错误类型应该(SHOULD)是"modify".<br />
<br />
:* <conflict/> -- 不同意访问,因为相同的名字或地址已存在一个资源或会话;相关的错误类型应该( SHOULD)是"cancel".<br />
<br />
:* <feature-not-implemented/> -- 请求的特性未被接收者或服务器实现所以不能处理;相关的错误类型应该(SHOULD)是"cancel".<br />
<br />
:* <forbidden/> -- 请求实体没有必需的许可来执行这一动作;相关的错误类型应该(SHOULD)是"auth".<br />
<br />
:* <gone/> -- 接收者或服务器无法再以这个地址进行联系(错误节可以(MAY)在<gone/>元素的XML字符数据中包含一个新的地址);相关的错误类型应该(SHOULD)是"modify".<br />
<br />
:* <internal-server-error/> -- 服务器不能处理节,因为错误的配置或其他未定义的内部服务器错误;相关的错误类型应该(SHOULD)是"wait".<br />
<br />
:* <item-not-found/> -- JID地址或申请的条目无法找到;相关的错误类型应该(SHOULD)是"cancel".<br />
<br />
:* <jid-malformed/> -- 发送的实体提供的XMPP地址或与之通信的某个XMPP地址(如一个'to'属性值)或这个XMPP地址中的一部分(如一个资源ID)不符合寻址方案的语法(第三章);相关的错误类型应该(SHOULD)是"modify".<br />
<br />
:* <not-acceptable/> -- 接收者或服务器理解这个请求但是拒绝处理,因为它不符合某些接收者或服务器定义的标准(例如,一个关于消息中可接收的单词的本地策略);相关错误类型应该(SHOULD)是"modify".<br />
<br />
:* <not-allowed/> -- 接收者或服务器不允许任何实体执行这个动作;相关错误类型应该(SHOULD)是"cancel".<br />
<br />
:* <not-authorized/> -- 在被允许执行某个动作之前发送者必须提供适当的证书,或已提供了不正确的证书;相关错误类型应该(SHOULD)是"auth".<br />
<br />
:* <payment-required/> -- 请求实体未被授权访问请求的服务,因为需要付费;相关错误类型应该(SHOULD)是"auth".<br />
<br />
:* <recipient-unavailable/> -- 预定的接收者暂时不可用;相关错误类型应该(SHOULD)是"wait"(注意: 如果这样做会导致泄露预定接收者的网络可用性给一个未被授权了解此信息的实体,应用程序不应该(MUST NOT)返回这个错误).<br />
<br />
:* <redirect/> -- 接收者或服务器重定向这个请求信息到另一个实体,通常是暂时的(这个错误节应该 (SHOULD)在<redirect/>元素的XML字符数据中包含一个预备的地址,它必须(MUST)是一个合法的JID); 相关的错误类型应该(SHOULD)是"modify".<br />
<br />
:* <registration-required/> -- 请求实体未被授权访问请求的服务,因为需要注册;相关错误类型应该(SHOULD)是"auth".<br />
<br />
:* <remote-server-not-found/> -- 在预定的接收者的全部或部分JID中的一个远程服务器或服务不存在;相关错误类型应该(SHOULD)是"cancel".<br />
<br />
:* <remote-server-timeout/> -- 在预定的接收者(或需要完成的一个申请)的全部或部分JID中的一个远程服务器或服务无法在合理的时间内联系到;相关错误类型应该(SHOULD)是"wait".<br />
<br />
:* <resource-constraint/> -- 服务器或接收者缺乏足够的系统资源来服务请求;相关错误类型应该(SHOULD)是"wait".<br />
<br />
:* <service-unavailable/> -- 服务器或接收者目前无法提供被请求的服务;相关错误类型应该(SHOULD)是"cancel".<br />
<br />
:* <subscription-required/> -- 请求实体未被授权访问能请求的服务,因为需要订阅;相关错误类型应该(SHOULD)是"auth".<br />
<br />
:* <undefined-condition/> -- 错误条件不是本列表中定于的其他条件之一;任何错误类型可能和这个条件有关,并且它应该(SHOULD)仅用于关联一个应用程序定义的条件.<br />
<br />
:* <unexpected-request/> -- 接收者或服务器理解这个请求但是不希望是在这个时间(比如,请求的顺序颠倒);相关错误类型应该(SHOULD)是"wait".<br />
<br />
====应用程序定义条件====<br />
<br />
:大家知道,一个应用程序可以(MAY)通过在错误元素里包含一个适当名字空间的字元素来提供应用程序定义的节错误信息. 应用程序定义的元素应该(SHOULD)补充或进一步限定一个已定义的元素. 因而,<error/>元素将包含两个或三个子元素:<br />
<br />
<source lang="xml"><br />
<iq type='error' id='some-id'><br />
<error type='modify'><br />
<bad-request xmlns='urn:ietf:params:xml:ns:xmpp-stanzas'/><br />
<too-many-parameters xmlns='application-ns'/><br />
</error><br />
</iq><br />
<message type='error' id='another-id'><br />
<error type='modify'><br />
<undefined-condition xmlns='urn:ietf:params:xml:ns:xmpp-stanzas'/><br />
<text xml:lang='en' xmlns='urn:ietf:params:xml:ns:xmpp-stanzas'><br />
Some special application diagnostic information...<br />
</text><br />
<special-application-condition xmlns='application-ns'/><br />
</error><br />
</message><br />
</source><br />
<br />
==服务器处理XML节的规则==<br />
<br />
:兼容的服务器实现必须(MUST)确保两个实体之间的XML节按次序处理.<br />
<br />
:在按次序处理的需求之外, 每个服务器实现将包含它自己的递送树"delivery tree"以处理它接收到的节.这个树决定一个节是否需要路由到其他域, 在内部处理, 还是递送到和一个已连接的节点相关的资源. 以下规则适用:<br />
<br />
===没有'to'地址===<br />
<br />
:如果这个节没有'to'属性, 服务器应该(SHOULD)为发送它的实体处理这个节. 因为所有从其他服务器收到的节必须(MUST)拥有'to'属性, 这个规则仅适用于从一个连接到这台服务器的已注册实体(如一个客户端)收到的节.如果这个服务器收到一个没有'to'属性的出席信息节, 服务器应该(SHOULD)向那些订阅了这个发送实体的出席信息的所有实体广播它, 如果可能的话(即时消息和出席信息应用程序中出席信息广播的语义定义在[XMPP-IM|XMPP文档列表/XMPP正式RFC标准/RFC3921]). 如果服务器接收到一个类型为"get" 或 "set" 的没有'to'属性的节并且它理解这个节的名字空间下的内容, 它必须(MUST)为这个发送实体处理节(在这里"process"的含义是由相关的名字空间的语义所决定的)或返回一个错误给发送实体.<br />
<br />
===外部域===<br />
<br />
:如果'to'属性中的JID的域ID部分的主机名和服务器自身或其子域配置的主机名不匹配, 服务器应该(SHOULD)路由这个节到外部域(取决于本地服务规定或安全策略关于域间通信的规定).有两种可能的情况:<br />
<br />
::- 一个服务器之间的流已经存在于两个域之间: 发送者的服务器通过这个已存在的流为这个外部域路由这个节到授权服务器<br />
<br />
::- 两个域之间不存在服务器间的流: 发送者服务器 (1) 解析这个外部域的主机名(定义在服务器间的通信Server-to-Server Communications (第十四章第四节)), (2) 在两个域之间进行服务器到服务器的流协商(定义在 Use of TLS (第五章) 和 Use of SASL (第六章)), 然后 (3) 通过这个新建的流为外部域路由这个节到授权服务器<br />
<br />
:如果路由到接收者的服务器不成功, 发送者的服务器必须(MUST)返回一个错误给发送者; 如果接收者的服务器联系上了但是从接收者的服务器递送到接收者不成功, 接收者服务器必须(MUST)通过发送者的服务器返回一个错误给发送者.<br />
<br />
===子域===<br />
<br />
:如果'to'属性中的JID的域ID部分的主机名和服务器自身配置的主机名的一个子域名匹配,服务器必须(MUST)自己处理这个节或路由这个节到专门负责这个子域的特定服务(如果子域被配置了),或者返回一个错误给发送者(如果子域没有配置).<br />
<br />
===纯粹的域或特定的资源===<br />
<br />
:如果'to'属性中的JID的域ID部分的主机名和服务器自身配置的主机名本身匹配,并且'to'属性中的JID类型是<domain> 或 <domain/resource>, 服务器(或其中定于的资源)必须(MUST)根据节的类型适当的处理这个节或返回一个错误节给发送者.<br />
<br />
===同一域中的节点===<br />
<br />
:如果'to'属性中的JID的域ID部分的主机名和服务器自身配置的主机名本身匹配,并且'to'属性中的JID类型是<node@domain> 或 <node@domain/resource>, 服务器应该(SHOULD)递送这个节到节的'to'属性中的JID所指明的预定的接收者. 以下规则适用:<br />
<br />
:# 如果这个JID包含一个资源ID(例如, 格式是<node@domain/resource>)并且存在一个连接的资源符合这个全JID, 接收者服务器应该(SHOULD)递送这个节给正确符合这个资源ID的流或会话.<br />
:# 如果这个JID包含一个资源ID(例如, 格式是<node@domain/resource>)并且不存在一个连接的资源符合这个全JID, 接收者服务器应该(SHOULD)返回一个<service-unavailable/> 节错误给发送者.<br />
:# 如果这个JID的格式是<node@domain>并且存在至少一个此节点的连接资源, 接收服务器应该( SHOULD)递送这个节给至少其中一个已连接的资源, 依据应用程序定义的规则(一系列即时消息和出席信息应用程序的递送规则定义在[XMPP-IM|XMPP文档列表/XMPP正式RFC标准/RFC3921]).<br />
<br />
==XMPP中的XML用法==<br />
<br />
===限制===<br />
<br />
:XMPP是一个简单的流式XML元素的专用协议用于接近实时地交换结构化信息. 因为XMPP不需要任意的解析和所有的XML文档, 所以XMPP不需要支持\[XML\]的所有功能. 特殊的, 适用以下限制.<br />
<br />
:关于XML生成, 一个XMPP实现不能(MUST NOT)在XML流中注入以下任何东西:<br />
<br />
:* 注释 (第二章第五节[XML])<br />
<br />
:* 处理指示(第二章第六节 同上)<br />
<br />
:* 内部或外部的 DTD 子集 (第二章第八节 同上)<br />
<br />
:* 内部或外部的实体参考 (第四章第二节 同上) 除了预定实体以外(第四章第六节 同上)<br />
<br />
:* 字符数据或属性值包含和预定实体列表中吻合的未逃逸的unescaped字符(第四章第六节 同上); 这些字符必须(MUST)逃逸<br />
<br />
:关于XML处理, 如果一个XMPP实现接收到这些受限的XML数据,它必须(MUST)忽略这些数据.<br />
<br />
===XML 名字空间的名字和前缀===<br />
<br />
:XML名字空间\[XML-NAMES\]为所有XMPP兼容的XML建立数据所有权的严格界限. 这个名字空间的基本功能是把结构上混合在一起的XML元素区分出不同的词汇. 确保XMPP兼容的XML有名字空间的感知能力使得任何允许的XML可以被结构化的混合到任何XMPP数据元素中. XML名字空间的名字和前缀的规则在下一小节中.<br />
<br />
====流名字空间====<br />
<br />
:在所有的XML流头中必须声明一个流名字空间. 流名字空间必须(MUST)是 'http://etherx.jabber.org/streams'. 元素名<stream/>和它的<features/>和<error/>子元素必须(MUST)在所有实例中符合这个流名字空间前缀. 一个实现应该(SHOULD)只为这些元素生成'stream:'前缀, 并且由于历史原因可以(MAY)只接受'stream:'前缀.<br />
<br />
====缺省名字空间====<br />
<br />
:在所有的XML流中必须声明一个缺省的流名字空间用于定义允许的流根元素的一级子元素. 这个名字空间声明对于初始化流和应答流必须(MUST)是相同的使得双方的流都是合格一致的. 缺省的名字空间声明适用于流和所有在流中发送的节(除非由流名字空间或回拨名字空间的前缀显式的符合另一个名字空间).<br />
<br />
:一个服务器实现必须(MUST)支持以下两个缺省名字空间(由于历史原因, 一些实现可能(MAY)只支持这两个缺省名字空间):<br />
<br />
:* jabber:client -- 当流用于客户端和服务器的通信时声明这个缺省名字空间<br />
<br />
:* jabber:server -- 当流用于两个服务器间的通信时声明这个缺省名字空间<br />
<br />
:一个客户端实现必须(MUST)支持'jabber:client'缺省名字空间,并且由于历史原因可以(MAY)只支持这个缺省名字空间.<br />
<br />
:如果缺省名字空间是'jabber:client'或'jabber:server',一个实施不能(MUST NOT)在这个名字空间下为元素生成名字空间前缀. 一个实现不应该(SHOULD NOT)按照元素的内容(可能和流相反)生成不同于'jabber:client'和'jabber:server'名字空间前缀.<br />
<br />
:注意: 'jabber:client' 和 'jabber:server' 名字空间接近于相同但是用于不同的上下文(客户端服务器通信用'jabber:client' 而服务器间通信用'jabber:server'). 这两者之间仅有的不同在于在'jabber:client'中被发送的节中'to'和'from'属性是可选的(OPTIONAL),而在'jabber:server'中被发送的节中它们是必需的(REQUIRED). 如果兼容的实施接受一个符合'jabber:client'或'jabber:server'名字空间的流, 它必须(MUST)支持通用属性(第九章第一节)和三个核心节类型(message, presence, 和IQ)的基本语义(第九章第二节).<br />
<br />
====回拨名字空间====<br />
<br />
:所有用于服务器回拨的(第八章)元素都必须声明一个回拨名字空间. 回拨名字空间的名字必须(MUST)是'jabber:server:dialback'. 所有符合此名字空间的元素必须(MUST)有前缀. 一个实现应该(SHOULD)只为这些元素生成'db:'前缀并且只可以(MAY)接受'db:'前缀.<br />
<br />
===确认===<br />
<br />
:除了注意'jabber:server'名字空间中关于节中'to'和'from'地址的规定,一个服务器不需要为转发到客户端或其他服务器负责检查XML元素;一个实现可以(MAY)选择仅提供有效数据元素但这是可选的(OPTIONAL)(尽管一个实现不能(MUST NOT)接受不规范的XML). 客户端不应该(SHOULD NOT)滥用发送不符合schema的数据的能力, 并且应该(SHOULD)忽略接收到的XML流中任何和schema不一致的元素或属性值. XML流和节的有效性确认是可选的(OPTIONAL),并且在这里提到的schemas仅用于描述的用途.<br />
<br />
===文本声明的包含===<br />
<br />
:实现应该(SHOULD)在发送一个流头信息之前发送一个文本声明. 应用程序必须(MUST)遵守\[XML\]中关于环境(那里对文本声明做了规定)的规则.<br />
<br />
===字符编码===<br />
<br />
:实现必须(MUST)支持通用字符集Universal Character Set (ISO/IEC 10646-1 \[UCS2\])字符到UTF\-8(RFC 3629 \[UTF\-8\])的转换, 必须符合 RFC 2277 \[CHARSET\]. 实现不能(MUST NOT)试图使用任何其他的编码.<br />
<br />
==核心的兼容性要求==<br />
<br />
:本章总结了可扩展的消息和出席信息协议中的某些方面,为了实施的兼容性,它们必须(MUST)被服务器和客户端支持,当然协议的其他方面也应该(SHOULD)被支持. 为了兼容的目的, 我们在核心协议(它必须(MUST)被任何服务器或客户端支持, 无论是什么特定的应用)和即时消息协议(仅仅是在核心协议之上的即时消息和出席信息应用必须(MUST)支持它)之间划了一个级别. 在本章中定义了所有服务器和客户端的兼容性要求; 即时消息服务器和客户端的兼容性要求在[XMPP-IM|XMPP文档列表/XMPP正式RFC标准/RFC3921]的相关章节中定义.<br />
<br />
===服务器===<br />
<br />
:除了所有已定义的关于安全, XML使用, 和国际化的要求之外, 一个服务器还必须(MUST)支持以下核心协议以保证兼容性:<br />
<br />
:* 在地址中应用\[STRINGPREP\] 的 \[NAMEPREP\], Nodeprep (附录 A),和 Resourceprep (附录 B) profiles (包括确保域ID是\[IDNA\]中定义的国际化域名)<br />
<br />
:* XML流(第四章), 包括Use of TLS(第五章), Use of SASL(第六章), 和Resource Binding (第七章)<br />
<br />
:* 三个在stanza semantics(第九章第二节)中已定义的节类型(即,<message/>, <presence/>, 和<iq/>)的基本语义<br />
<br />
:* 生成错误的语法及相关的流, TLS, SASL, 和 XML节的语义<br />
<br />
:另外, 一个服务器可以(MAY)支持以下核心协议:<br />
<br />
:* 服务器回拨 (第八章)<br />
<br />
===客户端===<br />
<br />
:一个客户端必须(MUST)支持以下核心协议以满足兼容性:<br />
<br />
:* XML流(第四章), 包括Use of TLS(第五章), Use of SASL(第六章), 和Resource Binding (第七章)<br />
<br />
:* 三个在stanza semantics(第九章第二节)中已定义的节类型(即,<message/>, <presence/>, 和<iq/>)的基本语义<br />
<br />
:* 处理(并且, 如果可能, 生成) 错误的语法及相关的流, TLS, SASL, 和 XML节的语义<br />
<br />
:另外, 一个客户端应该(SHOULD)支持以下核心协议:<br />
<br />
:* 地址的生成应用\[STRINGPREP\] 的 \[NAMEPREP\], Nodeprep (附录 A),和 Resourceprep (附录 B) profiles <br />
<br />
==国际化事项==<br />
<br />
:XML流在Character Encoding(第十一章第五节)中定义为必须(MUST)被编码成UTF\-8. 在Stream Attributes(第四章第四节)中特别定义了, 一个XML流应该(SHOULD)包含一个'xml:lang'属性,它被认为是通过这个用于人类用户解读的流发送的任何XML字符数据的缺省语言. 在 xml:lang (第九章第一节第五小节)特别定义了, 如果一个XML节是用来给人类用户解读,这个节应该(SHOULD)包含一个'xml:lang'属性. 服务器在为连接的实体路由或递送节的时候应该(SHOULD)应用缺省的'xml:lang'属性, 并且不能(MUST NOT)修改或删除它从其他实体收到的节的'xml:lang'属性.<br />
<br />
==安全性事项==<br />
<br />
===高安全性===<br />
<br />
:为了XMPP通信的目的(客户端-服务器 和 服务器-服务器), "高安全性"条款谈的是相互验证和完整性检查安全性技术的使用; 特别是, 当使用基于证书的验证来提供高安全性, 应该( SHOULD)建立一个带外的信任链,尽管一个共享签名证书可能允许以前不知道的证书在带内建立信任关系. 参见以下第十四章第二节关于证书确认程序.<br />
<br />
:实施必须(MUST)支持高安全性. 服务提供者应该(SHOULD)基于本地安全策略使用高安全性.<br />
<br />
===证书确认===<br />
<br />
:当一个XMPP点和另一个XMPP点安全的地通信, 它必须(MUST)确认对方终端的证书.有三种可能的情况:<br />
<br />
:情形 #1: 点包含一个终端实体证书,以根证书的证书链中一环出现(见\[X509\]中的第六章第一节).<br />
<br />
:情形 #2: 点的证书由一个对方不知道的证书授权.<br />
<br />
:情形 #3: 点的证书由自己签名.<br />
<br />
:在情形#1, 确认方必须(MUST)做以下两条之一:<br />
<br />
:# 根据\[X509\]的规则确认对方证书.然后证书应该(SHOULD)被对方接下来在\[HTTP-TLS\]中描述的规则反向确认预期的身份。但如果"xmpp"是subjectAltName扩展类型,则必须(MUST)使用证书中的显示的身份。如果这两项检查之一失败,用户导向的客户端必须(MUST)通知用户(客户端可以(MAY)给用户机会继续连接)或以一个坏证书的错误终止连接。自动客户端应该(SHOULD)终止连接(以一个坏证书错误)并在适当的日志中记录这个错误。自动客户端可以(MAY)提供一个配置设置成禁止检查,但同时必须(MUST)提供一个激活检查的配置。<br />
:# 点应该(SHOULD)出示证书给一个用户用于批准,包括完整的证书链.点必须(MUST)缓存这个证书(或一些其他不会忘记的表达方式比如一个哈希值).在将来的连接中,点必须(MUST)展示相同的证书并且如果改变了证书必须(MUST)通知用户.<br />
<br />
:在情形#2 和情形#3, 实现应该(SHOULD)执行上述第二条.<br />
<br />
===客户端-服务器通信===<br />
<br />
:一个兼容的客户端实现必须(MUST)支持TLS和SASL用于连接到服务器.<br />
<br />
:用于加密XML流的TLS协议(在 Use of TLS(第五章)定义)提供可信的机制帮助确保机密性和实体之间数据交换的完整性.<br />
<br />
:用于验证XML流的SASL协议(在 Use of SASL(第六章)定义)提供可靠的机制用于确认一个连接到服务器的客户端确实是它自己所声明的那个客户端.<br />
<br />
:服务器宣称的DNS主机名被解析之前,客户端-服务器通信不能(MUST NOT)继续进行。应该首先尝试解析\[SRV\]记录,其服务名为"xmpp-client",协议名为"tcp",整个资源记录类似"_xmpp-client._tcp.example.com."(使用字符"xmpp-client"表示服务ID是经过IANA注册).如果SRV查找失败,退而求其次,将查找一个正规的IPv4/IPv6地址记录来决定IP地址,使用"xmpp-client"端口5222,这个端口是在IANA注册了的。<br />
<br />
:客户端的IP地址和访问方法不能(MUST NOT)被服务器公开, 也不能被被任何原始服务器之外的服务器索取。这帮助保护客户端的服务器避免受到直接攻击(译者注:似乎应该是客户避免受到直接攻击,但原文如此)或被第三方知道它的身份。<br />
<br />
===服务器-服务器通信===<br />
<br />
:一个兼容的服务器实现必须(MUST)支持TLS和SASL,用于域间的通信.因为历史原因,一个兼容的实施也应该(SHOULD)支持服务器回拨(第八章).<br />
<br />
:因为服务提供者是一个策略问题,对于任何给定域和其他域的通信中,它是可选的(OPTIONAL),服务器之间的通信可以(MAY)被任何特定部署的管理员禁止。如果一个特殊的域允许域间的通信,它应该(SHOULD)允许高安全性。<br />
<br />
:管理员可能想在服务器间使用SASL来通信,以确保双方的验证和保密性(比如在机构的私有网络).兼容实施应该(SHOULD)为这个目的支持SASL.<br />
<br />
:服务器宣称的DNS主机名被解析之前,服务器-服务器通信不能(MUST NOT)继续进行。应该首先尝试解析\[SRV\]记录,其服务名为"xmpp-server",协议名为"tcp",整个资源记录类似"_xmpp-server._tcp.example.com."(使用字符"xmpp-server"表示服务ID是经过IANA注册的,注意要用"xmpp-server"取代以前用的"jabber",因为以前的用法不符合[SRV]标准;希望保持向后兼容的实现可以继续查找或应答"jabber"服务ID).如果SRV查找失败,退而求其次,将查找一个正规的IPv4/IPv6地址记录来决定IP地址,使用"xmpp-server"端口5269,这个端口是在IANA注册了的。<br />
<br />
:服务器回拨防止域欺骗,从而使得伪造XML节更为困难.它和SASL和TLS不一样,它不是一个用于验证、安全或加密服务器之间的流的机制, 所以只是服务器身份的微弱确认而已。而且除非它使用了DNSSec \[DNSSEC\]否则它 容易受到DNS中毒攻击,即使DNS信息是正确的,如果攻击者劫持了远程域,回拨也不能防止它的攻击.需要健壮的安全性的域应该(SHOULD)使用TLS和SASL.如果服务器间的验证使用了SASL,回拨就不应该(SHOULD NOT)使用了,因为它是多余的.<br />
<br />
===层的次序===<br />
<br />
:协议中的层的次序必须(MUST)如下堆积:<br />
<br />
:# TCP<br />
:# TLS<br />
:# SASL<br />
:# XMPP<br />
<br />
:这个次序的原理是,[TCP]是基于连接的层,被所有使用,所以处于最上层, [TLS]经常是由操作系统层提供,[SASL]经常由应用程序层提供, XMPP则是应用程序本身.<br />
<br />
===缺乏绑定到TLS的SASL通道===<br />
<br />
:SASL构架不提供一个机制来绑定SASL验证到一个提供机密性和完整性保护的安全层。这一通道绑定"channel binding"的缺乏阻碍了SASL确认低层安全性所绑定的源和目标终端和SASL所验证的结果是否一致。如果终端不一致, 低层安全性不能被信任用来保护SASL验证的实体之间的数据传输。在这种情况下,一个SASL安全层进行握手的时候应该有效的忽略低层安全性的存在。<br />
<br />
===强制实现的技术===<br />
<br />
:最低要求, 所有实现必须(MUST)支持以下机制:<br />
<br />
::对于验证: SASL [DIGEST-MD5] 机制<br />
<br />
::对于机密性: TLS (使用 TLS_RSA_WITH_3DES_EDE_CBC_SHA 密码)<br />
<br />
::对于两者: TLS 加 SASL EXTERNAL(使用 TLS_RSA_WITH_3DES_EDE_CBC_SHA 密码支持客户端证书)<br />
<br />
===防火墙===<br />
<br />
:使用XMPP通信通常是通过\[TCP\]连接到5222端口(客户端-服务器)或5269端口(服务器-服务器), 正如在IANA注册的那样(见 IANA Considerations (第十五章)). 使用这些广为人知的端口允许管理员很容易的通过一般的防火墙来激活或禁止XMPP活动.<br />
<br />
===在SASL中使用base64===<br />
<br />
:客户端和服务器都必须(MUST)确认在SASL协商中收到的任何\[BASE64\]数据. 一个实现必须(MUST)拒绝(不是忽略)任何非显式允许base64字母的字符串; 这有助于预防建立隐蔽通道泄漏信息的行为。一个实现不能(MUST NOT)在非法输入处中断,如果那个('=')被包含在一些和最后的数据字符(如, "=AAA" or "BBBB=CCC")不同的东西里面,必须(MUST)拒绝接下来的任何包含('=')的base64字符;这有助于防止对这个实现的缓存溢出攻击和其他攻击。Base 64编码从外表看隐藏了容易辨认的信息,例如密码,但是不提供任何算法机密性。Base 64编码必须(MUST)按照RFC 3548\[BASE64\]第三章的定义执行。<br />
<br />
===Stringprep Profiles===<br />
<br />
:为了处理域ID,XMPP使用了\[STRINGPREP\]中的\[NAMEPREP\] profile; 和Nameprep有关的安全性考虑, 参考\[NAMEPREP\]中的相关章节.<br />
<br />
:另外, XMPP 定义了两个\[STRINGPREP\]的 profiles: 用于node identifiers的Nodeprep(附录 A)和用于resource identifiers的Resourceprep(附录 B).<br />
<br />
:Unicode 和 ISO/IEC 10646 集有许多字符看起来相似. 在许多时候, 安全协议的使用者可能看起来吻合,比如当比较信任的第三方的名字的时候. 因为没有很多上下文的时候不可能映射看起来相似的字符,比如知道所用的字符集, stringprep不匹配相似字符串,也不因为一些字符串象看起来象别的字符串而禁止它们.<br />
<br />
:一个节点ID可能被作为一个实体的XMPP地址的一部分. 一个通常的用途是作为一个即时消息用户的用户名;另一个用途是作为一个多用途聊天室的名字; 很多其他种类的实体可能使用节点ID作为他们的地址的一部分。 这些服务的安全性可能会受到国际化节点ID的不同表达的威胁;例如, 一个用户键入一个单独的国际化的节点ID可能访问了另一个用户的帐号信息, 或一个用户可能获得访问一个受限的聊天室或服务的访问权限.<br />
<br />
:一个资源ID可能被作为一个实体的XMPP地址的一部分。一个通常的用户是即时消息用户所连接的资源(激活的会话)的名字; 另一个是作为多用户聊天室的某用户的昵称; 许多其他种类的实体可能使用资源ID作为他们地址的一部分.这些服务的安全性可能会受到国际化资源ID的不同表达的威胁;例如, 一个用户可能尝试以同一个名字初始化多个会话,或一个用户可能发送一个消息给多用户聊天室的一个人但实际上发给了另外一个人.<br />
<br />
==IANA 事项==<br />
<br />
===用于TLS数据的XML名字空间名===<br />
<br />
:XMPP中用于TLS相关数据的 URN 子名字空间定义如下. (这个名字空间的名字遵守The IETF XML Registry [XML-REG]定义的格式.)<br />
<br />
::URI: urn:ietf:params:xml:ns:xmpp-tls<br />
<br />
::Specification: RFC 3920<br />
<br />
::Description: This is the XML namespace name for TLS-related data in the Extensible Messaging and Presence Protocol (XMPP) as defined by RFC 3920.<br />
<br />
::Registrant Contact: IETF, XMPP Working Group, <xmppwg@jabber.org><br />
<br />
===用于SASL数据的XML名字空间名===<br />
<br />
:XMPP中用于SASL相关数据的 URN 子名字空间定义如下. (这个名字空间的名字遵守The IETF XML Registry \[XML-REG\]定义的格式.)<br />
<br />
::URI: urn:ietf:params:xml:ns:xmpp-sasl<br />
<br />
::Specification: RFC 3920<br />
<br />
::Description: This is the XML namespace name for SASL-related data in the Extensible Messaging and Presence Protocol (XMPP) as defined by RFC 3920.<br />
<br />
::Registrant Contact: IETF, XMPP Working Group, <xmppwg@jabber.org><br />
<br />
===用于流错误的XML名字空间名===<br />
<br />
:XMPP中用于流相关错误的 URN 子名字空间定义如下. (这个名字空间的名字遵守The IETF XML Registry [XML-REG]定义的格式.)<br />
<br />
::URI: urn:ietf:params:xml:ns:xmpp-streams<br />
<br />
::Specification: RFC 3920<br />
<br />
:Description: This is the XML namespace name for stream-related error data in the Extensible Messaging and Presence Protocol (XMPP) as defined by RFC 3920.<br />
<br />
::Registrant Contact: IETF, XMPP Working Group, <xmppwg@jabber.org><br />
<br />
===用于资源绑定的XML名字空间名===<br />
<br />
:XMPP中用于资源绑定的 URN 子名字空间定义如下. (这个名字空间的名字遵守The IETF XML Registry [XML-REG]定义的格式.)<br />
<br />
::URI: urn:ietf:params:xml:ns:xmpp-bind<br />
<br />
::Specification: RFC 3920<br />
<br />
::Description: This is the XML namespace name for resource binding in the Extensible Messaging and Presence Protocol (XMPP) as defined by RFC 3920.<br />
<br />
::Registrant Contact: IETF, XMPP Working Group, <xmppwg@jabber.org><br />
<br />
===用于节错误的XML名字空间名===<br />
<br />
:XMPP中用于节相关错误数据的 URN 子名字空间定义如下. (这个名字空间的名字遵守The IETF XML Registry \[XML-REG\]定义的格式.)<br />
<br />
::URI: urn:ietf:params:xml:ns:xmpp-stanzas<br />
<br />
::Specification: RFC 3920<br />
<br />
::Description: This is the XML namespace name for stanza-related error data in the Extensible Messaging and Presence Protocol (XMPP) as defined by RFC 3920.<br />
<br />
::Registrant Contact: IETF, XMPP Working Group, <xmppwg@jabber.org><br />
<br />
===Nodeprep Profile of Stringprep===<br />
<br />
:The Nodeprep profile of stringprep是在Nodeprep(附录 A)定义的. IANA已经在stringprep profile registry中注册了 Nodeprep.<br />
<br />
::Name of this profile:<br />
<br />
:::Nodeprep<br />
<br />
::RFC in which the profile is defined:<br />
<br />
:::RFC 3920<br />
<br />
::Indicator whether or not this is the newest version of the profile:<br />
<br />
:::This is the first version of Nodeprep<br />
<br />
===Resourceprep Profile of Stringprep===<br />
<br />
:The Resourceprep profile of stringprep是在Resourceprep(附录 B)定义的. IANA已经在stringprep profile registry中注册了Resourceprep.<br />
<br />
::Name of this profile:<br />
<br />
:::Resourceprep<br />
<br />
::RFC in which the profile is defined:<br />
<br />
:::RFC 3920<br />
<br />
::Indicator whether or not this is the newest version of the profile:<br />
<br />
:::This is the first version of Resourceprep<br />
<br />
===GSSAPI 服务名===<br />
<br />
:IANA已经注册了 "xmpp" 作为一个 GSSAPI \[GSS-API\] 服务名, 在SASL Definition (第六章第三节)定义了.<br />
<br />
===端口号===<br />
<br />
:IANA已经注册了"xmpp-client" 和 "xmpp-server" 作为\[TCP\]端口号5222和5269的关键字.<br />
<br />
:这些端口应该(SHOULD)用于客户端-服务器 和 服务器-服务器通信,但它们的使用是可选的(OPTIONAL).<br />
<br />
==参考==<br />
<br />
===标准化参考===<br />
<br />
:[ABNF] Crocker, D. and P. Overell, "Augmented BNF for Syntax Specifications: ABNF", RFC 2234, November 1997.<br />
<br />
:[BASE64] Josefsson, S., "The Base16, Base32, and Base64 Data Encodings", RFC 3548, July 2003.<br />
<br />
:[CHARSET] Alvestrand, H., "IETF Policy on Character Sets and Languages", BCP 18, RFC 2277, January 1998.<br />
<br />
:[DIGEST-MD5] Leach, P. and C. Newman, "Using Digest Authentication as a SASL Mechanism", RFC 2831, May 2000.<br />
<br />
:[DNS] Mockapetris, P., "Domain names \- implementation and specification", STD 13, RFC 1035, November 1987.<br />
<br />
:[GSS-API] Linn, J., "Generic Security Service Application Program Interface Version 2, Update 1", RFC 2743, January 2000.<br />
<br />
:[HTTP-TLS] Rescorla, E., "HTTP Over TLS", RFC 2818, May 2000.<br />
<br />
:[IDNA] Faltstrom, P., Hoffman, P., and A. Costello, "Internationalizing Domain Names in Applications (IDNA)", RFC 3490, March 2003.<br />
<br />
:[IPv6] Hinden, R. and S. Deering, "Internet Protocol Version 6 (IPv6) Addressing Architecture", RFC 3513, April 2003.<br />
<br />
:[LANGTAGS] Alvestrand, H., "Tags for the Identification of Languages", BCP 47, RFC 3066, January 2001.<br />
<br />
:[NAMEPREP] Hoffman, P. and M. Blanchet, "Nameprep: A Stringprep Profile for Internationalized Domain Names (IDN)", RFC 3491, March 2003.<br />
<br />
:[RANDOM] Eastlake 3rd, D., Crocker, S., and J. Schiller, "Randomness Recommendations for Security", RFC 1750, December 1994.<br />
<br />
:[SASL] Myers, J., "Simple Authentication and Security Layer (SASL)", RFC 2222, October 1997.<br />
<br />
:[SRV] Gulbrandsen, A., Vixie, P., and L. Esibov, "A DNS RR for specifying the location of services (DNS SRV)", RFC 2782, February 2000.<br />
<br />
:[STRINGPREP] Hoffman, P. and M. Blanchet, "Preparation of Internationalized Strings ("stringprep")", RFC 3454, December 2002.<br />
<br />
:[TCP] Postel, J., "Transmission Control Protocol", STD 7, RFC 793, September 1981.<br />
<br />
:[TERMS] Bradner, S., "Key words for use in RFCs to Indicate Requirement Levels", BCP 14, RFC 2119, March 1997.<br />
<br />
:[TLS] Dierks, T. and C. Allen, "The TLS Protocol Version 1.0", RFC 2246, January 1999.<br />
<br />
:[UCS2] International Organization for Standardization, "Information Technology \- Universal Multiple-octet coded Character Set (UCS) - Amendment 2: UCS Transformation Format 8 (UTF-8)", ISO Standard 10646-1 Addendum 2, October 1996.<br />
<br />
:[UTF-8] Yergeau, F., "UTF-8, a transformation format of ISO 10646", STD 63, RFC 3629, November 2003.<br />
<br />
:[X509] Housley, R., Polk, W., Ford, W., and D. Solo, "Internet X.509 Public Key Infrastructure Certificate and Certificate Revocation List (CRL) Profile", RFC 3280, April 2002.<br />
<br />
:[XML] Bray, T., Paoli, J., Sperberg-McQueen, C., and E. Maler, "Extensible Markup Language (XML) 1.0 (2nd ed)", W3C REC-xml, October 2000, <http://www.w3.org/TR/REC-xml>.<br />
<br />
:[XML-NAMES] Bray, T., Hollander, D., and A. Layman, "Namespaces in XML", W3C REC-xml-names, January 1999, <http://www.w3.org/TR/REC-xml-names>.<br />
<br />
===信息参考===<br />
<br />
:[ACAP] Newman, C. and J. Myers, "ACAP \-\- Application Configuration Access Protocol", RFC 2244, November 1997.<br />
<br />
:[ASN.1] CCITT, "Recommendation X.208: Specification of Abstract Syntax Notation One (ASN.1)", 1988.<br />
<br />
<br />
:[DNSSEC] Eastlake 3rd, D., "Domain Name System Security Extensions", RFC 2535, March 1999.<br />
<br />
:[HTTP] Fielding, R., Gettys, J., Mogul, J., Frystyk, H., Masinter, L., Leach, P., and T. Berners-Lee, "Hypertext Transfer Protocol -- HTTP/1.1", RFC 2616, June 1999.<br />
<br />
:[IMAP] Crispin, M., "INTERNET MESSAGE ACCESS PROTOCOL - VERSION 4rev1", RFC 3501, March 2003.<br />
<br />
:[IMP-REQS] Day, M., Aggarwal, S., Mohr, G., and J. Vincent, "Instant Messaging \/ Presence Protocol Requirements", RFC 2779, February 2000.<br />
<br />
:[IRC] Oikarinen, J. and D. Reed, "Internet Relay Chat Protocol", RFC 1459, May 1993.<br />
<br />
:[JEP-0029] Kaes, C., "Definition of Jabber Identifiers (JIDs)", JSF JEP 0029, October 2003.<br />
<br />
:[JEP-0078] Saint-Andre, P., "Non-SASL Authentication", JSF JEP 0078, July 2004.<br />
<br />
[JEP-0086] Norris, R. and P. Saint-Andre, "Error Condition Mappings", JSF JEP 0086, February 2004.<br />
<br />
:[JSF] Jabber Software Foundation, "Jabber Software Foundation", <http://www.jabber.org/>.<br />
<br />
:[POP3] Myers, J. and M. Rose, "Post Office Protocol - Version 3", STD 53, RFC 1939, May 1996.<br />
<br />
:[SIMPLE] SIMPLE Working Group, "SIMPLE WG", <http://www.ietf.org/html.charters/simple-charter.html>.<br />
<br />
:[SMTP] Klensin, J., "Simple Mail Transfer Protocol", RFC 2821, April 2001.<br />
<br />
:[URI] Berners-Lee, T., Fielding, R., and L. Masinter, "Uniform Resource Identifiers (URI): Generic Syntax", RFC 2396, August 1998.<br />
<br />
:[USINGTLS] Newman, C., "Using TLS with IMAP, POP3 and ACAP", RFC 2595, June 1999.<br />
<br />
:[XML-REG] Mealling, M., "The IETF XML Registry", BCP 81, RFC 3688, January 2004.<br />
<br />
:[[RFC3921]] Saint-Andre, P., Ed., "Extensible Messaging and Presence Protocol (XMPP): Instant Messaging and Presence", RFC 3921, October 2004.<br />
<br />
<br />
==附录 A. Nodeprep==<br />
<br />
===A.1. 介绍===<br />
<br />
:这个附录定义了 "Nodeprep" profile of [STRINGPREP]. 它定义了处理规则让用户能够在XMPP中输入国际化节点标识符并尽可能正确的获取正确的字符内容. (一个XMPP节点标识符是XMPP地址的可选部分,它在域名标识符和那个'@'分隔符之前;它经常但不是专门用来关联一个即时消息用户名)这些处理规则仅仅适用于XMPP节点标识符但不适用于任意文本或任何XMPP的其他方面.<br />
<br />
:这个脚本定义了以下这些, 正如 [STRINGPREP]要求的:<br />
<br />
:* 脚本预期的适用性: XMPP的国际化节点标识符<br />
<br />
:* 用于stringprep的输入输出字符集: Unicode 3.2, 定义在本附录的第二章<br />
<br />
:* 使用的映射: 定义在第三章<br />
<br />
:* Unicode正规化使用: 定义在第四章<br />
<br />
:* 禁止输出的字符串: 定义在第五章<br />
<br />
:* 双字节字符处理: 定义在第六章<br />
<br />
===A.2. 字符集===<br />
<br />
:本脚本使用Unicode 3.2的未分配编码列表,指向 Table A.1, 也定义在 [STRINGPREP]的附录 A 中.<br />
<br />
===A.3. 映射===<br />
<br />
:本脚本指定使用[STRINGPREP]的以下表:<br />
<br />
::Table B.1<br />
<br />
::Table B.2<br />
<br />
===A.4. 正规化===<br />
<br />
:本脚本指定 Unicode正规化使用 form KC, 定义在 [STRINGPREP]中.<br />
<br />
===A.5. 禁止输出===<br />
<br />
:本脚本指定使用以下的[STRINGPREP]表禁止输出.<br />
<br />
::Table C.1.1<br />
<br />
::Table C.1.2<br />
<br />
::Table C.2.1<br />
<br />
::Table C.2.2<br />
<br />
::Table C.3<br />
<br />
::Table C.4<br />
<br />
::Table C.5<br />
<br />
::Table C.6<br />
<br />
::Table C.7<br />
<br />
::Table C.8<br />
<br />
::Table C.9<br />
<br />
:另外, 以下Unicode字符也被禁止:<br />
<br />
: #x22 (")<br />
<br />
: #x26 (&)<br />
<br />
: #x27 (')<br />
<br />
: #x2F (/)<br />
<br />
: #x3A (:)<br />
<br />
: #x3C (<)<br />
<br />
: #x3E (>)<br />
<br />
: #x40 (@)<br />
<br />
===A.6. 双字节===<br />
<br />
:本脚本指定按照[STRINGPREP]第六章检查双字节.<br />
<br />
==附录 B. Resourceprep==<br />
<br />
===B.1. 介绍===<br />
<br />
:这个附录定义了 "Resourceprep" profile of \[STRINGPREP\]. 它定义了处理规则让用户能够在XMPP中输入国际化资源标识符并尽可能正确的获取正确的字符内容. (一个XMPP资源标识符是XMPP地址的可选部分,它在域名标识符和'/@'分隔符之后;它经常但不是专门用来关联一个即时消息会话名)这些处理规则仅仅适用于XMPP资源标识符但不适用于任意文本或任何XMPP的其他方面.<br />
<br />
:这个脚本定义了以下这些, 正如 [STRINGPREP]要求的:<br />
<br />
:* 脚本预期的适用性: XMPP的国际化节点标识符<br />
<br />
:* 用于stringprep的输入输出字符集: Unicode 3.2, 定义在本附录的第二章<br />
<br />
:* 使用的映射: 定义在第三章<br />
<br />
:* Unicode正规化使用: 定义在第四章<br />
<br />
:* 禁止输出的字符串: 定义在第五章<br />
<br />
:* 双字节字符处理: 定义在第六章<br />
<br />
===B.2. 字符集===<br />
<br />
:本脚本使用Unicode 3.2的未分配编码列表,指向 Table A.1, 也定义在 [STRINGPREP]的附录<br />
<br />
===B.3. 映射===<br />
<br />
:本脚本指定使用[STRINGPREP]的以下表:<br />
<br />
::Table B.1<br />
<br />
===B.4. 正规化===<br />
<br />
:本脚本指定使用 Unicode normalization form KC, 定义在 [STRINGPREP]中.<br />
<br />
===B.5. 禁止输出===<br />
<br />
:本脚本指定使用以下的[STRINGPREP]表禁止输出.<br />
<br />
::Table C.1.2<br />
<br />
::Table C.2.1<br />
<br />
::Table C.2.2<br />
<br />
::Table C.3<br />
<br />
::Table C.4<br />
<br />
::Table C.5<br />
<br />
::Table C.6<br />
<br />
::Table C.7<br />
<br />
::Table C.8<br />
<br />
::Table C.9<br />
<br />
===B.6. 双字节===<br />
<br />
:本脚本指定按照[STRINGPREP]第六章检查双字节.<br />
<br />
==附录 C. XML 规划==<br />
<br />
:以下 XML schemas 是描述性的, 不是标准的. 'jabber:client' 和 'jabber:server' 名字空间的标准定义, 参照 [[RFC3921]].<br />
<br />
===C.1. Streams namespace===<br />
<br />
<source lang="xml"><br />
<?xml version='1.0' encoding='UTF-8'?><br />
<br />
<xs:schema<br />
xmlns:xs='http://www.w3.org/2001/XMLSchema'<br />
targetNamespace='http://etherx.jabber.org/streams'<br />
xmlns='http://etherx.jabber.org/streams'<br />
elementFormDefault='unqualified'><br />
<br />
<xs:element name='stream'><br />
<xs:complexType><br />
<xs:sequence xmlns:client='jabber:client'<br />
xmlns:server='jabber:server'<br />
xmlns:db='jabber:server:dialback'><br />
<xs:element ref='features' minOccurs='0' maxOccurs='1'/><br />
<xs:any namespace='urn:ietf:params:xml:ns:xmpp-tls'<br />
minOccurs='0'<br />
maxOccurs='unbounded'/><br />
<xs:any namespace='urn:ietf:params:xml:ns:xmpp-sasl'<br />
minOccurs='0'<br />
maxOccurs='unbounded'/><br />
<xs:choice minOccurs='0' maxOccurs='1'><br />
<xs:choice minOccurs='0' maxOccurs='unbounded'><br />
<xs:element ref='client:message'/><br />
<xs:element ref='client:presence'/><br />
<xs:element ref='client:iq'/><br />
</xs:choice><br />
<xs:choice minOccurs='0' maxOccurs='unbounded'><br />
<xs:element ref='server:message'/><br />
<xs:element ref='server:presence'/><br />
<xs:element ref='server:iq'/><br />
<xs:element ref='db:result'/><br />
<xs:element ref='db:verify'/><br />
</xs:choice><br />
</xs:choice><br />
<xs:element ref='error' minOccurs='0' maxOccurs='1'/><br />
</xs:sequence><br />
<xs:attribute name='from' type='xs:string' use='optional'/><br />
<xs:attribute name='id' type='xs:NMTOKEN' use='optional'/><br />
<xs:attribute name='to' type='xs:string' use='optional'/><br />
<xs:attribute name='version' type='xs:decimal' use='optional'/><br />
<xs:attribute ref='xml:lang' use='optional'/><br />
</xs:complexType><br />
</xs:element><br />
<br />
<xs:element name='features'><br />
<xs:complexType><br />
<xs:all xmlns:tls='urn:ietf:params:xml:ns:xmpp-tls'<br />
xmlns:sasl='urn:ietf:params:xml:ns:xmpp-sasl'<br />
xmlns:bind='urn:ietf:params:xml:ns:xmpp-bind'<br />
xmlns:sess='urn:ietf:params:xml:ns:xmpp-session'><br />
<xs:element ref='tls:starttls' minOccurs='0'/><br />
<xs:element ref='sasl:mechanisms' minOccurs='0'/><br />
<xs:element ref='bind:bind' minOccurs='0'/><br />
<xs:elemnt ref='sess:session' minOccurs='0'/><br />
</xs:all><br />
</xs:complexType><br />
</xs:element><br />
<br />
<xs:element name='error'><br />
<xs:complexType><br />
<xs:sequence xmlns:err='urn:ietf:params:xml:ns:xmpp-streams'><br />
<xs:group ref='err:streamErrorGroup'/><br />
<xs:element ref='err:text'<br />
minOccurs='0'<br />
maxOccurs='1'/><br />
</xs:sequence><br />
</xs:complexType><br />
</xs:element><br />
<br />
</xs:schema><br />
</source><br />
<br />
===C.2. Stream error namespace===<br />
<br />
<source lang="xml"><br />
<?xml version='1.0' encoding='UTF-8'?><br />
<br />
<xs:schema<br />
xmlns:xs='http://www.w3.org/2001/XMLSchema'<br />
targetNamespace='urn:ietf:params:xml:ns:xmpp-streams'<br />
xmlns='urn:ietf:params:xml:ns:xmpp-streams'<br />
elementFormDefault='qualified'><br />
<br />
<xs:element name='bad-format' type='empty'/><br />
<xs:element name='bad-namespace-prefix' type='empty'/><br />
<xs:element name='conflict' type='empty'/><br />
<xs:element name='connection-timeout' type='empty'/><br />
<xs:element name='host-gone' type='empty'/><br />
<xs:element name='host-unknown' type='empty'/><br />
<xs:element name='improper-addressing' type='empty'/><br />
<xs:element name='internal-server-error' type='empty'/><br />
<xs:element name='invalid-from' type='empty'/><br />
<xs:element name='invalid-id' type='empty'/><br />
<xs:element name='invalid-namespace' type='empty'/><br />
<xs:element name='invalid-xml' type='empty'/><br />
<xs:element name='not-authorized' type='empty'/><br />
<xs:element name='policy-violation' type='empty'/><br />
<xs:element name='remote-connection-failed' type='empty'/><br />
<xs:element name='resource-constraint' type='empty'/><br />
<xs:element name='restricted-xml' type='empty'/><br />
<xs:element name='see-other-host' type='xs:string'/><br />
<xs:element name='system-shutdown' type='empty'/><br />
<xs:element name='undefined-condition' type='empty'/><br />
<xs:element name='unsupported-encoding' type='empty'/><br />
<xs:element name='unsupported-stanza-type' type='empty'/><br />
<xs:element name='unsupported-version' type='empty'/><br />
<xs:element name='xml-not-well-formed' type='empty'/><br />
<br />
<xs:group name='streamErrorGroup'><br />
<xs:choice><br />
<xs:element ref='bad-format'/><br />
<xs:element ref='bad-namespace-prefix'/><br />
<xs:element ref='conflict'/><br />
<xs:element ref='connection-timeout'/><br />
<xs:element ref='host-gone'/><br />
<xs:element ref='host-unknown'/><br />
<xs:element ref='improper-addressing'/><br />
<xs:element ref='internal-server-error'/><br />
<xs:element ref='invalid-from'/><br />
<xs:element ref='invalid-id'/><br />
<xs:element ref='invalid-namespace'/><br />
<xs:element ref='invalid-xml'/><br />
<xs:element ref='not-authorized'/><br />
<xs:element ref='policy-violation'/><br />
<xs:element ref='remote-connection-failed'/><br />
<xs:element ref='resource-constraint'/><br />
<xs:element ref='restricted-xml'/><br />
<xs:element ref='see-other-host'/><br />
<xs:element ref='system-shutdown'/><br />
<xs:element ref='undefined-condition'/><br />
<xs:element ref='unsupported-encoding'/><br />
<xs:element ref='unsupported-stanza-type'/><br />
<xs:element ref='unsupported-version'/><br />
<xs:element ref='xml-not-well-formed'/><br />
</xs:choice><br />
</xs:group><br />
<br />
<xs:element name='text'><br />
<xs:complexType><br />
<xs:simpleContent><br />
<xs:extension base='xs:string'><br />
<xs:attribute ref='xml:lang' use='optional'/><br />
</xs:extension><br />
</xs:simpleContent><br />
</xs:complexType><br />
</xs:element><br />
<br />
<xs:simpleType name='empty'><br />
<xs:restriction base='xs:string'><br />
<xs:enumeration value=''/><br />
</xs:restriction><br />
</xs:simpleType><br />
<br />
</xs:schema><br />
</source><br />
<br />
===C.3. TLS namespace==<br />
<br />
<source lang="xml"><br />
<?xml version='1.0' encoding='UTF-8'?><br />
<br />
<xs:schema<br />
xmlns:xs='http://www.w3.org/2001/XMLSchema'<br />
targetNamespace='urn:ietf:params:xml:ns:xmpp-tls'<br />
xmlns='urn:ietf:params:xml:ns:xmpp-tls'<br />
elementFormDefault='qualified'><br />
<br />
<xs:element name='starttls'><br />
<xs:complexType><br />
<xs:sequence><br />
<xs:element<br />
name='required'<br />
minOccurs='0'<br />
maxOccurs='1'<br />
type='empty'/><br />
</xs:sequence><br />
</xs:complexType><br />
</xs:element><br />
<br />
<xs:element name='proceed' type='empty'/><br />
<xs:element name='failure' type='empty'/><br />
<br />
<xs:simpleType name='empty'><br />
<xs:restriction base='xs:string'><br />
<xs:enumeration value=''/><br />
</xs:restriction><br />
</xs:simpleType><br />
<br />
</xs:schema><br />
</source><br />
<br />
===C.4. SASL namespace===<br />
<br />
<source lang="xml"><br />
<?xml version='1.0' encoding='UTF-8'?><br />
<br />
<xs:schema<br />
xmlns:xs='http://www.w3.org/2001/XMLSchema'<br />
targetNamespace='urn:ietf:params:xml:ns:xmpp-sasl'<br />
xmlns='urn:ietf:params:xml:ns:xmpp-sasl'<br />
elementFormDefault='qualified'><br />
<br />
<xs:element name='mechanisms'><br />
<xs:complexType><br />
<xs:sequence><br />
<xs:element name='mechanism'<br />
maxOccurs='unbounded'<br />
type='xs:string'/><br />
</xs:sequence><br />
</xs:complexType><br />
</xs:element><br />
<br />
<xs:element name='auth'><br />
<xs:complexType><br />
<xs:simpleContent><br />
<xs:extension base='empty'><br />
<xs:attribute name='mechanism'<br />
type='xs:string'<br />
use='optional'/><br />
</xs:extension><br />
</xs:simpleContent><br />
</xs:complexType><br />
</xs:element><br />
<br />
<xs:element name='challenge' type='xs:string'/><br />
<xs:element name='response' type='xs:string'/><br />
<xs:element name='abort' type='empty'/><br />
<xs:element name='success' type='empty'/><br />
<br />
<xs:element name='failure'><br />
<xs:complexType><br />
<xs:choice minOccurs='0'><br />
<xs:element name='aborted' type='empty'/><br />
<xs:element name='incorrect-encoding' type='empty'/><br />
<xs:element name='invalid-authzid' type='empty'/><br />
<xs:element name='invalid-mechanism' type='empty'/><br />
<xs:element name='mechanism-too-weak' type='empty'/><br />
<xs:element name='not-authorized' type='empty'/><br />
<xs:element name='temporary-auth-failure' type='empty'/><br />
</xs:choice><br />
</xs:complexType><br />
</xs:element><br />
<xs:simpleType name='empty'><br />
<xs:restriction base='xs:string'><br />
<xs:enumeration value=''/><br />
</xs:restriction><br />
</xs:simpleType><br />
<br />
</xs:schema><br />
</source><br />
<br />
===C.5. Resource binding namespace===<br />
<br />
<source lang="xml"><br />
<?xml version='1.0' encoding='UTF-8'?><br />
<br />
<xs:schema<br />
xmlns:xs='http://www.w3.org/2001/XMLSchema'<br />
targetNamespace='urn:ietf:params:xml:ns:xmpp-bind'<br />
xmlns='urn:ietf:params:xml:ns:xmpp-bind'<br />
elementFormDefault='qualified'><br />
<br />
<xs:element name='bind'><br />
<xs:complexType><br />
<xs:choice minOccurs='0' maxOccurs='1'><br />
<xs:element name='resource' type='xs:string'/><br />
<xs:element name='jid' type='xs:string'/><br />
</xs:choice><br />
</xs:complexType><br />
</xs:element><br />
<br />
</xs:schema><br />
</source><br />
<br />
===C.6. Dialback namespace===<br />
<br />
<source lang="xml"><br />
<?xml version='1.0' encoding='UTF-8'?><br />
<br />
<xs:schema<br />
xmlns:xs='http://www.w3.org/2001/XMLSchema'<br />
targetNamespace='jabber:server:dialback'<br />
xmlns='jabber:server:dialback'<br />
elementFormDefault='qualified'><br />
<br />
<xs:element name='result'><br />
<xs:complexType><br />
<xs:simpleContent><br />
<xs:extension base='xs:token'><br />
<xs:attribute name='from' type='xs:string' use='required'/><br />
<xs:attribute name='to' type='xs:string' use='required'/><br />
<xs:attribute name='type' use='optional'><br />
<xs:simpleType><br />
<xs:restriction base='xs:NCName'><br />
<xs:enumeration value='invalid'/><br />
<xs:enumeration value='valid'/><br />
</xs:restriction><br />
</xs:simpleType><br />
</xs:attribute><br />
</xs:extension><br />
</xs:simpleContent><br />
</xs:complexType><br />
</xs:element><br />
<br />
<xs:element name='verify'><br />
<xs:complexType><br />
<xs:simpleContent><br />
<xs:extension base='xs:token'><br />
<xs:attribute name='from' type='xs:string' use='required'/><br />
<xs:attribute name='id' type='xs:NMTOKEN' use='required'/><br />
<xs:attribute name='to' type='xs:string' use='required'/><br />
<xs:attribute name='type' use='optional'><br />
<xs:simpleType><br />
<xs:restriction base='xs:NCName'><br />
<xs:enumeration value='invalid'/><br />
<xs:enumeration value='valid'/><br />
</xs:restriction><br />
</xs:simpleType><br />
</xs:attribute><br />
</xs:extension><br />
</xs:simpleContent><br />
</xs:complexType><br />
</xs:element><br />
<br />
</xs:schema><br />
</source><br />
<br />
===C.7. Stanza error namespace===<br />
<br />
<source lang="xml"><br />
<?xml version='1.0' encoding='UTF-8'?><br />
<br />
<xs:schema<br />
xmlns:xs='http://www.w3.org/2001/XMLSchema'<br />
targetNamespace='urn:ietf:params:xml:ns:xmpp-stanzas'<br />
xmlns='urn:ietf:params:xml:ns:xmpp-stanzas'<br />
elementFormDefault='qualified'><br />
<br />
<xs:element name='bad-request' type='empty'/><br />
<xs:element name='conflict' type='empty'/><br />
<xs:element name='feature-not-implemented' type='empty'/><br />
<xs:element name='forbidden' type='empty'/><br />
<xs:element name='gone' type='xs:string'/><br />
<xs:element name='internal-server-error' type='empty'/><br />
<xs:element name='item-not-found' type='empty'/><br />
<xs:element name='jid-malformed' type='empty'/><br />
<xs:element name='not-acceptable' type='empty'/><br />
<xs:element name='not-allowed' type='empty'/><br />
<xs:element name='payment-required' type='empty'/><br />
<xs:element name='recipient-unavailable' type='empty'/><br />
<xs:element name='redirect' type='xs:string'/><br />
<xs:element name='registration-required' type='empty'/><br />
<xs:element name='remote-server-not-found' type='empty'/><br />
<xs:element name='remote-server-timeout' type='empty'/><br />
<xs:element name='resource-constraint' type='empty'/><br />
<xs:element name='service-unavailable' type='empty'/><br />
<xs:element name='subscription-required' type='empty'/><br />
<xs:element name='undefined-condition' type='empty'/><br />
<xs:element name='unexpected-request' type='empty'/><br />
<br />
<xs:group name='stanzaErrorGroup'><br />
<xs:choice><br />
<xs:element ref='bad-request'/><br />
<xs:element ref='conflict'/><br />
<xs:element ref='feature-not-implemented'/><br />
<xs:element ref='forbidden'/><br />
<xs:element ref='gone'/><br />
<xs:element ref='internal-server-error'/><br />
<xs:element ref='item-not-found'/><br />
<xs:element ref='jid-malformed'/><br />
<xs:element ref='not-acceptable'/><br />
<xs:element ref='not-allowed'/><br />
<xs:element ref='payment-required'/><br />
<xs:element ref='recipient-unavailable'/><br />
<xs:element ref='redirect'/><br />
<xs:element ref='registration-required'/><br />
<xs:element ref='remote-server-not-found'/><br />
<xs:element ref='remote-server-timeout'/><br />
<xs:element ref='resource-constraint'/><br />
<xs:element ref='service-unavailable'/><br />
<xs:element ref='subscription-required'/><br />
<xs:element ref='undefined-condition'/><br />
<xs:element ref='unexpected-request'/><br />
</xs:choice><br />
</xs:group><br />
<br />
<xs:element name='text'><br />
<xs:complexType><br />
<xs:simpleContent><br />
<xs:extension base='xs:string'><br />
<xs:attribute ref='xml:lang' use='optional'/><br />
</xs:extension><br />
</xs:simpleContent><br />
</xs:complexType><br />
</xs:element><br />
<br />
<xs:simpleType name='empty'><br />
<xs:restriction base='xs:string'><br />
<xs:enumeration value=''/><br />
</xs:restriction><br />
</xs:simpleType><br />
<br />
</xs:schema><br />
</source><br />
<br />
==附录 D. 核心Jabber协议和XMPP的不同==<br />
<br />
:本章是非标准的.<br />
<br />
::译者注:附录D对于新接触XMPP的人没有什么意义,就不翻译了,免得浪费时间。因为现在RFC公布已经很久了,以前的Jabber实现很多都进化到XMPP了。<br />
<br />
:XMPP has been adapted from the protocols originally developed in the Jabber open-source community, which can be thought of as "XMPP 0.9". Because there exists a large installed base of Jabber implementations and deployments, it may be helpful to specify the key differences between the relevant Jabber protocols and XMPP in order to expedite and encourage upgrades of those implementations and deployments to XMPP. This section summarizes the core differences, while the corresponding section of [[RFC3921]] summarizes the differences that relate specifically to instant messaging and presence applications.<br />
<br />
===D.1. Channel Encryption===<br />
<br />
:It was common practice in the Jabber community to use SSL for channel encryption on ports other than 5222 and 5269 (the convention is to use ports 5223 and 5270). XMPP uses TLS over the IANA-registered ports for channel encryption, as defined under Use of TLS (Section 5) herein.<br />
<br />
===D.2. Authentication===<br />
<br />
:The client-server authentication protocol developed in the Jabber community used a basic IQ interaction qualified by the 'jabber:iq:auth' namespace (documentation of this protocol is contained in \[JEP-0078\], published by the Jabber Software Foundation [JSF]). XMPP uses SASL for authentication, as defined under Use of SASL (Section 6) herein.<br />
<br />
:The Jabber community did not develop an authentication protocol for server-to-server communications, only the Server Dialback (Section 8) protocol to prevent server poofing. XMPP supersedes Server Dialback with a true server-to-server authentication protocol, as defined under Use of SASL (Section 6) herein.<br />
<br />
===D.3. Resource Binding===<br />
<br />
:Resource binding in the Jabber community was handled via the 'jabber:iq:auth' namespace (which was also used for client authentication with a server). XMPP defines a dedicated namespace for resource binding as well as the ability for a server to generate a resource identifier on behalf of a client, as defined under Resource Binding (Section 7).<br />
<br />
===D.4. JID Processing===<br />
<br />
:JID processing was somewhat loosely defined by the Jabber community (documentation of forbidden characters and case handling is contained in [JEP-0029], published by the Jabber Software Foundation [JSF]). XMPP specifies the use of \[NAMEPREP\] for domain identifiers and supplements Nameprep with two additional [STRINGPREP] profiles for JID processing: Nodeprep (Appendix A) for node identifiers and Resourceprep (Appendix B) for resource identifiers.<br />
<br />
===D.5. Error Handling===<br />
<br />
:Stream-related errors were handled in the Jabber community via XML character data text in a <stream:error/> element. In XMPP, stream-related errors are handled via an extensible mechanism defined under Stream Errors (Section 4.7) herein. Stanza-related errors were handled in the Jabber community via HTTP-style error codes. In XMPP, stanza-related errors are handled via an extensible mechanism defined under Stanza Errors (Section 9.3) herein. (Documentation of a mapping between Jabber and XMPP error handling mechanisms is contained in \[JEP-0086\], published by the Jabber Software Foundation [JSF].)<br />
<br />
===D.6. Internationalization===<br />
<br />
:Although use of UTF-8 has always been standard practice within the Jabber community, the community did not define mechanisms for specifying the language of human-readable text provided in XML character data. XMPP specifies the use of the 'xml:lang' attribute in such contexts, as defined under Stream Attributes (Section 4.4) and xml:lang (Section 9.1.5) herein.<br />
<br />
===D.7. Stream Version Attribute===<br />
<br />
:The Jabber community did not include a 'version' attribute in stream headers. XMPP specifies inclusion of that attribute as a way to signal support for the stream features (authentication, encryption, etc.) defined under Version Support (Section 4.4.1) herein.<br />
<br />
==贡献者==<br />
<br />
:XMPP的大部分核心方面是由1999年开始的Jabber开源社区开发的. 这个社区是由 Jeremie Miller建立的, 他于1999年1月发布了最初版的jabber server源代码. 主要的基础协议的早期贡献者还包括 Ryan Eatmon, Peter Millard, Thomas Muldowney,和 Dave Smith. XMPP工作组的工作主要集中在安全性和国际化方面; 在这些领域, 使用 TLS 和 SASL 的协议最初是由 Rob Norris贡献的, stringprep profiles 最初是由 Joe Hildebrand贡献的. The error code syntax 是由Lisa Dusseault建议的.<br />
<br />
==致谢==<br />
<br />
:感谢许多在贡献者名单之外的人们. 尽管很难提供一个完整的名单, 以下个人对于定义协议或评论标准提供了很多帮助:<br />
<br />
:Thomas Charron, Richard Dobson, Sam Hartman, Schuyler Heath, Jonathan Hogg, Cullen Jennings, Craig Kaes, Jacek Konieczny, Alexey Melnikov, Keith Minkler, Julian Missig, Pete Resnick, Marshall Rose, Alexey Shchepin, Jean-Louis Seguineau, Iain Shigeoka, Greg Troxel, and David Waite. <br />
<br />
:也感谢 XMPP工作组的成员和 IETF 社区在本文的成文过程中一直提供的评论和反馈。<br />
<br />
<br />
==作者地址==<br />
<br />
:Peter Saint-Andre (editor)<br />
<br />
:Jabber Software Foundation<br />
<br />
:EMail: stpeter@jabber.org<br />
<br />
==完整的版权声明==<br />
<br />
:Copyright (C) The Internet Society (2004).<br />
<br />
:This document is subject to the rights, licenses and restrictions contained in BCP 78, and except as set forth therein, the authors retain all their rights. This document and the information contained herein are provided on an "AS IS" basis and THE CONTRIBUTOR, THE ORGANIZATION HE/S HE REPRESENTS OR IS SPONSORED BY (IF ANY), THE INTERNET SOCIETY AND THE INTERNET ENGINEERING TASK FORCE DISCLAIM ALL WARRANTIES, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO ANY WARRANTY THAT THE USE OF THE INFORMATION HEREIN WILL NOT INFRINGE ANY RIGHTS OR ANY IMPLIED WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE.<br />
<br />
==Intellectual Property==<br />
<br />
:The IETF takes no position regarding the validity or scope of any Intellectual Property Rights or other rights that might be claimed to pertain to the implementation or use of the technology described in this document or the extent to which any license under such rights might or might not be available; nor does it represent that it has made any independent effort to identify any such rights. Information on the IETF's procedures with respect to rights in IETF Documents can be found in BCP 78 and BCP 79. Copies of IPR disclosures made to the IETF Secretariat and any assurances of licenses to be made available, or the result of an attempt made to obtain a general license or permission for the use of such proprietary rights by implementers or users of this specification can be obtained from the IETF on-line IPR repository at http://www.ietf.org/ipr. The IETF invites any interested party to bring to its attention any copyrights, patents or patent applications, or other proprietary rights that may cover technology that may be required to implement this standard. Please address the information to the IETF at ietf-ipr@ietf.org.<br />
<br />
==感谢==<br />
<br />
:目前为RFC编辑活动提供资金的Internet Society.</div>
Snowqiang
http://wiki.jabbercn.org/RFC3920
RFC3920
2011-05-18T08:20:44Z
<p>Snowqiang: </p>
<hr />
<div>[[Category:XMPP正式RFC标准]]<br />
[[Category:已翻译]]<br />
<br />
"本文的英文原文来自[http://www.ietf.org/rfc/rfc3920.txt RFC 3920]<br />
<br />
{|<br />
|网络工作组 || P. Saint-Andre, Ed.<br />
|-<br />
|申请讨论: 3920 || Jabber软件基金会<br />
|-<br />
|类别: 标准跟踪 || 2004年10月<br />
|}<br />
<br />
<br />
<br />
:::'''可扩展的消息和出席信息协议 (XMPP): 核心协议'''<br />
<br />
'''关于本文的说明'''<br />
<br />
:本文为互联网社区定义了一个互联网标准跟踪协议,并且申请讨论协议和提出了改进的建议。请参照“互联网官方协议标准”的最新版本(STD 1)获得这个协议的标准化进程和状态。本文可以不受限制的分发。<br />
<br />
'''版权声明'''<br />
<br />
:本文版权属于互联网社区 (C) The Internet Society (2004).<br />
<br />
'''摘要'''<br />
<br />
:本文定义了可扩展消息和出席信息协议(XMPP)的核心功能,这个协议采用XML流实现在任意两个网络终端接近实时的交换结构化信息。XMPP提供一个通用的可扩展的框架来交换XML数据,它主要用来建立即时消息和出席信息应用以实现 RFC 2779 的需求。 <br />
<br />
==绪论==<br />
<br />
===概览===<br />
<br />
:XMPP是一个开放式的XML协议,设计用于准实时消息和出席信息以及请求-响应服务。其基本的语法和语义最初主要是由Jabber开放源代码社区于1999年开发的。2002年,XMPP工作组被授权接手开发和改编Jabber协议以适应IETF的即时消息和出席信息技术。作为XMPP工作组的成果,本文定义了 XMPP 1.0 的核心功能;在 RFC 2779 [IMP-REQS] 中指定的提供即时消息和出席信息功能的扩展,定义在 XMPP-IM 协议 [the Extensible Messaging and Presence Protocol (XMPP): Instant Messaging and Presence] 中。<br />
<br />
===术语===<br />
<br />
:本文中大写的关键字 "MUST(必须)", "MUST NOT(不能)", "REQUIRED(必需)", "SHALL(将会)", "SHALL NOT(将不会)", "SHOULD(应该)", "SHOULD NOT(不应该)", "RECOMMENDED(建议)", "MAY(可以)", 和 "OPTIONAL(可选)" 的确切含义符合 BCP 14, RFC 2119 \[TERMS\].<br />
<br />
==通用的架构==<br />
<br />
===概览===<br />
<br />
:尽管XMPP没有指定任何特定的网络结构,但它通常是采用客户-服务器 架构进行实现,其中客户端通过TCP方式使用XMPP访问服务器,服务器之间也采用TCP方式进行通信。<br />
<br />
:以下是这一架构的抽象的示意图 (这里 "-" 表示使用 XMPP 通讯, "=" 表示可使用任何协议通讯)。<br />
<br />
<br />
::C1----S1---S2---C3<br />
<br />
::::|<br />
<br />
::C2----+---G1===FN1===FC1<br />
<br />
:符号的含义如下:<br />
<br />
::* C1, C2, C3 = XMPP 客户端<br />
<br />
::* S1, S2 = XMPP 服务器<br />
<br />
::* G1 = 一个XMPP和外部(非XMPP)消息网络之间进行“翻译”的网关<br />
<br />
::* FN1 = 一个外部消息网络<br />
<br />
::* FC1 = 外部消息网络上的一个客户端<br />
<br />
===服务器===<br />
<br />
:服务器充当XMPP通信的一个智能抽象层,它主要负责:<br />
<br />
:* 对受验证的客户端,服务器以及其他实体之间以XML流形式的连接和会话进行管理。<br />
<br />
:* 在这些实体间使用XML流对合理编址的XML节(第九章)进行路由<br />
<br />
:大部分 XMPP 兼容的服务器也负责存储客户端使用的数据 (比如基于XMPP协议的及时消息应用中的联系人名单); 在这种情况下, XML 数据直接服务器来处理,而不需要转发到其他实体。<br />
<br />
===客户端===<br />
<br />
:大部分客户端通过 TCP 连接直接连到服务器,并通过XMPP获得由服务器以及联合服务器所提供的全部功能。多个不同资源(比如不同的设备和地点)的客户端'''可以'''同时登陆并且并发的连接到一个服务器,每个不同资源的客户端通过XMPP地址的资源标识符来区分(比如<node@domain/ home> 和 <node@domain/work>),参见地址空间(第三章)。'''建议'''的客户端和服务器连接的端口是 5222 ,这个端口已经在 IANA(在第十五章第九节查阅端口号码) 注册了。<br />
<br />
===网关===<br />
<br />
:网关是一个特殊用途的服务器端的服务,主要功能是把 XMPP 翻译成外部(非XMPP)消息系统,并把返回的消息翻译成 XMPP 。例如到 email(参见 [SMTP] ),IRC(参见 [IRC] ),SIMPLE(参见 [SIMPLE] ),SMS 的网关;还有和别的消息服务的网关,比如AIM,ICQ,MSN Messenger,Yahoo! Instant Messenger。网关和服务器之间的通信,网关和外部消息系统的通信,不在本文描述范围之内。<br />
<br />
===网络===<br />
<br />
:因为每个服务器都是由一个网络地址来标识的并且服务器之间的通信是 客户-服务器 协议的直接扩展,实际上整个系统是由很多互通的服务器构成的。例如,<juliet@example.com> 可以和 <romeo@example.net> 交换消息,出席信息和其他信息。这种模式常见于那些需要使网络地址标准化的协议(比如 SMTP )。任意两个服务器之间的通信是可选(OPTIONAL)的。如果被激活,那么这种通信应该(SHOULD)通过 XML 流绑定到 TCP 连接上进行。建议的(RECOMMENDED)服务器之间的连接端口为 5269 ,这个端口号已经在 IANA (在第十五章第九节查阅端口号码)注册了。<br />
<br />
==地址空间==<br />
<br />
===概览===<br />
<br />
:一个实体可以是任何一个被认为是一个网络端点的东西(例如网络上的一个 ID ),而且它是通过XMPP进行通信的。所有这些实体都有一个具有唯一性的地址,并符合 RFC 2396 [URI]规范要求的格式。由于历史原因,一个 XMPP 实体的地址被称为 Jabber Identifier 或 JID 。一个合法的 JID 包括一组排列好的元素,包括域名(domain identifier),节点名(node identifier),和资源名(resource identifier)。<br />
<br />
:JID的语法定义,使用 [ABNF] 中的 Augmented Backus-Naur 格式。(IPv4 地址和 IPv6地址规则在 附录B 中的 [IPv6] 中定义;确定节点规则的合法字符顺序由 附录A 的 [STRINGPREP] 的 Nodeprep 部分来定义;确定资源规则的合法字符顺序由 附录B 的 [STRINGPREP] 的Resourceprep 部分来定义;子域名规则参考 [IDNA] 中关于国际域名标签的描述。)。<br />
<br />
::jid = [ node "@" ] domain [ "/" resource ]<br />
<br />
::domain = fqdn / address-literal<br />
<br />
::fqdn = (sub-domain 1*("." sub-domain))<br />
<br />
::sub-domain = (internationalized domain label)<br />
<br />
::address-literal = IPv4address / IPv6address<br />
<br />
:所有 JID 都是基于上述的结构。类似 <user@host/resource> 这种结构,最常用来标识一个即时消息用户,这个用户所连接的服务器,以及这个用户用于连接的资源(比如特定类型的客户端软件)。不过,节点类型不是客户端也是有可能的,比如一个用来提供多用户聊天服务的特定的聊天室,地址可以是 <room@service> (这里 “room“ 是聊天室的名字而 ”service“ 是多用户聊天服务的主机名),而加入了这个聊天室的某个特定的用户的地址则是 <room@service/nick> (这里 ”nick“ 是用户在聊天室的昵称)。许多其他的 JID 类型都是可能的(例如 <domain/resource> 可能是一个服务器端的脚本或服务)。<br />
<br />
:一个 JID 的每个合法部分(节点名,域名,资源名)的长度不能(MUST NOT)超过 1023 字节。也就是整体长度(包括 '@' 和 '/' )不能超过 3071 字节。<br />
<br />
===域名===<br />
<br />
:域名是一个主要的ID并且是 JID 中唯一必需(REQUIRED)的元素(一个纯粹的域名也是一个合法的 JID)。它通常代表网络的网关或者“主”服务器,其他实体通过连接它来实现 XML 转发和数据管理功能。然而,由一个域名标识引用的实体,并非总是一个服务器,它也可能是一个服务器的子域地址,提供额外的功能(比如多用户聊天服务,用户目录,或一个到外部消息系统的网关)。<br />
<br />
:每个服务器或者服务的域名,可以(MAY)是一个 IP 地址,但应该(SHOULD)是一个完全合法的域名(参见 [DNS]).一个域名ID必须(MUST)是 [IANA] 里定义的“国际化域名”,并且按 [STRINGPREP]中的 [NAMEPREP] profile进行成功的字符转换。在比较两个域名ID之前,服务器必须(MUST),客户端应该(SHOULD)首先按照Nameprep profile(定义在[IANA]中) 来转换每个域名的字符。<br />
<br />
===节点名===<br />
<br />
:节点名是一个可选(OPTIONAL)的第二 ID,放在域名之前并用符号"@"分开.它通常表示一个向服务器或网关请求和使用网络服务的实体(比如一个客户端),当然它也能够表示其他的实体(比如在多用户聊天系统中的一个房间). 节点名所代表的实体,它的地址依赖于一个特定的域名;在 XMPP 的即时消息和出席信息应用系统中,这个地址是“纯 JID” <node@domain> 中的一部分。<br />
<br />
:一个节点名必须按 \[STRINGPREP\] 中的 Nodeprep profile 进行成功的字符转换。在比较两个节点ID之前,服务器必须(MUST),客户端应该(SHOULD)首先按 Nodeprep profile 转换每个ID的字符。<br />
<br />
===资源名===<br />
<br />
:资源名是一个可选的第三 ID,它放在域名的后面并由符号"/"分开。资源名可以跟在 <node@domain>后面也可以跟在 <domain> 后面。它通常表示一个特定的会话,连接(比如设备或者所在位置),或者一个附属于某个节点ID实体相关实体的对象(比如多用户聊天室中的一个参加者)。对于服务器和和其他客户端来说,资源名是不透明的。当它提供必需的信息以完成资源绑定(参见第七章)的时候,通常是由客户端来实现的(尽管可以由客户端向服务器请求完成),然后显示为“已连接的资源”。一个实体可以(MAY)并发维护多个已连接的资源。每个已连接的资源由不同的资源ID来区分。<br />
<br />
:一个资源名必须(MUST)按 \[STRINGPREP\] 中的 Resourceprep profile 进行成功的格式化。在比较两个资源ID之前,服务器必须(MUST),客户端应该(SHOULD)首先按 Resourceprep profile 转换每个ID的字符。<br />
<br />
===地址的确认===<br />
<br />
:在 SASL (见第六章)握手之后(如果必要的话,也在资源绑定(见第七章)之后),正在接收流信息的实体必须(MUST)确认初始实体的 ID 。<br />
<br />
:对于服务器间的通信,在 SASL 握手时,如果没有指明授权的ID,这个初始的实体应该(SHOULD)是经过认证实体(参见 简单认证和安全层协议 \[SASL\] 中的定义)授权的ID(见第六章)。<br />
<br />
:对于客户端和服务器的通信,在 SASL 握手时,如果没有指明授权的ID,“纯 JID” (<node@domain>)应该(SHOULD)是经过认证实体(参见 [SASL] 中的定义)授权的ID,“全 JID” (<node@domain/resource>)的资源ID部分应该(SHOULD)是由客户端和服务器在资源绑定的时候商定的(参见第七章)。<br />
<br />
:接收的实体必须(MUST)确保结果JID(包括节点名,域名,资源名以及分隔符)与本章前面部分描述的规则和格式相一致;为了满足这些约束条件,接收实体可能(MAY)需要把初始实体的发送方 JID 替换成接收实体认可的规范 JID。<br />
<br />
==XML流==<br />
<br />
===概览===<br />
<br />
:两个基本概念,XML流和XML节,使得在出席信息已知的实体之间,异步交换低负载的结构化信息成为可能。这两个术语定义如下:<br />
<br />
:XML流的定义:一个XML流是一个容器,包含了两个实体之间通过网络交换的XML元素。一个XML流是由一个XML打开标签 <stream> (包含适当的属性和名字空间声明)开始的,流的结尾则是一个XML关闭L标签 </stream> 。在流的整个生命周期,初始化它的实体可以通过流发送大量的XML元素,用于流的握手(例如 TLS 握手(第五章) 或 SASL 握手(第六章))或XML节(在这里指符合缺省名字空间的元素,包括<message/>,<presence/>, 或 <iq/> 元素)。“初始的流”由初始化实体(通常是一个客户端或服务器)和接收实体(通常是一个服务器)握手,从接收实体来看,它就是那个初始实体的"会话".初始化流允许从初始化实体到接收实体的单向通信;为了使接收实体能够和初始实体交换信息,接收实体必须发起一个反向的握手(应答流).<br />
<br />
:XML节的定义: 一个XML节是一个实体通过 XML 流向另一个实体发送的结构化信息中的一个离散的语义单位。一个XML节直接存在于根元素<stream/>的下一级,这样可以说是很好的匹配了[XML](译者注:在标准参考一节)的第43条.任何XML节都是从一个XML流的下一级的某个打开标签(如 <presence>)开始,到相应的关闭标签(如 </presence>)。一个XML节可以(MAY)包含子元素(相关的属性,元素, 和 XML 字符数据等) 以表达完整的信息.在这里定义的XML节仅限于<message/>, <presence/>, 和 <iq/> 元素,具体描述间见 XML Stanzas(第九章);为TLS握手(第五章)、SASL握手(第六章)、服务器回拨(第八章)的需要而发送的XML元素,不被认为是一个XML节。<br />
<br />
:设想一个客户端和服务器会话的例子。为了连接一个服务器,一个客户端必须(MUST)发送一个打开标签<stream>给服务器,初始化一个XML流,也可选择(OPTIONAL)在这之前发送一段文本声明XML版本和支持的字符集(参见文本声明的内容(第十一章第四节); 也可看字符编码(第十一章第五节))。视本地化策略和提供的服务而定,服务器应该(SHOULD)回复一个XML流给客户端,同样的,也可选择在这之前发送一段文本声明。一旦客户端完成了SASL握手(第六章),客户端可以(MAY)通过流发送不限量的XML节给网络中的任何接收者。当客户端想关闭这个流,它只需要简单的发送一个关闭标签</stream>给服务器(或者作为另一个选择,可能由服务器关闭这个流)。然后,客户端和服务器都应该(SHOULD)彻底地终止这个连接(通常是一个TCP连接)。<br />
<br />
:那些习惯认为XML是一个以文本为中心风格的人可能希望看看一个与服务器连接的客户端会话,包含两个 打开-关闭 XML文档:一个是从客户端到服务器,一个是从服务器到客户端。下图中,根元素<stream/> 可以被认为是每个“文档”的文档实体,这两个“文档”通过累积那些在XML上传输的XML节来搭建的。无论如何,下图只是方便理解;实际上XMPP并不处理文档而是处理XML流和XML节。<br />
<br />
:基本上,一个XML流相当于一个会话期间所有XML节的一个信封。我们可以简单的把它描述成下图:<br />
<br />
::|----------------------------<br />
<br />
::| <stream><br />
<br />
::|----------------------------<br />
<br />
::| <presence> <br />
<br />
::| <show/> <br />
<br />
::| </presence><br />
<br />
::|----------------------------<br />
<br />
::| <message to='foo'> <br />
<br />
::| <body/> <br />
<br />
::| </message> <br />
<br />
::|----------------------------<br />
<br />
::| <iq to='bar'><br />
<br />
::| <query/> <br />
<br />
::| </iq> <br />
<br />
::|----------------------------<br />
<br />
::| ... <br />
<br />
::|----------------------------<br />
<br />
::| </stream> <br />
<br />
::|----------------------------<br />
<br />
===绑定到TCP===<br />
<br />
:虽然有很多非必需的连接使用XML流来绑定\[TCP\]连接(两个实体可以通过别的机制来互联,比如通过\[HTPP\]连接轮询),本规范只定义了 XMPP 到 TCP 的绑定。在客户和服务器通信的过程中,服务器必须(MUST)允许客户端共享一个TCP连接来传输XML节,包括从客户端传到服务器和从服务器传到客户端。在服务器之间的通信过程中,服务器必须(MUST)用一个 TCP连接 向对方发送 XML节,另一个 TCP连接(由对方初始化)接收对方的XML节,一共两个 TCP连接。<br />
<br />
===流的安全===<br />
<br />
:在XMPP 1.0中,当XML流开始握手时,TLS应该(SHOULD)按 第五章:TLS的使用 中的规定来使用,SASL必须(MUST)按 第六章:SASL的使用 中的规定来使用。尽管可能(MAY)存在某种共有的机制能够保证双向安全,但是“初始化流”(比如从初始化实体发给接收实体的流)和“应答流”(比如从接收实体发给初始化实体的流)还是必须(MUST)安全的分开。在流被验证之间,实体不应该(SHOULD NOT) 尝试通过流发送XML节(第九章);就算它这样做了,对方的实体也不能(MUST NOT)接受这些XML节,并且应该(SHOULD)返回一个 <not-authorized/> 的流错误信息并且终止当前TCP连接上双方的XML流;注意,这仅仅是针对XML节(包含在缺省命名空间中的 <message/>, <presence/>, 和 <iq/> 元素),而不是指那些用于 TLS握手(第五章)、SASL握手(第六章)握手的流。<br />
<br />
===stream 属性===<br />
<br />
:stream 元素的属性如下:<br />
<br />
:* to -- 'to' 属性应(SHOULD)仅出现在初始化实体发给接收实体的 XML 流的头当中,并且它的值必须(MUST)是接收实体所在的主机名。在接收实体发送给初始化实体的 XML 流的头中不应该(SHOULD NOT)出现 'to' 属性。若 'to' 属性出现在应答流中,则初始化实体应(SHOULD)忽略它。<br />
<br />
:* from -- 'from' 属性应(SHOULD)仅出现在接收实体发给初始化实体的 XML 流的头当中,并且它的值必须(MUST)是为当前初始化实体授权的接收实体所在的主机名。注意,不应该(SHOULD NOT)有 'from'属性出现在初始实体发送给接收实体的 XML流的头中;无论如何,如果'from'属性出现在初始化流中,接收实体应该(SHOULD)忽略它。<br />
<br />
:* id -- 'id'属性应该(SHOULD)仅用于接收实体发送给初始化实体 XML流的头。这个属性是一个由接收实体创建的具有唯一性的ID,一个初始实体和接收实体之间的会话ID,并且它在接收方的应用程序中(通常是一个服务器)必须(MUST)是唯一的。注意,这个流 ID 必须是足够安全的,所以它必须是不可预知的和不可重复的(参见[RANDOM] 了解如何获得随机性以保证安全性)。不应该(SHOULD NOT)有 'id'属性出现在初始实体发送给接收实体的 XML流的头中;无论如何,如果'id'属性出现在初始化流中,接收实体应该(SHOULD)忽略它。<br />
<br />
:* xml:lang -- 'xml:lang'属性(定义在\[XML\]中的第二章第十二节)应该(SHOULD)包含在初始化实体发给接收实体的 XML流的头中,以指定在流中传输的可读XML字符所使用的缺省语言。如果这个属性出现了,接收实体应该(SHOULD)记住它的值,作为初始化流和应答流的缺省属性;如果这个属性没有出现,接收实体应该(SHOULD)用一个可配置的缺省值用于双方的流,这个属性值必须(MUST)在应答流的头中传达。对于所有初始化流中传输的节,如果初始实体没有提供'xml:lang'属性,接收实体应该(SHOULD)应用缺省值;如果初始实体提供了'xml:lang'属性,接收实体不能(MUST NOT)修改或删除它(参见第九章第一节第五小节 xml:lang)。'xml:lang'属性的值必须(MUST)是一个 NMTOKEN (定义在\[XML\]的第二章第三节) 并且必须(MUST)遵守 RFC 3066 \[LANGTAGS\] 规定的格式。<br />
<br />
:* version -- version属性(最少需要"1.0")为本规范中和流相关的协议提供了支持。关于这个属性的生成和处理的详细规则将在下文中定义。<br />
<br />
:我们现在可以总结如下:<br />
<br />
{|border="1" cellspacing="0" <br />
! !! 初始化方发给接收方 !! 接收方发给初始化方<br />
|-<br />
|to || 接收方的主机名 || 忽略<br />
|-<br />
|from || 忽略 || 接收方的主机名<br />
|-<br />
|id || 忽略 || 会话键值<br />
|-<br />
|xml:lang || 缺省语言 || 缺省语言<br />
|-<br />
|version || 支持XMPP 1.0 || 支持XMPP 1.0<br />
|}<br />
<br />
====版本支持====<br />
<br />
:在这里XMPP的版本是"1.0";准确地说,这里囊括了和流相关的所有协议(TLS的使用 (第五章),SASL的使用(第六章), 和流错误(第四章第七节)),以及三个定义好的XML节类型(<message/>,<presence/>,和 <iq/>)。XMPP版本号的编号顺序是“<主版本号>.<副版本号>”。主版本和副版本号必须(MUST)是独立的整数并且每个号码可以(MAY)单独以阿拉伯数字增长。这样,"XMPP 2.4"的版本将比"XMPP 2.13"更低。号码前面 的“0”(比如XMPP 6.01)必须(MUST)被接收方忽略并且不能(MUST NOT)被发送出去.<br />
<br />
:如果流和节的格式或者必需的处理方式有了显著的改变,以至于老版本的实体如果只是简单的忽略它不理解的节和属性并且继续像老版本一样的处理方式,会使得老版本的实体不能够和新版本的实体交互,只有在这时候主版本号才应该(SHOULD)增加。副版本号显示新的性能,它必须(MUST)被副版本号更低的实体忽略,但被高(副)版本号的实体用于了解信息。例如,一个副版本号显示处理某种新定义的"type"属性的值(用于message,presence或IQ节)的能力;副版本号高的实体将会了解到与之通信的对方不能够理解这个"type"属性的值,所以将不会发送它。<br />
<br />
:以下规则是用于'版本'属性在实现流的头信息时如何生成和处理:<br />
<br />
:# 初始化实体必须(MUST)在初始化流的头信息中把'版本'的值设置成它所支持的最高版本。(比如,如果最高版本支持就是本规范,那么它必须(MUST)设置成"1.0").<br />
:# 接收实体必须(MUST)在应答流的头信息中把'版本'的值设置成初始化实体所提供的版本或它所支持的最高版本,取其中版本号较低的那一个。接收实体必须(MUST)把主版本号和副版本号作为数字来比较,而不是对"主版本号.副版本号"这个字符串进行比较.<br />
:# 如果在应答流的头信息的版本号中至少有一个主版本号低于初始化流的头信息的版本号,并且如前所述,新版本的实体不能够和旧版本实体交互,初始化实体应该(SHUOULD)生成一个<unsupported-version/>的流错误信息并终止XML流和它的TCP连接。<br />
:# 如果一个实体收到一个头信息中没有'version'属性的流,这个实体必须(MUST)把对方实体的'version'当成'0.0'并且在它发送的应答流的头中也不应该(SHOULD NOT)包含'version'属性.<br />
<br />
===名字空间声明===<br />
<br />
:流的元素必须(MUST)同时满足一个流名字空间声明和一个缺省名字空间声明("名字空间声明"定义在 XML 名字空间定义 \[XML-NAMES\]中).关于流名字空间和缺省名字空间的详细信息,参考 名字空间的名字和前缀(第十一章第二节).<br />
<br />
===流的特性===<br />
<br />
:如果初始化的实体在初始化流的头信息中设置'version'属性的信息为"1.0",接收实体必须(MUST)向初始化实体发送一个 <features/> 子元素以声明任何可供协商的流一级的特性(或者其他需要声明的能力).目前,这仅用于声明本文中定义的 TLS的使用(第五章),SASL的使用(第六章)和资源绑定(第七章),以及 [XMPP-IM|XMPP文档列表/XMPP正式RFC标准/RFC3921] 中定义的会话的建立;无论如何,流特性这一功能将来可以用于声明任何可协商的特性.如果一个实体不理解或支持安全特性,它应该(SHOULD)忽略它.如果要在一个非安全相关的特性(比如资源绑定)被提议之前,完成一个或多个安全特性(比如TLS和SASL)的协商,这个非安全相关的特性不应该(SHOULD NOT)在相应的安全特性协商完毕之前被声明.<br />
<br />
===流错误===<br />
<br />
:流的根元素可以(MAY)包含一个 <error/> 子元素,由流的名字空间前缀作为它的前缀。这个"错误"子元素必须(MUST)由感知到发生了流级别错误的实体发送(通常是一个服务器而不是一个客户端)。<br />
<br />
====规则====<br />
<br />
:以下规则适用于流级别的错误:<br />
<br />
:* 它假定所有流级别的错误都是不可恢复的;所以,如果一个错误发生在流级别,发现这个错误的实体必须(MUST)发送一个流错误信息给另一个实体,发送一个关闭标签 </stream>,并终止这个流所在的TCP连接。<br />
<br />
:* 如果这个错误发生在流刚开始设置的时候,接收实体必须(MUST)仍然发送一个开放标签 <stream> ,并在流元素中包含一个<error/>的子元素,然后发送一个关闭标签 </stream>,最后终止相应的TCP连接。在这种情况下,如果初始化实体在 'to' 属性中提供了一个未知的主机名,服务器应该(SHOULD)在终止之前,先在流的头信息的 'from' 属性中提供一个服务器认证的主机名.<br />
<br />
====语法====<br />
<br />
:流错误的语法如下:<br />
<br />
<source lang="xml"><br />
<stream:error><br />
<defined-condition xmlns='urn:ietf:params:xml:ns:xmpp-streams'/><br />
<text xmlns='urn:ietf:params:xml:ns:xmpp-streams' xml:lang='langcode'><br />
OPTIONAL descriptive text<br />
</text><br />
[OPTIONAL application-specific condition element]<br />
</stream:error><br />
</source><br />
<br />
:<error/>元素:<br />
:* 必须(MUST)包含一个子元素以描述一个下文定义的节错误条件;这个子元素必须(MUST)符合'urn:ietf:params:xml:ns:xmpp-streams'名字空间.<br />
<br />
:* 可以(MAY)包含一个 <text/> 子元素,用XML字符数据描述错误的细节;这个元素必须(MUST)符合'urn:ietf:params:xml:ns:xmpp-streams'名字空间并且应该(SHOULD)拥有一个'xml:lang'属性表明XML字符数据的自然语言。<br />
<br />
:* 可以(MAY)包含一个子元素用于描述一个明确的应用程序错误条件;这个元素必须(MUST)符合一个应用程序定义的名字空间,并且它的结构是由那个名字空间定义的。<br />
<br />
: <text/> 元素是可选的(OPTIONAL)。如果有这个元素,它应该(SHOULD)仅用于提供描述或调试信息以补充一个已定义的条件或应用程序定义的条件。它不应该(SHOULD NOT)被一个应用程序当成一个可编程的信息。它不应该(SHOULD NOT)被用于向用户表达错误信息,但是可以(MAY)作为和条件元素相关的错误信息之外的附加说明。<br />
<br />
====已定义的条件====<br />
<br />
:以下流级别的错误条件是已定义的:<br />
<br />
:* <bad-format/> -- 实体已经发送XML但是不能被处理;这个错误可以(可以)被更多特定的XML相关的错误替换,比如 <bad-namespace-prefix/>, <invalid-xml/>, <restricted-xml/>, <unsupported-encoding/>, 以及 <xml-not-well-formed/>,尽管更多特定的错误是首选的。 <br />
<br />
:* <bad-namespace-prefix/> -- 实体发送的名字空间前缀不被支持,或者在一个需要某种前缀的元素中没有发送一个名字空间前缀(参见 XML Namespace Names and Prefixes (第十一章第二节)).<br />
<br />
:* <conflict/> -- 服务器正在关闭为这个实体激活的流,因为一个和已经存在的流有冲突的新的流已经被初始化。<br />
<br />
:* <connection-timeout/> -- 实体已经很长时间没有通过这个流发生任何通信流量(可由一个本地服务策略来配置).<br />
<br />
:* <host-gone/> -- 初始化实体在流的头信息中提供的'to'属性的值所指定的主机已经不再由这台服务器提供<br />
<br />
:* <host-unknown/> -- 由初始化实体在流的头信息中提供的 'to' 属性的值和由服务器提供的主机名不一致.<br />
<br />
:* <improper-addressing/> -- 一个在两台服务器之间传送的节缺少 'to' 或 'from' 属性(或者这个属性没有值).<br />
<br />
:* <internal-server-error/> -- 服务器配置错误或者其他未定义的内部错误,使得服务器无法提供流服务.<br />
<br />
:* <invalid-from/> -- 在'from'属性中提供的 JID 或 主机名地址,和认证的 JID不匹配 或服务器之间无法通过SASL(或回拨)协商出合法的域名,或客户端和服务器之间无法通过它进行认证和资源绑定。<br />
<br />
:* <invalid-id/> -- 流 ID 或回拨 ID 是非法的或和以前提供的 ID 不一致.<br />
<br />
:* <invalid-namespace/> -- 流名字空间和 "http://etherx.jabber.org/streams" 不相同或回拨名字空间和 "jabber:server:dialback" 不相同.(参考 XML Namespace Names and Prefixes (第十一章第二节)).<br />
<br />
:* <invalid-xml/> -- 实体通过流发送了一个非法的XML给执行验证的服务器 (参考 Validation (第十一章第三节)).<br />
<br />
:* <not-authorized/> -- 实体试图在流被验证之前发送数据或不被许可执行一个和流协商有关的动作,接收实体在发送错误信息之前不允许(MUST NOT)处理厌恶的节。<br />
<br />
:* <policy-violation/> -- 实体违反了某些本地服务策略;服务器可以(MAY)选择在 <text/> 元素或应用程序定义的错误条件(元素)中详细说明策略。<br />
<br />
:* <remote-connection-failed/> -- 服务器无法正确连接到用于验证或授权的远程实体。<br />
<br />
:* <resource-constraint/> -- 服务器缺乏必要的系统资源为流服务。<br />
<br />
:* <restricted-xml/> -- 实体试图发送受限的XML特性,比如一个注释,处理指示,DTD,实体参考,或保留的字符(参考 Restrictions (第十一章第一节)).<br />
<br />
:* <see-other-host/> -- 服务器将不提供服务给初始化实体但是把它重定向到另一台主机;服务器应该(SHOULD)在<see-other-host/>元素的XML字符数据中指明替代服务器名或IP地址(它必须(必须)是合法的域名标识)。<br />
<br />
:* <system-shutdown/> -- 服务器正在关机并且所有激活的流正在被关闭。<br />
<br />
:* <undefined-condition/> -- 错误条件不在本文已定义的错误条件列表之中;这个错误条件应该(SHOULD)仅用于"应用程序定义条件"元素.<br />
<br />
:* <unsupported-encoding/> -- 初始化实体以一个服务器不不支持的编码方式编码了一个流(参照Character Encoding (第十一章第五节)).<br />
<br />
:* <unsupported-stanza-type/> -- 初始化实体发送了一个流的一级子元素但是服务器不支持.<br />
<br />
:* <unsupported-version/> -- 由初始化实体在流的头信息中指定的'version'属性的值所指定的版本不被服务器支持;服务器可以(MAY)在<text/>元素中指定一个它支持的版本号.<br />
<br />
:* <xml-not-well-formed/> -- 初始化实体发送了一个不规范的XML(参考[XML]).<br />
<br />
====应用程序定义条件====<br />
<br />
:大家知道,应用程序可以(MAY)在error元素中包含一个适当名字空间的子元素来提供一个应用程序定义流错误信息."应用程序定义"元素应该(SHOULD)补充或甚至限定一个已定义的元素.所以 <error/> 元素将包含两个或三个子元素:<br />
<br />
<source lang="xml"><br />
<stream:error><br />
<xml-not-well-formed xmlns='urn:ietf:params:xml:ns:xmpp-streams'/><br />
<text xml:lang='en' xmlns='urn:ietf:params:xml:ns:xmpp-streams'><br />
Some special application diagnostic information!<br />
</text><br />
<escape-your-data xmlns='application-ns'/><br />
</stream:error><br />
</stream:stream><br />
</source><br />
<br />
===简化的流示例===<br />
<br />
:这里包含两个简化的例子,描述了基于流的客户端在服务器上的“会话”(这里"C"表示从客户端发给服务器,"S"表示从服务器发给客户端);这些例子只是用于举例说明原理.<br />
<br />
:一个基本的 "会话":<br />
<br />
<source lang="xml"><br />
C: <?xml version='1.0'?><br />
<stream:stream to='example.com' xmlns='jabber:client' xmlns:stream='http://etherx.jabber.org/streams' version='1.0'><br />
<br />
S: <?xml version='1.0'?><br />
<stream:stream from='example.com' id='someid' xmlns='jabber:client' xmlns:stream='http://etherx.jabber.org/streams' version='1.0'><br />
... encryption, authentication, and resource binding ...<br />
<br />
C: <message from='juliet@example.com' to='romeo@example.net' xml:lang='en'><br />
<br />
C: <body>Art thou not Romeo, and a Montague?</body><br />
<br />
C: </message><br />
<br />
S: <message from='romeo@example.net' to='juliet@example.com' xml:lang='en'><br />
<br />
S: <body>Neither, fair saint, if either thee dislike.</body><br />
<br />
S: </message><br />
<br />
C: </stream:stream><br />
<br />
S: </stream:stream><br />
</source><br />
<br />
<br />
:一个不成功的 "会话" :<br />
<br />
<source lang="xml"><br />
C: <?xml version='1.0'?><br />
<stream:stream to='example.com' xmlns='jabber:client' xmlns:stream='http://etherx.jabber.org/streams' version='1.0'><br />
<br />
S: <?xml version='1.0'?><br />
<stream:stream from='example.com' id='someid' xmlns='jabber:client' xmlns:stream='http://etherx.jabber.org/streams' version='1.0'><br />
... encryption, authentication, and resource binding ...<br />
<br />
C: <message xml:lang='en'><br />
<body>Bad XML, no closing body tag!<br />
</message><br />
<br />
S: <stream:error><br />
<xml-not-well-formed xmlns='urn:ietf:params:xml:ns:xmpp-streams'/><br />
</stream:error><br />
<br />
S: </stream:stream><br />
</source><br />
<br />
==TLS 的使用==<br />
<br />
===概览===<br />
<br />
:XMPP包含的一个保证流安全的方法来防止篡改和偷听.这个传输层安全协议[TLS]的频道加密方法, 模拟了类似的其他"STARTTLS"(见RFC 2595 [USINGTLS])的扩展,如 IMAP [IMAP], POP3 [POP3], and ACAP [ACAP]."STARTTLS"的扩展名字空间是'urn:ietf:params:xml:ns:xmpp-tls'.<br />
<br />
:一个给定域的管理员可以(MAY)要求客户端和服务器通信以及服务器之间通信时使用TLS,或者两者都要求。客户端应该(SHOULD)在尝试完成 SASL (第六章)握手之前使用 TLS,服务器应该(SHOULD)在两个域之间使用 TLS 以保证服务器间通信的安全。<br />
<br />
:以下是使用规则:<br />
<br />
::# 一个遵守本协议的初始化实体必须(MUST)在初始化流的头信息中包含一个'version'属性并把值设为“1.0”。<br />
::# 如果TLS握手发生在两个服务器之间,除非服务器声称的DNS主机名已经被解析(见第十四章第四节 Server-to-Server Communications),通信不能(MUST NOT)继续进行。<br />
::# 当一个遵守本协议的接收实体接收了一个初始化流(它的头信息中包含一个'version'属性并且值设为“1.0”),在发送应答流的的头信息(其中包含版本标记)之后,它必须发送(MUST)<starttls/>元素(名字空间为 'urn:ietf:params:xml:ns:xmpp-tls')以及其他它支持的流特性 。<br />
::# 如果初始化实体选择使用TLS,TLS握手必须在SASL握手之前完成;这个顺序用于帮助保护SASL握手时发送的认证信息的安全,同时可以在必要的时候在TLS握手之前为SASL外部机制提供证书。<br />
::# TLS握手期间,一个实体不能(MUST NOT)在流的根元素中发送任何空格符号作为元素的分隔符(在下面的TLS示例中的任何空格符都仅仅是为了便于阅读);这个禁令用来帮助确保安全层字节精度。<br />
::# 接收实体必须(MUST)在发送<proceed/> 元素的关闭符号">" 之后立刻开始TLS协商。初始化实体必须(MUST)在从接收实体接收到<proceed/> 元素的关闭符号">" 之后立刻开始TLS协商。<br />
::# 初始化实体必须(MUST)验证接收实体出示的证书;关于证书验证流程参见Certificate Validation ( 第十四章第二节)。<br />
::# 证书必须(MUST)检查初始化实体(比如一个用户)提供的主机名;而不是通过DNS系统解析出来的主机名;例如,如果用户指定一个主机名"example.com"而一个DNS SRV [SRV]查询返回"im.example.com",证书必须(MUST)检查"example.com".如果任何种类的XMPP实体(例如客户端或服务器)的JID出现在一个证书里,它必须(MUST)表现为一个别名实体里面的UTF8字符串,存在于subjectAltName之中。如何使用 [ASN.1] 对象标识符 "id-on-xmppAddr" 定义在本文的第五章第一节第一小节。<br />
::# 如果 TLS 握手成功了,接收实体必须(MUST) 丢弃TLS 生效之前从初始化实体得到的任何不可靠的信息.<br />
::# 如果 TLS 握手成功了,初始化实体必须(MUST) 丢弃TLS 生效之前从接收实体得到的任何不可靠的信息. <br />
::# 如果 TLS 握手成功了,接收实体不能(MUST NOT)在流重新开始的时候通过提供其他的流特性来向初始化实体提供 STARTTLS 扩展.<br />
::# 如果 TLS 握手成功了,初始化实体必须(MUST)继续进行SASL握手。<br />
::# 如果 TLS 握手失败了,接收实体必须(MUST)终止XML流和相应的TCP连接。<br />
::# 关于必须(MUST)支持的机制,参照 Mandatory-to-Implement Technologies (第十四章第七节) 。<br />
<br />
====用于 XMPP 地址的 ASN.1 对象标识符====<br />
<br />
:上文提到的[ASN.1] 对象标识符 "id-on-xmppAddr"定义如下:<br />
<br />
::id-pkix OBJECT IDENTIFIER ::= { iso(1) identified-organization(3)<br />
<br />
::dod(6) internet(1) security(5) mechanisms(5) pkix(7) }<br />
<br />
::id-on OBJECT IDENTIFIER ::= { id-pkix 8 } \-\- other name forms<br />
<br />
::id-on-xmppAddr OBJECT IDENTIFIER ::= { id-on 5 }<br />
<br />
::XmppAddr ::= UTF8String<br />
<br />
:对象标识符也可以(MAY)使用点分隔的格式,如 "1.3.6.1.5.5.7.8.5".<br />
<br />
===叙述===<br />
<br />
:当一个初始化实体用TLS保护一个和接收实体之间的流,其步骤如下:<br />
<br />
::# 初始化实体打开一个TCP连接,发送一个打开的XML流头信息(其'version'属性设置为"1.0")给接收实体以初始化一个流。<br />
::# 接收实体打开一个TCP连接,发送一个XML流头信息(其'version'属性设置为"1.0")给初始化实体作为应答。<br />
::# 接收实体向初始化实体提议STARTTLS范围(包括其他支持的流特性),如果TLS对于和接收实体交互是必需的,它应该(SHOULD)在<starttls/>元素中包含子元素<required/>.<br />
::# 初始化实体发出STARTTLS命令(例如, 一个符合'urn:ietf:params:xml:ns:xmpp-tls'名字空间的 <starttls/> 元素) 以通知接收实体它希望开始一个TLS握手来保护流。<br />
::# 接收实体必须(MUST)以'urn:ietf:params:xml:ns:xmpp-tls'名字空间中的<proceed/>元素或<failure/>元素应答。如果失败,接收实体必须(MUST)终止XML流和相应的TCP连接。如果继续进行,接收实体必须(MUST)尝试通过TCP连接完成TLS握手并且在TLS握手完成之前不能(MUST NOT)发送任何其他XML数据。<br />
::# 初始化实体和接收实体尝试完成TLS握手。(要符合\[TLS\]规范)<br />
::# 如果 TLS 握手不成功, 接收实体必须(MUST)终止 TCP 连接. 如果 TLS 握手成功, 初始化实体必须(MUST)发送给接收实体一个打开的XML流头信息来初始化一个新的流(先发送一个关闭标签</stream>是不必要的,因为接收实体和初始化实体必须(MUST)确保原来的流在TLS握手成功之后被关闭) 。<br />
::# 在从初始化实体收到新的流头信息之后,接收实体必须(MUST)发送一个新的XML流头信息给初始化实体作为应答,其中应包含可用的特性但不包含STATRTTLS特性。<br />
<br />
===客户端-服务器 示例===<br />
<br />
:以下例子展示一个客户端使用STARTTLS保护数据流 (注意: 以下步骤举例说明协议中的失败案例;在这个例子中它们并不详尽并且也不是必须被数据传输触发的).<br />
<br />
:步骤 1: 客户端初始化流给服务器:<br />
<br />
<source lang="xml"><br />
<stream:stream xmlns='jabber:client' xmlns:stream='http://etherx.jabber.org/streams' to='example.com' version='1.0'><br />
</source><br />
<br />
:步骤 2: 服务器发送一个流标签给客户端作为应答:<br />
<br />
<source lang="xml"><br />
<stream:stream xmlns='jabber:client' xmlns:stream='http://etherx.jabber.org/streams' id='c2s_123' from='example.com' version='1.0'><br />
</source><br />
<br />
:步骤 3: 服务器发送 STARTTLS 范围给客户端(包括验证机制和任何其他流特性):<br />
<br />
<source lang="xml"><br />
<stream:features><br />
<starttls xmlns='urn:ietf:params:xml:ns:xmpp-tls'><br />
<required/><br />
</starttls><br />
<mechanisms xmlns='urn:ietf:params:xml:ns:xmpp-sasl'><br />
<mechanism>DIGEST-MD5</mechanism><br />
<mechanism>PLAIN</mechanism><br />
</mechanisms><br />
</stream:features><br />
</source><br />
<br />
:步骤 4: 客户端发送 STARTTLS 命令给服务器:<br />
<br />
<source lang="xml"><br />
<starttls xmlns='urn:ietf:params:xml:ns:xmpp-tls'/><br />
</source><br />
<br />
:步骤 5: 服务器通知客户端可以继续进行:<br />
<br />
<source lang="xml"><br />
<proceed xmlns='urn:ietf:params:xml:ns:xmpp-tls'/><br />
</source><br />
<br />
:步骤 5 (或者): 服务器通知客户端 TLS 握手失败并关闭流和TCP连接:<br />
<br />
<source lang="xml"><br />
<failure xmlns='urn:ietf:params:xml:ns:xmpp-tls'/><br />
</stream:stream><br />
</source><br />
<br />
:步骤 6: 客户端和服务器尝试通过已有的TCP连接完成 TLS 握手.<br />
<br />
:步骤 7: 如果 TLS 握手成功, 客户端初始化一个新的流给服务器:<br />
<br />
<source lang="xml"><br />
<stream:stream xmlns='jabber:client' xmlns:stream='http://etherx.jabber.org/streams' to='example.com' version='1.0'><br />
</source><br />
<br />
:步骤 7 (或者): 如果 TLS 握手不成功, 服务器关闭 TCP 连接.<br />
<br />
:步骤 8: 服务器发送一个流头信息应答客户端,其中包括任何可用的流特性:<br />
<br />
<source lang="xml"><br />
<stream:stream xmlns='jabber:client' xmlns:stream='http://etherx.jabber.org/streams' from='example.com' id='c2s_234' version='1.0'><br />
<stream:features><br />
<mechanisms xmlns='urn:ietf:params:xml:ns:xmpp-sasl'><br />
<mechanism>DIGEST-MD5</mechanism><br />
<mechanism>PLAIN</mechanism><br />
<mechanism>EXTERNAL</mechanism><br />
</mechanisms><br />
</stream:features><br />
</source><br />
<br />
:步骤 9: 客户端继续 SASL 握手 (第六章).<br />
<br />
===服务器-服务器示例===<br />
<br />
:以下例子展示两个服务器之间使用STARTTLS保护数据流 (注意: 以下步骤举例说明协议中的失败案例;在这个例子中它们并不详尽并且也不是必须被数据传输触发的).<br />
<br />
:步骤 1: Server1 初始化流给 Server2:<br />
<br />
<source lang="xml"><br />
<stream:stream xmlns='jabber:server' xmlns:stream='http://etherx.jabber.org/streams' to='example.com' version='1.0'><br />
</source><br />
<br />
:步骤 2: Server2 发送一个流标签给 Server1 作为应答:<br />
<br />
<source lang="xml"><br />
<stream:stream xmlns='jabber:server' xmlns:stream='http://etherx.jabber.org/streams' from='example.com' id='s2s_123' version='1.0'><br />
</source><br />
<br />
:步骤 3: Server2 发送 STARTTLS 范围给 Server1 ,包括验证机制和任何其他流特性:<br />
<br />
<source lang="xml"><br />
<stream:features><br />
<starttls xmlns='urn:ietf:params:xml:ns:xmpp-tls'><br />
<required/><br />
</starttls><br />
<mechanisms xmlns='urn:ietf:params:xml:ns:xmpp-sasl'><br />
<mechanism>DIGEST-MD5</mechanism><br />
<mechanism>KERBEROS_V4</mechanism><br />
</mechanisms><br />
</stream:features><br />
</source><br />
<br />
:步骤 4: Server1 发送 STARTTLS 命令给 Server2:<br />
<br />
<source lang="xml"><br />
<starttls xmlns='urn:ietf:params:xml:ns:xmpp-tls'/><br />
</source><br />
<br />
:步骤 5: Server2 通知 Server1 允许继续进行:<br />
<br />
<source lang="xml"><br />
<proceed xmlns='urn:ietf:params:xml:ns:xmpp-tls'/><br />
</source><br />
<br />
:步骤 5 (或者): Server2 通知 Server1 TLS握手失败并关闭流:<br />
<br />
<source lang="xml"><br />
<failure xmlns='urn:ietf:params:xml:ns:xmpp-tls'/><br />
</stream:stream><br />
</source><br />
<br />
:步骤 6: Server1 和 Server2 尝试通过 TCP 完成 TLS 握手.<br />
<br />
:步骤 7: 如果 TLS 握手成功, Server1 初始化一个新的流给 Server2:<br />
<br />
<source lang="xml"><br />
<stream:stream xmlns='jabber:server' xmlns:stream='http://etherx.jabber.org/streams' to='example.com' version='1.0'><br />
</source><br />
<br />
:步骤 7 (或者): 如果 TLS 握手不成功, Server2 关闭 TCP 连接.<br />
<br />
:步骤 8: Server2 发送一个包含任何可用流特性的流头信息给 Server1 :<br />
<br />
<source lang="xml"><br />
<stream:stream xmlns='jabber:server' xmlns:stream='http://etherx.jabber.org/streams' from='example.com' id='s2s_234' version='1.0'><br />
<stream:features><br />
<mechanisms xmlns='urn:ietf:params:xml:ns:xmpp-sasl'><br />
<mechanism>DIGEST-MD5</mechanism><br />
<mechanism>KERBEROS_V4</mechanism><br />
<mechanism>EXTERNAL</mechanism><br />
</mechanisms><br />
</stream:features><br />
</source><br />
<br />
:步骤 9: Server1 继续进行 SASL 握手(第六章).<br />
<br />
==SASL 的使用==<br />
<br />
===概览===<br />
<br />
:XMPP 有一个验证流的方法,即XMPP特定的SASL(简单验证和安全层)\[SASL\]。SASL提供了一个通用的方法为基于连接的协议增加验证支持,而XMPP使用了一个普通的XML名字空间来满足SASL的需要。<br />
<br />
:以下规则应用于:<br />
<br />
:# 如果SASL协商发生在两台服务器之间,除非服务器宣称的DNS主机名得到解析,不能(MUST NOT)进行通信。(参见 服务器间的通信(第十四章第四节)).<br />
:# 如果初始化实体有能力使用 SASL 协商, 它必须(MUST)在初始化流的头信息中包含一个值为"1.0"的属性'version'。<br />
:# 如果接收实体有能力使用 SASL 协商, 它必须(MUST)在应答从初始化实体收到的打开流标签时(如果打开的流标签包含一个值为"1.0"的'version'属性),通过'urn:ietf:params:xml:ns:xmpp-sasl'名字空间中的<mechanisms/>元素声明一个或多个验证机制.<br />
:# 当 SASL 协商时, 一个实体不能(MUST NOT)在流的根元素中发送任何空格符号(匹配 production \[3\] content of \[XML\])作为元素之间的分隔符(在以下的SASL例子中任何空格符号的出现仅仅是为了增加可读性); 这条禁令帮助确保安全层字节的精确度。<br />
:# 当SASL握手时,在XML元素中使用的任何 XML 字符数据必须被编码成 base64, 编码遵循 RFC 3548 第三章的规定。<br />
:# 如果一个 简单名字"simple username" 规范被选定的SASL机制所支持,(比如, 这被 DIGEST-MD5 和 CRAM-MD5 机制支持但不被 EXTERNAL 和 GSSAPI 机制支持), 验证的时候初始化实体应该(SHOULD)在服务器间通信时提供 简单名字 自身的发送域(IP地址或包含在一个域标识符中的域名全称),在客户端与服务器之间通信时提供注册用户名(包含在一个XMPP节点标识符中的用户或节点名)。<br />
:# 如果初始化实体希望以另一个实体的身份出现并且SASL机制支持授权ID的传输,初始化实体在SASL握手时必须(MUST)提供一个授权ID。如果初始化实体不希望以另一个实体的身份出现,初始化实体在SASL握手时不能(MUST NOT)提供一个授权ID。在 \[SASL\] 的定义中,除非授权ID不同于从验证ID(详见\[SASL\])中得到的缺省的授权ID,初始化实体不能(MUST NOT)提供授权ID。如果提供了,这个授权ID的值必须(MUST)是<domain>的格式(对于服务器来说)或<node@domain>的格式(对于客户端来说). <br />
:# 在成功进行包括安全层的SASL握手之后,接收实体必须(MUST)丢弃任何从初始化实体得到的而不是从SASL协商本身获得的信息。<br />
:# 在成功进行包括安全层的SASL握手之后,初始化实体必须(MUST)丢弃任何从接收实体得到的而不是从SASL协商本身获得的信息。<br />
:# 参看 强制执行的技术 (第十四章第七届) ,了解关于必须(MUST)支持的机制.<br />
<br />
===叙述===<br />
<br />
:一个初始化实体使用SASL和接收实体做验证的步骤如下:<br />
<br />
:# 初始化实体请求SASL验证,它发送一个打开的XML流头信息给接收实体,其'version'属性的值为"1.0".<br />
:# 在发送一个XML流头回复之后,接收实体声明一个可用的SASL验证机制清单;每个机制作为一个<mechanism/>元素,作为子元素包含在<mechanisms/>容器元素(其名字空间为'urn:ietf:params:xml:ns:xmpp-sasl')中,而<mechanisms/>则包含在流名字空间中的<features/>元素中。如果在使用任何验证机制之前需要使用TLS(见第五章),接收实体不能(MUST NOT)在TLS握手之前提供可用的SASL验证机制清单。如果初始化实体在优先的TLS协商过程中呈现了一个合法的证书,接收实体应该(SHOULD)在SASL握手中提出一个SASL外部机制给初始化实体,尽管这个外部机制可以(MAY)在其它环境下提供。<br />
:# 初始化实体发送一个符合'urn:ietf:params:xml:ns:xmpp-sasl'名字空间的<auth/>元素(其中包含了适当的'mechanism'属性值)给接收实体,以选择一个机制。如果这个机制支持或需要,这个元素可以(MAY)包含XML字符数据(在SASL术语中,即“初始化应答”);如果初始化实体需要发送一个零字节的初始化应答,它必须(MUST)传输一个单独的等号作为应答,这表示应答有效但不包含数据。<br />
:# 如果必要,接收实体向初始化实体发送一个符合'urn:ietf:params:xml:ns:xmpp-sasl'名字空间的<challenge/>元素来发出挑战;这个元素可以(MAY)包含XML字符数据(必须按照初始化实体选择的SASL机制进行一致性运算)。<br />
:# 初始化实体向接收实体发送符合'urn:ietf:params:xml:ns:xmpp-sasl'名字空间的<response/>元素作为应答;这个元素可以(MAY)包含XML字符数据(必须按照初始化实体选择的SASL机制进行一致性运算)。<br />
:# 如果必要,接收实体发送更多的挑战给初始化实体,初始化实体发送更多的回应。<br />
<br />
:这一系列的 挑战/应答 组,持续进行直到发生以下三件事中的一件为止:<br />
<br />
:# 初始化实体向接收实体发送符合'urn:ietf:params:xml:ns:xmpp-sasl'名字空间的<abort/>元素以中止握手。在接收到<abort/>元素之后,接收实体应该(SHOULD)允许一个可配置的但是合理的重试次数(至少2次),然后它必须(MUST)终止TCP连接;这使得初始化实体(如一个最终用户客户端)能够容忍可能不正确的credentials(如密码输入错误)而不用强制重新连接。<br />
:# 接收实体向初始化实体发送符合'urn:ietf:params:xml:ns:xmpp-sasl'名字空间的<failure/>元素以报告握手失败(详细的失败原因应该在<failure/>的一个适当的子元素中沟通,在第六章第四节中的SASL Errors中定义)。如果失败的情况发生了,接收实体应该(SHOULD)允许一个可配置的但是合理的重试次数(至少2次), 然后它必须(MUST)终止TCP连接;这使得初始化实体(如一个最终用户客户端)能够容忍可能不正确的credentials(如密码输入错误)而不用强制重新连接。<br />
:# 接收实体向初始化实体发送符合'urn:ietf:params:xml:ns:xmpp-sasl'名字空间的<success/>元素以报告握手成功;如果所选择的SASL机制要求,这个元素可以(MAY)包含XML字符数据(见SASL术语,“成功的额外数据”)。接收到<success/> 元素之后,初始化实体必须(MUST)发送一个打开的XML流头信息给接收实体以发起一个新的的流(不需要先发送一个 </stream>标签,因为在发送和接收到<success/>元素之后,接收实体和初始化实体必须确认原来的流被关闭了)。从初始化实体接收到新的流头信息之后,接收实体必须(MUST)发送一个新的流头信息给初始化实体作为回应,附上任何可用的特性(但不包括 STARTTLS 和 SASL 特性)或一个空的 <features/> 元素(这表示没有更多的特性可用);任何没有在本文定义的附加特性必须(MUST)在XMPP的相关扩展中定义。<br />
<br />
===SASL 定义===<br />
<br />
:[SASL]的必要条件要求通过协议定义来提供以下信息:<br />
<br />
::service name(服务名): "xmpp"<br />
<br />
::initiation sequence(开始序列): 当初始化实体提供一个打开的XML流头信息并且接收实体善意回应之后,接收实体提供一个可接受的验证方法清单。初始化实体从这个清单中选择一个方法,把它作为 <auth/> 元素的 'mechanism' 属性的值发送给接收实体,也可以选择发送一个初始化应答以避免循环。<br />
<br />
::exchange sequence(交换序列): 挑战和回应的交换,从接收实体发送给初始化实体的 <challenge/> 元素和从初始化实体发送给接收实体的 <response/> 元素信息。接收实体通过发送 <failure/>元素报告失败,发送<success/>元素报告成功;初始化实体通过发送<abort/> 元素中止交换。成功的协商之后,两边都认为原来的XML流已经关闭并且都开始发送新的流头信息。<br />
<br />
::security layer negotiation(安全层协商): 安全层在接收实体发送 <success/> 元素的关闭字符">"之后立刻生效,在初始化实体发送 <success/> 元素的关闭字符">"之后也立刻生效。层的顺序是 \[TCP\],\[TLS\],然后是 \[SASL\],然后是 \[XMPP\]。<br />
<br />
::use of the authorization identity(授权ID的使用): 授权ID可在xmpp中用于表示一个客户端的非缺省的<node@domain>,或一个服务器的<domain> 。<br />
<br />
===SASL 错误===<br />
<br />
:SASL相关的错误条件定义如下:<br />
<br />
::* <aborted/> -- 接收实体认可由初始化实体发送的<abort/>元素;在回应一个<abort/>元素时发送。<br />
<br />
::* <incorrect-encoding/> -- 由初始化实体提供的数据无法处理,因为[BASE64]编码不正确(例如,因为编码不符合[BASE64]的第三章); 在回应一个包含初始化响应数据的<response/> 元素或<auth/>元素时发送.<br />
<br />
::* <invalid-authzid/> -- 由初始化实体提供的授权id是非法的,因为它的格式不正确或初始化实体无权给那个ID授权;在回应一个包含初始化响应数据的<response/> 元素或<auth/>元素时发送。<br />
<br />
::* <invalid-mechanism/> -- 初始化实体不能提供一个机制活、或请求一个不被接受实体支持的机制;在回应一个<auth/>元素时发送。<br />
<br />
::* <mechanism-too-weak/> -- 初始化实体请求的机制比服务器策略对它的要求弱;在回应一个包含初始化响应数据的<response/> 元素或<auth/>元素时发送。<br />
<br />
::* <not-authorized/> -- 验证失败,因为初始化实体没有提供合法的credentials(这包括但不限于未知用户名等情形);在回应一个包含初始化响应数据的<response/> 元素或<auth/>元素时发送。<br />
<br />
::* <temporary-auth-failure/> -- 验证失败,因为接收实体出现了临时的错误;在回应一个<response/> 元素或<auth/>元素时发送。<br />
<br />
===客户端-服务器 示例===<br />
<br />
:以下例子展示了一个客户端和一个服务器使用SASL作验证的数据流,通常是在成功的TLS握手之后(注意:以下显示的替代步骤仅用于举例说明协议的失败情形;它们不够详尽也不需要由例子中的数据传送来触发)。<br />
<br />
:步骤 1: 客户端初始化流给服务器:<br />
<br />
<source lang="xml"><br />
<stream:stream xmlns='jabber:client' xmlns:stream='http://etherx.jabber.org/streams' to='example.com' version='1.0'><br />
</source><br />
<br />
:步骤 2: 服务器向客户端发送流标签作为应答:<br />
<br />
<source lang="xml"><br />
<stream:stream xmlns='jabber:client' xmlns:stream='http://etherx.jabber.org/streams' id='c2s_234' from='example.com' version='1.0'><br />
</source><br />
<br />
:步骤 3: 服务器通知客户端可用的验证机制:<br />
<br />
<source lang="xml"><br />
<stream:features><br />
<mechanisms xmlns='urn:ietf:params:xml:ns:xmpp-sasl'><br />
<mechanism>DIGEST-MD5</mechanism><br />
<mechanism>PLAIN</mechanism><br />
</mechanisms><br />
</stream:features><br />
</source><br />
<br />
:步骤 4: 客户端选择一个验证机制:<br />
<br />
<source lang="xml"><br />
<auth xmlns='urn:ietf:params:xml:ns:xmpp-sasl' mechanism='DIGEST-MD5'/><br />
</source><br />
<br />
:步骤 5: 服务器发送一个 \[BASE64\] 编码的挑战给客户端:<br />
<br />
<source lang="xml"><br />
<challenge xmlns='urn:ietf:params:xml:ns:xmpp-sasl'><br />
cmVhbG09InNvbWVyZWFsbSIsbm9uY2U9Ik9BNk1HOXRFUUdtMmhoIixxb3A9ImF1dGgi<br />
LGNoYXJzZXQ9dXRmLTgsYWxnb3JpdGhtPW1kNS1zZXNzCg==<br />
</challenge><br />
</source><br />
<br />
:解码后的挑战信息是:<br />
<br />
<source lang="xml"><br />
realm="somerealm",nonce="OA6MG9tEQGm2hh",\<br />
qop="auth",charset=utf-8,algorithm=md5-sess<br />
</source><br />
<br />
:步骤 5 (替代): 服务器返回一个错误给客户端:<br />
<br />
<source lang="xml"><br />
<failure xmlns='urn:ietf:params:xml:ns:xmpp-sasl'><br />
<incorrect-encoding/><br />
</failure><br />
</stream:stream><br />
</source><br />
<br />
:步骤 6: 客户端发送一个\[BASE64\]编码的回应这个挑战:<br />
<br />
<source lang="xml"><br />
<response xmlns='urn:ietf:params:xml:ns:xmpp-sasl'><br />
dXNlcm5hbWU9InNvbWVub2RlIixyZWFsbT0ic29tZXJlYWxtIixub25jZT0i<br />
T0E2TUc5dEVRR20yaGgiLGNub25jZT0iT0E2TUhYaDZWcVRyUmsiLG5jPTAw<br />
MDAwMDAxLHFvcD1hdXRoLGRpZ2VzdC11cmk9InhtcHAvZXhhbXBsZS5jb20i<br />
LHJlc3BvbnNlPWQzODhkYWQ5MGQ0YmJkNzYwYTE1MjMyMWYyMTQzYWY3LGNo<br />
YXJzZXQ9dXRmLTgK<br />
</response><br />
</source><br />
<br />
:解码后的回应信息是:<br />
<br />
<source lang="xml"><br />
username="somenode",realm="somerealm",\<br />
nonce="OA6MG9tEQGm2hh",cnonce="OA6MHXh6VqTrRk",\<br />
nc=00000001,qop=auth,digest-uri="xmpp/example.com",\<br />
response=d388dad90d4bbd760a152321f2143af7,charset=utf-8<br />
</source><br />
<br />
:步骤 7: 服务器发送另一个\[BASE64\]编码的挑战给客户端:<br />
<br />
<source lang="xml"><br />
<challenge xmlns='urn:ietf:params:xml:ns:xmpp-sasl'><br />
cnNwYXV0aD1lYTQwZjYwMzM1YzQyN2I1NTI3Yjg0ZGJhYmNkZmZmZAo=<br />
</challenge><br />
</source><br />
<br />
:解码后的挑战信息是:<br />
<br />
<source lang="xml"><br />
rspauth=ea40f60335c427b5527b84dbabcdfffd<br />
</source><br />
<br />
:步骤 7 (或者): 服务器返回一个错误给客户端:<br />
<br />
<source lang="xml"><br />
<failure xmlns='urn:ietf:params:xml:ns:xmpp-sasl'><br />
<temporary-auth-failure/><br />
</failure><br />
</stream:stream><br />
</source><br />
<br />
:步骤 8: 客户端应答这个挑战:<br />
<br />
<source lang="xml"><br />
<response xmlns='urn:ietf:params:xml:ns:xmpp-sasl'/><br />
</source><br />
<br />
:步骤 9: 服务器通知客户端验证成功:<br />
<br />
<source lang="xml"><br />
<success xmlns='urn:ietf:params:xml:ns:xmpp-sasl'/><br />
</source><br />
<br />
:步骤 9 (或者): 服务器通知客户端验证失败:<br />
<br />
<source lang="xml"><br />
<failure xmlns='urn:ietf:params:xml:ns:xmpp-sasl'><br />
<temporary-auth-failure/><br />
</failure><br />
</stream:stream><br />
</source><br />
<br />
:步骤 10: 客户端发起一个新的流给服务器:<br />
<br />
<source lang="xml"><br />
<stream:stream xmlns='jabber:client' xmlns:stream='http://etherx.jabber.org/streams' to='example.com' version='1.0'><br />
</source><br />
<br />
:步骤 11: 服务器发送一个流头信息回应客户端,并附上任何可用的特性(或空的features元素):<br />
<br />
<source lang="xml"><br />
<stream:stream xmlns='jabber:client' xmlns:stream='http://etherx.jabber.org/streams' id='c2s_345' from='example.com' version='1.0'><br />
<stream:features><br />
<bind xmlns='urn:ietf:params:xml:ns:xmpp-bind'/><br />
<session xmlns='urn:ietf:params:xml:ns:xmpp-session'/><br />
</stream:features><br />
</source><br />
<br />
===服务器-服务器 示例===<br />
<br />
:以下例子展示了一个服务器和另一个服务器使用SASL作验证的数据流,通常是在成功的TLS握手之后(注意:以下显示的替代步骤仅用于举例说明协议的失败情形;它们不够详尽也不需要由例子中的数据传送来触发)。<br />
<br />
:步骤 1: 服务器1 发起一个流给 服务器2 :<br />
<br />
<source lang="xml"><br />
<stream:stream xmlns='jabber:server' xmlns:stream='http://etherx.jabber.org/streams' to='example.com' version='1.0'><br />
</source><br />
<br />
:步骤 2: 服务器2 回应一个流标签给 服务器1:<br />
<br />
<source lang="xml"><br />
<stream:stream xmlns='jabber:server' xmlns:stream='http://etherx.jabber.org/streams' from='example.com' id='s2s_234' version='1.0'><br />
</source><br />
<br />
:步骤 3: 服务器2 通知 服务器1 可用的验证机制:<br />
<br />
<source lang="xml"><br />
<stream:features><br />
<mechanisms xmlns='urn:ietf:params:xml:ns:xmpp-sasl'><br />
<mechanism>DIGEST-MD5</mechanism><br />
<mechanism>KERBEROS_V4</mechanism><br />
</mechanisms><br />
</stream:features><br />
</source><br />
<br />
:步骤 4: 服务器1 选择一个验证机制:<br />
<br />
<source lang="xml"><br />
<auth xmlns='urn:ietf:params:xml:ns:xmpp-sasl' mechanism='DIGEST-MD5'/><br />
</source><br />
<br />
:步骤 5: 服务器2 发送一个\[BASE64\]编码的挑战给 服务器1:<br />
<br />
<source lang="xml"><br />
<challenge xmlns='urn:ietf:params:xml:ns:xmpp-sasl'><br />
cmVhbG09InNvbWVyZWFsbSIsbm9uY2U9Ik9BNk1HOXRFUUdtMmhoIixxb3A9<br />
ImF1dGgiLGNoYXJzZXQ9dXRmLTgsYWxnb3JpdGhtPW1kNS1zZXNz<br />
</challenge><br />
</source><br />
<br />
:解码后的挑战信息是:<br />
<br />
<source lang="xml"><br />
realm="somerealm",nonce="OA6MG9tEQGm2hh",\<br />
qop="auth",charset=utf-8,algorithm=md5-sess<br />
</source><br />
<br />
:步骤 5 (替代): 服务器2 返回一个错误给 服务器1:<br />
<br />
<source lang="xml"><br />
<failure xmlns='urn:ietf:params:xml:ns:xmpp-sasl'><br />
<incorrect-encoding/><br />
</failure><br />
</stream:stream><br />
</source><br />
<br />
:步骤 6: 服务器1 发送一个\[BASE64\]编码的回应这个挑战:<br />
<br />
<source lang="xml"><br />
<response xmlns='urn:ietf:params:xml:ns:xmpp-sasl'><br />
dXNlcm5hbWU9ImV4YW1wbGUub3JnIixyZWFsbT0ic29tZXJlYWxtIixub25j<br />
ZT0iT0E2TUc5dEVRR20yaGgiLGNub25jZT0iT0E2TUhYaDZWcVRyUmsiLG5j<br />
PTAwMDAwMDAxLHFvcD1hdXRoLGRpZ2VzdC11cmk9InhtcHAvZXhhbXBsZS5v<br />
cmciLHJlc3BvbnNlPWQzODhkYWQ5MGQ0YmJkNzYwYTE1MjMyMWYyMTQzYWY3<br />
LGNoYXJzZXQ9dXRmLTgK<br />
</response><br />
</source><br />
<br />
:解码后的应答信息是:<br />
<br />
<source lang="xml"><br />
username="example.org",realm="somerealm",\<br />
nonce="OA6MG9tEQGm2hh",cnonce="OA6MHXh6VqTrRk",\<br />
nc=00000001,qop=auth,digest-uri="xmpp/example.org",\<br />
response=d388dad90d4bbd760a152321f2143af7,charset=utf-8<br />
</source><br />
<br />
:步骤 7: 服务器2 发送另外一个\[BASE64\]编码的挑战给 服务器1:<br />
<br />
<source lang="xml"><br />
<challenge xmlns='urn:ietf:params:xml:ns:xmpp-sasl'><br />
cnNwYXV0aD1lYTQwZjYwMzM1YzQyN2I1NTI3Yjg0ZGJhYmNkZmZmZAo=<br />
</challenge><br />
</source><br />
<br />
:解码后的挑战信息是:<br />
<br />
<source lang="xml"><br />
rspauth=ea40f60335c427b5527b84dbabcdfffd<br />
</source><br />
<br />
:步骤 7 (或者): 服务器2 返回一个错误给 服务器1:<br />
<br />
<source lang="xml"><br />
<failure xmlns='urn:ietf:params:xml:ns:xmpp-sasl'><br />
<invalid-authzid/><br />
</failure><br />
</stream:stream><br />
</source><br />
<br />
:步骤 8: 服务器1 回应挑战:<br />
<br />
<source lang="xml"><br />
<response xmlns='urn:ietf:params:xml:ns:xmpp-sasl'/><br />
</source><br />
<br />
:步骤 8 (或者): 服务器1 中止协商:<br />
<br />
<source lang="xml"><br />
<abort xmlns='urn:ietf:params:xml:ns:xmpp-sasl'/><br />
</source><br />
<br />
:步骤 9: 服务器2 通知 服务器1 验证成功:<br />
<br />
<source lang="xml"><br />
<success xmlns='urn:ietf:params:xml:ns:xmpp-sasl'/><br />
</source><br />
<br />
:步骤 9 (或者): 服务器2 通知 服务器1 验证失败:<br />
<br />
<source lang="xml"><br />
<failure xmlns='urn:ietf:params:xml:ns:xmpp-sasl'><br />
<aborted/><br />
</failure><br />
</stream:stream><br />
</source><br />
<br />
:步骤 10: 服务器1 重新发起一个新的流给 服务器2:<br />
<br />
<source lang="xml"><br />
<stream:stream xmlns='jabber:server' xmlns:stream='http://etherx.jabber.org/streams' to='example.com' version='1.0'><br />
</source><br />
<br />
:步骤 11: 服务器2 发送一个流头信息应答 服务器1 ,并附上任何可用的特性(或一个空的features元素).:<br />
<br />
<source lang="xml"><br />
<stream:stream xmlns='jabber:client' xmlns:stream='http://etherx.jabber.org/streams' from='example.com' id='s2s_345' version='1.0'><br />
<stream:features/><br />
</source><br />
<br />
==资源绑定==<br />
<br />
:在和接收实体完成 SASL 协商(第六章)之后,初始化实体可能(MAY)想要或者需要绑定一个特定的资源到流上.通常这仅适用于客户端: 为了满足本文定义的寻址格式(第三章)和节传输规则(第十章),客户端<node@domain>必须(MUST)拥有一个相关的资源ID(由服务器生成或由客户端程序提供);以确保在流上使用的地址是一个“全JID”(<node@domain/resource>)。<br />
<br />
:接收到一个成功的SASL握手之后,客户端必须(MUST)发送一个新的流头信息给服务器,服务器必须(MUST)返回一个包含可用的流特性列表的头信息。特别是,在成功的SASL握手之后如果服务器需要客户端绑定一个资源,它必须(MUST)在握手成功之后(而不是之前)发送给客户端的应答流特性中包含一个空的符合'urn:ietf:params:xml:ns:xmpp-bind'名字空间的<bind/>元素。:<br />
<br />
:服务器向客户端声明资源绑定特性:<br />
<br />
<source lang="xml"><br />
<stream:stream xmlns='jabber:client' xmlns:stream='http://etherx.jabber.org/streams' id='c2s_345' from='example.com' version='1.0'><br />
<stream:features><br />
<bind xmlns='urn:ietf:params:xml:ns:xmpp-bind'/><br />
</stream:features><br />
</source><br />
<br />
:收到要求资源绑定的通知后,客户端必须(MUST)通过发送一个符合'urn:ietf:params:xml:ns:xmpp-bind'名字空间的“set”类型的IQ节(参见 IQ 语义 (第九章第二节第三小节))给服务器来绑定一个资源到流中。<br />
<br />
:如果客户端端希望允许服务器给自己生成一个资源ID,它可以发送一个包含空的<bind/>元素的“set”类型的IQ节。:<br />
<br />
:客户端请求服务器绑定资源:<br />
<br />
<source lang="xml"><br />
<iq type='set' id='bind_1'><br />
<bind xmlns='urn:ietf:params:xml:ns:xmpp-bind'/><br />
</iq><br />
</source><br />
<br />
:一个支持资源绑定的服务器必须(MUST)自动生成一个资源ID给客户端。一个由服务器生成的资源ID对于那个<node@domain>必须(MUST)是唯一的。<br />
<br />
:如果客户端希望指定资源ID,它发送一个包含期望资源ID的“set”类型的 IQ节,把资源ID作为<bind/>元素下的<resource/>子元素的XML字符数据:<br />
<br />
:客户端绑定一个资源:<br />
<br />
<source lang="xml"><br />
<iq type='set' id='bind_2'><br />
<bind xmlns='urn:ietf:params:xml:ns:xmpp-bind'><br />
<resource>someresource</resource><br />
</bind><br />
</iq><br />
</source><br />
<br />
:一旦服务器为客户端生成了一个资源ID或接受了客户端自己提供的资源ID,它必须(MUST)返回一个“result”类型的 IQ 节给客户端,这个节必须包含一个指明全JID的<jid/>子元素表示服务器决定连接的资源:<br />
<br />
:服务器通知客户端资源绑定成功:<br />
<br />
<source lang="xml"><br />
<iq type='result' id='bind_2'><br />
<bind xmlns='urn:ietf:params:xml:ns:xmpp-bind'><br />
<jid>somenode@example.com/someresource</jid><br />
</bind><br />
</iq><br />
</source><br />
<br />
:一个服务器应该(SHOULD)接受客户端提供的资源ID,但是可以(MAY)用服务器生成的资源ID覆盖它;在这种情况下,服务器不应该(SHOULD NOT)返回一个错误信息一个(如<forbidden/>)给客户端,而应该(SHOULD)在上文所述的 IQ result 中返回生成的资源ID。<br />
<br />
:当一个客户端自行提供资源ID时,可能发生以下的节错误(参见 Stanza Errors (第九章第三节)):<br />
<br />
::- 提供的资源ID服务器无法处理,因为不符合资源字符规范Resourceprep(附录B)。<br />
<br />
::- 客户端不被允许绑定一个资源(如节点或用户已经达到允许连接的资源数限制)。<br />
<br />
::- 提供的资源ID已经被使用但是服务器不允许以同一个资源ID绑定多个连接。<br />
<br />
:协议对这些错误条件规定如下.<br />
<br />
::资源ID不能处理:<br />
<br />
<source lang="xml"><br />
<iq type='error' id='bind_2'><br />
<bind xmlns='urn:ietf:params:xml:ns:xmpp-bind'><br />
<resource>someresource</resource><br />
</bind><br />
<error type='modify'><br />
<bad-request xmlns='urn:ietf:params:xml:ns:xmpp-stanzas'/><br />
</error><br />
</iq><br />
</source><br />
<br />
::客户端不允许绑定一个资源:<br />
<br />
<source lang="xml"><br />
<iq type='error' id='bind_2'><br />
<bind xmlns='urn:ietf:params:xml:ns:xmpp-bind'><br />
<resource>someresource</resource><br />
</bind><br />
<error type='cancel'><br />
<not-allowed xmlns='urn:ietf:params:xml:ns:xmpp-stanzas'/><br />
</error><br />
</iq><br />
</source><br />
<br />
::资源ID已经在使用:<br />
<br />
<source lang="xml"><br />
<iq type='error' id='bind_2'><br />
<bind xmlns='urn:ietf:params:xml:ns:xmpp-bind'><br />
<resource>someresource</resource><br />
</bind><br />
<error type='cancel'><br />
<conflict xmlns='urn:ietf:params:xml:ns:xmpp-stanzas'/><br />
</error><br />
</iq><br />
</source><br />
<br />
:如果,在完成资源绑定步骤之前,客户端试图以符合'urn:ietf:params:xml:ns:xmpp-bind'名字空间的<bind/>子元素发送一个非IQ类型的XML节,服务器不能(MUST NOT)处理这个节,而应该(SHOULD)返回一个<not-authorized/>节错误信息给客户端.<br />
<br />
==服务器回拨==<br />
<br />
===概览===<br />
<br />
:Jabber协议接受的来自XMPP的包括“服务器回拨”方法,用于防治域名欺骗,使得欺骗XML节更为困难。服务器回拨不是一个安全机制,并且它的服务器身份认证结果很弱(参见服务器之间的通信(第十四章第四节)中关于这个方法的安全特性)。需要健壮的安全性的域名应该(SHOULD)使用TLS或SASL;细节参见服务器间的通信(第十四章第四节)。如果SASL用于服务器间通信,回拨就不需要用了(SHOULD NOT)。本文描述回拨的好处在于向后兼容现存的实现和部署。<br />
<br />
:服务器回拨方法由现存的DNS系统的存在而成为可能,因为一个服务器(通常)可以查询给定域的授权服务器。由于服务器回拨依赖于DNS,除非服务器宣称的DNS主机得到解析,域之间的通信无法进行(参见服务器间的通信(第十四章第四节))。<br />
<br />
:服务器回拨是单向性的,可在单一方向上对一个流进行(微弱的)身份验证.因为服务器回拨不是一个验证机制,通过回拨获得相互的认证是不可能的.因此,为了使得服务器之间的双向通信,服务器回拨必须(MUST)在每个方向上完成。<br />
<br />
:在服务器回拨中生成和检验密钥的方法必须(MUST)考虑计算被使用的主机名,由接收服务器生成的流ID,和只有授权服务器网络才知道的秘密。在服务器回拨中流ID是安全性的关键所以必须(MUST)是不可预知的和不可重复的(见\[RANDOM\]中关于使用随机数获得安全性的建议).<br />
<br />
:任何回拨协商过程中发生的错误必须(MUST)被当成一个流错误,并导致流以及相关的TCP连接的终止.可能发生的错误情况协议中描述如下.<br />
<br />
:以下术语适用:<br />
<br />
:* 发起服务器 -- 尝试在两个域之间建立连接的那个服务器.<br />
<br />
:* 接收服务器 -- 尝试验证发起服务期声称的域名的那台服务器.<br />
<br />
:* 授权(权威?Authoritative) 服务器 -- 回答发起服务器声称的DNS主机名的服务器;基本上这应该是那台发起服务器,但是它也可能是一个在发起服务器网络中独立的服务器。<br />
<br />
===事件顺序===<br />
<br />
:以下是回拨中的事件顺序的简介:<br />
<br />
:# 发起服务器和接收服务器建立一个连接。<br />
:# 发起服务器通过到连接发送一个 'key' 值给接收服务期。<br />
:# 接收服务器建立一个连接到授权服务器。<br />
:# 接收服务器发送一个相同的 'key' 值给授权服务器。<br />
:# 授权服务器回答这个key是否合法。<br />
:# 接收服务器通知发起服务器是否被验证通过。<br />
<br />
:我们用用以下图形展示这个事件流程(见附件s2s.png):<br />
<br />
{image:img=s2s}<br />
<br />
===协议===<br />
<br />
:服务器之间互动的细节协议如下:<br />
<br />
:1. 发起服务器和接受服务器建立TCP连接.<br />
<br />
:2. 发起服务器发送流头信息给接收服务器:<br />
<br />
<source lang="xml"><br />
<stream:stream xmlns:stream='http://etherx.jabber.org/streams' xmlns='jabber:server' xmlns:db='jabber:server:dialback'><br />
</source><br />
<br />
:注意: 'to'和'from'属性在流的根元素是可选的(OPTIONAL). 其中包含的xmlns:db名字空间向接收服务器声明了发起服务器支持回拨. 如果名字空间不正确,接收实体必须(MUST)生成一个<invalid-namespace/>流错误条件并且终止XML流和相应的TCP连接.<br />
<br />
:3. 接收服务器应该(SHOULD)回送一个流头信息给发起服务器,为这次交互生成一个唯一性的ID :<br />
<br />
<source lang="xml"><br />
<stream:stream xmlns:stream='http://etherx.jabber.org/streams' xmlns='jabber:server' xmlns:db='jabber:server:dialback' id='457F9224A0...'><br />
</source><br />
<br />
:注意: 'to'和'from'属性在流的根元素是可选的(OPTIONAL). 如果名字空间不正确,发起服务器必须生成一个<invalid-namespace/>流错误条件并且终止XML流和相应的TCP连接.也要注意,在这里接收服务器应该(SHOULD)应答但是可以(MAY)出于安全策略考虑只是悄悄地终止XML流和TCP连接;无论如何,如果接收服务器希望继续,它必须(MUST)回送一个流头信息给发起服务器.<br />
<br />
:4. 发起服务器发送一个回拨密钥给接收服务器:<br />
<br />
<source lang="xml"><br />
<db:result to='Receiving Server' from='Originating Server'><br />
98AF014EDC0...<br />
</db:result><br />
</source><br />
<br />
:注意: 这个密钥不由接收服务器检查,因为接收服务器在会话之间(between sessions)不保存发起服务器的信息. 这个由发起服务器生成的密钥必须(MUST)是基于接收服务器在上一步骤中提供的ID值,以及发起服务器与授权服务器共享的安全机制生成的。 如果 'to' 地址的值和接收服务器知道的主机名不匹配,接收服务器必须(MUST)生成一个<host-unknown/>流错误条件并且终止XML流和相应的TCP连接. 如果 'from' 地址和接收服务器已经建立的连接的域名相吻合,接收服务器必须(MUST)维护这个已经存在的连接,直到证明这个新的连接是合法的为止;另外,接收实体可以(MAY)选择生成一个<not-authorized/> 流错误条件给这个新的连接并且终止和新连接申请相关的XML流及相应的TCP连接.<br />
<br />
:5. 接收服务器向发起服务器声明的那个域建立一个 TCP 连接,作为结果它连接到授权服务器. (注意: 为了优化性能, 在这里一个实现可以(MAY)重用现有的连接.)<br />
<br />
:6. 接收服务器发送一个流头信息给授权服务器:<br />
<br />
<source lang="xml"><br />
<stream:stream xmlns:stream='http://etherx.jabber.org/streams' xmlns='jabber:server' xmlns:db='jabber:server:dialback'><br />
</source><br />
<br />
:注意: 'to'和'from'属性在流的根元素是可选的(OPTIONAL). 如果名字空间不正确,授权服务器必须生成一个<invalid-namespace/>流错误条件并且终止XML流和相应的TCP连接. <br />
<br />
:7. 授权服务器发送流头信息给接收服务器:<br />
<br />
<source lang="xml"><br />
<stream:stream xmlns:stream='http://etherx.jabber.org/streams' xmlns='jabber:server' xmlns:db='jabber:server:dialback' id='1251A342B...'><br />
</source><br />
<br />
:注意: 如果名字空间不正确,接收服务器必须生成一个<invalid-namespace/>流错误条件并且终止它和授权服务器之间的XML流和相应的TCP连接. 如果一个流错误发生在接收服务器和 '''授权服务器''' 之间,接收服务器必须(MUST)生成一个 <remote-connection-failed/> 流错误条件并且终止它和 '''发起服务器''' 之间的XML流和相应的TCP连接.<br />
<br />
:8. 接收服务器发送一个密钥检查请求给授权服务器:<br />
<br />
<source lang="xml"><br />
<db:verify from='Receiving Server' to='Originating Server' id='457F9224A0...'><br />
98AF014EDC0...<br />
</db:verify><br />
</source><br />
<br />
:注意: 现在这里已经有了主机名,第三步中接收服务器发送给发起服务器的ID,第四步中发起服务器发送给接收服务器的密钥. 基于这些信息, 加上授权服务器网络共享的安全信息, 这个密钥被证实了.任何可用于验证的办法都可以(MAY)用于生成密钥. 如果 'to' 地址的值和授权服务器知道的主机名不匹配,授权服务器必须(MUST)生成一个<host-unknown/>流错误条件并且终止XML流和相应的TCP连接. 打开这个连接时,如果 'from' 地址和接收服务器声明的主机名(或任何合法的域,如验证过的接收服务器的子域名或寄宿在接收服务器上的其他经过验证的域)不符,授权服务器必须(MUST)生成一个<invalid-from/>流错误条件并且终止XML流和相应的TCP连接.<br />
<br />
:9. 授权服务器检查密钥是否合法:<br />
<br />
<source lang="xml"><br />
<db:verify from='Originating Server' to='Receiving Server' type='valid' id='457F9224A0...'/><br />
</source><br />
<br />
::或<br />
<br />
<source lang="xml"><br />
<db:verify from='Originating Server' to='Receiving Server' type='invalid' id='457F9224A0...'/><br />
</source><br />
<br />
:注意: 如果 ID 和第三步中接收服务器提供的不符,接收服务器必须(MUST)生成一个<invalid-id/>流错误条件并且终止XML流和相应的TCP连接. 如果 'to' 地址的值和接收服务器知道的主机名不匹配,接收服务器必须(MUST)生成一个<host-unknown/>流错误条件并且终止XML流和相应的TCP连接. 打开这个连接时,如果 'from' 地址和发起服务器声明的主机名(或任何合法的域,如验证过的发起服务器的子域名或寄宿在发起服务器上的其他经过验证的域)不符,接收服务器必须(MUST)生成一个<invalid-from/>流错误条件并且终止XML流和相应的TCP连接. 在返回验证信息给接收服务器之后,授权服务器应该(SHOULD)终止它们之间的流.<br />
<br />
:10. 接收服务器通知发起服务器结果:<br />
<br />
<source lang="xml"><br />
<db:result from='Receiving Server'to='Originating Server' type='valid'/><br />
</source><br />
<br />
:注意: 在这一个点上, 连接已经由 type='valid' 确认验证是通过了,还是没通过. 如果连接是非法的,接收服务器必须(MUST)终止XML流和相应的TCP连接. 如果连接是合法的, 数据可以从发起服务器发送由接收服务器读取;在此之前,所有发送给接收服务器的XML节应该(SHOULD)被丢弃.<br />
<br />
:进一步的结果是,接收服务器已经验证了发起服务器的ID,所以通过初始化流("initial stream",例如从发起服务器到接收服务器的流)发起服务器可以发送,接收服务器可以接受XML节. 为了使用应答流("response stream",例如从接收服务器到发起服务器的流)验证实体ID,回拨必须(MUST)在相对的两个方向上都完成.<br />
<br />
:在成功的回拨协商之后, 接收服务器应该(SHOULD)接受接下来发起服务器通过当前的合法连接发送的 <db:result/> 包 (例如, 发送给子域或其他寄宿在接收服务器上的主机名的验证请求); 这在单一方向上激活了原始合法连接的 "piggybacking" .<br />
<br />
:即使回拨协商成功了, 服务器仍然必须(MUST)检查从其他服务器接收的所有XML节的'from'和'to'属性; 如果一个节不符合这些限定, 收到这些节的服务器必须(MUST)生成一个<improper-addressing/> 流错误条件并终止XML流和相应的TCP连接. 而且, 一个服务器也必须(MUST)检查从其他的有合法域名的服务器的流中收到的节的'from'属性; 如果一个节不符合这一限定, 接收节的服务器必须(MUST)生成一个 <invalid-from/> 流错误条件并终止XML流和相应的TCP连接. 所有这些检查都用来帮助防止特定的节伪造行为.<br />
<br />
==XML节==<br />
<br />
:在 TLS 协商(第五章) (如果想要), SASL 协商(第六章), 和资源绑定(第七章)(如果需要)之后, XML节就可以通过流发送了. 在'jabber:client'和'jabber:server'名字空间中定义了三种XML节: <message/>, <presence/>, 和 <iq/>. 另外, 这三种节有五种通用的属性. 这些通用属性, 加上三种节的术语,在这里定义; 更多关于和即时消息及出席信息应用相关的XML节语法详细信息在[XMPP-IM|XMPP文档列表/XMPP正式RFC标准/RFC3921]中提供.<br />
<br />
===通用属性===<br />
<br />
:以下五种属性通用于 message, presence, 和 IQ 节:<br />
<br />
====to====<br />
<br />
:'to' 属性表示节的预期接收者的JID.<br />
<br />
:在'jabber:client'名字空间中, 一个节应该(SHOULD)处理一个'to'属性, 尽管由服务器处理的从客户端发给服务器的节(如, 发送给服务器用于广播给其他实体的出席信息) 应该不(SHOULD NOT)处理'to'属性.<br />
<br />
:在'jabber:server'名字空间中, 一个节必须(MUST)处理一个'to'属性; 如果一个服务器收到一个不符合此限定的节, 它必须(MUST)生成一个<improper-addressing/>流错误条件并终止和这个非法服务器的XML流和相应的TCP连接.<br />
<br />
:如果'to'属性的值非法或无法联络, 发现这个事实的实体(通常是发送者或接收者的服务器)必须(MUST)返回一个适当的错误给发送者, 错误节的'from'属性设置成非法节的提供的'to'属性的值.<br />
<br />
====from====<br />
<br />
:'from' 属性表示发送者的 JID .<br />
<br />
:当一个服务器接收了一个符合'jabber:client'名字空间的合法流的XML节, 它必须(MUST)做以下步骤中的一步:<br />
<br />
:# 验证客户端提供的'from'属性值就是那个相关实体连接的资源<br />
:# 为生成这个节的已连接的资源增加一个'from'地址(由服务器决定是纯JID或全JID)(参见 地址的决定 Determination of Addresses (第三章第五节))<br />
:# 如果一个客户端试图发送一个XML节,而它的'from'属性和这个实体已连接的资源不符, 服务器应该(SHOULD)返回一个<invalid-from/>流错误条件给客户端. 如果一个客户端试图通过一个尚未验证的流发送一个XML节, 服务器应该(SHOULD)返回一个<not-authorized/>流错误条件给客户端. 如果生成了, 所有这些条件必须(MUST)导致流的关闭和相应的TCP连接的终止; 这有助于防止不诚实的客户的拒绝服务攻击.<br />
<br />
:当一个服务器从服务器自身生成一个节用于一个已连接的客户端的信息发布(例如, 在服务器为客户端提供数据存储服务的情况下), 这个节必须(MUST) (1) 不包含 'from' 属性 或 (2) 包含一个'from'属性,它的值是这个账号的纯 JID (<node@domain>) 或 客户端的全 JID (<node@domain/resource>). 如果节不是由服务器自身生成的,那么一个服务器不能(MUST NOT)发送不带'from'属性的节. 当一个客户端接收到一个不包含'from'属性的节, 它必须(MUST)认为这个节是从客户端连接的服务器发来的.<br />
<br />
:在'jabber:server'名字空间, 一个节必须(MUST)处理一个'from'属性; 如果一个服务器接收到一个不符合此限定的节, 它必须(MUST)生成一个<improper-addressing/>流错误条件. 而且, 'from'属性的 JID值的域名ID部分必须(MUST)和以SASL协商连接或以回拨协商连接的发送服务器的主机名(或任何合法的域,如发送服务器主机名的合法子域,或其他寄宿在发送服务器上的合法域)吻合; 如果一个服务器接收到的节不符合此限定, 它必须(MUST)生成一个<invalid-from/>流错误条件. 所有这些条件都必须(MUST)导致流的关闭和相应的TCP连接的终止; 这有助于防止不诚实的客户端发起的拒绝服务攻击.<br />
<br />
====id====<br />
<br />
:可选的'id' 属性可以(MAY)用于为节的内部跟踪发送实体,从IQ节 语义来讲,就是通过发送和接收这些节来跟踪“请求-应答”型的交互行为。这个可选的(OPTIONAL)'id'属性值在一个域或一个流中是全局唯一的。IQ节语义学中对此有附加限定;见IQ Semantics (第九章第二节第三小节)。<br />
<br />
====type====<br />
<br />
:'type' 属性指明消息、出席信息或IQ节的意图或上下文的详细信息。'type'属性所允许的值依据节的类型是消息、出席信息还是IQ而有很大不同; 用于消息和出席信息节的值定义在即时消息和出席信息应用中,所以在[XMPP-IM|XMPP文档列表/XMPP正式RFC标准/RFC3921]中定义,反之用于IQ节的值定义了在一个 请求\-应答 的“会话”中IQ节的角色,所以定义在IQ语义学中(第九章第二节第三小节)。 所有三种节的通用'type'值是"error";见Stanza Errors (第九章第三节)。<br />
<br />
====xml:lang====<br />
<br />
:如果一个节包含用于显示给人human user看的XML字符数据(在RFC 2277中有所解释\[CHARSET\],"internationalization is for humans"),这个节应该(SHOULD)处理一个'xml:lang'属性(定义在第二章第十二节\[XML\])。 'xml:lang'属性的值指明任何一个人类可读的XML字符数据的缺省语言, 它可以(MAY)被特定的子元素的'xml:lang'值重载。 如果一个节不处理一个'xml:lang'属性,一个实现必须(MUST)认为缺省的语言就是流属性中定义的语言(第四章第四节). 'xml:lang'属性值必须(MUST)是一个 NMTOKEN 并且必须(MUST)遵守 RFC 3066 \[LANGTAGS\]中定义的格式. <br />
<br />
===基本语义学===<br />
<br />
====消息语义学====<br />
<br />
:<message/>节类型可以被看作是一个"push"机制用于一个实体推送信息给另一个实体,类似发生在email系统中的通信. 所有消息节应该(SHOULD)处理一个表明预定的消息接收者的'to'属性;接收了这样一个节之后,一个服务器应该(SHOULD)路由或递送它给预定的接收者(见 Server Rules for Handling XML Stanzas (第十章)的XML节相关的通用路由和递送规则).<br />
<br />
====出席信息语义学====<br />
<br />
:<presence/> 元素可以被看作一个基本的广播或“出版-订阅”机制,用于多个实体接收某个已订阅的实体的信息(在这里,是网络可用性信息). 通常,一个发行实体应该(SHOULD)不带'to'属性发送一个出席信息,这时这个实体所连接的服务器应该(SHOULD)广播或多播(multiplex?)那个节给所有订阅的实体.无论如何,一个发行实体也可以(MAY)带'to'属性发送一个出席信息节,这时服务器应该(SHOULD)路由或递送这个节给预定的接收者.见 Server Rules for Handling XML Stanzas (第十章)的XML节相关的通用路由和递送规则,以及[XMPP-IM|XMPP文档列表/XMPP正式RFC标准/RFC3921]中即时消息和出席信息应用中出席信息的特定规则.<br />
<br />
====IQ语义学====<br />
<br />
:信息/查询(Info/Query),或曰IQ,是一个 请求-回应 机制,某些情况下类似\[HTTP\].IQ语义学使一个实体能够向另一个实体做出请求并做出应答. 请求和应答所包含的数据定义在IQ元素的一个直接的子元素的名字空间声明中, 并且由请求实体用'id'属性来跟踪这一交互行为. 因而,IQ交互伴随着一个结构化的数据交换的通用模式例如 get/result 或 set/result (尽管有时候会以一个错误信息应答某个请求):<br />
<br />
:以下是IQ的流程图,参见附件iq.png<br />
<br />
{image:img=iq}<br />
<br />
:为了强制执行这些语义学,要应用以下规则:<br />
<br />
:1. 对于IQ节来说'id'属性是必需的(REQUIRED).<br />
:2. 对于IQ节来说'type'属性是必需的(REQUIRED). 它的值必须(MUST)是以下之一:<br />
::* get -- 这个节是一个对信息或需求的请求.<br />
::* set -- 这个节提供需要的数据, 设置新的值, 或取代现有的值.<br />
::* result -- 这个节是一个对一个成功的 get 或 set 请求的应答.<br />
::* error -- 发生了一个错误,关于处理或递送上次发送的 get 或 set的(参见 节错误 Stanza Errors(第九章第三节)).<br />
:3. 一个接收到"get" 或 "set" 类型的IQ请求的实体必须(MUST)回复一个"result"或"error"类型的IQ应答(这个应答必须(MUST)保留相关请求的'id'属性).<br />
:4. 一个接收到"result"或"error"类型的IQ节的实体不能(MUST NOT)再发送更多的"result"或"error"类型的IQ应答; 无论如何, 如上所述, 请求实体可以(MAY)发送另一个请求(如, 一个"set"类型的IQ,通过get/result对提供查询(discovery)所需的信息).<br />
:5. 一个"get" 或 "set" 类型的IQ节必须(MUST)包含并只包含一个子元素指明特定请求或应答的语义.<br />
:6. 一个"result"类型的IQ节必须(MUST)包含零或一个子元素.<br />
:7. 一个"error"类型的IQ节应该(SHOULD)包含和"get"或"set"相关联的那个子元素并且必须(MUST)包含一个<error/>子元素;详细信息,见Stanza Errors (第九章第三节).<br />
<br />
===节错误===<br />
<br />
:节相关的错误的处理方式类似流错误(第四章第七节). 无论如何, 不像流错误, 节错误是可恢复的;所以错误节包含了暗示原来的发送者可以采取什么行动来补救这个错误.<br />
<br />
====规则====<br />
<br />
:以下规则适用于节相关的错误:<br />
<br />
:* 接收或处理实体察觉到一个节相关的错误条件时应该(MUST)返回给发送实体一个同类型的节(消息,出席信息,或IQ),这个节的'type'属性值则设置为"error"(这里这样的节称之为"error stanza").<br />
<br />
:* 生成一个错误节的实体应该(SHOULD)包含原来发送的XML,这样发送者可以检查它,并且如果必要,在尝试重新发送之前纠正它.<br />
<br />
:* 一个错误节必须(MUST)包含一个<error/>子元素.<br />
<br />
:* 如果'type'属性值不是"error"(或没有"type"属性),节不能(MUST NOT)包含一个<error/>子元素.<br />
<br />
:* 接收到一个错误节的实体不能(MUST NOT)应答这个节更多的错误节; 这有助于防止死循环.<br />
<br />
====语法====<br />
<br />
:节相关错误的语法如下:<br />
<br />
<source lang="xml"><br />
<stanza-kind to='sender' type='error'><br />
[RECOMMENDED to include sender XML here]<br />
<error type='error-type'><br />
<defined-condition xmlns='urn:ietf:params:xml:ns:xmpp-stanzas'/><br />
<text xmlns='urn:ietf:params:xml:ns:xmpp-stanzas' xml:lang='langcode'><br />
OPTIONAL descriptive text<br />
</text><br />
[OPTIONAL application-specific condition element]<br />
</error><br />
</stanza-kind><br />
</source><br />
<br />
:stanza-kind 是 message, presence, 或 iq 中的一个.<br />
<br />
:<error/> 元素的'type'属性值必须(MUST)是以下之一:<br />
<br />
:* cancel \-\- 不重试(这个错误是不可恢复的)<br />
<br />
:* continue \-\- 继续进行(这个条件只是一个警告)<br />
<br />
:* modify \-\- 改变数据之后重试<br />
<br />
:* auth \-\- 提供证书之后重试<br />
<br />
:* wait \-\- 等待之后重试(错误是暂时的)<br />
<br />
:<error/>元素:<br />
<br />
:* 必须(MUST)包含一个子元素,符合以下定义的节错误条件之一;这个元素(MUST)符合'urn:ietf:params:xml:ns:xmpp-stanzas'名字空间.<br />
<br />
:* 可以(MAY)包含一个<text/>子元素容纳XML字符数据用来描述错误的更多细节;这个元素必须(MUST)符合'urn:ietf:params:xml:ns:xmpp-stanzas'名字空间并且应该(SHOULD)处理'xml:lang'属性.<br />
<br />
:* 可以(MAY)包含一个应用程序定义的错误条件子元素;这个元素必须(MUST)符合一个应用程序定义的名字空间,并且它的结构由这个名字空间定义.<br />
<br />
:<text/>元素是可选的(OPTIONAL).如果包含它,它应该(SHOULD)仅用于提供描述或诊断信息以补充一个已定义的条件或应用程序定义的条件. 它不应(SHOULD NOT)被应用程序认为是一个程序性的. 它不应(SHOULD NOT)被用作向一个使用者展示的错误信息,但是可以(MAY)展示除条件元素(或元素们)相关的错误信息之外的信息.<br />
<br />
:最后,为了维护向后兼容性, 这个schema (定义在[XMPP-IM|XMPP文档列表/XMPP正式RFC标准/RFC3921])允许可选的在<error/>元素中包含一个("code")属性.<br />
<br />
====已定义的条件====<br />
<br />
:以下条件定义用于节错误.<br />
<br />
:* <bad-request/> -- 发送者发送的XML是不规范的或不能被处理(例如 一个IQ节包含了一个未被承认的'type'属性值); 相关的错误类型应该(SHOULD)是"modify".<br />
<br />
:* <conflict/> -- 不同意访问,因为相同的名字或地址已存在一个资源或会话;相关的错误类型应该( SHOULD)是"cancel".<br />
<br />
:* <feature-not-implemented/> -- 请求的特性未被接收者或服务器实现所以不能处理;相关的错误类型应该(SHOULD)是"cancel".<br />
<br />
:* <forbidden/> -- 请求实体没有必需的许可来执行这一动作;相关的错误类型应该(SHOULD)是"auth".<br />
<br />
:* <gone/> -- 接收者或服务器无法再以这个地址进行联系(错误节可以(MAY)在<gone/>元素的XML字符数据中包含一个新的地址);相关的错误类型应该(SHOULD)是"modify".<br />
<br />
:* <internal-server-error/> -- 服务器不能处理节,因为错误的配置或其他未定义的内部服务器错误;相关的错误类型应该(SHOULD)是"wait".<br />
<br />
:* <item-not-found/> -- JID地址或申请的条目无法找到;相关的错误类型应该(SHOULD)是"cancel".<br />
<br />
:* <jid-malformed/> -- 发送的实体提供的XMPP地址或与之通信的某个XMPP地址(如一个'to'属性值)或这个XMPP地址中的一部分(如一个资源ID)不符合寻址方案的语法(第三章);相关的错误类型应该(SHOULD)是"modify".<br />
<br />
:* <not-acceptable/> -- 接收者或服务器理解这个请求但是拒绝处理,因为它不符合某些接收者或服务器定义的标准(例如,一个关于消息中可接收的单词的本地策略);相关错误类型应该(SHOULD)是"modify".<br />
<br />
:* <not-allowed/> -- 接收者或服务器不允许任何实体执行这个动作;相关错误类型应该(SHOULD)是"cancel".<br />
<br />
:* <not-authorized/> -- 在被允许执行某个动作之前发送者必须提供适当的证书,或已提供了不正确的证书;相关错误类型应该(SHOULD)是"auth".<br />
<br />
:* <payment-required/> -- 请求实体未被授权访问请求的服务,因为需要付费;相关错误类型应该(SHOULD)是"auth".<br />
<br />
:* <recipient-unavailable/> -- 预定的接收者暂时不可用;相关错误类型应该(SHOULD)是"wait"(注意: 如果这样做会导致泄露预定接收者的网络可用性给一个未被授权了解此信息的实体,应用程序不应该(MUST NOT)返回这个错误).<br />
<br />
:* <redirect/> -- 接收者或服务器重定向这个请求信息到另一个实体,通常是暂时的(这个错误节应该 (SHOULD)在<redirect/>元素的XML字符数据中包含一个预备的地址,它必须(MUST)是一个合法的JID); 相关的错误类型应该(SHOULD)是"modify".<br />
<br />
:* <registration-required/> -- 请求实体未被授权访问请求的服务,因为需要注册;相关错误类型应该(SHOULD)是"auth".<br />
<br />
:* <remote-server-not-found/> -- 在预定的接收者的全部或部分JID中的一个远程服务器或服务不存在;相关错误类型应该(SHOULD)是"cancel".<br />
<br />
:* <remote-server-timeout/> -- 在预定的接收者(或需要完成的一个申请)的全部或部分JID中的一个远程服务器或服务无法在合理的时间内联系到;相关错误类型应该(SHOULD)是"wait".<br />
<br />
:* <resource-constraint/> -- 服务器或接收者缺乏足够的系统资源来服务请求;相关错误类型应该(SHOULD)是"wait".<br />
<br />
:* <service-unavailable/> -- 服务器或接收者目前无法提供被请求的服务;相关错误类型应该(SHOULD)是"cancel".<br />
<br />
:* <subscription-required/> -- 请求实体未被授权访问能请求的服务,因为需要订阅;相关错误类型应该(SHOULD)是"auth".<br />
<br />
:* <undefined-condition/> -- 错误条件不是本列表中定于的其他条件之一;任何错误类型可能和这个条件有关,并且它应该(SHOULD)仅用于关联一个应用程序定义的条件.<br />
<br />
:* <unexpected-request/> -- 接收者或服务器理解这个请求但是不希望是在这个时间(比如,请求的顺序颠倒);相关错误类型应该(SHOULD)是"wait".<br />
<br />
====应用程序定义条件====<br />
<br />
:大家知道,一个应用程序可以(MAY)通过在错误元素里包含一个适当名字空间的字元素来提供应用程序定义的节错误信息. 应用程序定义的元素应该(SHOULD)补充或进一步限定一个已定义的元素. 因而,<error/>元素将包含两个或三个子元素:<br />
<br />
<source lang="xml"><br />
<iq type='error' id='some-id'><br />
<error type='modify'><br />
<bad-request xmlns='urn:ietf:params:xml:ns:xmpp-stanzas'/><br />
<too-many-parameters xmlns='application-ns'/><br />
</error><br />
</iq><br />
<message type='error' id='another-id'><br />
<error type='modify'><br />
<undefined-condition xmlns='urn:ietf:params:xml:ns:xmpp-stanzas'/><br />
<text xml:lang='en' xmlns='urn:ietf:params:xml:ns:xmpp-stanzas'><br />
Some special application diagnostic information...<br />
</text><br />
<special-application-condition xmlns='application-ns'/><br />
</error><br />
</message><br />
</source><br />
<br />
==服务器处理XML节的规则==<br />
<br />
:兼容的服务器实现必须(MUST)确保两个实体之间的XML节按次序处理.<br />
<br />
:在按次序处理的需求之外, 每个服务器实现将包含它自己的递送树"delivery tree"以处理它接收到的节.这个树决定一个节是否需要路由到其他域, 在内部处理, 还是递送到和一个已连接的节点相关的资源. 以下规则适用:<br />
<br />
===没有'to'地址===<br />
<br />
:如果这个节没有'to'属性, 服务器应该(SHOULD)为发送它的实体处理这个节. 因为所有从其他服务器收到的节必须(MUST)拥有'to'属性, 这个规则仅适用于从一个连接到这台服务器的已注册实体(如一个客户端)收到的节.如果这个服务器收到一个没有'to'属性的出席信息节, 服务器应该(SHOULD)向那些订阅了这个发送实体的出席信息的所有实体广播它, 如果可能的话(即时消息和出席信息应用程序中出席信息广播的语义定义在[XMPP-IM|XMPP文档列表/XMPP正式RFC标准/RFC3921]). 如果服务器接收到一个类型为"get" 或 "set" 的没有'to'属性的节并且它理解这个节的名字空间下的内容, 它必须(MUST)为这个发送实体处理节(在这里"process"的含义是由相关的名字空间的语义所决定的)或返回一个错误给发送实体.<br />
<br />
===外部域===<br />
<br />
:如果'to'属性中的JID的域ID部分的主机名和服务器自身或其子域配置的主机名不匹配, 服务器应该(SHOULD)路由这个节到外部域(取决于本地服务规定或安全策略关于域间通信的规定).有两种可能的情况:<br />
<br />
::- 一个服务器之间的流已经存在于两个域之间: 发送者的服务器通过这个已存在的流为这个外部域路由这个节到授权服务器<br />
<br />
::- 两个域之间不存在服务器间的流: 发送者服务器 (1) 解析这个外部域的主机名(定义在服务器间的通信Server-to-Server Communications (第十四章第四节)), (2) 在两个域之间进行服务器到服务器的流协商(定义在 Use of TLS (第五章) 和 Use of SASL (第六章)), 然后 (3) 通过这个新建的流为外部域路由这个节到授权服务器<br />
<br />
:如果路由到接收者的服务器不成功, 发送者的服务器必须(MUST)返回一个错误给发送者; 如果接收者的服务器联系上了但是从接收者的服务器递送到接收者不成功, 接收者服务器必须(MUST)通过发送者的服务器返回一个错误给发送者.<br />
<br />
===子域===<br />
<br />
:如果'to'属性中的JID的域ID部分的主机名和服务器自身配置的主机名的一个子域名匹配,服务器必须(MUST)自己处理这个节或路由这个节到专门负责这个子域的特定服务(如果子域被配置了),或者返回一个错误给发送者(如果子域没有配置).<br />
<br />
===纯粹的域或特定的资源===<br />
<br />
:如果'to'属性中的JID的域ID部分的主机名和服务器自身配置的主机名本身匹配,并且'to'属性中的JID类型是<domain> 或 <domain/resource>, 服务器(或其中定于的资源)必须(MUST)根据节的类型适当的处理这个节或返回一个错误节给发送者.<br />
<br />
===同一域中的节点===<br />
<br />
:如果'to'属性中的JID的域ID部分的主机名和服务器自身配置的主机名本身匹配,并且'to'属性中的JID类型是<node@domain> 或 <node@domain/resource>, 服务器应该(SHOULD)递送这个节到节的'to'属性中的JID所指明的预定的接收者. 以下规则适用:<br />
<br />
:# 如果这个JID包含一个资源ID(例如, 格式是<node@domain/resource>)并且存在一个连接的资源符合这个全JID, 接收者服务器应该(SHOULD)递送这个节给正确符合这个资源ID的流或会话.<br />
:# 如果这个JID包含一个资源ID(例如, 格式是<node@domain/resource>)并且不存在一个连接的资源符合这个全JID, 接收者服务器应该(SHOULD)返回一个<service-unavailable/> 节错误给发送者.<br />
:# 如果这个JID的格式是<node@domain>并且存在至少一个此节点的连接资源, 接收服务器应该( SHOULD)递送这个节给至少其中一个已连接的资源, 依据应用程序定义的规则(一系列即时消息和出席信息应用程序的递送规则定义在[XMPP-IM|XMPP文档列表/XMPP正式RFC标准/RFC3921]).<br />
<br />
==XMPP中的XML用法==<br />
<br />
===限制===<br />
<br />
:XMPP是一个简单的流式XML元素的专用协议用于接近实时地交换结构化信息. 因为XMPP不需要任意的解析和所有的XML文档, 所以XMPP不需要支持\[XML\]的所有功能. 特殊的, 适用以下限制.<br />
<br />
:关于XML生成, 一个XMPP实现不能(MUST NOT)在XML流中注入以下任何东西:<br />
<br />
:* 注释 (第二章第五节[XML])<br />
<br />
:* 处理指示(第二章第六节 同上)<br />
<br />
:* 内部或外部的 DTD 子集 (第二章第八节 同上)<br />
<br />
:* 内部或外部的实体参考 (第四章第二节 同上) 除了预定实体以外(第四章第六节 同上)<br />
<br />
:* 字符数据或属性值包含和预定实体列表中吻合的未逃逸的unescaped字符(第四章第六节 同上); 这些字符必须(MUST)逃逸<br />
<br />
:关于XML处理, 如果一个XMPP实现接收到这些受限的XML数据,它必须(MUST)忽略这些数据.<br />
<br />
===XML 名字空间的名字和前缀===<br />
<br />
:XML名字空间\[XML-NAMES\]为所有XMPP兼容的XML建立数据所有权的严格界限. 这个名字空间的基本功能是把结构上混合在一起的XML元素区分出不同的词汇. 确保XMPP兼容的XML有名字空间的感知能力使得任何允许的XML可以被结构化的混合到任何XMPP数据元素中. XML名字空间的名字和前缀的规则在下一小节中.<br />
<br />
====流名字空间====<br />
<br />
:在所有的XML流头中必须声明一个流名字空间. 流名字空间必须(MUST)是 'http://etherx.jabber.org/streams'. 元素名<stream/>和它的<features/>和<error/>子元素必须(MUST)在所有实例中符合这个流名字空间前缀. 一个实现应该(SHOULD)只为这些元素生成'stream:'前缀, 并且由于历史原因可以(MAY)只接受'stream:'前缀.<br />
<br />
====缺省名字空间====<br />
<br />
:在所有的XML流中必须声明一个缺省的流名字空间用于定义允许的流根元素的一级子元素. 这个名字空间声明对于初始化流和应答流必须(MUST)是相同的使得双方的流都是合格一致的. 缺省的名字空间声明适用于流和所有在流中发送的节(除非由流名字空间或回拨名字空间的前缀显式的符合另一个名字空间).<br />
<br />
:一个服务器实现必须(MUST)支持以下两个缺省名字空间(由于历史原因, 一些实现可能(MAY)只支持这两个缺省名字空间):<br />
<br />
:* jabber:client -- 当流用于客户端和服务器的通信时声明这个缺省名字空间<br />
<br />
:* jabber:server -- 当流用于两个服务器间的通信时声明这个缺省名字空间<br />
<br />
:一个客户端实现必须(MUST)支持'jabber:client'缺省名字空间,并且由于历史原因可以(MAY)只支持这个缺省名字空间.<br />
<br />
:如果缺省名字空间是'jabber:client'或'jabber:server',一个实施不能(MUST NOT)在这个名字空间下为元素生成名字空间前缀. 一个实现不应该(SHOULD NOT)按照元素的内容(可能和流相反)生成不同于'jabber:client'和'jabber:server'名字空间前缀.<br />
<br />
:注意: 'jabber:client' 和 'jabber:server' 名字空间接近于相同但是用于不同的上下文(客户端服务器通信用'jabber:client' 而服务器间通信用'jabber:server'). 这两者之间仅有的不同在于在'jabber:client'中被发送的节中'to'和'from'属性是可选的(OPTIONAL),而在'jabber:server'中被发送的节中它们是必需的(REQUIRED). 如果兼容的实施接受一个符合'jabber:client'或'jabber:server'名字空间的流, 它必须(MUST)支持通用属性(第九章第一节)和三个核心节类型(message, presence, 和IQ)的基本语义(第九章第二节).<br />
<br />
====回拨名字空间====<br />
<br />
:所有用于服务器回拨的(第八章)元素都必须声明一个回拨名字空间. 回拨名字空间的名字必须(MUST)是'jabber:server:dialback'. 所有符合此名字空间的元素必须(MUST)有前缀. 一个实现应该(SHOULD)只为这些元素生成'db:'前缀并且只可以(MAY)接受'db:'前缀.<br />
<br />
===确认===<br />
<br />
:除了注意'jabber:server'名字空间中关于节中'to'和'from'地址的规定,一个服务器不需要为转发到客户端或其他服务器负责检查XML元素;一个实现可以(MAY)选择仅提供有效数据元素但这是可选的(OPTIONAL)(尽管一个实现不能(MUST NOT)接受不规范的XML). 客户端不应该(SHOULD NOT)滥用发送不符合schema的数据的能力, 并且应该(SHOULD)忽略接收到的XML流中任何和schema不一致的元素或属性值. XML流和节的有效性确认是可选的(OPTIONAL),并且在这里提到的schemas仅用于描述的用途.<br />
<br />
===文本声明的包含===<br />
<br />
:实现应该(SHOULD)在发送一个流头信息之前发送一个文本声明. 应用程序必须(MUST)遵守\[XML\]中关于环境(那里对文本声明做了规定)的规则.<br />
<br />
===字符编码===<br />
<br />
:实现必须(MUST)支持通用字符集Universal Character Set (ISO/IEC 10646-1 \[UCS2\])字符到UTF\-8(RFC 3629 \[UTF\-8\])的转换, 必须符合 RFC 2277 \[CHARSET\]. 实现不能(MUST NOT)试图使用任何其他的编码.<br />
<br />
==核心的兼容性要求==<br />
<br />
:本章总结了可扩展的消息和出席信息协议中的某些方面,为了实施的兼容性,它们必须(MUST)被服务器和客户端支持,当然协议的其他方面也应该(SHOULD)被支持. 为了兼容的目的, 我们在核心协议(它必须(MUST)被任何服务器或客户端支持, 无论是什么特定的应用)和即时消息协议(仅仅是在核心协议之上的即时消息和出席信息应用必须(MUST)支持它)之间划了一个级别. 在本章中定义了所有服务器和客户端的兼容性要求; 即时消息服务器和客户端的兼容性要求在[XMPP-IM|XMPP文档列表/XMPP正式RFC标准/RFC3921]的相关章节中定义.<br />
<br />
===服务器===<br />
<br />
:除了所有已定义的关于安全, XML使用, 和国际化的要求之外, 一个服务器还必须(MUST)支持以下核心协议以保证兼容性:<br />
<br />
:* 在地址中应用\[STRINGPREP\] 的 \[NAMEPREP\], Nodeprep (附录 A),和 Resourceprep (附录 B) profiles (包括确保域ID是\[IDNA\]中定义的国际化域名)<br />
<br />
:* XML流(第四章), 包括Use of TLS(第五章), Use of SASL(第六章), 和Resource Binding (第七章)<br />
<br />
:* 三个在stanza semantics(第九章第二节)中已定义的节类型(即,<message/>, <presence/>, 和<iq/>)的基本语义<br />
<br />
:* 生成错误的语法及相关的流, TLS, SASL, 和 XML节的语义<br />
<br />
:另外, 一个服务器可以(MAY)支持以下核心协议:<br />
<br />
:* 服务器回拨 (第八章)<br />
<br />
===客户端===<br />
<br />
:一个客户端必须(MUST)支持以下核心协议以满足兼容性:<br />
<br />
:* XML流(第四章), 包括Use of TLS(第五章), Use of SASL(第六章), 和Resource Binding (第七章)<br />
<br />
:* 三个在stanza semantics(第九章第二节)中已定义的节类型(即,<message/>, <presence/>, 和<iq/>)的基本语义<br />
<br />
:* 处理(并且, 如果可能, 生成) 错误的语法及相关的流, TLS, SASL, 和 XML节的语义<br />
<br />
:另外, 一个客户端应该(SHOULD)支持以下核心协议:<br />
<br />
:* 地址的生成应用\[STRINGPREP\] 的 \[NAMEPREP\], Nodeprep (附录 A),和 Resourceprep (附录 B) profiles <br />
<br />
==国际化事项==<br />
<br />
:XML流在Character Encoding(第十一章第五节)中定义为必须(MUST)被编码成UTF\-8. 在Stream Attributes(第四章第四节)中特别定义了, 一个XML流应该(SHOULD)包含一个'xml:lang'属性,它被认为是通过这个用于人类用户解读的流发送的任何XML字符数据的缺省语言. 在 xml:lang (第九章第一节第五小节)特别定义了, 如果一个XML节是用来给人类用户解读,这个节应该(SHOULD)包含一个'xml:lang'属性. 服务器在为连接的实体路由或递送节的时候应该(SHOULD)应用缺省的'xml:lang'属性, 并且不能(MUST NOT)修改或删除它从其他实体收到的节的'xml:lang'属性.<br />
<br />
==安全性事项==<br />
<br />
===高安全性===<br />
<br />
:为了XMPP通信的目的(客户端-服务器 和 服务器-服务器), "高安全性"条款谈的是相互验证和完整性检查安全性技术的使用; 特别是, 当使用基于证书的验证来提供高安全性, 应该( SHOULD)建立一个带外的信任链,尽管一个共享签名证书可能允许以前不知道的证书在带内建立信任关系. 参见以下第十四章第二节关于证书确认程序.<br />
<br />
:实施必须(MUST)支持高安全性. 服务提供者应该(SHOULD)基于本地安全策略使用高安全性.<br />
<br />
===证书确认===<br />
<br />
:当一个XMPP点和另一个XMPP点安全的地通信, 它必须(MUST)确认对方终端的证书.有三种可能的情况:<br />
<br />
:情形 #1: 点包含一个终端实体证书,以根证书的证书链中一环出现(见\[X509\]中的第六章第一节).<br />
<br />
:情形 #2: 点的证书由一个对方不知道的证书授权.<br />
<br />
:情形 #3: 点的证书由自己签名.<br />
<br />
:在情形#1, 确认方必须(MUST)做以下两条之一:<br />
<br />
:# 根据\[X509\]的规则确认对方证书.然后证书应该(SHOULD)被对方接下来在\[HTTP-TLS\]中描述的规则反向确认预期的身份。但如果"xmpp"是subjectAltName扩展类型,则必须(MUST)使用证书中的显示的身份。如果这两项检查之一失败,用户导向的客户端必须(MUST)通知用户(客户端可以(MAY)给用户机会继续连接)或以一个坏证书的错误终止连接。自动客户端应该(SHOULD)终止连接(以一个坏证书错误)并在适当的日志中记录这个错误。自动客户端可以(MAY)提供一个配置设置成禁止检查,但同时必须(MUST)提供一个激活检查的配置。<br />
:# 点应该(SHOULD)出示证书给一个用户用于批准,包括完整的证书链.点必须(MUST)缓存这个证书(或一些其他不会忘记的表达方式比如一个哈希值).在将来的连接中,点必须(MUST)展示相同的证书并且如果改变了证书必须(MUST)通知用户.<br />
<br />
:在情形#2 和情形#3, 实现应该(SHOULD)执行上述第二条.<br />
<br />
===客户端-服务器通信===<br />
<br />
:一个兼容的客户端实现必须(MUST)支持TLS和SASL用于连接到服务器.<br />
<br />
:用于加密XML流的TLS协议(在 Use of TLS(第五章)定义)提供可信的机制帮助确保机密性和实体之间数据交换的完整性.<br />
<br />
:用于验证XML流的SASL协议(在 Use of SASL(第六章)定义)提供可靠的机制用于确认一个连接到服务器的客户端确实是它自己所声明的那个客户端.<br />
<br />
:服务器宣称的DNS主机名被解析之前,客户端-服务器通信不能(MUST NOT)继续进行。应该首先尝试解析\[SRV\]记录,其服务名为"xmpp-client",协议名为"tcp",整个资源记录类似"_xmpp-client._tcp.example.com."(使用字符"xmpp-client"表示服务ID是经过IANA注册).如果SRV查找失败,退而求其次,将查找一个正规的IPv4/IPv6地址记录来决定IP地址,使用"xmpp-client"端口5222,这个端口是在IANA注册了的。<br />
<br />
:客户端的IP地址和访问方法不能(MUST NOT)被服务器公开, 也不能被被任何原始服务器之外的服务器索取。这帮助保护客户端的服务器避免受到直接攻击(译者注:似乎应该是客户避免受到直接攻击,但原文如此)或被第三方知道它的身份。<br />
<br />
===服务器-服务器通信===<br />
<br />
:一个兼容的服务器实现必须(MUST)支持TLS和SASL,用于域间的通信.因为历史原因,一个兼容的实施也应该(SHOULD)支持服务器回拨(第八章).<br />
<br />
:因为服务提供者是一个策略问题,对于任何给定域和其他域的通信中,它是可选的(OPTIONAL),服务器之间的通信可以(MAY)被任何特定部署的管理员禁止。如果一个特殊的域允许域间的通信,它应该(SHOULD)允许高安全性。<br />
<br />
:管理员可能想在服务器间使用SASL来通信,以确保双方的验证和保密性(比如在机构的私有网络).兼容实施应该(SHOULD)为这个目的支持SASL.<br />
<br />
:服务器宣称的DNS主机名被解析之前,服务器-服务器通信不能(MUST NOT)继续进行。应该首先尝试解析\[SRV\]记录,其服务名为"xmpp-server",协议名为"tcp",整个资源记录类似"_xmpp-server._tcp.example.com."(使用字符"xmpp-server"表示服务ID是经过IANA注册的,注意要用"xmpp-server"取代以前用的"jabber",因为以前的用法不符合[SRV]标准;希望保持向后兼容的实现可以继续查找或应答"jabber"服务ID).如果SRV查找失败,退而求其次,将查找一个正规的IPv4/IPv6地址记录来决定IP地址,使用"xmpp-server"端口5269,这个端口是在IANA注册了的。<br />
<br />
:服务器回拨防止域欺骗,从而使得伪造XML节更为困难.它和SASL和TLS不一样,它不是一个用于验证、安全或加密服务器之间的流的机制, 所以只是服务器身份的微弱确认而已。而且除非它使用了DNSSec \[DNSSEC\]否则它 容易受到DNS中毒攻击,即使DNS信息是正确的,如果攻击者劫持了远程域,回拨也不能防止它的攻击.需要健壮的安全性的域应该(SHOULD)使用TLS和SASL.如果服务器间的验证使用了SASL,回拨就不应该(SHOULD NOT)使用了,因为它是多余的.<br />
<br />
===层的次序===<br />
<br />
:协议中的层的次序必须(MUST)如下堆积:<br />
<br />
:# TCP<br />
:# TLS<br />
:# SASL<br />
:# XMPP<br />
<br />
:这个次序的原理是,[TCP]是基于连接的层,被所有使用,所以处于最上层, [TLS]经常是由操作系统层提供,[SASL]经常由应用程序层提供, XMPP则是应用程序本身.<br />
<br />
===缺乏绑定到TLS的SASL通道===<br />
<br />
:SASL构架不提供一个机制来绑定SASL验证到一个提供机密性和完整性保护的安全层。这一通道绑定"channel binding"的缺乏阻碍了SASL确认低层安全性所绑定的源和目标终端和SASL所验证的结果是否一致。如果终端不一致, 低层安全性不能被信任用来保护SASL验证的实体之间的数据传输。在这种情况下,一个SASL安全层进行握手的时候应该有效的忽略低层安全性的存在。<br />
<br />
===强制实现的技术===<br />
<br />
:最低要求, 所有实现必须(MUST)支持以下机制:<br />
<br />
::对于验证: SASL [DIGEST-MD5] 机制<br />
<br />
::对于机密性: TLS (使用 TLS_RSA_WITH_3DES_EDE_CBC_SHA 密码)<br />
<br />
::对于两者: TLS 加 SASL EXTERNAL(使用 TLS_RSA_WITH_3DES_EDE_CBC_SHA 密码支持客户端证书)<br />
<br />
===防火墙===<br />
<br />
:使用XMPP通信通常是通过\[TCP\]连接到5222端口(客户端-服务器)或5269端口(服务器-服务器), 正如在IANA注册的那样(见 IANA Considerations (第十五章)). 使用这些广为人知的端口允许管理员很容易的通过一般的防火墙来激活或禁止XMPP活动.<br />
<br />
===在SASL中使用base64===<br />
<br />
:客户端和服务器都必须(MUST)确认在SASL协商中收到的任何\[BASE64\]数据. 一个实现必须(MUST)拒绝(不是忽略)任何非显式允许base64字母的字符串; 这有助于预防建立隐蔽通道泄漏信息的行为。一个实现不能(MUST NOT)在非法输入处中断,如果那个('=')被包含在一些和最后的数据字符(如, "=AAA" or "BBBB=CCC")不同的东西里面,必须(MUST)拒绝接下来的任何包含('=')的base64字符;这有助于防止对这个实现的缓存溢出攻击和其他攻击。Base 64编码从外表看隐藏了容易辨认的信息,例如密码,但是不提供任何算法机密性。Base 64编码必须(MUST)按照RFC 3548\[BASE64\]第三章的定义执行。<br />
<br />
===Stringprep Profiles===<br />
<br />
:为了处理域ID,XMPP使用了\[STRINGPREP\]中的\[NAMEPREP\] profile; 和Nameprep有关的安全性考虑, 参考\[NAMEPREP\]中的相关章节.<br />
<br />
:另外, XMPP 定义了两个\[STRINGPREP\]的 profiles: 用于node identifiers的Nodeprep(附录 A)和用于resource identifiers的Resourceprep(附录 B).<br />
<br />
:Unicode 和 ISO/IEC 10646 集有许多字符看起来相似. 在许多时候, 安全协议的使用者可能看起来吻合,比如当比较信任的第三方的名字的时候. 因为没有很多上下文的时候不可能映射看起来相似的字符,比如知道所用的字符集, stringprep不匹配相似字符串,也不因为一些字符串象看起来象别的字符串而禁止它们.<br />
<br />
:一个节点ID可能被作为一个实体的XMPP地址的一部分. 一个通常的用途是作为一个即时消息用户的用户名;另一个用途是作为一个多用途聊天室的名字; 很多其他种类的实体可能使用节点ID作为他们的地址的一部分。 这些服务的安全性可能会受到国际化节点ID的不同表达的威胁;例如, 一个用户键入一个单独的国际化的节点ID可能访问了另一个用户的帐号信息, 或一个用户可能获得访问一个受限的聊天室或服务的访问权限.<br />
<br />
:一个资源ID可能被作为一个实体的XMPP地址的一部分。一个通常的用户是即时消息用户所连接的资源(激活的会话)的名字; 另一个是作为多用户聊天室的某用户的昵称; 许多其他种类的实体可能使用资源ID作为他们地址的一部分.这些服务的安全性可能会受到国际化资源ID的不同表达的威胁;例如, 一个用户可能尝试以同一个名字初始化多个会话,或一个用户可能发送一个消息给多用户聊天室的一个人但实际上发给了另外一个人.<br />
<br />
==IANA 事项==<br />
<br />
===用于TLS数据的XML名字空间名===<br />
<br />
:XMPP中用于TLS相关数据的 URN 子名字空间定义如下. (这个名字空间的名字遵守The IETF XML Registry [XML-REG]定义的格式.)<br />
<br />
::URI: urn:ietf:params:xml:ns:xmpp-tls<br />
<br />
::Specification: RFC 3920<br />
<br />
::Description: This is the XML namespace name for TLS-related data in the Extensible Messaging and Presence Protocol (XMPP) as defined by RFC 3920.<br />
<br />
::Registrant Contact: IETF, XMPP Working Group, <xmppwg@jabber.org><br />
<br />
===用于SASL数据的XML名字空间名===<br />
<br />
:XMPP中用于SASL相关数据的 URN 子名字空间定义如下. (这个名字空间的名字遵守The IETF XML Registry \[XML-REG\]定义的格式.)<br />
<br />
::URI: urn:ietf:params:xml:ns:xmpp-sasl<br />
<br />
::Specification: RFC 3920<br />
<br />
::Description: This is the XML namespace name for SASL-related data in the Extensible Messaging and Presence Protocol (XMPP) as defined by RFC 3920.<br />
<br />
::Registrant Contact: IETF, XMPP Working Group, <xmppwg@jabber.org><br />
<br />
===用于流错误的XML名字空间名===<br />
<br />
:XMPP中用于流相关错误的 URN 子名字空间定义如下. (这个名字空间的名字遵守The IETF XML Registry [XML-REG]定义的格式.)<br />
<br />
::URI: urn:ietf:params:xml:ns:xmpp-streams<br />
<br />
::Specification: RFC 3920<br />
<br />
:Description: This is the XML namespace name for stream-related error data in the Extensible Messaging and Presence Protocol (XMPP) as defined by RFC 3920.<br />
<br />
::Registrant Contact: IETF, XMPP Working Group, <xmppwg@jabber.org><br />
<br />
===用于资源绑定的XML名字空间名===<br />
<br />
:XMPP中用于资源绑定的 URN 子名字空间定义如下. (这个名字空间的名字遵守The IETF XML Registry [XML-REG]定义的格式.)<br />
<br />
::URI: urn:ietf:params:xml:ns:xmpp-bind<br />
<br />
::Specification: RFC 3920<br />
<br />
::Description: This is the XML namespace name for resource binding in the Extensible Messaging and Presence Protocol (XMPP) as defined by RFC 3920.<br />
<br />
::Registrant Contact: IETF, XMPP Working Group, <xmppwg@jabber.org><br />
<br />
===用于节错误的XML名字空间名===<br />
<br />
:XMPP中用于节相关错误数据的 URN 子名字空间定义如下. (这个名字空间的名字遵守The IETF XML Registry \[XML-REG\]定义的格式.)<br />
<br />
::URI: urn:ietf:params:xml:ns:xmpp-stanzas<br />
<br />
::Specification: RFC 3920<br />
<br />
::Description: This is the XML namespace name for stanza-related error data in the Extensible Messaging and Presence Protocol (XMPP) as defined by RFC 3920.<br />
<br />
::Registrant Contact: IETF, XMPP Working Group, <xmppwg@jabber.org><br />
<br />
===Nodeprep Profile of Stringprep===<br />
<br />
:The Nodeprep profile of stringprep是在Nodeprep(附录 A)定义的. IANA已经在stringprep profile registry中注册了 Nodeprep.<br />
<br />
::Name of this profile:<br />
<br />
:::Nodeprep<br />
<br />
::RFC in which the profile is defined:<br />
<br />
:::RFC 3920<br />
<br />
::Indicator whether or not this is the newest version of the profile:<br />
<br />
:::This is the first version of Nodeprep<br />
<br />
===Resourceprep Profile of Stringprep===<br />
<br />
:The Resourceprep profile of stringprep是在Resourceprep(附录 B)定义的. IANA已经在stringprep profile registry中注册了Resourceprep.<br />
<br />
::Name of this profile:<br />
<br />
:::Resourceprep<br />
<br />
::RFC in which the profile is defined:<br />
<br />
:::RFC 3920<br />
<br />
::Indicator whether or not this is the newest version of the profile:<br />
<br />
:::This is the first version of Resourceprep<br />
<br />
===GSSAPI 服务名===<br />
<br />
:IANA已经注册了 "xmpp" 作为一个 GSSAPI \[GSS-API\] 服务名, 在SASL Definition (第六章第三节)定义了.<br />
<br />
===端口号===<br />
<br />
:IANA已经注册了"xmpp-client" 和 "xmpp-server" 作为\[TCP\]端口号5222和5269的关键字.<br />
<br />
:这些端口应该(SHOULD)用于客户端-服务器 和 服务器-服务器通信,但它们的使用是可选的(OPTIONAL).<br />
<br />
==参考==<br />
<br />
===标准化参考===<br />
<br />
:[ABNF] Crocker, D. and P. Overell, "Augmented BNF for Syntax Specifications: ABNF", RFC 2234, November 1997.<br />
<br />
:[BASE64] Josefsson, S., "The Base16, Base32, and Base64 Data Encodings", RFC 3548, July 2003.<br />
<br />
:[CHARSET] Alvestrand, H., "IETF Policy on Character Sets and Languages", BCP 18, RFC 2277, January 1998.<br />
<br />
:[DIGEST-MD5] Leach, P. and C. Newman, "Using Digest Authentication as a SASL Mechanism", RFC 2831, May 2000.<br />
<br />
:[DNS] Mockapetris, P., "Domain names \- implementation and specification", STD 13, RFC 1035, November 1987.<br />
<br />
:[GSS-API] Linn, J., "Generic Security Service Application Program Interface Version 2, Update 1", RFC 2743, January 2000.<br />
<br />
:[HTTP-TLS] Rescorla, E., "HTTP Over TLS", RFC 2818, May 2000.<br />
<br />
:[IDNA] Faltstrom, P., Hoffman, P., and A. Costello, "Internationalizing Domain Names in Applications (IDNA)", RFC 3490, March 2003.<br />
<br />
:[IPv6] Hinden, R. and S. Deering, "Internet Protocol Version 6 (IPv6) Addressing Architecture", RFC 3513, April 2003.<br />
<br />
:[LANGTAGS] Alvestrand, H., "Tags for the Identification of Languages", BCP 47, RFC 3066, January 2001.<br />
<br />
:[NAMEPREP] Hoffman, P. and M. Blanchet, "Nameprep: A Stringprep Profile for Internationalized Domain Names (IDN)", RFC 3491, March 2003.<br />
<br />
:[RANDOM] Eastlake 3rd, D., Crocker, S., and J. Schiller, "Randomness Recommendations for Security", RFC 1750, December 1994.<br />
<br />
:[SASL] Myers, J., "Simple Authentication and Security Layer (SASL)", RFC 2222, October 1997.<br />
<br />
:[SRV] Gulbrandsen, A., Vixie, P., and L. Esibov, "A DNS RR for specifying the location of services (DNS SRV)", RFC 2782, February 2000.<br />
<br />
:[STRINGPREP] Hoffman, P. and M. Blanchet, "Preparation of Internationalized Strings ("stringprep")", RFC 3454, December 2002.<br />
<br />
:[TCP] Postel, J., "Transmission Control Protocol", STD 7, RFC 793, September 1981.<br />
<br />
:[TERMS] Bradner, S., "Key words for use in RFCs to Indicate Requirement Levels", BCP 14, RFC 2119, March 1997.<br />
<br />
:[TLS] Dierks, T. and C. Allen, "The TLS Protocol Version 1.0", RFC 2246, January 1999.<br />
<br />
:[UCS2] International Organization for Standardization, "Information Technology \- Universal Multiple-octet coded Character Set (UCS) - Amendment 2: UCS Transformation Format 8 (UTF-8)", ISO Standard 10646-1 Addendum 2, October 1996.<br />
<br />
:[UTF-8] Yergeau, F., "UTF-8, a transformation format of ISO 10646", STD 63, RFC 3629, November 2003.<br />
<br />
:[X509] Housley, R., Polk, W., Ford, W., and D. Solo, "Internet X.509 Public Key Infrastructure Certificate and Certificate Revocation List (CRL) Profile", RFC 3280, April 2002.<br />
<br />
:[XML] Bray, T., Paoli, J., Sperberg-McQueen, C., and E. Maler, "Extensible Markup Language (XML) 1.0 (2nd ed)", W3C REC-xml, October 2000, <http://www.w3.org/TR/REC-xml>.<br />
<br />
:[XML-NAMES] Bray, T., Hollander, D., and A. Layman, "Namespaces in XML", W3C REC-xml-names, January 1999, <http://www.w3.org/TR/REC-xml-names>.<br />
<br />
===信息参考===<br />
<br />
:[ACAP] Newman, C. and J. Myers, "ACAP \-\- Application Configuration Access Protocol", RFC 2244, November 1997.<br />
<br />
:[ASN.1] CCITT, "Recommendation X.208: Specification of Abstract Syntax Notation One (ASN.1)", 1988.<br />
<br />
<br />
:[DNSSEC] Eastlake 3rd, D., "Domain Name System Security Extensions", RFC 2535, March 1999.<br />
<br />
:[HTTP] Fielding, R., Gettys, J., Mogul, J., Frystyk, H., Masinter, L., Leach, P., and T. Berners-Lee, "Hypertext Transfer Protocol -- HTTP/1.1", RFC 2616, June 1999.<br />
<br />
:[IMAP] Crispin, M., "INTERNET MESSAGE ACCESS PROTOCOL - VERSION 4rev1", RFC 3501, March 2003.<br />
<br />
:[IMP-REQS] Day, M., Aggarwal, S., Mohr, G., and J. Vincent, "Instant Messaging \/ Presence Protocol Requirements", RFC 2779, February 2000.<br />
<br />
:[IRC] Oikarinen, J. and D. Reed, "Internet Relay Chat Protocol", RFC 1459, May 1993.<br />
<br />
:[JEP-0029] Kaes, C., "Definition of Jabber Identifiers (JIDs)", JSF JEP 0029, October 2003.<br />
<br />
:[JEP-0078] Saint-Andre, P., "Non-SASL Authentication", JSF JEP 0078, July 2004.<br />
<br />
[JEP-0086] Norris, R. and P. Saint-Andre, "Error Condition Mappings", JSF JEP 0086, February 2004.<br />
<br />
:[JSF] Jabber Software Foundation, "Jabber Software Foundation", <http://www.jabber.org/>.<br />
<br />
:[POP3] Myers, J. and M. Rose, "Post Office Protocol - Version 3", STD 53, RFC 1939, May 1996.<br />
<br />
:[SIMPLE] SIMPLE Working Group, "SIMPLE WG", <http://www.ietf.org/html.charters/simple-charter.html>.<br />
<br />
:[SMTP] Klensin, J., "Simple Mail Transfer Protocol", RFC 2821, April 2001.<br />
<br />
:[URI] Berners-Lee, T., Fielding, R., and L. Masinter, "Uniform Resource Identifiers (URI): Generic Syntax", RFC 2396, August 1998.<br />
<br />
:[USINGTLS] Newman, C., "Using TLS with IMAP, POP3 and ACAP", RFC 2595, June 1999.<br />
<br />
:[XML-REG] Mealling, M., "The IETF XML Registry", BCP 81, RFC 3688, January 2004.<br />
<br />
:[[RFC3921]] Saint-Andre, P., Ed., "Extensible Messaging and Presence Protocol (XMPP): Instant Messaging and Presence", RFC 3921, October 2004.<br />
<br />
<br />
==附录 A. Nodeprep==<br />
<br />
===A.1. 介绍===<br />
<br />
:这个附录定义了 "Nodeprep" profile of [STRINGPREP]. 它定义了处理规则让用户能够在XMPP中输入国际化节点标识符并尽可能正确的获取正确的字符内容. (一个XMPP节点标识符是XMPP地址的可选部分,它在域名标识符和那个'@'分隔符之前;它经常但不是专门用来关联一个即时消息用户名)这些处理规则仅仅适用于XMPP节点标识符但不适用于任意文本或任何XMPP的其他方面.<br />
<br />
:这个脚本定义了以下这些, 正如 [STRINGPREP]要求的:<br />
<br />
:* 脚本预期的适用性: XMPP的国际化节点标识符<br />
<br />
:* 用于stringprep的输入输出字符集: Unicode 3.2, 定义在本附录的第二章<br />
<br />
:* 使用的映射: 定义在第三章<br />
<br />
:* Unicode正规化使用: 定义在第四章<br />
<br />
:* 禁止输出的字符串: 定义在第五章<br />
<br />
:* 双字节字符处理: 定义在第六章<br />
<br />
===A.2. 字符集===<br />
<br />
:本脚本使用Unicode 3.2的未分配编码列表,指向 Table A.1, 也定义在 [STRINGPREP]的附录 A 中.<br />
<br />
===A.3. 映射===<br />
<br />
:本脚本指定使用[STRINGPREP]的以下表:<br />
<br />
::Table B.1<br />
<br />
::Table B.2<br />
<br />
===A.4. 正规化===<br />
<br />
:本脚本指定 Unicode正规化使用 form KC, 定义在 [STRINGPREP]中.<br />
<br />
===A.5. 禁止输出===<br />
<br />
:本脚本指定使用以下的[STRINGPREP]表禁止输出.<br />
<br />
::Table C.1.1<br />
<br />
::Table C.1.2<br />
<br />
::Table C.2.1<br />
<br />
::Table C.2.2<br />
<br />
::Table C.3<br />
<br />
::Table C.4<br />
<br />
::Table C.5<br />
<br />
::Table C.6<br />
<br />
::Table C.7<br />
<br />
::Table C.8<br />
<br />
::Table C.9<br />
<br />
:另外, 以下Unicode字符也被禁止:<br />
<br />
: #x22 (")<br />
<br />
: #x26 (&)<br />
<br />
: #x27 (')<br />
<br />
: #x2F (/)<br />
<br />
: #x3A (:)<br />
<br />
: #x3C (<)<br />
<br />
: #x3E (>)<br />
<br />
: #x40 (@)<br />
<br />
===A.6. 双字节===<br />
<br />
:本脚本指定按照[STRINGPREP]第六章检查双字节.<br />
<br />
==附录 B. Resourceprep==<br />
<br />
===B.1. 介绍===<br />
<br />
:这个附录定义了 "Resourceprep" profile of \[STRINGPREP\]. 它定义了处理规则让用户能够在XMPP中输入国际化资源标识符并尽可能正确的获取正确的字符内容. (一个XMPP资源标识符是XMPP地址的可选部分,它在域名标识符和'/@'分隔符之后;它经常但不是专门用来关联一个即时消息会话名)这些处理规则仅仅适用于XMPP资源标识符但不适用于任意文本或任何XMPP的其他方面.<br />
<br />
:这个脚本定义了以下这些, 正如 [STRINGPREP]要求的:<br />
<br />
:* 脚本预期的适用性: XMPP的国际化节点标识符<br />
<br />
:* 用于stringprep的输入输出字符集: Unicode 3.2, 定义在本附录的第二章<br />
<br />
:* 使用的映射: 定义在第三章<br />
<br />
:* Unicode正规化使用: 定义在第四章<br />
<br />
:* 禁止输出的字符串: 定义在第五章<br />
<br />
:* 双字节字符处理: 定义在第六章<br />
<br />
===B.2. 字符集===<br />
<br />
:本脚本使用Unicode 3.2的未分配编码列表,指向 Table A.1, 也定义在 [STRINGPREP]的附录<br />
<br />
===B.3. 映射===<br />
<br />
:本脚本指定使用[STRINGPREP]的以下表:<br />
<br />
::Table B.1<br />
<br />
===B.4. 正规化===<br />
<br />
:本脚本指定使用 Unicode normalization form KC, 定义在 [STRINGPREP]中.<br />
<br />
===B.5. 禁止输出===<br />
<br />
:本脚本指定使用以下的[STRINGPREP]表禁止输出.<br />
<br />
::Table C.1.2<br />
<br />
::Table C.2.1<br />
<br />
::Table C.2.2<br />
<br />
::Table C.3<br />
<br />
::Table C.4<br />
<br />
::Table C.5<br />
<br />
::Table C.6<br />
<br />
::Table C.7<br />
<br />
::Table C.8<br />
<br />
::Table C.9<br />
<br />
===B.6. 双字节===<br />
<br />
:本脚本指定按照[STRINGPREP]第六章检查双字节.<br />
<br />
==附录 C. XML 规划==<br />
<br />
:以下 XML schemas 是描述性的, 不是标准的. 'jabber:client' 和 'jabber:server' 名字空间的标准定义, 参照 [[RFC3921]].<br />
<br />
===C.1. Streams namespace===<br />
<br />
<source lang="xml"><br />
<?xml version='1.0' encoding='UTF-8'?><br />
<br />
<xs:schema<br />
xmlns:xs='http://www.w3.org/2001/XMLSchema'<br />
targetNamespace='http://etherx.jabber.org/streams'<br />
xmlns='http://etherx.jabber.org/streams'<br />
elementFormDefault='unqualified'><br />
<br />
<xs:element name='stream'><br />
<xs:complexType><br />
<xs:sequence xmlns:client='jabber:client'<br />
xmlns:server='jabber:server'<br />
xmlns:db='jabber:server:dialback'><br />
<xs:element ref='features' minOccurs='0' maxOccurs='1'/><br />
<xs:any namespace='urn:ietf:params:xml:ns:xmpp-tls'<br />
minOccurs='0'<br />
maxOccurs='unbounded'/><br />
<xs:any namespace='urn:ietf:params:xml:ns:xmpp-sasl'<br />
minOccurs='0'<br />
maxOccurs='unbounded'/><br />
<xs:choice minOccurs='0' maxOccurs='1'><br />
<xs:choice minOccurs='0' maxOccurs='unbounded'><br />
<xs:element ref='client:message'/><br />
<xs:element ref='client:presence'/><br />
<xs:element ref='client:iq'/><br />
</xs:choice><br />
<xs:choice minOccurs='0' maxOccurs='unbounded'><br />
<xs:element ref='server:message'/><br />
<xs:element ref='server:presence'/><br />
<xs:element ref='server:iq'/><br />
<xs:element ref='db:result'/><br />
<xs:element ref='db:verify'/><br />
</xs:choice><br />
</xs:choice><br />
<xs:element ref='error' minOccurs='0' maxOccurs='1'/><br />
</xs:sequence><br />
<xs:attribute name='from' type='xs:string' use='optional'/><br />
<xs:attribute name='id' type='xs:NMTOKEN' use='optional'/><br />
<xs:attribute name='to' type='xs:string' use='optional'/><br />
<xs:attribute name='version' type='xs:decimal' use='optional'/><br />
<xs:attribute ref='xml:lang' use='optional'/><br />
</xs:complexType><br />
</xs:element><br />
<br />
<xs:element name='features'><br />
<xs:complexType><br />
<xs:all xmlns:tls='urn:ietf:params:xml:ns:xmpp-tls'<br />
xmlns:sasl='urn:ietf:params:xml:ns:xmpp-sasl'<br />
xmlns:bind='urn:ietf:params:xml:ns:xmpp-bind'<br />
xmlns:sess='urn:ietf:params:xml:ns:xmpp-session'><br />
<xs:element ref='tls:starttls' minOccurs='0'/><br />
<xs:element ref='sasl:mechanisms' minOccurs='0'/><br />
<xs:element ref='bind:bind' minOccurs='0'/><br />
<xs:elemnt ref='sess:session' minOccurs='0'/><br />
</xs:all><br />
</xs:complexType><br />
</xs:element><br />
<br />
<xs:element name='error'><br />
<xs:complexType><br />
<xs:sequence xmlns:err='urn:ietf:params:xml:ns:xmpp-streams'><br />
<xs:group ref='err:streamErrorGroup'/><br />
<xs:element ref='err:text'<br />
minOccurs='0'<br />
maxOccurs='1'/><br />
</xs:sequence><br />
</xs:complexType><br />
</xs:element><br />
<br />
</xs:schema><br />
</source><br />
<br />
===C.2. Stream error namespace===<br />
<br />
<source lang="xml"><br />
<?xml version='1.0' encoding='UTF-8'?><br />
<br />
<xs:schema<br />
xmlns:xs='http://www.w3.org/2001/XMLSchema'<br />
targetNamespace='urn:ietf:params:xml:ns:xmpp-streams'<br />
xmlns='urn:ietf:params:xml:ns:xmpp-streams'<br />
elementFormDefault='qualified'><br />
<br />
<xs:element name='bad-format' type='empty'/><br />
<xs:element name='bad-namespace-prefix' type='empty'/><br />
<xs:element name='conflict' type='empty'/><br />
<xs:element name='connection-timeout' type='empty'/><br />
<xs:element name='host-gone' type='empty'/><br />
<xs:element name='host-unknown' type='empty'/><br />
<xs:element name='improper-addressing' type='empty'/><br />
<xs:element name='internal-server-error' type='empty'/><br />
<xs:element name='invalid-from' type='empty'/><br />
<xs:element name='invalid-id' type='empty'/><br />
<xs:element name='invalid-namespace' type='empty'/><br />
<xs:element name='invalid-xml' type='empty'/><br />
<xs:element name='not-authorized' type='empty'/><br />
<xs:element name='policy-violation' type='empty'/><br />
<xs:element name='remote-connection-failed' type='empty'/><br />
<xs:element name='resource-constraint' type='empty'/><br />
<xs:element name='restricted-xml' type='empty'/><br />
<xs:element name='see-other-host' type='xs:string'/><br />
<xs:element name='system-shutdown' type='empty'/><br />
<xs:element name='undefined-condition' type='empty'/><br />
<xs:element name='unsupported-encoding' type='empty'/><br />
<xs:element name='unsupported-stanza-type' type='empty'/><br />
<xs:element name='unsupported-version' type='empty'/><br />
<xs:element name='xml-not-well-formed' type='empty'/><br />
<br />
<xs:group name='streamErrorGroup'><br />
<xs:choice><br />
<xs:element ref='bad-format'/><br />
<xs:element ref='bad-namespace-prefix'/><br />
<xs:element ref='conflict'/><br />
<xs:element ref='connection-timeout'/><br />
<xs:element ref='host-gone'/><br />
<xs:element ref='host-unknown'/><br />
<xs:element ref='improper-addressing'/><br />
<xs:element ref='internal-server-error'/><br />
<xs:element ref='invalid-from'/><br />
<xs:element ref='invalid-id'/><br />
<xs:element ref='invalid-namespace'/><br />
<xs:element ref='invalid-xml'/><br />
<xs:element ref='not-authorized'/><br />
<xs:element ref='policy-violation'/><br />
<xs:element ref='remote-connection-failed'/><br />
<xs:element ref='resource-constraint'/><br />
<xs:element ref='restricted-xml'/><br />
<xs:element ref='see-other-host'/><br />
<xs:element ref='system-shutdown'/><br />
<xs:element ref='undefined-condition'/><br />
<xs:element ref='unsupported-encoding'/><br />
<xs:element ref='unsupported-stanza-type'/><br />
<xs:element ref='unsupported-version'/><br />
<xs:element ref='xml-not-well-formed'/><br />
</xs:choice><br />
</xs:group><br />
<br />
<xs:element name='text'><br />
<xs:complexType><br />
<xs:simpleContent><br />
<xs:extension base='xs:string'><br />
<xs:attribute ref='xml:lang' use='optional'/><br />
</xs:extension><br />
</xs:simpleContent><br />
</xs:complexType><br />
</xs:element><br />
<br />
<xs:simpleType name='empty'><br />
<xs:restriction base='xs:string'><br />
<xs:enumeration value=''/><br />
</xs:restriction><br />
</xs:simpleType><br />
<br />
</xs:schema><br />
</source><br />
<br />
===C.3. TLS namespace==<br />
<br />
<source lang="xml"><br />
<?xml version='1.0' encoding='UTF-8'?><br />
<br />
<xs:schema<br />
xmlns:xs='http://www.w3.org/2001/XMLSchema'<br />
targetNamespace='urn:ietf:params:xml:ns:xmpp-tls'<br />
xmlns='urn:ietf:params:xml:ns:xmpp-tls'<br />
elementFormDefault='qualified'><br />
<br />
<xs:element name='starttls'><br />
<xs:complexType><br />
<xs:sequence><br />
<xs:element<br />
name='required'<br />
minOccurs='0'<br />
maxOccurs='1'<br />
type='empty'/><br />
</xs:sequence><br />
</xs:complexType><br />
</xs:element><br />
<br />
<xs:element name='proceed' type='empty'/><br />
<xs:element name='failure' type='empty'/><br />
<br />
<xs:simpleType name='empty'><br />
<xs:restriction base='xs:string'><br />
<xs:enumeration value=''/><br />
</xs:restriction><br />
</xs:simpleType><br />
<br />
</xs:schema><br />
</source><br />
<br />
===C.4. SASL namespace===<br />
<br />
<source lang="xml"><br />
<?xml version='1.0' encoding='UTF-8'?><br />
<br />
<xs:schema<br />
xmlns:xs='http://www.w3.org/2001/XMLSchema'<br />
targetNamespace='urn:ietf:params:xml:ns:xmpp-sasl'<br />
xmlns='urn:ietf:params:xml:ns:xmpp-sasl'<br />
elementFormDefault='qualified'><br />
<br />
<xs:element name='mechanisms'><br />
<xs:complexType><br />
<xs:sequence><br />
<xs:element name='mechanism'<br />
maxOccurs='unbounded'<br />
type='xs:string'/><br />
</xs:sequence><br />
</xs:complexType><br />
</xs:element><br />
<br />
<xs:element name='auth'><br />
<xs:complexType><br />
<xs:simpleContent><br />
<xs:extension base='empty'><br />
<xs:attribute name='mechanism'<br />
type='xs:string'<br />
use='optional'/><br />
</xs:extension><br />
</xs:simpleContent><br />
</xs:complexType><br />
</xs:element><br />
<br />
<xs:element name='challenge' type='xs:string'/><br />
<xs:element name='response' type='xs:string'/><br />
<xs:element name='abort' type='empty'/><br />
<xs:element name='success' type='empty'/><br />
<br />
<xs:element name='failure'><br />
<xs:complexType><br />
<xs:choice minOccurs='0'><br />
<xs:element name='aborted' type='empty'/><br />
<xs:element name='incorrect-encoding' type='empty'/><br />
<xs:element name='invalid-authzid' type='empty'/><br />
<xs:element name='invalid-mechanism' type='empty'/><br />
<xs:element name='mechanism-too-weak' type='empty'/><br />
<xs:element name='not-authorized' type='empty'/><br />
<xs:element name='temporary-auth-failure' type='empty'/><br />
</xs:choice><br />
</xs:complexType><br />
</xs:element><br />
<xs:simpleType name='empty'><br />
<xs:restriction base='xs:string'><br />
<xs:enumeration value=''/><br />
</xs:restriction><br />
</xs:simpleType><br />
<br />
</xs:schema><br />
</source><br />
<br />
===C.5. Resource binding namespace===<br />
<br />
<source lang="xml"><br />
<?xml version='1.0' encoding='UTF-8'?><br />
<br />
<xs:schema<br />
xmlns:xs='http://www.w3.org/2001/XMLSchema'<br />
targetNamespace='urn:ietf:params:xml:ns:xmpp-bind'<br />
xmlns='urn:ietf:params:xml:ns:xmpp-bind'<br />
elementFormDefault='qualified'><br />
<br />
<xs:element name='bind'><br />
<xs:complexType><br />
<xs:choice minOccurs='0' maxOccurs='1'><br />
<xs:element name='resource' type='xs:string'/><br />
<xs:element name='jid' type='xs:string'/><br />
</xs:choice><br />
</xs:complexType><br />
</xs:element><br />
<br />
</xs:schema><br />
</source><br />
<br />
===C.6. Dialback namespace===<br />
<br />
<source lang="xml"><br />
<?xml version='1.0' encoding='UTF-8'?><br />
<br />
<xs:schema<br />
xmlns:xs='http://www.w3.org/2001/XMLSchema'<br />
targetNamespace='jabber:server:dialback'<br />
xmlns='jabber:server:dialback'<br />
elementFormDefault='qualified'><br />
<br />
<xs:element name='result'><br />
<xs:complexType><br />
<xs:simpleContent><br />
<xs:extension base='xs:token'><br />
<xs:attribute name='from' type='xs:string' use='required'/><br />
<xs:attribute name='to' type='xs:string' use='required'/><br />
<xs:attribute name='type' use='optional'><br />
<xs:simpleType><br />
<xs:restriction base='xs:NCName'><br />
<xs:enumeration value='invalid'/><br />
<xs:enumeration value='valid'/><br />
</xs:restriction><br />
</xs:simpleType><br />
</xs:attribute><br />
</xs:extension><br />
</xs:simpleContent><br />
</xs:complexType><br />
</xs:element><br />
<br />
<xs:element name='verify'><br />
<xs:complexType><br />
<xs:simpleContent><br />
<xs:extension base='xs:token'><br />
<xs:attribute name='from' type='xs:string' use='required'/><br />
<xs:attribute name='id' type='xs:NMTOKEN' use='required'/><br />
<xs:attribute name='to' type='xs:string' use='required'/><br />
<xs:attribute name='type' use='optional'><br />
<xs:simpleType><br />
<xs:restriction base='xs:NCName'><br />
<xs:enumeration value='invalid'/><br />
<xs:enumeration value='valid'/><br />
</xs:restriction><br />
</xs:simpleType><br />
</xs:attribute><br />
</xs:extension><br />
</xs:simpleContent><br />
</xs:complexType><br />
</xs:element><br />
<br />
</xs:schema><br />
</source><br />
<br />
===C.7. Stanza error namespace===<br />
<br />
<source lang="xml"><br />
<?xml version='1.0' encoding='UTF-8'?><br />
<br />
<xs:schema<br />
xmlns:xs='http://www.w3.org/2001/XMLSchema'<br />
targetNamespace='urn:ietf:params:xml:ns:xmpp-stanzas'<br />
xmlns='urn:ietf:params:xml:ns:xmpp-stanzas'<br />
elementFormDefault='qualified'><br />
<br />
<xs:element name='bad-request' type='empty'/><br />
<xs:element name='conflict' type='empty'/><br />
<xs:element name='feature-not-implemented' type='empty'/><br />
<xs:element name='forbidden' type='empty'/><br />
<xs:element name='gone' type='xs:string'/><br />
<xs:element name='internal-server-error' type='empty'/><br />
<xs:element name='item-not-found' type='empty'/><br />
<xs:element name='jid-malformed' type='empty'/><br />
<xs:element name='not-acceptable' type='empty'/><br />
<xs:element name='not-allowed' type='empty'/><br />
<xs:element name='payment-required' type='empty'/><br />
<xs:element name='recipient-unavailable' type='empty'/><br />
<xs:element name='redirect' type='xs:string'/><br />
<xs:element name='registration-required' type='empty'/><br />
<xs:element name='remote-server-not-found' type='empty'/><br />
<xs:element name='remote-server-timeout' type='empty'/><br />
<xs:element name='resource-constraint' type='empty'/><br />
<xs:element name='service-unavailable' type='empty'/><br />
<xs:element name='subscription-required' type='empty'/><br />
<xs:element name='undefined-condition' type='empty'/><br />
<xs:element name='unexpected-request' type='empty'/><br />
<br />
<xs:group name='stanzaErrorGroup'><br />
<xs:choice><br />
<xs:element ref='bad-request'/><br />
<xs:element ref='conflict'/><br />
<xs:element ref='feature-not-implemented'/><br />
<xs:element ref='forbidden'/><br />
<xs:element ref='gone'/><br />
<xs:element ref='internal-server-error'/><br />
<xs:element ref='item-not-found'/><br />
<xs:element ref='jid-malformed'/><br />
<xs:element ref='not-acceptable'/><br />
<xs:element ref='not-allowed'/><br />
<xs:element ref='payment-required'/><br />
<xs:element ref='recipient-unavailable'/><br />
<xs:element ref='redirect'/><br />
<xs:element ref='registration-required'/><br />
<xs:element ref='remote-server-not-found'/><br />
<xs:element ref='remote-server-timeout'/><br />
<xs:element ref='resource-constraint'/><br />
<xs:element ref='service-unavailable'/><br />
<xs:element ref='subscription-required'/><br />
<xs:element ref='undefined-condition'/><br />
<xs:element ref='unexpected-request'/><br />
</xs:choice><br />
</xs:group><br />
<br />
<xs:element name='text'><br />
<xs:complexType><br />
<xs:simpleContent><br />
<xs:extension base='xs:string'><br />
<xs:attribute ref='xml:lang' use='optional'/><br />
</xs:extension><br />
</xs:simpleContent><br />
</xs:complexType><br />
</xs:element><br />
<br />
<xs:simpleType name='empty'><br />
<xs:restriction base='xs:string'><br />
<xs:enumeration value=''/><br />
</xs:restriction><br />
</xs:simpleType><br />
<br />
</xs:schema><br />
</source><br />
<br />
==附录 D. 核心Jabber协议和XMPP的不同==<br />
<br />
:本章是非标准的.<br />
<br />
::译者注:附录D对于新接触XMPP的人没有什么意义,就不翻译了,免得浪费时间。因为现在RFC公布已经很久了,以前的Jabber实现很多都进化到XMPP了。<br />
<br />
:XMPP has been adapted from the protocols originally developed in the Jabber open-source community, which can be thought of as "XMPP 0.9". Because there exists a large installed base of Jabber implementations and deployments, it may be helpful to specify the key differences between the relevant Jabber protocols and XMPP in order to expedite and encourage upgrades of those implementations and deployments to XMPP. This section summarizes the core differences, while the corresponding section of [[RFC3921]] summarizes the differences that relate specifically to instant messaging and presence applications.<br />
<br />
===D.1. Channel Encryption===<br />
<br />
:It was common practice in the Jabber community to use SSL for channel encryption on ports other than 5222 and 5269 (the convention is to use ports 5223 and 5270). XMPP uses TLS over the IANA-registered ports for channel encryption, as defined under Use of TLS (Section 5) herein.<br />
<br />
===D.2. Authentication===<br />
<br />
:The client-server authentication protocol developed in the Jabber community used a basic IQ interaction qualified by the 'jabber:iq:auth' namespace (documentation of this protocol is contained in \[JEP-0078\], published by the Jabber Software Foundation [JSF]). XMPP uses SASL for authentication, as defined under Use of SASL (Section 6) herein.<br />
<br />
:The Jabber community did not develop an authentication protocol for server-to-server communications, only the Server Dialback (Section 8) protocol to prevent server poofing. XMPP supersedes Server Dialback with a true server-to-server authentication protocol, as defined under Use of SASL (Section 6) herein.<br />
<br />
===D.3. Resource Binding===<br />
<br />
:Resource binding in the Jabber community was handled via the 'jabber:iq:auth' namespace (which was also used for client authentication with a server). XMPP defines a dedicated namespace for resource binding as well as the ability for a server to generate a resource identifier on behalf of a client, as defined under Resource Binding (Section 7).<br />
<br />
===D.4. JID Processing===<br />
<br />
:JID processing was somewhat loosely defined by the Jabber community (documentation of forbidden characters and case handling is contained in [JEP-0029], published by the Jabber Software Foundation [JSF]). XMPP specifies the use of \[NAMEPREP\] for domain identifiers and supplements Nameprep with two additional [STRINGPREP] profiles for JID processing: Nodeprep (Appendix A) for node identifiers and Resourceprep (Appendix B) for resource identifiers.<br />
<br />
===D.5. Error Handling===<br />
<br />
:Stream-related errors were handled in the Jabber community via XML character data text in a <stream:error/> element. In XMPP, stream-related errors are handled via an extensible mechanism defined under Stream Errors (Section 4.7) herein. Stanza-related errors were handled in the Jabber community via HTTP-style error codes. In XMPP, stanza-related errors are handled via an extensible mechanism defined under Stanza Errors (Section 9.3) herein. (Documentation of a mapping between Jabber and XMPP error handling mechanisms is contained in \[JEP-0086\], published by the Jabber Software Foundation [JSF].)<br />
<br />
===D.6. Internationalization===<br />
<br />
:Although use of UTF-8 has always been standard practice within the Jabber community, the community did not define mechanisms for specifying the language of human-readable text provided in XML character data. XMPP specifies the use of the 'xml:lang' attribute in such contexts, as defined under Stream Attributes (Section 4.4) and xml:lang (Section 9.1.5) herein.<br />
<br />
===D.7. Stream Version Attribute===<br />
<br />
:The Jabber community did not include a 'version' attribute in stream headers. XMPP specifies inclusion of that attribute as a way to signal support for the stream features (authentication, encryption, etc.) defined under Version Support (Section 4.4.1) herein.<br />
<br />
==贡献者==<br />
<br />
:XMPP的大部分核心方面是由1999年开始的Jabber开源社区开发的. 这个社区是由 Jeremie Miller建立的, 他于1999年1月发布了最初版的jabber server源代码. 主要的基础协议的早期贡献者还包括 Ryan Eatmon, Peter Millard, Thomas Muldowney,和 Dave Smith. XMPP工作组的工作主要集中在安全性和国际化方面; 在这些领域, 使用 TLS 和 SASL 的协议最初是由 Rob Norris贡献的, stringprep profiles 最初是由 Joe Hildebrand贡献的. The error code syntax 是由Lisa Dusseault建议的.<br />
<br />
==致谢==<br />
<br />
:感谢许多在贡献者名单之外的人们. 尽管很难提供一个完整的名单, 以下个人对于定义协议或评论标准提供了很多帮助:<br />
<br />
:Thomas Charron, Richard Dobson, Sam Hartman, Schuyler Heath, Jonathan Hogg, Cullen Jennings, Craig Kaes, Jacek Konieczny, Alexey Melnikov, Keith Minkler, Julian Missig, Pete Resnick, Marshall Rose, Alexey Shchepin, Jean-Louis Seguineau, Iain Shigeoka, Greg Troxel, and David Waite. <br />
<br />
:也感谢 XMPP工作组的成员和 IETF 社区在本文的成文过程中一直提供的评论和反馈。<br />
<br />
<br />
==作者地址==<br />
<br />
:Peter Saint-Andre (editor)<br />
<br />
:Jabber Software Foundation<br />
<br />
:EMail: stpeter@jabber.org<br />
<br />
==完整的版权声明==<br />
<br />
:Copyright (C) The Internet Society (2004).<br />
<br />
:This document is subject to the rights, licenses and restrictions contained in BCP 78, and except as set forth therein, the authors retain all their rights. This document and the information contained herein are provided on an "AS IS" basis and THE CONTRIBUTOR, THE ORGANIZATION HE/S HE REPRESENTS OR IS SPONSORED BY (IF ANY), THE INTERNET SOCIETY AND THE INTERNET ENGINEERING TASK FORCE DISCLAIM ALL WARRANTIES, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO ANY WARRANTY THAT THE USE OF THE INFORMATION HEREIN WILL NOT INFRINGE ANY RIGHTS OR ANY IMPLIED WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE.<br />
<br />
==Intellectual Property==<br />
<br />
:The IETF takes no position regarding the validity or scope of any Intellectual Property Rights or other rights that might be claimed to pertain to the implementation or use of the technology described in this document or the extent to which any license under such rights might or might not be available; nor does it represent that it has made any independent effort to identify any such rights. Information on the IETF's procedures with respect to rights in IETF Documents can be found in BCP 78 and BCP 79. Copies of IPR disclosures made to the IETF Secretariat and any assurances of licenses to be made available, or the result of an attempt made to obtain a general license or permission for the use of such proprietary rights by implementers or users of this specification can be obtained from the IETF on-line IPR repository at http://www.ietf.org/ipr. The IETF invites any interested party to bring to its attention any copyrights, patents or patent applications, or other proprietary rights that may cover technology that may be required to implement this standard. Please address the information to the IETF at ietf-ipr@ietf.org.<br />
<br />
==感谢==<br />
<br />
:目前为RFC编辑活动提供资金的Internet Society.</div>
Snowqiang
http://wiki.jabbercn.org/XEP-0045
XEP-0045
2009-07-02T09:04:31Z
<p>Snowqiang: </p>
<hr />
<div>[[Category:XMPP扩展]]<br />
[[Category:翻译中]]<br />
<br />
'''本文的英文原文来自[http://www.xmpp.org/extensions/xep-0045.html XEP-0045]'''<br />
<br />
'''XEP-0045: 多用户聊天'''<br />
<br />
本文定义了一个XMPP协议扩展用于多用户文本会议.即多个XMPP可以在一个房间或频道互相交流信息, 类似的互联网中继聊天系统(IRC).此外,标准聊天室功能如聊天室的主题和邀请,本协议定义了一个强有力的房间控制模型,包括能够踢和禁止用户,任命室主和管理员,要求会员或密码才能加入房间,等等。<br />
<br />
注意: 这里定义的协议是XMPP标准化基金会的一个草案标准.对本协议的执行是被鼓励的,也适于部署到生产系统,但是在它成为最终标准之前可能还会有一些变动.<br />
<br />
'''文档信息'''<br />
<br />
系列: [[XMPP扩展]]<br />
<br />
编号: 0045<br />
<br />
发行者: [XMPP文档列表/XMPP标准基金会]<br />
<br />
状态: 草案<br />
<br />
类型: 标准跟踪<br />
<br />
版本: 1.24<br />
<br />
最后更新日期: 2008-07-16<br />
<br />
批准机构: [XMPP文档列表/XMPP理事会]<br />
<br />
依赖于: [[XMPP Core]], [[XMPP IM]], XEP-0004, XEP-0030, XEP-0068, XEP-0082, XEP-0128<br />
<br />
上文: 无<br />
<br />
下文: 无<br />
<br />
简称: muc<br />
<br />
muc名字空间的XML方案: <http://www.xmpp.org/schemas/muc.xsd><br />
<br />
muc#admin名字空间的XML方案: <http://www.xmpp.org/schemas/muc-admin.xsd><br />
<br />
muc#owner名字空间的XML方案: <http://www.xmpp.org/schemas/muc-owner.xsd><br />
<br />
muc#unique名字空间的XML方案: <http://www.xmpp.org/schemas/muc-unique.xsd><br />
<br />
muc#user名字空间的XML方案: <http://www.xmpp.org/schemas/muc-user.xsd><br />
<br />
注册项: <http://www.xmpp.org/registrar/muc.html><br />
<br />
Wiki页: <http://wiki.jabber.org/index.php/Multi-User Chat (XEP-0045)><br />
<br />
'''作者信息'''<br />
<br />
:'''Peter Saint-Andre'''<br />
<br />
:Email: [mailto:stpeter@jabber.org stpeter@jabber.org]<br />
<br />
:JabberID: [xmpp:stpeter@jabber.org stpeter@jabber.org]<br />
<br />
'''法律通告'''<br />
<br />
'''版权'''<br />
<br />
XMPP扩展协议的版权(1999-2008)归XMPP标准化基金会(XSF)所有.<br />
<br />
'''权限'''<br />
<br />
特此授权,费用全免,对任何获得本协议副本的人,对使用本协议没有限制,包括不限制在软件程序中实现本协议,不限制在网络服务中布署本协议,不限制拷贝,修改,合并,发行,翻译,分发,转授,或销售本协议的副本,被允许使用本协议做了以上工作的人士,应接受前述的版权声明和本许可通知并且必须包含在所有的副本或实质性部分的规格中.除非单独的许可,被重新分发的修改工作,不得含有关于作者,标题,编号,或出版者的规格的误导性资料,并不得宣称修改工作是由本文的作者,作者所属的任何组织或项目,或XMPP标准基金会签注。<br />
<br />
'''免责声明''''<br />
<br />
注意:本协议是提供的“原样”的基础,没有担保或任何形式的条件,明示或暗示,包括,但不限于任何担保或关于名称,非侵权性,适销性或适合作某一特定目的的条件.在任何情况XMPP标准基金会或作者不对此协议承担任何责任索赔,损害赔偿,或其他责任,无论是在一项行动的合同,侵权,或否则,所产生的,运出,或在他涉嫌与规格或执行,部署或以其它方式使用本协议. ##<br />
<br />
'''责任限制'''<br />
<br />
在任何情况下以及没有任何法律规定时,不论是侵权行为(包括疏忽),合同或其它方面,除非根据适用法律的要求(如蓄意和有严重疏忽行为)或同意以书面形式,XMPP标准基金会或任何作者不对本协议承担所造成的损失,包括任何直接,间接,特殊,偶发,或相应的损害赔偿的任何字符利用所产生的或不能使用的规格(包括但不限于善意的损失,停止作业,电脑失灵或故障,或任何和所有其他商业损害或损失) ,即使XMPP标准基金会或作者已被告知此类损害的可能性。<br />
<br />
'''知识产权的一致性'''<br />
<br />
XMPP扩展协议完全遵守XSF的知识产权策略(可在<http://www.xmpp.org/extensions/ipr-policy.shtml>找到副本或写信给XSF, P.O. Box 1641, Denver, CO 80201 USA). <br />
<br />
'''讨论地点'''<br />
<br />
首选的讨论的地方是标准讨论邮件列表: <http://mail.jabber.org/mailman/listinfo/standards>.<br />
<br />
勘误表发送到[mailto:editor@xmpp.org editor@xmpp.org]<br />
<br />
'''XMPP 相关信息'''<br />
<br />
XMPP 是由XSF(XMPP标准化基金会)按互联网标准程序贡献的,和 IETF的RFC 2026兼容的规范,包括 XMPP核心(RFC 3920)和 XMPP IM(RFC 3921).在本文中定义的任何协议,都是在互联网标准程序之外开发的,是扩展XMPP,而不是改变、发展和修改 XMPP本身.<br />
<br />
'''一致性术语'''<br />
<br />
本文中以下关键词的含义如 RFC 2119 所述: "MUST", "SHALL", "REQUIRED"; "MUST NOT", "SHALL NOT"; "SHOULD", "RECOMMENDED"; "SHOULD NOT", "NOT RECOMMENDED"; "MAY", "OPTIONAL".<br />
<br />
==绪论==<br />
<br />
传统上, 即时消息被视为由一对一的聊天构成而不是多对多聊天(即所谓"群聊"或"文本会议"). 群聊功能常见于一些系统如 Internet Relay Chat (IRC) 和 流行的IM服务所提供的聊天室功能. Jabber社区早在1999年开发和实施了一个基本的群聊协议. 这个 "groupchat 1.0" 协议为聊天室提供了一个最小功能集但是范围很有限. 本协议(多用户聊天或简称MUC)建立在向后兼容旧的"groupchat 1.0"协议的基础上但是提供高级功能如邀请, 房间Moderation和管理, 以及专门的房间类型.<br />
<br />
==范围==<br />
<br />
本文着重于和配置,参与以及管理一个独立的基于文本的会议室相关的通用需求. 这里所指出的需求是应用于单个房间级别的并且是"通用的", 某种意义上它们是在Jabber社区广泛讨论的或在现有的Jabber之外的基于文本的会议环境(例如, 定义在 RFC 1459 \[1\]中的Internet Relay Chat 和它的继承者: RFC 2810 \[2\], RFC 2811 \[3\], RFC 2812 \[4\], RFC 2813 \[5\])中已经存在的.<br />
<br />
本文明确地不涉及以下需求:<br />
<br />
* 房间之间的关系(例如, 房间的层次)<br />
<br />
* 多用户聊天服务的管理(例如, 管理跨越整个服务级别的许可或注册一个全局可用的房间昵称)<br />
<br />
* 独立消息的Moderation<br />
<br />
* 房间或服务级别的安全和加密<br />
<br />
* 高级特性, 如附加文件给一个房间, 集成白板, 以及和语音服务的交互<br />
<br />
* MUC部署和外来的聊天系统(例如, 和IRC网关或现有的其他IM系统)之间的交互<br />
<br />
* 在MUC部署之间进行镜像或复制<br />
<br />
这一受限的范围并非蔑视这些都很有用的主题; 无论如何, 这意味着本文专注于讨论和介绍一个易于理解的协议能够被类似的Jabber客户端和组件开发者实现. 将来的协议当然可以涉及以上提到的这些主题.<br />
<br />
==需求==<br />
<br />
本文指明了由Jabber现有的多用户聊天服务提供的最小功能集. 为了向后兼容性的原因, 本文使用原来的"groupchat 1.0"协议作为基线功能, 包括以下这些:<br />
<br />
* 每个房间被标识为 <room@service> (例如, <jdev@conference.jabber.org>), 这里 "room" 是房间的名称而 "service" 是多用户聊天服务运行所在的主机名.<br />
<br />
* 在一个房间里每个驻留者被标识为 <room@service/nick>, 这里 "nick" 是这个驻留者的房间昵称,定义于加入房间的时候或后来在驻留者驻留房间期间修改.<br />
<br />
* 一个用户通过发送一个出席信息给 <room@service/nick> 来加入一个房间.<br />
<br />
* 在多用户聊天房间里发送的消息使用特殊的类型"groupchat"并且被定向于房间本身 (room@service), 然后反射给所有参与者.<br />
<br />
* 一个驻留者可以改变他或她的房间昵称以及在房间中的可用性状态, 通过发送出席信息给 <room@service/newnick>.<br />
<br />
* 一个驻留者通过发送一个类型为"unavailable"的出席信息给当前的<room@service/nick>来退出房间.<br />
<br />
本文追加的特性和功能包括以下这些:<br />
<br />
# 本地会话日志(不需要房间内的机器人)<br />
# 用户可以申请成为一个房间的成员<br />
# 在一个非匿名房间里, 驻留者可以察看一个驻留者的全JID<br />
# 在一个半匿名房间里, moderators可以察看一个驻留者的全JID<br />
# 只允许moderators修改房间主题<br />
# moderators可以从房间里踢出参与者和访问者<br />
# 在一个moderated房间里,moderators可以授权和禁止交谈(也就是说, 交谈的特权), 并且管理交谈列表<br />
# 管理员可以授权和取消moderator特权, 并且管理moderator列表<br />
# 管理员可以在房间禁止用户, 并且管理黑名单<br />
# 管理员可以授权和取消成员特权, 并且管理一个只有成员可以加入的房间的成员列表<br />
# 所有者可以限制驻留者的数量<br />
# 所有者可以指定其他的所有者<br />
# 所有者可以授权或取消管理特权, 并且管理管理员列表<br />
# 所有者可以销毁房间<br />
<br />
另外, 本文提供了协议元素用于支持以下房间类型:<br />
<br />
# 公共或隐藏<br />
# 持久或临时<br />
# 密码保护或不安全的<br />
# 仅限成员或开放<br />
# moderated或unmoderated<br />
# 非匿名或半匿名<br />
<br />
为了实现这些需求, 本扩展协议需要符合 'http://jabber.org/protocol/muc' 名字空间(以及 在主名字空间URI加上 #owner, #admin, 和 #user 片断).<br />
<br />
==术语==<br />
<br />
===通用术语===<br />
<br />
Affiliation(从属关系) -- 一个长期存在的和房间之间的联系或连接; 可能的从属关系有 "owner"(所有者), "admin"(管理者), "member"(成员), 以及 "outcast"(被排斥者) (当然也可能没有从属关系); 从属关系从角色来看唯一的. 一个从属关系跨越了用户对一个房间的访问期间.<br />
<br />
Ban(禁止) -- 从一个房间移除一个用户以使这个用户不能够再进入这个房间 (直到这个禁令被废除为止). 一个被禁止的用户的从属关系为 "outcast"(被排斥者).<br />
<br />
Bare JID(纯JID) -- 一个用户的标识符 <user@host>, 不同于任何已有会话或资源的上下文, 与之相对的是全JID和房间JID.<br />
<br />
Full JID(全JID) -- 一个在线用户的标识符 <user@host/resource> , 不同于一个房间的上下文; 与之相对的是纯JID和房间JID.<br />
<br />
GC -- 最小的 "groupchat 1.0" 协议\[6\], Jabber社区于1999年开发; MUC 向后兼容GC.<br />
<br />
History(历史) -- 有限数量的消息节, 由当前讨论的上下文提供发送给一个新的驻留者.<br />
<br />
Invitation(邀请) -- 从一个用户发出的特殊消息给另一个用户, 邀请对方加入房间.<br />
<br />
IRC -- Internet Relay Chat.<br />
<br />
Kick(踢人) -- 临时从一个房间移除一个参与者或访问者; 这个用户任何时候都可以再次进入这个房间. 一个被踢的用户的角色是"none".<br />
<br />
Logging(记录) -- 存储发生在一个房间的讨论内容用于公开发布到房间上下文之外的地方.<br />
<br />
Member(成员) -- 一个用户在一个仅限会员的房间内处于"white list"(白名单)内或已经注册到一个公开的房间. 一个成员拥有一个"member"从属关系.<br />
<br />
Moderator(主持人) -- 一个房间角色,通常和房间的管理有关但是这个角色可以被赋予非管理员; 可以踢人, 可以允许和禁止发言, 等等. 一个 moderator 有一个 "moderator" 的角色.<br />
<br />
MUC -- 本文所定义的基于文本会议的多用户聊天协议.<br />
<br />
Occupant(驻留者) -- 一个房间里的任何Jabber用户 (这是一个 "抽象类" 并且不属于任何特定的角色).<br />
<br />
Outcast(被排斥者) -- 一个被某个房间禁止的用户. 一个被排斥者的从属关系是 "outcast".<br />
<br />
Participant(参与者) -- 一个没有管理权限的驻留者; 在一个 moderated 房间里, 一个参与者更多地被定义为有发言权的 (与之相反的是访问者). 一个参与者有一个 "participant" 的角色.<br />
<br />
Private Message(私有消息) -- 从一个驻留者直接发给另一个房间JID的消息(不是房间本身广播给所有驻留者的消息).<br />
<br />
Role(角色) -- 在一个房间里的一个临时的地位或者权限级别, 对于这个房间中用户的长期从属关系来说是唯一的; 可能的角色有 "moderator", "participant"(参与者), 和 "visitor"(访问者) (也可能没有定义好的角色). 一个角色仅仅存在于一个驻留者访问一个房间的期间.<br />
<br />
Room(房间) -- 一个虚拟的地方, Jabber用户象征性地加入它, 来和其他用户一起参与一个实时的基于文本的会议.<br />
<br />
Room Administrator(房间管理员) -- 一个由房间所有这授权的用户, 可以执行管理功能, 如禁止用户等等; 无论如何, 不允许改变定义的房间特性. 一个管理员有一个 "admin" 从属关系.<br />
<br />
Room ID(房间ID) -- 一个房间JID的节点标识符部分, 它可以是不透明的因而对人类用户没有什么含义(见 语法的商业规则Business Rules for syntax); 与之相对的是房间名.<br />
<br />
Room JID(房间JID) -- 在一个房间上下文中一个驻留者以 <room@service/nick> 来标识; 与之相对的是纯JID和全JID.<br />
<br />
Room Name(房间名) -- 一个用户友好的, 自然语言的房间名字, 由房间所有者配置并在服务发现查询中展示; 相对的是房间ID.<br />
<br />
Room Nickname(房间昵称) -- 房间JID的资源标识符部分(见语法的商业规则); 这是这个房间中一个驻留者展示自己的"友好的名字".<br />
<br />
Room Owner(房间所有者) -- 建立某个房间的Jabber用户或一个被房间创建者或所有者指派拥有所有者权限(如果允许的话)的Jabber用户; 它被允许改变定义好的房间特性, 也可以执行全部的管理功能. 一个所有者的从属关系为"owner".<br />
<br />
Room Roster(房间名册) -- 一个房间中的所有驻留者在一个Jabber客户端的展现.<br />
<br />
Server(服务器) -- 一个Jabber服务器可以选择是否关联一个基于文本的会议服务.<br />
<br />
Service(服务) -- 一个主机, 提供基于文本的会议的能力; 通常但不必须是一个Jabber服务器的子域(例如, conference.jabber.org).<br />
<br />
Subject(主题) -- 一个房间的一个临时讨论标题.<br />
<br />
Visit(访问) -- 一个房间的一个用户的"session"(会话), 当用户进入这个房间时开始(也就是说, 成为一个驻留者) , 结束于用户离开房间之时.<br />
<br />
Visitor(访问者) -- 在一个 moderated 房间, 一个没有发言权的驻留者(相反的是一个参与者). 一个访问的角色是"visitor".<br />
<br />
Voice(发言权) -- 在一个 moderated 房间, 发送消息给全部参与者的权限.<br />
<br />
===房间类型===<br />
<br />
Fully-Anonymous Room(全匿名房间) -- 一个房间的驻留者的全JID或纯JID不能被任何人查询到, 包括房间管理员和房间所有者; 这类房间是不推荐的(NOT RECOMMENDED)或不被MUC显式支持, 但是如果一个服务可能会提供适当的配置选项来使用这个协议; 相对的则是非匿名房间和半匿名房间.<br />
<br />
Hidden Room(隐藏房间) -- 一个无法被任何用户以普通方法如搜索和服务查询来发现的房间; 反义词: 公开房间.<br />
<br />
Members-Only Room(仅限会员的房间) -- 如果一个用户不在成员列表中则无法加入的一个房间; 反义词: 开放房间.<br />
<br />
Moderated Room(Moderated房间) -- 只有有"发言权"的用户才可以发送消息给所有驻留者的房间; 反义词: Unmoderated房间.<br />
<br />
Non-Anonymous Room(非匿名房间) -- 一个驻留者的全JID会暴露给所有其他驻留者的房间, 尽管驻留者可以选择任何期望的房间昵称; 相对的是半匿名房间和全匿名房间.<br />
<br />
Open Room(开放房间) -- 任何人可以加入而不需要在成员列表中的房间; 反义词: 仅限会员的房间.<br />
<br />
Password-Protected Room(密码保护房间) -- 一个用户必须提供正确密码才能加入的房间; 反义词: 非保密房间.<br />
<br />
Persistent Room(持久房间) -- 如果最后一个驻留者退出也不会被销毁的房间; 反义词: 临时房间.<br />
<br />
Public Room(公开房间) -- 用户可以通过普通方法如搜索和服务查询来发现的房间; 反义词: 隐藏房间.<br />
<br />
Semi-Anonymous Room(半匿名房间) -- 一个驻留者的全JID只能被房间管理员发现的房间; 相对的是全匿名房间和非匿名房间.<br />
<br />
Temporary Room(临时房间) -- 如果最后一个驻留者退出就会被销毁的房间; 反义词: 持久房间.<br />
<br />
Unmoderated Room(Unmoderated房间) -- 任何驻留者都被允许发送消息给所有驻留者的房间; 反义词: Moderated房间.<br />
<br />
Unsecured Room(非保密房间) -- 任何人不需要提供密码就可以进入的房间; 反义词: 密码保护房间.<br />
<br />
===4.3 人物===<br />
<br />
本文的大部分例子使用了 the scenario of the witches' meeting held in a dark cave at the beginning of Act IV, Scene I of Shakespeare's Macbeth, 在这里代表"darkcave@macbeth.shakespeare.lit"聊天室. 人物如下:<br />
<br />
'''表1: 剧中人'''<br />
<br />
{|border="1" cellspacing="0" <br />
!房间昵称 !!全 JID !!从属关系<br />
|-<br />
|firstwitch ||crone1@shakespeare.lit/desktop ||所有者<br />
|-<br />
|secondwitch ||wiccarocks@shakespeare.lit/laptop ||管理员<br />
|-<br />
|thirdwitch ||hag66@shakespeare.lit/pda ||无<br />
|}<br />
<br />
==角色和从属关系==<br />
<br />
有两个尺度我们可以用来衡量一个用户的连接或在一个房间的地位. 一个是用户和一个房间的长期的从属关系 -- 例如, 一个用户的状态是一个所有者或一个被驱逐者. 另一个是当一个用户驻留于一个聊天室的时候的角色 -- 例如, 一个驻留者的地位是一个主持人,有权利踢出访问者和参与者. 这两个尺度各自都是唯一的, 因为一个从属关系是跨越访问的, 而一个角色只存在于一次访问期间. 另外, 在角色和从属关系之间没有一对一的对应关系; 例如, 某个不从属于某房间的人可能成为一个(临时的)主持人, 以及一个成员可能在一个moderated房间中是一个参与者或访问者. 这些概念以下全面解释.<br />
<br />
===角色===<br />
<br />
一个驻留者可能有四种已定义的角色:<br />
<br />
# 主持人<br />
# 参与者<br />
# 来访者<br />
# 无 (没有角色)<br />
<br />
角色是临时的,它不需要在用户对房间的访问中持续,它可以(MAY)在一个驻留者访问房间期间改变. 一个实现可以(MAY)穿越访问地持久化角色并且应该(SHOULD)在 moderated 房间这样做 (因为在访问者和参与者之间,唯一性对一个 moderated 房间是很关键的).<br />
<br />
在角色和从属关系之间没有一对一的映射(例如, 一个成员可以是一个参与者或一个访问者).<br />
<br />
在房间会话中,一个主持人是最有权力的驻留者, 它能在某种程度走上管理房间的其他驻留者的角色. 一个参与者的权力小于一个主持人, 尽管他或她有权限发言. 在一个moderated房间会话中一个访问者是一个更受限制的角色, 因为访问者不允许发送消息给所有驻留者.<br />
<br />
角色的授权,废除, 和维护是基于驻留者的房间昵称或全JID,而不是纯JID. 和这些角色相关的权限,还有角色改变触发的动作, 定义如下.<br />
<br />
关于角色的信息必须(MUST)在房间生成或反射的所有出席信息中被发送,从而也被发送给驻留者们.<br />
<br />
====权限====<br />
<br />
大部分情况下, 角色存在于一个等级中. 例如, 一个参与者可以做任何访问者能做的事, 而一个主持人可以做任何参与者能做的事. 每个角色拥有下一级角色所没有的权限; 这些权限定义于下表作为缺省值(一个实现可以(MAY)提供配置选项来超越这些缺省值).<br />
<br />
'''表2: 和角色相关的权限'''<br />
<br />
{|border="1" cellspacing="0" <br />
!权限 !!无 !!访问者 !!参与者 !!主持人<br />
|-<br />
|在房间中出席 ||否 ||是 ||是 ||是<br />
|-<br />
|接收消息 ||否 ||是 ||是 ||是<br />
|-<br />
|改变可用性状态 ||否 ||是 ||是 ||是<br />
|-<br />
|改变房间昵称 ||否 ||是* ||是 ||是<br />
|-<br />
|发送私人消息 ||否 ||是* ||是 ||是<br />
|-<br />
|邀请其他用户 ||否 ||是* ||是* ||是<br />
|-<br />
|发送消息给所有人 ||否 ||否** ||是 ||是<br />
|-<br />
|修改标题 ||否 ||否* ||是* ||是<br />
|-<br />
|踢出参与者和访问者 ||否 ||否 ||否 ||是<br />
|-<br />
|授予发言权 ||否 ||否 ||否 ||是<br />
|-<br />
|收回发言权 ||否 ||否 ||否 ||是***<br />
|}<br />
<br />
* 缺省; 配置设定可以(MAY)修改这个权限.<br />
<br />
** 一个实现可以(MAY)在非主持的房间缺省地授予发言权给访问者.<br />
<br />
*** 一个主持人不能(MUST NOT)从一个管理员或所有者收回发言权.<br />
<br />
====变更角色====<br />
<br />
一个驻留者的角色变更方法是定义好的. 有时候驻留者自己的动作导致变更 (例如, 介入或退出房间), 反之有时候由主持人,管理员或所有者的动作导致变更. 如果一个驻留者的角色改变了, 一个 MUC 服务实现必须(MUST)变更这个驻留者的角色来反映这个变更并且传达这已变更给所有驻留者. 角色的变更和它们触发的动作定义于下表.<br />
<br />
'''表3: 角色状态表'''<br />
<br />
{|border="1" cellspacing="0" <br />
!> !!无 !!访问者 !!参与者 !!主持人<br />
|-<br />
|无 ||-- ||进入moderated房间 ||进入unmoderated房间 ||管理员或所有者进入房间<br />
|-<br />
|访问者 ||退出房间或被主持人踢出房间 ||-- ||主持人授予发言权 ||管理员或所有者授予主持人权限<br />
|-<br />
|参与者 ||退出房间或被主持人踢出房间 ||主持人收回发言权 |-- ||管理员或所有者授予主持人权限<br />
|-<br />
|主持人 ||退出房间 ||管理员或所有者改变角色成为访问者* ||管理员或所有者改变角色成为参与者或收回主持人权限* ||--<br />
|}<br />
<br />
* 一个主持人不能(MUST NOT)从一个级别属于等于或高于主持人的驻留者那里收回主持人权限.<br />
<br />
注意: 特定的角色一般暗含特定的权限. 例如, 一个管理员或所有者自动成为一个主持人, 所以如果一个驻留者被授予管理员地位那么这个驻留者事实上将被授予主持人权限; 类似的, 当一个驻留者成为一个 moderated 房间的成员, 这个驻留者自动拥有一个参与者的角色. 无论如何, 失去管理员地位并不足以意味这个驻留者不再是主持人 (因为只要是参与者就可能成为一个主持人). 因此, 当一个驻留者被授予特定的从属关系的时候所拥有的角色是固定的, 反之当一个驻留者失去一个特定的从属关系它的角色是不确定的并取决于(服务的)实现. 因为一个客户端无法预料是否在收回某个从属关系之后这个角色成为什么, 如果它不想同时移除管理员/所有者权限和主持人角色, 那么除从属关系变更之外它还必须特意请求角色变更.<br />
<br />
===从属关系===<br />
<br />
一个用户可以有五种已定义的和房间之间的从属关系:<br />
<br />
# 所有者<br />
# 管理员<br />
# 成员<br />
# 排斥者<br />
# 无 (缺从属关系)<br />
<br />
这些从属关系是长时间的跨越一个用户对这个房间的访问期间的并且不受房间里事件的影响. 而且, 在这些从属关系和一个驻留者在房间中的角色之间没有一对一的映射关系. 从属关系被授予, 收回, 和维护都是基于这个用户的纯 JID.<br />
<br />
如果一个没有已定义的从属关系的用户进入一个房间, 这个用户的从属关系被定义为"无"; 无论如何, 这个从属关系不能穿越(多次的)访问 (也就是说, 一个服务不会跨越访问维护一个 "无 列表").<br />
<br />
成员从属关系为房间所有者或管理员提供了一个方法来指定一个"白名单",其中的用户被允许加入一个仅供会员的房间. 当一个成员加入了一个仅供会员的房间, 他或她的从属关系不会改变, 无论他或她的角色是什么. 成员从属关系也为用户提供一个方法来高效地注册一个开放的房间并在某种方式意义上保持和那个房间的联系(例如可能在房间里预留那个用户的昵称).<br />
<br />
一个被排斥者就是一个被从房间踢出来并且不允许进入那个房间的用户.<br />
<br />
关于从属关系的信息必须(MUST)由房间生成或反射到所有的出席信息节之中发送给驻留者们.<br />
<br />
====权限====<br />
<br />
大部分情况下, 从属关系存在一个级别. 例如, 一个所有者可以做任何管理员能做的事情, 而一个管理员可以做任何成员能做的事情. 每个从属关系拥有其下一级从属关系所没有的权限; 这些权限定义在下表中.<br />
<br />
'''表4: Privileges Associated With Affiliations'''<br />
<br />
{|border="1" cellspacing="0" <br />
!权限 !!Outcast(被排斥者) !!None(无) !!Member(成员) !!Admin(管理员) !!Owner(所有者)<br />
|-<br />
|进入房间 ||否 ||是* ||是 ||是 ||是<br />
|-<br />
|注册一个开放的房间 ||否 ||是 ||N/A ||N/A ||N/A<br />
|-<br />
|加入一个仅供会员的房间 ||否 ||否 ||是* ||是 ||是<br />
|-<br />
|踢出成员并把用户剔除从属关系 ||否 ||否 ||否 ||是 ||是<br />
|-<br />
|编辑成员列表 ||否 ||否 ||否 ||是 ||是<br />
|-<br />
|编辑主持人列表 ||否 ||否 ||否 ||是** ||是**<br />
|-<br />
|编辑管理员列表 ||否 ||否 ||否 ||否 ||是<br />
|-<br />
|编辑所有者列表 ||否 ||否 ||否 ||否 ||是<br />
|-<br />
|变更房间定义 ||否 ||否 ||否 ||否 ||是<br />
|-<br />
|销毁房间 ||否 ||否 ||否 ||否 ||是<br />
|}<br />
<br />
* 作为缺省值, 一个无从属关系的用户进入一个 moderated 房间的身份是一个访问者, 而进入一个开放的房间的身份是一个参与者. 一个成员进入一个房间的身份是参与者. 一个管理员或所有者进入房间的身份是一个主持人.<br />
<br />
** 一个管理员或所有者不能(MUST NOT)撤销另一个管理员或所有者的权限.<br />
<br />
====变更从属关系====<br />
<br />
一个用户的从属关系变更方法已经定义得很完善. 有时用户自己的动作导致这些变更(例如, 注册为一个房间的新成员), 反之有时候一个管理员或所有者的动作导致了这些变更. 如果一个用户的从属关系改变了, 一个MUC服务实现必须(MUST)变更这个用户的从属关系来反射这一变更并通知所有驻留者. 从属关系变更和他们出发的动作定义在下表中.<br />
<br />
'''表 5: 从属关系状态表'''<br />
<br />
{|border="1" cellspacing="0" <br />
| ||Outcast ||None ||Member ||Admin ||Owner<br />
|-<br />
|Outcast ||-- ||管理员或所有者移除屏蔽 ||管理员或所有者增加用户到成员列表 ||所有者增加用户到管理员列表 ||所有者增加用户到所有者列表<br />
|-<br />
|None ||管理员或所有者使用屏蔽 ||-- ||管理员或所有者增加用户到成员列表, 或用户注册一个成员(如果允许) ||所有者增加用户到管理员列表 ||所有者增加用户到所有者列表<br />
|-<br />
|Member ||管理员或所有这使用屏蔽 ||管理员或所有者变更从属关系为"none" ||-- ||所有者增加用户到管理员列表 ||所有者增加用户到所有者列表<br />
|-<br />
|Admin ||所有者使用屏蔽 ||所有者变更从属关系为"none" ||所有者变更从属关系为"member" ||-- ||所有者增加用户到所有者列表<br />
|-<br />
|Owner ||所有者使用屏蔽 ||所有者变更从属关系为"none" ||所有者变更从属关系为"member" ||所有者变更从属关系为"admin" ||--<br />
|}<br />
<br />
==实体用例==<br />
<br />
一个MUC实现必须(MUST)支持服务探索\[7\].<br />
<br />
===MUC的探索组件支持===<br />
<br />
一个Jabber实体可能希望探索是否一个服务实现了多用户聊天协议; 为了达到这个目的, 它发送一个服务探索信息("disco#info")查询给这组件的JID:<br />
<br />
'''例子 1. 用户通过Disco查询聊天服务是否支持MUC'''<br />
<br />
<source lang="xml"><br />
<iq from='hag66@shakespeare.lit/pda'<br />
id='disco1'<br />
to='macbeth.shakespeare.lit'<br />
type='get'><br />
<query xmlns='http://jabber.org/protocol/disco#info'/><br />
</iq><br />
</source><br />
<br />
服务必须(MUST)返回它的的身份和它所支持的特性:<br />
<br />
'''例子 2. 服务返回Disco Info结果'''<br />
<br />
<source lang="xml"><br />
<iq from='macbeth.shakespeare.lit'<br />
id='disco1'<br />
to='hag66@shakespeare.lit/pda'<br />
type='result'><br />
<query xmlns='http://jabber.org/protocol/disco#info'><br />
<identity<br />
category='conference'<br />
name='Macbeth Chat Service'<br />
type='text'/><br />
<feature var='http://jabber.org/protocol/muc'/><br />
</query><br />
</iq><br />
</source><br />
<br />
注意: 因为MUC是旧的"groupchat 1.0"协议的超集, 一个MUC服务不应该(SHOULD NOT)返回一个<feature var='gc-1.0'/>条目在一个disco#info结果中.<br />
<br />
===探索房间===<br />
<br />
服务探索条目("disco#items")协议使得一个用户可以向一个服务查询相关的条目列表, 在一个聊天服务中这包含这个服务所承载的所有特定房间的集合.<br />
<br />
'''例子 3. 用户向聊天服务查询房间'''<br />
<br />
<source lang="xml"><br />
<iq from='hag66@shakespeare.lit/pda'<br />
id='disco2'<br />
to='macbeth.shakespeare.lit'<br />
type='get'><br />
<query xmlns='http://jabber.org/protocol/disco#items'/><br />
</iq><br />
</source><br />
<br />
服务应该(SHOULD)返回它承载的所有房间的列表.<br />
<br />
'''例子 4. 服务返回Disco Item结果'''<br />
<br />
<source lang="xml"><br />
<iq from='macbeth.shakespeare.lit'<br />
id='disco2'<br />
to='hag66@shakespeare.lit/pda'<br />
type='result'><br />
<query xmlns='http://jabber.org/protocol/disco#items'><br />
<item jid='heath@macbeth.shakespeare.lit'<br />
name='A Lonely Heath'/><br />
<item jid='darkcave@macbeth.shakespeare.lit'<br />
name='A Dark Cave'/><br />
<item jid='forres@macbeth.shakespeare.lit'<br />
name='The Palace'/><br />
<item jid='inverness@macbeth.shakespeare.lit'<br />
name='Macbeth&apos;s Castle'/><br />
</query><br />
</iq><br />
</source><br />
<br />
如果全部房间的列表太大(详见[XMPP文档列表/XMPP扩展/XEP-0030]), 服务可以(MAY)只返回部分的房间列表.<br />
<br />
===查询房间信息===<br />
<br />
使用 disco#info 协议, 一个用户也可以查询一个特定房间的详情. 为了在进入房间之间确定这个房间的隐私和安全配置用户应该(SHOULD)这样做(详见 Security Considerations).<br />
<br />
'''例子 5. 用户查询特定聊天室的信息'''<br />
<br />
<source lang="xml"><br />
<iq from='hag66@shakespeare.lit/pda'<br />
id='disco3'<br />
to='darkcave@macbeth.shakespeare.lit'<br />
type='get'><br />
<query xmlns='http://jabber.org/protocol/disco#info'/><br />
</iq><br />
</source><br />
<br />
房间必须(MUST)返回它的标识并且应该(SHOULD)返回它支持的特性:<br />
<br />
'''例子 6. 房间返回查询信息结果'''<br />
<br />
<source lang="xml"><br />
<iq from='darkcave@macbeth.shakespeare.lit'<br />
id='disco3'<br />
to='hag66@shakespeare.lit/pda'<br />
type='result'><br />
<query xmlns='http://jabber.org/protocol/disco#info'><br />
<identity<br />
category='conference'<br />
name='A Dark Cave'<br />
type='text'/><br />
<feature var='http://jabber.org/protocol/muc'/><br />
<feature var='muc_passwordprotected'/><br />
<feature var='muc_hidden'/><br />
<feature var='muc_temporary'/><br />
<feature var='muc_open'/><br />
<feature var='muc_unmoderated'/><br />
<feature var='muc_nonanonymous'/><br />
</query><br />
</iq><br />
</source><br />
<br />
注意: 因为 MUC 是旧的 "groupchat 1.0" 协议的超集, 一个 MUC 房间不应该(SHOULD NOT)在一个disco#info结果中返回<feature var='gc-1.0'/>条目. 房间应该(SHOULD)返回它支持的实质的有意义的特性, 例如密码保护和房间主持(这些特性被完整地列入了特性注册项, 由XMPP注册项维护; 也见于本文的XMPP Registrar 章节).<br />
<br />
一个聊天室可以(MAY)使用服务查询扩展\[8\]在它的disco#info应答中返回更详细的信息, 通过包含一个隐含的其值为"http://jabber.org/protocol/muc#roominfo"的FORM_TYPE属性来标识. 这些信息可能包括关于一个房间的更详细的描述, 当前的房间标题, 以及这个房间当前的驻留者数量:<br />
<br />
'''例子 7. 房间返回扩展的查询信息结果'''<br />
<br />
<source lang="xml"><br />
<iq from='darkcave@macbeth.shakespeare.lit'<br />
id='disco3a'<br />
to='hag66@shakespeare.lit/pda'<br />
type='result'><br />
<query xmlns='http://jabber.org/protocol/disco#info'><br />
<identity<br />
category='conference'<br />
name='A Dark Cave'<br />
type='text'/><br />
<feature var='http://jabber.org/protocol/muc'/><br />
<feature var='muc_passwordprotected'/><br />
<feature var='muc_hidden'/><br />
<feature var='muc_temporary'/><br />
<feature var='muc_open'/><br />
<feature var='muc_unmoderated'/><br />
<feature var='muc_nonanonymous'/><br />
<x xmlns='jabber:x:data' type='result'><br />
<field var='FORM_TYPE' type='hidden'><br />
<value>http://jabber.org/protocol/muc#roominfo</value><br />
</field><br />
<field var='muc#roominfo_description' label='Description'><br />
<value>The place for all good witches!</value><br />
</field><br />
<field var='muc#roominfo_changesubject' label='Whether Occupants May Change the Subject'><br />
<value>true</value><br />
</field><br />
<field var='muc#roominfo_contactjid' label='Contact Addresses'><br />
<value>crone1@shakespeare.lit</value><br />
</field><br />
<field var='muc#roominfo_subject' label='Subject'><br />
<value>Spells</value><br />
</field><br />
<field var='muc#roominfo_occupants' label='Number of occupants'><br />
<value>3</value><br />
</field><br />
<field var='muc#roominfo_lang' label='Language of discussion'><br />
<value>en</value><br />
</field><br />
<field var='muc#roominfo_logs' label='URL for discussion logs'><br />
<value>http://www.shakespeare.lit/chatlogs/darkcave/</value><br />
</field><br />
<field var='muc#roominfo_pubsub' label='Associated pubsub node'><br />
<value>xmpp:pubsub.shakespeare.lit?node=chatrooms/darkcave</value><br />
</field><br />
</x><br />
</query><br />
</iq><br />
</source><br />
<br />
某些扩展的房间信息可能是动态生成的(例如, 讨论日志的URL地址, 它可能取决于服务器端的配置) 反之另一些信息则可能基于房间的配置.<br />
<br />
注意: 前述用于'http://jabber.org/protocol/muc#roominfo'FORM_TYPE的扩展服务查询字段将来还可以扩充(通过本文的Field Standardization章节描述的机制).<br />
<br />
===查询房间条目===<br />
<br />
一个用户也可以(MAY)向一个特定的聊天室查询和它相关的条目:<br />
<br />
'''例子 8. 用户查询和一个特定聊天室相关的条目'''<br />
<br />
<source lang="xml"><br />
<iq from='hag66@shakespeare.lit/pda'<br />
id='disco4'<br />
to='darkcave@macbeth.shakespeare.lit'<br />
type='get'><br />
<query xmlns='http://jabber.org/protocol/disco#items'/><br />
</iq><br />
</source><br />
<br />
一个实现可以(MAY)返回现有驻留者的列表(如果那信息是公开可用的话), 或不返回列表(如果那信息是私有的).<br />
<br />
'''例子 9. 房间返回查询条目结果(条目是公开的)'''<br />
<br />
<source lang="xml"><br />
<iq from='darkcave@macbeth.shakespeare.lit'<br />
id='disco4'<br />
to='hag66@shakespeare.lit/pda'<br />
type='result'><br />
<query xmlns='http://jabber.org/protocol/disco#items'><br />
<item jid='darkcave@macbeth.shakespeare.lit/firstwitch'/><br />
<item jid='darkcave@macbeth.shakespeare.lit/secondwitch'/><br />
</query><br />
</iq><br />
</source><br />
<br />
注意: 这些 <item/> 元素由 disco#items 名字空间限定, 而不是 muc 名字空间; 这意味着他们不能拥有 'affiliation' 或 'role' 属性, 例如.<br />
<br />
'''例子 10. 房间返回空的查询条目结果(条目是私有的)'''<br />
<br />
<source lang="xml"><br />
<iq from='darkcave@macbeth.shakespeare.lit'<br />
id='disco4'<br />
to='hag66@shakespeare.lit/pda'<br />
type='result'><br />
<query xmlns='http://jabber.org/protocol/disco#items'/><br />
</iq><br />
</source><br />
<br />
===查询一个房间的驻留者===<br />
<br />
如果一个非驻留者试图发送一个查询请求给一个<room@service/nick>类型的地址, 一个 MUC 服务应该(SHOULD)返回这个请求给这个实体并指明一个<bad-request/>错误条件. 如果一个驻留者发送这样一个请求, 服务可以(MAY)把它传递给预订的接收者; 详见本文的 实施指南章节Implementation Guidelines.<br />
<br />
===查询客户端对MUC的支持===<br />
<br />
一个 Jabber 用户可能想发现这个用户的某个联系人是否支持多用户聊天协议. 这可以使用服务发现(协议)来完成.<br />
<br />
'''例子 11. 用户查询联系人对于 MUC 的支持'''<br />
<br />
<source lang="xml"><br />
<iq from='hag66@shakespeare.lit/pda'<br />
id='disco5'<br />
to='wiccarocks@shakespeare.lit/laptop'<br />
type='get'><br />
<query xmlns='http://jabber.org/protocol/disco#info'/><br />
</iq><br />
</source><br />
<br />
客户端应该(SHOULD)返回它的标识和它支持的特性:<br />
<br />
'''例子 12. 联系人返回发现信息结果'''<br />
<br />
<source lang="xml"><br />
<iq from='wiccarocks@shakespeare.lit/laptop'<br />
id='disco5'<br />
to='hag66@shakespeare.lit/pda'<br />
type='result'><br />
<query xmlns='http://jabber.org/protocol/disco#info'><br />
<identity<br />
category='client'<br />
type='pc'/><br />
...<br />
<feature var='http://jabber.org/protocol/muc'/><br />
...<br />
</query><br />
</iq><br />
</source><br />
<br />
一个用户也可能查询一个联系人在哪个房间. 这可以通过特定服务发现节点'http://jabber.org/protocol/muc#rooms'查询联系人的全JID(<user@host/resource>)来完成 :<br />
<br />
'''例子 13. 用户在当前房间查询联系人'''<br />
<br />
<source lang="xml"><br />
<iq from='hag66@shakespeare.lit/pda'<br />
id='rooms1'<br />
to='wiccarocks@shakespeare.lit/laptop'<br />
type='get'><br />
<query xmlns='http://jabber.org/protocol/disco#items'<br />
node='http://jabber.org/protocol/muc#rooms'/><br />
</iq><br />
</source><br />
<br />
'''例子 14. 联系人返回房间查询结果'''<br />
<br />
<source lang="xml"><br />
<iq from='wiccarocks@shakespeare.lit/laptop'<br />
id='rooms1'<br />
to='hag66@shakespeare.lit/pda'<br />
type='result'><br />
<query xmlns='http://jabber.org/protocol/disco#items'<br />
node='http://jabber.org/protocol/muc#rooms'/><br />
<item jid='darkcave@macbeth.shakespeare.lit'/><br />
<item jid='characters@conference.shakespeare.lit'/><br />
</query><br />
</iq><br />
</source><br />
<br />
可选择的, 联系人可以(MAY)把它的房间昵称作为'name'属性的值返回:<br />
<br />
<source lang="xml"><br />
...<br />
<item jid='darkcave@macbeth.shakespeare.lit'<br />
name='secondwitch'/><br />
...<br />
</source><br />
<br />
==驻留者用例==<br />
<br />
在一个多用户聊天环境中主要的行为者是驻留者, 它可以被认为存在于一个多用户聊天室"之内"并且参与那个房间的讨论 (在本协议中, 参与者和访问者"仅仅"被认为是驻留者, 因为他们不拥有管理员权限). 为了更加清晰起见, 本文中的协议元素中涉及到驻留者的用例分为以下三类:<br />
<br />
# 现存于 "groupchat 1.0" 协议的最小功能集<br />
# 对于 "groupchat 1.0" 协议向前兼容的应用, 如处理一些和新房间类型有关的错误<br />
# 用来处理"groupchat 1.0"协议未涉及的功能的额外的协议元素(房间邀请, 房间密码, 和房间角色及从属关系相关的扩展出席信息); 在'http://jabber.org/protocol/muc#user'名字空间<br />
<br />
注意: 这里所有客户端生成的例子是从服务的角度来展示的, 所以所有由服务收到的节都包含一个'from'属性来表达发送者的全JID(由一个通用的Jabber路由或会话管理者加入). 另外, 通常的表示请求已被完成的 IQ 结果节(如 RFC 3920 \[9\]中所要求的)未被展示.<br />
<br />
===进入一个房间===<br />
<br />
====群聊1.0协议====<br />
<br />
为了参加一个多用户聊天室的讨论, 一个Jabber用户必须(MUST)首先进入一个房间成为一个驻留者. 在旧的"groupchat 1.0"协议中, 这是通过发送出席信息<room@service/nick>来实现的, 这里"room"是房间的 ID, "service" 是聊天服务的主机名, "nick" 是这个用户在这房间里预期的昵称:<br />
<br />
'''例子 15. Jabber用户进入一个房间(Groupchat 1.0)'''<br />
<br />
<source lang="xml"><br />
<presence<br />
from='hag66@shakespeare.lit/pda'<br />
to='darkcave@macbeth.shakespeare.lit/thirdwitch'/><br />
</source><br />
<br />
在这个例子中, 一个全JID为"hag66@shakespeare.lit/pda"的用户请求用昵称"thirdwitch"进入位于"macbeth.shakespeare.lit"聊天服务的房间"darkcave".<br />
<br />
如果用户未指定一个房间昵称, 服务应该(SHOULD)返回一个<jid-malformed/>错误:<br />
<br />
'''例子 16. Jabber用户进入一个房间(Groupchat 1.0)'''<br />
<br />
<source lang="xml"><br />
<presence<br />
from='darkcave@macbeth.shakespeare.lit'<br />
to='hag66@shakespeare.lit/pda'<br />
type='error'><br />
<error code='400' type='modify'><br />
<jid-malformed xmlns='urn:ietf:params:xml:ns:xmpp-stanzas'/><br />
</error><br />
</presence><br />
</source><br />
<br />
====基本MUC协议====<br />
<br />
兼容的多用户聊天服务必须(MUST)接受知道"groupchat 1.0" (GC)协议或multi-user chat (MUC)协议的任何客户端发出上述请求进入会议室; 无论如何, MUC 客户端应该(SHOULD)声明他们的有能力支持 MUC 协议, 方法是在出席信息节里面包含一个空的 <x/> 元素, 满足名字空间 'http://jabber.org/protocol/muc' (注意不需要 '#user' 部分):<br />
<br />
'''例子 17. Jabber用户进入一个房间(Multi-User Chat)'''<br />
<br />
<source lang="xml"><br />
<presence<br />
from="hag66@shakespeare.lit/pda"<br />
to='darkcave@macbeth.shakespeare.lit/thirdwitch'><br />
<x xmlns='http://jabber.org/protocol/muc'/><br />
</presence><br />
</source><br />
<br />
在尝试进入房间之间, 一个兼容MUC的客户端应该(SHOULD)首先查询它的保留的房间昵称 (如果有的话), 接下来的协议本文中的 Discovering Reserved Room Nickname 章节对此作了定义.<br />
<br />
====出席信息广播====<br />
<br />
如果服务能够添加用户到房间, 它必须(MUST)从所有现存的驻留者的房间JID发送出席信息给新的驻留者的全JID, 包括扩展的关于角色的出席信息, 一个符合 'http://jabber.org/protocol/muc#user' 名字空间的<x/> 元素并包含一个<item/>子元素, 这个子元素的'role'属性值设为"moderator", "participant", 或"visitor", 这个子元素的'affiliation'属性值设为"owner", "admin", "member", 或 "none" 中的一个:<br />
<br />
'''例子 18. 服务从现有的驻留者发送出席信息给新的驻留者'''<br />
<br />
<source lang="xml"><br />
<presence<br />
from='darkcave@macbeth.shakespeare.lit/firstwitch'<br />
to='hag66@shakespeare.lit/pda'><br />
<x xmlns='http://jabber.org/protocol/muc#user'><br />
<item affiliation='owner' role='moderator'/><br />
</x><br />
</presence><br />
<presence<br />
from='darkcave@macbeth.shakespeare.lit/secondwitch'<br />
to='hag66@shakespeare.lit/pda'><br />
<x xmlns='http://jabber.org/protocol/muc#user'><br />
<item affiliation='admin' role='moderator'/><br />
</x><br />
</presence><br />
</source><br />
<br />
这个示例中, 用户已从前一个例子进入房间, 有两个人已经进入房间: 一个是昵称为"firstwitch"的(房间拥有者), 另一个是昵称为"secondwitch"的(房间管理员).<br />
<br />
服务也必须(MUST)从新进入驻留者房间JID向所有驻留者JID发送出席信息(含新驻留者):<br />
<br />
示例:19. 服务发送新驻留者的出席信息给所有驻留者<br />
<br />
<presence<br />
<br />
from='darkcave@macbeth.shakespeare.lit/thirdwitch'<br />
<br />
to='crone1@shakespeare.lit/desktop'><br />
<br />
<x xmlns='http://jabber.org/protocol/muc#user'><br />
<br />
<item affiliation='member' role='participant'/><br />
<br />
</x><br />
<br />
</presence><br />
<br />
<br />
<br />
<presence<br />
<br />
from='darkcave@macbeth.shakespeare.lit/thirdwitch'<br />
<br />
to='wiccarocks@shakespeare.lit/laptop'><br />
<br />
<x xmlns='http://jabber.org/protocol/muc#user'><br />
<br />
<item affiliation='member' role='participant'/><br />
<br />
</x><br />
<br />
</presence><br />
<br />
<br />
<br />
<presence<br />
<br />
from='darkcave@macbeth.shakespeare.lit/thirdwitch'<br />
<br />
to='hag66@shakespeare.lit/pda'><br />
<br />
<x xmlns='http://jabber.org/protocol/muc#user'><br />
<br />
<item affiliation='member' role='participant'/><br />
<br />
<status code='110'/><br />
<br />
</x><br />
<br />
</presence><br />
<br />
<br />
<br />
<br />
<br />
In this example, initial room presence is being sent from the new occupant (thirdwitch) to all occupants, including the new occupant. As shown in the last stanza, the presence sent by the room to a user from itself as an occupant SHOULD include a status code of 110 so that the user knows this presence refers to itself as an occupant.<br />
<br />
<br />
<br />
The service MAY rewrite the new occupant's roomnick (e.g., if roomnicks are locked down). If the service does not accept the new occupant's requested roomnick but instead assigns a new roomnick, it MUST include a status code of "210" in the presence broadcast that it sends to the new occupant.<br />
<br />
<br />
<br />
Example 20. Service Sends New Occupant's Presence to New Occupant<br />
<br />
<br />
<br />
<presence<br />
<br />
from='darkcave@macbeth.shakespeare.lit/thirdwitch'<br />
<br />
to='hag66@shakespeare.lit/pda'><br />
<br />
<x xmlns='http://jabber.org/protocol/muc#user'><br />
<br />
<item affiliation='member' role='participant'/><br />
<br />
<status code='110'/><br />
<br />
<status code='210'/><br />
<br />
</x><br />
<br />
</presence><br />
<br />
<br />
<br />
<br />
<br />
Note: The order of the presence stanzas sent to the new occupant is important. The service MUST first send the complete list of the existing occupants to the new occupant and only then send the new occupant's own presence to the new occupant. This helps the client know when it has received the complete "room roster".<br />
<br />
<br />
<br />
After sending the presence broadcast (and only after doing so), the service may then send discussion history, live messages, presence updates, and other in-room traffic.<br />
<br />
7.1.4 Default Roles<br />
<br />
<br />
<br />
The following table summarizes the initial default roles that a service should set based on the user's affiliation (there is no role associated with the "outcast" affiliation, since such users are not allowed to enter the room).<br />
<br />
<br />
<br />
Table 6: Initial Role Based on Affiliation<br />
<br />
Room Type None Member Admin Owner<br />
<br />
Moderated Visitor Participant Moderator Moderator<br />
<br />
Unmoderated Participant Participant Moderator Moderator<br />
<br />
Members-Only N/A * Participant Moderator Moderator<br />
<br />
Open Participant Participant Moderator Moderator<br />
<br />
<br />
<br />
* Entry is not permitted.<br />
<br />
7.1.5 Non-Anonymous Rooms<br />
<br />
<br />
<br />
If the room is non-anonymous, the service MUST send the new occupant's full JID to all occupants using extended presence information in an <x/> element qualified by the 'http://jabber.org/protocol/muc#user' namespace and containing an <item/> child with a 'jid' attribute specifying the occupant's full JID:<br />
<br />
<br />
<br />
Example 21. Service Sends Full JID to All Occupants<br />
<br />
<br />
<br />
<presence<br />
<br />
from='darkcave@macbeth.shakespeare.lit/thirdwitch'<br />
<br />
to='crone1@shakespeare.lit/desktop'><br />
<br />
<x xmlns='http://jabber.org/protocol/muc#user'><br />
<br />
<item affiliation='none'<br />
<br />
jid='hag66@shakespeare.lit/pda'<br />
<br />
role='participant'/><br />
<br />
</x><br />
<br />
</presence><br />
<br />
.<br />
<br />
.<br />
<br />
.<br />
<br />
<br />
<br />
<br />
<br />
If the user is entering a room that is non-anonymous (i.e., which informs all occupants of each occupant's full JID as shown above), the service SHOULD allow the user to enter the room but MUST also warn the user that the room is not anonymous. This SHOULD be done by including a status code of "100" in the initial presence that the room sends to the new occupant:<br />
<br />
<br />
<br />
Example 22. Service Sends New Occupant's Presence to New Occupant<br />
<br />
<br />
<br />
<presence<br />
<br />
from='darkcave@macbeth.shakespeare.lit/thirdwitch'<br />
<br />
to='hag66@shakespeare.lit/pda'><br />
<br />
<x xmlns='http://jabber.org/protocol/muc#user'><br />
<br />
<item affiliation='member' role='participant'/><br />
<br />
<status code='100'/><br />
<br />
<status code='110'/><br />
<br />
<status code='210'/><br />
<br />
</x><br />
<br />
</presence><br />
<br />
<br />
<br />
<br />
<br />
However, it MAY be done by sending a message of type "groupchat" to the new occupant containing an <x/> child with a <status/> element that has the 'code' attribute set to a value of "100":<br />
<br />
<br />
<br />
Example 23. Service Warns New Occupant About Lack of Anonymity<br />
<br />
<br />
<br />
<message<br />
<br />
from='darkcave@macbeth.shakespeare.lit'<br />
<br />
to='hag66@shakespeare.lit/pda'<br />
<br />
type='groupchat'><br />
<br />
<body>This room is not anonymous.</body><br />
<br />
<x xmlns='http://jabber.org/protocol/muc#user'><br />
<br />
<status code='100'/><br />
<br />
</x><br />
<br />
</message><br />
<br />
<br />
<br />
<br />
<br />
The inclusion of the status code assists clients in presenting their own notification messages (e.g., information appropriate to the user's locality).<br />
<br />
7.1.6 Semi-Anonymous Rooms<br />
<br />
<br />
<br />
If the room is semi-anonymous, the service MUST send the new occupant's full JID in the format shown above only to those occupants with a role of "moderator".<br />
<br />
<br />
<br />
(Note: All subsequent examples include the 'jid' attribute for each <item/> element, even though this information is not sent to non-moderators in semi-anonymous rooms.)<br />
<br />
7.1.7 Password-Protected Rooms<br />
<br />
<br />
<br />
If the room requires a password and the user did not supply one (or the password provided is incorrect), the service MUST deny access to the room and inform the user that they are unauthorized; this is done by returning a presence stanza of type "error" specifying a <not-authorized/> error:<br />
<br />
<br />
<br />
Example 24. Service Denies Access Because No Password Provided<br />
<br />
<br />
<br />
<presence<br />
<br />
from='darkcave@macbeth.shakespeare.lit'<br />
<br />
to='hag66@shakespeare.lit/pda'<br />
<br />
type='error'><br />
<br />
<error code='401' type='auth'><br />
<br />
<not-authorized xmlns='urn:ietf:params:xml:ns:xmpp-stanzas'/><br />
<br />
</error><br />
<br />
</presence><br />
<br />
<br />
<br />
<br />
<br />
Passwords SHOULD be supplied with the presence stanza sent when entering the room, contained within an <x/> element qualified by the 'http://jabber.org/protocol/muc' namespace and containing a <password/> child. Passwords are to be sent as cleartext; no other authentication methods are supported at this time, and any such authentication or authorization methods shall be defined in a separate specification (see the Security Considerations section of this document).<br />
<br />
<br />
<br />
Example 25. User Provides Password On Entering a Room<br />
<br />
<br />
<br />
<presence<br />
<br />
from='hag66@shakespeare.lit/pda'<br />
<br />
to='darkcave@macbeth.shakespeare.lit/thirdwitch'><br />
<br />
<x xmlns='http://jabber.org/protocol/muc'><br />
<br />
<password>cauldronburn</password><br />
<br />
</x><br />
<br />
</presence><br />
<br />
<br />
<br />
<br />
<br />
7.1.8 Members-Only Rooms<br />
<br />
<br />
<br />
If the room is members-only but the user is not on the member list, the service MUST deny access to the room and inform the user that they are not allowed to enter the room; this is done by returning a presence stanza of type "error" specifying a <registration-required/> error condition:<br />
<br />
<br />
<br />
Example 26. Service Denies Access Because User Is Not on Member List<br />
<br />
<br />
<br />
<presence<br />
<br />
from='darkcave@macbeth.shakespeare.lit'<br />
<br />
to='hag66@shakespeare.lit/pda'<br />
<br />
type='error'><br />
<br />
<error code='407' type='auth'><br />
<br />
<registration-required xmlns='urn:ietf:params:xml:ns:xmpp-stanzas'/><br />
<br />
</error><br />
<br />
</presence><br />
<br />
<br />
<br />
<br />
<br />
7.1.9 Banned Users<br />
<br />
<br />
<br />
If the user has been banned from the room (i.e., has an affiliation of "outcast"), the service MUST deny access to the room and inform the user of the fact that he or she is banned; this is done by returning a presence stanza of type "error" specifying a <forbidden/> error condition:<br />
<br />
<br />
<br />
Example 27. Service Denies Access Because User is Banned<br />
<br />
<br />
<br />
<presence<br />
<br />
from='darkcave@macbeth.shakespeare.lit'<br />
<br />
to='hag66@shakespeare.lit/pda'<br />
<br />
type='error'><br />
<br />
<error code='403' type='auth'><br />
<br />
<forbidden xmlns='urn:ietf:params:xml:ns:xmpp-stanzas'/><br />
<br />
</error><br />
<br />
</presence><br />
<br />
<br />
<br />
<br />
<br />
7.1.10 Nickname Conflict<br />
<br />
<br />
<br />
If the room already contains another user with the nickname desired by the user seeking to enter the room (or if the nickname is reserved by another user on the member list), the service MUST deny access to the room and inform the user of the conflict; this is done by returning a presence stanza of type "error" specifying a <conflict/> error condition:<br />
<br />
<br />
<br />
Example 28. Service Denies Access Because of Nick Conflict<br />
<br />
<br />
<br />
<presence<br />
<br />
from='darkcave@macbeth.shakespeare.lit'<br />
<br />
to='hag66@shakespeare.lit/pda'<br />
<br />
type='error'><br />
<br />
<error code='409' type='cancel'><br />
<br />
<conflict xmlns='urn:ietf:params:xml:ns:xmpp-stanzas'/><br />
<br />
</error><br />
<br />
</presence><br />
<br />
<br />
<br />
<br />
<br />
However, if the bare JID (<node@domain.tld>) of the present occupant matches the bare JID of the user seeking to enter the room, then the service SHOULD allow entry to the user, so that the user has two (or more) in-room "sessions" with the same roomnick, one for each resource. If a service allows more than one occupant with the same bare JID and the same room nickname, it SHOULD route in-room messages to all of the user's resources and allow all of the user's resources to send messages to the room; it is up to the implementation to determine how to appropriately handle presence from the user's resources and how to route private messages to all or only one resource (based on presence priority or some other algorithm).<br />
<br />
7.1.11 Max Users<br />
<br />
<br />
<br />
If the room has reached its maximum number of users, the service SHOULD deny access to the room and inform the user of the restriction; this is done by returning a presence stanza of type "error" specifying a <service-unavailable/> error condition:<br />
<br />
<br />
<br />
Example 29. Service Informs User that Room Occupant Limit Has Been Reached<br />
<br />
<br />
<br />
<presence<br />
<br />
from='darkcave@macbeth.shakespeare.lit'<br />
<br />
to='hag66@shakespeare.lit/pda'<br />
<br />
type='error'><br />
<br />
<error code='503' type='wait'><br />
<br />
<service-unavailable xmlns='urn:ietf:params:xml:ns:xmpp-stanzas'/><br />
<br />
</error><br />
<br />
</presence><br />
<br />
<br />
<br />
<br />
<br />
Alternatively, the room could kick an "idle user" in order to free up space. Also, a room MUST always allow entry by a room admin or owner.<br />
<br />
7.1.12 Locked Room<br />
<br />
<br />
<br />
If a user attempts to enter a room while it is "locked" (i.e., before the room creator provides an initial configuration and therefore before the room officially exists), the service MUST refuse entry and return an <item-not-found/> error to the user:<br />
<br />
<br />
<br />
Example 30. Service Denies Access Because Room Does Not Exist<br />
<br />
<br />
<br />
<presence<br />
<br />
from='darkcave@macbeth.shakespeare.lit'<br />
<br />
to='hag66@shakespeare.lit/pda'<br />
<br />
type='error'><br />
<br />
<error code='404' type='cancel'><br />
<br />
<item-not-found xmlns='urn:ietf:params:xml:ns:xmpp-stanzas'/><br />
<br />
</error><br />
<br />
</presence><br />
<br />
<br />
<br />
<br />
<br />
7.1.13 Nonexistent Room<br />
<br />
<br />
<br />
If the room does not already exist when the user seeks to enter it, the service SHOULD create it; however, this is not required, since an implementation or deployment MAY choose to restrict the privilege of creating rooms. For details, see the Creating a Room section of this document.<br />
<br />
7.1.14 Room Logging<br />
<br />
<br />
<br />
If the user is entering a room in which the discussions are logged to a public archive (often accessible via HTTP), the service SHOULD allow the user to enter the room but MUST also warn the user that the discussions are logged. This SHOULD be done by including a status code of "170" in the initial presence that the room sends to the new occupant:<br />
<br />
<br />
<br />
Example 31. Service Sends New Occupant's Presence to New Occupant<br />
<br />
<br />
<br />
<presence<br />
<br />
from='darkcave@macbeth.shakespeare.lit/thirdwitch'<br />
<br />
to='hag66@shakespeare.lit/pda'><br />
<br />
<x xmlns='http://jabber.org/protocol/muc#user'><br />
<br />
<item affiliation='member' role='participant'/><br />
<br />
<status code='100'/><br />
<br />
<status code='110'/><br />
<br />
<status code='170'/><br />
<br />
<status code='210'/><br />
<br />
</x><br />
<br />
</presence><br />
<br />
<br />
<br />
<br />
<br />
7.1.15 Discussion History<br />
<br />
<br />
<br />
After sending initial presence as shown above, a room MAY send discussion history to the new occupant. (The room MUST NOT send any discussion history before it finishes sending room presence as specified in the Presence Broadcast section of this document.) Whether such history is sent, and how many messages comprise the history, shall be determined by the chat service implementation or specific deployment.<br />
<br />
<br />
<br />
Example 32. Delivery of Discussion History<br />
<br />
<br />
<br />
<message<br />
<br />
from='darkcave@macbeth.shakespeare.lit/firstwitch'<br />
<br />
to='hecate@shakespeare.lit/broom'<br />
<br />
type='groupchat'><br />
<br />
<body>Thrice the brinded cat hath mew'd.</body><br />
<br />
<delay xmlns='urn:xmpp:delay'<br />
<br />
from='crone1@shakespeare.lit/desktop'<br />
<br />
stamp='2002-10-13T23:58:37Z'/><br />
<br />
</message><br />
<br />
<br />
<br />
<message<br />
<br />
from='darkcave@macbeth.shakespeare.lit/secondwitch'<br />
<br />
to='hecate@shakespeare.lit/broom'<br />
<br />
type='groupchat'><br />
<br />
<body>Thrice and once the hedge-pig whined.</body><br />
<br />
<delay xmlns='urn:xmpp:delay'<br />
<br />
from='wiccarocks@shakespeare.lit/laptop'<br />
<br />
stamp='2002-10-13T23:58:43Z'/><br />
<br />
</message><br />
<br />
<br />
<br />
<message<br />
<br />
from='darkcave@macbeth.shakespeare.lit/thirdwitch'<br />
<br />
to='hecate@shakespeare.lit/broom'<br />
<br />
type='groupchat'><br />
<br />
<body>Harpier cries 'Tis time, 'tis time.</body><br />
<br />
<delay xmlns='urn:xmpp:delay'<br />
<br />
from='hag66@shakespeare.lit/pda'<br />
<br />
stamp='2002-10-13T23:58:49Z'/><br />
<br />
</message><br />
<br />
<br />
<br />
<br />
<br />
Discussion history messages MUST be stamped with Delayed Delivery [10] information qualified by the 'urn:xmpp:delay' namespace to indicate that they are sent with delayed delivery and to specify the times at which they were originally sent. (Note: The 'urn:xmpp:delay' namespace defined in XEP-0203 supersedes the older 'jabber:x:delay' namespace defined in Delayed Delivery [11]; until the status of XEP-0091 is changed to Obsolete, implementations SHOULD include both datetime formats.) The 'from' attribute SHOULD be the full JID of the original sender in non-anonymous rooms, but MUST NOT be in semi-anonymous rooms (where the 'from' attribute SHOULD be set to the JID of the room itself). The service SHOULD send all discussion history messages before delivering any "live" messages sent after the user enters the room.<br />
<br />
7.1.16 Managing Discussion History<br />
<br />
<br />
<br />
A user MAY want to manage the amount of discussion history provided on entering a room (perhaps because the user is on a low-bandwidth connection or is using a small-footprint client). This MUST be accomplished by including a <history/> child in the initial presence stanza sent when joining the room. There are four allowable attributes for this element:<br />
<br />
<br />
<br />
Table 7: History Management Attributes<br />
<br />
Attribute Datatype Meaning<br />
<br />
maxchars int Limit the total number of characters in the history to "X" (where the character count is the characters of the complete XML stanzas, not only their XML character data).<br />
<br />
maxstanzas int Limit the total number of messages in the history to "X".<br />
<br />
seconds int Send only the messages received in the last "X" seconds.<br />
<br />
since dateTime Send only the messages received since the datetime specified (which MUST conform to the DateTime profile specified in XMPP Date and Time Profiles [12]).<br />
<br />
<br />
<br />
The service MUST send the smallest amount of traffic that meets any combination of the above criteria, taking into account service-level and room-level defaults. The service MUST send complete message stanzas only (i.e., it MUST not literally truncate the history at a certain number of characters, but MUST send the largest number of complete stanzas that results in a number of characters less than or equal to the 'maxchars' value specified). If the client wishes to receive no history, it MUST set the 'maxchars' attribute to a value of "0" (zero).<br />
<br />
<br />
<br />
The following examples illustrate the use of this protocol.<br />
<br />
<br />
<br />
Example 33. User Requests Limit on Number of Messages in History<br />
<br />
<br />
<br />
<presence<br />
<br />
from='hag66@shakespeare.lit/pda'<br />
<br />
to='darkcave@macbeth.shakespeare.lit/thirdwitch'><br />
<br />
<x xmlns='http://jabber.org/protocol/muc'><br />
<br />
<history maxstanzas='20'/><br />
<br />
</x><br />
<br />
</presence><br />
<br />
<br />
<br />
<br />
<br />
Example 34. User Requests History in Last 3 Minutes<br />
<br />
<br />
<br />
<presence<br />
<br />
from='hag66@shakespeare.lit/pda'<br />
<br />
to='darkcave@macbeth.shakespeare.lit/thirdwitch'><br />
<br />
<x xmlns='http://jabber.org/protocol/muc'><br />
<br />
<history seconds='180'/><br />
<br />
</x><br />
<br />
</presence><br />
<br />
<br />
<br />
<br />
<br />
Example 35. User Requests All History Since the Beginning of the Unix Era<br />
<br />
<br />
<br />
<presence<br />
<br />
from='hag66@shakespeare.lit/pda'<br />
<br />
to='darkcave@macbeth.shakespeare.lit/thirdwitch'><br />
<br />
<x xmlns='http://jabber.org/protocol/muc'><br />
<br />
<history since='1970-01-01T00:00Z'/><br />
<br />
</x><br />
<br />
</presence><br />
<br />
<br />
<br />
<br />
<br />
Obviously the service SHOULD NOT return all messages sent in the room since the beginning of the Unix era, and SHOULD appropriately limit the amount of history sent to the user based on service or room defaults.<br />
<br />
<br />
<br />
Example 36. User Requests No History<br />
<br />
<br />
<br />
<presence<br />
<br />
from='hag66@shakespeare.lit/pda'<br />
<br />
to='darkcave@macbeth.shakespeare.lit/thirdwitch'><br />
<br />
<x xmlns='http://jabber.org/protocol/muc'><br />
<br />
<history maxchars='0'/><br />
<br />
</x><br />
<br />
</presence><br />
<br />
<br />
<br />
<br />
<br />
7.2 Exiting a Room<br />
<br />
<br />
<br />
In order to exit a multi-user chat room, an occupant sends a presence stanza of type "unavailable" to the <room@service/nick> it is currently using in the room.<br />
<br />
<br />
<br />
Example 37. Occupant Exits a Room<br />
<br />
<br />
<br />
<presence<br />
<br />
from='hag66@shakespeare.lit/pda'<br />
<br />
to='darkcave@macbeth.shakespeare.lit/thirdwitch'<br />
<br />
type='unavailable'/><br />
<br />
<br />
<br />
<br />
<br />
The service MUST then send presence stanzas of type "unavailable" from the departing occupant's room JID to the full JIDs of the departing occupant and of the remaining occupants:<br />
<br />
<br />
<br />
Example 38. Service Sends Presence Related to Departure of Occupant<br />
<br />
<br />
<br />
<presence<br />
<br />
from='darkcave@macbeth.shakespeare.lit/thirdwitch'<br />
<br />
to='hag66@shakespeare.lit/pda'<br />
<br />
type='unavailable'><br />
<br />
<x xmlns='http://jabber.org/protocol/muc#user'><br />
<br />
<item affiliation='member' role='none'/><br />
<br />
<status code='110'/><br />
<br />
</x><br />
<br />
</presence><br />
<br />
<presence<br />
<br />
from='darkcave@macbeth.shakespeare.lit/thirdwitch'<br />
<br />
to='crone1@shakespeare.lit/desktop'<br />
<br />
type='unavailable'><br />
<br />
<x xmlns='http://jabber.org/protocol/muc#user'><br />
<br />
<item affiliation='member' role='none'/><br />
<br />
</x><br />
<br />
</presence><br />
<br />
<presence<br />
<br />
from='darkcave@macbeth.shakespeare.lit/thirdwitch'<br />
<br />
to='wiccarocks@shakespeare.lit/laptop'<br />
<br />
type='unavailable'><br />
<br />
<x xmlns='http://jabber.org/protocol/muc#user'><br />
<br />
<item affiliation='member' role='none'/><br />
<br />
</x><br />
<br />
</presence><br />
<br />
<br />
<br />
<br />
<br />
Presence stanzas of type "unavailable" reflected by the room MUST contain extended presence information about roles and affiliations; the 'role' attribute SHOULD be set to a value of "none" to denote that the individual is no longer an occupant.<br />
<br />
<br />
<br />
The occupant MAY include normal <status/> information in the unavailable presence stanzas; this enables the occupant to provide a custom exit message if desired:<br />
<br />
<br />
<br />
Example 39. Custom Exit Message<br />
<br />
<br />
<br />
<presence<br />
<br />
from='wiccarocks@shakespeare.lit/laptop'<br />
<br />
to='darkcave@macbeth.shakespeare.lit/oldhag'<br />
<br />
type='unavailable'><br />
<br />
<status>gone where the goblins go</status><br />
<br />
</presence><br />
<br />
<br />
<br />
<br />
<br />
Normal presence stanza generation rules apply as defined in XMPP IM [13], so that if the user sends a general unavailable presence stanza, the user's server will broadcast that stanza to the <room@service/nick> to which the user's client has sent directed presence.<br />
<br />
<br />
<br />
It is possible that a user may not be able to gracefully exit the room by sending unavailable presence directly to the room. If the user goes offline without sending unavailable presence, the user's server is responsible for sending unavailable presence on behalf of the user (in accordance with RFC 3921). If the user's server goes offline or connectivity is lost between the user's server and the MUC service to which the user is connected (e.g., in federated communications), the MUC service is responsible for monitoring error stanzas it receives in order to determine if the user has gone offline. If the MUC service determines that the user has gone offline, it must treat the user as if the user had itself sent unavailable presence.<br />
<br />
<br />
<br />
Note: If the room is not persistent and this occupant is the last to exit, the service is responsible for destroying the room.<br />
<br />
7.3 Changing Nickname<br />
<br />
<br />
<br />
A common feature of multi-user chat rooms is the ability for an occupant to change his or her nickname within the room. In MUC this is done by sending updated presence information to the room, specifically by sending presence to a new room JID in the same room (changing only the resource identifier in the room JID).<br />
<br />
<br />
<br />
Example 40. Occupant Changes Nickname<br />
<br />
<br />
<br />
<presence<br />
<br />
from='hag66@shakespeare.lit/pda'<br />
<br />
to='darkcave@macbeth.shakespeare.lit/oldhag'/><br />
<br />
<br />
<br />
<br />
<br />
The service then sends two presence stanzas to the full JID of each occupant (including the occupant who is changing his or her room nickname), one of type "unavailable" for the old nickname and one indicating availability for the new nickname.<br />
<br />
<br />
<br />
The unavailable presence MUST contain the following as extended presence information in an <x/> element qualified by the 'http://jabber.org/protocol/muc#user' namespace:<br />
<br />
<br />
<br />
* The new nickname (in this case, nick='oldhag')<br />
<br />
* A status code of 303<br />
<br />
<br />
<br />
This enables the recipients to correlate the old roomnick with the new roomnick.<br />
<br />
<br />
<br />
Example 41. Service Updates Nick<br />
<br />
<br />
<br />
<presence<br />
<br />
from='darkcave@macbeth.shakespeare.lit/thirdwitch'<br />
<br />
to='crone1@shakespeare.lit/desktop'<br />
<br />
type='unavailable'><br />
<br />
<x xmlns='http://jabber.org/protocol/muc#user'><br />
<br />
<item affiliation='member'<br />
<br />
jid='hag66@shakespeare.lit/pda'<br />
<br />
nick='oldhag'<br />
<br />
role='participant'/><br />
<br />
<status code='303'/><br />
<br />
</x><br />
<br />
</presence><br />
<br />
<presence<br />
<br />
from='darkcave@macbeth.shakespeare.lit/thirdwitch'<br />
<br />
to='wiccarocks@shakespeare.lit/laptop'<br />
<br />
type='unavailable'><br />
<br />
<x xmlns='http://jabber.org/protocol/muc#user'><br />
<br />
<item affiliation='member'<br />
<br />
jid='hag66@shakespeare.lit/pda'<br />
<br />
nick='oldhag'<br />
<br />
role='participant'/><br />
<br />
<status code='303'/><br />
<br />
</x><br />
<br />
</presence><br />
<br />
<presence<br />
<br />
from='darkcave@macbeth.shakespeare.lit/thirdwitch'<br />
<br />
to='hag66@shakespeare.lit/pda'<br />
<br />
type='unavailable'><br />
<br />
<x xmlns='http://jabber.org/protocol/muc#user'><br />
<br />
<item affiliation='member'<br />
<br />
jid='hag66@shakespeare.lit/pda'<br />
<br />
nick='oldhag'<br />
<br />
role='participant'/><br />
<br />
<status code='303'/><br />
<br />
<status code='110'/><br />
<br />
</x><br />
<br />
</presence><br />
<br />
<br />
<br />
<presence<br />
<br />
from='darkcave@macbeth.shakespeare.lit/oldhag'<br />
<br />
to='crone1@shakespeare.lit/desktop'><br />
<br />
<x xmlns='http://jabber.org/protocol/muc#user'><br />
<br />
<item affiliation='member'<br />
<br />
jid='hag66@shakespeare.lit/pda'<br />
<br />
role='participant'/><br />
<br />
</x><br />
<br />
</presence><br />
<br />
<presence<br />
<br />
from='darkcave@macbeth.shakespeare.lit/oldhag'<br />
<br />
to='wiccarocks@shakespeare.lit/laptop'><br />
<br />
<x xmlns='http://jabber.org/protocol/muc#user'><br />
<br />
<item affiliation='member'<br />
<br />
jid='hag66@shakespeare.lit/pda'<br />
<br />
role='participant'/><br />
<br />
</x><br />
<br />
</presence><br />
<br />
<presence<br />
<br />
from='darkcave@macbeth.shakespeare.lit/oldhag'<br />
<br />
to='hag66@shakespeare.lit/pda'><br />
<br />
<x xmlns='http://jabber.org/protocol/muc#user'><br />
<br />
<item affiliation='member'<br />
<br />
jid='hag66@shakespeare.lit/pda'<br />
<br />
role='participant'/><br />
<br />
<status code='110'/><br />
<br />
</x><br />
<br />
</presence><br />
<br />
<br />
<br />
<br />
<br />
If the user attempts to change his or her room nickname to a room nickname that is already in use by another user (or that is reserved by another user affiliated with the room, e.g., a member or owner), the service MUST deny the nickname change request and inform the user of the conflict; this is done by returning a presence stanza of type "error" specifying a <conflict/> error condition:<br />
<br />
<br />
<br />
Example 42. Service Denies Nickname Change Because of Nick Conflict<br />
<br />
<br />
<br />
<presence<br />
<br />
from='darkcave@macbeth.shakespeare.lit'<br />
<br />
to='hag66@shakespeare.lit/pda'<br />
<br />
type='error'><br />
<br />
<error code='409' type='cancel'><br />
<br />
<conflict xmlns='urn:ietf:params:xml:ns:xmpp-stanzas'/><br />
<br />
</error><br />
<br />
</presence><br />
<br />
<br />
<br />
<br />
<br />
However, if the bare JID (<node@domain.tld>) of the present occupant matches the bare JID of the user seeking to change his or her nickname, then the service MAY allow the nickname change. See the Nickname Conflict section of this document for details.<br />
<br />
<br />
<br />
If the user attempts to change his or her room nickname but room nicknames are "locked down", the service MUST deny the nickname change request and return a presence stanza of type "error" specifying a <not-acceptable/> error condition:<br />
<br />
<br />
<br />
Example 43. Service Denies Nickname Change Because Roomnicks Are Locked Down<br />
<br />
<br />
<br />
<presence<br />
<br />
from='darkcave@macbeth.shakespeare.lit'<br />
<br />
to='hag66@shakespeare.lit/pda'<br />
<br />
type='error'><br />
<br />
<error code='406' type='cancel'><br />
<br />
<not-acceptable xmlns='urn:ietf:params:xml:ns:xmpp-stanzas'/><br />
<br />
</error><br />
<br />
</presence><br />
<br />
<br />
<br />
<br />
<br />
The user SHOULD then discover its reserved nickname as specified in the Discovering Reserved Room Nickname section of this document.<br />
<br />
7.4 Changing Availability Status<br />
<br />
<br />
<br />
In multi-user chat systems such as IRC, one common use for changing one's room nickname is to indicate a change in one's availability (e.g., changing one's room nickname to "thirdwitch|away"). In Jabber, availability is of course noted by a change in presence (specifically the <show/> and <status/> elements), which can provide important context within a chatroom. An occupant changes availability status within the room by sending the updated presence to its <room@service/nick>.<br />
<br />
<br />
<br />
Example 44. Occupant Changes Availability Status<br />
<br />
<br />
<br />
<br />
<br />
<presence<br />
<br />
from='wiccarocks@shakespeare.lit/laptop'<br />
<br />
to='darkcave@macbeth.shakespeare.lit/oldhag'><br />
<br />
<show>xa</show><br />
<br />
<status>gone where the goblins go</status><br />
<br />
</presence><br />
<br />
<br />
<br />
<br />
<br />
The service then sends a presence stanza from the occupant changing his or her presence to the full JID of each occupant, including extended presence information about the occupant's role and full JID to those with privileges to view such information:<br />
<br />
<br />
<br />
Example 45. Service Passes Along Changed Presence to All Occupants<br />
<br />
<br />
<br />
<presence<br />
<br />
from='darkcave@macbeth.shakespeare.lit/secondwitch'<br />
<br />
to='crone1@shakespeare.lit/desktop'><br />
<br />
<show>xa</show><br />
<br />
<status>gone where the goblins go</status><br />
<br />
<x xmlns='http://jabber.org/protocol/muc#user'><br />
<br />
<item affiliation='admin'<br />
<br />
jid='wiccarocks@shakespeare.lit/laptop'<br />
<br />
role='moderator'/><br />
<br />
</x><br />
<br />
</presence><br />
<br />
.<br />
<br />
.<br />
<br />
.<br />
<br />
<br />
<br />
<br />
<br />
7.5 Inviting Another User to a Room<br />
<br />
<br />
<br />
It can be useful to invite another user to a room in which one is an occupant. To do this, a MUC client MUST send XML of the following form to the <room@service> itself (the reason is OPTIONAL and the message MUST be explicitly or implicitly of type "normal"):<br />
<br />
<br />
<br />
Example 46. Occupant Sends an Invitation by Way of Room<br />
<br />
<br />
<br />
<message<br />
<br />
from='crone1@shakespeare.lit/desktop'<br />
<br />
to='darkcave@macbeth.shakespeare.lit'><br />
<br />
<x xmlns='http://jabber.org/protocol/muc#user'><br />
<br />
<invite to='hecate@shakespeare.lit'><br />
<br />
<reason><br />
<br />
Hey Hecate, this is the place for all good witches!<br />
<br />
</reason><br />
<br />
</invite><br />
<br />
</x><br />
<br />
</message><br />
<br />
<br />
<br />
<br />
<br />
The <room@service> itself MUST then add a 'from' address to the <invite/> element whose value is the bare JID (or, optionally, the room JID) of the invitor and send the invitation to the invitee captured in the 'to' address (the service SHOULD include a message body explaining the invitation or containing the reason, for the sake of older clients; in addition, the room SHOULD add the password if the room is password-protected):<br />
<br />
<br />
<br />
Example 47. Room Sends Invitation to Invitee on Behalf of Invitor<br />
<br />
<br />
<br />
<message<br />
<br />
from='darkcave@macbeth.shakespeare.lit'<br />
<br />
to='hecate@shakespeare.lit'><br />
<br />
<body>You have been invited to darkcave@macbeth by crone1@shakespeare.lit.</body><br />
<br />
<x xmlns='http://jabber.org/protocol/muc#user'><br />
<br />
<invite from='crone1@shakespeare.lit'><br />
<br />
<reason><br />
<br />
Hey Hecate, this is the place for all good witches!<br />
<br />
</reason><br />
<br />
</invite><br />
<br />
<password>cauldronburn</password><br />
<br />
</x><br />
<br />
</message><br />
<br />
<br />
<br />
<br />
<br />
If the room is members-only, the service MAY also add the invitee to the member list. (Note: Invitation privileges in members-only rooms SHOULD be restricted to room admins; if a member without privileges to edit the member list attempts to invite another user, the service SHOULD return a <forbidden/> error to the occupant; for details, see the Modifying the Member List section of this document.)<br />
<br />
<br />
<br />
If the invitor supplies a non-existent JID, the room SHOULD return an <item-not-found/> error to the invitor.<br />
<br />
<br />
<br />
The invitee MAY choose to formally decline (as opposed to ignore) the invitation; and this is something that the sender may want to be informed about. In order to decline the invitation, the invitee MUST send a message of the following form to the <room@service> itself:<br />
<br />
<br />
<br />
Example 48. Invitee Declines Invitation<br />
<br />
<br />
<br />
<message<br />
<br />
from='hecate@shakespeare.lit/broom'<br />
<br />
to='darkcave@macbeth.shakespeare.lit'><br />
<br />
<x xmlns='http://jabber.org/protocol/muc#user'><br />
<br />
<decline to='crone1@shakespeare.lit'><br />
<br />
<reason><br />
<br />
Sorry, I'm too busy right now.<br />
<br />
</reason><br />
<br />
</decline><br />
<br />
</x><br />
<br />
</message><br />
<br />
<br />
<br />
<br />
<br />
Example 49. Room Informs Invitor that Invitation Was Declined<br />
<br />
<br />
<br />
<message<br />
<br />
from='darkcave@macbeth.shakespeare.lit'<br />
<br />
to='crone1@shakespeare.lit/desktop'><br />
<br />
<x xmlns='http://jabber.org/protocol/muc#user'><br />
<br />
<decline from='hecate@shakespeare.lit'><br />
<br />
<reason><br />
<br />
Sorry, I'm too busy right now.<br />
<br />
</reason><br />
<br />
</decline><br />
<br />
</x><br />
<br />
</message><br />
<br />
<br />
<br />
<br />
<br />
It may be wondered why the invitee does not send the decline message directly to the invitor. The main reason is that certain implementations MAY choose to base invitations on room JIDs rather than bare JIDs (so that, for example, an occupant could invite someone from one room to another without knowing that person's bare JID). Thus the service MUST handle both the invites and declines.<br />
<br />
7.6 Converting a One-to-One Chat Into a Conference<br />
<br />
<br />
<br />
Sometimes it is desirable to convert a one-to-one chat into a multi-user conference. The process flow is shown in the following examples.<br />
<br />
<br />
<br />
First, two users begin a one-to-one chat.<br />
<br />
<br />
<br />
Example 50. A One-to-One Chat<br />
<br />
<br />
<br />
<message<br />
<br />
from='crone1@shakespeare.lit/desktop'<br />
<br />
to='wiccarocks@shakespeare.lit/laptop'<br />
<br />
type='chat'><br />
<br />
<body>Thrice the brinded cat hath mew'd.</body><br />
<br />
</message><br />
<br />
<br />
<br />
<message<br />
<br />
from='wiccarocks@shakespeare.lit/laptop'<br />
<br />
to='crone1@shakespeare.lit/desktop'<br />
<br />
type='chat'><br />
<br />
<body>Thrice and once the hedge-pig whined.</body><br />
<br />
</message><br />
<br />
<br />
<br />
<br />
<br />
Now the first person decides to include a third person in the discussion, so she (or, more precisely, her client) does the following:<br />
<br />
<br />
<br />
1. Creates a new room<br />
<br />
2. Optionally sends history of the one-to-one chat to the room<br />
<br />
3. Sends an invitation to the second person and the third person, including a <continue/> flag.<br />
<br />
<br />
<br />
Note: The new room SHOULD be non-anonymous, MAY be an instant room as specified in the Creating an Instant Room section of this document, and MAY have a unique room name received from the service as specified in the Requesting a Unique Room Name section of this document.<br />
<br />
<br />
<br />
Example 51. Continuing the Discussion I: User Creates Room<br />
<br />
<br />
<br />
<presence<br />
<br />
from='crone1@shakespeare.lit/desktop'<br />
<br />
to='darkcave@macbeth.shakespeare.lit/firstwitch'><br />
<br />
<x xmlns='http://jabber.org/protocol/muc'/><br />
<br />
</presence><br />
<br />
<br />
<br />
<presence<br />
<br />
from='darkcave@macbeth.shakespeare.lit/firstwitch'<br />
<br />
to='crone1@shakespeare.lit/desktop'><br />
<br />
<x xmlns='http://jabber.org/protocol/muc#user'><br />
<br />
<item affiliation='owner' role='moderator'/><br />
<br />
</x><br />
<br />
</presence><br />
<br />
<br />
<br />
<br />
<br />
Example 52. Continuing the Discussion II: Owner Sends History to Room<br />
<br />
<br />
<br />
<message<br />
<br />
from='crone1@shakespeare.lit/desktop'<br />
<br />
to='darkcave@macbeth.shakespeare.lit'<br />
<br />
type='groupchat'><br />
<br />
<body>Thrice the brinded cat hath mew'd.</body><br />
<br />
<delay xmlns='urn:xmpp:delay'<br />
<br />
from='crone1@shakespeare.lit/desktop'<br />
<br />
stamp='20040929T01:54:37Z'/><br />
<br />
</message><br />
<br />
<br />
<br />
<message<br />
<br />
from='crone1@shakespeare.lit/desktop'<br />
<br />
to='darkcave@macbeth.shakespeare.lit'<br />
<br />
type='groupchat'><br />
<br />
<body>Thrice and once the hedge-pig whined.</body><br />
<br />
<delay xmlns='urn:xmpp:delay'<br />
<br />
from='wiccarocks@shakespeare.lit/laptop'<br />
<br />
stamp='20040929T01:55:21Z'/><br />
<br />
</message><br />
<br />
<br />
<br />
<br />
<br />
Note: Use of the Delayed Delivery protocol enables the room creator to specify the datetime of each message from the one-to-one chat history (via the 'stamp' attribute), as well as the JID of the original sender of each message (via the 'from' attribute). The room creator SHOULD send the complete one-to-one chat history before inviting additional users to the room, and SHOULD also send as history any messages appearing in the one-to-one chat interface after joining the room and before the second person joins the room; if the one-to-one history is especially large, the sending client may want to send the history over a few seconds rather than all at once (to avoid triggering rate limits). The service SHOULD NOT add its own delay elements (as described in the Discussion History section of this document) to prior chat history messages received from the room owner.<br />
<br />
<br />
<br />
Example 53. Continuing the Discussion III: Owner Sends Invitations, Including Continue Flag<br />
<br />
<br />
<br />
<message<br />
<br />
from='crone1@shakespeare.lit/desktop'<br />
<br />
to='darkcave@macbeth.shakespeare.lit'><br />
<br />
<x xmlns='http://jabber.org/protocol/muc#user'><br />
<br />
<invite to='wiccarocks@shakespeare.lit/laptop'><br />
<br />
<reason>This coven needs both wiccarocks and hag66.</reason><br />
<br />
<continue/><br />
<br />
</invite><br />
<br />
<invite to='hag66@shakespeare.lit'><br />
<br />
<reason>This coven needs both wiccarocks and hag66.</reason><br />
<br />
<continue/><br />
<br />
</invite><br />
<br />
</x><br />
<br />
</message><br />
<br />
<br />
<br />
<br />
<br />
Note: Since the invitor's client knows the full JID of the person with whom the invitor was having a one-to-one chat, it SHOULD include the full JID (rather than the bare JID) in the invitation.<br />
<br />
<br />
<br />
The invitations are delivered to the invitees:<br />
<br />
<br />
<br />
Example 54. Invitations Delivered<br />
<br />
<br />
<br />
<message<br />
<br />
from='darkcave@macbeth.shakespeare.lit'><br />
<br />
to='wiccarocks@shakespeare.lit/laptop'><br />
<br />
<x xmlns='http://jabber.org/protocol/muc#user'><br />
<br />
<invite from='crone1@shakespeare.lit'><br />
<br />
<reason>This coven needs both wiccarocks and hag66.</reason><br />
<br />
<continue/><br />
<br />
</invite><br />
<br />
</x><br />
<br />
</message><br />
<br />
<br />
<br />
<message<br />
<br />
from='darkcave@macbeth.shakespeare.lit'><br />
<br />
to='hag66@shakespeare.lit'><br />
<br />
<x xmlns='http://jabber.org/protocol/muc#user'><br />
<br />
<invite from='crone1@shakespeare.lit'><br />
<br />
<reason>This coven needs both wiccarocks and hag66.</reason><br />
<br />
<continue/><br />
<br />
</invite><br />
<br />
</x><br />
<br />
</message><br />
<br />
<br />
<br />
<br />
<br />
When the client being used by <wiccarocks@shakespeare.lit/laptop> receives the invitation, it SHOULD auto-join the room or prompt the user whether to join (subject to user preferences) and then seamlessly convert the existing one-to-one chat window into a multi-user conferencing window:<br />
<br />
<br />
<br />
Example 55. Invitee Accepts Invitation, Joins Room, and Receives Presence and History<br />
<br />
<br />
<br />
<presence<br />
<br />
from='wiccarocks@shakespeare.lit/laptop'<br />
<br />
to='darkcave@macbeth.shakespeare.lit/secondwitch'><br />
<br />
<x xmlns='http://jabber.org/protocol/muc'/><br />
<br />
</presence><br />
<br />
<br />
<br />
<presence<br />
<br />
from='darkcave@macbeth.shakespeare.lit/firstwitch'<br />
<br />
to='wiccarocks@shakespeare.lit/laptop'><br />
<br />
<x xmlns='http://jabber.org/protocol/muc#user'><br />
<br />
<item affiliation='owner' role='moderator'/><br />
<br />
</x><br />
<br />
</presence><br />
<br />
<br />
<br />
<presence<br />
<br />
from='darkcave@macbeth.shakespeare.lit/secondwitch'<br />
<br />
to='wiccarocks@shakespeare.lit/laptop'><br />
<br />
<x xmlns='http://jabber.org/protocol/muc#user'><br />
<br />
<item affiliation='member' role='participant'/><br />
<br />
</x><br />
<br />
</presence><br />
<br />
<br />
<br />
<message<br />
<br />
from='darkcave@macbeth.shakespeare.lit'<br />
<br />
to='wiccarocks@shakespeare.lit/laptop'<br />
<br />
type='groupchat'><br />
<br />
<body>Thrice the brinded cat hath mew'd.</body><br />
<br />
<delay xmlns='urn:xmpp:delay'<br />
<br />
from='crone1@shakespeare.lit/desktop'<br />
<br />
stamp='20040929T01:54:37Z'/><br />
<br />
</message><br />
<br />
<br />
<br />
<message<br />
<br />
from='darkcave@macbeth.shakespeare.lit'<br />
<br />
to='wiccarocks@shakespeare.lit/laptop'<br />
<br />
type='groupchat'><br />
<br />
<body>Thrice and once the hedge-pig whined.</body><br />
<br />
<delay xmlns='urn:xmpp:delay'<br />
<br />
from='wiccarocks@shakespeare.lit/laptop'<br />
<br />
stamp='20040929T01:55:21Z'/><br />
<br />
</message><br />
<br />
<br />
<br />
<br />
<br />
Note: The fact that the messages come from the <room@service> itself rather than <room@service/nick> is a clue to the receiving client that these messages are prior chat history, since any message from a room occupant will have a 'from' address equal to the sender's room JID.<br />
<br />
7.7 Occupant Modification of the Room Subject<br />
<br />
<br />
<br />
If allowed in accordance with room configuration, a mere occupant MAY be allowed to change the subject in a room. For details, see the Modifying the Room Subject section of this document.<br />
<br />
7.8 Sending a Private Message<br />
<br />
<br />
<br />
Since each occupant has a unique room JID, an occupant MAY send a "private message" to a selected occupant via the service by sending a message to the occupant's room JID. The message type SHOULD be "chat" and MUST NOT be "groupchat", but MAY be left unspecified (i.e., a normal message). This privilege SHOULD be allowed to any occupant (even a visitor in a moderated room).<br />
<br />
<br />
<br />
Example 56. Occupant Sends Private Message<br />
<br />
<br />
<br />
<message<br />
<br />
from='wiccarocks@shakespeare.lit/laptop'<br />
<br />
to='darkcave@macbeth.shakespeare.lit/firstwitch'<br />
<br />
type='chat'><br />
<br />
<body>I'll give thee a wind.</body><br />
<br />
</message><br />
<br />
<br />
<br />
<br />
<br />
The service is responsible for changing the 'from' address to the sender's room JID and delivering the message to the intended recipient's full JID.<br />
<br />
<br />
<br />
Example 57. Recipient Receives the Private Message<br />
<br />
<br />
<br />
<message<br />
<br />
from='darkcave@macbeth.shakespeare.lit/secondwitch'<br />
<br />
to='crone1@shakespeare.lit/desktop'<br />
<br />
type='chat'><br />
<br />
<body>I'll give thee a wind.</body><br />
<br />
</message><br />
<br />
<br />
<br />
<br />
<br />
If the sender attempts to send a private message of type "groupchat" to a particular occupant, the service MUST refuse to deliver the message (since the recipient's client would expect in-room messages to be of type "groupchat") and return a <bad-request/> error to the sender:<br />
<br />
<br />
<br />
Example 58. Occupant Attempts to Send a Message of Type "Groupchat" to a Particular Occupant<br />
<br />
<br />
<br />
<message<br />
<br />
from='wiccarocks@shakespeare.lit/laptop'<br />
<br />
to='darkcave@macbeth.shakespeare.lit/firstwitch'<br />
<br />
type='groupchat'><br />
<br />
<body>I'll give thee a wind.</body><br />
<br />
</message><br />
<br />
<br />
<br />
<message<br />
<br />
from='darkcave@macbeth.shakespeare.lit'<br />
<br />
to='wiccarocks@shakespeare.lit/laptop'<br />
<br />
type='error'><br />
<br />
<body>I'll give thee a wind.</body><br />
<br />
<error code='400' type='modify'><br />
<br />
<bad-request xmlns='urn:ietf:params:xml:ns:xmpp-stanzas'/><br />
<br />
</error><br />
<br />
</message><br />
<br />
<br />
<br />
<br />
<br />
If the sender attempts to send a private message to a room JID that does not exist, the service MUST return an <item-not-found/> error to the sender.<br />
<br />
<br />
<br />
If the sender is not an occupant of the room in which the intended recipient is visiting, the service MUST return a <not-acceptable/> error to the sender.<br />
<br />
7.9 Sending a Message to All Occupants<br />
<br />
<br />
<br />
An occupant sends a message to all other occupants in the room by sending a message of type "groupchat" to the <room@service> itself (a service MAY ignore or reject messages that do not have a type of "groupchat"). In a moderated room, this privilege is restricted to occupants with a role of participant or higher.<br />
<br />
<br />
<br />
Example 59. Occupant Sends a Message to All Occupants<br />
<br />
<br />
<br />
<message<br />
<br />
from='hag66@shakespeare.lit/pda'<br />
<br />
to='darkcave@macbeth.shakespeare.lit'<br />
<br />
type='groupchat'><br />
<br />
<body>Harpier cries: 'tis time, 'tis time.</body><br />
<br />
</message><br />
<br />
<br />
<br />
<br />
<br />
If the sender has voice in the room (this is the default except in moderated rooms), the service MUST change the 'from' attribute to the sender's room JID and reflect the message out to the full JID of each occupant.<br />
<br />
<br />
<br />
Example 60. Service Reflects Message to All Occupants<br />
<br />
<br />
<br />
<message<br />
<br />
from='darkcave@macbeth.shakespeare.lit/thirdwitch'<br />
<br />
to='crone1@shakespeare.lit/desktop'<br />
<br />
type='groupchat'><br />
<br />
<body>Harpier cries: 'tis time, 'tis time.</body><br />
<br />
</message><br />
<br />
<message<br />
<br />
from='darkcave@macbeth.shakespeare.lit/thirdwitch'<br />
<br />
to='wiccarocks@shakespeare.lit/laptop'<br />
<br />
type='groupchat'><br />
<br />
<body>Harpier cries: 'tis time, 'tis time.</body><br />
<br />
</message><br />
<br />
<message<br />
<br />
from='darkcave@macbeth.shakespeare.lit/thirdwitch'<br />
<br />
to='hag66@shakespeare.lit/pda'<br />
<br />
type='groupchat'><br />
<br />
<body>Harpier cries: 'tis time, 'tis time.</body><br />
<br />
</message><br />
<br />
<br />
<br />
<br />
<br />
If the sender is a visitor (i.e., does not have voice in a moderated room), the service MAY return a <forbidden/> error to the sender and MUST NOT reflect the message to all occupants. If the sender is not an occupant of the room, the service SHOULD return a <not-acceptable/> error to the sender and SHOULD NOT reflect the message to all occupants; the only exception to this rule is that an implementation MAY allow users with certain privileges (e.g., a room owner, room admin, or service-level admin) to send messages to the room even if those users are not occupants.<br />
<br />
7.10 Registering with a Room<br />
<br />
<br />
<br />
An implementation MAY allow an unaffiliated user (in a moderated room, normally a participant) to register with a room and thus become a member of the room (conversely, an implementation MAY restrict this privilege and allow only room admins to add new members). In particular, it is not possible to join a members-only room without being on the member list, so an entity may need to request membership in order to join such a room.<br />
<br />
<br />
<br />
If allowed, this functionality SHOULD be implemented by enabling a user to send a request for registration requirements to the room qualified by the 'jabber:iq:register' namespace as described in In-Band Registration [14]:<br />
<br />
<br />
<br />
Example 61. User Requests Registration Requirements<br />
<br />
<br />
<br />
<iq from='hag66@shakespeare.lit/pda'<br />
<br />
id='reg1'<br />
<br />
to='darkcave@macbeth.shakespeare.lit'<br />
<br />
type='get'><br />
<br />
<query xmlns='jabber:iq:register'/><br />
<br />
</iq><br />
<br />
<br />
<br />
<br />
<br />
If the user requesting registration requirements is not allowed to register with the room (e.g., because that privilege has been restricted), the room MUST return a <not-allowed/> error to the user. If the user is already registered, the room MUST reply with an IQ stanza of type "result" that contains an empty <register/> element as described in XEP-0077. If the room does not exist, the service MUST return an <item-not-found/> error.<br />
<br />
<br />
<br />
Otherwise, the room MUST then return a Data Form to the user (as described in Data Forms [15]). The information required to register MAY vary by implementation or deployment and is not fully specified in this document (e.g., the fields registered by this document for the 'http://jabber.org/protocol/muc#register' FORM_TYPE may be supplemented in the future via the mechanisms described in the Field Standardization section of this document). The following can be taken as a fairly typical example:<br />
<br />
<br />
<br />
Example 62. Service Returns Registration Form<br />
<br />
<br />
<br />
<iq from='darkcave@macbeth.shakespeare.lit'<br />
<br />
id='reg1'<br />
<br />
to='hag66@shakespeare.lit/pda'<br />
<br />
type='result'><br />
<br />
<query xmlns='jabber:iq:register'><br />
<br />
<instructions><br />
<br />
To register on the web, visit http://shakespeare.lit/<br />
<br />
</instructions><br />
<br />
<x xmlns='jabber:x:data' type='form'><br />
<br />
<title>Dark Cave Registration</title><br />
<br />
<instructions><br />
<br />
Please provide the following information<br />
<br />
to register with this room.<br />
<br />
</instructions><br />
<br />
<field<br />
<br />
type='hidden'<br />
<br />
var='FORM_TYPE'><br />
<br />
<value>http://jabber.org/protocol/muc#register</value><br />
<br />
</field><br />
<br />
<field<br />
<br />
label='First Name'<br />
<br />
type='text-single'<br />
<br />
var='muc#register_first'><br />
<br />
<required/><br />
<br />
</field><br />
<br />
<field<br />
<br />
label='Last Name'<br />
<br />
type='text-single'<br />
<br />
var='muc#register_last'><br />
<br />
<required/><br />
<br />
</field><br />
<br />
<field<br />
<br />
label='Desired Nickname'<br />
<br />
type='text-single'<br />
<br />
var='muc#register_roomnick'><br />
<br />
<required/><br />
<br />
</field><br />
<br />
<field<br />
<br />
label='Your URL'<br />
<br />
type='text-single'<br />
<br />
var='muc#register_url'/><br />
<br />
<field<br />
<br />
label='Email Address'<br />
<br />
type='text-single'<br />
<br />
var='muc#register_email'/><br />
<br />
<field<br />
<br />
label='FAQ Entry'<br />
<br />
type='text-multi'<br />
<br />
var='muc#register_faqentry'/><br />
<br />
</x><br />
<br />
</query><br />
<br />
</iq><br />
<br />
<br />
<br />
<br />
<br />
The user SHOULD then submit the form:<br />
<br />
<br />
<br />
Example 63. User Submits Registration Form<br />
<br />
<br />
<br />
<iq from='hag66@shakespeare.lit/pda'<br />
<br />
id='reg2'<br />
<br />
to='darkcave@macbeth.shakespeare.lit'<br />
<br />
type='set'><br />
<br />
<query xmlns='jabber:iq:register'><br />
<br />
<x xmlns='jabber:x:data' type='submit'><br />
<br />
<field var='FORM_TYPE'><br />
<br />
<value>http://jabber.org/protocol/muc#register</value><br />
<br />
</field><br />
<br />
<field var='muc#register_first'><br />
<br />
<value>Brunhilde</value><br />
<br />
</field><br />
<br />
<field var='muc#register_last'><br />
<br />
<value>Entwhistle-Throckmorton</value><br />
<br />
</field><br />
<br />
<field var='muc#register_roomnick'><br />
<br />
<value>thirdwitch</value><br />
<br />
</field><br />
<br />
<field var='muc#register_url'><br />
<br />
<value>http://witchesonline/~hag66/</value><br />
<br />
</field><br />
<br />
<field var='muc#register_email'><br />
<br />
<value>hag66@witchesonline</value><br />
<br />
</field><br />
<br />
<field var='muc#register_faqentry'><br />
<br />
<value>Just another witch.</value><br />
<br />
</field><br />
<br />
</x><br />
<br />
</query><br />
<br />
</iq><br />
<br />
<br />
<br />
<br />
<br />
If the desired room nickname is already reserved for that room, the room MUST return a <conflict/> error to the user:<br />
<br />
<br />
<br />
Example 64. Room Returns Conflict Error to User<br />
<br />
<br />
<br />
<iq from='darkcave@macbeth.shakespeare.lit'<br />
<br />
id='reg2'<br />
<br />
to='hag66@shakespeare.lit/pda'<br />
<br />
type='error'><br />
<br />
<error code='409' type='cancel'><br />
<br />
<conflict xmlns='urn:ietf:params:xml:ns:xmpp-stanzas'/><br />
<br />
</error><br />
<br />
</iq><br />
<br />
<br />
<br />
<br />
<br />
If the room or service does not support registration, it MUST return a <service-unavailable/> error to the user:<br />
<br />
<br />
<br />
Example 65. Room Returns Service Unavailable Error to User<br />
<br />
<br />
<br />
<iq from='darkcave@macbeth.shakespeare.lit'<br />
<br />
id='reg2'<br />
<br />
to='hag66@shakespeare.lit/pda'<br />
<br />
type='error'><br />
<br />
<error code='503' type='cancel'><br />
<br />
<service-unavailable xmlns='urn:ietf:params:xml:ns:xmpp-stanzas'/><br />
<br />
</error><br />
<br />
</iq><br />
<br />
<br />
<br />
<br />
<br />
If the user did not include a valid data form, the room MUST return a <bad-request/> error to the user:<br />
<br />
<br />
<br />
Example 66. Room Returns Service Bad Request Error to User<br />
<br />
<br />
<br />
<iq from='darkcave@macbeth.shakespeare.lit'<br />
<br />
id='reg2'<br />
<br />
to='hag66@shakespeare.lit/pda'<br />
<br />
type='error'><br />
<br />
<error code='400' type='modify'><br />
<br />
<bad-request xmlns='urn:ietf:params:xml:ns:xmpp-stanzas'/><br />
<br />
</error><br />
<br />
</iq><br />
<br />
<br />
<br />
<br />
<br />
Otherwise, the room MUST inform the user that the registration request was successfully received:<br />
<br />
<br />
<br />
Example 67. Room Informs User that Registration Request Has Been Processed<br />
<br />
<br />
<br />
<iq from='darkcave@macbeth.shakespeare.lit'<br />
<br />
id='reg2'<br />
<br />
to='hag66@shakespeare.lit/pda'<br />
<br />
type='result'/><br />
<br />
<br />
<br />
<br />
<br />
After the user submits the form, the service MAY request that the submission be approved by a room admin/owner (see the Approving Registration Requests section of this document) or MAY immediately add the user to the member list by changing the user's affiliation from "none" to "member". If the service changes the user's affiliation and the user is in the room, it MUST send updated presence from this individual to all occupants, indicating the change in affiliation by including an <x/> element qualified by the 'http://jabber.org/protocol/muc#user' namespace and containing an <item/> child with the 'affiliation' attribute set to a value of "member".<br />
<br />
<br />
<br />
Example 68. Service Sends Notice of Membership to All Occupants<br />
<br />
<br />
<br />
<presence<br />
<br />
from='darkcave@macbeth.shakespeare.lit/thirdwitch'<br />
<br />
to='crone1@shakespeare.lit/desktop'><br />
<br />
<x xmlns='http://jabber.org/protocol/muc#user'><br />
<br />
<item affiliation='member'<br />
<br />
jid='hag66@shakespeare.lit/pda'<br />
<br />
role='participant'/><br />
<br />
</x><br />
<br />
</presence><br />
<br />
.<br />
<br />
.<br />
<br />
.<br />
<br />
<br />
<br />
<br />
<br />
If a user has registered with a room, the room MAY choose to restrict the user to use of the registered nickname only in that room. If it does so, it SHOULD return a <not-acceptable/> error to the user if the user attempts to join the room with a roomnick other than the user's registered roomnick (this enables a room to "lock down" roomnicks for consistent identification of occupants).<br />
<br />
7.11 Discovering Reserved Room Nickname<br />
<br />
<br />
<br />
A user MAY have a reserved room nickname, for example through explicit room registration, database integration, or nickname "lockdown". A user SHOULD discover his or her reserved nickname before attempting to enter the room. This is done by sending a Service Discovery information request to the room JID while specifying a well-known Service Discovery node of "x-roomuser-item".<br />
<br />
<br />
<br />
Example 69. User Requests Reserved Nickname<br />
<br />
<br />
<br />
<iq from='hag66@shakespeare.lit/pda'<br />
<br />
id='getnick1'<br />
<br />
to='darkcave@macbeth.shakespeare.lit'<br />
<br />
type='get'><br />
<br />
<query xmlns='http://jabber.org/protocol/disco#info'<br />
<br />
node='x-roomuser-item'/><br />
<br />
</iq><br />
<br />
<br />
<br />
<br />
<br />
It is OPTIONAL for a multi-user chat service to support the foregoing service discovery node. If the room or service does not support the foregoing service discovery node, it MUST return a <feature-not-implemented/> error to the user. If it does and the user has a registered nickname, it MUST return the nickname to the user as the value of the 'name' attribute of a Service Discovery <identity/> element (for which the category/type SHOULD be "conference/text"):<br />
<br />
<br />
<br />
Example 70. Room Returns Nickname<br />
<br />
<br />
<br />
<iq from='darkcave@macbeth.shakespeare.lit'<br />
<br />
id='getnick1'<br />
<br />
to='hag66@shakespeare.lit/pda'<br />
<br />
type='result'><br />
<br />
<query xmlns='http://jabber.org/protocol/disco#info'<br />
<br />
node='x-roomuser-item'><br />
<br />
<identity<br />
<br />
category='conference'<br />
<br />
name='thirdwitch'<br />
<br />
type='text'/><br />
<br />
</query><br />
<br />
</iq><br />
<br />
<br />
<br />
<br />
<br />
If the user does not have a registered nickname, the room MUST return a service discovery <query/> element that is empty (in accordance with XEP-0030).<br />
<br />
<br />
<br />
Even if a user has registered one room nickname, the service SHOULD allow the user to specify a different nickname on entering the room (e.g., in order to join from different client resources), although the service MAY choose to "lock down" nicknames and therefore deny entry to the user, including a <not-acceptable/> error. The service MUST NOT return an error to the user if his or her client sends the foregoing request after having already joined the room, but instead SHOULD reply as described above.<br />
<br />
<br />
<br />
If another user attempts to join the room with a nickname reserved by the first user, the service MUST deny entry to the second user and return a <conflict/> error as previously described.<br />
<br />
7.12 Requesting Voice<br />
<br />
<br />
<br />
It is not possible for a visitor to speak (i.e., send a message to all occupants) in a moderated room. To request voice, a visitor SHOULD send a <message/> stanza containing a data form to the room itself, where data form contains only a 'muc#role' field with a value of "participant".<br />
<br />
<br />
<br />
Example 71. Occupant Requests Voice<br />
<br />
<br />
<br />
<message from='hag66@shakespeare.lit/pda'<br />
<br />
to='darkcave@macbeth.shakespeare.lit'><br />
<br />
<x xmlns='jabber:x:data' type='submit'><br />
<br />
<field var='FORM_TYPE'><br />
<br />
<value>http://jabber.org/protocol/muc#request</value><br />
<br />
</field><br />
<br />
<field var='muc#role'<br />
<br />
type='text-single'<br />
<br />
label='Requested role'><br />
<br />
<value>participant</value><br />
<br />
</field><br />
<br />
</x><br />
<br />
</message><br />
<br />
<br />
<br />
<br />
<br />
The service then SHOULD forward the request to the room moderator(s) as described in the Approving Voice Requests section of this document.<br />
<br />
8. Moderator Use Cases<br />
<br />
<br />
<br />
A moderator has privileges to perform certain actions within the room (e.g., to change the roles of some occupants) but does not have rights to change persistent information about affiliations (which may be changed only by an admin or owner) or defining information about the room. Exactly which actions may be performed by a moderator is subject to configuration. However, for the purposes of the MUC framework, moderators are stipulated to have privileges to perform the following actions:<br />
<br />
<br />
<br />
1. discover an occupant's full JID in a semi-anonymous room (occurs by default as shown above)<br />
<br />
2. modify the subject<br />
<br />
3. kick a participant or visitor from the room<br />
<br />
4. grant or revoke voice in a moderated room<br />
<br />
5. modify the list of occupants who have voice in a moderated room<br />
<br />
<br />
<br />
These features shall be implemented with a request/response exchange using <iq/> elements that contain children qualified by the 'http://jabber.org/protocol/muc#admin' namespace. The examples below illustrate the protocol interactions to implement the desired functionality. (Except where explicitly noted below, any of the following administrative requests MUST be denied if the <user@host> of the 'from' address of the request does not match the bare JID portion of one of the moderators; in this case, the service MUST return a <forbidden/> error.)<br />
<br />
8.1 Modifying the Room Subject<br />
<br />
<br />
<br />
A common feature of multi-user chat rooms is the ability to change the subject within the room. By default, only users with a role of "moderator" SHOULD be allowed to change the subject in a room (although this SHOULD be configurable, with the result that a mere participant or even visitor may be allowed to change the subject if desired). The subject is changed by sending a message of type "groupchat" to the <room@service>, containing no body but a <subject/> that specifies the new subject:<br />
<br />
<br />
<br />
Example 72. Moderator Changes Subject<br />
<br />
<br />
<br />
<message<br />
<br />
from='wiccarocks@shakespeare.lit/laptop'<br />
<br />
to='darkcave@macbeth.shakespeare.lit'<br />
<br />
type='groupchat'><br />
<br />
<subject>Fire Burn and Cauldron Bubble!</subject><br />
<br />
</message><br />
<br />
<br />
<br />
<br />
<br />
If a MUC service receives such a message, it MUST reflect the message to all other occupants with a 'from' address equal to the room JID that corresponds to the sender of the subject change:<br />
<br />
<br />
<br />
Example 73. Service Informs All Occupants of Subject Change<br />
<br />
<br />
<br />
<message<br />
<br />
from='darkcave@macbeth.shakespeare.lit/secondwitch'<br />
<br />
to='crone1@shakespeare.lit/desktop'<br />
<br />
type='groupchat'><br />
<br />
<subject>Fire Burn and Cauldron Bubble!</subject><br />
<br />
</message><br />
<br />
.<br />
<br />
.<br />
<br />
.<br />
<br />
<br />
<br />
<br />
<br />
In addition, the room SHOULD include the last subject change in the discussion history sent when a new occupant joins the room.<br />
<br />
<br />
<br />
A MUC client that receives such a message MAY choose to display an in-room message, such as the following:<br />
<br />
<br />
<br />
Example 74. Client Displays Room Subject Change Message<br />
<br />
<br />
<br />
* secondwitch has changed the subject to: Fire Burn and Cauldron Bubble!<br />
<br />
<br />
<br />
<br />
<br />
If someone without appropriate privileges attempts to change the room subject, the service MUST return a message of type "error" specifying a <forbidden/> error condition:<br />
<br />
<br />
<br />
Example 75. Service Returns Error Related to Unauthorized Subject Change<br />
<br />
<br />
<br />
<message<br />
<br />
from='darkcave@macbeth.shakespeare.lit'<br />
<br />
to='hag66@shakespeare.lit/pda'<br />
<br />
type='error'><br />
<br />
<subject>Fire Burn and Cauldron Bubble!</subject><br />
<br />
<error code='403' type='auth'><br />
<br />
<forbidden xmlns='urn:ietf:params:xml:ns:xmpp-stanzas'/><br />
<br />
</error><br />
<br />
</message><br />
<br />
<br />
<br />
<br />
<br />
8.2 Kicking an Occupant<br />
<br />
<br />
<br />
A moderator has permissions kick certain kinds of occupants from a room (which occupants are "kickable" depends on service provisioning, room configuration, and the moderator's affiliation -- see below). The kick is normally performed based on the occupant's room nickname (though it MAY be based on the full JID) and is completed by setting the role of a participant or visitor to a value of "none".<br />
<br />
<br />
<br />
Example 76. Moderator Kicks Occupant<br />
<br />
<br />
<br />
<iq from='fluellen@shakespeare.lit/pda'<br />
<br />
id='kick1'<br />
<br />
to='harfleur@henryv.shakespeare.lit'<br />
<br />
type='set'><br />
<br />
<query xmlns='http://jabber.org/protocol/muc#admin'><br />
<br />
<item nick='pistol' role='none'><br />
<br />
<reason>Avaunt, you cullion!</reason><br />
<br />
</item><br />
<br />
</query><br />
<br />
</iq><br />
<br />
<br />
<br />
<br />
<br />
The service MUST remove the kicked occupant by sending a presence stanza of type "unavailable" to each kicked occupant, including status code 307 in the extended presence information, optionally along with the reason (if provided) and the bare JID of the user who initiated the kick.<br />
<br />
<br />
<br />
Example 77. Service Removes Kicked Occupant<br />
<br />
<br />
<br />
<presence<br />
<br />
from='harfleur@henryv.shakespeare.lit/pistol'<br />
<br />
to='pistol@shakespeare.lit/harfleur'<br />
<br />
type='unavailable'><br />
<br />
<x xmlns='http://jabber.org/protocol/muc#user'><br />
<br />
<item affiliation='none' role='none'><br />
<br />
<actor jid='fluellen@shakespeare.lit'/><br />
<br />
<reason>Avaunt, you cullion!</reason><br />
<br />
</item><br />
<br />
<status code='307'/><br />
<br />
</x><br />
<br />
</presence><br />
<br />
<br />
<br />
<br />
<br />
The inclusion of the status code assists clients in presenting their own notification messages (e.g., information appropriate to the user's locality). The optional inclusion of the reason and actor enable the kicked user to understand why he or she was kicked, and by whom if the kicked occupant would like to discuss the matter. [16]<br />
<br />
<br />
<br />
After removing the kicked occupant(s), the service MUST then inform the moderator of success:<br />
<br />
<br />
<br />
Example 78. Service Informs Moderator of Success<br />
<br />
<br />
<br />
<iq from='harfleur@henryv.shakespeare.lit'<br />
<br />
id='kick1'<br />
<br />
to='fluellen@shakespeare.lit/pda'<br />
<br />
type='result'/><br />
<br />
<br />
<br />
<br />
<br />
After informing the moderator, the service MUST then inform all of the remaining occupants that the kicked occupant is no longer in the room by sending presence stanzas of type "unavailable" from the individual's roomnick (<room@service/nick>) to all the remaining occupants (just as it does when occupants exit the room of their own volition), including the status code and optionally the reason and actor.<br />
<br />
<br />
<br />
Example 79. Service Informs Remaining Occupants<br />
<br />
<br />
<br />
<presence<br />
<br />
from='harfleur@henryv.shakespeare.lit/pistol'<br />
<br />
to='gower@shakespeare.lit/cell'<br />
<br />
type='unavailable'><br />
<br />
<x xmlns='http://jabber.org/protocol/muc#user'><br />
<br />
<item affiliation='none' role='none'/><br />
<br />
<status code='307'/><br />
<br />
</x><br />
<br />
</presence><br />
<br />
.<br />
<br />
.<br />
<br />
.<br />
<br />
<br />
<br />
<br />
<br />
A user cannot be kicked by a moderator with a lower affiliation. Therefore, if a moderator who is a participant attempts to kick an admin or a moderator who is a participant or admin attempts to kick an owner, the service MUST deny the request and return a <not-allowed/> error to the sender:<br />
<br />
<br />
<br />
Example 80. Service Returns Error on Attempt to Kick User With Higher Affiliation<br />
<br />
<br />
<br />
<iq from='darkcave@macbeth.shakespeare.lit'<br />
<br />
id='kicktest'<br />
<br />
to='wiccarocks@shakespeare.lit/laptop'<br />
<br />
type='error'><br />
<br />
<query xmlns='http://jabber.org/protocol/muc#admin'><br />
<br />
<item nick='firstwitch' role='none'><br />
<br />
<reason>Be gone!</reason><br />
<br />
</item><br />
<br />
</query><br />
<br />
<error code='405' type='cancel'><br />
<br />
<not-allowed xmlns='urn:ietf:params:xml:ns:xmpp-stanzas'/><br />
<br />
</error><br />
<br />
</iq><br />
<br />
<br />
<br />
<br />
<br />
If a moderator attempts to kick himself, the service MAY deny the request and return a <conflict/> error to the sender. (Although the act of kicking oneself may seem odd, it is common in IRC as a way of apologizing for one's actions in the room.)<br />
<br />
8.3 Granting Voice to a Visitor<br />
<br />
<br />
<br />
In a moderated room, a moderator may want to manage who does and does not have "voice" in the room (i.e., the ability to send messages to all occupants). Voice is granted based on the visitor's room nickname, which the service will convert into the visitor's full JID internally. The moderator grants voice to a visitor by changing the visitor's role to "participant" (the <reason/> element is optional):<br />
<br />
<br />
<br />
Example 81. Moderator Grants Voice to a Visitor<br />
<br />
<br />
<br />
<iq from='crone1@shakespeare.lit/desktop'<br />
<br />
id='voice1'<br />
<br />
to='darkcave@macbeth.shakespeare.lit'<br />
<br />
type='set'><br />
<br />
<query xmlns='http://jabber.org/protocol/muc#admin'><br />
<br />
<item nick='thirdwitch'<br />
<br />
role='participant'><br />
<br />
<reason>A worthy witch indeed!</reason><br />
<br />
</item><br />
<br />
</query><br />
<br />
</iq><br />
<br />
<br />
<br />
<br />
<br />
The service MUST then inform the moderator of success:<br />
<br />
<br />
<br />
Example 82. Service Informs Moderator of Success<br />
<br />
<br />
<br />
<iq from='darkcave@macbeth.shakespeare.lit'<br />
<br />
id='voice1'<br />
<br />
to='crone1@shakespeare.lit/desktop'<br />
<br />
type='result'/><br />
<br />
<br />
<br />
<br />
<br />
The service MUST then send updated presence from this individual's <room@service/nick> to all occupants, indicating the addition of voice privileges by including an <x/> element qualified by the 'http://jabber.org/protocol/muc#user' namespace and containing an <item/> child with the 'role' attribute set to a value of "participant".<br />
<br />
<br />
<br />
Example 83. Service Sends Notice of Voice to All Occupants<br />
<br />
<br />
<br />
<presence<br />
<br />
from='darkcave@macbeth.shakespeare.lit/thirdwitch'<br />
<br />
to='crone1@shakespeare.lit/desktop'><br />
<br />
<x xmlns='http://jabber.org/protocol/muc#user'><br />
<br />
<item affiliation='member'<br />
<br />
nick='thirdwitch'<br />
<br />
role='participant'><br />
<br />
<reason>A worthy witch indeed!</reason><br />
<br />
</item><br />
<br />
</x><br />
<br />
</presence><br />
<br />
.<br />
<br />
.<br />
<br />
.<br />
<br />
<br />
<br />
<br />
<br />
8.4 Revoking Voice from a Participant<br />
<br />
<br />
<br />
In a moderated room, a moderator may want to revoke a participant's privileges to speak. The moderator can revoke voice from a participant by changing the participant's role to "visitor":<br />
<br />
<br />
<br />
Example 84. Moderator Revokes Voice from a Participant<br />
<br />
<br />
<br />
<iq from='crone1@shakespeare.lit/desktop'<br />
<br />
id='voice2'<br />
<br />
to='darkcave@macbeth.shakespeare.lit'<br />
<br />
type='set'><br />
<br />
<query xmlns='http://jabber.org/protocol/muc#admin'><br />
<br />
<item nick='thirdwitch'<br />
<br />
role='visitor'/><br />
<br />
</query><br />
<br />
</iq><br />
<br />
<br />
<br />
<br />
<br />
The service MUST then inform the moderator of success:<br />
<br />
<br />
<br />
Example 85. Service Informs Moderator of Success<br />
<br />
<br />
<br />
<iq from='darkcave@macbeth.shakespeare.lit'<br />
<br />
id='voice2'<br />
<br />
to='crone1@shakespeare.lit/desktop'<br />
<br />
type='result'/><br />
<br />
<br />
<br />
<br />
<br />
The service MUST then send updated presence from this individual to all occupants, indicating the removal of voice privileges by sending a presence element that contains an <x/> element qualified by the 'http://jabber.org/protocol/muc#user' namespace and containing an <item/> child with the 'role' attribute set to a value of "visitor".<br />
<br />
<br />
<br />
Example 86. Service Notes Loss of Voice<br />
<br />
<br />
<br />
<presence<br />
<br />
from='darkcave@macbeth.shakespeare.lit/thirdwitch'<br />
<br />
to='crone1@shakespeare.lit/desktop'><br />
<br />
<x xmlns='http://jabber.org/protocol/muc#user'><br />
<br />
<item affiliation='member'<br />
<br />
jid='hag66@shakespeare.lit/pda'<br />
<br />
role='visitor'/><br />
<br />
</x><br />
<br />
</presence><br />
<br />
.<br />
<br />
.<br />
<br />
.<br />
<br />
<br />
<br />
<br />
<br />
A moderator MUST NOT be able to revoke voice from a user whose affiliation is at or above the moderator's level. In addition, a service MUST NOT allow the voice privileges of an admin or owner to be removed by anyone. If a moderator attempts to revoke voice privileges from such a user, the service MUST deny the request and return a <not-allowed/> error to the sender along with the offending item(s):<br />
<br />
<br />
<br />
Example 87. Service Returns Error on Attempt to Revoke Voice from an Admin, Owner, or User with a Higher Affiliation<br />
<br />
<br />
<br />
<iq from='darkcave@macbeth.shakespeare.lit'<br />
<br />
id='voicetest'<br />
<br />
to='crone1@shakespeare.lit/desktop'<br />
<br />
type='error'><br />
<br />
<query xmlns='http://jabber.org/protocol/muc#admin'><br />
<br />
<item nick='secondwitch' role='visitor'/><br />
<br />
</query><br />
<br />
<error code='405' type='cancel'><br />
<br />
<not-allowed xmlns='urn:ietf:params:xml:ns:xmpp-stanzas'/><br />
<br />
</error><br />
<br />
</iq><br />
<br />
<br />
<br />
<br />
<br />
8.5 Modifying the Voice List<br />
<br />
<br />
<br />
A moderator in a moderated room may want to modify the voice list. To do so, the moderator first requests the voice list by querying the room for all occupants with a role of 'participant'.<br />
<br />
<br />
<br />
Example 88. Moderator Requests Voice List<br />
<br />
<br />
<br />
<iq from='bard@shakespeare.lit/globe'<br />
<br />
id='voice3'<br />
<br />
to='goodfolk@chat.shakespeare.lit'<br />
<br />
type='get'><br />
<br />
<query xmlns='http://jabber.org/protocol/muc#admin'><br />
<br />
<item role='participant'/><br />
<br />
</query><br />
<br />
</iq><br />
<br />
<br />
<br />
<br />
<br />
The service MUST then return the voice list to the moderator; each item MUST include the 'nick' and 'role' attributes and SHOULD include the 'affiliation' and 'jid' attributes:<br />
<br />
<br />
<br />
Example 89. Service Sends Voice List to Moderator<br />
<br />
<br />
<br />
<iq from='goodfolk@chat.shakespeare.lit'<br />
<br />
id='voice3'<br />
<br />
to='bard@shakespeare.lit/globe'<br />
<br />
type='result'><br />
<br />
<query xmlns='http://jabber.org/protocol/muc#admin'><br />
<br />
<item affiliation='none'<br />
<br />
jid='polonius@hamlet/castle'<br />
<br />
nick='Polo'<br />
<br />
role='participant'/><br />
<br />
<item affiliation='none'<br />
<br />
jid='horatio@hamlet/castle'<br />
<br />
nick='horotoro'<br />
<br />
role='participant'/><br />
<br />
<item affiliation='member'<br />
<br />
jid='hecate@shakespeare.lit/broom'<br />
<br />
nick='Hecate'<br />
<br />
role='participant'/><br />
<br />
</query><br />
<br />
</iq><br />
<br />
<br />
<br />
<br />
<br />
The moderator MAY then modify the voice list. In order to do so, the moderator MUST send the changed items (i.e., only the "delta") back to the service; each item MUST include the 'nick' attribute and 'role' attribute (normally set to a value of "participant" or "visitor") but SHOULD NOT include the 'jid' attribute and MUST NOT include the 'affiliation' attribute (which is used to manage affiliations such as owner rather than the participant role):<br />
<br />
<br />
<br />
Example 90. Moderator Sends Modified Voice List to Service<br />
<br />
<br />
<br />
<iq from='bard@shakespeare.lit/globe'<br />
<br />
id='voice4'<br />
<br />
to='goodfolk@chat.shakespeare.lit'<br />
<br />
type='set'><br />
<br />
<query xmlns='http://jabber.org/protocol/muc#admin'><br />
<br />
<item nick='Hecate'<br />
<br />
role='visitor'/><br />
<br />
<item nick='rosencrantz'<br />
<br />
role='participant'><br />
<br />
<reason>A worthy fellow.</reason><br />
<br />
</item><br />
<br />
<item nick='guildenstern'<br />
<br />
role='participant'><br />
<br />
<reason>A worthy fellow.</reason><br />
<br />
</item><br />
<br />
</query><br />
<br />
</iq><br />
<br />
<br />
<br />
<br />
<br />
The service MUST then inform the moderator of success:<br />
<br />
<br />
<br />
Example 91. Service Informs Moderator of Success<br />
<br />
<br />
<br />
<iq from='goodfolk@chat.shakespeare.lit'<br />
<br />
id='voice1'<br />
<br />
to='bard@shakespeare.lit/globe'<br />
<br />
type='result'/><br />
<br />
<br />
<br />
<br />
<br />
The service MUST then send updated presence for any affected individuals to all occupants, indicating the change in voice privileges by sending the appropriate extended presence stanzas as described in the foregoing use cases.<br />
<br />
<br />
<br />
As noted, voice privileges cannot be revoked from a room owner or room admin, nor from any user with a higher affiliation than the moderator making the request. If a room admin attempts to revoke voice privileges from such a user by modifying the voice list, the service MUST deny the request and return a <not-allowed/> error to the sender:<br />
<br />
<br />
<br />
Example 92. Service Returns Error on Attempt to Revoke Voice from an Admin, Owner, or User with a Higher Affiliation<br />
<br />
<br />
<br />
<iq from='goodfolk@chat.shakespeare.lit'<br />
<br />
id='voicetest'<br />
<br />
to='bard@shakespeare.lit/globe'<br />
<br />
type='error'><br />
<br />
<query xmlns='http://jabber.org/protocol/muc#admin'><br />
<br />
<item jid='hecate@shakespeare.lit'<br />
<br />
nick='Hecate'<br />
<br />
role='visitor'/><br />
<br />
</query><br />
<br />
<error code='405' type='cancel'><br />
<br />
<not-allowed xmlns='urn:ietf:params:xml:ns:xmpp-stanzas'/><br />
<br />
</error><br />
<br />
</iq><br />
<br />
<br />
<br />
<br />
<br />
8.6 Approving Voice Requests<br />
<br />
<br />
<br />
As noted in the Requesting Voice section of this document, when a service receives a request for voice from an occupant it SHOULD forward that request to the room moderator(s). To do so, the service SHOULD send a <message/> stanza to the room moderator(s), where the <message/> stanza contains a data form asking for approval or denial of the request, as shown below.<br />
<br />
<br />
<br />
Example 93. Voice Request Approval Form<br />
<br />
<br />
<br />
<message from='darkcave@macbeth.shakespeare.lit'<br />
<br />
id='approve'<br />
<br />
to='crone1@shakespeare.lit/pda'><br />
<br />
<x xmlns='jabber:x:data' type='form'><br />
<br />
<title>Voice request</title><br />
<br />
<instructions><br />
<br />
To approve this request for voice, select <br />
<br />
the &quot;Grant voice to this person?&quot;<br />
<br />
checkbox and click OK. To skip this request, <br />
<br />
click the cancel button.<br />
<br />
</instructions><br />
<br />
<field var='FORM_TYPE' type='hidden'><br />
<br />
<value>http://jabber.org/protocol/muc#request</value><br />
<br />
</field><br />
<br />
<field var='muc#role'<br />
<br />
type='text-single'<br />
<br />
label='Requested role'><br />
<br />
<value>participant</value><br />
<br />
</field><br />
<br />
<field var='muc#jid'<br />
<br />
type='text-single'<br />
<br />
label='User ID'><br />
<br />
<value>hag66@shakespeare.lit/pda</value><br />
<br />
</field><br />
<br />
<field var='muc#roomnick'<br />
<br />
type='text-single'<br />
<br />
label='Room Nickname'><br />
<br />
<value>thirdwitch</value><br />
<br />
</field><br />
<br />
<field var='muc#request_allow'<br />
<br />
type='boolean'<br />
<br />
label='Grant voice to this person?'><br />
<br />
<value>false</value><br />
<br />
</field><br />
<br />
</x><br />
<br />
</message><br />
<br />
<br />
<br />
<br />
<br />
In order to approve the request, a moderator shall submit the form:<br />
<br />
<br />
<br />
Example 94. Voice Request Approval Submission<br />
<br />
<br />
<br />
<message from='crone1@shakespeare.lit/pda'<br />
<br />
id='approve'<br />
<br />
to='darkcave@macbeth.shakespeare.lit'><br />
<br />
<x xmlns='jabber:x:data' type='submit'><br />
<br />
<field var='FORM_TYPE' type='hidden'><br />
<br />
<value>http://jabber.org/protocol/muc#request</value><br />
<br />
</field><br />
<br />
<field var='muc#role'><br />
<br />
<value>participant</value><br />
<br />
</field><br />
<br />
<field var='muc#jid'><br />
<br />
<value>hag66@shakespeare.lit/pda</value><br />
<br />
</field><br />
<br />
<field var='muc#roomnick'><br />
<br />
<value>thirdwitch</value><br />
<br />
</field><br />
<br />
<field var='muc#request_allow'><br />
<br />
<value>true</value><br />
<br />
</field><br />
<br />
</x><br />
<br />
</message><br />
<br />
<br />
<br />
<br />
<br />
If a moderator approves the voice request, the service shall grant voice to the occupant and send a presence update as described in the Granting Voice to a Visitor section of this document.<br />
<br />
9. Admin Use Cases<br />
<br />
<br />
<br />
A room administrator has privileges to modify persistent information about user affiliations (e.g., by banning users) and to grant and revoke moderator privileges, but does not have rights to change the defining features of the room, which are the sole province of the room owner(s). Exactly which actions may be performed by a room admin will be subject to configuration. However, for the purposes of the MUC framework, room admins are stipulated to at a minimum have privileges to perform the following actions:<br />
<br />
<br />
<br />
1. ban a user from the room<br />
<br />
2. modify the list of users who are banned from the room<br />
<br />
3. grant or revoke membership<br />
<br />
4. modify the member list<br />
<br />
5. grant or revoke moderator privileges<br />
<br />
6. modify the list of moderators<br />
<br />
<br />
<br />
These features shall be implemented with a request/response exchange using <iq/> elements that contain children qualified by the 'http://jabber.org/protocol/muc#admin' namespace. The examples below illustrate the protocol interactions that implement the desired functionality. (Except where explicitly noted below, any of the following administrative requests MUST be denied if the <user@host> of the 'from' address of the request does not match the bare JID of one of the room admins; in this case, the service MUST return a <forbidden/> error.)<br />
<br />
9.1 Banning a User<br />
<br />
<br />
<br />
An admin or owner can ban one or more users from a room. The ban MUST be performed based on the occupant's bare JID. In order to ban a user, an admin MUST change the user's affiliation to "outcast".<br />
<br />
<br />
<br />
Example 95. Admin Bans User<br />
<br />
<br />
<br />
<iq from='kinghenryv@shakespeare.lit/throne'<br />
<br />
id='ban1'<br />
<br />
to='southampton@henryv.shakespeare.lit'<br />
<br />
type='set'><br />
<br />
<query xmlns='http://jabber.org/protocol/muc#admin'><br />
<br />
<item affiliation='outcast'<br />
<br />
jid='earlofcambridge@shakespeare.lit'><br />
<br />
<reason>Treason</reason><br />
<br />
</item><br />
<br />
</query><br />
<br />
</iq><br />
<br />
<br />
<br />
<br />
<br />
The service MUST add that bare JID to the ban list, SHOULD remove the outcast's nickname from the list of registered nicknames, and MUST inform the admin or owner of success:<br />
<br />
<br />
<br />
Example 96. Service Informs Admin or Owner of Success<br />
<br />
<br />
<br />
<iq from='southampton@henryv.shakespeare.lit'<br />
<br />
id='ban1'<br />
<br />
to='kinghenryv@shakespeare.lit/throne'<br />
<br />
type='result'/><br />
<br />
<br />
<br />
<br />
<br />
The service MUST also remove any banned users who are in the room by sending a presence stanza of type "unavailable" to each banned occupant, including status code 301 in the extended presence information, optionally along with the reason (if provided) and the bare JID of the user who initiated the ban.<br />
<br />
<br />
<br />
Example 97. Service Removes Banned User<br />
<br />
<br />
<br />
<presence<br />
<br />
from='southampton@henryv.shakespeare.lit/cambridge'<br />
<br />
to='earlofcambridge@shakespeare.lit/stabber'<br />
<br />
type='unavailable'><br />
<br />
<x xmlns='http://jabber.org/protocol/muc#user'><br />
<br />
<item affiliation='outcast' role='none'><br />
<br />
<actor jid='kinghenryv@shakespeare.lit'/><br />
<br />
<reason>Treason</reason><br />
<br />
</item><br />
<br />
<status code='301'/><br />
<br />
</x><br />
<br />
</presence><br />
<br />
<br />
<br />
<br />
<br />
The inclusion of the status code assists clients in presenting their own notification messages (e.g., information appropriate to the user's locality). The optional inclusion of the reason and actor enable the banned user to understand why he or she was banned, and by whom if the banned user would like to discuss the matter.<br />
<br />
<br />
<br />
The service MUST then inform all of the remaining occupants that the banned user is no longer in the room by sending presence stanzas of type "unavailable" from the banned user to all remaining occupants (just as it does when occupants exit the room of their own volition), including the status code and optionally the reason and actor:<br />
<br />
<br />
<br />
Example 98. Service Informs Remaining Occupants<br />
<br />
<br />
<br />
<presence<br />
<br />
type='unavailable'<br />
<br />
from='southampton@henryv.shakespeare.lit/cambridge'<br />
<br />
to='exeter@shakespeare.lit/pda'><br />
<br />
<x xmlns='http://jabber.org/protocol/muc#user'><br />
<br />
<item affiliation='outcast'<br />
<br />
jid='earlofcambridge@shakespeare.lit/stabber'<br />
<br />
role='none'/><br />
<br />
<status code='301'/><br />
<br />
</x><br />
<br />
</presence><br />
<br />
.<br />
<br />
.<br />
<br />
.<br />
<br />
<br />
<br />
<br />
<br />
As with Kicking an Occupant, a user cannot be banned by an admin with a lower affiliation. Therefore, if an admin attempts to ban an owner, the service MUST deny the request and return a <not-allowed/> error to the sender:<br />
<br />
<br />
<br />
Example 99. Service Returns Error on Attempt to Ban User With Higher Affiliation<br />
<br />
<br />
<br />
<iq from='kinghenryv@shakespeare.lit/throne'<br />
<br />
id='ban1'<br />
<br />
to='southampton@henryv.shakespeare.lit'<br />
<br />
type='set'><br />
<br />
<query xmlns='http://jabber.org/protocol/muc#admin'><br />
<br />
<item affiliation='outcast'<br />
<br />
jid='earlofcambridge@shakespeare.lit'><br />
<br />
<reason>Treason</reason><br />
<br />
</item><br />
<br />
</query><br />
<br />
<error code='405' type='cancel'><br />
<br />
<not-allowed xmlns='urn:ietf:params:xml:ns:xmpp-stanzas'/><br />
<br />
</error><br />
<br />
</iq><br />
<br />
<br />
<br />
<br />
<br />
If an admin or owner attempts to ban himself, the service MUST deny the request and return a <conflict/> error to the sender. (Note: This is different from the recommended service behavior on kicking oneself, which a service may allow.)<br />
<br />
9.2 Modifying the Ban List<br />
<br />
<br />
<br />
A room admin may want to modify the ban list. Note: The ban list is always based on a user's bare JID, although a nick (perhaps the last room nickname associated with that JID) MAY be included for convenience. To modify the list of banned JIDs, the admin first requests the ban list by querying the room for all users with an affiliation of 'outcast'.<br />
<br />
<br />
<br />
Example 100. Admin Requests Ban List<br />
<br />
<br />
<br />
<iq from='kinghenryv@shakespeare.lit/throne'<br />
<br />
id='ban2'<br />
<br />
to='southampton@henryv.shakespeare.lit'<br />
<br />
type='get'><br />
<br />
<query xmlns='http://jabber.org/protocol/muc#admin'><br />
<br />
<item affiliation='outcast'/><br />
<br />
</query><br />
<br />
</iq><br />
<br />
<br />
<br />
<br />
<br />
The service MUST then return the list of banned users to the admin; each item MUST include the 'affiliation' and 'jid' attributes but SHOULD NOT include the 'nick' and 'role' attributes:<br />
<br />
<br />
<br />
Example 101. Service Sends Ban List to Admin<br />
<br />
<br />
<br />
<iq from='southampton@henryv.shakespeare.lit'<br />
<br />
id='ban2'<br />
<br />
to='kinghenryv@shakespeare.lit/throne'<br />
<br />
type='result'><br />
<br />
<query xmlns='http://jabber.org/protocol/muc#admin'><br />
<br />
<item affiliation='outcast'<br />
<br />
jid='earlofcambridge@shakespeare.lit'><br />
<br />
<reason>Treason</reason><br />
<br />
</item><br />
<br />
</query><br />
<br />
</iq><br />
<br />
<br />
<br />
<br />
<br />
The admin MAY then modify the ban list. In order to do so, the admin MUST send the changed items (i.e., only the "delta") back to the service; each item MUST include the 'affiliation' attribute (normally set to a value of "outcast" to ban or "none" to remove ban) and 'jid' attribute but SHOULD NOT include the 'nick' attribute and MUST NOT include the 'role' attribute (which is used to manage roles such as participant rather than the outcast affiliation); in addition, the reason and actor elements are OPTIONAL:<br />
<br />
<br />
<br />
Example 102. Admin Sends Modified Ban List to Service<br />
<br />
<br />
<br />
<iq from='kinghenryv@shakespeare.lit/throne'<br />
<br />
id='ban3'<br />
<br />
to='southampton@henryv.shakespeare.lit'<br />
<br />
type='set'><br />
<br />
<query xmlns='http://jabber.org/protocol/muc#admin'><br />
<br />
<item affiliation='outcast'<br />
<br />
jid='earlofcambridge@shakespeare.lit'><br />
<br />
<reason>Treason</reason><br />
<br />
</item><br />
<br />
<item affiliation='outcast'><br />
<br />
jid='lordscroop@shakespeare.lit'><br />
<br />
<reason>Treason</reason><br />
<br />
</item><br />
<br />
<item affiliation='outcast'<br />
<br />
jid='sirthomasgrey@shakespeare.lit'><br />
<br />
<reason>Treason</reason><br />
<br />
</item><br />
<br />
</query><br />
<br />
</iq><br />
<br />
<br />
<br />
<br />
<br />
After updating the ban list, the service MUST inform the admin of success:<br />
<br />
<br />
<br />
Example 103. Service Informs Admin of Success<br />
<br />
<br />
<br />
<iq from='southampton@henryv.shakespeare.lit'<br />
<br />
id='ban3'<br />
<br />
to='kinghenryv@shakespeare.lit/throne'<br />
<br />
type='result'/><br />
<br />
<br />
<br />
<br />
<br />
The service MUST then remove the affected occupants (if they are in the room) and send updated presence (including the appropriate status code) from them to all the remaining occupants as described in the "Banning a User" use case. (The service SHOULD also remove each banned user's reserved nickname from the list of reserved roomnicks, if appropriate.)<br />
<br />
<br />
<br />
When an entity is banned from a room, an implementation SHOULD match JIDs in the following order (these matching rules are the same as those defined for privacy lists in RFC 3921):<br />
<br />
<br />
<br />
1. <user@domain/resource> (only that resource matches)<br />
<br />
2. <user@domain> (any resource matches)<br />
<br />
3. <domain/resource> (only that resource matches)<br />
<br />
4. <domain> (the domain itself matches, as does any user@domain, domain/resource, or address containing a subdomain)<br />
<br />
<br />
<br />
Some administrators may wish to ban all users associated with a specific domain from all rooms hosted by a MUC service. Such functionality is a service-level feature and is therefore out of scope for this document (but see Service Administration [17]).<br />
<br />
9.3 Granting Membership<br />
<br />
<br />
<br />
An admin can grant membership to a user; this is done by changing the user's affiliation to "member" (normally based on nick if the user is in the room, or on bare JID if not; in either case, if the nick is provided, that nick becomes the user's default nick in the room if that functionality is supported by the implementation):<br />
<br />
<br />
<br />
Example 104. Admin Grants Membership<br />
<br />
<br />
<br />
<iq from='crone1@shakespeare.lit/desktop'<br />
<br />
id='member1'<br />
<br />
to='darkcave@macbeth.shakespeare.lit'<br />
<br />
type='set'><br />
<br />
<query xmlns='http://jabber.org/protocol/muc#admin'><br />
<br />
<item affiliation='member'<br />
<br />
jid='hag66@shakespeare.lit'/><br />
<br />
</query><br />
<br />
</iq><br />
<br />
<br />
<br />
<br />
<br />
The service MUST add the user to the member list and then inform the admin of success:<br />
<br />
<br />
<br />
Example 105. Service Informs Admin of Success<br />
<br />
<br />
<br />
<iq from='darkcave@macbeth.shakespeare.lit'<br />
<br />
id='member1'<br />
<br />
to='crone1@shakespeare.lit/desktop'<br />
<br />
type='result'/><br />
<br />
<br />
<br />
<br />
<br />
If the user is in the room, the service MUST then send updated presence from this individual to all occupants, indicating the granting of membership by including an <x/> element qualified by the 'http://jabber.org/protocol/muc#user' namespace and containing an <item/> child with the 'affiliation' attribute set to a value of "member".<br />
<br />
<br />
<br />
Example 106. Service Sends Notice of Membership to All Occupants<br />
<br />
<br />
<br />
<presence<br />
<br />
from='darkcave@macbeth.shakespeare.lit/thirdwitch'<br />
<br />
to='crone1@shakespeare.lit/desktop'><br />
<br />
<x xmlns='http://jabber.org/protocol/muc#user'><br />
<br />
<item affiliation='member'<br />
<br />
jid='hag66@shakespeare.lit/pda'<br />
<br />
role='participant'/><br />
<br />
</x><br />
<br />
</presence><br />
<br />
.<br />
<br />
.<br />
<br />
.<br />
<br />
<br />
<br />
<br />
<br />
9.4 Revoking Membership<br />
<br />
<br />
<br />
An admin may want to revoke a user's membership; this is done by changing the user's affiliation to "none":<br />
<br />
<br />
<br />
Example 107. Admin Revokes Membership<br />
<br />
<br />
<br />
<iq from='crone1@shakespeare.lit/desktop'<br />
<br />
id='member2'<br />
<br />
to='darkcave@macbeth.shakespeare.lit'<br />
<br />
type='set'><br />
<br />
<query xmlns='http://jabber.org/protocol/muc#admin'><br />
<br />
<item affiliation='none'<br />
<br />
jid='hag66@shakespeare.lit'/><br />
<br />
</query><br />
<br />
</iq><br />
<br />
<br />
<br />
<br />
<br />
The service MUST remove the user from the member list and then inform the moderator of success:<br />
<br />
<br />
<br />
Example 108. Service Informs Moderator of Success<br />
<br />
<br />
<br />
<iq from='darkcave@macbeth.shakespeare.lit'<br />
<br />
id='member2'<br />
<br />
to='crone1@shakespeare.lit/desktop'<br />
<br />
type='result'/><br />
<br />
<br />
<br />
<br />
<br />
The service MUST then send updated presence from this individual to all occupants, indicating the loss of membership by sending a presence element that contains an <x/> element qualified by the 'http://jabber.org/protocol/muc#user' namespace and containing an <item/> child with the 'affiliation' attribute set to a value of "none".<br />
<br />
<br />
<br />
Example 109. Service Notes Loss of Membership<br />
<br />
<br />
<br />
<presence<br />
<br />
from='darkcave@macbeth.shakespeare.lit/thirdwitch'<br />
<br />
to='crone1@shakespeare.lit/desktop'><br />
<br />
<x xmlns='http://jabber.org/protocol/muc#user'><br />
<br />
<item affiliation='none'<br />
<br />
jid='hag66@shakespeare.lit/pda'<br />
<br />
role='participant'/><br />
<br />
</x><br />
<br />
</presence><br />
<br />
.<br />
<br />
.<br />
<br />
.<br />
<br />
<br />
<br />
<br />
<br />
If the room is members-only, the service MUST remove the user from the room, including a status code of 321 to indicate that the user was removed because of an affiliation change, and inform all remaining occupants:<br />
<br />
<br />
<br />
Example 110. Service Removes Non-Member<br />
<br />
<br />
<br />
<presence<br />
<br />
from='darkcave@macbeth.shakespeare.lit/thirdwitch'<br />
<br />
to='crone1@shakespeare.lit/desktop'><br />
<br />
type='unavailable'><br />
<br />
<x xmlns='http://jabber.org/protocol/muc#user'><br />
<br />
<item affiliation='none' role='none'><br />
<br />
<actor jid='bard@shakespeare.lit'/><br />
<br />
</item><br />
<br />
<status code='321'/><br />
<br />
</x><br />
<br />
</presence><br />
<br />
<br />
<br />
<presence<br />
<br />
from='darkcave@macbeth.shakespeare.lit/thirdwitch'<br />
<br />
to='crone1@shakespeare.lit/desktop'><br />
<br />
type='unavailable'><br />
<br />
<x xmlns='http://jabber.org/protocol/muc#user'><br />
<br />
<item affiliation='none' role='none'/><br />
<br />
<status code='321'/><br />
<br />
</x><br />
<br />
</presence><br />
<br />
.<br />
<br />
.<br />
<br />
.<br />
<br />
<br />
<br />
<br />
<br />
9.5 Modifying the Member List<br />
<br />
<br />
<br />
In the context of a members-only room, the member list is essentially a "whitelist" of people who are allowed to enter the room. Anyone who is not a member is effectively banned from entering the room, even if their affiliation is not "outcast".<br />
<br />
<br />
<br />
In the context of an open room, the member list is simply a list of users (bare JID and reserved nick) who are registered with the room. Such users may appear in a room roster, have their room nickname reserved, be returned in search results or FAQ queries, and the like.<br />
<br />
<br />
<br />
It is RECOMMENDED that only room admins have the privilege to modify the member list in members-only rooms. To do so, the admin first requests the member list by querying the room for all users with an affiliation of "member":<br />
<br />
<br />
<br />
Example 111. Admin Requests Member List<br />
<br />
<br />
<br />
<iq from='crone1@shakespeare.lit/desktop'<br />
<br />
id='member3'<br />
<br />
to='darkcave@macbeth.shakespeare.lit'<br />
<br />
type='get'><br />
<br />
<query xmlns='http://jabber.org/protocol/muc#admin'><br />
<br />
<item affiliation='member'/><br />
<br />
</query><br />
<br />
</iq><br />
<br />
<br />
<br />
<br />
<br />
(A service SHOULD also return the member list to any occupant in a members-only room; i.e., it SHOULD NOT generate a <forbidden/> error when a member in the room requests the member list. This functionality may assist clients in showing all the existing members even if some of them are not in the room, e.g. to help a member determine if another user should be invited.)<br />
<br />
<br />
<br />
The service MUST then return the full member list to the admin qualified by the 'http://jabber.org/protocol/muc#admin' namespace; each item MUST include the 'affiliation' and 'jid' attributes and MAY include the 'nick' and 'role' attributes for each members that is currently an occupant.<br />
<br />
<br />
<br />
Example 112. Service Sends Member List to Admin<br />
<br />
<br />
<br />
<iq from='darkcave@macbeth.shakespeare.lit'<br />
<br />
id='member3'<br />
<br />
to='crone1@shakespeare.lit/desktop'<br />
<br />
type='result'><br />
<br />
<query xmlns='http://jabber.org/protocol/muc#admin'><br />
<br />
<item affiliation='member'<br />
<br />
jid='hag66@shakespeare.lit'<br />
<br />
nick='thirdwitch'<br />
<br />
role='participant'/><br />
<br />
</query><br />
<br />
</iq><br />
<br />
<br />
<br />
<br />
<br />
The admin MAY then modify the member list. In order to do so, the admin MUST send the changed items (i.e., only the "delta") to the service; each item MUST include the 'affiliation' attribute (normally set to a value of "member" or "none") and 'jid' attribute but SHOULD NOT include the 'nick' attribute and MUST NOT include the 'role' attribute (which is used to manage roles such as participant rather than the member affiliation):<br />
<br />
<br />
<br />
Example 113. Admin Sends Modified Member List to Service<br />
<br />
<br />
<br />
<iq from='crone1@shakespeare.lit/desktop'<br />
<br />
id='member4'<br />
<br />
to='darkcave@macbeth.shakespeare.lit'<br />
<br />
type='set'><br />
<br />
<query xmlns='http://jabber.org/protocol/muc#admin'><br />
<br />
<item affiliation='none'<br />
<br />
jid='hag66@shakespeare.lit'/><br />
<br />
<item affiliation='member'<br />
<br />
jid='hecate@shakespeare.lit'/><br />
<br />
</query><br />
<br />
</iq><br />
<br />
<br />
<br />
<br />
<br />
The service MUST modify the member list and then inform the moderator of success:<br />
<br />
<br />
<br />
Example 114. Service Informs Moderator of Success<br />
<br />
<br />
<br />
<iq from='darkcave@macbeth.shakespeare.lit'<br />
<br />
id='member4'<br />
<br />
to='crone1@shakespeare.lit/desktop'<br />
<br />
type='result'/><br />
<br />
<br />
<br />
<br />
<br />
The service MUST change the affiliation of any affected user. If the user has been removed from the member list, the service MUST change the user's affiliation from "member" to "none". If the user has been added to the member list, the service MUST change the user's affiliation to "member".<br />
<br />
<br />
<br />
If a removed member is currently in a members-only room, the service SHOULD kick the occupant by changing the removed member's role to "none" and send appropriate presence to the removed member as previously described. No matter whether the removed member was in or out of a members-only room, the service MUST subsequently refuse entry to the user.<br />
<br />
<br />
<br />
For all room types, the service MUST send updated presence from this individual to all occupants, indicating the change in affiliation by including an <x/> element qualified by the 'http://jabber.org/protocol/muc#user' namespace and containing an <item/> child with the 'affiliation' attribute set to a value of "none".<br />
<br />
<br />
<br />
Example 115. Service Sends Notice of Loss of Membership to All Occupants<br />
<br />
<br />
<br />
<presence<br />
<br />
from='darkcave@macbeth.shakespeare.lit/thirdwitch'<br />
<br />
to='crone1@shakespeare.lit/desktop'><br />
<br />
<x xmlns='http://jabber.org/protocol/muc#user'><br />
<br />
<item affiliation='none'<br />
<br />
jid='hag66@shakespeare.lit/pda'<br />
<br />
role='participant'/><br />
<br />
</x><br />
<br />
</presence><br />
<br />
.<br />
<br />
.<br />
<br />
.<br />
<br />
<br />
<br />
<br />
<br />
In addition, the service SHOULD send an invitation to any user who has been added to the member list of a members-only room if the user is not currently affiliated with the room, for example as an admin or owner (such a user would by definition not be in the room; note also that this example includes a password but not a reason -- both child elements are OPTIONAL):<br />
<br />
<br />
<br />
Example 116. Room Sends Invitation to New Member<br />
<br />
<br />
<br />
<message<br />
<br />
from='darkcave@macbeth.shakespeare.lit'<br />
<br />
to='hecate@shakespeare.lit'><br />
<br />
<x xmlns='http://jabber.org/protocol/muc#user'><br />
<br />
<invite from='bard@shakespeare.lit'/><br />
<br />
<password>cauldronburn</password><br />
<br />
</x><br />
<br />
</message><br />
<br />
<br />
<br />
<br />
<br />
While only admins and owners SHOULD be allowed to modify the member list, an implementation MAY provide a configuration option that opens invitation privileges to any member of a members-only room. In such a situation, any invitation sent SHOULD automatically trigger the addition of the invitee to the member list. However, if invitation privileges are restricted to admins and a mere member attempts to a send an invitation, the service MUST deny the invitation request and return a <forbidden/> error to the sender:<br />
<br />
<br />
<br />
Example 117. Service Returns Error on Attempt by Mere Member to Invite Others to a Members-Only Room<br />
<br />
<br />
<br />
<message<br />
<br />
from='darkcave@macbeth.shakespeare.lit'<br />
<br />
to='hag66@shakespeare.lit/pda'<br />
<br />
type='error'><br />
<br />
<x xmlns='http://jabber.org/protocol/muc#user'><br />
<br />
<invite to='hecate@shakespeare.lit'><br />
<br />
<reason><br />
<br />
Hey Hecate, this is the place for all good witches!<br />
<br />
</reason><br />
<br />
</invite><br />
<br />
</x><br />
<br />
<error code='403' type='auth'><br />
<br />
<forbidden xmlns='urn:ietf:params:xml:ns:xmpp-stanzas'/><br />
<br />
</error><br />
<br />
</message><br />
<br />
<br />
<br />
<br />
<br />
Invitations sent through an open room MUST NOT trigger the addition of the invitee to the member list.<br />
<br />
<br />
<br />
If a user is added to the member list of an open room and the user is in the room, the service MUST send updated presence from this individual to all occupants, indicating the change in affiliation by including an <x/> element qualified by the 'http://jabber.org/protocol/muc#user' namespace and containing an <item/> child with the 'affiliation' attribute set to a value of "member".<br />
<br />
<br />
<br />
Example 118. Service Sends Notice of Membership to All Occupants<br />
<br />
<br />
<br />
<presence<br />
<br />
from='darkcave@macbeth.shakespeare.lit/hecate'<br />
<br />
to='crone1@shakespeare.lit/desktop'><br />
<br />
<x xmlns='http://jabber.org/protocol/muc#user'><br />
<br />
<item affiliation='member'<br />
<br />
jid='hecate@shakespeare.lit/broom'<br />
<br />
role='participant'/><br />
<br />
</x><br />
<br />
</presence><br />
<br />
.<br />
<br />
.<br />
<br />
.<br />
<br />
<br />
<br />
<br />
<br />
9.6 Granting Moderator Privileges<br />
<br />
<br />
<br />
An admin may want to grant moderator privileges to a participant or visitor; this is done by changing the user's role to "moderator":<br />
<br />
<br />
<br />
Example 119. Admin Grants Moderator Privileges<br />
<br />
<br />
<br />
<iq from='crone1@shakespeare.lit/desktop'<br />
<br />
id='mod1'<br />
<br />
to='darkcave@macbeth.shakespeare.lit'<br />
<br />
type='set'><br />
<br />
<query xmlns='http://jabber.org/protocol/muc#admin'><br />
<br />
<item nick='thirdwitch'<br />
<br />
role='moderator'/><br />
<br />
</query><br />
<br />
</iq><br />
<br />
<br />
<br />
<br />
<br />
The service MUST add the user to the moderator list and then inform the admin of success:<br />
<br />
<br />
<br />
Example 120. Service Informs Admin of Success<br />
<br />
<br />
<br />
<iq from='darkcave@macbeth.shakespeare.lit'<br />
<br />
id='mod1'<br />
<br />
to='crone1@shakespeare.lit/desktop'<br />
<br />
type='result'/><br />
<br />
<br />
<br />
<br />
<br />
The service MUST then send updated presence from this individual to all occupants, indicating the addition of moderator privileges by including an <x/> element qualified by the 'http://jabber.org/protocol/muc#user' namespace and containing an <item/> child with the 'role' attribute set to a value of "moderator".<br />
<br />
<br />
<br />
Example 121. Service Sends Notice of Moderator Privileges to All Occupants<br />
<br />
<br />
<br />
<presence<br />
<br />
from='darkcave@macbeth.shakespeare.lit/thirdwitch'<br />
<br />
to='crone1@shakespeare.lit/desktop'><br />
<br />
<x xmlns='http://jabber.org/protocol/muc#user'><br />
<br />
<item affiliation='member'<br />
<br />
jid='hag66@shakespeare.lit/pda'<br />
<br />
role='moderator'/><br />
<br />
</x><br />
<br />
</presence><br />
<br />
.<br />
<br />
.<br />
<br />
.<br />
<br />
<br />
<br />
<br />
<br />
9.7 Revoking Moderator Privileges<br />
<br />
<br />
<br />
An admin may want to revoke a user's moderator privileges. An admin MAY revoke moderator privileges only from a user whose affiliation is "member" or "none" (i.e., not from an owner or admin). The privilege is revoked by changing the user's role to "participant":<br />
<br />
<br />
<br />
Example 122. Admin Revokes Moderator Privileges<br />
<br />
<br />
<br />
<iq from='crone1@shakespeare.lit/desktop'<br />
<br />
id='mod2'<br />
<br />
to='darkcave@macbeth.shakespeare.lit'<br />
<br />
type='set'><br />
<br />
<query xmlns='http://jabber.org/protocol/muc#admin'><br />
<br />
<item nick='thirdwitch'<br />
<br />
role='participant'/><br />
<br />
</query><br />
<br />
</iq><br />
<br />
<br />
<br />
<br />
<br />
The service MUST remove the user from the moderator list and then inform the admin of success:<br />
<br />
<br />
<br />
Example 123. Service Informs Admin of Success<br />
<br />
<br />
<br />
<iq from='darkcave@macbeth.shakespeare.lit'<br />
<br />
id='mod2'<br />
<br />
to='crone1@shakespeare.lit/desktop'<br />
<br />
type='result'/><br />
<br />
<br />
<br />
<br />
<br />
The service MUST then send updated presence from this individual to all occupants, indicating the removal of moderator privileges by sending a presence element that contains an <x/> element qualified by the 'http://jabber.org/protocol/muc#user' namespace and containing an <item/> child with the 'role' attribute set to a value of "participant".<br />
<br />
<br />
<br />
Example 124. Service Notes Loss of Moderator Privileges<br />
<br />
<br />
<br />
<presence<br />
<br />
from='darkcave@macbeth.shakespeare.lit/thirdwitch'<br />
<br />
to='crone1@shakespeare.lit/desktop'><br />
<br />
<x xmlns='http://jabber.org/protocol/muc#user'><br />
<br />
<item affiliation='member'<br />
<br />
jid='hag66@shakespeare.lit/pda'<br />
<br />
role='participant'/><br />
<br />
</x><br />
<br />
</presence><br />
<br />
.<br />
<br />
.<br />
<br />
.<br />
<br />
<br />
<br />
<br />
<br />
As noted, an admin MUST NOT be allowed to revoke moderator privileges from a user whose affiliation is "owner" or "admin". If an admin attempts to revoke moderator privileges from such a user, the service MUST deny the request and return a <not-allowed/> error to the sender:<br />
<br />
<br />
<br />
Example 125. Service Returns Error on Attempt to Revoke Moderator Privileges from an Admin or Owner<br />
<br />
<br />
<br />
<iq from='darkcave@macbeth.shakespeare.lit'<br />
<br />
id='modtest'<br />
<br />
to='crone1@shakespeare.lit/desktop'<br />
<br />
type='error'><br />
<br />
<query xmlns='http://jabber.org/protocol/muc#admin'><br />
<br />
<item nick='secondwitch' role='participant'/><br />
<br />
</query><br />
<br />
<error code='405' type='cancel'><br />
<br />
<not-allowed xmlns='urn:ietf:params:xml:ns:xmpp-stanzas'/><br />
<br />
</error><br />
<br />
</iq><br />
<br />
<br />
<br />
<br />
<br />
9.8 Modifying the Moderator List<br />
<br />
<br />
<br />
An admin may want to modify the moderator list. To do so, the admin first requests the moderator list by querying the room for all users with a role of 'moderator'.<br />
<br />
<br />
<br />
Example 126. Admin Requests Moderator List<br />
<br />
<br />
<br />
<iq from='crone1@shakespeare.lit/desktop'<br />
<br />
id='mod3'<br />
<br />
to='darkcave@macbeth.shakespeare.lit'<br />
<br />
type='get'><br />
<br />
<query xmlns='http://jabber.org/protocol/muc#admin'><br />
<br />
<item role='moderator'/><br />
<br />
</query><br />
<br />
</iq><br />
<br />
<br />
<br />
<br />
<br />
The service MUST then return the moderator list to the admin; each item MUST include the 'jid', 'nick', and 'role' attributes and SHOULD include the 'affiliation' attribute:<br />
<br />
<br />
<br />
Example 127. Service Sends Moderator List to Admin<br />
<br />
<br />
<br />
<iq from='darkcave@macbeth.shakespeare.lit'<br />
<br />
id='mod3'<br />
<br />
to='crone1@shakespeare.lit/desktop'<br />
<br />
type='result'><br />
<br />
<query xmlns='http://jabber.org/protocol/muc#admin'><br />
<br />
<item affiliation='member'<br />
<br />
jid='hag66@shakespeare.lit/pda'<br />
<br />
nick='thirdwitch'<br />
<br />
role='moderator'/><br />
<br />
</query><br />
<br />
</iq><br />
<br />
<br />
<br />
<br />
<br />
The admin MAY then modify the moderator list. In order to do so, the admin MUST send the changed items (i.e., only the "delta") back to the service; each item MUST include the 'jid' attribute and 'role' attribute (normally set to a value of "member" or "participant") but SHOULD NOT include the 'nick' attribute and MUST NOT include the 'affiliation' attribute (which is used to manage affiliations such as admin rather than the moderator role):<br />
<br />
<br />
<br />
Example 128. Admin Sends Modified Moderator List to Service<br />
<br />
<br />
<br />
<iq from='crone1@shakespeare.lit/desktop'<br />
<br />
id='mod4'<br />
<br />
to='darkcave@macbeth.shakespeare.lit'<br />
<br />
type='set'><br />
<br />
<query xmlns='http://jabber.org/protocol/muc#admin'><br />
<br />
<item jid='hag66@shakespeare.lit/pda'<br />
<br />
role='participant'/><br />
<br />
<item jid='hecate@shakespeare.lit/broom'<br />
<br />
role='moderator'/><br />
<br />
</query><br />
<br />
</iq><br />
<br />
<br />
<br />
<br />
<br />
The service MUST modify the moderator list and then inform the admin of success:<br />
<br />
<br />
<br />
Example 129. Service Informs Admin of Success<br />
<br />
<br />
<br />
<iq from='darkcave@macbeth.shakespeare.lit'<br />
<br />
id='mod4'<br />
<br />
to='crone1@shakespeare.lit/desktop'<br />
<br />
type='result'/><br />
<br />
<br />
<br />
<br />
<br />
The service MUST then send updated presence for any affected individuals to all occupants, indicating the change in moderator privileges by sending the appropriate extended presence stanzas as described in the foregoing use cases.<br />
<br />
<br />
<br />
As noted, moderator privileges cannot be revoked from a room owner or room admin. If a room admin attempts to revoke moderator privileges from such a user by modifying the moderator list, the service MUST deny the request and return a <not-allowed/> error to the sender:<br />
<br />
<br />
<br />
Example 130. Service Returns Error on Attempt to Revoke Moderator Privileges from an Admin or Owner<br />
<br />
<br />
<br />
<iq from='darkcave@macbeth.shakespeare.lit'<br />
<br />
id='modtest'<br />
<br />
to='hag66@shakespeare.lit/pda'<br />
<br />
type='error'><br />
<br />
<query xmlns='http://jabber.org/protocol/muc#admin'><br />
<br />
<item jid='hecate@shakespeare.lit/broom'<br />
<br />
nick='Hecate'<br />
<br />
role='participant'/><br />
<br />
</query><br />
<br />
<error code='405' type='cancel'><br />
<br />
<not-allowed xmlns='urn:ietf:params:xml:ns:xmpp-stanzas'/><br />
<br />
</error><br />
<br />
</iq><br />
<br />
<br />
<br />
<br />
<br />
9.9 Approving Registration Requests<br />
<br />
<br />
<br />
If a service does not automatically accept requests to register with a room, it MAY provide a way for room admins to approve or deny registration requests over Jabber (alternatively, it could provide a web interface or some other admin tool). The simplest way to do so is for the service to send a <message/> stanza to the room admin(s) when the registration request is received, where the <message/> stanza contains a Data Form asking for approval or denial of the request. The following Data Form is RECOMMENDED but implementations MAY use a different form entirely, or supplement the following form with additional fields.<br />
<br />
<br />
<br />
Example 131. Registration Request Approval Form<br />
<br />
<br />
<br />
<message from='darkcave@macbeth.shakespeare.lit'<br />
<br />
id='approve'<br />
<br />
to='crone1@shakespeare.lit/pda'><br />
<br />
<x xmlns='jabber:x:data' type='form'><br />
<br />
<title>Registration request</title><br />
<br />
<instructions><br />
<br />
To approve this registration request, select the<br />
<br />
&quot;Allow this person to register with the room?&quot;<br />
<br />
checkbox and click OK. To skip this request, click the <br />
<br />
cancel button.<br />
<br />
</instructions><br />
<br />
<field var='FORM_TYPE' type='hidden'><br />
<br />
<value>http://jabber.org/protocol/muc#register</value><br />
<br />
</field><br />
<br />
<field var='muc#register_first'<br />
<br />
type='text-single'<br />
<br />
label='First Name'><br />
<br />
<value>Brunhilde</value><br />
<br />
</field><br />
<br />
<field var='muc#register_last'<br />
<br />
type="text-single"<br />
<br />
label="Last Name"><br />
<br />
<value>Entwhistle-Throckmorton</value><br />
<br />
</field><br />
<br />
<field var='muc#register_roomnick'<br />
<br />
type="text-single"<br />
<br />
label="Desired Nickname"><br />
<br />
<value>thirdwitch</value><br />
<br />
</field><br />
<br />
<field var='muc#register_url'<br />
<br />
type="text-single"<br />
<br />
label="User URL"><br />
<br />
<value>http://witchesonline/~hag66/</value><br />
<br />
</field><br />
<br />
<field var='muc#register_email'<br />
<br />
type="text-single"<br />
<br />
label="Email Address"><br />
<br />
<value>hag66@witchesonline</value><br />
<br />
</field><br />
<br />
<field var='muc#register_faqentry'<br />
<br />
type="text-single"<br />
<br />
label="FAQ Entry"><br />
<br />
<value>Just another witch.</value><br />
<br />
</field><br />
<br />
<field var='muc#register_allow'<br />
<br />
type='boolean'<br />
<br />
label='Allow this person to register with the room?'><br />
<br />
<value>0</value><br />
<br />
</field><br />
<br />
</x><br />
<br />
</message><br />
<br />
<br />
<br />
<br />
<br />
If the admin approves the registration request, the service shall register the user with the room.<br />
<br />
<br />
<br />
More advanced registration approval mechanisms (e.g., retrieving a list of registration requests using Ad-Hoc Commands [18] as is done in Publish-Subscribe [19]) are out of scope for this document.<br />
<br />
10. Owner Use Cases<br />
<br />
<br />
<br />
Every room MUST have at least one owner, and that owner (or a successor) is a long-lived attribute of the room for as long as the room exists (e.g., the owner does not lose ownership on exiting a persistent room). This document assumes that the (initial) room owner is the individual who creates the room and that only a room owner has the right to change defining room configuration settings such as the room type. Ideally, room owners will be able to specify not only the room types (password-protected, members-only, etc.) but also certain attributes of the room as listed in the Requirements section of this document. In addition, it would be good if an owner were able to specify the JIDs of other owners, but that shall be determined by the implementation.<br />
<br />
<br />
<br />
In order to provide the necessary flexibility for a wide range of configuration options, Data Forms (XEP-0004) shall be used for room configuration, triggered by use of the 'http://jabber.org/protocol/muc' namespace. That is, if an entity does not include the MUC namespace in its room join/create request, then the service shall create the room and not wait for configuration via Data Forms before creating the room (this ensures backwards-compatibility with the old "groupchat 1.0" protocol); however, if the room join/create request includes the MUC extension, then the service shall require configuration via Data Forms before creating and unlocking the room.<br />
<br />
<br />
<br />
Note: The configuration options shown below address all of the features and room types listed in the requirements section of this document; however, the exact configuration options and form layout shall be determined by the implementation or specific deployment. Also, these are examples only and are not intended to define the only allowed or required configuration options for rooms. A given implementation or deployment MAY choose to provide additional configuration options (profanity filters, setting the default language for a room, message logging, etc.), which is why the use of the 'jabber:x:data' protocol is valuable here.<br />
<br />
10.1 Creating a Room<br />
<br />
10.1.1 General Considerations<br />
<br />
<br />
<br />
The privilege to create rooms MAY be restricted to certain users or MAY be reserved to an administrator of the service. If access is restricted and a user attempts to create a room, the service MUST return a <not-allowed/> error:<br />
<br />
<br />
<br />
Example 132. Service Informs User of Inability to Create a Room<br />
<br />
<br />
<br />
<presence<br />
<br />
from='darkcave@macbeth.shakespeare.lit/thirdwitch'<br />
<br />
to='hag66@shakespeare.lit/pda'<br />
<br />
type='error'><br />
<br />
<error code='405' type='cancel'><br />
<br />
<not-allowed xmlns='urn:ietf:params:xml:ns:xmpp-stanzas'/><br />
<br />
</error><br />
<br />
</presence><br />
<br />
<br />
<br />
<br />
<br />
If access is not restricted, the service MUST allow the user to create a room as described below.<br />
<br />
<br />
<br />
From the perspective of room creation, there are in essence two kinds of rooms:<br />
<br />
<br />
<br />
*<br />
<br />
<br />
<br />
"Instant rooms" -- these are available for immediate access and are automatically created based on some default configuration.<br />
<br />
*<br />
<br />
<br />
<br />
"Reserved rooms" -- these are manually configured by the room creator before anyone is allowed to enter.<br />
<br />
<br />
<br />
The workflow for creating and configuring such rooms is as follows:<br />
<br />
<br />
<br />
1.<br />
<br />
<br />
<br />
The user MUST send presence to <room@service/nick> and signal his or her support for the Multi-User Chat protocol by including extended presence information in an empty <x/> child element qualified by the 'http://jabber.org/protocol/muc' namespace (note the lack of an '#owner' or '#user' fragment).<br />
<br />
2.<br />
<br />
<br />
<br />
If this user is allowed to create a room and the room does not yet exist, the service MUST create the room according to some default configuration, assign the requesting user as the initial room owner, and add the owner to the room but not allow anyone else to enter the room (effectively "locking" the room). The initial presence stanza received by the owner from the room MUST include extended presence information indicating the user's status as an owner and acknowledging that the room has been created (via status code 201) and is awaiting configuration.<br />
<br />
3.<br />
<br />
<br />
<br />
If the initial room owner would like to create and configure a reserved room, the room owner MUST then request a configuration form by sending an IQ stanza of type "get" to the room containing an empty <query/> element qualified by the 'http://jabber.org/protocol/muc#owner' namespace, then complete Steps 4 and 5. If the room owner would prefer to create an instant room, the room owner MUST send a query element qualified by the 'http://jabber.org/protocol/muc#owner' namespace and containing an empty <x/> element of type "submit" qualified by the 'jabber:x:data' namespace, then skip to Step 6.<br />
<br />
4.<br />
<br />
<br />
<br />
If the room owner requested a configuration form, the service MUST send an IQ to the room owner containing a configuration form qualified by the 'jabber:x:data' namespace. If there are no configuration options available, the room MUST return an empty query element to the room owner.<br />
<br />
5.<br />
<br />
<br />
<br />
The initial room owner SHOULD provide a starting configuration for the room (or accept the default configuration) by sending an IQ of type "set" containing the completed configuration form. Alternatively, the room owner MAY cancel the configuration process. (An implementation MAY set a timeout for initial configuration, such that if the room owner does not configure the room within the timeout period, the room owner is assumed to have accepted the default configuration or to have cancelled the configuration process.)<br />
<br />
6.<br />
<br />
<br />
<br />
Once the service receives the completed configuration form from the initial room owner (or receives a request for an instant room), the service MUST "unlock" the room (i.e., allow other users to enter the room) and send an IQ of type "result" to the room owner. If the service receives a cancellation, it MUST destroy the room.<br />
<br />
<br />
<br />
The protocol for this workflow is shown in the examples below.<br />
<br />
<br />
<br />
First, the Jabber user MUST send presence to the room, including an empty <x/> element qualified by the 'http://jabber.org/protocol/muc' namespace (this is the same stanza sent when seeking to enter a room).<br />
<br />
<br />
<br />
Example 133. Jabber User Creates a Room and Signals Support for Multi-User Chat<br />
<br />
<br />
<br />
<presence<br />
<br />
from='crone1@shakespeare.lit/desktop'<br />
<br />
to='darkcave@macbeth.shakespeare.lit/firstwitch'><br />
<br />
<x xmlns='http://jabber.org/protocol/muc'/><br />
<br />
</presence><br />
<br />
<br />
<br />
<br />
<br />
If the room does not yet exist, the service SHOULD create the room (subject to local policies regarding room creation), assign the bare JID of the requesting user as the owner, add the owner to the room, and acknowledge successful creation of the room by sending a presence stanza of the following form:<br />
<br />
<br />
<br />
Example 134. Service Acknowledges Room Creation<br />
<br />
<br />
<br />
<presence<br />
<br />
from='darkcave@macbeth.shakespeare.lit/firstwitch'<br />
<br />
to='crone1@shakespeare.lit/desktop'><br />
<br />
<x xmlns='http://jabber.org/protocol/muc#user'><br />
<br />
<item affiliation='owner'<br />
<br />
role='moderator'/><br />
<br />
<status code='201'/><br />
<br />
</x><br />
<br />
</presence><br />
<br />
<br />
<br />
<br />
<br />
After receiving notification that the room has been created, the room owner needs to decide whether to accept the default room configuration (i.e., create an "instant room") or configure the room to have something other than the default room configuration (i.e., create a "reserved room"). The protocol flows for completing those two use cases are shown in the following sections.<br />
<br />
<br />
<br />
Note: If the presence stanza sent to a nonexistent room does not include an <x/> element qualified by the 'http://jabber.org/protocol/muc' namespace as shown above, the service SHOULD create a default room without delay (i.e., it MUST assume that the client supports "groupchat 1.0" rather than Multi-User Chat and therefore it MUST NOT lock the room while waiting for the room creator to either accept an instant room or configure a reserved room).<br />
<br />
10.1.2 Creating an Instant Room<br />
<br />
<br />
<br />
If the initial room owner wants to accept the default room configuration (i.e., create an "instant room"), the room owner MUST decline an initial configuration form by sending an IQ set to the <room@service> itself containing a <query/> element qualified by the 'http://jabber.org/protocol/muc#owner' namespace, where the only child of the <query/> is an empty <x/> element that is qualified by the 'jabber:x:data' namespace and that possesses a 'type' attribute whose value is "submit":<br />
<br />
<br />
<br />
Example 135. Owner Requests Instant Room<br />
<br />
<br />
<br />
<iq from='crone1@shakespeare.lit/desktop'<br />
<br />
id='create1'<br />
<br />
to='darkcave@macbeth.shakespeare.lit'<br />
<br />
type='set'><br />
<br />
<query xmlns='http://jabber.org/protocol/muc#owner'><br />
<br />
<x xmlns='jabber:x:data' type='submit'/><br />
<br />
</query><br />
<br />
</iq><br />
<br />
<br />
<br />
<br />
<br />
The service MUST then unlock the room and allow other entities to join it.<br />
<br />
10.1.3 Creating a Reserved Room<br />
<br />
<br />
<br />
If the initial room owner wants to create and configure a reserved room, the room owner MUST request an initial configuration form by sending an IQ get to the <room@service> itself containing an empty <query/> element qualified by the 'http://jabber.org/protocol/muc#owner' namespace:<br />
<br />
<br />
<br />
Example 136. Owner Requests Configuration Form<br />
<br />
<br />
<br />
<iq from='crone1@shakespeare.lit/desktop'<br />
<br />
id='create1'<br />
<br />
to='darkcave@macbeth.shakespeare.lit'<br />
<br />
type='get'><br />
<br />
<query xmlns='http://jabber.org/protocol/muc#owner'/><br />
<br />
</iq><br />
<br />
<br />
<br />
<br />
<br />
If the room does not already exist, the service MUST return an initial room configuration form to the user. (Note: The following example shows a representative sample of configuration options. A full list of x:data fields registered for use in room creation and configuration is maintained by the XMPP Registrar; see the XMPP Registrar Considerations section of this document.)<br />
<br />
<br />
<br />
Example 137. Service Sends Configuration Form<br />
<br />
<br />
<br />
<iq from='darkcave@macbeth.shakespeare.lit'<br />
<br />
id='create1'<br />
<br />
to='crone1@shakespeare.lit/desktop'<br />
<br />
type='result'><br />
<br />
<query xmlns='http://jabber.org/protocol/muc#owner'><br />
<br />
<x xmlns='jabber:x:data' type='form'><br />
<br />
<title>Configuration for "darkcave" Room</title><br />
<br />
<instructions><br />
<br />
Your room darkcave@macbeth has been created!<br />
<br />
The default configuration is as follows:<br />
<br />
- No logging<br />
<br />
- No moderation<br />
<br />
- Up to 20 occupants<br />
<br />
- No password required<br />
<br />
- No invitation required<br />
<br />
- Room is not persistent<br />
<br />
- Only admins may change the subject<br />
<br />
- Presence broadcasted for all users<br />
<br />
To accept the default configuration, click OK. To<br />
<br />
select a different configuration, please complete<br />
<br />
this form.<br />
<br />
</instructions><br />
<br />
<field<br />
<br />
type='hidden'<br />
<br />
var='FORM_TYPE'><br />
<br />
<value>http://jabber.org/protocol/muc#roomconfig</value><br />
<br />
</field><br />
<br />
<field<br />
<br />
label='Natural-Language Room Name'<br />
<br />
type='text-single'<br />
<br />
var='muc#roomconfig_roomname'/><br />
<br />
<field<br />
<br />
label='Short Description of Room'<br />
<br />
type='text-single'<br />
<br />
var='muc#roomconfig_roomdesc'/><br />
<br />
<field<br />
<br />
label='Natural Language for Room Discussions'<br />
<br />
type='text-single'<br />
<br />
var='muc#roomconfig_lang'/><br />
<br />
<field<br />
<br />
label='Enable Public Logging?'<br />
<br />
type='boolean'<br />
<br />
var='muc#roomconfig_enablelogging'><br />
<br />
<value>0</value><br />
<br />
</field><br />
<br />
<field<br />
<br />
label='Allow Occupants to Change Subject?'<br />
<br />
type='boolean'<br />
<br />
var='muc#roomconfig_changesubject'><br />
<br />
<value>0</value><br />
<br />
</field><br />
<br />
<field<br />
<br />
label='Allow Occupants to Invite Others?'<br />
<br />
type='boolean'<br />
<br />
var='muc#roomconfig_allowinvites'><br />
<br />
<value>0</value><br />
<br />
</field><br />
<br />
<field<br />
<br />
label='Maximum Number of Occupants'<br />
<br />
type='list-single'<br />
<br />
var='muc#roomconfig_maxusers'><br />
<br />
<value>20</value><br />
<br />
<option label='10'><value>10</value></option><br />
<br />
<option label='20'><value>20</value></option><br />
<br />
<option label='30'><value>30</value></option><br />
<br />
<option label='50'><value>50</value></option><br />
<br />
<option label='100'><value>100</value></option><br />
<br />
<option label='None'><value>none</value></option><br />
<br />
</field><br />
<br />
<field<br />
<br />
label='Roles for which Presence is Broadcast'<br />
<br />
type='list-multi'<br />
<br />
var='muc#roomconfig_presencebroadcast'><br />
<br />
<value>moderator</value><br />
<br />
<value>participant</value><br />
<br />
<value>visitor</value><br />
<br />
<option label='Moderator'><value>moderator</value></option><br />
<br />
<option label='Participant'><value>participant</value></option><br />
<br />
<option label='Visitor'><value>visitor</value></option><br />
<br />
</field><br />
<br />
<field<br />
<br />
label='Make Room Publicly Searchable?'<br />
<br />
type='boolean'<br />
<br />
var='muc#roomconfig_publicroom'><br />
<br />
<value>1</value><br />
<br />
</field><br />
<br />
<field<br />
<br />
label='Make Room Persistent?'<br />
<br />
type='boolean'<br />
<br />
var='muc#roomconfig_persistentroom'><br />
<br />
<value>0</value><br />
<br />
</field><br />
<br />
<field<br />
<br />
label='Make Room Moderated?'<br />
<br />
type='boolean'<br />
<br />
var='muc#roomconfig_moderatedroom'><br />
<br />
<value>0</value><br />
<br />
</field><br />
<br />
<field<br />
<br />
label='Make Room Members-Only?'<br />
<br />
type='boolean'<br />
<br />
var='muc#roomconfig_membersonly'><br />
<br />
<value>0</value><br />
<br />
</field><br />
<br />
<field<br />
<br />
label='Password Required to Enter?'<br />
<br />
type='boolean'<br />
<br />
var='muc#roomconfig_passwordprotectedroom'><br />
<br />
<value>0</value><br />
<br />
</field><br />
<br />
<field type='fixed'><br />
<br />
<value><br />
<br />
If a password is required to enter this room,<br />
<br />
you must specify the password below.<br />
<br />
</value><br />
<br />
</field><br />
<br />
<field<br />
<br />
label='Password'<br />
<br />
type='text-private'<br />
<br />
var='muc#roomconfig_roomsecret'/><br />
<br />
<field<br />
<br />
label='Who May Discover Real JIDs?'<br />
<br />
type='list-single'<br />
<br />
var='muc#roomconfig_whois'><br />
<br />
<option label='Moderators Only'><br />
<br />
<value>moderators</value><br />
<br />
</option><br />
<br />
<option label='Anyone'><br />
<br />
<value>anyone</value><br />
<br />
</option><br />
<br />
</field><br />
<br />
<field type='fixed'><br />
<br />
<value><br />
<br />
You may specify additional people who have<br />
<br />
administrative privileges in the room. Please<br />
<br />
provide one Jabber ID per line.<br />
<br />
</value><br />
<br />
</field><br />
<br />
<field<br />
<br />
label='Room Admins'<br />
<br />
type='jid-multi'<br />
<br />
var='muc#roomconfig_roomadmins'/><br />
<br />
<field type='fixed'><br />
<br />
<value><br />
<br />
You may specify additional owners for this<br />
<br />
room. Please provide one Jabber ID per line.<br />
<br />
</value><br />
<br />
</field><br />
<br />
<field<br />
<br />
label='Room Owners'<br />
<br />
type='jid-multi'<br />
<br />
var='muc#roomconfig_roomowners'/><br />
<br />
</x><br />
<br />
</query><br />
<br />
</iq><br />
<br />
<br />
<br />
<br />
<br />
Note: The _whois configuration option specifies whether the room is non-anonymous (a value of "anyone"), semi-anonymous (a value of "moderators"), or fully anonmyous (a value of "none", not shown here).<br />
<br />
<br />
<br />
If there are no configuration options available, the service MUST return an empty query element to the room owner:<br />
<br />
<br />
<br />
Example 138. Service Informs Owner that No Configuration is Possible<br />
<br />
<br />
<br />
<iq from='darkcave@macbeth.shakespeare.lit'<br />
<br />
id='create1'<br />
<br />
to='crone1@shakespeare.lit/desktop'<br />
<br />
type='result'><br />
<br />
<query xmlns='http://jabber.org/protocol/muc#owner'/><br />
<br />
</iq><br />
<br />
<br />
<br />
<br />
<br />
The room owner SHOULD then fill out the form and submit it to the service.<br />
<br />
<br />
<br />
Example 139. Owner Submits Configuration Form<br />
<br />
<br />
<br />
<iq from='crone1@shakespeare.lit/desktop'<br />
<br />
id='create2'<br />
<br />
to='darkcave@macbeth.shakespeare.lit'<br />
<br />
type='set'><br />
<br />
<query xmlns='http://jabber.org/protocol/muc#owner'><br />
<br />
<x xmlns='jabber:x:data' type='submit'><br />
<br />
<field var='FORM_TYPE'><br />
<br />
<value>http://jabber.org/protocol/muc#roomconfig</value><br />
<br />
</field><br />
<br />
<field var='muc#roomconfig_roomname'><br />
<br />
<value>A Dark Cave</value><br />
<br />
</field><br />
<br />
<field var='muc#roomconfig_roomdesc'><br />
<br />
<value>The place for all good witches!</value><br />
<br />
</field><br />
<br />
<field var='muc#roomconfig_enablelogging'><br />
<br />
<value>0</value><br />
<br />
</field><br />
<br />
<field var='muc#roomconfig_changesubject'><br />
<br />
<value>1</value><br />
<br />
</field><br />
<br />
<field var='muc#roomconfig_allowinvites'><br />
<br />
<value>0</value><br />
<br />
</field><br />
<br />
<field var='muc#roomconfig_maxusers'><br />
<br />
<value>10</value><br />
<br />
</field><br />
<br />
<field var='muc#roomconfig_publicroom'><br />
<br />
<value>0</value><br />
<br />
</field><br />
<br />
<field var='muc#roomconfig_persistentroom'><br />
<br />
<value>0</value><br />
<br />
</field><br />
<br />
<field var='muc#roomconfig_moderatedroom'><br />
<br />
<value>0</value><br />
<br />
</field><br />
<br />
<field var='muc#roomconfig_membersonly'><br />
<br />
<value>0</value><br />
<br />
</field><br />
<br />
<field var='muc#roomconfig_passwordprotectedroom'><br />
<br />
<value>1</value><br />
<br />
</field><br />
<br />
<field var='muc#roomconfig_roomsecret'><br />
<br />
<value>cauldronburn</value><br />
<br />
</field><br />
<br />
<field var='muc#roomconfig_whois'><br />
<br />
<value>moderators</value><br />
<br />
</field><br />
<br />
<field var='muc#roomconfig_roomadmins'><br />
<br />
<value>wiccarocks@shakespeare.lit</value><br />
<br />
<value>hecate@shakespeare.lit</value><br />
<br />
</field><br />
<br />
</x><br />
<br />
</query><br />
<br />
</iq><br />
<br />
<br />
<br />
<br />
<br />
If room creation is successful, the service MUST inform the new room owner of success:<br />
<br />
<br />
<br />
Example 140. Service Informs New Room Owner of Success<br />
<br />
<br />
<br />
<iq from='darkcave@macbeth.shakespeare.lit'<br />
<br />
id='create2'<br />
<br />
to='crone1@shakespeare.lit/desktop'<br />
<br />
type='result'/><br />
<br />
<br />
<br />
<br />
<br />
If the room creation fails because the specified room configuration options violate one or more service policies (e.g., because the password for a password-protected room is blank), the service MUST return a <not-acceptable/> error.<br />
<br />
<br />
<br />
Example 141. Service Informs Owner that Requested Configuration Options Are Unacceptable<br />
<br />
<br />
<br />
<iq from='darkcave@macbeth.shakespeare.lit'<br />
<br />
id='create2'<br />
<br />
to='crone1@shakespeare.lit/desktop'<br />
<br />
type='error'><br />
<br />
<error type='modify'><br />
<br />
<not-acceptable xmlns='urn:ietf:params:xml:ns:xmpp-stanzas'/><br />
<br />
</error><br />
<br />
</iq><br />
<br />
<br />
<br />
<br />
<br />
Alternatively, the room owner MAY cancel the configuration process:<br />
<br />
<br />
<br />
Example 142. Owner Cancels Initial Configuration<br />
<br />
<br />
<br />
<iq from='crone1@shakespeare.lit/desktop'<br />
<br />
id='create2'<br />
<br />
to='darkcave@macbeth.shakespeare.lit'<br />
<br />
type='set'><br />
<br />
<query xmlns='http://jabber.org/protocol/muc#owner'><br />
<br />
<x xmlns='jabber:x:data' type='cancel'/><br />
<br />
</query><br />
<br />
</iq><br />
<br />
<br />
<br />
<br />
<br />
If the room owner cancels the initial configuration, the service SHOULD destroy the room, making sure to send unavailable presence to the room owner (see the "Destroying a Room" use case for protocol details).<br />
<br />
<br />
<br />
If the room owner becomes unavailable for any reason before submitting the form (e.g., a lost connection), the service will receive a presence stanza of type "unavailable" from the owner to the owner's <room@service/nick> or to <room@service> (or both). The service MUST then destroy the room, sending a presence stanza of type "unavailable" from the room to the owner including a <destroy/> element and reason (if provided) as defined in the Destroying a Room section of this document.<br />
<br />
10.1.4 Requesting a Unique Room Name<br />
<br />
<br />
<br />
In some situations (e.g., when Converting a One-to-One Chat Into a Conference), the room creator may want to request a unique room name before attempting to create the room (e.g., to avoid the possibility of a room conflict). In order to facilitate this, a service MAY support the feature described in this section. (If a service does support this feature, it MUST return a feature of "http://jabber.org/protocol/muc#unique" in its response to service discovery information requests.)<br />
<br />
<br />
<br />
The room creator requests a unique room name by sending an IQ-get to the service itself, containing an empty <unique/> element qualified by the 'http://jabber.org/protocol/muc#unique' namespace:<br />
<br />
<br />
<br />
Example 143. Entity Requests Unique Room Name<br />
<br />
<br />
<br />
<iq from='crone1@shakespeare.lit/desktop'<br />
<br />
id='unique1'<br />
<br />
to='macbeth.shakespeare.lit'<br />
<br />
type='get'><br />
<br />
<unique xmlns='http://jabber.org/protocol/muc#unique'/><br />
<br />
</iq><br />
<br />
<br />
<br />
<br />
<br />
If the service supports this feature, it SHOULD return a unique room name as the XML character data of the <unique/> element:<br />
<br />
<br />
<br />
Example 144. Service Returns Unique Room Name<br />
<br />
<br />
<br />
<iq from='macbeth.shakespeare.lit'<br />
<br />
id='unique1'<br />
<br />
to='crone1@shakespeare.lit/desktop'<br />
<br />
type='result'><br />
<br />
<unique xmlns='http://jabber.org/protocol/muc#unique'><br />
<br />
6d9423a55f499b29ad20bf7b2bdea4f4b885ead1<br />
<br />
</unique><br />
<br />
</iq><br />
<br />
<br />
<br />
<br />
<br />
The service MAY refuse to return a unique room name to entities that are not entitled to create rooms, entities that have sent an excessive number of requests for unique room names, etc.<br />
<br />
<br />
<br />
The service MAY use any algorithm that ensures the creation of a room name that will be permanently unique in the context of the service (e.g., a SHA-1 hash of the requesting JID, datetime, and random salt).<br />
<br />
<br />
<br />
The room creator would then use the XML character data of the <unique/> element as the node identifier portion of the room JID it requests:<br />
<br />
<br />
<br />
Example 145. Owner Creates Room With Unique Name<br />
<br />
<br />
<br />
<presence <br />
<br />
from='crone1@shakespeare.lit/desktop'<br />
<br />
to='6d9423a55f499b29ad20bf7b2bdea4f4b885ead1@macbeth.shakespeare.lit/firstwitch'><br />
<br />
<x xmlns='http://jabber.org/protocol/muc'/><br />
<br />
</presence><br />
<br />
<br />
<br />
<br />
<br />
10.2 Subsequent Room Configuration<br />
<br />
<br />
<br />
At any time after specifying the initial configuration of the room, a room owner may want to change the configuration. In order to initiate this process, a room owner MUST request a new configuration form from the room by sending an IQ to <room@service> containing an empty <query/> element qualified by the 'http://jabber.org/protocol/muc#owner' namespace.<br />
<br />
<br />
<br />
Example 146. Owner Requests Configuration Form<br />
<br />
<br />
<br />
<iq from='crone1@shakespeare.lit/desktop'<br />
<br />
id='config1'<br />
<br />
to='darkcave@macbeth.shakespeare.lit'<br />
<br />
type='get'><br />
<br />
<query xmlns='http://jabber.org/protocol/muc#owner'/><br />
<br />
</iq><br />
<br />
<br />
<br />
<br />
<br />
If the <user@host> of the 'from' address does not match the bare JID of a room owner, the service MUST return a <forbidden/> error to the sender:<br />
<br />
<br />
<br />
Example 147. Service Denies Configuration Access to Non-Owner<br />
<br />
<br />
<br />
<iq from='darkcave@macbeth.shakespeare.lit'<br />
<br />
id='configures'<br />
<br />
to='wiccarocks@shakespeare.lit/laptop'<br />
<br />
type='error'><br />
<br />
<query xmlns='http://jabber.org/protocol/muc#owner'/><br />
<br />
<error code='403' type='auth'><br />
<br />
<forbidden xmlns='urn:ietf:params:xml:ns:xmpp-stanzas'/><br />
<br />
</error><br />
<br />
</iq><br />
<br />
<br />
<br />
<br />
<br />
Otherwise, the service MUST send a configuration form to the room owner with the current options set as defaults:<br />
<br />
<br />
<br />
Example 148. Service Sends Configuration Form to Owner<br />
<br />
<br />
<br />
<iq from='darkcave@macbeth.shakespeare.lit'<br />
<br />
id='config1'<br />
<br />
to='crone1@shakespeare.lit/desktop'<br />
<br />
type='result'><br />
<br />
<query xmlns='http://jabber.org/protocol/muc#owner'><br />
<br />
<x xmlns='jabber:x:data' type='form'><br />
<br />
<title>Configuration for "darkcave" Room</title><br />
<br />
<instructions><br />
<br />
Complete this form to make changes to<br />
<br />
the configuration of your room.<br />
<br />
</instructions><br />
<br />
<field<br />
<br />
type='hidden'<br />
<br />
var='FORM_TYPE'><br />
<br />
<value>http://jabber.org/protocol/muc#roomconfig</value><br />
<br />
</field><br />
<br />
<field<br />
<br />
label='Natural-Language Room Name'<br />
<br />
type='text-single'<br />
<br />
var='muc#roomconfig_roomname'><br />
<br />
<value>A Dark Cave</value><br />
<br />
</field><br />
<br />
<field<br />
<br />
label='Short Description of Room'<br />
<br />
type='text-single'<br />
<br />
var='muc#roomconfig_roomdesc'><br />
<br />
<value>The place for all good witches!</value><br />
<br />
</field><br />
<br />
<field<br />
<br />
label='Enable Public Logging?'<br />
<br />
type='boolean'<br />
<br />
var='muc#roomconfig_enablelogging'><br />
<br />
<value>0</value><br />
<br />
</field><br />
<br />
<field<br />
<br />
label='Allow Occupants to Change Subject?'<br />
<br />
type='boolean'<br />
<br />
var='muc#roomconfig_changesubject'><br />
<br />
<value>0</value><br />
<br />
</field><br />
<br />
<field<br />
<br />
label='Allow Occupants to Invite Others?'<br />
<br />
type='boolean'<br />
<br />
var='muc#roomconfig_allowinvites'><br />
<br />
<value>0</value><br />
<br />
</field><br />
<br />
<field<br />
<br />
label='Maximum Number of Occupants'<br />
<br />
type='list-single'<br />
<br />
var='muc#roomconfig_maxusers'><br />
<br />
<value>10</value><br />
<br />
<option label='10'><value>10</value></option><br />
<br />
<option label='20'><value>20</value></option><br />
<br />
<option label='30'><value>30</value></option><br />
<br />
<option label='50'><value>50</value></option><br />
<br />
<option label='100'><value>100</value></option><br />
<br />
<option label='None'><value>none</value></option><br />
<br />
</field><br />
<br />
<field<br />
<br />
label='Roles for which Presence is Broadcast'<br />
<br />
type='list-multi'<br />
<br />
var='muc#roomconfig_presencebroadcast'><br />
<br />
<value>moderator</value><br />
<br />
<value>participant</value><br />
<br />
<value>visitor</value><br />
<br />
<option label='Moderator'><value>moderator</value></option><br />
<br />
<option label='Participant'><value>participant</value></option><br />
<br />
<option label='Visitor'><value>visitor</value></option><br />
<br />
</field><br />
<br />
<field<br />
<br />
label='Make Room Publicly Searchable?'<br />
<br />
type='boolean'<br />
<br />
var='muc#roomconfig_publicroom'><br />
<br />
<value>0</value><br />
<br />
</field><br />
<br />
<field<br />
<br />
label='Make Room Persistent?'<br />
<br />
type='boolean'<br />
<br />
var='muc#roomconfig_persistentroom'><br />
<br />
<value>0</value><br />
<br />
</field><br />
<br />
<field<br />
<br />
label='Make Room Moderated?'<br />
<br />
type='boolean'<br />
<br />
var='muc#roomconfig_moderatedroom'><br />
<br />
<value>0</value><br />
<br />
</field><br />
<br />
<field<br />
<br />
label='Make Room Members Only?'<br />
<br />
type='boolean'<br />
<br />
var='muc#roomconfig_membersonly'><br />
<br />
<value>0</value><br />
<br />
</field><br />
<br />
<field<br />
<br />
label='Password Required for Entry?'<br />
<br />
type='boolean'<br />
<br />
var='muc#roomconfig_passwordprotectedroom'><br />
<br />
<value>1</value><br />
<br />
</field><br />
<br />
<field type='fixed'><br />
<br />
<value><br />
<br />
If a password is required to enter this room,<br />
<br />
you must specify the password below.<br />
<br />
</value><br />
<br />
</field><br />
<br />
<field<br />
<br />
label='Password'<br />
<br />
type='text-private'<br />
<br />
var='muc#roomconfig_roomsecret'><br />
<br />
<value>cauldronburn</value><br />
<br />
</field><br />
<br />
<field<br />
<br />
label='Who May Discover Real JIDs?'<br />
<br />
type='list-single'<br />
<br />
var='muc#roomconfig_whois'><br />
<br />
<value>moderators</value><br />
<br />
<option label='Moderators Only'><br />
<br />
<value>moderators</value><br />
<br />
</option><br />
<br />
<option label='Anyone'><br />
<br />
<value>anyone</value><br />
<br />
</option><br />
<br />
</field><br />
<br />
<field type='fixed'><br />
<br />
<value><br />
<br />
You may specify additional people who have<br />
<br />
administrative privileges in the room. Please<br />
<br />
provide one Jabber ID per line.<br />
<br />
</value><br />
<br />
</field><br />
<br />
<field<br />
<br />
label='Room Admins'<br />
<br />
type='jid-multi'<br />
<br />
var='muc#roomconfig_roomadmins'><br />
<br />
<value>wiccarocks@shakespeare.lit</value><br />
<br />
<value>hecate@shakespeare.lit</value><br />
<br />
</field><br />
<br />
<field type='fixed'><br />
<br />
<value><br />
<br />
You may specify additional owners for this<br />
<br />
room. Please provide one Jabber ID per line.<br />
<br />
</value><br />
<br />
</field><br />
<br />
<field<br />
<br />
label='Room Owners'<br />
<br />
type='jid-multi'<br />
<br />
var='muc#roomconfig_roomowners'/><br />
<br />
</x><br />
<br />
</query><br />
<br />
</iq><br />
<br />
<br />
<br />
<br />
<br />
If there are no configuration options available, the service MUST return an empty query element to the room owner as shown in the previous use case.<br />
<br />
<br />
<br />
The room owner SHOULD then submit the form with updated configuration information.<br />
<br />
<br />
<br />
Alternatively, the room owner MAY cancel the configuration process:<br />
<br />
<br />
<br />
Example 149. Owner Cancels Subsequent Configuration<br />
<br />
<br />
<br />
<iq from='crone1@shakespeare.lit/desktop'<br />
<br />
id='config2'<br />
<br />
to='darkcave@macbeth.shakespeare.lit'<br />
<br />
type='set'><br />
<br />
<query xmlns='http://jabber.org/protocol/muc#owner'><br />
<br />
<x xmlns='jabber:x:data' type='cancel'/><br />
<br />
</query><br />
<br />
</iq><br />
<br />
<br />
<br />
<br />
<br />
If the room owner cancels the subsequent configuration, the service MUST leave the configuration of the room as it was before the room owner initiated the subsequent configuration process.<br />
<br />
<br />
<br />
If as a result of a change in the room configuration a room admin loses administrative privileges while the admin is in the room, the room MUST send updated presence for that individual to all occupants, denoting the change in status by including an <x/> element qualified by the 'http://jabber.org/protocol/muc#user' namespace and containing an <item/> child with the 'affiliation' attribute set to a value of "member" and the 'role' attribute set to a value of "participant" or "visitor" as appropriate for the affiliation level and the room type:<br />
<br />
<br />
<br />
Example 150. Service Notes Loss of Admin Affiliation<br />
<br />
<br />
<br />
<presence<br />
<br />
from='darkcave@macbeth.shakespeare.lit/secondwitch'<br />
<br />
to='crone1@shakespeare.lit/desktop'><br />
<br />
<x xmlns='http://jabber.org/protocol/muc#user'><br />
<br />
<item affiliation='member'<br />
<br />
jid='wiccarocks@shakespeare.lit/laptop'<br />
<br />
role='participant'/><br />
<br />
</x><br />
<br />
</presence><br />
<br />
.<br />
<br />
.<br />
<br />
.<br />
<br />
<br />
<br />
<br />
<br />
If as a result of a change in the room configuration a user gains administrative privileges while the user is in the room, the room MUST send updated presence for that individual to all occupants, denoting the change in status by including an <x/> element qualified by the 'http://jabber.org/protocol/muc#user' namespace and containing an <item/> child with the 'affiliation' attribute set to a value of "admin" and the 'role' attribute set to a value of "admin":<br />
<br />
<br />
<br />
Example 151. Service Notes Gain of Admin Affiliation to All Users<br />
<br />
<br />
<br />
<presence<br />
<br />
from='darkcave@macbeth.shakespeare.lit/secondwitch'<br />
<br />
to='crone1@shakespeare.lit/desktop'><br />
<br />
<x xmlns='http://jabber.org/protocol/muc#user'><br />
<br />
<item affiliation='admin'<br />
<br />
jid='wiccarocks@shakespeare.lit/laptop'<br />
<br />
role='moderator'/><br />
<br />
</x><br />
<br />
</presence><br />
<br />
.<br />
<br />
.<br />
<br />
.<br />
<br />
<br />
<br />
<br />
<br />
If as a result of a change in the room configuration a room owner loses owner privileges while that owner is in the room, the room MUST send updated presence for that individual to all occupants, denoting the change in status by including an <x/> element qualified by the 'http://jabber.org/protocol/muc#user' namespace and containing an <item/> child with the 'affiliation' attribute set to a value of "admin" and the 'role' attribute set to an appropriate value given the affiliation and room type ("moderator" is recommended).<br />
<br />
<br />
<br />
Example 152. Service Notes Loss of Owner Affiliation<br />
<br />
<br />
<br />
<presence<br />
<br />
from='darkcave@macbeth.shakespeare.lit/secondwitch'<br />
<br />
to='crone1@shakespeare.lit/desktop'><br />
<br />
<x xmlns='http://jabber.org/protocol/muc#user'><br />
<br />
<item affiliation='admin'<br />
<br />
jid='wiccarocks@shakespeare.lit/laptop'<br />
<br />
role='moderator'/><br />
<br />
</x><br />
<br />
</presence><br />
<br />
.<br />
<br />
.<br />
<br />
.<br />
<br />
<br />
<br />
<br />
<br />
A service MUST NOT allow an owner to revoke his or her own ownership privileges if there are no other owners; if an owner attempts to do this, the service MUST return a <conflict/> error to the owner. However, a service SHOULD allow an owner to revoke his or her own ownership privileges if there are other owners.<br />
<br />
<br />
<br />
If as a result of a change in the room configuration a user gains ownership privileges while the user is in the room, the room MUST send updated presence for that individual to all occupants, denoting the change in status by including an <x/> element qualified by the 'http://jabber.org/protocol/muc#user' namespace and containing an <item/> child with the 'affiliation' attribute set to a value of "owner" and the 'role' attribute set to an appropriate value given the affiliation and room type ("moderator" is recommended).<br />
<br />
<br />
<br />
Example 153. Service Notes Gain of Owner Affiliation to All Users<br />
<br />
<br />
<br />
<presence<br />
<br />
from='darkcave@macbeth.shakespeare.lit/secondwitch'<br />
<br />
to='crone1@shakespeare.lit/desktop'><br />
<br />
<x xmlns='http://jabber.org/protocol/muc#user'><br />
<br />
<item affiliation='owner'<br />
<br />
jid='wiccarocks@shakespeare.lit/laptop'<br />
<br />
role='moderator'/><br />
<br />
</x><br />
<br />
</presence><br />
<br />
.<br />
<br />
.<br />
<br />
.<br />
<br />
<br />
<br />
<br />
<br />
If as a result of a change in the room configuration the room type is changed to members-only but there are non-members in the room, the service MUST remove any non-members from the room and include a status code of 322 in the presence unavailable stanzas sent to those users as well as any remaining occupants.<br />
<br />
10.2.1 Notification of Configuration Changes<br />
<br />
<br />
<br />
A room MUST send notification to all occupants when the room configuration changes in a way that has an impact on the privacy or security profile of the room. This notification shall consist of a <message/> stanza containing an <x/> element qualified by the 'http://jabber.org/protocol/muc#user' namespace, which shall contain only a <status/> element with an appropriate value for the 'code' attribute. Here is an example:<br />
<br />
<br />
<br />
Example 154. Configuration Status Code<br />
<br />
<br />
<br />
<message from='darkcave@macbeth.shakespeare.lit'<br />
<br />
to='crone1@shakespeare.lit/desktop'><br />
<br />
<x xmlns='http://jabber.org/protocol/muc#user'><br />
<br />
<status code='170'/><br />
<br />
</x><br />
<br />
</message><br />
<br />
<br />
<br />
<br />
<br />
The codes to be generated as a result of a privacy-related change in room configuration are as follows:<br />
<br />
<br />
<br />
* If room logging is now enabled, status code 170.<br />
<br />
* If room logging is now disabled, status code 171.<br />
<br />
* If the room is now non-anonymous, status code 172.<br />
<br />
* If the room is now semi-anonymous, status code 173.<br />
<br />
* If the room is now fully-anonymous, status code 174.<br />
<br />
<br />
<br />
For any other configuration change, the room SHOULD send status code 104 so that interested occupants can retrieve the updated room configuration if desired.<br />
<br />
10.3 Granting Ownership Privileges<br />
<br />
<br />
<br />
If allowed by an implementation, an owner MAY grant ownership privileges to another user; this is done by changing the user's affiliation to "owner":<br />
<br />
<br />
<br />
Example 155. Owner Grants Ownership Privileges<br />
<br />
<br />
<br />
<iq from='crone1@shakespeare.lit/desktop'<br />
<br />
id='owner1'<br />
<br />
to='darkcave@macbeth.shakespeare.lit'<br />
<br />
type='set'><br />
<br />
<query xmlns='http://jabber.org/protocol/muc#admin'><br />
<br />
<item affiliation='owner'<br />
<br />
jid='hecate@shakespeare.lit'/><br />
<br />
</query><br />
<br />
</iq><br />
<br />
<br />
<br />
<br />
<br />
The service MUST add the user to the owner list and then inform the owner of success:<br />
<br />
<br />
<br />
Example 156. Service Informs Owner of Success<br />
<br />
<br />
<br />
<iq from='darkcave@macbeth.shakespeare.lit'<br />
<br />
id='owner1'<br />
<br />
to='crone1@shakespeare.lit/desktop'<br />
<br />
type='result'/><br />
<br />
<br />
<br />
<br />
<br />
If the user is in the room, the service MUST then send updated presence from this individual to all occupants, indicating the granting of ownership privileges by including an <x/> element qualified by the 'http://jabber.org/protocol/muc#user' namespace and containing an <item/> child with the 'affiliation' attribute set to a value of "owner" and the 'role' attribute set to an appropriate value given the affiliation and room type ("moderator" is recommended).<br />
<br />
<br />
<br />
Example 157. Service Sends Notice of Ownership Privileges to All Occupants<br />
<br />
<br />
<br />
<presence<br />
<br />
from='darkcave@macbeth.shakespeare.lit/hecate'<br />
<br />
to='crone1@shakespeare.lit/desktop'><br />
<br />
<x xmlns='http://jabber.org/protocol/muc#user'><br />
<br />
<item affiliation='owner'<br />
<br />
jid='hecate@shakespeare.lit/broom'<br />
<br />
role='moderator'/><br />
<br />
</x><br />
<br />
</presence><br />
<br />
.<br />
<br />
.<br />
<br />
.<br />
<br />
<br />
<br />
<br />
<br />
10.4 Revoking Ownership Privileges<br />
<br />
<br />
<br />
An implementation MAY allow an owner to revoke another user's ownership privileges; this is done by changing the user's affiliation to something other than "owner":<br />
<br />
<br />
<br />
Example 158. Owner Revokes Ownership Privileges<br />
<br />
<br />
<br />
<iq from='crone1@shakespeare.lit/desktop'<br />
<br />
id='owner2'<br />
<br />
to='darkcave@macbeth.shakespeare.lit'<br />
<br />
type='set'><br />
<br />
<query xmlns='http://jabber.org/protocol/muc#admin'><br />
<br />
<item affiliation='admin'<br />
<br />
jid='hecate@shakespeare.lit'/><br />
<br />
</query><br />
<br />
</iq><br />
<br />
<br />
<br />
<br />
<br />
A service MUST NOT allow an owner to revoke his or her own ownership privileges if there are no other owners; if an owner attempts to do this, the service MUST return a <conflict/> error to the owner. However, a service SHOULD allow an owner to revoke his or her own ownership privileges if there are other owners.<br />
<br />
<br />
<br />
If an implementation does not allow one owner to revoke another user's ownership privileges, the implementation MUST return a <not-authorized/> error to the owner who made the request.<br />
<br />
<br />
<br />
In all other cases, the service MUST remove the user from the owner list and then inform the owner of success:<br />
<br />
<br />
<br />
Example 159. Service Informs Owner of Success<br />
<br />
<br />
<br />
<iq from='darkcave@macbeth.shakespeare.lit'<br />
<br />
id='owner2'<br />
<br />
to='crone1@shakespeare.lit/desktop'<br />
<br />
type='result'/><br />
<br />
<br />
<br />
<br />
<br />
If the user is in the room, the service MUST then send updated presence from this individual to all occupants, indicating the loss of ownership privileges by sending a presence element that contains an <x/> element qualified by the 'http://jabber.org/protocol/muc#user' namespace and containing an <item/> child with the 'affiliation' attribute set to a value other than "owner" and the 'role' attribute set to an appropriate value:<br />
<br />
<br />
<br />
Example 160. Service Notes Loss of Owner Affiliation<br />
<br />
<br />
<br />
<presence<br />
<br />
from='darkcave@macbeth.shakespeare.lit/secondwitch'<br />
<br />
to='crone1@shakespeare.lit/desktop'><br />
<br />
<x xmlns='http://jabber.org/protocol/muc#user'><br />
<br />
<item affiliation='admin'<br />
<br />
jid='hecate@shakespeare.lit/broom'<br />
<br />
role='moderator'/><br />
<br />
</x><br />
<br />
</presence><br />
<br />
.<br />
<br />
.<br />
<br />
.<br />
<br />
<br />
<br />
<br />
<br />
Note: Allowing an owner to remove another user's ownership privileges can compromise the control model for room management; therefore this feature is OPTIONAL, and implementations are encouraged to support owner removal through an interface that is open only to individuals with service-wide administrative privileges.<br />
<br />
10.5 Modifying the Owner List<br />
<br />
<br />
<br />
If allowed by an implementation, a room owner may want to modify the owner list. To do so, the owner first requests the owner list by querying the room for all users with an affiliation of 'owner'.<br />
<br />
<br />
<br />
Example 161. Owner Requests Owner List<br />
<br />
<br />
<br />
<iq from='bard@shakespeare.lit/globe'<br />
<br />
id='owner3'<br />
<br />
to='darkcave@macbeth.shakespeare.lit'<br />
<br />
type='get'><br />
<br />
<query xmlns='http://jabber.org/protocol/muc#admin'><br />
<br />
<item affiliation='owner'/><br />
<br />
</query><br />
<br />
</iq><br />
<br />
<br />
<br />
<br />
<br />
If the <user@host> of the 'from' address does not match the bare JID of a room owner, the service MUST return a <forbidden/> error to the sender.<br />
<br />
<br />
<br />
Otherwise, the service MUST then return the owner list to the owner; each item MUST include the 'affiliation' and 'jid' attributes and MAY include the 'nick' and 'role' attributes for any owner that is currently an occupant:<br />
<br />
<br />
<br />
Example 162. Service Sends Owner List to Owner<br />
<br />
<br />
<br />
<iq from='darkcave@macbeth.shakespeare.lit'<br />
<br />
id='owner3'<br />
<br />
to='bard@shakespeare.lit/globe'<br />
<br />
type='result'><br />
<br />
<query xmlns='http://jabber.org/protocol/muc#admin'><br />
<br />
<item affiliation='owner'<br />
<br />
jid='crone1@shakespeare.lit'/><br />
<br />
</query><br />
<br />
</iq><br />
<br />
<br />
<br />
<br />
<br />
The owner MAY then modify the owner list. In order to do so, the owner MUST send the changed items (i.e., only the "delta") back to the service; [20] each item MUST include the 'affiliation' and 'jid' attributes but SHOULD NOT include the 'nick' attribute and MUST NOT include the 'role' attribute (which is used to manage roles such as participant rather than the owner affiliation):<br />
<br />
<br />
<br />
Example 163. Owner Sends Modified Owner List to Service<br />
<br />
<br />
<br />
<iq from='bard@shakespeare.lit/globe'<br />
<br />
id='owner4'<br />
<br />
to='darkcave@macbeth.shakespeare.lit'<br />
<br />
type='set'><br />
<br />
<query xmlns='http://jabber.org/protocol/muc#admin'><br />
<br />
<item affiliation='owner'<br />
<br />
jid='hecate@shakespeare.lit'/><br />
<br />
</query><br />
<br />
</iq><br />
<br />
<br />
<br />
<br />
<br />
Only owners shall be allowed to modify the owner list. If a non-owner attempts to view or modify the owner list, the service MUST deny the request and return a <forbidden/> error to the sender:<br />
<br />
<br />
<br />
Example 164. Service Returns Error on Attempt by Non-Owner to Modify Owner List<br />
<br />
<br />
<br />
<iq from='darkcave@macbeth.shakespeare.lit'<br />
<br />
id='ownertest'<br />
<br />
to='hag66@shakespeare.lit/pda'<br />
<br />
type='error'><br />
<br />
<query xmlns='http://jabber.org/protocol/muc#admin'><br />
<br />
<item affiliation='owner' <br />
<br />
jid='hecate@shakespeare.lit'/><br />
<br />
</query><br />
<br />
<error code='403' type='auth'><br />
<br />
<forbidden xmlns='urn:ietf:params:xml:ns:xmpp-stanzas'/><br />
<br />
</error><br />
<br />
</iq><br />
<br />
<br />
<br />
<br />
<br />
A service MUST NOT allow an owner to revoke his or her own ownership privileges if there are no other owners; if an owner attempts to do this, the service MUST return a <conflict/> error to the owner. However, a service SHOULD allow an owner to revoke his or her own ownership privileges if there are other owners.<br />
<br />
<br />
<br />
In all other cases, the service MUST modify owner list and then inform the owner of success:<br />
<br />
<br />
<br />
Example 165. Service Informs Owner of Success<br />
<br />
<br />
<br />
<iq from='darkcave@macbeth.shakespeare.lit'<br />
<br />
id='owner4'<br />
<br />
to='crone1@shakespeare.lit/desktop'<br />
<br />
type='result'/><br />
<br />
<br />
<br />
<br />
<br />
The service MUST also send presence notifications related to any affiliation changes that result from modifying the owner list as previously described.<br />
<br />
10.6 Granting Administrative Privileges<br />
<br />
<br />
<br />
An owner can grant administrative privileges to a member or unaffiliated user; this is done by changing the user's affiliation to "admin":<br />
<br />
<br />
<br />
Example 166. Owner Grants Admin Privileges<br />
<br />
<br />
<br />
<iq from='crone1@shakespeare.lit/desktop'<br />
<br />
id='admin1'<br />
<br />
to='darkcave@macbeth.shakespeare.lit'<br />
<br />
type='set'><br />
<br />
<query xmlns='http://jabber.org/protocol/muc#admin'><br />
<br />
<item affiliation='admin'<br />
<br />
jid='wiccarocks@shakespeare.lit'/><br />
<br />
</query><br />
<br />
</iq><br />
<br />
<br />
<br />
<br />
<br />
The service MUST add the user to the admin list and then inform the owner of success:<br />
<br />
<br />
<br />
Example 167. Service Informs Owner of Success<br />
<br />
<br />
<br />
<iq from='darkcave@macbeth.shakespeare.lit'<br />
<br />
id='admin1'<br />
<br />
to='crone1@shakespeare.lit/desktop'<br />
<br />
type='result'/><br />
<br />
<br />
<br />
<br />
<br />
If the user is in the room, the service MUST then send updated presence from this individual to all occupants, indicating the granting of administrative privileges by including an <x/> element qualified by the 'http://jabber.org/protocol/muc#user' namespace and containing an <item/> child with the 'affiliation' attribute set to a value of "admin" and the 'role' attribute set to an appropriate value given the affiliation and room type.<br />
<br />
<br />
<br />
Example 168. Service Sends Notice of Administrative Privileges to All Occupants<br />
<br />
<br />
<br />
<presence<br />
<br />
from='darkcave@macbeth.shakespeare.lit/secondwitch'<br />
<br />
to='crone1@shakespeare.lit/desktop'><br />
<br />
<x xmlns='http://jabber.org/protocol/muc#user'><br />
<br />
<item affiliation='admin'<br />
<br />
jid='wiccarocks@shakespeare.lit/laptop'<br />
<br />
role='moderator'/><br />
<br />
</x><br />
<br />
</presence><br />
<br />
.<br />
<br />
.<br />
<br />
.<br />
<br />
<br />
<br />
<br />
<br />
10.7 Revoking Administrative Privileges<br />
<br />
<br />
<br />
An owner may want to revoke a user's administrative privileges; this is done by changing the user's affiliation to something other than "admin" or "owner":<br />
<br />
<br />
<br />
Example 169. Owner Revokes Administrative Privileges<br />
<br />
<br />
<br />
<iq from='crone1@shakespeare.lit/desktop'<br />
<br />
id='admin2'<br />
<br />
to='darkcave@macbeth.shakespeare.lit'<br />
<br />
type='set'><br />
<br />
<query xmlns='http://jabber.org/protocol/muc#admin'><br />
<br />
<item affiliation='member'<br />
<br />
jid='wiccarocks@shakespeare.lit'/><br />
<br />
</query><br />
<br />
</iq><br />
<br />
<br />
<br />
<br />
<br />
The service MUST remove the user from the admin list and then inform the owner of success:<br />
<br />
<br />
<br />
Example 170. Service Informs Owner of Success<br />
<br />
<br />
<br />
<iq from='darkcave@macbeth.shakespeare.lit'<br />
<br />
id='admin2'<br />
<br />
to='crone1@shakespeare.lit/desktop'<br />
<br />
type='result'/><br />
<br />
<br />
<br />
<br />
<br />
The service MUST then send updated presence from this individual to all occupants, indicating the loss of administrative privileges by sending a presence element that contains an <x/> element qualified by the 'http://jabber.org/protocol/muc#user' namespace and containing an <item/> child with the 'affiliation' attribute set to a value other than "admin" or "owner" and the 'role' attribute set to an appropriate value given the affiliation level and the room type:<br />
<br />
<br />
<br />
Example 171. Service Notes Loss of Admin Affiliation<br />
<br />
<br />
<br />
<presence<br />
<br />
from='darkcave@macbeth.shakespeare.lit/secondwitch'<br />
<br />
to='crone1@shakespeare.lit/desktop'><br />
<br />
<x xmlns='http://jabber.org/protocol/muc#user'><br />
<br />
<item affiliation='member'<br />
<br />
jid='wiccarocks@shakespeare.lit/laptop'<br />
<br />
role='participant'/><br />
<br />
</x><br />
<br />
</presence><br />
<br />
.<br />
<br />
.<br />
<br />
.<br />
<br />
<br />
<br />
<br />
<br />
10.8 Modifying the Admin List<br />
<br />
<br />
<br />
A room owner may want to modify the admin list. To do so, the owner first requests the admin list by querying the room for all users with an affiliation of 'admin'.<br />
<br />
<br />
<br />
Example 172. Owner Requests Admin List<br />
<br />
<br />
<br />
<iq from='bard@shakespeare.lit/desktopaffiliation<br />
<br />
id='admin3'<br />
<br />
to='darkcave@macbeth.shakespeare.lit'<br />
<br />
type='get'><br />
<br />
<query xmlns='http://jabber.org/protocol/muc#admin'><br />
<br />
<item affiliation='admin'/><br />
<br />
</query><br />
<br />
</iq><br />
<br />
<br />
<br />
<br />
<br />
If the <user@host> of the 'from' address does not match the bare JID of a room owner, the service MUST return a <forbidden/> error to the sender.<br />
<br />
<br />
<br />
Otherwise, the service MUST then return the admin list to the owner; each item MUST include the 'affiliation' and 'jid' attributes and MAY include the 'nick' and 'role' attributes for any admin that is currently an occupant:<br />
<br />
<br />
<br />
Example 173. Service Sends Admin List to Owner<br />
<br />
<br />
<br />
<iq from='darkcave@macbeth.shakespeare.lit'<br />
<br />
id='admin3'<br />
<br />
to='bard@shakespeare.lit/globe'<br />
<br />
type='result'><br />
<br />
<query xmlns='http://jabber.org/protocol/muc#admin'><br />
<br />
<item affiliation='admin'<br />
<br />
jid='wiccarocks@shakespeare.lit'<br />
<br />
nick='secondwitch'/><br />
<br />
<item affiliation='admin'<br />
<br />
jid='hag66@shakespeare.lit'/><br />
<br />
</query><br />
<br />
</iq><br />
<br />
<br />
<br />
<br />
<br />
The owner MAY then modify the admin list. In order to do so, the owner MUST send the changed items (i.e., only the "delta") back to the service; [21] each item MUST include the 'affiliation' attribute (normally set to a value of "admin" or "none") and 'jid' attribute but SHOULD NOT include the 'nick' attribute and MUST NOT include the 'role' attribute (which is used to manage roles such as participant rather than the admin affiliation):<br />
<br />
<br />
<br />
Example 174. Owner Sends Modified Admin List to Service<br />
<br />
<br />
<br />
<iq from='bard@shakespeare.lit/globe'<br />
<br />
id='admin4'<br />
<br />
to='darkcave@macbeth.shakespeare.lit'<br />
<br />
type='set'><br />
<br />
<query xmlns='http://jabber.org/protocol/muc#admin'><br />
<br />
<item affiliation='none'<br />
<br />
jid='hag66@shakespeare.lit'><br />
<br />
</item><br />
<br />
<item affiliation='admin'<br />
<br />
jid='hecate@shakespeare.lit'><br />
<br />
</item><br />
<br />
</query><br />
<br />
</iq><br />
<br />
<br />
<br />
<br />
<br />
Only owners shall be allowed to modify the admin list. If a non-owner attempts to view or modify the admin list, the service MUST deny the request and return a <forbidden/> error to the sender:<br />
<br />
<br />
<br />
Example 175. Service Returns Error on Attempt by Non-Owner to Modify Admin List<br />
<br />
<br />
<br />
<iq from='darkcave@macbeth.shakespeare.lit'<br />
<br />
id='admintest'<br />
<br />
to='hag66@shakespeare.lit/pda'<br />
<br />
type='error'><br />
<br />
<query xmlns='http://jabber.org/protocol/muc#admin'><br />
<br />
<item affiliation='admin' <br />
<br />
jid='hecate@shakespeare.lit'/><br />
<br />
</query><br />
<br />
<error code='403' type='auth'><br />
<br />
<forbidden xmlns='urn:ietf:params:xml:ns:xmpp-stanzas'/><br />
<br />
</error><br />
<br />
</iq><br />
<br />
<br />
<br />
<br />
<br />
Otherwise, the service MUST modify the admin list and then inform the owner of success:<br />
<br />
<br />
<br />
Example 176. Service Informs Owner of Success<br />
<br />
<br />
<br />
<iq from='darkcave@macbeth.shakespeare.lit'<br />
<br />
id='admin4'<br />
<br />
to='crone1@shakespeare.lit/desktop'<br />
<br />
type='result'/><br />
<br />
<br />
<br />
<br />
<br />
The service MUST also send presence notifications related to any affiliation changes that result from modifying the admin list as previously described.<br />
<br />
10.9 Destroying a Room<br />
<br />
<br />
<br />
A room owner MUST be able to destroy a room, especially if the room is persistent. The workflow is as follows:<br />
<br />
<br />
<br />
1.<br />
<br />
<br />
<br />
The room owner requests that the room be destroyed, specifying a reason and an alternate venue if desired.<br />
<br />
2.<br />
<br />
<br />
<br />
The room removes all users from the room (including appropriate information about the alternate location and the reason for being removed) and destroys the room, even if it was defined as persistent.<br />
<br />
<br />
<br />
Other than the foregoing, this document does not specify what (if anything) a MUC service implementation shall do as a result of a room destruction request. For example, if the room was defined as persistent, an implementation MAY choose to lock the room ID so that it cannot be re-used, redirect enter requests to the alternate venue, or invite the current participants to the new room; however, such behavior is OPTIONAL.<br />
<br />
<br />
<br />
In order to destroy a room, the room owner MUST send an IQ set to the address of the room to be destroyed. The <iq/> stanza shall contain a <query/> element qualified by the 'http://jabber.org/protocol/muc#owner' namespace, which in turn shall contain a <destroy/> element. The address of the alternate venue MAY be provided as the value of the <destroy/> element's 'jid' attribute. A password for the alternate venue MAY be provided as the XML character data of a <password/> child element of the <destroy/> element. The reason for the room destruction MAY be provided as the XML character data of a <reason/> child element of the <destroy/> element.<br />
<br />
<br />
<br />
The following examples illustrate the protocol elements to be sent and received:<br />
<br />
<br />
<br />
Example 177. Owner Submits Room Destruction Request<br />
<br />
<br />
<br />
<iq from='crone1@shakespeare.lit/desktop'<br />
<br />
id='begone'<br />
<br />
to='heath@macbeth.shakespeare.lit'<br />
<br />
type='set'><br />
<br />
<query xmlns='http://jabber.org/protocol/muc#owner'><br />
<br />
<destroy jid='darkcave@macbeth.shakespeare.lit'><br />
<br />
<reason>Macbeth doth come.</reason><br />
<br />
</destroy><br />
<br />
</query><br />
<br />
</iq><br />
<br />
<br />
<br />
<br />
<br />
The service is responsible for removing all the occupants. It SHOULD NOT broadcast presence stanzas of type "unavailable" from all occupants, instead sending only one presence stanza of type "unavailable" to each occupant so that the user knows he or she has been removed from the room. If extended presence information specifying the JID of an alternate location and the reason for the room destruction was provided by the room owner, the presence stanza MUST include that information.<br />
<br />
<br />
<br />
Example 178. Service Removes Each Occupant<br />
<br />
<br />
<br />
<presence<br />
<br />
from='heath@macbeth.shakespeare.lit/firstwitch'<br />
<br />
to='crone1@shakespeare.lit/desktop'<br />
<br />
type='unavailable'><br />
<br />
<x xmlns='http://jabber.org/protocol/muc#user'><br />
<br />
<item affiliation='none' role='none'/><br />
<br />
<destroy jid='darkcave@macbeth.shakespeare.lit'><br />
<br />
<reason>Macbeth doth come.</reason><br />
<br />
</destroy><br />
<br />
</x><br />
<br />
</presence><br />
<br />
<br />
<br />
<presence<br />
<br />
from='heath@macbeth.shakespeare.lit/secondwitch'<br />
<br />
to='wiccarocks@shakespeare.lit/laptop'<br />
<br />
type='unavailable'><br />
<br />
<x xmlns='http://jabber.org/protocol/muc#user'><br />
<br />
<item affiliation='none' role='none'/><br />
<br />
<destroy jid='darkcave@macbeth.shakespeare.lit'><br />
<br />
<reason>Macbeth doth come.</reason><br />
<br />
</destroy><br />
<br />
</x><br />
<br />
</presence><br />
<br />
<br />
<br />
<presence<br />
<br />
from='heath@macbeth.shakespeare.lit/thirdwitch'<br />
<br />
to='hag66@shakespeare.lit/pda'<br />
<br />
type='unavailable'><br />
<br />
<x xmlns='http://jabber.org/protocol/muc#user'><br />
<br />
<item affiliation='none' role='none'/><br />
<br />
<destroy jid='darkcave@macbeth.shakespeare.lit'><br />
<br />
<reason>Macbeth doth come.</reason><br />
<br />
</destroy><br />
<br />
</x><br />
<br />
</presence><br />
<br />
<br />
<br />
<br />
<br />
Example 179. Service Informs Owner of Successful Destruction<br />
<br />
<br />
<br />
<iq from='heath@macbeth.shakespeare.lit'<br />
<br />
id='begone'<br />
<br />
to='crone1@shakespeare.lit/desktop'<br />
<br />
type='result'/><br />
<br />
<br />
<br />
<br />
<br />
If the <user@host> of the 'from' address received on a destroy request does not match the bare JID of a room owner, the service MUST return a <forbidden/> error to the sender:<br />
<br />
<br />
<br />
Example 180. Service Denies Destroy Request Submitted by Non-Owner<br />
<br />
<br />
<br />
<iq from='heath@macbeth.shakespeare.lit'<br />
<br />
id='destroytest'<br />
<br />
to='wiccarocks@shakespeare.lit/laptop'<br />
<br />
type='error'><br />
<br />
<query xmlns='http://jabber.org/protocol/muc#owner'><br />
<br />
<destroy jid='darkcave@macbeth.shakespeare.lit'><br />
<br />
<reason>Macbeth doth come.</reason><br />
<br />
</destroy><br />
<br />
</query><br />
<br />
<error code='403' type='auth'><br />
<br />
<forbidden xmlns='urn:ietf:params:xml:ns:xmpp-stanzas'/><br />
<br />
</error><br />
<br />
</iq><br />
<br />
<br />
<br />
<br />
<br />
11. Error and Status Codes<br />
<br />
11.1 Error Codes<br />
<br />
<br />
<br />
The error codes associated with the 'http://jabber.org/protocol/muc#user' namespace are fairly straightforward, as summarized in the following table. For detailed information about mapping legacy error codes to XMPP-style error types and conditions, refer to Error Condition Mappings [22]; implementations SHOULD support both legacy and XMPP error handling.<br />
<br />
<br />
<br />
Table 8: Error Codes for http://jabber.org/protocol/muc#user Namespace<br />
<br />
Code Type Element Context Purpose<br />
<br />
401 Error Presence Entering a room Inform user that a password is required<br />
<br />
403 Error Presence Entering a room Inform user that he or she is banned from the room<br />
<br />
404 Error Presence Entering a room Inform user that the room does not exist<br />
<br />
405 Error Presence Entering a room Inform user that room creation is restricted<br />
<br />
406 Error Presence Entering a room Inform user that the reserved roomnick must be used<br />
<br />
407 Error Presence Entering a room Inform user that he or she is not on the member list<br />
<br />
409 Error Presence Entering a room Inform user that his or her desired room nickname is in use or registered by another user<br />
<br />
503 Error Presence Entering a room Inform user that the maximum number of users has been reached<br />
<br />
<br />
<br />
This document does not stipulate text strings (i.e., values of the XMPP <text/> element) associated with the foregoing error conditions.<br />
<br />
11.2 Status Codes<br />
<br />
<br />
<br />
Multi-User Chat uses a <status/> element (specifically, the 'code' attribute of the <status/> element) to communicate information about a user's status in a room. Over time, the number of status codes has grown quite large, and new status codes continue to be requested of the author. Therefore, these codes are now documented in a registry maintained by the XMPP Registrar. For details, refer to the Status Codes Registry section of this document.<br />
<br />
<br />
<br />
Note: In general, MUC status codes tend to follow the "philosophy" of status codes that is implicit in RFC 2616 [23] and RFC 1893 [24] (1xx codes are informational, 2xx codes specify that it is fine to continue, 3xx codes specify redirects such as being kicked or banned, x3x codes refer to system status, x7x codes refer to security or policy matters, etc.).<br />
<br />
<br />
<br />
Note: If the MUC protocol were being designed today, it would specify a more flexible, XML-friendly approach rather than hardcoded status numbers; however, at this point the pain of changing the status reporting system would be greater than the benefit of doing so, which is why the status code numbers remain in use. A future version of this document may define a more XMPP-like approach to status conditions, retaining the code numbers but supplementing them with more descriptive child elements as is done in RFC 3920.<br />
<br />
12. Internationalization Considerations<br />
<br />
<br />
<br />
As specified in RFC 3920, XMPP entities (including MUC rooms and MUC services) SHOULD respect the value of the 'xml:lang' attribute provided with any given stanza. However, simultaneous translation of groupchat messages is out of scope for this document.<br />
<br />
<br />
<br />
The status and error codes defined herein enable a client implementation to present a localized interface; however, definition of the localized text strings for any given language community is out of scope for this document.<br />
<br />
<br />
<br />
Although the labels for various data form fields are shown here in English, MUC clients SHOULD present localized text for these fields rather than the English text.<br />
<br />
13. Security Considerations<br />
<br />
13.1 User Authentication and Authorization<br />
<br />
<br />
<br />
No room entrance authentication or authorization method more secure than cleartext passwords is defined or required by this document. However, the risks involved can mitigated by the use of channel encryption and strong authentication via TLS and SASL as described in RFC 3920.<br />
<br />
13.2 End-to-End Encryption<br />
<br />
<br />
<br />
No end-to-end message or session encryption method is specified herein. Users SHOULD NOT trust a service to keep secret any text sent through a room.<br />
<br />
13.3 Privacy<br />
<br />
<br />
<br />
Depending on room configuration, a room may publicly log all discussions held in the room. A service MUST warn the user that the room is publicly logged by returning a status code of "170" with the user's initial presence, and user's the client MUST so warn the user if the room discussion is logged (a user's client SHOULD also query the room for its configuration prior to allowing the user to enter in order to "pre-discover" whether the room is logged). A client MUST also warn the user if the room's configuration is subsequently modified to allow room logging (which the client will discover when the room sends status code 170). Note: In-room history is different from public room logging, and naturally a room cannot effectively prevent occupants from separately maintaining their own room logs, which may become public; users SHOULD exercise due caution and consider any room discussions to be effectively public.<br />
<br />
13.4 Anonymity<br />
<br />
<br />
<br />
Depending on room configuration, a room MAY expose each occupant's real JID to other occupants (if the room is non-anonymous) and will almost certainly expose each occupant's real JID to the room owners and administrators (if the room is not fully-anonymous). A service MUST warn the user that real JIDs are exposed in the room by returning a status code of "100" with the user's initial presence, and the user's client MUST so warn the user (a user's client SHOULD also query the room for its configuration prior to allowing the user to enter in order to "pre-discover" whether real JIDs are exposed in the room). A client MUST also warn the user if the room's configuration is subsequently modified from semi-anonymous or fully-anonymous to non-anonymous (which the client will discover when the room sends status code 172) and SHOULD warn the user if the room's configuration is subsequently modified from fully-anonymous to semi-anonymous (which the client will discover when the room sends status code 173).<br />
<br />
14. IANA Considerations<br />
<br />
<br />
<br />
This document requires no interaction with the Internet Assigned Numbers Authority (IANA) [25].<br />
<br />
15. XMPP Registrar Considerations<br />
<br />
<br />
<br />
The XMPP Registrar [26] includes the following information in its registries.<br />
<br />
15.1 Protocol Namespaces<br />
<br />
<br />
<br />
The XMPP Registrar includes the following MUC-related namespaces in its registry of protocol namespaces:<br />
<br />
<br />
<br />
* http://jabber.org/protocol/muc<br />
<br />
* http://jabber.org/protocol/muc#admin<br />
<br />
* http://jabber.org/protocol/muc#owner<br />
<br />
* http://jabber.org/protocol/muc#unique<br />
<br />
* http://jabber.org/protocol/muc#user<br />
<br />
<br />
<br />
15.2 Service Discovery Category/Type<br />
<br />
<br />
<br />
A Multi-User Chat service or room is identified by the "conference" category and the "text" type within Service Discovery.<br />
<br />
15.3 Service Discovery Features<br />
<br />
<br />
<br />
There are many features related to a MUC service or room that can be discovered by means of Service Discovery. The most fundamental of these is the 'http://jabber.org/protocol/muc' namespace. In addition, a MUC room SHOULD provide information about the specific room features it implements, such as password protection and room moderation.<br />
<br />
<br />
<br />
Registry Submission<br />
<br />
<br />
<br />
<var><br />
<br />
<name>http://jabber.org/protocol/muc#register</name><br />
<br />
<desc>Support for the muc#register FORM_TYPE</desc><br />
<br />
<doc>XEP-0045</doc><br />
<br />
</var><br />
<br />
<var><br />
<br />
<name>http://jabber.org/protocol/muc#roomconfig</name><br />
<br />
<desc>Support for the muc#roomconfig FORM_TYPE</desc><br />
<br />
<doc>XEP-0045</doc><br />
<br />
</var><br />
<br />
<var><br />
<br />
<name>http://jabber.org/protocol/muc#roominfo</name><br />
<br />
<desc>Support for the muc#roominfo FORM_TYPE</desc><br />
<br />
<doc>XEP-0045</doc><br />
<br />
</var><br />
<br />
<var><br />
<br />
<name>muc_hidden</name><br />
<br />
<desc>Hidden room in Multi-User Chat (MUC)</desc><br />
<br />
<doc>XEP-0045</doc><br />
<br />
</var><br />
<br />
<var><br />
<br />
<name>muc_membersonly</name><br />
<br />
<desc>Members-only room in Multi-User Chat (MUC)</desc><br />
<br />
<doc>XEP-0045</doc><br />
<br />
</var><br />
<br />
<var><br />
<br />
<name>muc_moderated</name><br />
<br />
<desc>Moderated room in Multi-User Chat (MUC)</desc><br />
<br />
<doc>XEP-0045</doc><br />
<br />
</var><br />
<br />
<var><br />
<br />
<name>muc_nonanonymous</name><br />
<br />
<desc>Non-anonymous room in Multi-User Chat (MUC)</desc><br />
<br />
<doc>XEP-0045</doc><br />
<br />
</var><br />
<br />
<var><br />
<br />
<name>muc_open</name><br />
<br />
<desc>Open room in Multi-User Chat (MUC)</desc><br />
<br />
<doc>XEP-0045</doc><br />
<br />
</var><br />
<br />
<var><br />
<br />
<name>muc_passwordprotected</name><br />
<br />
<desc>Password-protected room in Multi-User Chat (MUC)</desc><br />
<br />
<doc>XEP-0045</doc><br />
<br />
</var><br />
<br />
<var><br />
<br />
<name>muc_persistent</name><br />
<br />
<desc>Persistent room in Multi-User Chat (MUC)</desc><br />
<br />
<doc>XEP-0045</doc><br />
<br />
</var><br />
<br />
<var><br />
<br />
<name>muc_public</name><br />
<br />
<desc>Public room in Multi-User Chat (MUC)</desc><br />
<br />
<doc>XEP-0045</doc><br />
<br />
</var><br />
<br />
<var><br />
<br />
<name>muc_rooms</name><br />
<br />
<desc>List of MUC rooms (each as a separate item)</desc><br />
<br />
<doc>XEP-0045</doc><br />
<br />
</var><br />
<br />
<var><br />
<br />
<name>muc_semianonymous</name><br />
<br />
<desc>Semi-anonymous room in Multi-User Chat (MUC)</desc><br />
<br />
<doc>XEP-0045</doc><br />
<br />
</var><br />
<br />
<var><br />
<br />
<name>muc_temporary</name><br />
<br />
<desc>Temporary room in Multi-User Chat (MUC)</desc><br />
<br />
<doc>XEP-0045</doc><br />
<br />
</var><br />
<br />
<var><br />
<br />
<name>muc_unmoderated</name><br />
<br />
<desc>Unmoderated room in Multi-User Chat (MUC)</desc><br />
<br />
<doc>XEP-0045</doc><br />
<br />
</var><br />
<br />
<var><br />
<br />
<name>muc_unsecured</name><br />
<br />
<desc>Unsecured room in Multi-User Chat (MUC)</desc><br />
<br />
<doc>XEP-0045</doc><br />
<br />
</var><br />
<br />
<br />
<br />
<br />
<br />
15.4 Well-Known Service Discovery Nodes<br />
<br />
<br />
<br />
The well-known Service Discovery node 'http://jabber.org/protocol/muc#rooms' enables discovery of the rooms in which a user is an occupant.<br />
<br />
<br />
<br />
The well-known Service Discovery node 'x-roomuser-item' enables a user to discover his or her registered roomnick from outside the room.<br />
<br />
<br />
<br />
The well-known Service Discovery node 'http://jabber.org/protocol/muc#traffic' enables discovery of the namespaces that are allowed in traffic sent through a room (see the Allowable Traffic section of this document).<br />
<br />
15.5 Field Standardization<br />
<br />
<br />
<br />
Field Standardization for Data Forms [27] defines a process for standardizing the fields used within Data Forms qualified by a particular namespace. Within MUC, there are four uses of such forms: room registration (the "muc#register" FORM_TYPE), requesting voice and approving voice requests ("muc#request"), room configuration ("muc#roomconfig"), and service discovery extensions for room information ("muc#roominfo"). The reserved fields are defined below.<br />
<br />
15.5.1 muc#register FORM_TYPE<br />
<br />
<br />
<br />
Registry Submission<br />
<br />
<br />
<br />
<form_type><br />
<br />
<name>http://jabber.org/protocol/muc#register</name><br />
<br />
<doc>XEP-0045</doc><br />
<br />
<desc><br />
<br />
Forms enabling user registration with a<br />
<br />
Multi-User Chat (MUC) room or admin approval<br />
<br />
of user registration requests.<br />
<br />
</desc><br />
<br />
<field <br />
<br />
var='muc#register_allow'<br />
<br />
type='boolean'<br />
<br />
label='Allow this person to register with the room?'/><br />
<br />
<field<br />
<br />
var='muc#register_email'<br />
<br />
type='text-single'<br />
<br />
label='Email Address'/><br />
<br />
<field<br />
<br />
var='muc#register_faqentry'<br />
<br />
type='text-multi'<br />
<br />
label='FAQ Entry'/><br />
<br />
<field<br />
<br />
var='muc#register_first'<br />
<br />
type='text-single'<br />
<br />
label='First Name'/><br />
<br />
<field<br />
<br />
var='muc#register_last'<br />
<br />
type='text-single'<br />
<br />
label='Last Name'/><br />
<br />
<field<br />
<br />
var='muc#register_roomnick'<br />
<br />
type='text-single'<br />
<br />
label='Desired Nickname'/><br />
<br />
<field<br />
<br />
var='muc#register_url'<br />
<br />
type='text-single'<br />
<br />
label='Your URL'/><br />
<br />
</form_type><br />
<br />
<br />
<br />
<br />
<br />
15.5.2 muc#request FORM_TYPE<br />
<br />
<br />
<br />
Registry Submission<br />
<br />
<br />
<br />
<form_type><br />
<br />
<name>http://jabber.org/protocol/muc#request</name><br />
<br />
<doc>XEP-0045</doc><br />
<br />
<desc><br />
<br />
Forms enabling voice requests in a <br />
<br />
Multi-User Chat (MUC) room or admin<br />
<br />
approval of such requests.<br />
<br />
</desc><br />
<br />
<field var='muc#role'<br />
<br />
type='text-single'<br />
<br />
label='Requested role'/><br />
<br />
<field var='muc#jid'<br />
<br />
type='text-single'<br />
<br />
label='User ID'/><br />
<br />
<field var='muc#roomnick'<br />
<br />
type='text-single'<br />
<br />
label='Room Nickname'/><br />
<br />
<field var='muc#request_allow'<br />
<br />
type='boolean'<br />
<br />
label='Whether to grant voice'/><br />
<br />
</form_type><br />
<br />
<br />
<br />
<br />
<br />
15.5.3 muc#roomconfig FORM_TYPE<br />
<br />
<br />
<br />
Registry Submission<br />
<br />
<br />
<br />
<form_type><br />
<br />
<name>http://jabber.org/protocol/muc#roomconfig</name><br />
<br />
<doc>XEP-0045</doc><br />
<br />
<desc><br />
<br />
Forms enabling creation and configuration of<br />
<br />
a Multi-User Chat (MUC) room.<br />
<br />
</desc><br />
<br />
<field<br />
<br />
var='muc#roomconfig_allowinvites'<br />
<br />
type='boolean'<br />
<br />
label='Whether to Allow Occupants to Invite Others'/><br />
<br />
<field<br />
<br />
var='muc#roomconfig_changesubject'<br />
<br />
type='boolean'<br />
<br />
label='Whether to Allow Occupants to Change Subject'/><br />
<br />
<field<br />
<br />
var='muc#roomconfig_enablelogging'<br />
<br />
type='boolean'<br />
<br />
label='Whether to Enable Public Logging of Room Conversations'/><br />
<br />
<field<br />
<br />
var='muc#roomconfig_lang'<br />
<br />
type='text-single'<br />
<br />
label='Natural Language for Room Discussions'/><br />
<br />
<field<br />
<br />
var='muc#roomconfig_pubsub'<br />
<br />
type='text-single'<br />
<br />
label='XMPP URI of Associated Publish-Subcribe Node'/><br />
<br />
<field<br />
<br />
var='muc#roomconfig_maxusers'<br />
<br />
type='list-single'<br />
<br />
label='Maximum Number of Room Occupants'/><br />
<br />
<field<br />
<br />
var='muc#roomconfig_membersonly'<br />
<br />
type='boolean'<br />
<br />
label='Whether an Make Room Members-Only'/><br />
<br />
<field<br />
<br />
var='muc#roomconfig_moderatedroom'<br />
<br />
type='boolean'<br />
<br />
label='Whether to Make Room Moderated'/><br />
<br />
<field<br />
<br />
var='muc#roomconfig_passwordprotectedroom'<br />
<br />
type='boolean'<br />
<br />
label='Whether a Password is Required to Enter'/><br />
<br />
<field<br />
<br />
var='muc#roomconfig_persistentroom'<br />
<br />
type='boolean'<br />
<br />
label='Whether to Make Room Persistent'/><br />
<br />
<field<br />
<br />
var='muc#roomconfig_presencebroadcast'<br />
<br />
type='list-multi'<br />
<br />
label='Roles for which Presence is Broadcast'/><br />
<br />
<field<br />
<br />
var='muc#roomconfig_publicroom'<br />
<br />
type='boolean'<br />
<br />
label='Whether to Allow Public Searching for Room'/><br />
<br />
<field<br />
<br />
var='muc#roomconfig_roomadmins'<br />
<br />
type='jid-multi'<br />
<br />
label='Full List of Room Admins'/><br />
<br />
<field<br />
<br />
var='muc#roomconfig_roomdesc'<br />
<br />
type='text-single'<br />
<br />
label='Short Description of Room'/><br />
<br />
<field<br />
<br />
var='muc#roomconfig_roomname'<br />
<br />
type='text-single'<br />
<br />
label='Natural-Language Room Name'/><br />
<br />
<field<br />
<br />
var='muc#roomconfig_roomowners'<br />
<br />
type='jid-multi'<br />
<br />
label='Full List of Room Owners'/><br />
<br />
<field<br />
<br />
var='muc#roomconfig_roomsecret'<br />
<br />
type='text-private'<br />
<br />
label='The Room Password'/><br />
<br />
<field<br />
<br />
var='muc#roomconfig_whois'<br />
<br />
type='list-single'<br />
<br />
label='Affiliations that May Discover Real JIDs of Occupants'/><br />
<br />
</form_type><br />
<br />
<br />
<br />
<br />
<br />
15.5.4 muc#roominfo FORM_TYPE<br />
<br />
<br />
<br />
Registry Submission<br />
<br />
<br />
<br />
<form_type><br />
<br />
<name>http://jabber.org/protocol/muc#roominfo</name><br />
<br />
<doc>XEP-0045</doc><br />
<br />
<desc><br />
<br />
Forms enabling the communication of extended service discovery<br />
<br />
information about a Multi-User Chat (MUC) room.<br />
<br />
</desc><br />
<br />
<field<br />
<br />
var='muc#roominfo_contactjid'<br />
<br />
type='jid-multi'<br />
<br />
label='Contact Addresses (normally, room owner or owners)'/><br />
<br />
<field<br />
<br />
var='muc#roominfo_description'<br />
<br />
type='text-single'<br />
<br />
label='Short Description of Room'/><br />
<br />
<field<br />
<br />
var='muc#roominfo_lang'<br />
<br />
type='text-single'<br />
<br />
label='Natural Language for Room Discussions'/><br />
<br />
<field<br />
<br />
var='muc#roominfo_logs'<br />
<br />
type='text-single'<br />
<br />
label='URL for Archived Discussion Logs'/><br />
<br />
<field<br />
<br />
var='muc#roominfo_occupants'<br />
<br />
type='text-single'<br />
<br />
label='Current Number of Occupants in Room'/><br />
<br />
<field<br />
<br />
var='muc#roominfo_subject'<br />
<br />
type='text-single'<br />
<br />
label='Current Subject or Discussion Topic in Room'/><br />
<br />
</form_type><br />
<br />
<br />
<br />
<br />
<br />
15.6 Status Codes Registry<br />
<br />
15.6.1 Process<br />
<br />
<br />
<br />
The XMPP Registrar maintains a registry of values for the 'code' attribute of the <status/> element when qualified by the 'http://jabber.org/protocol/muc#user' namespace.<br />
<br />
<br />
<br />
In order to submit new values to this registry, the registrant must define an XML fragment of the following form and either include it in the relevant XMPP Extension Protocol or send it to the email address <registrar@xmpp.org>:<br />
<br />
<br />
<br />
<statuscode><br />
<br />
<number>the three-digit code number</number><br />
<br />
<stanza>the stanza type of which it is a child (message or presence)</desc><br />
<br />
<context>the use case or situation in which the status is used</context><br />
<br />
<purpose>a natural-language description of the meaning</purpose><br />
<br />
<child>the descriptive child element (reserved for future use)</child><br />
<br />
</statuscode><br />
<br />
<br />
<br />
<br />
<br />
The registrant may register more than one status code at a time, each contained in a separate <statuscode/> element.<br />
<br />
15.6.2 Initial Submission<br />
<br />
<br />
<br />
As part of this document, the following status codes are registered:<br />
<br />
<br />
<br />
<statuscode><br />
<br />
<number>100</number><br />
<br />
<stanza>message or presence</stanza><br />
<br />
<context>Entering a room</context><br />
<br />
<purpose>Inform user that any occupant is allowed to see the user's full JID</purpose><br />
<br />
</statuscode><br />
<br />
<statuscode><br />
<br />
<number>101</number><br />
<br />
<stanza>message (out of band)</stanza><br />
<br />
<context>Affiliation change</context><br />
<br />
<purpose>Inform user that his or her affiliation changed while not in the room</purpose><br />
<br />
</statuscode><br />
<br />
<statuscode><br />
<br />
<number>102</number><br />
<br />
<stanza>message</stanza><br />
<br />
<context>Configuration change</context><br />
<br />
<purpose>Inform occupants that room now shows unavailable members</purpose><br />
<br />
</statuscode><br />
<br />
<statuscode><br />
<br />
<number>103</number><br />
<br />
<stanza>message</stanza><br />
<br />
<context>Configuration change</context><br />
<br />
<purpose>Inform occupants that room now does not show unavailable members</purpose><br />
<br />
</statuscode><br />
<br />
<statuscode><br />
<br />
<number>104</number><br />
<br />
<stanza>message</stanza><br />
<br />
<context>Configuration change</context><br />
<br />
<purpose><br />
<br />
Inform occupants that a non-privacy-related room configuration change has occurred<br />
<br />
</purpose><br />
<br />
</statuscode><br />
<br />
<statuscode><br />
<br />
<number>110</number><br />
<br />
<stanza>presence</stanza><br />
<br />
<context>Any room presence</context><br />
<br />
<purpose>Inform user that presence refers to one of its own room occupants</purpose><br />
<br />
</statuscode><br />
<br />
<statuscode><br />
<br />
<number>170</number><br />
<br />
<stanza>message or initial presence</stanza><br />
<br />
<context>Configuration change</context><br />
<br />
<purpose>Inform occupants that room logging is now enabled</purpose><br />
<br />
</statuscode><br />
<br />
<statuscode><br />
<br />
<number>171</number><br />
<br />
<stanza>message</stanza><br />
<br />
<context>Configuration change</context><br />
<br />
<purpose>Inform occupants that room logging is now disabled</purpose><br />
<br />
</statuscode><br />
<br />
<statuscode><br />
<br />
<number>172</number><br />
<br />
<stanza>message</stanza><br />
<br />
<context>Configuration change</context><br />
<br />
<purpose>Inform occupants that the room is now non-anonymous</purpose><br />
<br />
</statuscode><br />
<br />
<statuscode><br />
<br />
<number>173</number><br />
<br />
<stanza>message</stanza><br />
<br />
<context>Configuration change</context><br />
<br />
<purpose>Inform occupants that the room is now semi-anonymous</purpose><br />
<br />
</statuscode><br />
<br />
<statuscode><br />
<br />
<number>174</number><br />
<br />
<stanza>message</stanza><br />
<br />
<context>Configuration change</context><br />
<br />
<purpose>Inform occupants that the room is now fully-anonymous</purpose><br />
<br />
</statuscode><br />
<br />
<statuscode><br />
<br />
<number>201</number><br />
<br />
<stanza>presence</stanza><br />
<br />
<context>Entering a room</context><br />
<br />
<purpose>Inform user that a new room has been created</purpose><br />
<br />
</statuscode><br />
<br />
<statuscode><br />
<br />
<number>210</number><br />
<br />
<stanza>presence</stanza><br />
<br />
<context>Entering a room</context><br />
<br />
<purpose>Inform user that service has assigned or modified occupant's roomnick</purpose><br />
<br />
</statuscode><br />
<br />
<statuscode><br />
<br />
<number>301</number><br />
<br />
<stanza>presence</stanza><br />
<br />
<context>Removal from room</context><br />
<br />
<purpose>Inform user that he or she has been banned from the room</purpose><br />
<br />
</statuscode><br />
<br />
<statuscode><br />
<br />
<number>303</number><br />
<br />
<stanza>presence</stanza><br />
<br />
<context>Exiting a room</context><br />
<br />
<purpose>Inform all occupants of new room nickname</purpose><br />
<br />
</statuscode><br />
<br />
<statuscode><br />
<br />
<number>307</number><br />
<br />
<stanza>presence</stanza><br />
<br />
<context>Removal from room</context><br />
<br />
<purpose>Inform user that he or she has been kicked from the room</purpose><br />
<br />
</statuscode><br />
<br />
<statuscode><br />
<br />
<number>321</number><br />
<br />
<stanza>presence</stanza><br />
<br />
<context>Removal from room</context><br />
<br />
<purpose>Inform user that he or she is being removed from the room <br />
<br />
because of an affiliation change</purpose><br />
<br />
</statuscode><br />
<br />
<statuscode><br />
<br />
<number>322</number><br />
<br />
<stanza>presence</stanza><br />
<br />
<context>Removal from room</context><br />
<br />
<purpose>Inform user that he or she is being removed from the room <br />
<br />
because the room has been changed to members-only and the user <br />
<br />
is not a member</purpose><br />
<br />
</statuscode><br />
<br />
<statuscode><br />
<br />
<number>332</number><br />
<br />
<stanza>presence</stanza><br />
<br />
<context>Removal from room</context><br />
<br />
<purpose>Inform user that he or she is being removed from the room <br />
<br />
because of a system shutdown</purpose><br />
<br />
</statuscode><br />
<br />
<br />
<br />
<br />
<br />
15.7 URI Query Types<br />
<br />
<br />
<br />
As authorized by XMPP URI Query Components [28], the XMPP Registrar maintains a registry of queries and key-value pairs for use in XMPP URIs (see <http://www.xmpp.org/registrar/querytypes.html>).<br />
<br />
15.7.1 join<br />
<br />
<br />
<br />
The "join" querytype is registered as a MUC-related action, with an optional key of "password".<br />
<br />
<br />
<br />
Example 181. Join Action: IRI/URI<br />
<br />
<br />
<br />
xmpp:darkcave@macbeth.shakespeare.lit?join<br />
<br />
<br />
<br />
<br />
<br />
The application MUST either present an interface enabling the user to provide a room nickname or populate the room nickname based on configured preferences or nickname discovery.<br />
<br />
<br />
<br />
Example 182. Join Action: Resulting Stanza<br />
<br />
<br />
<br />
<presence to='darkcave@macbeth.shakespeare.lit/thirdwitch'><br />
<br />
<x xmlns='http://jabber.org/protocol/muc'/><br />
<br />
</presence><br />
<br />
<br />
<br />
<br />
<br />
The join action MAY include a password for the room. Naturally, access to a URI that includes a room password MUST be appropriately controlled.<br />
<br />
<br />
<br />
Example 183. Join Action with Password: IRI/URI<br />
<br />
<br />
<br />
xmpp:darkcave@macbeth.shakespeare.lit?join;password=cauldronburn<br />
<br />
<br />
<br />
<br />
<br />
Example 184. Join Action with Password: Resulting Stanza<br />
<br />
<br />
<br />
<presence to='darkcave@macbeth.shakespeare.lit/thirdwitch'><br />
<br />
<x xmlns='http://jabber.org/protocol/muc'><br />
<br />
<password>cauldronburn</password><br />
<br />
</x><br />
<br />
</presence><br />
<br />
<br />
<br />
<br />
<br />
The following submission registers the "join" querytype.<br />
<br />
<br />
<br />
<querytype><br />
<br />
<name>join</name><br />
<br />
<proto>http://jabber.org/protocol/muc</proto><br />
<br />
<desc>enables joining a multi-user chat room</desc><br />
<br />
<doc>XEP-0045</doc><br />
<br />
<keys><br />
<br />
<key><br />
<br />
<name>password</name><br />
<br />
<desc>the password required to enter a multi-user chat room</desc><br />
<br />
</key><br />
<br />
</keys><br />
<br />
</querytype><br />
<br />
<br />
<br />
<br />
<br />
15.7.2 invite<br />
<br />
<br />
<br />
The "invite" querytype is registered as a MUC-related action, with an optional key of "jid".<br />
<br />
<br />
<br />
Example 185. Invite Action: IRI/URI<br />
<br />
<br />
<br />
xmpp:darkcave@macbeth.shakespeare.lit?invite;jid=hecate@shakespeare.lit<br />
<br />
<br />
<br />
<br />
<br />
If the joining user is not yet in the room, the application MUST send two stanzas: the first to join the room and the second to invite the other individual. If the joining user is in the room already, the application shall send only the invitation stanza.<br />
<br />
<br />
<br />
Example 186. Invite Action: Resulting Stanza(s)<br />
<br />
<br />
<br />
<presence to='darkcave@macbeth.shakespeare.lit/thirdwitch'><br />
<br />
<x xmlns='http://jabber.org/protocol/muc'/><br />
<br />
</presence><br />
<br />
<br />
<br />
<message to='darkcave@macbeth.shakespeare.lit'><br />
<br />
<x xmlns='http://jabber.org/protocol/muc#user'><br />
<br />
<invite to='hecate@shakespeare.lit'/><br />
<br />
</x><br />
<br />
</message><br />
<br />
<br />
<br />
<br />
<br />
The URI may include multiple invitees:<br />
<br />
<br />
<br />
Example 187. Invite Action With Multiple Invitees: IRI/URI<br />
<br />
<br />
<br />
xmpp:darkcave@macbeth.shakespeare.lit?invite;jid=hecate@shakespeare.lit;jid=bard@shakespeare.lit<br />
<br />
<br />
<br />
<br />
<br />
Example 188. Invite Action With Multiple Invitees: Resulting Stanza<br />
<br />
<br />
<br />
<message to='darkcave@macbeth.shakespeare.lit'><br />
<br />
<x xmlns='http://jabber.org/protocol/muc#user'><br />
<br />
<invite to='hecate@shakespeare.lit'/><br />
<br />
<invite to='bard@shakespeare.lit'/><br />
<br />
</x><br />
<br />
</message><br />
<br />
<br />
<br />
<br />
<br />
The URI may also include a password:<br />
<br />
<br />
<br />
Example 189. Invite Action With Password: IRI/URI<br />
<br />
<br />
<br />
xmpp:darkcave@macbeth.shakespeare.lit?invite;jid=hecate@shakespeare.lit;password=cauldronburn<br />
<br />
<br />
<br />
<br />
<br />
If the joining user is not yet in the room, the application MUST send two stanzas: the first to join the room and the second to invite the other individual. If the joining user is in the room already, the application shall send only the invitation stanza.<br />
<br />
<br />
<br />
Example 190. Invite Action With Password: Resulting Stanza(s)<br />
<br />
<br />
<br />
<presence to='darkcave@macbeth.shakespeare.lit/thirdwitch'><br />
<br />
<x xmlns='http://jabber.org/protocol/muc'/><br />
<br />
</presence><br />
<br />
<br />
<br />
<message to='darkcave@macbeth.shakespeare.lit'><br />
<br />
<x xmlns='http://jabber.org/protocol/muc#user'><br />
<br />
<invite to='hecate@shakespeare.lit'><br />
<br />
<password>cauldronburn</password><br />
<br />
</invite><br />
<br />
</x><br />
<br />
</message><br />
<br />
<br />
<br />
<br />
<br />
<br />
<br />
The following submission registers the "invite" querytype.<br />
<br />
<br />
<br />
<querytype><br />
<br />
<name>invite</name><br />
<br />
<proto>http://jabber.org/protocol/muc</proto><br />
<br />
<desc>enables simultaneously joining a groupchat room and inviting others</desc><br />
<br />
<doc>XEP-0045</doc><br />
<br />
<keys><br />
<br />
<key><br />
<br />
<name>jid</name><br />
<br />
<desc>the Jabber ID of the invitee</desc><br />
<br />
</key><br />
<br />
<key><br />
<br />
<name>password</name><br />
<br />
<desc>the password required to enter a multi-user chat room</desc><br />
<br />
</key><br />
<br />
</keys><br />
<br />
</querytype><br />
<br />
<br />
<br />
<br />
<br />
16. Business Rules<br />
<br />
16.1 Addresses<br />
<br />
<br />
<br />
In order to provide consistency regarding the addresses captured in room JIDs, Room IDs MUST match the Nodeprep profile of Stringprep and Room Nicknames MUST match the Resourceprep profile of Stringprep (both of these are defined in RFC 3920). Although not explicitly stated in RFC 3920, both the Room ID (node) and Room Nickname (resource) portions of a Room JID MUST be of non-zero length. In addition, a MUC service MUST NOT allow empty or invisible Room Nicknames (i.e., Room Nicknames that consist only of one or more space characters).<br />
<br />
16.2 Message<br />
<br />
<br />
<br />
1.<br />
<br />
<br />
<br />
If an occupant wants to send a message to all other occupants, a MUC client MUST set the 'type' attribute to a value of "groupchat". A service MAY ignore messages that are improperly typed, or reject them with a <bad-request/> error.<br />
<br />
2.<br />
<br />
<br />
<br />
If a MUC service receives a message directed to the room or to a single occupant from a Jabber user who has a role of "none", the service MUST NOT deliver the message and SHOULD return the message to the sender with a <forbidden/> error.<br />
<br />
3.<br />
<br />
<br />
<br />
If a MUC service receives a message directed to a room that does not exist or is not yet unlocked, the service SHOULD return the message to the sender with an <item-not-found/> error.<br />
<br />
4.<br />
<br />
<br />
<br />
A MUC service SHOULD pass extended information (e.g., an XHTML version of the message body) through to occupants unchanged; however, a MUC service MAY disallow message specific extensions (see the Allowable Traffic section of this document).<br />
<br />
5.<br />
<br />
<br />
<br />
A MUC client MAY generate extensions that conform to the Message Events [29] or Chat State Notifications [30] specification; however, a MUC service MAY disallow these extensions (see the Allowable Traffic section of this document).<br />
<br />
<br />
<br />
16.3 Presence<br />
<br />
<br />
<br />
1.<br />
<br />
<br />
<br />
A room MUST silently ignore unavailable presence received from a user who has a role of "none".<br />
<br />
2.<br />
<br />
<br />
<br />
Only the MUC service itself SHOULD generate extended presence information about roles, affiliations, full JIDs, or status codes qualified by the 'http://jabber.org/protocol/muc#user' namespace (based on information the service knows about occupants, e.g., roles, or as a result of actions taken by a moderator or room administrator). A client SHOULD NOT presume to generate such information. If a MUC service receives such extended presence information from an occupant, it MUST NOT reflect it to other occupants. (A client MAY generate extended presence information qualified by the 'http://jabber.org/protocol/muc#user' namespace in order to supply a password, but naturally this is not reflected to other occupants.)<br />
<br />
3.<br />
<br />
<br />
<br />
A MUC service SHOULD allow all other presence information to pass through, although it MAY choose to block extended presence information; see the Allowable Traffic section of this document.<br />
<br />
4.<br />
<br />
<br />
<br />
In order to appropriately inform occupants of room roles and affiliations, and to make it easier for Jabber clients to track the current state of all users in the room, MUC service implementations MUST provide extended presence information about roles and affiliations in all presence stanzas, including presence stanzas of type "unavailable" sent when a user exits the room for any reason.<br />
<br />
5.<br />
<br />
<br />
<br />
If a privilege is revoked, the service MUST note that by sending an <x/> element qualified by the 'http://jabber.org/protocol/muc#user' namespace and containing an <item/> child element with the 'role' and/or 'affiliation' attributes set to a value that indicates the loss of the relevant privilege. All future presence stanzas for the occupant MUST include the updated role and affiliation, until and unless they change again.<br />
<br />
6.<br />
<br />
<br />
<br />
A MUC service MUST send extended presence to a client even if the client did not send an empty <x/> element qualified by the 'http://jabber.org/protocol/muc' namespace on entering the room; naturally, a client MUST ignore such information if it does not understand it (in accordance with RFC 3920).<br />
<br />
7.<br />
<br />
<br />
<br />
Extended presence about roles and affiliations sent in the muc#user namespace MUST include the full JID (not the bare JID) as the value of the 'jid' attribute.<br />
<br />
8.<br />
<br />
<br />
<br />
A client MAY send a custom exit message if desired (as is often done in IRC channels) by including a <status/> element in the presence stanza of type "unavailable" sent when exiting a room.<br />
<br />
<br />
<br />
16.4 IQ<br />
<br />
<br />
<br />
1.<br />
<br />
<br />
<br />
If an occupant wants to send an IQ stanza to another user in a non-anonymous room, the sender SHOULD send the request directly to the recipient's bare JID or full JID, rather than attempting to send the request through the room (i.e., via the recipient's room JID).<br />
<br />
2.<br />
<br />
<br />
<br />
If an occupant wants to send an IQ stanza to another user in a semi-anonymous room, the sender can direct the stanza to the recipient's room JID and the service MAY forward the stanza to the recipient's real JID. However, a MUC service MUST NOT reveal the sender's real JID to the recipient at any time, nor reveal the recipient's real JID to the sender.<br />
<br />
3.<br />
<br />
<br />
<br />
A MUC client MUST send only the 'affiliation' attribute or the 'role' attribute in the <item/> element contained within an IQ set qualified by the 'http://jabber.org/protocol/muc#admin' namespace; if a moderator, admin, or owner attempts to modify both the affiliation and role of the same item in the same IQ set, the service MUST return a <bad-request/> error to the sender. However, a MUC service MAY modify a role based on a change to an affiliation and thus MAY send presence updates that include both a modified role and a modified affiliation.<br />
<br />
4.<br />
<br />
<br />
<br />
In IQ sets regarding roles, a MUC client MUST include the 'nick' attribute only; in IQ results regarding roles, a MUC service MUST include the 'nick', 'role', 'affiliation', and 'jid' attributes (with the value of the latter set to the user's full JID).<br />
<br />
5.<br />
<br />
<br />
<br />
In IQ sets regarding affiliations, a MUC client MUST include the 'jid' attribute only (with the value set to the bare JID); in IQ results regarding affiliations, a MUC service MUST NOT include the 'role' attribute, MUST include the 'affiliation' attribute and the 'jid' attribute (with the value set to the bare JID), and SHOULD include the 'nick' attribute (except if the affiliation is "outcast", since outcasts SHOULD NOT have reserved nicknames).<br />
<br />
<br />
<br />
17. Implementation Notes<br />
<br />
<br />
<br />
The following guidelines may assist client and component developers in creating MUC implementations.<br />
<br />
17.1 Services<br />
<br />
<br />
<br />
1.<br />
<br />
<br />
<br />
In handling messages sent by visitors in a moderated room, a MUC service MAY queue each message for approval by a moderator and MAY inform the sender that the message is being held for approval; however, such behavior is OPTIONAL, and definition of a message approval protocol (e.g., using Data Forms as defined in XEP-0004) is out of scope for this document.<br />
<br />
2.<br />
<br />
<br />
<br />
It is common for MUC services to provide in-room messages when certain events occur, such as when the subject changes, when an occupant enters or exits, or when a room is destroyed. Such messages are entirely OPTIONAL and are left up to the implementation or deployment, but if used MUST be messages of type "groupchat" sent from the room JID itself (<room@service>) rather than a specific occupant (<room@service/nick>). However, in general it is preferable for the receiving client to generate such messages based on events in the room (e.g., user entrances and exits) as well as specific status codes provided in MUC; this will help ensure correct localization of such messages.<br />
<br />
3.<br />
<br />
<br />
<br />
Out of courtesy, a MUC service MAY send an out-of-room <message/> to an occupant who is kicked or banned, and MAY broadcast an in-room <message/> to all remaining occupants informing them that the occupant has been kicked or banned from the room. However, such messages are OPTIONAL, and indeed are unnecessary since the information required for a receiving client to generate such messages is communicated in the presence stanzas (specifically the status codes) sent by a MUC service.<br />
<br />
4.<br />
<br />
<br />
<br />
Out of courtesy, a MUC service MAY send an out-of-room <message/> if a user's affiliation changes while the user is not in the room; the message SHOULD be sent from the room to the user's bare JID, MAY contain a <body/> element describing the affiliation change, and MUST contain a status code of 101.<br />
<br />
5.<br />
<br />
<br />
<br />
There is no requirement that a MUC service shall provide special treatment for users of the older "groupchat 1.0" protocol, such as messages that contain equivalents to the extended presence information that is qualified by the 'http://jabber.org/protocol/muc#user' namespace.<br />
<br />
6.<br />
<br />
<br />
<br />
Room types MAY be configured in any combination. A MUC service MAY support or allow any desired room types or combinations thereof.<br />
<br />
7.<br />
<br />
<br />
<br />
A MUC service MAY limit the number of configuration options presented to an owner after initial configuration has been completed, e.g. because certain options cannot take effect without restarting the service.<br />
<br />
8.<br />
<br />
<br />
<br />
A MUC service MAY provide an interface to room creation and configuration (e.g., in the form of a special Jabber user or a Web page), so that the ostensible room owner is actually the application instead of a human user.<br />
<br />
9.<br />
<br />
<br />
<br />
A MUC service MAY choose to make available a special in-room resource that provides an interface to administrative functionality (e.g., a "user" named "ChatBot"), which occupants could interact with directly, thus enabling admins to type '/command parameter' in a private message to that "user". Obviously this kind of implementation would require the service to add a 'ChatBot' user to the room when it is created, and to prevent any occupant from having the nickname 'ChatBot' in the room. This might be difficult to ensure in some implementations or deployments. In any case, any such interface is OPTIONAL.<br />
<br />
10.<br />
<br />
<br />
<br />
A MUC service SHOULD remove a user if the service receives a delivery-related error in relation to a stanza it has previously sent to the user (remote server unreachable, user not found, etc.).<br />
<br />
11.<br />
<br />
<br />
<br />
A MUC service MAY choose to discard extended presence information that is attached to a <presence/> stanza before reflecting the presence change to the occupants of a room. That is, an implementation MAY choose to reflect only the <show/>, <status/>, and <priority/> child elements of the presence element as specified in the XML schema for the 'jabber:client' namespace, with the result that presence "changes" in extended namespaces (e.g., gabber:x:music:info) are not passed through to occupants. If a service prohibits certain extended namespaces, it SHOULD provide a description of allowable traffic at the well-known Service Discovery node 'http://jabber.org/protocol/muc#traffic' as described in the Allowable Traffic section of this document.<br />
<br />
12.<br />
<br />
<br />
<br />
A MUC service MAY choose to discard extended information attached to <message/> stanzas before reflecting the message to the occupants of a room. An example of such extended information is the lightweight text markup specified by XHTML-IM [31]. If a service prohibits certain extended namespaces, it SHOULD provide a description of allowable traffic at the well-known Service Discovery node 'http://jabber.org/protocol/muc#traffic' as described in the Allowable Traffic section of this document.<br />
<br />
13.<br />
<br />
<br />
<br />
A MUC service MAY choose to "lock down" room nicknames (e.g., hardcoding the room nickname to the bare JID of the occupant). If so, the service MUST treat the locked down nickname as a reserved room nickname and MUST support the protocol specified in the Discovering Reserved Room Nickname section of this document.<br />
<br />
<br />
<br />
17.1.1 Allowable Traffic<br />
<br />
<br />
<br />
As noted, a service (more precisely, a properly-configured room) MAY discard some or all extended namespaces attached to <message/> and <presence/> stanzas that are intended for reflection from the sender through the room to all of the room occupants. If the room does so, it SHOULD enable senders to discover the list of allowable extensions by sending a disco#info query to the well-known Service Discovery node 'http://jabber.org/protocol/muc#traffic', returning one <feature/> element for each namespace supported in the result. If the room does not allow any extended namespaces, it MUST return an empty query as specified in XEP-0030. If the room does not support the "#traffic" node, it MUST return a <feature-not-implemented/> error in response to queries sent to the 'http://jabber.org/protocol/muc#traffic' node.<br />
<br />
<br />
<br />
The following example shows a room that allows the 'http://jabber.org/protocol/xhtml-im' and 'http://jabber.org/protocol/rosterx' namespaces only, but no other extended namespaces.<br />
<br />
<br />
<br />
Example 191. User Queries Service Regarding Allowable Namespaces<br />
<br />
<br />
<br />
<iq from='wiccarocks@shakespeare.lit/laptop'<br />
<br />
to='heath@macbeth.shakespeare.lit'<br />
<br />
id='allow1'<br />
<br />
type='get'><br />
<br />
<query xmlns='http://jabber.org/protocol/disco#info'<br />
<br />
node='http://jabber.org/protocol/muc#traffic'/><br />
<br />
</iq><br />
<br />
<br />
<br />
<br />
<br />
Example 192. Service Returns Allowable Namespaces<br />
<br />
<br />
<br />
<iq from='heath@macbeth.shakespeare.lit'<br />
<br />
to='wiccarocks@shakespeare.lit/laptop'<br />
<br />
id='allow1'<br />
<br />
type='result'><br />
<br />
<query xmlns='http://jabber.org/protocol/disco#info'<br />
<br />
node='http://jabber.org/protocol/muc#traffic'><br />
<br />
<feature var='http://jabber.org/protocol/xhtml-im'/><br />
<br />
<feature var='http://jabber.org/protocol/rosterx'/><br />
<br />
</query><br />
<br />
</iq><br />
<br />
<br />
<br />
<br />
<br />
If a service does not discard any namespaces or does not implement this feature, it MUST return a <service-unavailable/> error:<br />
<br />
<br />
<br />
Example 193. Service Returns Service Unavailable<br />
<br />
<br />
<br />
<iq from='heath@macbeth.shakespeare.lit'<br />
<br />
to='wiccarocks@shakespeare.lit/laptop'<br />
<br />
id='allow1'<br />
<br />
type='error'><br />
<br />
<query xmlns='http://jabber.org/protocol/disco#info'<br />
<br />
node='http://jabber.org/protocol/muc#traffic'/><br />
<br />
<error code='503' type='cancel'><br />
<br />
<service-unavailable xmlns='urn:ietf:params:xml:ns:xmpp-stanzas'/><br />
<br />
</error><br />
<br />
</iq><br />
<br />
<br />
<br />
<br />
<br />
17.2 Clients<br />
<br />
<br />
<br />
1.<br />
<br />
<br />
<br />
Jabber clients MAY present room roles by showing ad-hoc groups for each role within a room roster. This will enable occupants to clearly visualize which occupants are moderators, participants, and visitors. However, such a representation is OPTIONAL.<br />
<br />
2.<br />
<br />
<br />
<br />
Jabber clients MAY implement a variety of interface styles that provide "shortcuts" to functionality such as changing one's nickname, kicking or banning users, discovering an occupant's full JID, or changing the subject. One option consists of IRC-style commands such as '/nick', '/kick', '/ban', and '/whois'; another is to enable a user to right-click items in a room roster. All such interface styles are OPTIONAL. However, for convenience, a mapping of IRC commands to MUC protocols is provided below.<br />
<br />
<br />
<br />
17.2.1 IRC Command Mapping<br />
<br />
<br />
<br />
Internet Relay Chat clients use a number of common "shortcut" commands that begin with a forward slash, such as '/nick' and '/ban'. The following table provides a mapping of IRC-style commands to MUC protocols, for use by Jabber clients that wish to support such functionality.<br />
<br />
<br />
<br />
Table 9: IRC Command Mapping<br />
<br />
Command Function MUC protocol<br />
<br />
/ban <roomnick> [comment] bans user with that roomnick from this room (client translates roomnick to bare JID) <br />
<br />
<br />
<br />
<iq id='someid'<br />
<br />
to='room@service'<br />
<br />
type='set'><br />
<br />
<query xmlns='http://jabber.org/protocol/muc#admin'><br />
<br />
<item affiliation='outcast'<br />
<br />
jid='bare-jid-of-user'><br />
<br />
<reason>comment</reason><br />
<br />
</item><br />
<br />
</query><br />
<br />
</iq><br />
<br />
<br />
<br />
<br />
<br />
/invite <jid> [comment] invites user with that JID to this room <br />
<br />
<br />
<br />
<message to='room@service'><br />
<br />
<x xmlns='http://jabber.org/protocol/muc#user'><br />
<br />
<invite to='jid'><br />
<br />
<reason>comment</reason><br />
<br />
</invite><br />
<br />
</x><br />
<br />
</message><br />
<br />
<br />
<br />
<br />
<br />
/join <roomname> [pass] joins room on this service (roomnick is same as nick in this room) <br />
<br />
<br />
<br />
<presence to='room@service/nick'><br />
<br />
<br />
<br />
<x xmlns='http://jabber.org/protocol/muc#user'><br />
<br />
<password>pass</password><br />
<br />
</x><br />
<br />
</presence><br />
<br />
<br />
<br />
<br />
<br />
/kick <roomnick> [comment] kicks user with that roomnick from this room <br />
<br />
<br />
<br />
<iq id='someid'<br />
<br />
to='room@service'<br />
<br />
type='set'><br />
<br />
<query xmlns='http://jabber.org/protocol/muc#admin'><br />
<br />
<item nick='roomnick' role='none'><br />
<br />
<reason>comment</reason><br />
<br />
</item><br />
<br />
</query><br />
<br />
</iq><br />
<br />
<br />
<br />
<br />
<br />
/msg <roomnick> <foo> sends private message "foo" to roomnick <br />
<br />
<br />
<br />
<message to='room@service/nick' type='chat'><br />
<br />
<body>foo</body><br />
<br />
</message><br />
<br />
<br />
<br />
<br />
<br />
/nick <newnick> changes nick in this room to "newnick" <br />
<br />
<br />
<br />
<presence to='room@service/newnick'/><br />
<br />
<br />
<br />
<br />
<br />
/part [comment] exits this room (some IRC clients also support /leave) <br />
<br />
<br />
<br />
<presence to='room@service/nick'<br />
<br />
type='unavailable'><br />
<br />
<status>comment</status><br />
<br />
</presence><br />
<br />
<br />
<br />
<br />
<br />
/topic <foo> changes subject of this room to "foo" <br />
<br />
<br />
<br />
<message to='room@service' type='groupchat'><br />
<br />
<subject>foo</subject><br />
<br />
</message><br />
<br />
<br />
<br />
<br />
<br />
Note: Because MUC roomnicks follow the Resourceprep profile of stringprep, they are allowed to contain a space character, whereas IRC nicknames do not. Although a given client MAY support quotation characters for this purpose (resulting in commands such as '/ban "king lear" insanity is no defense'), most common quotation characters (such as " and ') are also allowed by Resourceprep, thus leading to added complexity and potential problems with quotation of roomnicks that contain both spaces and quotation characters. Therefore it is NOT RECOMMENDED for Jabber clients to support IRC-style shortcut commands with roomnicks that contain space characters.<br />
<br />
<br />
<br />
Note: Many Jabber clients also implement a '/me ' command, where the command is followed by a verb or verb phrase (e.g., '/me laughs'). This command does not result in any MUC or IRC protocol action and is therefore not shown in the foregoing table. Instead, the message is sent as-is (e.g., <body>/me laughs</body>) and the receiving client performs string-matching on the character data of the <body/> element to determine if the message begins with the string '/me '; if it does the receiving client will show the message in a special format, usually italicized text sometimes prepended by the "*" character:<br />
<br />
<br />
<br />
* stpeter laughs<br />
<br />
18. XML Schemas<br />
<br />
18.1 http://jabber.org/protocol/muc<br />
<br />
<br />
<br />
<?xml version='1.0' encoding='UTF-8'?><br />
<br />
<br />
<br />
<xs:schema<br />
<br />
xmlns:xs='http://www.w3.org/2001/XMLSchema'<br />
<br />
targetNamespace='http://jabber.org/protocol/muc'<br />
<br />
xmlns='http://jabber.org/protocol/muc'<br />
<br />
elementFormDefault='qualified'><br />
<br />
<br />
<br />
<xs:annotation><br />
<br />
<xs:documentation><br />
<br />
The protocol documented by this schema is defined in<br />
<br />
XEP-0045: http://www.xmpp.org/extensions/xep-0045.html<br />
<br />
</xs:documentation><br />
<br />
</xs:annotation><br />
<br />
<br />
<br />
<xs:element name='x'><br />
<br />
<xs:complexType><br />
<br />
<xs:sequence><br />
<br />
<xs:element ref='history' minOccurs='0'/><br />
<br />
<xs:element name='password' type='xs:string' minOccurs='0'/><br />
<br />
</xs:sequence><br />
<br />
</xs:complexType><br />
<br />
</xs:element><br />
<br />
<br />
<br />
<xs:element name='history'><br />
<br />
<xs:complexType><br />
<br />
<xs:simpleContent><br />
<br />
<xs:extension base='empty'><br />
<br />
<xs:attribute name='maxchars' type='xs:int' use='optional'/><br />
<br />
<xs:attribute name='maxstanzas' type='xs:int' use='optional'/><br />
<br />
<xs:attribute name='seconds' type='xs:int' use='optional'/><br />
<br />
<xs:attribute name='since' type='xs:dateTime' use='optional'/><br />
<br />
</xs:extension><br />
<br />
</xs:simpleContent><br />
<br />
</xs:complexType><br />
<br />
</xs:element><br />
<br />
<br />
<br />
<xs:simpleType name='empty'><br />
<br />
<xs:restriction base='xs:string'><br />
<br />
<xs:enumeration value=''/><br />
<br />
</xs:restriction><br />
<br />
</xs:simpleType><br />
<br />
<br />
<br />
</xs:schema><br />
<br />
<br />
<br />
<br />
<br />
18.2 http://jabber.org/protocol/muc#user<br />
<br />
<br />
<br />
<?xml version='1.0' encoding='UTF-8'?><br />
<br />
<br />
<br />
<xs:schema<br />
<br />
xmlns:xs='http://www.w3.org/2001/XMLSchema'<br />
<br />
targetNamespace='http://jabber.org/protocol/muc#user'<br />
<br />
xmlns='http://jabber.org/protocol/muc#user'<br />
<br />
elementFormDefault='qualified'><br />
<br />
<br />
<br />
<xs:annotation><br />
<br />
<xs:documentation><br />
<br />
The protocol documented by this schema is defined in<br />
<br />
XEP-0045: http://www.xmpp.org/extensions/xep-0045.html<br />
<br />
</xs:documentation><br />
<br />
</xs:annotation><br />
<br />
<br />
<br />
<xs:element name='x'><br />
<br />
<xs:complexType><br />
<br />
<xs:choice minOccurs='0' maxOccurs='unbounded'><br />
<br />
<xs:element ref='decline' minOccurs='0'/><br />
<br />
<xs:element ref='destroy' minOccurs='0'/><br />
<br />
<xs:element ref='invite' minOccurs='0' maxOccurs='unbounded'/><br />
<br />
<xs:element ref='item' minOccurs='0'/><br />
<br />
<xs:element name='password' type='xs:string' minOccurs='0'/><br />
<br />
<xs:element ref='status' minOccurs='0'/><br />
<br />
</xs:choice><br />
<br />
</xs:complexType><br />
<br />
</xs:element><br />
<br />
<br />
<br />
<xs:element name='decline'><br />
<br />
<xs:complexType><br />
<br />
<xs:sequence><br />
<br />
<xs:element ref='reason' minOccurs='0'/><br />
<br />
</xs:sequence><br />
<br />
<xs:attribute name='from' type='xs:string' use='optional'/><br />
<br />
<xs:attribute name='to' type='xs:string' use='optional'/><br />
<br />
</xs:complexType><br />
<br />
</xs:element><br />
<br />
<br />
<br />
<xs:element name='destroy'><br />
<br />
<xs:complexType><br />
<br />
<xs:sequence><br />
<br />
<xs:element ref='reason' minOccurs='0'/><br />
<br />
</xs:sequence><br />
<br />
<xs:attribute name='jid' type='xs:string' use='optional'/><br />
<br />
</xs:complexType><br />
<br />
</xs:element><br />
<br />
<br />
<br />
<xs:element name='invite'><br />
<br />
<xs:complexType><br />
<br />
<xs:sequence><br />
<br />
<xs:element ref='reason' minOccurs='0'/><br />
<br />
</xs:sequence><br />
<br />
<xs:attribute name='from' type='xs:string' use='optional'/><br />
<br />
<xs:attribute name='to' type='xs:string' use='optional'/><br />
<br />
</xs:complexType><br />
<br />
</xs:element><br />
<br />
<br />
<br />
<xs:element name='item'><br />
<br />
<xs:complexType><br />
<br />
<xs:sequence><br />
<br />
<xs:element ref='actor' minOccurs='0'/><br />
<br />
<xs:element ref='reason' minOccurs='0'/><br />
<br />
<xs:element name='continue' type='empty' minOccurs='0'/><br />
<br />
</xs:sequence><br />
<br />
<xs:attribute name='affiliation' use='optional'><br />
<br />
<xs:simpleType><br />
<br />
<xs:restriction base='xs:NCName'><br />
<br />
<xs:enumeration value='admin'/><br />
<br />
<xs:enumeration value='member'/><br />
<br />
<xs:enumeration value='none'/><br />
<br />
<xs:enumeration value='outcast'/><br />
<br />
<xs:enumeration value='owner'/><br />
<br />
</xs:restriction><br />
<br />
</xs:simpleType><br />
<br />
</xs:attribute><br />
<br />
<xs:attribute name='jid' type='xs:string' use='optional'/><br />
<br />
<xs:attribute name='nick' type='xs:string' use='optional'/><br />
<br />
<xs:attribute name='role' use='optional'><br />
<br />
<xs:simpleType><br />
<br />
<xs:restriction base='xs:NCName'><br />
<br />
<xs:enumeration value='moderator'/><br />
<br />
<xs:enumeration value='none'/><br />
<br />
<xs:enumeration value='participant'/><br />
<br />
<xs:enumeration value='visitor'/><br />
<br />
</xs:restriction><br />
<br />
</xs:simpleType><br />
<br />
</xs:attribute><br />
<br />
</xs:complexType><br />
<br />
</xs:element><br />
<br />
<br />
<br />
<xs:element name='actor'><br />
<br />
<xs:complexType><br />
<br />
<xs:simpleContent><br />
<br />
<xs:extension base='empty'><br />
<br />
<xs:attribute name='jid' type='xs:string' use='required'/><br />
<br />
</xs:extension><br />
<br />
</xs:simpleContent><br />
<br />
</xs:complexType><br />
<br />
</xs:element><br />
<br />
<br />
<br />
<xs:element name='status'><br />
<br />
<xs:complexType><br />
<br />
<xs:attribute name='code' use='required'><br />
<br />
<xs:simpleType><br />
<br />
<xs:restriction base='xs:int'><br />
<br />
<xs:length value='3'/><br />
<br />
</xs:restriction><br />
<br />
</xs:simpleType><br />
<br />
</xs:attribute><br />
<br />
</xs:complexType><br />
<br />
</xs:element><br />
<br />
<br />
<br />
<xs:element name='reason' type='xs:string'/><br />
<br />
<br />
<br />
<xs:simpleType name='empty'><br />
<br />
<xs:restriction base='xs:string'><br />
<br />
<xs:enumeration value=''/><br />
<br />
</xs:restriction><br />
<br />
</xs:simpleType><br />
<br />
<br />
<br />
</xs:schema><br />
<br />
<br />
<br />
<br />
<br />
18.3 http://jabber.org/protocol/muc#admin<br />
<br />
<br />
<br />
<?xml version='1.0' encoding='UTF-8'?><br />
<br />
<br />
<br />
<xs:schema<br />
<br />
xmlns:xs='http://www.w3.org/2001/XMLSchema'<br />
<br />
targetNamespace='http://jabber.org/protocol/muc#admin'<br />
<br />
xmlns='http://jabber.org/protocol/muc#admin'<br />
<br />
elementFormDefault='qualified'><br />
<br />
<br />
<br />
<xs:annotation><br />
<br />
<xs:documentation><br />
<br />
The protocol documented by this schema is defined in<br />
<br />
XEP-0045: http://www.xmpp.org/extensions/xep-0045.html<br />
<br />
</xs:documentation><br />
<br />
</xs:annotation><br />
<br />
<br />
<br />
<xs:element name='query'><br />
<br />
<xs:complexType><br />
<br />
<xs:sequence><br />
<br />
<xs:element ref='item' maxOccurs='unbounded'/><br />
<br />
</xs:sequence><br />
<br />
</xs:complexType><br />
<br />
</xs:element><br />
<br />
<br />
<br />
<xs:element name='item'><br />
<br />
<xs:complexType><br />
<br />
<xs:sequence><br />
<br />
<xs:element ref='actor' minOccurs='0'/><br />
<br />
<xs:element ref='reason' minOccurs='0'/><br />
<br />
</xs:sequence><br />
<br />
<xs:attribute name='affiliation' use='optional'><br />
<br />
<xs:simpleType><br />
<br />
<xs:restriction base='xs:NCName'><br />
<br />
<xs:enumeration value='admin'/><br />
<br />
<xs:enumeration value='member'/><br />
<br />
<xs:enumeration value='none'/><br />
<br />
<xs:enumeration value='outcast'/><br />
<br />
<xs:enumeration value='owner'/><br />
<br />
</xs:restriction><br />
<br />
</xs:simpleType><br />
<br />
</xs:attribute><br />
<br />
<xs:attribute name='jid' type='xs:string' use='optional'/><br />
<br />
<xs:attribute name='nick' type='xs:string' use='optional'/><br />
<br />
<xs:attribute name='role' use='optional'><br />
<br />
<xs:simpleType><br />
<br />
<xs:restriction base='xs:NCName'><br />
<br />
<xs:enumeration value='moderator'/><br />
<br />
<xs:enumeration value='none'/><br />
<br />
<xs:enumeration value='participant'/><br />
<br />
<xs:enumeration value='visitor'/><br />
<br />
</xs:restriction><br />
<br />
</xs:simpleType><br />
<br />
</xs:attribute><br />
<br />
</xs:complexType><br />
<br />
</xs:element><br />
<br />
<br />
<br />
<xs:element name='actor'><br />
<br />
<xs:complexType><br />
<br />
<xs:simpleContent><br />
<br />
<xs:extension base='empty'><br />
<br />
<xs:attribute name='jid' type='xs:string' use='required'/><br />
<br />
</xs:extension><br />
<br />
</xs:simpleContent><br />
<br />
</xs:complexType><br />
<br />
</xs:element><br />
<br />
<br />
<br />
<xs:element name='reason' type='xs:string'/><br />
<br />
<br />
<br />
<xs:simpleType name='empty'><br />
<br />
<xs:restriction base='xs:string'><br />
<br />
<xs:enumeration value=''/><br />
<br />
</xs:restriction><br />
<br />
</xs:simpleType><br />
<br />
<br />
<br />
</xs:schema><br />
<br />
<br />
<br />
<br />
<br />
18.4 http://jabber.org/protocol/muc#owner<br />
<br />
<br />
<br />
<?xml version='1.0' encoding='UTF-8'?><br />
<br />
<br />
<br />
<xs:schema<br />
<br />
xmlns:xs='http://www.w3.org/2001/XMLSchema'<br />
<br />
targetNamespace='http://jabber.org/protocol/muc#owner'<br />
<br />
xmlns='http://jabber.org/protocol/muc#owner'<br />
<br />
elementFormDefault='qualified'><br />
<br />
<br />
<br />
<xs:annotation><br />
<br />
<xs:documentation><br />
<br />
The protocol documented by this schema is defined in<br />
<br />
XEP-0045: http://www.xmpp.org/extensions/xep-0045.html<br />
<br />
</xs:documentation><br />
<br />
</xs:annotation><br />
<br />
<br />
<br />
<xs:import <br />
<br />
namespace='jabber:x:data'<br />
<br />
schemaLocation='http://www.xmpp.org/schemas/x-data.xsd'/><br />
<br />
<br />
<br />
<xs:element name='query'><br />
<br />
<xs:complexType><br />
<br />
<xs:choice xmlns:xdata='jabber:x:data' minOccurs='0'><br />
<br />
<xs:element ref='xdata:x'/><br />
<br />
<xs:element ref='destroy'/><br />
<br />
</xs:choice><br />
<br />
</xs:complexType><br />
<br />
</xs:element><br />
<br />
<br />
<br />
<xs:element name='destroy'><br />
<br />
<xs:complexType><br />
<br />
<xs:sequence><br />
<br />
<xs:element name='password' type='xs:string' minOccurs='0'/><br />
<br />
<xs:element name='reason' type='xs:string' minOccurs='0'/><br />
<br />
</xs:sequence><br />
<br />
<xs:attribute name='jid' type='xs:string' use='optional'/><br />
<br />
</xs:complexType><br />
<br />
</xs:element><br />
<br />
<br />
<br />
<xs:simpleType name='empty'><br />
<br />
<xs:restriction base='xs:string'><br />
<br />
<xs:enumeration value=''/><br />
<br />
</xs:restriction><br />
<br />
</xs:simpleType><br />
<br />
<br />
<br />
</xs:schema><br />
<br />
<br />
<br />
<br />
<br />
18.5 http://jabber.org/protocol/muc#unique<br />
<br />
<br />
<br />
<?xml version='1.0' encoding='UTF-8'?><br />
<br />
<br />
<br />
<xs:schema<br />
<br />
xmlns:xs='http://www.w3.org/2001/XMLSchema'<br />
<br />
targetNamespace='http://jabber.org/protocol/muc#unique'<br />
<br />
xmlns='http://jabber.org/protocol/muc#unique'<br />
<br />
elementFormDefault='qualified'><br />
<br />
<br />
<br />
<xs:annotation><br />
<br />
<xs:documentation><br />
<br />
The protocol documented by this schema is defined in<br />
<br />
XEP-0045: http://www.xmpp.org/extensions/xep-0045.html<br />
<br />
</xs:documentation><br />
<br />
</xs:annotation><br />
<br />
<br />
<br />
<xs:element name='unique' type='xs:string'/><br />
<br />
<br />
<br />
</xs:schema><br />
<br />
<br />
<br />
<br />
<br />
19. Acknowledgements<br />
<br />
<br />
<br />
The author would like to thank the following individuals for their many helpful comments on various drafts of this proposal: David Sutton, Peter Millard, Joe Hildebrand, Craig Kaes, Alexey Shchepin, David Waite, Jean-Louis Seguineau, Jacek Konieczny, Gaston Dombiak, and many others in the jdev@conference.jabber.org conference room and on the Standards mailing list.<br />
<br />
Notes<br />
<br />
<br />
<br />
1. RFC 1459: Internet Relay Chat <http://tools.ietf.org/html/rfc1459>.<br />
<br />
<br />
<br />
2. RFC 2810: Internet Relay Chat: Architecture <http://tools.ietf.org/html/rfc2810>.<br />
<br />
<br />
<br />
3. RFC 2811: Internet Relay Chat: Channel Management <http://tools.ietf.org/html/rfc2811>.<br />
<br />
<br />
<br />
4. RFC 2812: Internet Relay Chat: Client Protocol <http://tools.ietf.org/html/rfc2812>.<br />
<br />
<br />
<br />
5. RFC 2813: Internet Relay Chat: Server Protocol <http://tools.ietf.org/html/rfc2813>.<br />
<br />
<br />
<br />
6. http://www.jabber.org/protocol/groupchat.html<br />
<br />
<br />
<br />
7. XEP-0030: Service Discovery <http://www.xmpp.org/extensions/xep-0030.html>.<br />
<br />
<br />
<br />
8. XEP-0128: Service Discovery Extensions <http://www.xmpp.org/extensions/xep-0128.html>.<br />
<br />
<br />
<br />
9. RFC 3920: Extensible Messaging and Presence Protocol (XMPP): Core <http://tools.ietf.org/html/rfc3920>.<br />
<br />
<br />
<br />
10. XEP-0203: Delayed Delivery <http://www.xmpp.org/extensions/xep-0203.html>.<br />
<br />
<br />
<br />
11. XEP-0091: Delayed Delivery <http://www.xmpp.org/extensions/xep-0091.html>.<br />
<br />
<br />
<br />
12. XEP-0082: XMPP Date and Time Profiles <http://www.xmpp.org/extensions/xep-0082.html>.<br />
<br />
<br />
<br />
13. RFC 3921: Extensible Messaging and Presence Protocol (XMPP): Instant Messaging and Presence <http://tools.ietf.org/html/rfc3921>.<br />
<br />
<br />
<br />
14. XEP-0077: In-Band Registration <http://www.xmpp.org/extensions/xep-0077.html>.<br />
<br />
<br />
<br />
15. XEP-0004: Data Forms <http://www.xmpp.org/extensions/xep-0004.html>.<br />
<br />
<br />
<br />
16. Some commentors have complained that this opens room owners and administrators up to potential abuse; unfortunately, with great power comes great responsibility.<br />
<br />
<br />
<br />
17. XEP-0133: Service Administration <http://www.xmpp.org/extensions/xep-0133.html>.<br />
<br />
<br />
<br />
18. XEP-0050: Ad-Hoc Commands <http://www.xmpp.org/extensions/xep-0050.html>.<br />
<br />
<br />
<br />
19. XEP-0060: Publish-Subscribe <http://www.xmpp.org/extensions/xep-0060.html>.<br />
<br />
<br />
<br />
20. This is different from the behavior of room configuration, wherein the 'muc#roomconfig_roomowners' field specifies the full list of room owners, not the delta.<br />
<br />
<br />
<br />
21. This is different from the behavior of room configuration, wherein the 'muc#roomconfig_roomadmins' field specifies the full list of room admins, not the delta.<br />
<br />
<br />
<br />
22. XEP-0086: Error Condition Mappings <http://www.xmpp.org/extensions/xep-0086.html>.<br />
<br />
<br />
<br />
23. RFC 2616: Hypertext Transport Protocol -- HTTP/1.1 <http://tools.ietf.org/html/rfc2616>.<br />
<br />
<br />
<br />
24. RFC 1893: Enhanced Mail System Status Codes <http://tools.ietf.org/html/rfc1893>.<br />
<br />
<br />
<br />
25. The Internet Assigned Numbers Authority (IANA) is the central coordinator for the assignment of unique parameter values for Internet protocols, such as port numbers and URI schemes. For further information, see <http://www.iana.org/>.<br />
<br />
<br />
<br />
26. The XMPP Registrar maintains a list of reserved protocol namespaces as well as registries of parameters used in the context of XMPP extension protocols approved by the XMPP Standards Foundation. For further information, see <http://www.xmpp.org/registrar/>.<br />
<br />
<br />
<br />
27. XEP-0068: Field Data Standardization for Data Forms <http://www.xmpp.org/extensions/xep-0068.html>.<br />
<br />
<br />
<br />
28. XEP-0147: XMPP URI Query Components <http://www.xmpp.org/extensions/xep-0147.html>.<br />
<br />
<br />
<br />
29. XEP-0022: Message Events <http://www.xmpp.org/extensions/xep-0022.html>.<br />
<br />
<br />
<br />
30. XEP-0085: Chat State Notifications <http://www.xmpp.org/extensions/xep-0085.html>.<br />
<br />
<br />
<br />
31. XEP-0071: XHTML-IM <http://www.xmpp.org/extensions/xep-0071.html>.<br />
<br />
Revision History<br />
<br />
Version 1.22 (2007-04-10)<br />
<br />
<br />
<br />
Updated delayed delivery reference to reflect advancement of XEP-0203 to Draft and deprecation of XEP-0091.<br />
<br />
(psa)<br />
<br />
Version 1.21 (2006-09-13)<br />
<br />
<br />
<br />
* Clarified that inclusion of MUC extension in room join/create request triggers Data Forms flow but that absence of MUC extension leads to automatic room creation for backwards compatibility with older groupchat 1.0 protocol.<br />
<br />
* Specified use of <not-acceptable/> error on nickname change if nicks are locked down.<br />
<br />
* Required clients to discover room configuration prior to entering room and specified related security considerations, including use of privacy-related status codes 170, 171, 172, 173, and 174.<br />
<br />
* Specified use of <not-acceptable/> error if room configuration options cannot be processed or violate service policies.<br />
<br />
* Made explicit that roomnicks must not consist only of spaces.<br />
<br />
* Moved all service discovery use cases into dedicated section.<br />
<br />
* Changed urn:xmpp:delay support from SHOULD to MUST.<br />
<br />
* Clarified that _whois room configuration option specifies room type.<br />
<br />
* Defined XEP-0128 room information fields for discussion logs, associated pubsub node, and contact JID.<br />
<br />
* Specified that changing role to moderator upon affiliation change to admin or owner is recommended, not required.<br />
<br />
* Added internationalization consideration about localization of field labels for various data forms.<br />
<br />
* Specified that implementations may persist roles across visits and should do so for moderated rooms.<br />
<br />
* Added protocol and service discovery feature for requesting a unique room name prior to room creation.<br />
<br />
* Further clarified nature of reserved room nicknames and nickname lockdown.<br />
<br />
* Defined data forms for requesting voice and approving voice requests.<br />
<br />
* Added multiple invitee example for XMPP URI.<br />
<br />
* Clarified order of presence, discussion history, etc.<br />
<br />
* Added status codes for occupant's own roomnick, service-modified roomnick, and warning that room discussion is publicly logged.<br />
<br />
* Clarified privacy and anonymity considerations regarding room logging and non-anonymous rooms.<br />
<br />
<br />
<br />
(psa)<br />
<br />
Version 1.20 (2005-09-08)<br />
<br />
<br />
<br />
Harmonized ability to kick and ban users, and clarified that a user cannot be kicked or banned by a moderator or admin with a lower affiliation.<br />
<br />
(psa)<br />
<br />
Version 1.19 (2005-04-21)<br />
<br />
<br />
<br />
Specified how to send multiple invitations simultaneously; corrected some errors regarding consistency of affiliation state changes; changed message events prohibition from MUST NOT to SHOULD NOT; corrected error handling related to the #traffic disco node; allowed <password/> as a child of <destroy/>; changed max users error from <not-allowed/> to <service-unavailable/>; specified that the maxchars attribute counts characters in complete XML stanzas; added disco features for FORM_TYPEs; defined registry for status codes; split Create Instant Room into separate use case for protocol compliance purposes; adjusted XML schemas to reflect the foregoing changes; re-wrote the introduction; clarified small textual matters throughout.<br />
<br />
(psa)<br />
<br />
Version 1.18 (2004-11-02)<br />
<br />
<br />
<br />
Corrected several errors in the affiliation state chart and in the examples (wrong FORM_TYPE values); mentioned /me command.<br />
<br />
(psa)<br />
<br />
Version 1.17 (2004-10-04)<br />
<br />
<br />
<br />
Added text about allowable extension namespaces and related service discovery mechanisms; specified well-known service discovery nodes; added conformance terms to clarify some descriptions; modified affiliation state chart to allow more flexible state changes; per list dicussion, added ability to convert a one-to-one chat into a conference, including sending of history; specified error to use when max users limit is reached; specified form for admin approval of user registration requests and modified FORM_TYPE from http://jabber.org/protocol/muc#user to http://jabber.org/protocol/muc#register; modified FORM_TYPE for room configuration from http://jabber.org/protocol/muc#owner to http://jabber.org/protocol/muc#roomconfig.<br />
<br />
(psa)<br />
<br />
Version 1.16 (2004-06-30)<br />
<br />
<br />
<br />
Added example and registry submission for service discovery extension.<br />
<br />
(psa)<br />
<br />
Version 1.15 (2004-06-24)<br />
<br />
<br />
<br />
Removed jabber:iq:browse references; clarified order of presence stanzas sent to new occupant on entering room; specified format of in-room messages (type='groupchat', from='room@service'); clarified allowable attributes in various list-related operations; made admin/owner revocation text and examples consistent with state chart; clarified ownership revocation conflict scenarios; changed the 'muc#roomconfig_inviteonly' field to 'muc#roomconfig_membersonly'; changed attribute order in examples to match XML canonicalization rules; corrected several errors in the schemas.<br />
<br />
(psa)<br />
<br />
Version 1.14 (2004-05-03)<br />
<br />
<br />
<br />
Corrected discovery of registered roomnicks; added note about error to return if nicks are locked down.<br />
<br />
(psa)<br />
<br />
Version 1.13 (2004-03-31)<br />
<br />
<br />
<br />
Fixed an error in the muc#user schema.<br />
<br />
(psa)<br />
<br />
Version 1.12 (2004-03-01)<br />
<br />
<br />
<br />
Corrected a few errors in the examples; added IQ results in order to clarify workflows.<br />
<br />
(psa)<br />
<br />
Version 1.11 (2004-02-05)<br />
<br />
<br />
<br />
Clarified JID matching rules (same as for privacy lists in XMPP IM).<br />
<br />
(psa)<br />
<br />
Version 1.10 (2004-01-07)<br />
<br />
<br />
<br />
Added XMPP error handling; fully specified all conformance terms.<br />
<br />
(psa)<br />
<br />
Version 1.9 (2003-12-14)<br />
<br />
<br />
<br />
Removed protocol for requesting voice in a moderated room (should be performed using Ad-Hoc Commands).<br />
<br />
(psa)<br />
<br />
Version 1.8 (2003-12-04)<br />
<br />
<br />
<br />
Added protocol for requesting voice in a moderated room; added (informational) mapping of IRC commands to MUC protocols.<br />
<br />
(psa)<br />
<br />
Version 1.7 (2003-10-21)<br />
<br />
<br />
<br />
Added room configuration option for restricting presence broadcast to certain roles.<br />
<br />
(psa)<br />
<br />
Version 1.6 (2003-10-03)<br />
<br />
<br />
<br />
Added history management protocol on entering a room.<br />
<br />
(psa)<br />
<br />
Version 1.5 (2003-09-11)<br />
<br />
<br />
<br />
Specified that ban occurs by JID, not roomnick; allowed privileged users to send messages to the room even if not present in the room; added note that service should remove occupant if a delivery-related stanza error occurs; enabled user to disco the room in order to discover registered roomnick; specified that "banning" by domain or regex is a service-level configuration matter and therefore out of scope for MUC; specified that role should be decremented as appropriate if affiliation is lowered; added some clarifying text to room creation workflow; added implementation note about sending an out-of-band message if a user's affiliation changes while the user is not in the room; fixed stringprep references (room nicks use Resourceprep); clarified relationship between Room ID (i.e., node identifier of Room JID, which may be opaque) and natural-language Room Name; specified Field Standardization profile per XEP-0068; defined XMPP Registrar submissions; added schema locations.<br />
<br />
(psa)<br />
<br />
Version 1.4 (2003-02-16)<br />
<br />
<br />
<br />
Added XML schemas.<br />
<br />
(psa)<br />
<br />
Version 1.3 (2003-02-11)<br />
<br />
<br />
<br />
Added reference to nodeprep Internet-Draft.<br />
<br />
(psa)<br />
<br />
Version 1.2 (2003-01-30)<br />
<br />
<br />
<br />
Commented out revision history prior to version 1.0 (too long); clarified business rules regarding when nicks, full JIDs, and bare JIDs are used in reference to roles and affiliations; consistently specified that extended presence information in the muc#user namespace must include the full JID as the value of the 'jid' attribute in all cases; cleaned up text and examples throughout; added open issue regarding syntax of room nicknames.<br />
<br />
(psa)<br />
<br />
Version 1.1 (2002-12-16)<br />
<br />
<br />
<br />
Added protocol for declining an invitation; replaced <created/> element with status code 201; modified the destroy room protocol so that <destroy/> is a child of <query/>; clarified usage of 'nick' attribute when adding members; prohibited use of message events.<br />
<br />
(psa)<br />
<br />
Version 1.0 (2002-11-21)<br />
<br />
<br />
<br />
Per a vote of the Jabber Council, revision 0.23 was advanced to Draft on 2002-11-21. (For earlier revision history, refer to XML source.)<br />
<br />
(psa)<br />
<br />
Version 0.23 (2002-11-06)<br />
<br />
<br />
<br />
Added examples for disco#items queries sent to a room; prohibited 'type' attribute on invite messages sent from client to room; added dependencies on browse and disco; changed 'room user' to 'occupant'; fixed many small errors throughout.<br />
<br />
(psa)<br />
<br />
Version 0.22 (2002-11-04)<br />
<br />
<br />
<br />
Added example for disco#items; added support for cancellation of room configuration using type='cancel' from XEP-0004; noted 403 error for invites sent by non-admins in members-only room.<br />
<br />
(psa)<br />
<br />
Version 0.21 (2002-11-01)<br />
<br />
<br />
<br />
Clarified several small ambiguities; made <body/> optional on invites sent from the service to the invitee; added error scenarios for changing nickname and for destroying the room; specified that the service must return the full member list for a members-only room (not only the members in the room); updated the disco examples to track protocol changes.<br />
<br />
(psa)<br />
<br />
Version 0.20 (2002-10-29)<br />
<br />
<br />
<br />
Specified that messages sent to change the room subject must be of type "groupchat"; updated the legal notice to conform to the XSF IPR policy.<br />
<br />
(psa)<br />
<br />
Version 0.19 (2002-10-28)<br />
<br />
<br />
<br />
Added ability to create an instant room within MUC (not by using gc-1.0 protocol); cleaned up disco examples.<br />
<br />
(psa)<br />
<br />
Version 0.18 (2002-10-27)<br />
<br />
<br />
<br />
Added experimental support for disco; added sections for security, IANA, and JANA considerations; corrected typographical errors; cleaned up some DocBook formatting.<br />
<br />
(psa)<br />
<br />
Version 0.17 (2002-10-23)<br />
<br />
<br />
<br />
Added the optional <actor/> element (with 'jid' attribute) to <item/> elements inside presence stanzas of type "unavailable" that are sent to users who are kicked or banned, as well as within IQs for tracking purposes; reverted all list editing use cases (ban, voice, member, moderator, admin, owner) to use of MUC format rather than 'jabber:x:data' namespace; added several guidelines regarding generation and handling of XML stanzas; cleaned up the change room subject use case; changed several ambiguous uses of 'would', 'can', and 'will' to 'should', 'may', or 'must'; fixed several small errors in the text, examples, and DTDs.<br />
<br />
(psa)<br />
<br />
Version 0.16 (2002-10-20)<br />
<br />
<br />
<br />
Added the <item/> element to presence stanzas of type "unavailable" in order to improve the tracking of user states in the room; consolidated <invitee/> and <invitor/> elements into an <invite/> element with 'from' and 'to' attributes; made <reason/> element always a child of <item/> or <invite/> in the muc#user namespace; moved the alternate room location in room destruction to a 'jid' attribute of the <alt/> element; further specified several error messages; disallowed simultaneous modifications of both affiliations and roles by a moderator or admin; added several more rules regarding handling of XML stanzas; added use cases for granting and revoking administrative privileges; adjusted DTD to track all changes.<br />
<br />
(psa)<br />
<br />
Version 0.15 (2002-10-18)<br />
<br />
<br />
<br />
Fully incorporated the change to affiliations + roles; moved a number of admin use cases to a new section for moderator use cases; added participant use case for requesting membership; added admin use cases for adding members, removing members, granting and revoking moderator privileges, and modifying the moderator list; organized the sections in a more logical manner.<br />
<br />
(psa)<br />
<br />
Version 0.14 (2002-10-17)<br />
<br />
<br />
<br />
Significantly modified the privileges model by distinguishing between in-room "roles" and long-lived "affiliations"; specified the privileges of the various roles and affiliations; included state transition charts for both roles and affiliations; removed use of MUC protocol for editing ban, voice, and admin lists (but not for the actions of banning users and granting/revoking voice); added delivery rule regarding IQ stanzas; changed kick so that the action is based on changing the role to "none".<br />
<br />
(psa)<br />
<br />
Version 0.13 (2002-10-16)<br />
<br />
<br />
<br />
Corrected the change nickname examples (newnick sent on unavailable, no nick sent on available).<br />
<br />
(psa)<br />
<br />
Version 0.12 (2002-10-16)<br />
<br />
<br />
<br />
Removed SHA1 passwords; specified that room shall add passwords on invitations to password-protected rooms (not supplied by invitor).<br />
<br />
(psa)<br />
<br />
Version 0.11 (2002-10-16)<br />
<br />
<br />
<br />
Changed 'participant' to 'room user' and 'discussant' to 'participant'; clarified presence rule about client generation of extended presence information; added role of 'none'.<br />
<br />
(psa)<br />
<br />
Version 0.10 (2002-10-15)<br />
<br />
<br />
<br />
Fixed extended presence on entering or creating a room (plain '...muc' with no fragment); harmonized #user with #admin regarding the use of the <item/> element and associated attributes (jid, nick, etc.), and added 'role' attribute; modified management of voice, ban, admin, and member lists to use <query/> wrapper and new <item/> structure; changed the 'member' role to 'discussant', added 'outcast' role for banned users, and added new 'member' role to enable management of member lists; changed invitation-only rooms to members-only rooms and made appropriate adjustments to apply member lists to both members-only rooms and open rooms; modified nickname change protocol slightly to send the old nickname in the unavailable presence and the new nickname in the available presence; removed prohibition on members-only rooms that are password-protected; removed the <query/> wrapper for the <destroy/> element; updated the DTDs.<br />
<br />
(psa)<br />
<br />
Version 0.9 (2002-10-13)<br />
<br />
<br />
<br />
Added extended presence ('...#user') on entering a room for MUC clients; changed namespace on room creation request to '...#owner'; added a service discovery example using jabber:iq:browse; added information about discussion history; made small fixes to several examples; further defined the presence rules; transferred all implementation notes to a dedicated section; added a Terminology section.<br />
<br />
(psa)<br />
<br />
Version 0.8 (2002-10-10)<br />
<br />
<br />
<br />
Made further changes to the room creation workflow (finally correct); removed feature discovery use case (this needs to be addressed by a real service discovery protocol!); added ability for room owners to edit the admin list; removed <body/> from invitations generated by the service; removed messages sent to kicked and banned users (handled by unavailable presence with status code); added a number of implementation notes; converted all examples to Shakespeare style.<br />
<br />
(psa)<br />
<br />
Version 0.7.6 (2002-10-09)<br />
<br />
<br />
<br />
Fixed the room creation workflow; changed some terminology ("join" to "enter" and "leave" to "exit").<br />
<br />
(psa)<br />
<br />
Version 0.7.5 (2002-10-08)<br />
<br />
<br />
<br />
Specified and improved the handling of invitation-only rooms. In particular, added the ability for room admins to edit the invitation list and added a configuration option that limits the ability to send invitations to room admins only.<br />
<br />
(psa)<br />
<br />
Version 0.7.4 (2002-10-07)<br />
<br />
<br />
<br />
Changed namespaces from http://jabber.org/protocol/muc/owner etc. to http://jabber.org/protocol/muc#owner etc. per Jabber Council discussion.<br />
<br />
(psa)<br />
<br />
Version 0.7.3 (2002-10-07)<br />
<br />
<br />
<br />
Changed namespaces to HTTP URIs; left role handling up to the implementation; further clarified presence rules.<br />
<br />
(psa)<br />
<br />
Version 0.7.2 (2002-10-06)<br />
<br />
<br />
<br />
Disallowed kicking, banning, and revoking voice with respect to room admins and room owners; replaced <x/> with <query/> in the Discovering Room Features and Destroying a Room use cases; corrected some small errors and made many clarifications throughout.<br />
<br />
(psa)<br />
<br />
Version 0.7.1 (2002-10-04)<br />
<br />
<br />
<br />
Removed <whois/> command (unnecessary since participants with appropriate privileges receive the full JID of all participants in presence stanzas); completed many small fixes throughout.<br />
<br />
(psa)<br />
<br />
Version 0.7 (2002-10-03)<br />
<br />
<br />
<br />
More clearly delineated participant roles and defined the hierarchy thereof (owner, admin, member, visitor); replaced <voice/> element in extended presence with <item role='member'/>; changed initial room configuration to use IQ rather than message; adjusted presence rules (especially regarding extended presence information); cleaned up examples throughout; updated DTD to track changes.<br />
<br />
(psa)<br />
<br />
Version 0.6 (2002-09-21)<br />
<br />
<br />
<br />
More clearly defined the scope; removed fully anonymous rooms; changed meaning of semi-anonymous rooms and of non-anonymous rooms; added mechanism for notification of full JIDs in non-anonymous rooms; replaced the <admin/> element in extended presence with a <role/> element (more extensible); changed room passwords to cleartext; added status codes for various messages received from the service; added lists of valid error and status codes associated with the 'http://jabber.org/protocol/muc#user' namespace; added a <reason/> element for invitations; made kick and ban reasons child elements rather than attributes; replaced stopgap feature discovery mechanism with jabber:iq:negotiate; added extended presence element to room creation request and clarified the room creation process; specified presence reflection rules; added method for destroying a room; adjusted DTDs to track all changes.<br />
<br />
(psa)<br />
<br />
Version 0.5.1 (2002-09-20)<br />
<br />
<br />
<br />
Added DTDs; changed feature discovery to use <x/> element rather than query and made service response come in IQ result; fixed reference to JID spec; changed 'grant' to 'add' and 'revoke' to 'remove' for consistency in the item attributes; made several other small changes.<br />
<br />
(psa)<br />
<br />
Version 0.5 (2002-09-19)<br />
<br />
<br />
<br />
Changed the kick, ban, and voice protocols; added a few more configuration options; specified the restrictions for roomnicks; and added a stopgap service discovery protocol.<br />
<br />
(psa)<br />
<br />
Version 0.4 (2002-09-18)<br />
<br />
<br />
<br />
Changed all non-GC-1.0 use cases to jabber:gc:* namespaces or jabber:x:data; added use cases for ban list management and room moderation; added protocol for sending notice of admin and voice privileges in presence; cleaned up text and many examples.<br />
<br />
(psa)<br />
<br />
Version 0.3 (2002-09-17)<br />
<br />
<br />
<br />
Changed admin use cases; cleaned up participant and owner use cases.<br />
<br />
(psa)<br />
<br />
Version 0.2 (2002-09-12)<br />
<br />
<br />
<br />
Broke content out into three actors (participant, owner, and admin) and added more detail to owner and admin use cases.<br />
<br />
(psa)<br />
<br />
Version 0.1 (2002-09-09)<br />
<br />
<br />
<br />
Initial version.<br />
<br />
(psa)<br />
<br />
<br />
<br />
END"</div>
Snowqiang