- QUIC 传输协议具有 HTTP 传输所需的几个特性,例如流多路复用、每个流的流控制和低延迟连接建立。本文档描述了 HTTP 语义在 QUIC 上的映射。本文档还确定了 QUIC 包含的 HTTP/2 功能,并描述了如何将 HTTP/2 扩展移植到 HTTP/3。
不要部署此版本的 HTTP
请勿部署此版本的 HTTP/3,直到它位于 RFC 中。此版本仍在进行中。对于试用部署,请使用早期版本。
读者须知
该草案的讨论在 QUIC 工作组邮件列表 (quic@ietf.org) 上进行,该邮件存档于 https://mailarchive.ietf.org/arch/search/?email_list=quic。
工作组信息可以在https://github.com/quicwg找到;该草案的源代码和问题列表可以在 https://github.com/quicwg/base-drafts/labels/-http找到。
本备忘录的状态
本互联网草案的提交完全符合 BCP 78 和 BCP 79 的规定
Internet-Drafts 是 Internet 工程任务组 (IETF) 的工作文件。请注意,其他小组也可以将工作文档作为 Internet-Drafts 分发。当前 Internet-Drafts 列表位于https://datatracker.ietf.org/drafts/current/。
Internet-Drafts 是有效期最长为六个月的草稿文件,可以随时被其他文件更新、替换或作废。将 Internet-Drafts 用作参考材料或引用它们而不是“正在进行的工作”是不合适的。
该互联网草案将于 2021 年 8 月 6 日到期
版权声明
版权所有 (c) 2021 IETF Trust 和文件作者。版权所有。
本文件受 BCP 78 和 IETF 信托关于 IETF 文件的法律规定 ( https://trustee.ietf.org/license-info ) 的约束,该条款在本文件发布之日生效。请仔细阅读这些文件,因为它们描述了您对本文件的权利和限制。从本文档中提取的代码组件必须包含 Trust Legal Provisions 第 4.e 节中所述的简化 BSD 许可文本,并且按照简化 BSD 许可中的说明在不保证的情况下提供。
一、简介
HTTP 语义 ( [ SEMANTICS ] ) 用于 Internet 上的广泛服务。这些语义最常用于 HTTP/1.1 和 HTTP/2。HTTP/1.1 已用于各种传输层和会话层,而 HTTP/2 主要用于 TCP 上的 TLS。HTTP/3 通过新的传输协议 QUIC 支持相同的语义。
1.1。HTTP 的早期版本
HTTP/1.1 ( [ HTTP11 ] ) 使用空格分隔的文本字段来传达 HTTP 消息。虽然这些交换是人类可读的,但使用空格进行消息格式化会导致解析复杂性和对变体行为的过度容忍。
由于 HTTP/1.1 不包含多路复用层,因此通常使用多个 TCP 连接来并行处理请求。然而,这对拥塞控制和网络效率有负面影响,因为 TCP 不跨多个连接共享拥塞控制。
HTTP/2 ( [ HTTP2 ] ) 引入了二进制帧和多路复用层,以在不修改传输层的情况下改善延迟。但是,由于 HTTP/2 多路复用的并行特性对 TCP 的丢失恢复机制不可见,因此丢失或重新排序的数据包会导致所有活动事务都经历停顿,无论该事务是否直接受到丢失数据包的影响。
1.2. 委托给 QUIC
QUIC 传输协议结合了流多路复用和每个流的流控制,类似于 HTTP/2 成帧层提供的。通过提供流级别的可靠性和整个连接的拥塞控制,与 TCP 映射相比,QUIC 能够提高 HTTP 的性能。QUIC 还在传输层整合了 TLS 1.3 ( [ TLS13 ] ),提供与通过 TCP 运行 TLS 相当的机密性和完整性,并改进了 TCP Fast Open ( [ TFO ] ) 的连接设置延迟。
本文档定义了 HTTP/3,它是 HTTP 语义在 QUIC 传输协议上的映射,大量借鉴了 HTTP/2 的设计。HTTP/3 依赖于 QUIC 来提供数据的机密性和完整性保护;对等认证;可靠、有序、按流交付。在将流生命周期和流控制问题委托给 QUIC 时,每个流都使用类似于 HTTP/2 框架的二进制框架。QUIC 包含一些 HTTP/2 功能,而其他功能则在 QUIC 之上实现。
QUIC 在[ QUIC-TRANSPORT ]中有描述。有关 HTTP/2 的完整描述,请参阅 [ HTTP2 ]。
2. HTTP/3 协议概述
HTTP/3 使用 QUIC 传输协议和类似于 HTTP/2 的内部框架层为 HTTP 语义提供传输。
一旦客户端知道某个端点存在 HTTP/3 服务器,它就会打开一个 QUIC 连接。QUIC 提供协议协商、基于流的多路复用和流控制。第 3.1 节描述了 HTTP/3 端点的发现 。
在每个流中,HTTP/3 通信的基本单位是一个帧(第 7.2 节)。每种帧类型都有不同的用途。例如,HEADERS 和 DATA 帧构成了 HTTP 请求和响应的基础(第 4.1 节)。适用于整个连接的帧在专用控制流上传送。
使用 QUIC 流抽象来执行请求的多路复用,在[ QUIC-TRANSPORT ]的第 2 节中进行了描述。每个请求-响应对使用一个 QUIC 流。流相互独立,因此一个流被阻塞或丢包不会阻止其他流的进展。
服务器推送是 HTTP/2 ( [ HTTP2 ] ) 中引入的一种交互模式,它允许服务器将请求-响应交换推送到客户端,以等待客户端发出指示的请求。这权衡了网络使用与潜在的延迟增益。几个 HTTP/3 帧用于管理服务器推送,例如 PUSH_PROMISE、MAX_PUSH_ID 和 CANCEL_PUSH。
与 HTTP/2 一样,请求和响应字段被压缩以进行传输。因为 HPACK ( [ HPACK ] ) 依赖于压缩字段部分的按顺序传输(QUIC 不提供保证),所以 HTTP/3 用 QPACK ( [ QPACK ] ) 替换了 HPACK。QPACK 使用单独的单向流来修改和跟踪字段表状态,而编码字段部分引用表的状态而不修改它。
2.1。文件组织
以下部分提供了 HTTP/3 连接生命周期的详细概述:
- 连接设置和管理(第 3 节)介绍了如何发现 HTTP/3 端点并建立 HTTP/3 连接。
- HTTP 请求生命周期(第 4 节)描述了如何使用帧来表达 HTTP 语义。
- 连接关闭(第 5 节)描述了 HTTP/3 连接如何优雅地或突然地终止。
有线协议的细节以及与传输的交互在后续章节中描述:
- 流映射和使用(第 6 节)描述了 QUIC 流的使用方式。
- HTTP 帧层(第 7 节)描述了大多数流上使用的帧。
- 错误处理(第 8 节)描述了如何处理和表达错误条件,无论是在特定流上还是对于整个连接。
最后部分提供了其他资源:
2.2. 约定和术语
关键词“必须”、“不得”、“要求”、“应”、“不得”、“应该”、“不应”、“推荐”、“不推荐”、“可以”和“可选”当且仅当它们以全部大写字母出现时,本文档中的 " 将按照 BCP 14 [ RFC2119 ] [ RFC8174 ]中的描述进行解释,如此处所示。
本文档使用 [ QUIC-TRANSPORT ]中的可变长度整数编码。
使用以下术语:
- 中止:
-
连接或流的突然终止,可能是由于错误情况。
- 客户:
-
启动 HTTP/3 连接的端点。客户端发送 HTTP 请求并接收 HTTP 响应。
- 联系:
-
两个端点之间的传输层连接,使用 QUIC 作为传输协议。
- 连接错误:
-
影响整个 HTTP/3 连接的错误。
- 端点:
-
连接的客户端或服务器。
- 框架:
-
HTTP/3 中流上的最小通信单元,由标头和根据帧类型构造的可变长度字节序列组成。
本文档和[ QUIC-TRANSPORT ]中都存在称为“框架”的协议元素 。如果引用了[ QUIC-TRANSPORT ]中的帧,则帧名称将以“QUIC”开头。例如,“QUIC CONNECTION_CLOSE 帧”。没有此前言的参考文献是指 第 7.2 节中定义的框架。
- HTTP/3 连接:
-
协商的应用程序协议为 HTTP/3 的 QUIC 连接。
- 同行:
-
一个端点。在讨论特定端点时,“对等点”是指远离主要讨论主题的端点。
- 接收者:
-
正在接收帧的端点。
- 发件人:
-
正在传输帧的端点。
- 服务器:
-
接受 HTTP/3 连接的端点。服务器接收 HTTP 请求并发送 HTTP 响应。
- 溪流:
-
QUIC 传输提供的双向或单向字节流。HTTP/3 连接中的所有流都可以被视为“HTTP/3 流”,但在 HTTP/3 中定义了多种流类型。
- 流错误:
-
单个流上的应用程序级错误。
最后,术语“资源”、“消息”、“用户代理”、“源服务器”、“网关”、“中介”、“代理”和“隧道”在[语义]的第 3 节中定义。
本文档中的数据包图使用 [ QUIC-TRANSPORT ]的第 1.3 节中定义的格式来说明字段的顺序和大小。
3.连接设置和管理
3.1。发现 HTTP/3 端点
HTTP 依赖于权威响应的概念:在给定目标资源在响应消息由源服务器发起(或在其方向)时的状态的情况下,该响应已被确定为对该请求最合适的响应在目标 URI 中标识。[语义]的4.3 节讨论了为 HTTP URI 定位权威服务器 。
“https”方案将授权与拥有证书相关联,客户端认为该证书对于由 URI 的授权组件标识的主机是可信赖的。在 TLS 握手中接收到服务器证书后,客户端必须使用[语义学]的第 4.3.4 节中描述的过程来验证证书是否与 URI 的源服务器匹配。如果证书无法针对 URI 的源服务器进行验证,则客户端不得认为服务器对该源具有权威性。
客户端可以尝试通过将主机标识符解析为 IP 地址来尝试访问具有“https”URI 的资源,在指定端口上建立到该地址的 QUIC 连接(包括如上所述的服务器证书验证),并发送通过该安全连接将 URI 定位到服务器的 HTTP/3 请求消息。除非使用某种其他机制来选择 HTTP/3,否则在 TLS 握手期间在应用层协议协商(ALPN;参见[ RFC7301 ] )扩展中使用令牌“h3”。
连接问题(例如,阻塞 UDP)可能导致 QUIC 连接建立失败;在这种情况下,客户端应该尝试使用基于 TCP 的 HTTP 版本。
服务器可以在任何 UDP 端口上提供 HTTP/3;替代服务广告始终包含显式端口,并且 URI 包含与方案关联的显式端口或默认端口。
3.2. 连接建立
HTTP/3 依赖于 QUIC 版本 1 作为底层传输。未来的规范可能会定义使用 HTTP/3 的其他 QUIC 传输版本。
QUIC 版本 1 使用 TLS 版本 1.3 或更高版本作为其握手协议。HTTP/3 客户端必须支持在 TLS 握手期间向服务器指示目标主机的机制。如果服务器由域名 ( [ DNS-TERMS ] ) 标识,则客户端必须发送服务器名称指示 (SNI; [ RFC6066 ] ) TLS 扩展,除非使用了指示目标主机的替代机制。
QUIC 连接按照[ QUIC-TRANSPORT ]中的描述建立。在连接建立期间,通过在 TLS 握手中选择 ALPN 令牌“h3”来指示 HTTP/3 支持。可以在同一握手中提供对其他应用层协议的支持。
虽然与核心 QUIC 协议相关的连接级别选项在初始加密握手中设置,但 HTTP/3 特定设置在 SETTINGS 帧中传达。QUIC 连接建立后,每个端点必须发送一个 SETTINGS 帧(第 7.2.4 节)作为各自 HTTP 控制流的初始帧;见第 6.2.1 节。
3.3. 连接重用
HTTP/3 连接在多个请求中是持久的。为了获得最佳性能,预计客户端不会关闭连接,直到确定不需要与服务器进行进一步通信(例如,当用户导航离开特定网页时)或直到服务器关闭连接。
一旦存在到服务器端点的连接,该连接可以重用于具有多个不同 URI 权限组件的请求。要将现有连接用于新源,客户端必须使用[语义]的第 4.3.4 节中描述的过程验证服务器为新源服务器提供的证书。这意味着客户端将需要保留服务器证书以及验证该证书所需的任何其他信息;不这样做的客户端将无法将连接重用于其他来源。
如果证书由于任何原因对于新源不可接受,则不得重用连接,并且应该为新源建立新连接。如果证书无法验证的原因可能适用于已经与连接关联的其他来源,则客户端应该重新验证这些来源的服务器证书。例如,如果由于证书已过期或被吊销而导致证书验证失败,则这可能用于使该证书用于建立权限的所有其他来源无效。
客户端不应打开多个到给定 IP 地址和 UDP 端口的 HTTP/3 连接,其中 IP 地址和端口可能来自 URI、选定的替代服务 ( [ ALTSVC ] )、配置的代理或名称解析其中任何一个。客户端可以使用不同的传输或 TLS 配置打开到相同 IP 地址和 UDP 端口的多个 HTTP/3 连接,但应避免使用相同配置创建多个连接。
鼓励服务器尽可能长时间地保持打开的 HTTP/3 连接,但在必要时允许终止空闲连接。当任一端点选择关闭 HTTP/3 连接时,终止端点应该首先发送一个 GOAWAY 帧(第 5.2 节),以便两个端点可以可靠地确定先前发送的帧是否已被处理并优雅地完成或终止任何必要的剩余任务。
不希望客户端为特定来源重用 HTTP/3 连接的服务器可以通过发送 421(错误定向请求)状态代码来响应请求来表明它对请求不具有权威性;参见[语义学]第 7.4 节。
4. HTTP 请求生命周期
4.1。HTTP 消息交换
客户端在请求流上发送 HTTP 请求,请求流是客户端发起的双向 QUIC 流;见第 6.1 节。客户端必须在给定的流上只发送一个请求。服务器在与请求相同的流上发送零个或多个临时 HTTP 响应,然后是单个最终 HTTP 响应,如下所述。有关临时和最终 HTTP 响应的描述,请参见[语义]的第 15 节。
推送的响应在服务器发起的单向 QUIC 流上发送;见 第 6.2.2 节。服务器以与标准响应相同的方式发送零个或多个临时 HTTP 响应,然后是单个最终 HTTP 响应。推送在4.4 节中有更详细的描述。
在给定的流上,收到多个请求或在最终 HTTP 响应之后收到额外的 HTTP 响应必须被视为格式错误(第 4.1.3 节)。
HTTP 消息(请求或响应)包括:
- 标头部分,作为单个 HEADERS 帧发送(参见第 7.2.2 节),
- 可选地,内容(如果存在)作为一系列 DATA 帧发送(参见第 7.2.1 节),并且
- 可选地,尾部部分(如果存在)作为单个 HEADERS 帧发送。
标题和尾部部分在[语义]的第6.3和6.5节中进行了描述;内容在[语义]的第6.4节中描述。
接收到无效的帧序列必须被视为 H3_FRAME_UNEXPECTED 类型的连接错误;见第 8 节。特别是,任何 HEADERS 帧之前的 DATA 帧,或尾部 HEADERS 帧之后的 HEADERS 或 DATA 帧,都被认为是无效的。其他帧类型,尤其是未知帧类型,可能会根据它们自己的规则被允许;见第 9 节。
服务器可以在响应消息的帧之前、之后或与响应消息的帧交错发送一个或多个 PUSH_PROMISE 帧(第 7.2.5 节)。这些 PUSH_PROMISE 帧不是响应的一部分;有关详细信息,请参阅第 4.4 节。推送流上不允许使用 PUSH_PROMISE 帧;包含 PUSH_PROMISE 帧的推送响应必须被视为 H3_FRAME_UNEXPECTED 类型的连接错误;见第 8 节。
未知类型的帧(第 9 节),包括保留帧(第 7.2.8 节)可以在请求或推送流之前、之后或与本节中描述的其他帧交错发送。
HEADERS 和 PUSH_PROMISE 帧可能会引用对 QPACK 动态表的更新。虽然这些更新不是消息交换的直接部分,但必须先接收和处理它们,然后才能使用消息。有关详细信息,请参阅 第 4.1.1 节。
没有为 HTTP/3 定义传输编码(参见[ HTTP11 ]的第 6.1 节);不得使用 Transfer-Encoding 头域。
当且仅当一个或多个临时响应(1xx;参见[语义]的第 15.2 节)在对同一请求的最终响应之前,响应可能包含多个消息。临时响应不包含内容或预告片部分。
HTTP 请求/响应交换完全使用客户端发起的双向 QUIC 流。发送请求后,客户端必须关闭要发送的流。除非使用 CONNECT 方法(参见第 4.2 节),否则客户端不得依赖于接收到对其请求的响应来进行流关闭。发送最终响应后,服务器必须关闭要发送的流。此时,QUIC 流已完全关闭。
当一个流关闭时,这表示最终 HTTP 消息的结束。由于某些消息很大或无界,端点应该在收到足够多的消息以取得进展后开始处理部分 HTTP 消息。如果客户端发起的流在没有足够的 HTTP 消息来提供完整响应的情况下终止,则服务器应该中止其响应流,错误代码为 H3_REQUEST_INCOMPLETE;见第 8 节。
如果响应不依赖于尚未发送和接收的请求的任何部分,则服务器可以在客户端发送整个请求之前发送完整的响应。当服务器不需要接收请求的剩余部分时,它可以中止读取请求流,发送完整的响应,并干净地关闭流的发送部分。当请求客户端停止在请求流上发送时,应该使用错误代码 H3_NO_ERROR。客户端不能因为他们的请求突然终止而丢弃完整的响应,尽管客户端总是可以出于其他原因自行决定丢弃响应。如果服务器发送了部分或完整的响应但没有中止读取请求,客户端应该继续发送请求的主体并正常关闭流。
4.1.1。字段格式化和压缩
HTTP 消息携带元数据作为一系列称为 HTTP 字段的键值对;参见[语义]的第6.3和6.5节。有关已注册 HTTP 字段的列表,请参阅https://www.iana.org/assignments/http-fields/上维护的“超文本传输协议 (HTTP) 字段名称注册表” 。
- 注意:在[ SEMANTICS ]获得批准 之前,此注册表将不存在。RFC 编辑器,请在发布前删除此注释。
字段名称是包含 ASCII 字符子集的字符串。HTTP 字段名称和值的属性在[语义]的第 5.1 节中进行了更详细的讨论。与 HTTP/2 一样,字段名称中的字符必须在编码之前转换为小写。字段名称中包含大写字符的请求或响应必须被视为格式错误(第 4.1.3 节)。
与 HTTP/2 一样,HTTP/3 不使用 Connection 头字段来指示特定于连接的字段;在此协议中,特定于连接的元数据通过其他方式传送。端点不得生成包含连接特定字段的 HTTP/3 字段部分;任何包含特定连接字段的消息必须被视为格式错误(第 4.1.3 节)。
唯一的例外是 TE 标头字段,它可能出现在 HTTP/3 请求标头中;如果是,它不能包含除“trailers”之外的任何值。
将 HTTP/1.x 消息转换为 HTTP/3 的中介必须删除[ SEMANTICS ]的第 7.6.1 节中讨论的特定于连接的头字段,否则它们的消息将被其他 HTTP/3 端点视为格式错误(第 4.1 节.3 )。
4.1.1.1。伪标题字段
与 HTTP/2 一样,HTTP/3 使用一系列伪标题字段,其中字段名称以“:”字符(ASCII 0x3a)开头。这些伪标头字段传达目标 URI、请求的方法和响应的状态代码。
伪标头字段不是 HTTP 字段。除了本文档中定义的之外,端点不得生成伪头字段;但是,延期可以协商修改此限制;见 第 9 节。
伪标题字段仅在定义它们的上下文中有效。为请求定义的伪标头字段不得出现在响应中;为响应定义的伪标头字段不得出现在请求中。伪标题字段不得出现在预告片部分中。端点必须将包含未定义或无效伪标头字段的请求或响应视为格式错误(第 4.1.3 节)。
所有伪标题字段必须出现在标题部分中的常规标题字段之前。任何包含出现在常规标头字段之后的标头部分中的伪标头字段的请求或响应都必须被视为格式错误(第 4.1.3 节)。
为请求定义了以下伪标头字段:
- “:方法”:
- “:方案”:
-
":scheme" 不限于方案 "http" 和 "https" 的 URI。代理或网关可以转换非 HTTP 方案的请求,使 HTTP 能够与非 HTTP 服务进行交互。
-
有关使用“https”以外的方案的指导,请参见第 3.1.2 节。
- “:权威”:
-
包含目标 URI 的授权部分([ URI ]的第 3.2 节)。权限不得包含方案“http”或“https”的 URI 的已弃用“userinfo”子组件。
-
为确保 HTTP/1.1 请求行可以准确再现,当从具有源或星号形式的请求目标的 HTTP/1.1 请求转换时,必须省略此伪头字段;参见[语义学]第 7.1 节。直接生成 HTTP/3 请求的客户端应该使用 ":authority" 伪头字段而不是 Host 字段。如果请求中不存在主机字段,则将 HTTP/3 请求转换为 HTTP/1.1 的中介必须通过复制 ":authority" 伪标头字段的值来创建主机字段。
- “:小路”:
-
包含目标 URI 的路径和查询部分(“绝对路径”产生式和可选的“?”字符后跟“查询”产生式;参见[ URI ]的第3.3和3.4节。星号形式的请求包括":path" 伪标题字段的值 '*'。
-
对于“http”或“https”URI,此伪头字段不得为空;不包含路径组件的“http”或“https”URI 必须包含“/”值。此规则的例外是对不包含路径组件的“http”或“https”URI 的 OPTIONS 请求;这些必须包含一个值为 '*' 的 ":path" 伪标题字段;参见 [语义学]第 7.1 节。
所有 HTTP/3 请求必须只包含一个 ":method"、":scheme" 和 ":path" 伪标头字段的值,除非它是一个 CONNECT 请求;见 第 4.2 节。
如果 ":scheme" 伪头字段标识了具有强制权限组件(包括 "http" 和 "https")的方案,则请求必须包含 ":authority" 伪头字段或 "Host" 头场地。如果这些字段存在,则它们不得为空。如果两个字段都存在,它们必须包含相同的值。如果方案没有强制授权组件并且在请求目标中没有提供任何内容,则请求不得包含“:authority”伪标头或“Host”标头字段。
省略强制性伪标头字段或包含这些伪标头字段的无效值的 HTTP 请求格式错误(第 4.1.3 节)。
HTTP/3 没有定义携带包含在 HTTP/1.1 请求行中的版本标识符的方法。
对于响应,定义了一个带有 HTTP 状态代码的“:status”伪头字段;参见[语义学]第 15 节。这个伪头域必须包含在所有响应中;否则,响应格式错误(第 4.1.3 节)。
HTTP/3 没有定义携带包含在 HTTP/1.1 状态行中的版本或原因短语的方法。
4.1.1.2。场压缩
[ QPACK ]描述了 HPACK 的一种变体,它使编码器可以控制压缩可能导致多少行头阻塞。这允许编码器平衡压缩效率和延迟。HTTP/3 使用 QPACK 来压缩 header 和 trailing 部分,包括 header 部分中的伪 header 字段。
为了获得更好的压缩效率,“Cookie”字段([ RFC6265 ])可以在压缩之前分成单独的字段行,每行都有一个或多个 cookie 对。如果解压缩的字段部分包含多个 cookie 字段行,则必须使用两字节分隔符 0x3b、0x20(ASCII 字符串“;”)将它们连接成单个字节字符串,然后再传递到 HTTP/2 以外的上下文或HTTP/3,例如 HTTP/1.1 连接,或通用 HTTP 服务器应用程序。
4.1.1.3。标题大小约束
HTTP/3 实现可以对它将接受的单个 HTTP 消息的消息头的最大大小施加限制。接收到比它愿意处理的更大的标头部分的服务器可以发送 HTTP 431(请求标头字段太大)状态代码([ RFC6585 ])。客户端可以丢弃它无法处理的响应。字段列表的大小是根据未压缩的字段大小计算的,包括名称和值的长度(以字节为单位)加上每个字段的 32 个字节的开销。
如果一个实现希望将此限制通知其对等方,则可以在 SETTINGS_MAX_FIELD_SECTION_SIZE 参数中将其作为字节数传送。接收到此参数的实现不应该发送超过指示大小的 HTTP 消息头,因为对等方可能会拒绝处理它。但是,HTTP 消息在到达源服务器之前可以经过一个或多个中介;参见[语义学]第 3.7 节。因为这个限制是由处理消息的每个实现单独应用的,所以不能保证低于这个限制的消息被接受。
4.1.2. 请求取消和拒绝
一旦请求流被打开,请求可以被任一端点取消。如果响应不再感兴趣,客户会取消请求;如果服务器无法响应或选择不响应,则服务器会取消请求。如果可能,建议服务器发送带有适当状态代码的 HTTP 响应,而不是取消它已经开始处理的请求。
实现应该通过突然终止仍然打开的流的任何方向来取消请求。这意味着重置流的发送部分并中止对流的接收部分的读取;请参阅[ QUIC-TRANSPORT ]的第 2.4 节。
当服务器取消请求而不执行任何应用程序处理时,该请求被视为“被拒绝”。服务器应该使用错误代码 H3_REQUEST_REJECTED 中止其响应流。在这种情况下,“已处理”意味着来自流的一些数据被传递到某些更高层的软件,这些软件可能因此采取了一些行动。客户端可以将被服务器拒绝的请求视为根本没有发送过,从而允许稍后重试它们。
对于部分或全部处理的请求,服务器不得使用 H3_REQUEST_REJECTED 错误代码。当服务器在部分处理后放弃响应时,它应该以错误代码 H3_REQUEST_CANCELLED 中止其响应流。
客户端应该使用错误代码 H3_REQUEST_CANCELLED 来取消请求。收到此错误代码后,如果未执行任何处理,服务器可能会使用错误代码 H3_REQUEST_REJECTED 突然终止响应。客户端不得使用 H3_REQUEST_REJECTED 错误代码,除非服务器使用此错误代码请求关闭请求流。
如果在收到完整响应后取消流,客户端可以忽略取消并使用响应。但是,如果在收到部分响应后取消流,则不应使用响应。只有 GET、PUT 或 DELETE 等幂等操作可以安全地重试;客户端不应该使用非幂等方法自动重试请求,除非它有某种方法可以知道请求语义是独立于方法的幂等,或者有某种方法可以检测到原始请求从未被应用。有关更多详细信息,请参阅[语义]的第 9.2.2 节。
4.1.3。格式错误的请求和响应
格式错误的请求或响应是一个有效的帧序列,但由于以下原因而无效:
- 禁止字段或伪标题字段的存在,
- 没有强制性的伪标题字段,
- 伪标题字段的无效值,
- 字段后的伪标题字段,
- 无效的 HTTP 消息序列,
- 包含大写字段名称,或
- 在字段名称或值中包含无效字符。
如果 Content-Length 头字段的值不等于 DATA 的和接收到的帧长度。被定义为从不包含内容的响应,即使存在 Content-Length,也可以具有非零的 Content-Length 字段,即使 DATA 帧中不包含任何内容。
处理 HTTP 请求或响应的中介(即任何不充当隧道的中介)不得转发格式错误的请求或响应。检测到的格式错误的请求或响应必须被视为 H3_MESSAGE_ERROR 类型的流错误(第 8 节)。
对于格式错误的请求,服务器可以在关闭或重置流之前发送一个指示错误的 HTTP 响应。客户端不得接受格式错误的响应。请注意,这些要求旨在防止针对 HTTP 的几种常见攻击;它们是故意严格的,因为放纵可能会使实现暴露于这些漏洞。
4.2. 连接方法
CONNECT 方法请求接收方建立一条到请求目标标识的目标源服务器的隧道;参见[语义学]第 9.3.6 节。它主要与 HTTP 代理一起使用,以与源服务器建立 TLS 会话,以便与“https”资源进行交互。
在 HTTP/1.x 中,CONNECT 用于将整个 HTTP 连接转换为到远程主机的隧道。在 HTTP/2 和 HTTP/3 中,CONNECT 方法用于在单个流上建立隧道。
一个 CONNECT 请求必须按如下方式构造:
- ":method" 伪头字段设置为 "CONNECT"
- ":scheme" 和 ":path" 伪标题字段被省略
- ":authority" 伪头字段包含要连接的主机和端口(相当于 CONNECT 请求的请求目标的权限形式;参见[语义]的第 7.1 节)
请求流在请求结束时保持打开以携带要传输的数据。不符合这些限制的 CONNECT 请求格式不正确;请参阅第 4.1.3 节。
支持 CONNECT 的代理会建立一个 TCP 连接([ RFC0793 ])到在 ":authority" 伪标头字段中标识的服务器。一旦成功建立此连接,代理就会向客户端发送一个包含 2xx 系列状态代码的 HEADERS 帧,如[语义]的第 15.3 节中所定义。
流上的所有 DATA 帧都对应于 TCP 连接上发送或接收的数据。客户端发送的任何 DATA 帧的有效载荷由代理传输到 TCP 服务器;从 TCP 服务器接收到的数据被代理打包成 DATA 帧。请注意,不能保证 TCP 段的大小和数量可预测地映射到 HTTP DATA 或 QUIC STREAM 帧的大小和数量。
一旦 CONNECT 方法完成,就只允许在流上发送 DATA 帧。如果扩展定义特别允许,可以使用扩展帧。收到任何其他已知帧类型必须被视为 H3_FRAME_UNEXPECTED 类型的连接错误;见第 8 节。
TCP 连接可以由任一对等方关闭。当客户端结束请求流(即代理处的接收流进入“Data Recvd”状态)时,代理将在其与 TCP 服务器的连接上设置 FIN 位。当代理接收到一个设置了 FIN 位的数据包时,它将关闭它发送给客户端的发送流。在单个方向上保持半关闭状态的 TCP 连接并非无效,但服务器通常处理不当,因此客户端不应在仍期望从 CONNECT 目标接收数据时关闭流以进行发送。
通过突然终止流来表示 TCP 连接错误。代理将 TCP 连接中的任何错误(包括接收设置了 RST 位的 TCP 段)视为 H3_CONNECT_ERROR 类型的流错误;见 第 8 节。相应地,如果代理检测到流或 QUIC 连接错误,它必须关闭 TCP 连接。如果底层 TCP 实现允许,代理应该发送一个设置了 RST 位的 TCP 段。
由于 CONNECT 创建了一个到任意服务器的隧道,支持 CONNECT 的代理应该将其使用限制在一组已知端口或安全请求目标列表;有关更多详细信息,请参阅[语义]的第 9.3.6 节。
4.3. HTTP 升级
HTTP/3 不支持 HTTP 升级机制([ SEMANTICS ]的第 7.8 节)或 101(交换协议)信息状态代码([ SEMANTICS ]的第 15.2.2 节)。
4.4. 服务器推送
服务器推送是一种交互模式,它允许服务器将请求-响应交换推送到客户端,以等待客户端发出指示的请求。这权衡了网络使用与潜在的延迟增益。HTTP/3 服务器推送类似于 [ HTTP2 ]的第 8.2 节中描述的内容,但使用不同的机制。
每个服务器推送都由服务器分配一个唯一的推送 ID。Push ID 用于在 HTTP/3 连接的整个生命周期中指代各种上下文中的推送。
Push ID空间从零开始,到MAX_PUSH_ID帧设置的最大值结束;请参阅第 7.2.7 节。特别是,在客户端发送 MAX_PUSH_ID 帧之前,服务器无法推送。客户端发送 MAX_PUSH_ID 帧来控制服务器可以承诺的推送次数。服务器应该按顺序使用 Push ID,从零开始。当没有发送 MAX_PUSH_ID 帧或当流引用大于最大推送 ID 的推送 ID 时,客户端必须将接收推送流视为 H3_ID_ERROR 类型的连接错误(第 8 节)。
Push ID 用于一个或多个 PUSH_PROMISE 帧(第 7.2.5 节),这些帧携带请求消息的标头部分。这些帧在生成推送的请求流上发送。这允许服务器推送与客户端请求相关联。当在多个请求流上承诺相同的 Push ID 时,解压后的请求字段部分必须包含相同顺序的相同字段,并且每个字段中的名称和值都必须相同。
然后将推送 ID 包含在最终履行这些承诺的推送流中;见第 6.2.2 节。推送流标识它履行的承诺的推送 ID,然后包含对承诺请求的响应,如第 4.1 节所述。
最后,Push ID 可以用在 CANCEL_PUSH 帧中;请参阅 第 7.2.3 节。客户使用此框架表示他们不希望收到承诺的资源。服务器使用这个框架来表明他们不会履行之前的承诺。
并非所有请求都可以推送。服务器可以推送具有以下属性的请求:
服务器必须在 ":authority" 伪头字段中包含一个服务器对其具有权威性的值。如果客户端尚未验证推送请求所指示的源的连接,它必须执行与在连接上发送该源的请求之前相同的验证过程;见第 3.3 节。如果此验证失败,则客户端不得认为服务器对该来源具有权威性。
客户端应该在收到一个 PUSH_PROMISE 帧时发送一个 CANCEL_PUSH 帧,该帧携带的请求是不可缓存的,不知道是安全的,表示存在请求主体,或者它不认为服务器具有权威性。不得使用或缓存任何相应的响应。
每个推送的响应都与一个或多个客户端请求相关联。推送与接收到 PUSH_PROMISE 帧的请求流相关联。在多个请求流上使用具有相同推送 ID 的 PUSH_PROMISE 帧可以将相同的服务器推送与其他客户端请求相关联。这些关联不影响协议的运行,但可以由用户代理在决定如何使用推送资源时考虑。
与响应的某些部分相关的 PUSH_PROMISE 帧的顺序很重要。服务器应该在发送引用承诺响应的 HEADERS 或 DATA 帧之前发送 PUSH_PROMISE 帧。这减少了客户端请求将由服务器推送的资源的机会。
由于重新排序,推流数据可以在相应的 PUSH_PROMISE 帧之前到达。当客户端接收到带有未知推送 ID 的新推送流时,关联的客户端请求和推送的请求头字段都是未知的。客户端可以缓存流数据以期待匹配的 PUSH_PROMISE。客户端可以使用流流控制(参见[ QUIC-TRANSPORT ]的第 4.1 节)来限制服务器可以提交到推送流的数据量。
推送流数据也可以在客户端取消推送后到达。在这种情况下,客户端可以使用错误代码 H3_REQUEST_CANCELLED 中止读取流。这要求服务器不要传输额外的数据,并表明它将在收到时被丢弃。
如果客户端实现了 HTTP 缓存,则可缓存的推送响应(参见[ CACHING ]的第 3 节)可以被客户端存储。在接收到推送的响应时,推送的响应被认为在源服务器上成功验证(例如,如果存在“no-cache”缓存响应指令;请参阅[ CACHING ]的第 5.2.2.3 节)。
不可缓存的推送响应不得由任何 HTTP 缓存存储。它们可以单独提供给应用程序。
5.连接关闭
一旦建立,HTTP/3 连接就可以随着时间的推移用于许多请求和响应,直到连接关闭。连接关闭可以通过多种不同方式中的任何一种发生。
5.1。空闲连接
每个 QUIC 端点在握手期间声明一个空闲超时。如果 QUIC 连接保持空闲(没有收到数据包)超过此持续时间,则对等方将假定连接已关闭。如果现有连接的空闲时间超过 QUIC 握手期间协商的空闲超时时间,HTTP/3 实现将需要为新请求打开一个新的 HTTP/3 连接,如果接近空闲超时时间,应该这样做;请参阅[ QUIC-TRANSPORT ]的第 10.1 节。
如[ QUIC-TRANSPORT ]的第 10.1.2 节所述,当请求或服务器推送有未完成的响应时,HTTP 客户端应请求传输保持连接打开。如果客户端不期望来自服务器的响应,则允许空闲连接超时比花费精力维护可能不需要的连接更可取。网关可以根据需要维护连接,而不是产生与服务器建立连接的延迟成本。服务器不应主动保持连接打开。
5.2. 连接关闭
即使连接不是空闲的,任何一个端点都可以决定停止使用该连接并启动一个正常的连接关闭。端点通过发送 GOAWAY 帧(第 7.2.6 节)启动 HTTP/3 连接的正常关闭。GOAWAY 帧包含一个标识符,该标识符向接收者指示在此连接中已处理或可能处理的请求或推送的范围。服务器发送一个客户端发起的双向 Stream ID;客户端发送一个 Push ID(第 4.4 节)。GOAWAY 的发送者拒绝具有指定标识符或更大标识符的请求或推送(第 4.1.2 节)。如果没有处理请求或推送,则此标识符可能为零。
GOAWAY 帧中的信息使客户端和服务器能够在关闭 HTTP/3 连接之前就接受哪些请求或推送达成一致。在发送 GOAWAY 帧后,端点应该明确取消(参见第 4.1.2节和第 7.2.3 节)任何标识符大于或等于指示的请求或推送,以便清理受影响流的传输状态。随着更多请求或推送到达,端点应该继续这样做。
端点在收到对等方的 GOAWAY 帧后,不得发起新的请求或承诺在连接上进行新的推送。客户端可以建立一个新的连接来发送额外的请求。
一些请求或推送可能已经在传输中:
-
在收到 GOAWAY 帧后,如果客户端已经发送了 Stream ID 大于或等于 GOAWAY 帧中包含的标识符的请求,则不会处理这些请求。客户端可以在不同的 HTTP 连接上安全地重试未处理的请求。当服务器关闭连接时,无法重试请求的客户端会丢失所有正在进行的请求。
来自服务器的对小于 GOAWAY 帧中流 ID 的流 ID 的请求可能已被处理;在收到响应、单独重置流、接收到另一个流 ID 低于相关请求的流 ID 的 GOAWAY 或连接终止之前,无法知道它们的状态。
如果未处理这些请求,服务器可能会拒绝低于指定 ID 的流上的单个请求。
- 如果服务器在承诺推送后收到 GOAWAY 帧,并且推送 ID 大于或等于 GOAWAY 帧中包含的标识符,则这些推送将不被接受。
服务器应该在提前知道连接关闭时发送 GOAWAY 帧,即使提前通知很小,以便远程对等方可以知道请求是否已部分处理。例如,如果 HTTP 客户端在服务器关闭 QUIC 连接的同时发送 POST,如果服务器没有发送 GOAWAY 帧来指示它可能会发送哪些流,则客户端无法知道服务器是否开始处理该 POST 请求已采取行动。
端点可以发送多个指示不同标识符的 GOAWAY 帧,但每个帧中的标识符不得大于任何先前帧中的标识符,因为客户端可能已经在另一个 HTTP 连接上重试了未处理的请求。接收到包含比先前接收到的更大标识符的 GOAWAY 必须被视为 H3_ID_ERROR 类型的连接错误;见第 8 节。
尝试正常关闭连接的端点可以发送一个 GOAWAY 帧,其值设置为最大可能值(服务器为2 62 -4,客户端为 2 62 -1)。这可确保对等方停止创建新请求或推送。在允许任何正在进行的请求或推送到达之后,端点可以发送另一个 GOAWAY 帧,指示在连接结束之前它可能接受哪些请求或推送。这确保了可以干净地关闭连接而不会丢失请求。
客户端在为它发送的 GOAWAY 中的 Push ID 选择的值方面具有更大的灵活性。值 2 62 -1 表示服务器可以继续完成已经承诺的推送。较小的值表示客户端将拒绝推送 ID 大于或等于该值的推送。与服务器一样,客户端可以发送后续的 GOAWAY 帧,只要指定的 Push ID 不大于任何先前发送的值。
即使当一个 GOAWAY 指示一个给定的请求或推送在接收时不会被处理或接受时,底层的传输资源仍然存在。发起这些请求的端点可以取消它们以清理传输状态。
一旦处理了所有接受的请求和推送,端点可以允许连接变为空闲,或者可以启动连接的立即关闭。完成正常关闭的端点在关闭连接时应该使用 H3_NO_ERROR 错误代码。
如果客户端已经通过请求消耗了所有可用的双向流 ID,则服务器不需要发送 GOAWAY 帧,因为客户端无法发出进一步的请求。
5.3. 立即关闭申请
HTTP/3 实现可以随时立即关闭 QUIC 连接。这导致向对等方发送 QUIC CONNECTION_CLOSE 帧,指示应用层已终止连接。此帧中的应用程序错误代码向对等方指示关闭连接的原因。有关在 HTTP/3 中关闭连接时可以使用的错误代码,请参阅第 8 节。
在关闭连接之前,可能会发送一个 GOAWAY 帧以允许客户端重试某些请求。在与 QUIC CONNECTION_CLOSE 帧相同的数据包中包含 GOAWAY 帧可以提高客户端接收帧的机会。
如果存在未显式关闭的打开流,则在关闭连接时将其隐式关闭;请参阅 [ QUIC-TRANSPORT ]的第 10.2 节。
6.流映射和使用
QUIC 流提供可靠的字节顺序传递,但不保证其他流上字节的传递顺序。在 QUIC 版本 1 中,包含 HTTP 帧的流数据由 QUIC STREAM 帧承载,但这种帧对 HTTP 帧层是不可见的。传输层对接收到的流数据进行缓冲和排序,向应用程序公开可靠的字节流。尽管 QUIC 允许在流中进行无序交付,但 HTTP/3 并未使用此功能。
QUIC 流可以是单向的,仅将数据从发起方传送到接收方,也可以是双向的。流可以由客户端或服务器发起。有关 QUIC 流的更多详细信息,请参阅 [ QUIC-TRANSPORT ]的第 2 节。
当通过 QUIC 发送 HTTP 字段和数据时,QUIC 层处理大部分流管理。使用 QUIC 时,HTTP 不需要进行任何单独的多路复用——通过 QUIC 流发送的数据总是映射到特定的 HTTP 事务或整个 HTTP/3 连接上下文。
6.1。双向流
所有客户端发起的双向流都用于 HTTP 请求和响应。双向流确保响应可以很容易地与请求相关联。这些流称为请求流。
这意味着客户端的第一个请求发生在 QUIC 流 0 上,随后的请求发生在流 4、8 上,依此类推。为了允许这些流打开,HTTP/3 服务器应该为允许的流数量和初始流流控制窗口配置非零最小值。为了避免不必要地限制并行性,一次至少应该允许 100 个请求流。
HTTP/3 不使用服务器启动的双向流,尽管扩展可以定义这些流的用途。客户端必须将接收到服务器发起的双向流视为 H3_STREAM_CREATION_ERROR 类型的连接错误(第 8 节),除非已经协商了这样的扩展。
6.2. 单向流
在任一方向上的单向流用于多种目的。目的由流类型指示,它在流的开头作为可变长度整数发送。此整数之后的数据格式和结构由流类型决定。
本文档中定义了两种流类型:控制流(第 6.2.1 节)和推送流(第 6.2.2 节)。[ QPACK ]定义了两种额外的流类型。其他流类型可以通过对 HTTP/3 的扩展来定义;有关详细信息,请参阅第 9 节。某些流类型是保留的(第 6.2.3 节)。
HTTP/3 连接在其生命周期的早期阶段的性能对单向流上数据的创建和交换很敏感。过度限制流数量或这些流的流控制窗口的端点将增加远程对等点提前达到限制并被阻塞的机会。特别是,实现应该考虑远程对等点可能希望行使保留的流行为(第 6.2.3 节) 与他们被允许使用的一些单向流。为了避免阻塞,客户端和服务器发送的传输参数必须允许对端为 HTTP 控制流创建至少一个单向流加上强制扩展所需的单向流的数量(三个是基本 HTTP 所需的最小数量/3 协议和 QPACK),并且应该为每个流提供至少 1,024 字节的流量控制信用。
请注意,如果端点在创建关键单向流之前消耗了所有初始信用,则不需要授予额外信用来创建更多单向流。端点应该首先创建 HTTP 控制流以及强制扩展所需的单向流(例如 QPACK 编码器和解码器流),然后在其对等方允许的情况下创建其他流。
如果流标头指示接收方不支持的流类型,则无法使用流的其余部分,因为语义未知。未知流类型的接收者可以使用 H3_STREAM_CREATION_ERROR 错误代码或保留错误代码(第 8.1 节)中止读取流,但不得将此类流视为任何类型的连接错误。
实现可以在知道对等方是否支持它们之前发送流类型。但是,可以修改现有协议组件(包括 QPACK 或其他扩展)的状态或语义的流类型,在已知对等方支持它们之前不得发送。
除非另有说明,否则发送者可以关闭或重置单向流。接收者必须容忍单向流在接收到单向流标头之前被关闭或重置。
6.2.1. 控制流
控制流由流类型 0x00 指示。此流上的数据由第 7.2 节中定义的 HTTP/3 帧组成。
每一方必须在连接开始时启动单个控制流,并将其 SETTINGS 帧作为该流上的第一帧发送。如果控制流的第一帧是任何其他帧类型,则必须将其视为 H3_MISSING_SETTINGS 类型的连接错误。每个对等点只允许一个控制流;接收到声称是控制流的第二个流必须被视为 H3_STREAM_CREATION_ERROR 类型的连接错误。发送方不得关闭控制流,接收方不得要求发送方关闭控制流。如果任一控制流在任何时候关闭,则必须将其视为 H3_CLOSED_CRITICAL_STREAM 类型的连接错误。连接错误在 第 8 节中描述。
因为控制流的内容用于管理其他流的行为,端点应该提供足够的流控制信用来防止对等点的控制流被阻塞。
使用一对单向流而不是单个双向流。这允许任一对等方尽快发送数据。根据 QUIC 连接上 0-RTT 是否可用,客户端或服务器可能能够首先发送流数据。
6.2.2. 推流
服务器推送是 HTTP/2 中引入的一个可选功能,它允许服务器在发出请求之前发起响应。有关详细信息,请参阅第 4.4 节。
推流由流类型 0x01 指示,后跟它所履行的承诺的推 ID,编码为可变长度整数。此流上的剩余数据由第 7.2 节中定义的 HTTP/3 帧组成 ,并通过零个或多个临时 HTTP 响应以及随后的单个最终 HTTP 响应来满足承诺的服务器推送,如 第 4.1 节中定义。服务器推送和推送 ID 在 第 4.4 节中描述。
只有服务器可以推送;如果服务器接收到客户端发起的推送流,则必须将其视为 H3_STREAM_CREATION_ERROR 类型的连接错误;见 第 8 节。
每个推送 ID 只能在推送流标头中使用一次。如果一个推流标头包含在另一个推流标头中使用的推 ID,客户端必须将此视为 H3_ID_ERROR 类型的连接错误;见 第 8 节。
7. HTTP 成帧层
HTTP 帧在 QUIC 流上承载,如第 6 节所述。HTTP/3 定义了三种流类型:控制流、请求流和推送流。本节介绍 HTTP/3 帧格式及其允许的流类型;概览见表1。附录 A.2中提供了 HTTP/2 和 HTTP/3 帧之间的比较。
框架 | 控制流 | 请求流 | 推流 | 部分 |
---|---|---|---|---|
数据 | 不 | 是的 | 是的 | 第 7.2.1 节 |
标题 | 不 | 是的 | 是的 | 第 7.2.2 节 |
CANCEL_PUSH | 是的 | 不 | 不 | 第 7.2.3 节 |
设置 | 是 (1) | 不 | 不 | 第 7.2.4 节 |
PUSH_PROMISE | 不 | 是的 | 不 | 第 7.2.5 节 |
离开 | 是的 | 不 | 不 | 第 7.2.6 节 |
MAX_PUSH_ID | 是的 | 不 | 不 | 第 7.2.7 节 |
预订的 | 是的 | 是的 | 是的 | 第 7.2.8 节 |
SETTINGS 帧只能作为控制流的第一帧出现;这在表 1中用 (1) 表示。具体指导见相关章节。
请注意,与 QUIC 帧不同,HTTP/3 帧可以跨越多个数据包。
7.1。框架布局
所有帧都具有以下格式:
HTTP/3 帧格式 { 类型 (i), 长度 (i), 帧有效载荷 (..), }
一个框架包括以下字段:
- 类型:
-
标识帧类型的可变长度整数。
- 长度:
-
一个可变长度整数,用于描述帧有效负载的长度(以字节为单位)。
- 帧载荷:
-
有效负载,其语义由 Type 字段确定。
每个帧的有效负载必须准确包含在其描述中标识的字段。在已识别字段之后包含附加字节的帧有效载荷或在已识别字段结束之前终止的帧有效载荷必须被视为 H3_FRAME_ERROR 类型的连接错误;见第 8 节。特别是,冗余长度编码必须经过验证是自洽的;见第 10.8 节。
当流完全终止时,如果流上的最后一帧被截断,则必须将其视为 H3_FRAME_ERROR 类型的连接错误;见 第 8 节。突然终止的流可以在帧中的任何点重置。
7.2. 框架定义
7.2.1. 数据
DATA 帧 (type=0x0) 传送与 HTTP 请求或响应内容相关的任意可变长度字节序列。
DATA 帧必须与 HTTP 请求或响应相关联。如果在控制流上接收到 DATA 帧,接收者必须以 H3_FRAME_UNEXPECTED 类型的连接错误进行响应;见第 8 节。
7.2.2. 标题
HEADERS 帧 (type=0x1) 用于携带 HTTP 字段部分,使用 QPACK 编码。有关详细信息,请参阅[ QPACK ] 。
HEADERS 帧只能根据请求或推送流发送。如果在控制流上接收到 HEADERS 帧,接收者必须以 H3_FRAME_UNEXPECTED 类型的连接错误(第 8 节)进行响应。
7.2.3. CANCEL_PUSH
CANCEL_PUSH 帧(类型=0x3)用于在接收到推送流之前请求取消服务器推送。CANCEL_PUSH 帧通过 Push ID 标识服务器推送(参见第 4.4 节),编码为可变长度整数。
当客户端发送 CANCEL_PUSH 时,表明它不希望收到承诺的资源。服务器应该中止发送资源,但这样做的机制取决于相应推送流的状态。如果服务器尚未创建推送流,则不会创建推送流。如果推送流是打开的,服务器应该突然终止该流。如果推送流已经结束,服务器可能仍然突然终止流或可能不采取任何行动。
服务器发送 CANCEL_PUSH 表示它不会履行先前发送的承诺。客户端不能期望相应的承诺被履行,除非它已经收到并处理了承诺的响应。无论是否打开了推送流,当服务器确定承诺不会被履行时,它应该发送一个 CANCEL_PUSH 帧。如果流已经打开,服务器可以中止在流上发送,错误代码为 H3_REQUEST_CANCELLED。
发送 CANCEL_PUSH 帧对现有推送流的状态没有直接影响。当客户端已经接收到相应的推送流时,它不应该发送 CANCEL_PUSH 帧。在客户端发送 CANCEL_PUSH 帧后,推送流可能会到达,因为服务器可能尚未处理 CANCEL_PUSH。客户端应该中止读取流,错误代码为 H3_REQUEST_CANCELLED。
在控制流上发送 CANCEL_PUSH 帧。在控制流以外的流上接收到 CANCEL_PUSH 帧必须被视为 H3_FRAME_UNEXPECTED 类型的连接错误。
CANCEL_PUSH 帧 { 类型 (i) = 0x3, 长度 (i), 推送 ID (i), }
CANCEL_PUSH 帧携带一个被编码为可变长度整数的 Push ID。Push ID 标识正在取消的服务器推送;见 第 4.4 节。如果收到一个 CANCEL_PUSH 帧,它引用的 Push ID 大于连接上当前允许的,则必须将其视为 H3_ID_ERROR 类型的连接错误。
如果客户端收到 CANCEL_PUSH 帧,则该帧可能会标识由于重新排序而尚未被 PUSH_PROMISE 帧提及的 Push ID。如果服务器接收到一个尚未被 PUSH_PROMISE 帧提及的 Push ID 的 CANCEL_PUSH 帧,则必须将其视为 H3_ID_ERROR 类型的连接错误。
7.2.4. 设置
SETTINGS 帧(类型=0x4)传达影响端点通信方式的配置参数,例如对对等行为的偏好和约束。单独地,一个 SETTINGS 参数也可以称为“设置”;每个设置参数的标识和值可以称为“设置标识”和“设置值”。
SETTINGS 帧始终适用于整个 HTTP/3 连接,而不是单个流。SETTINGS 帧必须作为每个控制流的第一帧(参见第 6.2.1 节)由每个对等方发送,并且不得随后发送。如果端点在控制流上接收到第二个 SETTINGS 帧,端点必须以 H3_FRAME_UNEXPECTED 类型的连接错误响应。
SETTINGS 帧不得在控制流以外的任何流上发送。如果端点在不同的流上接收到 SETTINGS 帧,端点必须以 H3_FRAME_UNEXPECTED 类型的连接错误响应。
SETTINGS 参数未协商;它们描述了接收对等方可以使用的发送对等方的特征。但是,可以通过使用 SETTINGS 来暗示协商 - 每个对等方都使用 SETTINGS 来通告一组支持的值。设置的定义将描述每个对等方如何组合这两个集合以得出将使用哪个选项的结论。SETTINGS 不提供识别选择何时生效的机制。
每个对等点可以通告相同参数的不同值。例如,客户端可能愿意使用非常大的响应字段部分,而服务器对请求大小更加谨慎。
相同的设置标识符不能在 SETTINGS 帧中出现多次。接收器可以将重复设置标识符的存在视为 H3_SETTINGS_ERROR 类型的连接错误。
SETTINGS 帧的有效载荷由零个或多个参数组成。每个参数由一个设置标识符和一个值组成,两者都编码为 QUIC 可变长度整数。
一个实现必须忽略任何带有它不理解的标识符的参数。
7.2.4.1。定义的 SETTINGS 参数
HTTP/3 中定义了以下设置:
- SETTINGS_MAX_FIELD_SECTION_SIZE (0x6):
-
默认值为无限制。用法见第 4.1.1.3 节。
0x1f * N + 0x21
为 N 的非负整数值设置格式的标识符是为了满足忽略未知标识符的要求而保留的。此类设置没有明确的含义。端点应该在它们的 SETTINGS 框架中至少包含一个这样的设置。端点在收到时不得认为此类设置具有任何意义。
因为设置没有定义的含义,所以设置的值可以是实现选择的任何值。
在[ HTTP2 ]中定义的没有相应 HTTP/3 设置的设置标识符也被保留(第 11.2.2 节)。不得发送这些保留的设置,并且必须将它们的接收视为 H3_SETTINGS_ERROR 类型的连接错误。
其他设置可以通过 HTTP/3 的扩展来定义; 有关详细信息,请参阅第 9 节。
7.2.4.2。初始化
HTTP 实现不得发送基于其当前对对等设置的理解而无效的帧或请求。
所有设置都从初始值开始。每个端点应该使用这些初始值在对等方的 SETTINGS 帧到达之前发送消息,因为携带设置的数据包可能会丢失或延迟。当 SETTINGS 帧到达时,所有设置都会更改为新值。
这消除了在发送消息之前等待 SETTINGS 帧的需要。端点在发送 SETTINGS 帧之前不得要求从对等方接收任何数据;必须在传输准备好发送数据后立即发送设置。
对于服务器,每个客户端设置的初始值都是默认值。
对于使用 1-RTT QUIC 连接的客户端,每个服务器设置的初始值都是默认值。1-RTT 密钥总是在 QUIC 处理包含 SETTINGS 的数据包之前变得可用,即使服务器立即发送 SETTINGS 也是如此。客户端不应该在发送请求之前无限期地等待 SETTINGS 到达,而是应该处理接收到的数据报以增加在发送第一个请求之前处理 SETTINGS 的可能性。
当使用 0-RTT QUIC 连接时,每个服务器设置的初始值是前一个会话中使用的值。客户端应该存储服务器在提供恢复信息的 HTTP/3 连接中提供的设置,但可以选择在某些情况下不存储设置(例如,如果在 SETTINGS 帧之前收到会话票证)。客户端在尝试 0-RTT 时必须遵守存储的设置——或默认值,如果没有存储值。一旦服务器提供了新设置,客户端必须遵守这些值。
服务器可以记住它公布的设置,或在票证中存储受完整性保护的值副本,并在接受 0-RTT 数据时恢复信息。服务器使用 HTTP/3 设置值来确定是否接受 0-RTT 数据。如果服务器无法确定客户端记住的设置与其当前设置兼容,则它不得接受 0-RTT 数据。如果符合这些设置的客户端不会违反服务器的当前设置,则记住的设置是兼容的。
服务器可以接受 0-RTT 并随后在其 SETTINGS 帧中提供不同的设置。如果服务器接受 0-RTT 数据,则其 SETTINGS 帧不得减少任何限制或更改客户端使用其 0-RTT 数据可能违反的任何值。服务器必须包括与其默认值不同的所有设置。如果服务器接受 0-RTT 但随后发送的设置与先前指定的设置不兼容,则必须将其视为 H3_SETTINGS_ERROR 类型的连接错误。如果服务器接受 0-RTT 但随后发送的 SETTINGS 帧忽略了客户端理解的设置值(除了保留的设置标识符),该设置值之前指定为具有非默认值,则必须将其视为连接错误输入 H3_SETTINGS_ERROR。
7.2.5。PUSH_PROMISE
PUSH_PROMISE 帧(类型=0x5)用于在请求流上从服务器到客户端携带承诺的请求头部分,如 HTTP/2 中。
PUSH_PROMISE 帧 { 类型 (i) = 0x5, 长度 (i), 推送 ID (i), 编码字段部分(..), }
有效载荷包括:
- 推送 ID:
-
标识服务器推送操作的可变长度整数。Push ID 用于推送流标头(第 4.4 节)和 CANCEL_PUSH 帧(第 7.2.3 节)。
- 编码字段部分:
-
承诺响应的 QPACK 编码请求头字段。 有关详细信息,请参阅[ QPACK ] 。
服务器不得使用大于客户端在 MAX_PUSH_ID 帧中提供的推送 ID(第 7.2.7 节)。客户端必须将收到的 PUSH_PROMISE 帧包含比客户端通告的更大的 Push ID 视为 H3_ID_ERROR 的连接错误。
服务器可以在多个 PUSH_PROMISE 帧中使用相同的 Push ID。如果是这样,解压缩的请求头集必须包含以相同顺序的相同字段,并且每个字段中的名称和值都必须完全匹配。客户端应该比较多次承诺资源的请求头部分。如果客户端收到已经承诺的 Push ID 并检测到不匹配,它必须以 H3_GENERAL_PROTOCOL_ERROR 类型的连接错误进行响应。如果解压缩的字段部分完全匹配,客户端应该将推送的内容与接收到 PUSH_PROMISE 帧的每个流相关联。
允许对同一个 Push ID 的重复引用主要是为了减少并发请求造成的重复。服务器应该避免长时间重复使用 Push ID。客户端可能会使用服务器推送响应,并且不会保留它们以供随着时间的推移重用。看到 PUSH_PROMISE 帧的客户端使用了他们已经消费和丢弃的 Push ID,他们将被迫忽略该承诺。
如果在控制流上接收到 PUSH_PROMISE 帧,客户端必须以 H3_FRAME_UNEXPECTED 类型的连接错误进行响应;见第 8 节。
客户端不得发送 PUSH_PROMISE 帧。服务器必须将收到 PUSH_PROMISE 帧视为 H3_FRAME_UNEXPECTED 类型的连接错误;见 第 8 节。
有关整体服务器推送机制的描述,请参见第 4.4 节。
7.2.6。离开
GOAWAY 帧 (type=0x7) 用于启动任一端点的 HTTP/3 连接的正常关闭。GOAWAY 允许端点停止接受新请求或推送,同时仍完成对先前接收到的请求和推送的处理。这将启用管理操作,例如服务器维护。GOAWAY 本身不会关闭连接。
GOAWAY 帧总是在控制流上发送。在服务器到客户端的方向上,它携带一个 QUIC 流 ID,用于客户端发起的双向流,编码为可变长度整数。客户端必须将接收到包含任何其他类型的流 ID 的 GOAWAY 帧视为 H3_ID_ERROR 类型的连接错误。
在客户端到服务器的方向上,GOAWAY 帧携带一个被编码为可变长度整数的 Push ID。
GOAWAY 帧适用于整个连接,而不是特定的流。客户端必须将控制流以外的流上的 GOAWAY 帧视为 H3_FRAME_UNEXPECTED 类型的连接错误;见第 8 节。
有关使用 GOAWAY 框架的更多信息,请参见第 5.2 节。
7.2.7. MAX_PUSH_ID
客户端使用 MAX_PUSH_ID 帧 (type=0xd) 来控制服务器可以发起的服务器推送次数。这设置了服务器可以在 PUSH_PROMISE 和 CANCEL_PUSH 帧中使用的推送 ID 的最大值。因此,除了 QUIC 传输维护的限制之外,这也限制了服务器可以启动的推送流的数量。
MAX_PUSH_ID 帧总是在控制流上发送。在任何其他流上接收到 MAX_PUSH_ID 帧必须被视为 H3_FRAME_UNEXPECTED 类型的连接错误。
服务器不得发送 MAX_PUSH_ID 帧。客户端必须将收到 MAX_PUSH_ID 帧视为 H3_FRAME_UNEXPECTED 类型的连接错误。
创建 HTTP/3 连接时未设置最大推送 ID,这意味着服务器在收到 MAX_PUSH_ID 帧之前无法推送。希望管理承诺的服务器推送次数的客户端可以通过在服务器完成或取消服务器推送时发送 MAX_PUSH_ID 帧来增加最大推送 ID。
MAX_PUSH_ID 帧 { 类型 (i) = 0xd, 长度 (i), 推送 ID (i), }
MAX_PUSH_ID 帧携带一个可变长度整数,用于标识服务器可以使用的 Push ID 的最大值;见第 4.4 节。一个 MAX_PUSH_ID 帧不能减少最大 Push ID;接收到的 MAX_PUSH_ID 帧包含的值小于先前接收到的值,必须将其视为 H3_ID_ERROR 类型的连接错误。
7.2.8. 保留帧类型
0x1f * N + 0x21
N 的非负整数值格式的帧类型被保留以执行忽略未知类型的要求(第 9 节)。这些帧没有语义,可以在允许发送帧的任何流上发送。这使得它们能够用于应用层填充。端点在收到这些帧时不得认为这些帧具有任何意义。
帧的有效负载和长度以实现选择的任何方式选择。
在没有相应 HTTP/3 帧的 HTTP/2 中使用的帧类型也被保留(第 11.2.1 节)。不得发送这些帧类型,并且必须将它们的接收视为 H3_FRAME_UNEXPECTED 类型的连接错误。
8.错误处理
当流无法成功完成时,QUIC 允许应用程序突然终止(重置)该流并传达原因;请参阅[ QUIC-TRANSPORT ]的第 2.4 节。这称为“流错误”。HTTP/3 实现可以决定关闭 QUIC 流并传达错误类型。错误代码的有线编码在第 8.1 节中定义。流错误不同于指示错误条件的 HTTP 状态代码。流错误表明发送方没有传输或消费完整的请求或响应,而 HTTP 状态码表明成功接收到的请求的结果。
如果需要终止整个连接,QUIC 类似地提供了传达原因的机制;请参阅[ QUIC-TRANSPORT ]的第 5.3 节。这称为“连接错误”。与流错误类似,HTTP/3 实现可以终止 QUIC 连接并使用第 8.1 节中的错误代码传达原因。
尽管关闭流和连接的原因称为“错误”,但这些操作并不一定表明连接或任一实现存在问题。例如,如果不再需要请求的资源,则可以重置流。
在某些情况下,端点可以选择将流错误视为连接错误,关闭整个连接以响应单个流上的条件。在做出此选择之前,实现需要考虑对未完成请求的影响。
因为可以在没有协商的情况下定义新的错误代码(参见第 9 节),所以在意外上下文中使用错误代码或收到未知错误代码必须被视为等同于 H3_NO_ERROR。但是,无论错误代码如何,关闭流都会产生其他影响;例如,参见 第 4.1 节。
8.1。HTTP/3 错误代码
以下错误代码定义为在突然终止流、中止读取流或立即关闭 HTTP/3 连接时使用。
- H3_NO_ERROR (0x100):
-
没有错误。当连接或流需要关闭但没有错误信号时使用。
- H3_GENERAL_PROTOCOL_ERROR (0x101):
-
对等方违反协议要求的方式与更具体的错误代码不匹配,或者端点拒绝使用更具体的错误代码。
- H3_INTERNAL_ERROR (0x102):
-
HTTP 堆栈中发生内部错误。
- H3_STREAM_CREATION_ERROR (0x103):
-
端点检测到其对等方创建了一个它不会接受的流。
- H3_CLOSED_CRITICAL_STREAM (0x104):
-
HTTP/3 连接所需的流已关闭或重置。
- H3_FRAME_UNEXPECTED (0x105):
-
接收到的帧在当前状态或当前流中是不允许的。
- H3_FRAME_ERROR (0x106):
-
接收到不满足布局要求或大小无效的框架。
- H3_EXCESSIVE_LOAD (0x107):
-
端点检测到其对等方正在表现出可能会产生过多负载的行为。
- H3_ID_ERROR (0x108):
-
Stream ID 或 Push ID 使用不正确,例如超出限制、降低限制或被重用。
- H3_SETTINGS_ERROR (0x109):
-
端点在 SETTINGS 帧的有效负载中检测到错误。
- H3_MISSING_SETTINGS (0x10a):
-
在控制流的开头没有收到 SETTINGS 帧。
- H3_REQUEST_REJECTED (0x10b):
-
服务器拒绝了请求,但未执行任何应用程序处理。
- H3_REQUEST_CANCELLED (0x10c):
-
请求或其响应(包括推送响应)被取消。
- H3_REQUEST_INCOMPLETE (0x10d):
-
客户端的流在不包含完整请求的情况下终止。
- H3_MESSAGE_ERROR (0x10e):
-
HTTP 消息格式不正确,无法处理。
- H3_CONNECT_ERROR (0x10f):
-
为响应 CONNECT 请求而建立的 TCP 连接被重置或异常关闭。
- H3_VERSION_FALLBACK (0x110):
-
请求的操作无法通过 HTTP/3 提供。对等方应通过 HTTP/1.1 重试。
保留 N 的非负整数值格式的错误代码0x1f * N + 0x21
以执行将未知错误代码视为等效于 H3_NO_ERROR 的要求(第 9 节)。实现应该从这个空间中选择一个错误代码,当他们发送 H3_NO_ERROR 时有一定的概率。
9. HTTP/3 的扩展
HTTP/3 允许扩展协议。在本节描述的限制范围内,协议扩展可用于提供附加服务或更改协议的任何方面。扩展仅在单个 HTTP/3 连接范围内有效。
这适用于本文档中定义的协议元素。这不会影响扩展 HTTP 的现有选项,例如定义新方法、状态代码或字段。
允许扩展使用新的帧类型(第 7.2 节)、新的设置(第 7.2.4.1 节)、新的错误代码(第 8 节)或新的单向流类型(第 6.2 节)。为管理这些扩展点建立了注册表:帧类型(第 11.2.1 节)、设置(第 11.2.2 节)、错误代码(第 11.2.3 节)和流类型(第 11.2.4 节)。
实现必须忽略所有可扩展协议元素中的未知或不受支持的值。实现必须丢弃帧并中止对具有未知或不支持类型的单向流的读取。这意味着这些扩展点中的任何一个都可以被扩展安全地使用,而无需事先安排或协商。然而,如果已知帧类型需要位于特定位置,例如作为控制流的第一帧的 SETTINGS 帧(参见第 6.2.1 节),未知帧类型不满足该要求,应予以处理作为一个错误。
可能改变现有协议组件语义的扩展必须在使用之前进行协商。例如,更改 HEADERS 帧布局的扩展不能使用,直到对等方给出可以接受的肯定信号。在这种修改后的布局生效时进行协调可能会很复杂。因此,为现有协议元素的新定义分配新标识符可能更有效。
本文档没有规定协商使用扩展的特定方法,但指出可以为此目的使用设置(第 7.2.4.1 节)。如果两个对等点都设置了表示愿意使用扩展的值,则可以使用扩展。如果设置用于扩展协商,则必须以这样一种方式定义默认值,即如果省略该设置,则禁用扩展。
10.安全注意事项
HTTP/3 的安全考虑应该与带有 TLS 的 HTTP/2 相当。但是,[ HTTP2 ]第 10 节中的许多注意事项 适用于[ QUIC-TRANSPORT ],并在该文档中进行了讨论。
10.2. 跨协议攻击
在 TLS 和 QUIC 握手中使用 ALPN 在处理应用层字节之前建立目标应用协议。这确保了端点有强有力的保证,即对等点使用相同的协议。
这并不能保证免受所有跨协议攻击。[ QUIC-TRANSPORT ]的第 21.5 节描述了一些可以使用 QUIC 数据包的明文对不使用经过身份验证的传输的端点执行请求伪造的方法。
10.3. 中间封装攻击
HTTP/3 字段编码允许在 HTTP 使用的语法中表达不是有效字段名称的名称([语义]的第 5.1 节)。包含无效字段名称的请求或响应必须被视为格式错误(第 4.1.3 节)。因此,中介无法将包含无效字段名称的 HTTP/3 请求或响应转换为 HTTP/1.1 消息。
同样,HTTP/3 可以传输无效的字段值。虽然大多数可以编码的值不会改变字段解析,但回车(CR,ASCII 0xd),换行(LF,ASCII 0xa)和零字符(NUL,ASCII 0x0)可能会被攻击者利用,如果它们是逐字翻译。任何包含字段值中不允许的字符的请求或响应必须被视为格式错误(第 4.1.3 节)。有效字符由[语义]第 5.5 节中的“字段内容”ABNF 规则定义。
10.4. 推送响应的可缓存性
推送的响应没有来自客户端的明确请求;请求由服务器在 PUSH_PROMISE 帧中提供。
根据原始服务器在 Cache-Control 标头字段中提供的指导,可以缓存推送的响应。但是,如果一台服务器托管多个租户,这可能会导致问题。例如,服务器可能会为多个用户提供其 URI 空间的一小部分。
当多个租户在同一台服务器上共享空间时,该服务器必须确保租户无法推送他们无权访问的资源的表示。未能强制执行此操作将允许租户提供将在缓存之外提供的表示,从而覆盖权威租户提供的实际表示。
要求客户端拒绝原始服务器不具有权威性的推送响应;见第 4.4 节。
10.5。拒绝服务注意事项
与 HTTP/1.1 或 HTTP/2 连接相比,HTTP/3 连接可能需要更大的资源承诺才能运行。字段压缩和流量控制的使用取决于用于存储更多状态的资源的承诺。这些功能的设置可确保这些功能的内存承诺受到严格限制。
PUSH_PROMISE 帧的数量以类似的方式受到限制。接受服务器推送的客户端应该限制它一次发布的推送 ID 的数量。
处理能力不能像状态能力那样得到有效保护。
发送要求对等方忽略的未定义协议元素的能力可能会被滥用以导致对等方花费额外的处理时间。这可以通过设置多个未定义的 SETTINGS 参数、未知帧类型或未知流类型来完成。但是请注意,某些用途是完全合法的,例如可理解的扩展和填充以增加对流量分析的抵抗力。
压缩现场部分也提供了一些浪费加工资源的机会;有关潜在滥用的更多详细信息,请参阅[ QPACK ]的第 7 节。
所有这些特性——即服务器推送、未知协议元素、字段压缩——都有合法用途。这些功能只有在不必要或过度使用时才会成为负担。
不监视此类行为的端点会将自己暴露在拒绝服务攻击的风险中。实现应该跟踪这些特性的使用并设置它们的使用限制。端点可以将可疑活动视为 H3_EXCESSIVE_LOAD 类型的连接错误(第 8 节),但误报将导致中断有效连接和请求。
10.5.1。字段部分大小的限制
大字段部分(第 4.1 节)可能导致实现提交大量状态。对路由至关重要的标头字段可能出现在标头部分的末尾,这会阻止标头部分流式传输到其最终目的地。这种排序和其他原因(例如确保缓存正确性)意味着端点可能需要缓冲整个标头部分。由于字段部分的大小没有硬性限制,一些端点可能被迫为标题字段提交大量可用内存。
端点可以使用 SETTINGS_MAX_FIELD_SECTION_SIZE(第 4.1.1.3 节)设置来告知对等方可能适用于字段部分大小的限制。此设置只是建议性的,因此端点可以选择发送超出此限制的字段部分,并有可能将请求或响应视为格式错误。此设置特定于 HTTP/3 连接,因此任何请求或响应都可能遇到具有较低未知限制的跃点。中间人可以尝试通过传递不同对等方提供的值来避免这个问题,但他们没有义务这样做。
接收到比它愿意处理的更大的字段部分的服务器可以发送 HTTP 431(请求标头字段太大)状态代码([ RFC6585 ])。客户端可以丢弃它无法处理的响应。
10.6。使用压缩
当秘密数据在与攻击者控制的数据相同的上下文中被压缩时,压缩可以让攻击者恢复秘密数据。HTTP/3 启用字段压缩(第 4.1.1 节);以下问题也适用于 HTTP 压缩内容编码的使用;见[语义]第 8.4.1 节。
有一些可证明的利用网络特性的压缩攻击(例如,[ BREACH ])。攻击者引发多个包含不同明文的请求,观察每个请求中生成的密文的长度,当对秘密的猜测正确时,会显示较短的长度。
在安全通道上通信的实现不得压缩包含机密和攻击者控制的数据的内容,除非每个数据源使用单独的压缩上下文。如果不能可靠地确定数据源,则不得使用压缩。
[ QPACK ]中描述了有关字段部分压缩的进一步考虑。
10.7。填充和流量分析
填充可用于模糊帧内容的确切大小,并用于减轻 HTTP 中的特定攻击,例如,压缩内容包括攻击者控制的明文和秘密数据的攻击(例如, [ BREACH ])。
在 HTTP/2 使用 PADDING 帧和其他帧中的填充字段以使连接更能抵抗流量分析的情况下,HTTP/3 可以依赖传输层填充或使用第 7.2.8 节和第 7.2.8节中讨论的保留帧和流类型6.2.3 . 这些填充方法在填充的粒度、如何根据受保护的信息安排填充、是否在数据包丢失的情况下应用填充以及实现如何控制填充等方面产生不同的结果。
即使连接空闲,保留流类型也可用于呈现发送流量的外观。由于 HTTP 流量经常以突发的形式出现,因此可以使用明显的流量来掩盖这种突发的时间或持续时间,甚至看起来像是在发送恒定的数据流。但是,由于此类流量仍由接收方进行流量控制,因此未能及时排出此类流量并提供额外的流量控制信用可能会限制发送方发送真实流量的能力。
为了减轻依赖于压缩的攻击,禁用或限制压缩可能比填充作为对策更可取。
使用填充可能导致比看起来立即明显的保护更少。冗余填充甚至可能适得其反。充其量,填充只会使攻击者更难通过增加攻击者必须观察的帧数来推断长度信息。错误实现的填充方案很容易被击败。特别是,具有可预测分布的随机填充提供的保护非常少。同样,将有效载荷填充到固定大小会在有效载荷大小跨越固定大小边界时暴露信息,如果攻击者可以控制明文,这可能是可能的。
10.9。早期数据
将 0-RTT 与 HTTP/3 一起使用会导致重放攻击。当使用带有 0-RTT 的 HTTP/3 时,必须应用[ HTTP-REPLAY ]中的反重放缓解措施。在将[ HTTP-REPLAY ]应用于 HTTP/3 时,对 TLS 层的引用是指在 QUIC 中执行的握手,而对应用程序数据的所有引用都是指流的内容。
11. IANA 注意事项
本文档注册了一个新的 ALPN 协议 ID(第 11.1 节)并创建了管理 HTTP/3 中代码点分配的新注册表。
11.1。HTTP/3 标识字符串的注册
本文档为在[ RFC7301 ]中建立的“应用层协议协商 (ALPN) 协议 ID”注册表中的 HTTP/3 标识创建了一个新注册。
“h3”字符串标识 HTTP/3:
- 协议:
-
HTTP/3
- 识别顺序:
-
0x68 0x33 ("h3")
- 规格:
-
本文档
11.2. 新登记处
本文档中创建的新注册中心根据[ QUIC-TRANSPORT ]第 22.1 节中记录的 QUIC 注册政策运行。这些注册表都包括[ QUIC-TRANSPORT ]的第 22.1.1 节中列出的通用字段集。这些注册表[应/被]收集在“超文本传输协议版本 3 (HTTP/3) 参数”标题下。
在本文档中创建的这些注册中心的初始分配都被分配了永久状态,并列出了 IETF 的变更控制者和 HTTP 工作组的联系人 (ietf-http-wg@w3.org)。
11.2.1. 框架类型
本文档为 HTTP/3 帧类型代码建立了一个注册表。“HTTP/3 帧类型”注册表管理 62 位空间。该注册表遵循 QUIC 注册表政策;见第 11.2 节。此注册表中的永久注册是使用规范要求策略([ RFC8126 ])分配的,除了 0x00 和 0x3f(十六进制;包括)之间的值,这些值是使用标准操作或 IESG 批准分配的,如[ RFC8126 ]。
虽然此注册表与[ HTTP2 ]中定义的“HTTP/2 帧类型”注册表是分开的 ,但在代码空间重叠的情况下,分配最好彼此平行。如果一个条目仅存在于一个注册表中,则应尽一切努力避免将相应的值分配给不相关的操作。专家审阅者可以拒绝不相关的注册,这些注册会与相应注册表中的相同值发生冲突。
除了第 11.2 节中描述的通用字段外,此注册表中的永久注册必须包括以下字段:
- 框架类型:
-
框架类型的名称或标签。
框架类型的规范必须包括框架布局及其语义的描述,包括有条件存在的框架的任何部分。
表 2中的条目由本文档注册。
框架类型 | 价值 | 规格 |
---|---|---|
数据 | 0x0 | 第 7.2.1 节 |
标题 | 0x1 | 第 7.2.2 节 |
预订的 | 0x2 | 不适用 |
CANCEL_PUSH | 0x3 | 第 7.2.3 节 |
设置 | 0x4 | 第 7.2.4 节 |
PUSH_PROMISE | 0x5 | 第 7.2.5 节 |
预订的 | 0x6 | 不适用 |
离开 | 0x7 | 第 7.2.6 节 |
预订的 | 0x8 | 不适用 |
预订的 | 0x9 | 不适用 |
MAX_PUSH_ID | 0xd | 第 7.2.7 节 |
N 的非负整数值格式的每个代码0x1f * N + 0x21
(即 0x21、0x40、...、到 0x3ffffffffffffffe)不得由 IANA 分配,也不得出现在分配值列表中。
11.2.2. 设置参数
本文档为 HTTP/3 设置建立了注册表。“HTTP/3 设置”注册表管理 62 位空间。该注册表遵循 QUIC 注册表政策;见第 11.2 节。此注册表中的永久注册是使用规范要求策略([ RFC8126 ])分配的,除了 0x00 和 0x3f(十六进制;包括)之间的值,这些值是使用标准操作或 IESG 批准分配的,如[ RFC8126 ]。
虽然此注册表与[ HTTP2 ]中定义的“HTTP/2 设置”注册表是分开的 ,但最好是这些分配相互平行。如果一个条目仅存在于一个注册表中,则应尽一切努力避免将相应的值分配给不相关的操作。专家审阅者可以拒绝不相关的注册,这些注册会与相应注册表中的相同值发生冲突。
除了第 11.2 节中描述的通用字段外,此注册表中的永久注册必须包括以下字段:
- 设置名称:
-
设置的符号名称。指定设置名称是可选的。
- 默认:
-
除非另有说明,否则设置的值。默认值应该是最严格的可能值。
表 3中的条目由本文档注册。
设置名称 | 价值 | 规格 | 默认 |
---|---|---|---|
预订的 | 0x0 | 不适用 | 不适用 |
预订的 | 0x2 | 不适用 | 不适用 |
预订的 | 0x3 | 不适用 | 不适用 |
预订的 | 0x4 | 不适用 | 不适用 |
预订的 | 0x5 | 不适用 | 不适用 |
MAX_FIELD_SECTION_SIZE | 0x6 | 第 7.2.4.1 节 | 无限 |
N 的非负整数值格式的每个代码0x1f * N + 0x21
(即 0x21、0x40、...、到 0x3ffffffffffffffe)不得由 IANA 分配,也不得出现在分配值列表中。
11.2.3. 错误代码
本文档为 HTTP/3 错误代码建立了一个注册表。“HTTP/3 错误代码”注册表管理 62 位空间。该注册表遵循 QUIC 注册表政策;见第 11.2 节。此注册表中的永久注册是使用规范要求策略([ RFC8126 ])分配的,除了 0x00 和 0x3f(十六进制;包括)之间的值,这些值是使用标准操作或 IESG 批准分配的,如[ RFC8126 ]。
错误代码的注册需要包含错误代码的描述。建议专家审阅者检查新注册是否可能与现有错误代码重复。鼓励使用现有注册,但不是强制性的。不鼓励使用在“HTTP/2 错误代码”注册表中注册的值,专家审阅者可能会拒绝此类注册。
除了第 11.2 节中描述的通用字段外,此注册表还包括两个附加字段。此注册表中的永久注册必须包括以下字段:
- 名称:
-
错误代码的名称。
- 描述:
-
错误代码语义的简要描述。
表 4中的条目由本文档注册。这些错误代码是从对规范要求策略运行的范围中选择的,以避免与 HTTP/2 错误代码冲突。
名称 | 价值 | 描述 | 规格 |
---|---|---|---|
H3_NO_ERROR | 0x100 | 没有错误 | 第 8.1 节 |
H3_GENERAL_PROTOCOL_ERROR | 0x101 | 一般协议错误 | 第 8.1 节 |
H3_INTERNAL_ERROR | 0x102 | 内部错误 | 第 8.1 节 |
H3_STREAM_CREATION_ERROR | 0x103 | 流创建错误 | 第 8.1 节 |
H3_CLOSED_CRITICAL_STREAM | 0x104 | 关键流已关闭 | 第 8.1 节 |
H3_FRAME_UNEXPECTED | 0x105 | 当前状态下不允许帧 | 第 8.1 节 |
H3_FRAME_ERROR | 0x106 | 框架违反布局或尺寸规则 | 第 8.1 节 |
H3_EXCESSIVE_LOAD | 0x107 | 对等产生过大的负载 | 第 8.1 节 |
H3_ID_ERROR | 0x108 | 标识符使用不正确 | 第 8.1 节 |
H3_SETTINGS_ERROR | 0x109 | SETTINGS 框架包含无效值 | 第 8.1 节 |
H3_MISSING_SETTINGS | 0x10a | 未收到 SETTINGS 帧 | 第 8.1 节 |
H3_REQUEST_REJECTED | 0x10b | 请求未处理 | 第 8.1 节 |
H3_REQUEST_CANCELLED | 0x10c | 不再需要数据 | 第 8.1 节 |
H3_REQUEST_INCOMPLETE | 0x10d | 流提前终止 | 第 8.1 节 |
H3_MESSAGE_ERROR | 0x10e | 格式错误的消息 | 第 8.1 节 |
H3_CONNECT_ERROR | 0x10f | TCP 重置或 CONNECT 请求出错 | 第 8.1 节 |
H3_VERSION_FALLBACK | 0x110 | 通过 HTTP/1.1 重试 | 第 8.1 节 |
N 的非负整数值格式的每个代码0x1f * N + 0x21
(即 0x21、0x40、...、到 0x3ffffffffffffffe)不得由 IANA 分配,也不得出现在分配值列表中。
11.2.4. 流类型
本文档为 HTTP/3 单向流类型建立了注册表。“HTTP/3 流类型”注册表管理 62 位空间。该注册表遵循 QUIC 注册表政策;见第 11.2 节。此注册表中的永久注册是使用规范要求策略([ RFC8126 ])分配的,除了 0x00 和 0x3f(十六进制;包括)之间的值,这些值是使用标准操作或 IESG 批准分配的,如[ RFC8126 ]。
除了第 11.2 节中描述的通用字段外,此注册表中的永久注册必须包括以下字段:
- 流类型:
-
流类型的名称或标签。
- 发件人:
-
HTTP/3 连接上的哪个端点可以启动这种类型的流。值为“客户端”、“服务器”或“两者”。
永久注册的规范必须包括流类型的描述,包括流内容的布局和语义。
下表中的条目由本文档注册。
流类型 | 价值 | 规格 | 发件人 |
---|---|---|---|
控制流 | 0x00 | 第 6.2.1 节 | 两个都 |
推流 | 0x01 | 第 4.4 节 | 服务器 |
N 的非负整数值格式的每个代码0x1f * N + 0x21
(即 0x21、0x40、...、到 0x3ffffffffffffffe)不得由 IANA 分配,也不得出现在分配值列表中。
12.参考文献
12.1. 规范性参考
- [ALTSVC]
- Nottingham, M. 、McManus, P.和 J. Reschke,“HTTP 替代服务”,RFC 7838,DOI 10.17487/RFC7838,, < https://www.rfc-editor.org/info/rfc7838 > .
- [缓存]
- Fielding, R. 、Nottingham, M.和 J. Reschke,“HTTP 缓存”,正在进行的工作,Internet-Draft,draft-ietf-httpbis-cache-14,, < http://www.ietf.org/internet-drafts/draft-ietf-httpbis-cache-14.txt > .
- [HTTP-重播]
- Thomson, M. 、Nottingham, M.和 W. Tarreau,“在 HTTP 中使用早期数据”,RFC 8470,DOI 10.17487/RFC8470,, < https://www.rfc-editor.org/info/rfc8470 > .
- [QPACK]
- Krasic, C. , Bishop, M.和 A. Frindell, Ed。, "QPACK: HTTP over QUIC 的标头压缩" ,工作进行中, Internet-Draft, draft-ietf-quic-qpack-21 ,, < https://tools.ietf.org/html/draft-ietf-quic-qpack-21 > .
- [快速运输]
- 艾扬格,J.,Ed。和 M.汤姆森,埃德。,“QUIC:基于 UDP 的多路复用和安全传输”,正在进行的工作,Internet-Draft,draft-ietf-quic-transport-34,, < https://tools.ietf.org/html/draft-ietf-quic-transport-34 >。
- [RFC0793]
- Postel, J.,“传输控制协议”,STD 7,RFC 793,DOI 10.17487/RFC0793,, < https://www.rfc-editor.org/info/rfc793 > .
- [RFC2119]
- Bradner, S.,“在 RFC 中使用以指示需求级别的关键词”,BCP 14,RFC 2119,DOI 10.17487/RFC2119,, < https://www.rfc-editor.org/info/rfc2119 > .
- [RFC6066]
- Eastlake 3rd, D.,“传输层安全 (TLS) 扩展:扩展定义”,RFC 6066,DOI 10.17487/RFC6066,, < https://www.rfc-editor.org/info/rfc6066 > .
- [RFC6265]
- Barth, A.,“HTTP 状态管理机制”,RFC 6265,DOI 10.17487/RFC6265,, < https://www.rfc-editor.org/info/rfc6265 > .
- [RFC7301]
- Friedl, S. 、Popov, A. 、Langley, A.和 E. Stephan,“传输层安全 (TLS) 应用层协议协商扩展”,RFC 7301,DOI 10.17487/RFC7301,, < https://www.rfc-editor.org/info/rfc7301 > .
- [RFC8126]
- Cotton, M. 、Leiba, B.和 T. Narten,“在 RFC 中编写 IANA 注意事项部分的指南”,BCP 26,RFC 8126,DOI 10.17487/RFC8126,, < https://www.rfc-editor.org/info/rfc8126 > .
- [RFC8174]
- Leiba, B.,“RFC 2119 关键字中大写与小写的歧义”,BCP 14,RFC 8174,DOI 10.17487/RFC8174,, < https://www.rfc-editor.org/info/rfc8174 > .
- [语义]
- Fielding, R. 、Nottingham, M.和 J. Reschke,“HTTP 语义”,正在进行的工作,Internet-Draft,draft-ietf-httpbis-semantics-14,, < http://www.ietf.org/internet-drafts/draft-ietf-httpbis-semantics-14.txt > .
- [URI]
- Berners-Lee, T. 、Fielding, R.和 L. Masinter,“统一资源标识符 (URI):通用语法”,STD 66,RFC 3986,DOI 10.17487/RFC3986,, < https://www.rfc-editor.org/info/rfc3986 > .
12.2. 参考资料
- [违反]
- Gluck, Y. , Harris, N.和 A. Prado,“BREACH: Reviving the CRIME Attack”,, < http://breachattack.com/resources/BREACH%20-%20SSL,%20gone%20in%2030%20seconds.pdf > .
- [DNS-条款]
- Hoffman, P. 、Sullivan, A.和 K. Fujiwara,“DNS 术语”,BCP 219,RFC 8499,DOI 10.17487/RFC8499,, < https://www.rfc-editor.org/info/rfc8499 > .
- [HPACK]
- Peon, R.和 H. Ruellan,“HPACK:HTTP/2 的标头压缩”,RFC 7541,DOI 10.17487/RFC7541,, < https://www.rfc-editor.org/info/rfc7541 > .
- [HTTP11]
- Fielding, R. 、Nottingham, M.和 J. Reschke,“HTTP/1.1”,正在进行的工作,Internet-Draft,draft-ietf-httpbis-messaging-14,, < http://www.ietf.org/internet-drafts/draft-ietf-httpbis-messaging-14.txt > .
- [HTTP2]
- Belshe, M. , Peon, R.和 M. Thomson, Ed。, "超文本传输协议第 2 版 (HTTP/2)" , RFC 7540 , DOI 10.17487/RFC7540 ,, < https://www.rfc-editor.org/info/rfc7540 > .
- [RFC6585]
- Nottingham, M.和 R. Fielding,“附加 HTTP 状态代码”,RFC 6585,DOI 10.17487/RFC6585,, < https://www.rfc-editor.org/info/rfc6585 > .
- [RFC8164]
- Nottingham, M.和 M. Thomson,“HTTP/2 的机会安全”,RFC 8164,DOI 10.17487/RFC8164,, < https://www.rfc-editor.org/info/rfc8164 > .
- [TFO]
- Cheng, Y. 、Chu, J. 、Radhakrishnan, S.和 A. Jain,“TCP 快速打开”,RFC 7413,DOI 10.17487/RFC7413,, < https://www.rfc-editor.org/info/rfc7413 > .
- [TLS13]
- Rescorla, E.,“传输层安全 (TLS) 协议版本 1.3”,RFC 8446,DOI 10.17487/RFC8446,, < https://www.rfc-editor.org/info/rfc8446 > .
附录 A.从 HTTP/2 转换的注意事项
HTTP/3 受到 HTTP/2 的强烈影响,并且有许多相似之处。本节描述了设计 HTTP/3 所采用的方法,指出了与 HTTP/2 的重要区别,并描述了如何将 HTTP/2 扩展映射到 HTTP/3。
HTTP/3 的前提是与 HTTP/2 的相似性是可取的,但不是硬性要求。HTTP/3 与 HTTP/2 不同,其中 QUIC 与 TCP 不同,要么利用 QUIC 特性(如流),要么适应重要的缺点(如缺乏总排序)。这些差异使得 HTTP/3 在关键方面类似于 HTTP/2,例如请求和响应与流的关系。但是,HTTP/3 设计的细节与 HTTP/2 有很大不同。
本节指出了一些重要的偏离。
A.1。流
HTTP/3 允许使用比 HTTP/2 更多的流 (2 62 -1)。关于流标识符空间耗尽的相同考虑也适用,尽管空间要大得多,因此很可能首先达到 QUIC 中的其他限制,例如连接流控制窗口的限制。
与 HTTP/2 相比,HTTP/3 中的流并发由 QUIC 管理。当所有数据都已接收并且发送的数据已被对等方确认时,QUIC 认为流已关闭。当包含 END_STREAM 位的帧已提交到传输时,HTTP/2 认为流已关闭。结果,等价交换的流可以在更长的时间段内保持“活跃”。HTTP/3 服务器可能会选择允许更大数量的并发客户端发起的双向流来实现与 HTTP/2 等效的并发性,具体取决于预期的使用模式。
在 HTTP/2 中,只有请求和响应主体(DATA 帧的帧负载)受流控制。所有 HTTP/3 帧都在 QUIC 流上发送,因此所有流上的所有帧都在 HTTP/3 中进行流控制。
由于存在其他单向流类型,HTTP/3 并不仅仅依赖于并发单向流的数量来控制并发进行中推送的数量。相反,HTTP/3 客户端使用 MAX_PUSH_ID 帧来控制从 HTTP/3 服务器接收到的推送数量。
A2。HTTP 帧类型
HTTP/2 中的许多框架概念可以在 QUIC 上省略,因为传输处理它们。因为帧已经在流上,所以它们可以省略流号。因为帧不会阻塞多路复用(QUIC 的多路复用发生在这一层之下),所以可以删除对可变最大长度数据包的支持。因为流终止由 QUIC 处理,所以不需要 END_STREAM 标志。这允许从通用框架布局中删除标志字段。
帧有效载荷主要来自[ HTTP2 ]。但是,QUIC 包含许多 HTTP/2 中也存在的特性(例如,流控制)。在这些情况下,HTTP 映射不会重新实现它们。因此,HTTP/3 中不需要几种 HTTP/2 帧类型。在不再使用 HTTP/2 定义的帧的地方,已经保留了帧 ID,以最大限度地提高 HTTP/2 和 HTTP/3 实现之间的可移植性。然而,即使出现在两个映射中的帧类型也不具有相同的语义。
许多差异源于 HTTP/2 提供了跨所有流的帧之间的绝对排序这一事实,而 QUIC 仅在每个流上提供这种保证。因此,如果一种帧类型假设来自不同流的帧仍将按发送顺序接收,那么 HTTP/3 将破坏它们。
下面描述了一些特性调整的示例,以及扩展框架实现者将 HTTP/2 扩展转换为 HTTP/3 的一般指导。
A.2.1。优先级差异
HTTP/2 在 PRIORITY 帧和(可选)在 HEADERS 帧中指定优先级分配。HTTP/3 不提供信号优先级的方法。
请注意,虽然没有明确的优先级信号,但这并不意味着优先级对于实现良好性能并不重要。
A.2.2。场压缩差异
HPACK 的设计假设是按顺序交付。编码字段部分的序列必须以与它们编码相同的顺序到达(并被解码)端点。这确保了两个端点的动态状态保持同步。
因为 QUIC 不提供这种总排序,所以 HTTP/3 使用 HPACK 的修改版本,称为 QPACK。QPACK 使用单个单向流对动态表进行所有修改,确保更新的总顺序。所有包含编码字段的帧仅在给定时间引用表状态而不修改它。
[ QPACK ]提供更多详细信息。
A.2.3。流量控制差异
HTTP/2 指定了流流控制机制。尽管所有 HTTP/2 帧都通过流传输,但只有 DATA 帧有效负载受流控制。QUIC 为流数据提供流控制,本文档中定义的所有 HTTP/3 帧类型都在流上发送。因此,所有帧头和有效载荷都受到流控制。
A.2.4。新框架类型定义指南
HTTP/3 中的帧类型定义通常使用 QUIC 变长整数编码。特别是,流 ID 使用这种编码,它允许比 HTTP/2 中使用的编码更大范围的可能值。HTTP/3 中的某些帧使用流 ID 以外的标识符(例如,推送 ID)。如果编码包括流 ID,则可能需要重新定义扩展帧类型的编码。
由于通用 HTTP/3 帧中不存在 Flags 字段,因此那些依赖于标志存在的帧需要为标志分配空间作为其帧有效负载的一部分。
除了这些问题,帧类型 HTTP/2 扩展通常可以移植到 QUIC,只需将 HTTP/2 中的 Stream 0 替换为 HTTP/3 中的控制流。HTTP/3 扩展不会假定排序,但不会受到排序的损害,并且有望移植到 HTTP/2。
A.2.5。HTTP/2 和 HTTP/3 帧类型比较
- 数据(0x0):
-
HTTP/3 帧中没有定义填充。请参阅第 7.2.1 节。
- 标头(0x1):
-
HTTP/3 帧中没有定义 HEADERS 的 PRIORITY 区域。HTTP/3 帧中没有定义填充。请参阅第 7.2.2 节。
- 优先级(0x2):
-
如附录 A.2.1中所述,HTTP/3 不提供信号优先级的方法。
- RST_STREAM (0x3):
-
HTTP/3 中不存在 RST_STREAM 帧,因为 QUIC 提供了流生命周期管理。相同的代码点用于 CANCEL_PUSH 帧(第 7.2.3 节)。
- 设置(0x4):
- PUSH_PROMISE (0x5):
-
PUSH_PROMISE 帧不引用流;相反,推送流使用推送 ID 引用 PUSH_PROMISE 帧。请参阅 第 7.2.5 节。
- 平(0x6):
-
HTTP/3 中不存在 PING 帧,因为 QUIC 提供了等效的功能。
- 离开(0x7):
-
GOAWAY 不包含错误代码。在客户端到服务器的方向,它携带一个 Push ID 而不是服务器发起的流 ID。请参阅第 7.2.6 节。
- WINDOW_UPDATE (0x8):
-
HTTP/3 中不存在 WINDOW_UPDATE 帧,因为 QUIC 提供了流控制。
- 继续(0x9):
-
HTTP/3 中不存在 CONTINUATION 帧;相反,允许使用比 HTTP/2 更大的 HEADERS/PUSH_PROMISE 帧。
如果仍然适用,由 HTTP/2 的扩展定义的帧类型需要为 HTTP/3 单独注册。[ HTTP2 ]中定义的帧 ID为简单起见保留。请注意,HTTP/3 中的帧类型空间要大得多(62 位对 8 位),因此许多 HTTP/3 帧类型没有等效的 HTTP/2 代码点。请参阅第 11.2.1 节。
A.3。HTTP/2 设置参数
与 HTTP/2 的一个重要区别是设置被发送一次,作为控制流的第一帧,此后不能更改。这消除了围绕更改同步的许多极端情况。
HTTP/2 通过 SETTINGS 帧指定的一些传输级选项被 HTTP/3 中的 QUIC 传输参数取代。HTTP/3 中保留的 HTTP 级别设置与 HTTP/2 中的值相同。被取代的设置被保留,它们的接收是错误的。有关保留值和保留值的讨论,请参见 第 7.2.4.1 节。
下面是如何映射每个 HTTP/2 SETTINGS 参数的列表:
- SETTINGS_HEADER_TABLE_SIZE (0x1):
-
见[ QPACK ]。
- SETTINGS_ENABLE_PUSH (0x2):
-
这被删除以支持 MAX_PUSH_ID 框架,它提供对服务器推送的更精细控制。在 HTTP/3 SETTINGS 帧中指定标识符为 0x2(对应于 SETTINGS_ENABLE_PUSH 参数)的设置是错误的。
- SETTINGS_MAX_CONCURRENT_STREAMS (0x3):
-
QUIC 控制最大的开放流 ID 作为其流控制逻辑的一部分。在 HTTP/3 SETTINGS 帧中指定标识符为 0x3(对应于 SETTINGS_MAX_CONCURRENT_STREAMS 参数)的设置是错误的。
- SETTINGS_INITIAL_WINDOW_SIZE (0x4):
-
QUIC 要求在初始传输握手中指定流和连接流控制窗口大小。在 HTTP/3 SETTINGS 帧中使用标识符 0x4(对应于 SETTINGS_INITIAL_WINDOW_SIZE 参数)指定设置是错误的。
- SETTINGS_MAX_FRAME_SIZE (0x5):
-
此设置在 HTTP/3 中没有等效项。在 HTTP/3 SETTINGS 帧中指定标识符为 0x5(对应于 SETTINGS_MAX_FRAME_SIZE 参数)的设置是错误的。
- SETTINGS_MAX_HEADER_LIST_SIZE (0x6):
-
此设置标识符已重命名为 SETTINGS_MAX_FIELD_SECTION_SIZE。
在 HTTP/3 中,设置值是可变长度整数(6、14、30 或 62 位长),而不是 HTTP/2 中的固定长度 32 位字段。这通常会产生较短的编码,但可以为使用完整 32 位空间的设置产生较长的编码。从 HTTP/2 移植的设置可能会选择重新定义其值以将其限制为 30 位以实现更有效的编码,或者如果需要超过 30 位,则使用 62 位空间。
需要为 HTTP/2 和 HTTP/3 分别定义设置。[ HTTP2 ]中定义的设置 ID为简单起见而保留。请注意,HTTP/3 中的设置标识符空间要大得多(62 位对 16 位),因此许多 HTTP/3 设置没有等效的 HTTP/2 代码点。请参阅 第 11.2.2 节。
由于 QUIC 流可能无序到达,因此建议端点在响应其他流之前不要等待对等方的设置到达。请参阅 第 7.2.4.2 节。
A.4。HTTP/2 错误代码
QUIC 与 HTTP/2 提供的“流”和“连接”错误概念相同。但是,HTTP/2 和 HTTP/3 之间的差异意味着错误代码不能在版本之间直接移植。
[ HTTP2 ]的第 7 节中定义的 HTTP/2 错误代码在逻辑上映射到 HTTP/3 错误代码如下:
- NO_ERROR (0x0):
-
第 8.1 节中的 H3_NO_ERROR 。
- PROTOCOL_ERROR (0x1):
-
这被映射到 H3_GENERAL_PROTOCOL_ERROR ,除非已经定义了更具体的错误代码。此类情况包括第 8.1 节中定义的 H3_FRAME_UNEXPECTED、H3_MESSAGE_ERROR 和 H3_CLOSED_CRITICAL_STREAM 。
- INTERNAL_ERROR (0x2):
-
第 8.1 节中的 H3_INTERNAL_ERROR 。
- FLOW_CONTROL_ERROR (0x3):
-
不适用,因为 QUIC 处理流量控制。
- SETTINGS_TIMEOUT (0x4):
-
不适用,因为没有定义 SETTINGS 的确认。
- STREAM_CLOSED (0x5):
-
不适用,因为 QUIC 处理流管理。
- FRAME_SIZE_ERROR (0x6):
-
H3_FRAME_ERROR 错误代码在第 8.1 节中定义。
- REFUSED_STREAM (0x7):
-
H3_REQUEST_REJECTED(在第 8.1 节中)用于指示未处理请求。否则,不适用,因为 QUIC 处理流管理。
- 取消(0x8):
-
第 8.1 节中的 H3_REQUEST_CANCELLED 。
- COMPRESSION_ERROR (0x9):
-
[ QPACK ]中定义了多个错误代码。
- CONNECT_ERROR (0xa):
-
第 8.1 节中的 H3_CONNECT_ERROR 。
- ENHANCE_YOUR_CALM (0xb):
-
第 8.1 节中的 H3_EXCESSIVE_LOAD 。
- INADEQUATE_SECURITY (0xc):
-
不适用,因为假设 QUIC 为所有连接提供足够的安全性。
- HTTP_1_1_REQUIRED (0xd):
-
第 8.1 节中的 H3_VERSION_FALLBACK 。
需要分别为 HTTP/2 和 HTTP/3 定义错误代码。请参阅 第 11.2.3 节。
A.4.1。HTTP/2 和 HTTP/3 错误之间的映射
在 HTTP/2 和 HTTP/3 之间转换的中介可能会遇到来自上游的错误条件。将错误的发生传达给下游很有用,但错误代码在很大程度上反映了通常没有意义传播的连接本地问题。
遇到来自上游源的错误的中介可以通过发送 HTTP 状态代码(例如 502)来指示这一点,这适用于广泛的错误类别。
在极少数情况下,通过将错误映射到与接收器最接近的匹配错误类型来传播错误是有益的。例如,从源接收到 REFUSED_STREAM 类型的 HTTP/2 流错误的中介有一个明确的信号,表明请求没有被处理,并且请求可以安全地重试。将此错误条件作为 H3_REQUEST_REJECTED 类型的 HTTP/3 流错误传播给客户端允许客户端采取它认为最合适的操作。在相反的方向上,中介可能认为传递客户端请求取消是有益的,这些请求通过使用 H3_REQUEST_CANCELLED 终止流来指示;见 第 4.1.2 节。
错误之间的转换在逻辑映射中描述。错误代码在非重叠空间中定义,以防止意外转换可能导致对目标版本使用不适当或未知的错误代码。允许中间人将流错误升级为连接错误,但他们应该意识到 HTTP/3 连接可能是临时或间歇性错误的成本。
附录 B.更改日志
- RFC 编者注: 请在发布本文档的最终版本之前删除此部分。
B.1。由于草案-ietf-quic-http-32
- 删除了草案版本指南;添加了最终版本字符串
- 为格式错误的消息添加了 H3_MESSAGE_ERROR
B.2。由于草案-ietf-quic-http-31
仅编辑更改。
B.3。由于草案-ietf-quic-http-30
仅编辑更改。
B.4。由于草案-ietf-quic-http-29
- 如果接收到与 HTTP/2 中的帧相对应的保留帧类型,则需要连接错误 (#3991, #3993)
- 如果接收到与 HTTP/2 中的设置相对应的保留设置,则需要连接错误 (#3954, #3955)
B.5。自草案-ietf-quic-http-28
- 即使流被重置,也建议使用 CANCEL_PUSH (#3698, #3700)
- 当 GOAWAY 包含更大的标识符时使用 H3_ID_ERROR (#3631, #3634)
B.6。由于草案-ietf-quic-http-27
- 更新文本以引用最新的 HTTP 修订
- 使用 HTTP 权限定义来建立和合并连接 (#253, #2223, #3558)
- 定义从两个端点使用 GOAWAY (#2632, #3129)
- 如果 URI 方案具有强制权限组件,则需要 :authority 或 Host (#3408, #3475)
B.8. 由于草案-ietf-quic-http-25
- HTTP/3 需要 QUICv1 (#3117, #3323)
- 移除 DUPLICATE_PUSH 并允许重复的 PUSH_PROMISE (#3275, #3309)
- 澄清“畸形”的定义(#3352,#3345)
B.9。由于草案-ietf-quic-http-24
- 删除了 H3_EARLY_RESPONSE 错误代码;建议使用 H3_NO_ERROR (#3130,#3208)
- 未知错误码等价于 H3_NO_ERROR (#3276,#3331)
- 一些错误代码保留用于润滑 (#3325,#3360)
B.10。由于草案-ietf-quic-http-23
- 删除
quic
了 Alt-Svc 参数 (#3061,#3118) - 客户端无需保留未知设置以用于 0-RTT (#3110,#3113)
- 澄清 CANCEL_PUSH 周围的错误情况 (#2819,#3083)
B.11。由于草案-ietf-quic-http-22
- 删除了优先级信令 (#2922,#2924)
-
错误代码的进一步更改(#2662,#2551):
- 错误代码重新编号
- HTTP_MALFORMED_FRAME 替换为 HTTP_FRAME_ERROR、HTTP_ID_ERROR 等
- 阐明未知帧类型如何与所需帧序列交互 (#2867,#2858)
- 根据定义的接口术语描述与传输的交互(#2857,#2805)
http-opportunistic
当方案为http
(#2439,#2973)时要求使用资源 (RFC 8164)- 设置标识符不能重复 (#2979)
-
0-RTT (#2972,#2790,#2945) 中 SETTINGS 帧的更改:
- 服务器必须在其 SETTINGS 框架中发送所有具有非默认值的设置,即使在恢复时
- 如果客户端没有与 0-RTT 票证关联的设置,它将使用默认值
- 如果服务器无法恢复客户端将记住的设置,则服务器无法接受早期数据
- 明确禁止升级和 101 状态码 (#2898,#2889)
- 澄清为润滑而保留的帧类型可以出现在任何流上,但禁止由于 HTTP/2 对应而保留的帧类型 (#2997,#2692,#2693)
- 未知的错误代码不能被视为错误 (#2998,#2816)
B.13。由于草案-ietf-quic-http-20
- 禁止关闭控制流 (#2509, #2666)
- 更改默认优先级以使用孤立节点 (#2502, #2690)
- 恢复独占优先级 (#2754, #2781)
- 使用 CONNECT 时限制使用帧 (#2229, #2702)
- 如果 CONNECT 发生连接错误,则关闭并可能重置流 (#2228, #2703)
- 鼓励为 QPACK 提供足够的单向流 (#2100, #2529, #2762)
- 允许扩展使用服务器发起的双向流 (#2711, #2773)
- 阐明最大标题列表大小设置的使用 (#2516, #2774)
-
错误代码及其发送条件的广泛更改
- 更多错误条件需要连接错误(#2511,#2510)
- 更新了非法 GOAWAY 帧的错误代码 (#2714, #2707)
- 为控制流上的 HEADERS 指定错误代码 (#2708)
- 为接收 PUSH_PROMISE 的服务器指定错误代码 (#2709)
- 指定在 HEADERS 之前接收 DATA 的错误代码 (#2715)
- 描述格式错误的消息及其处理 (#2410, #2764)
- 移除 HTTP_PUSH_ALREADY_IN_CACHE 错误 (#2812, #2813)
- 重构 Push ID 相关错误 (#2818, #2820)
- 合理化 HTTP/3 流创建错误 (#2821, #2822)
B.14。自草案-ietf-quic-http-19
- SETTINGS_NUM_PLACEHOLDERS 为 0x9 (#2443,#2530)
- PRIORITY 帧的 Empty 字段中的非零位可能被视为错误 (#2501)
B.15。自草案-ietf-quic-http-18
- 建议在 GOAWAY 之后重置流,但不是必需的 (#2256,#2457)
-
始终使用可变长度整数 (#2437,#2233,#2253,#2275)
- 可变长度帧类型、流类型和设置标识符
- 重新编号的流类型分配
- 修改后的关联保留值
- 帧布局从 Length-Type-Value 切换到 Type-Length-Value (#2395,#2235)
- 为接收 DUPLICATE_PUSH 的服务器指定错误代码 (#2497)
- 对无效优先级使用连接错误 (#2507, #2508)
B.16。自草案-ietf-quic-http-17
- HTTP_REQUEST_REJECTED 用于表示请求可以重试 (#2106, #2325)
- 在错误的流上更改了 GOAWAY 的错误代码 (#2231, #2343)
B.17. 自草案-ietf-quic-http-16
- 将“HTTP/QUIC”重命名为“HTTP/3”(#1973)
-
PRIORITY 框架的变化 (#1865, #2075)
- 允许作为请求流的第一帧
- 删除排他优先级
- 更改优先元素类型位
- 定义 DUPLICATE_PUSH 帧以引用另一个 PUSH_PROMISE (#2072)
- 设置设置的默认值,在接收 SETTINGS 之前允许请求 (#1809, #1846, #2038)
- 阐明未关闭的流的消息处理规则 (#1972, #2003)
- 删除了错误代码 0 的保留并将 HTTP_NO_ERROR 移动到该值 (#1922)
- 删除了对零长度 DATA 帧的禁止 (#2098)
B.18. 由于草案-ietf-quic-http-15
大量的编辑重组;没有技术变化。
B.19。由于草案-ietf-quic-http-14
- 为 QUIC 传输参数推荐合理的值 (#1720,#1806)
- 定义缺少 SETTINGS 帧的错误 (#1697,#1808)
- 设置值是可变长度整数 (#1556,#1807) 并且没有单独的最大值 (#1820)
- 连接关闭的扩展讨论 (#1599,#1717,#1712)
- HTTP_VERSION_FALLBACK 回退到 HTTP/1.1 (#1677,#1685)
B.20。由于草案-ietf-quic-http-13
- 为润滑脂保留一些框架类型 (#1333, #1446)
- 允许未知的单向流类型,而不是错误;一些保留用于润滑脂 (#1490, #1525)
- 要求为 0-RTT 记住设置,禁止减少 (#1541, #1641)
- 指定截断请求的行为 (#1596, #1643)
B.21。由于草案-ietf-quic-http-12
- 如果使用替代方法,则 TLS SNI 扩展不是强制性的 (#1459, #1462, #1466)
- 从 HTTP/3 帧中删除了标志 (#1388, #1398)
- 用于保留可扩展性的保留帧类型和设置 (#1333, #1446)
- 添加了一般错误代码 (#1391, #1397)
- 单向流带有类型字节并且是可扩展的 (#910,#1359)
- 优先级机制现在使用显式占位符来启用树中的持久结构 (#441,#1421,#1422)
B.22。由于草案-ietf-quic-http-11
- 将 QPACK 表更新和确认移动到专用流(#1121、#1122、#1238)
B.23。由于草案-ietf-quic-http-10
- 尝试和接受 0-RTT 时需要记住设置 (#1157, #1207)
B.24。自草案-ietf-quic-http-09
- 选择 QCRAM 用于头部压缩 (#228, #1117)
- server_name TLS 扩展现在是强制性的 (#296, #495)
- 指定处理 Alt-Svc 中不支持的版本 (#1093, #1097)
B.25。由于草案-ietf-quic-http-08
- 阐明连接合并规则 (#940, #1024)
B.26。从草案-ietf-quic-http-07
- QUIC 中整数编码的变化 (#595,#905)
- 酌情使用单向流 (#515, #240, #281, #886)
- 对 GOAWAY 描述的改进 (#604, #898)
- 改进对服务器推送使用的描述 (#947, #950, #957)
B.27。自草案-ietf-quic-http-06
- 跟踪 QUIC 错误代码使用的变化 (#485)
B.28. 由于草案-ietf-quic-http-05
- 使推送 ID 连续,添加 MAX_PUSH_ID,删除 SETTINGS_ENABLE_PUSH (#709)
- 关于 keep-alive 和 QUIC PING 的指南 (#729)
- 关于 GOAWAY 和取消的扩展文本 (#757)
B.29。由于草案-ietf-quic-http-04
- 引用 RFC 5234 (#404)
- 每个请求返回单个流 (#245,#557)
- 使用来自 HTTP/2 (#81) 的单独帧类型和设置注册表
- SETTINGS_ENABLE_PUSH 而不是 SETTINGS_DISABLE_PUSH (#477)
- 恢复 GOAWAY (#696)
- 使用 Push ID 而不是流 ID 识别服务器推送 (#702,#281)
- DATA 帧不能为空 (#700)
B.31。从草案-ietf-quic-http-02
- 跟踪运输草案的变化
B.32。由于草案-ietf-quic-http-01
-
设置更改(#181):
- SETTINGS 只能在连接开始时发送一次;此后没有变化
- SETTINGS_ACK 已移除
- 设置只能在 SETTINGS 框架中发生一次
- 布尔格式更新
- Alt-Svc 参数从“v”更改为“quic”;格式更新 (#229)
- 关闭连接控制流或任何消息控制流是致命错误 (#176)
- HPACK 序列计数器可以换行 (#173)
- 添加了 0-RTT 指导
- 添加了与 HTTP/2 和移植 HTTP/2 扩展的差异指南 (#127,#242)
B.33。由于草案-ietf-quic-http-00
- 在整个 (#11,#29) 中将“HTTP/2-over-QUIC”更改为“HTTP/QUIC”
- 从在 Stream 3 中使用 HTTP/2 帧更改为新的帧格式和每个请求两个流的模型 (#71,#72,#73)
- 从 draft-bishop-httpbis-extended-settings-01 采用 SETTINGS 格式
- 重新设计 SETTINGS_ACK 以解决不确定的流间顺序 (#75)
- 描述的 CONNECT 伪方法 (#95)
- 更新了 ALPN 令牌和 Alt-Svc 指南 (#13,#87)
- 应用层定义的错误代码 (#19,#74)
B.34。由于 draft-shade-quic-http2-mapping-00
- 被采纳为 draft-ietf-quic-http 的基础
- 更新的作者/编辑列表
致谢
本规范的原始作者是 Robbie Shade 和 Mike Warres。
IETF QUIC 工作组得到了很多人的大力支持。其中,以下人员为本文档提供了大量贡献:
- 本斯·贝基
- 达安·德迈耶
- 马丁杜克
- 罗伊菲尔丁
- 艾伦·弗林德尔
- 亚历山德罗·盖迪尼
- 尼克哈珀
- 瑞安汉密尔顿
- 克里斯蒂安·惠特玛
- 苏博德·艾扬格
- 罗宾马克思
- 帕特里克·麦克马纳斯
- 卢卡·尼科里尼
-
奥一穂( Kazuho Oku )
- 卢卡斯·帕杜
- 罗伯托·佩恩
- 朱利安·雷施克
- 埃里克·雷斯科拉
- 马丁·西曼
- 本·施瓦茨
- 伊恩·斯威特
- 威利·陶罗
- 马丁汤姆森
- 德米特里·季霍诺夫
- 辻川达弘
Mike 的部分贡献在他在那里工作期间得到了 Microsoft 的支持。