本篇翻译了XMPP核心协议RFC 3920的第四章,由于第四章内容太多,所以独自成一篇。主要讲解了XML流的概念、与TCP绑定、流的安全、流的属性、命名空间的声明、流特性、流错误以及一个简化的流的例子。
4.1. 概述
XML流与XML节点这两个基础的概念使得可以快速、 异步的在presence-aware实体间交换相关的小量结构化信息。这两个术语定义如下:
- XML流的定义:
- XML流是用于任意两个实体间通过网络进行XML元素交换的容器。XML流的开端明确的由一个开的XML<stream>标记标明(含有适当的属性及命名空间的声明),XML流的结束明确的由一个闭的XML</stream>标记标明。在XML流的生命周期里,初始化它的实体能够通过流发送大量的XML元素,元素也通常制定一个特定的XML流(例:来制定使用TLS(第5节)或使用SASL(第6节))或者XML节点(如定义在这些由缺省命名空间限定的<message/>、<presence/>和<iq/>元素上)。“初始流”是由发送实体(通常是一个客户端或服务器)给接收实体(通常是一个服务器)制定的,可以见到它是与发送实体和接收实体间的会话相一致的。发送流能进行从发送实体到接收实体的单向通信;为了实现从接收实体到发送实体的信息交换,接收实体必须在反方向上制定一个流(“响应流”)。
- XML节的定义:
- XML节是一个不连续的通过XML流从一个实体到另一个实体所传送的结构化信息的语义单元。XML节存在于根元素<stream/>的直接子层上,and is said to be well-balanced if it matches the production [43] content of [XML] 。任何XML节的开端都由处于XML流中深度为1的层上的元素开标记符明确标明(如,<presence>), 其结尾则由在深度为1的层上的相应闭标记符明确标明(如,</presence>)。为了传送期望的信息,一个XML节可能需要包含子元素(带有一些属性、元素、XML字符数据)。在这(RFC 3920中)定义的用于流的XML节仅有在缺省命名空间限定下的<message/>、<presence/>和<iq/>元素,这些在XML节(第9节)中会讲到;为制定TLS和SASL,以及服务器回叫而发送的XML元素,并不会当作XML节来考虑。
考虑一个客户端与服务器会话的例子。为了连接到服务器,客户端必须初始化一个XML流:发送一个开的<stream>标记到服务器,在这之前可以(OPTIONAL)有一个指定XML版本与字符编码支持的文本声明(参考文本声明的内容(11.4);也可参考字符编码(11.5))。根据本地策略与所提供的服务,服务器接下来应该(SHOULD)回应一个XML流给客户端,然后也可以具有一个可选的文本声名。一旦客户端完成了SASL(第6节),客户端可以(MAY)可以通过流发送大量的XML节给网络上的任意接受实体。当客户端想关闭流时,它只需简单的发送一个闭</stream>标记符给服务器(也可以由服务器来关闭流),接着,客户端与服务器都应(SHOULD)终止underlying连接(通常是一个TCP连接)。
习惯于以基于文档的方式来考虑XML的人可能一厢情愿的把客户端与服务器的会话看作是由两个无限制的XML文档所组成:一个从客户端到服务器,另一个从服务器到客户端。依这种看法,根<stream/>元素可被认为是每个“文档”的文档实体,两个“文档”都是通过两个XML流发送的XML节的堆积而建立。然而,这种观点仅是图个方便;XMPP并不以文档的方式处理,而是以XML流或XML节来处理。
从本质上看,那么一个XML流其实是充当了在会话中所发送的所有XML节的信封。我们可将其用简图表示如下:
|--------------------| | <stream> | |--------------------| | <presence> | | <show/> | | </presence> | |--------------------| | <message to='foo'> | | <body/> | | </message> | |--------------------| | <iq to='bar'> | | <query/> | | </iq> | |--------------------| | ... | |--------------------| | </stream> | |--------------------|
4.2. 绑定到TCP
虽然没必要将一个XML流结合到一个TCP连接上(例如:两个实体能通过其它诸如通过HTTP来polling的机制实现彼此互连),此规范也只定义了XMPP到TCP的绑定。在客户端到服务器端的通信中,服务器必须(MUST)允许客户端共享一条单一的TCP连接来发送从客户端到服务器或服务器到客户端的XML节。在服务器到服务器的通信中,服务器必须(MUST)使用一条TCP连接来用于传送从服务器到其它对等服务器的XML节,和另外的一条TCP连接(由对等服务器初始化)用于传送其它对等服务器到服务器的XML节,总共有两条TCP连接。
4.3. 流的安全
当在XMPP1.0中制定XML流时,TLS(第5节)和SASL(第6节)应当(SHOULD)按其所定义的来使用。“初始流”(例如:从发送实体到接收实体的流)与“响应流”(例如:从接收实体到发送实体的流)必须(MUST)被分别保护,即使两个方向上的安全可能(MAY)由提供相互认证的机制建立起来。实体也不应当(SHOULD NOT)在流被认证之前,尝试通过该流发送XML节(第9节),但如果这么做了,那么,其它实体禁止(MUST NOT)接受此类XML节,并应当(SHOULD)返回一个<non-authorized/>流错误,然后终止两端的XML流与underlyingTCP连接;注意,这只适用于XML节(例如:缺省命名空间限定<message/>、<presence/>、<iq/>元素),并不适用于制定流的的XML元素(例如:用于制定TLS(第5节)或SASL(第6节)的XML元素)。
4.4.流的属性
流元素的属性如下:
- to -- ‘to’属性应当(SHOULD)只用在从发送实体到接受实体的XML流的header中,而且必须(MUST)被设置成一个由接受实体所提供的主机名。不应当(SHOULD NOT)有‘to’设置在接受实体回应给发送实体的XML流的header中;然而,如果已经被包含了,它应当(SHOULD)被发送实体默默地忽略掉。
- from -- ‘from’属性应当(SHOULD)只用在从接受实体到发送实体的XML流的header中,而且必须(MUST)被设置成一个由以准许连接到发送实体的接受实体所提供的主机名。不应当(SHOULD NOT)有‘from’设置在发送实体传送给接受实体的XML流的header中;然而,如果已经被包含了,它应当(SHOULD)被接送实体默默地忽略掉。
- id -- ‘id’属性应当(SHOULD)只用在从接受实体到发送实体的XML流的header中。id属性是由接受实体创建的,起到发送流与接受实体间会话的密钥的作用,且必须在接受应用程序中是唯一的(通常是个服务器)。注意到流的ID可能有安全隐患,因此此ID必须(MUST)不可预测且不重复的(参见[RANDOM]中关于随机的建议)。不应当(SHOULD NOT)有‘id’设置在发送实体传送给接受实体的XML流的header中;然而,如果已经被包含了,它应当(SHOULD)被接送实体默默地忽略掉。
- xml:lang -- ‘ xml:lang’属性(定义在[XML]的2.12中)应当包含在发送实体的初始流头中,用于指定任何通过流发送的人类可读的XML字符数据的缺省语言。如果属性包含在流内,接收实体应当记住此值并做为初始流与响应流的缺省值;如果此属性不包含在流内,接收实体应当(SHOULD)为两个流使用一个可配置的缺省值,该值必须放置到响应流的header中。对所有通过初始化流发送的节,如果发送实体不包含‘xml:lang’属性,接收实体应当(SHOULD)应用缺省值;如果初始实体包含‘xml:lang’属性,接收实体不准(MUST NOT)修改或删除它(参考xml:lang(9.1.5))。‘xml:lang’属性值必须是一个NMTOKEN(定义在[XML](2.3)中),并且必须与定义在RFC3006[LANGTAGS]中的格式一致。
- version -- 所出现的版本属性得设置值至少是“1.0”以标志支持定义在本规范中的相关流协议(包括流特征)。有关该属性的产生与处理的具体规则定义在之后的4.4.1节中。
我们可以总结为下表:
| initiating to receiving | receiving to initiating ---------+---------------------------+----------------------- to | hostname of receiver | silently ignored from | silently ignored | hostname of receiver id | silently ignored | session key xml:lang | default language | default language version | signals XMPP 1.0 support | signals XMPP 1.0 support
4.4.1 版本支持
XMPP版本在此指定为“1.0”,特别的,这封装了流相关协议(TLS应用(5)、SASL应用(6)、流错误(4.7)),还有三个已定义的XML节类型(<message/>、 <presence/>、<iq/>)的语义。XMPP版本的编号方案是这样的“<major>.<minor>”。major与minor数字必须(MUST)作为分离的整数对待,并且每个数字值可能增加到超过一位数。因此“XMPP 2.4”是一个比“XMPP 2.13”低的版本,依次又低于“XMPP 12.3”。而以零开头的(例如:“XMPP 6.01”)必须(MUST)被接收者忽略并不准(MUST NOT)发送。
major版本号只有当流与节的格式或是需要的行为已很大程度上改变,以至于老版本的实体不能够通过简单的忽略其元素和属性的方法来接受新版本的实体以及实现旧版本中定义的行为时,才应该增加。次版本号表示有新性能,并且必须(MUST)被带有更小的次版本号的实体所忽略,但被有更大次版本号的实体用作提供信息的目的。例如:次版本号可能标志了处理消息、出席或IQ节最新定义的‘type’属性值;有更大次版本号的实体将简单注意它的通信对象不会理解此‘type’属性值,并因此不会去发送它。
以下规则应用于产生与处理在实际应用中的流的headers中的‘版本’属性:
- 发送实体必须(MUST)在初始流头中将版本属性值设到它所支持的最高版本号(例如:如果它所支持的最高版本号定义在此说明中,必须(MUST)设值为“1.0”)。
- 接收实体必须(MUST)将响应流header中版本属性值设置成初始实体提供的值与接收实体所支持的最高版本号这两个中较低的一个。接收实体必须(MUST)分别对主、次版本号做数字比较,而不是简单的对"<major>.<minor>"进行字符串匹配。
- 如果包含在响应流header中的版本号至少有一个主版本号低于包含在初始流header中的版本号,并且新版本实体不能像上述那样与旧版本互操作,发送实体应当(SHOULD)产生一个<unsupported-version/>流错误,并终止XML流及underlyingTCP连接。
- 如果任一实体收到了带有无“版本”属性的流header时,该实体必须(MUST)认为其它实体支持版本是“0.0”,并且不应当(SHOULD NOT)在发送响应流时包括‘version’属性。
4.5. 声名命名空间
流元素(MUST)同时具有流的命名空间声名和一个缺省的命名空间声明(“namespace declaration”定义在XML 命名空间规范[XML-NAMES]中)。关于流的命名空间和缺省的命名空间的详细信息,请参阅命名空间名与前缀(11.2节)
4.6. 流特性
如果发送实体在其发送的初始流hea的人中包含了版本属性且此属性值至少为“1.0”,那么接受实体必须(MUST)发送一个<features/>子元素(带有流命名空间的前缀)给发送实体,用于报告那些可制定的任何流级别的特性(或者是其它必须注册的性能)。目前,这个只用于注册TLS的使用,SASL的使用以及这儿定义的资源绑定和定义在[XMPP-IM]中的建立会话;可是,在将来流的功能特性能够用来注册其它被制定的特性。如果一个实体不理解或支持一些特性,它应该(SHOULD)忽略它们。如果需要在提供非安全相关特征前成功的制定一个或多个安全特性(如:TLS和SASL),那么在制定相关的安全特性前我们不应该(SHOULD NOT)在已注册的流特性中包含那些非安全相关特性。
4.7. 流错误
流的根元素可以(MAY)包含一个被赋予流命名空间前缀的<error/>子元素。如果错误子元素感觉到一个流级别错误发生,该错误子元素必须(MUST)由一个兼容实体(通常是一个服务器而非客户端)来发送。
4.7.1. 规则
以下规则应用于流级别错误:
- 我们设想说有流级别的错误都是不可复原的;因此,要是在流级别上发生了错误,侦查到该错误的实体必须(MUST)发送一个流错误给其它实体,然后发送一个闭</stream>标志,并终止underlyingTCP连接。
- 如果在流被建立期间发生错误,接收实体必须(MUST)仍旧发送起始<stream>标记,将<error/>元素作为流元素的子元素包括在内,然后发送关闭</stream>标记,并终止潜在的TCP连接。此种情况下,如果初始实体在‘to’属性(或根本没提供‘to’属性)中提供了一个未知主机,服务器应当(SHOULD)在流头的‘from’属性中提供服务器的授权主机名,并在终止前发送。
4.7.2. 语法
流错误的语法如下:
<stream:error> <defined-condition xmlns='urn:ietf:params:xml:ns:xmpp-streams'/> <text xmlns='urn:ietf:params:xml:ns:xmpp-streams' xml:lang='langcode'> OPTIONAL descriptive text </text> [OPTIONAL application-specific condition element] </stream:error>
<error/>元素:
- 必须(MUST)包含一个子元素,此子元素与后面定义的节错误因素之一相符;此子元素必须(MUST)由‘urn:ietf:params:xml:ns:xmpp-streams’命名空间限定。
- 可能(MAY)包含一个<text/>子元素,用于包含更详细的描述错误的XML字符数据;此子元素必须(MUST)由‘urn:ietf:params:xml:ns:xmpp-streams’命名空间限定,并且,应当(SHOULD)有一个'xml:lang'属性来指定XML字符数据使用的语言。
- 可能(MAY)包含一个用于说明特定应用中的错误因素的子元素;此元素必须(MUST)由一个已定义的应用的命名空间来限定,并且,它的结构也由那个命名空间来定义。
<text/>元素是可选(OPTIONAL)的。如果包含了此元素,它应当(SHOULD)仅用于提供描述性或诊断性的信息,来补充一个已定义的因素或特殊应用中的因素所表示的意思;它不应当(SHOULD NOT)由一个应用以程序化的形式叙述。它不应当(SHOULD NOT)作为错误消息展示给一个用户,但可以(MAY)特定条件下显示在与包含错误因素的元素(或元素们)相关的错误消息中。
4.7.3 已定义因素
以下定义了流级别的错误因素:
- <bad-format/> -- 已经发送XML的实体不能被处理;此错误可以(MAY)用于代替更特殊的XML相关错误,例如:<bad-namespace-prefix/>、<invalid-xml/>、<restricted-xml/>、<unsupported-encoding/>和<xml-not-well-formed/>,虽然更特殊的错误才是首选。
- <bad-namespace-prefix/> -- 实体发送了一个不被支持的名空间前缀,或在一个需要那样一个前缀的元素中发送了没有命名空间的前缀(参考XML命名空间名与前缀(11.2))。
- <conflict/> -- 服务器正为实体关闭活动流,因为一个已经被初始化的新流与现存流冲突。
- <connection-timeout/> -- 一段时间内(根据本地服务配置)实体并不通过流产生任何通信。
- <host-gone/> -- 由初始实体在流头中提供的‘to’属性值对应于一个主机名,而此主机名已不再被一个服务器当作主机名了。
- <host-unknown/> -- 由初始实体在流头中提供的‘to’属性值与服务器所拥有的主机名不一致。
- <improper-addressing/> -- 一个在两个服务器间发送的节,缺少‘to’或‘from’属性(或此属性无值)
- <internal-server-error/> -- 服务器经历了错误配置或其它未定义内部错误使其无法提供服务。
- <invalid-from/> -- 在‘from’地址中提供的JID或主机名与已授权的JID或有效域协商不匹配,此有效域协商为通过SASL或回叫服务器间的协商,或通过授权与资源绑定的客户端与服务器间的协商。
- <invalid-id/> -- 流ID或回叫ID是无效的或与以前提供的ID不匹配。
- <invalid-namespace/> -- 流命名空间名不只是http://etherx.jabber.org/streams,或回叫命名空间名不只是"jabber:server:dialback"(参考XML命名空间名与前缀(11.2))
- <invalid-xml/> -- 实体通过流向执行验证的服务器发送了无效的XML(参考验证(11.3))。
- <not-authorized/> -- 实体试图在流被认证前发送数据,或不授权执行一个相关流协商的活动;接收实体在发送流错误前不准处理违规节。
- <policy-violation/> -- 实体违反了某些本地策略;服务器可能选择在<text/>元素或特殊-应用条件元素中指定策略。
- <remote-connection-failed/> -- 服务器不能适当的连接到远程实体,需要认证或授权。
- <resource-constraint/> -- 服务器缺少提供服务给流的必要的系统资源。
- <restricted-xml/> -- 实体试图发送受限的XML特征,例如评注、处理介绍,DTD,实体参考,或保留字符(参考(11.1))。
- <see-other-host/> -- 服务器将不提供服务给初始实体,但正重定向传输给另一个主机;服务器应当指定替换的主机名或IP地址(必须是有效域标识符),作为<see-other-host/>元素的XML字符数据。
- <system-shutdown/> -- 服务器被关闭,并且所有的活动流被关闭。
- <undefined-condition/> -- 错误因素是由此列表中的其它已定义因素中的一个;此错误因素应当仅用于与特殊应用错误因素相结合。
- <unsupported-encoding/> -- 初始实体以不被服务器支持的编码给流编码(11.5)
- <unsupported-stanza-type/> -- 初始实体发送了一个不被服务器支持的第一级子流。
- <unsupported-version/> -- 由初始实体在流头提供的版本属性值指定了一个不被服务器支持的XMPP版本;服务器可能在<text/>元素中指定它支持的版本。
- <xml-not-well-formed/> -- 初始实体发送了不标准的XML,标准的XML由[XML]定义。
原文:
- <bad-format/> -- the entity has sent XML that cannot be processed; this error MAY be used instead of the more specific XML-related errors, such as <bad-namespace-prefix/>, <invalid-xml/>, <restricted-xml/>, <unsupported-encoding/>, and <xml-not-well-formed/>, although the more specific errors are preferred.
- <bad-namespace-prefix/> -- the entity has sent a namespace prefix that is unsupported, or has sent no namespace prefix on an element that requires such a prefix (see XML Namespace Names and Prefixes).
- <conflict/> -- the server is closing the active stream for this entity because a new stream has been initiated that conflicts with the existing stream.
- <connection-timeout/> -- the entity has not generated any traffic over the stream for some period of time (configurable according to a local service policy).
- <host-gone/> -- the value of the 'to' attribute provided by the initiating entity in the stream header corresponds to a hostname that is no longer hosted by the server.
- <host-unknown/> -- the value of the 'to' attribute provided by the initiating entity in the stream header does not correspond to a hostname that is hosted by the server.
- <improper-addressing/> -- a stanza sent between two servers lacks a 'to' or 'from' attribute (or the attribute has no value).
- <internal-server-error/> -- the server has experienced a misconfiguration or an otherwise-undefined internal error that prevents it from servicing the stream.
- <invalid-from/> -- the JID or hostname provided in a 'from' address does not match an authorized JID or validated domain negotiated between servers via SASL or dialback, or between a client and a server via authentication and resource binding.
- <invalid-id/> -- the stream ID or dialback ID is invalid or does not match an ID previously provided.
- <invalid-namespace/> -- the streams namespace name is something other than "http://etherx.jabber.org/streams" or the dialback namespace name is something other than "jabber:server:dialback" (see XML Namespace Names and Prefixes).
- <invalid-xml/> -- the entity has sent invalid XML over the stream to a server that performs validation (see Validation).
- <not-authorized/> -- the entity has attempted to send data before the stream has been authenticated, or otherwise is not authorized to perform an action related to stream negotiation; the receiving entity MUST NOT process the offending stanza before sending the stream error.
- <policy-violation/> -- the entity has violated some local service policy; the server MAY choose to specify the policy in the <text/> element or an application-specific condition element.
- <remote-connection-failed/> -- the server is unable to properly connect to a remote entity that is required for authentication or authorization.
- <resource-constraint/> -- the server lacks the system resources necessary to service the stream.
- <restricted-xml/> -- the entity has attempted to send restricted XML features such as a comment, processing instruction, DTD, entity reference, or unescaped character (see Restrictions).
- <see-other-host/> -- the server will not provide service to the initiating entity but is redirecting traffic to another host; the server SHOULD specify the alternate hostname or IP address (which MUST be a valid domain identifier) as the XML character data of the <see-other-host/> element.
- <system-shutdown/> -- the server is being shut down and all active streams are being closed.
- <undefined-condition/> -- the error condition is not one of those defined by the other conditions in this list; this error condition SHOULD be used only in conjunction with an application-specific condition.
- <unsupported-encoding/> -- the initiating entity has encoded the stream in an encoding that is not supported by the server (see Character Encoding).
- <unsupported-stanza-type/> -- the initiating entity has sent a first-level child of the stream that is not supported by the server.
- <unsupported-version/> -- the value of the 'version' attribute provided by the initiating entity in the stream header specifies a version of XMPP that is not supported by the server; the server MAY specify the version(s) it supports in the <text/> element.
- <xml-not-well-formed/> -- the initiating entity has sent XML that is not well-formed as defined by [XML].
4.7.4. 特定应用的错误因素
注意,一个应用可以(MAY)通过在错误元素中包含一个合适的命名空间限定的子元素来提供特定应用的流错误信息。特定应用元素应当(SHOULD)补充或进一步限定一个已定义的元素。因此,<error/>元素将包含两、三个子元素:
<stream:error> <xml-not-well-formed xmlns='urn:ietf:params:xml:ns:xmpp-streams'/> <text xml:lang='en' xmlns='urn:ietf:params:xml:ns:xmpp-streams'> Some special application diagnostic information! </text> <escape-your-data xmlns='application-ns'/> </stream:error> </stream:stream>
4.8. 简化的流的例子
此部分包含两个简化的客户端与服务器(“C”行是从客户端发送到服务器,而“S”行是由服务器发送到客户端)间基于流会话的例子;这些例子用于进一步的介绍这些概念。
A basic "session": //一个基础的会话
C: <?xml version='1.0'?> <stream:stream to='example.com' xmlns='jabber:client' xmlns:stream='http://etherx.jabber.org/streams' version='1.0'> S: <?xml version='1.0'?> <stream:stream from='example.com' id='someid' xmlns='jabber:client' xmlns:stream='http://etherx.jabber.org/streams' version='1.0'> ... encryption, authentication, and resource binding ... C: <message from='juliet@example.com' to='romeo@example.net' xml:lang='en'> C: <body>Art thou not Romeo, and a Montague?</body> C: </message> S: <message from='romeo@example.net' to='juliet@example.com' xml:lang='en'> S: <body>Neither, fair saint, if either thee dislike.</body> S: </message> C: </stream:stream> S: </stream:stream>
A "session" gone bad: //出现错误的会话
C: <?xml version='1.0'?> <stream:stream to='example.com' xmlns='jabber:client' xmlns:stream='http://etherx.jabber.org/streams' version='1.0'> S: <?xml version='1.0'?> <stream:stream from='example.com' id='someid' xmlns='jabber:client' xmlns:stream='http://etherx.jabber.org/streams' version='1.0'> ... encryption, authentication, and resource binding ... C: <message xml:lang='en'> <body>Bad XML, no closing body tag! </message> S: <stream:error> <xml-not-well-formed xmlns='urn:ietf:params:xml:ns:xmpp-streams'/> </stream:error> S: </stream:stream>
XMPP翻译:RFC 3920核心[3]到此结束,请继续关注 XMPP翻译:RFC 3920核心[4]