9. 取消请求 (Canceling a Request)
9 取消请求 (Canceling a Request)
前一节讨论了 UA 为所有方法的请求生成请求和处理响应的一般行为. 本节讨论一种通用方法, 称为 CANCEL.
顾名思义, CANCEL 请求用于取消客户端先前发送的请求. 具体而言, 它要求 UAS 停止处理该请求, 并为该请求生成错误响应. 对于 UAS 已经给出最终响应的请求, CANCEL 没有效果. 因此, CANCEL 最适用于那些服务器可能需要较长时间才能响应的请求. 基于这一原因, CANCEL 最适合 INVITE 请求, 因为生成 INVITE 的响应可能需要较长时间. 在这种用法中, UAS 如果收到针对 INVITE 的 CANCEL 请求, 但尚未发送最终响应, 则会 "stop ringing", 然后以特定错误响应 (487) 响应该 INVITE.
CANCEL 请求可以由 proxy 和 user agent client 构造并发送. Section 15 讨论 UAC 会在什么条件下 CANCEL 一个 INVITE 请求, Section 16.10 讨论 proxy 对 CANCEL 的使用.
有状态 proxy 会响应 CANCEL, 而不是简单地转发它会从下游元素收到的响应. 因此, CANCEL 被称为 "hop-by-hop" 请求, 因为它会在每一个有状态 proxy 跳点上得到响应.
9.1 客户端行为 (Client Behavior)
CANCEL 请求 SHOULD NOT 用于取消 INVITE 以外的请求.
由于 INVITE 以外的请求会被立即响应, 为非 INVITE 请求发送 CANCEL 总会造成竞态条件.
以下过程用于构造 CANCEL 请求. CANCEL 请求中的 Request-URI, Call-ID, To, CSeq 的数字部分以及 From header field MUST 与被取消请求中的对应值完全相同, 包括 tag. 客户端构造的 CANCEL MUST 只有一个 Via header field value, 且与被取消请求中的顶部 Via value 匹配. 对这些 header field 使用相同值, 可使 CANCEL 与其取消的请求相匹配 (Section 9.2 指出这种匹配如何发生). 然而, CSeq header field 的 method 部分 MUST 具有 CANCEL 值. 这使其能够作为一个独立事务被识别和处理 (见 Section 17).
如果被取消的请求包含 Route header field, CANCEL 请求 MUST 包含该 Route header field 的值.
这是为了让无状态 proxy 能够正确路由 CANCEL 请求.
CANCEL 请求 MUST NOT 包含任何 Require 或 Proxy-Require header field.
CANCEL 构造完成后, 客户端 SHOULD 检查它是否已经收到被取消请求 (本文称为 "original request") 的任何响应 (临时响应或最终响应).
如果尚未收到临时响应, CANCEL 请求 MUST NOT 被发送; 客户端反而 MUST 等待临时响应到达后再发送该请求. 如果原始请求已经生成最终响应, CANCEL SHOULD NOT 被发送, 因为它实际上是 no-op, CANCEL 对已经生成最终响应的请求没有影响. 当客户端决定发送 CANCEL 时, 它为 CANCEL 创建一个 client transaction, 并将 CANCEL 请求连同目的地址, 端口和传输交给该事务. CANCEL 的目的地址, 端口和传输 MUST 与发送原始请求时使用的值完全相同.
如果允许在收到前一请求的响应之前发送 CANCEL, 服务器可能会在收到原始请求之前收到 CANCEL.
注意, 与原始请求对应的事务和 CANCEL 事务都会独立完成. 然而, 取消请求的 UAC 不能依赖于收到针对原始请求的 487 (Request Terminated) 响应, 因为符合 RFC 2543 的 UAS 不会生成这样的响应. 如果原始请求在 64*T1 秒内没有最终响应 (T1 在 Section 17.1.1.1 中定义), 客户端 SHOULD 将原始事务视为已取消, 并 SHOULD 销毁处理原始请求的 client transaction.
9.2 服务器行为 (Server Behavior)
CANCEL 方法请求服务器侧的 TU 取消一个挂起事务. TU 通过取得 CANCEL 请求, 然后假定请求方法是除 CANCEL 或 ACK 以外的任意方法, 并应用 Section 17.2.3 的事务匹配过程, 来确定要取消的事务. 匹配到的事务就是要取消的事务.
服务器处理 CANCEL 请求的方式取决于服务器类型. 无状态 proxy 会转发它, 有状态 proxy 可能响应它并生成自己的若干 CANCEL 请求, UAS 则会响应它. 关于 proxy 对 CANCEL 的处理, 见 Section 16.10.
UAS 首先按照 Section 8.2 中描述的一般 UAS 处理来处理 CANCEL 请求. 然而, 由于 CANCEL 请求是 hop-by-hop 且不能被重新提交, 服务器不能对它进行 challenge 以取得 Authorization header field 中的适当凭据. 还应注意, CANCEL 请求不包含 Require header field.
如果 UAS 按照上述过程没有找到与 CANCEL 匹配的事务, 它 SHOULD 以 481 (Call Leg/Transaction Does Not Exist) 响应 CANCEL. 如果原始请求的事务仍然存在, UAS 在收到 CANCEL 请求时的行为取决于它是否已经为原始请求发送最终响应. 如果已经发送, CANCEL 请求对原始请求的处理没有影响, 对任何会话状态没有影响, 对为原始请求生成的响应也没有影响. 如果 UAS 尚未为原始请求发出最终响应, 其行为取决于原始请求的方法. 如果原始请求是 INVITE, UAS SHOULD 立即以 487 (Request Terminated) 响应 INVITE. CANCEL 请求对本规范中定义的任何其他方法的事务处理没有影响.
无论原始请求的方法是什么, 只要 CANCEL 匹配了一个现有事务, UAS 就以 200 (OK) 响应该 CANCEL 请求本身. 该响应按照 Section 8.2.6 中描述的过程构造, 并注意 CANCEL 响应中的 To tag 与原始请求响应中的 To tag SHOULD 相同. 对 CANCEL 的响应被传递给 server transaction 进行传输.