1. 简介
本节为非规范性内容。
本规范使用 [WEB-TRANSPORT-OVERVIEW] 向服务器发送和接收数据。它的用法类似于 WebSockets,但支持多路流、单向流、乱序传输,以及可靠和不可靠的传输方式。
注意: 本规范中提供的 API 代表了基于 IETF WEBTRANS WG 正在进行的工作的初步提案。 由于 [WEB-TRANSPORT-HTTP3] 和 [WEB-TRANSPORT-HTTP2] 规范仍在制定中,因此协议和 API 都可能会在未来发生重大变化。
2. 一致性
除了标记为非规范性的章节外,本规范中的所有编写指南、图表、示例和注释均为非规范性内容。本规范中的其他所有内容均为规范性内容。
关键词“MUST”、“MUST NOT”、“REQUIRED”、“SHALL”、“SHALL NOT”、“SHOULD”、“SHOULD NOT”、“RECOMMENDED”、“NOT RECOMMENDED”、“MAY”和“OPTIONAL”应按照 [RFC2119] 和 [RFC8174] 中的描述进行解释,当且仅当它们全部以大写形式出现时,如此处所示。
本规范定义了一致性标准,该标准适用于单个产品:实现其中包含的接口的用户代理。
以算法或特定步骤表达的一致性要求可以通过任何方式实现,只要最终结果是等效的。(特别是,本规范中定义的算法旨在易于理解,而不是为了高性能。)
使用 ECMAScript 实现本规范中定义的 API 的实现必须以符合 Web IDL 规范 [WEBIDL] 中定义的 ECMAScript 绑定的方式实现它们,因为本规范使用了该规范及其术语。
3. 协议概念
WebTransport 有两个主要的协议概念:会话和流。每个 WebTransport 会话 可以包含多个 WebTransport 流。
这些不应与 协议名称 混淆,后者是应用层 API 构造。
3.1. WebTransport 会话
一个 WebTransport 会话 是指通过 HTTP/3 或 HTTP/2 底层连接建立的 WebTransport 会话。启用连接池时,一个连接上可能存在多个 WebTransport 会话。
根据 [WEB-TRANSPORT-OVERVIEW] 的定义,一个 WebTransport 会话具有以下能力:
当服务器请求CONNECT 流优雅关闭时,WebTransport 会话 session处于排空状态,详见[WEB-TRANSPORT-OVERVIEW] 第 4.1 节。
要使用可选的整数code和可选的字节序列reason终止终止一个WebTransport 会话session,请遵循[WEB-TRANSPORT-OVERVIEW] 第 4.1 节。
当服务器关闭CONNECT 流时,WebTransport 会话session被终止,可选地包含整数code和字节序列reason,详见[WEB-TRANSPORT-OVERVIEW] 第 4.1 节。
3.2. WebTransport 流
WebTransport 流是 WebTransport 会话上可靠且按顺序排列的字节流的概念,如 [WEB-TRANSPORT-OVERVIEW] Section 4.3 中所述。
一个 WebTransport 流是入向单向、出向单向或双向中的一种。
一个 WebTransport 流具有以下能力:
| 能力 | 定义 | 入向单向流 | 出向单向流 | 双向流 |
|---|---|---|---|---|
| 发送字节(可能带 FIN) | [WEB-TRANSPORT-OVERVIEW] 第4.3节 | 否 | 是 | 是 |
| 接收字节(可能带 FIN) | [WEB-TRANSPORT-OVERVIEW] 第4.3节 | 是 | 否 | 是 |
| 中止接收于WebTransport 流 | [WEB-TRANSPORT-OVERVIEW] 第4.3节 | 是 | 否 | 是 |
| 中止发送于WebTransport 流 | [WEB-TRANSPORT-OVERVIEW] 第4.3节 | 否 | 是 | 是 |
WebTransport 流具有如下信号:
| 事件 | 定义 | 入向单向流 | 出向单向流 | 双向流 |
|---|---|---|---|---|
| 接收中止 | [WEB-TRANSPORT-OVERVIEW] 第4.3节 | 否 | 是 | 是 |
| 发送中止 | [WEB-TRANSPORT-OVERVIEW] 第4.3节 | 是 | 否 | 是 |
| 流量控制 | [WEB-TRANSPORT-OVERVIEW] 第4.3节 | 否 | 是 | 是 |
4. WebTransportDatagramsWritable 接口
WebTransportDatagramsWritable 是一个
WritableStream,为发送数据报提供出站流式传输功能。
[Exposed =(Window ,Worker ),SecureContext ,Transferable ]interface WebTransportDatagramsWritable :WritableStream {attribute WebTransportSendGroup ?sendGroup ;attribute long long sendOrder ; };
4.1. 内部插槽
一个 WebTransportDatagramsWritable 对象具有以下内部插槽。
| 内部槽位 | 描述(非规范性) |
|---|---|
[[OutgoingDatagramsQueue]]
| 一个包含外发数据报、时间戳和 promise 的队列,该 promise 会在数据报被发送或丢弃时被解决。 |
[[Transport]]
| WebTransport
拥有的这个 WebTransportDatagramsWritable。
|
[[SendGroup]]
| 可选的 WebTransportSendGroup,
或 null。
|
[[SendOrder]]
| 可选的发送顺序号,默认为 0。 |
WebTransportDatagramsWritable,
给定一个 WebTransport
transport、sendGroup 和 sendOrder,执行以下步骤。
-
令 stream 为一个 新的
WebTransportDatagramsWritable, 其各项为:[[OutgoingDatagramsQueue]]-
一个空队列
[[Transport]]-
transport
[[SendGroup]]-
sendGroup
[[SendOrder]]-
sendOrder
-
令 writeDatagramsAlgorithm 为执行 writeDatagrams, 参数为 transport 和 stream 的操作。
-
设置 stream, writeAlgorithm 设置为 writeDatagramsAlgorithm。
-
返回 stream。
4.2. 属性
sendGroup, 类型为 WebTransportSendGroup, 可空-
getter 步骤:
-
返回 this 的
[[SendGroup]]。
setter 步骤,给定 value:
-
如果 value 非空,且 value.
[[Transport]]不是 this.[[Transport]],抛出一个InvalidStateError。 -
设置 this.
[[SendGroup]]为 value。
-
sendOrder, 类型为 long long-
getter 步骤:
-
返回 this 的
[[SendOrder]]。
setter 步骤,给定 value:
-
设置 this.
[[SendOrder]]为 value。
-
4.3. 过程
writeDatagrams 算法给定一个 transport 和 writable 作为参数,以及 data 作为输入。它通过运行以下步骤来定义:
-
设 timestamp 为一个表示当前时间的 timestamp。
-
如果 data 不是一个
BufferSource对象,则返回 一个 promise 被拒绝,并返回一个TypeError。 -
设 datagrams 为 transport.
[[Datagrams]]。 -
如果 datagrams.
[[OutgoingMaxDatagramSize]]小于 data 的 [[ByteLength]],则返回 一个 promise 被解析,并返回 undefined。 -
设 promise 为一个新的 promise。
-
设 bytes 为 data 表示的字节的副本。
-
设 chunk 为一个元组,包含 bytes、timestamp 和 promise。
-
将 chunk 入队到 writable.
[[OutgoingDatagramsQueue]]。 -
如果 writable.
[[OutgoingDatagramsQueue]]的长度小于 datagrams.[[OutgoingDatagramsHighWaterMark]],则解析 promise 并返回 undefined。 -
返回 promise。
注意: 关联的 WritableStream 仅当该流的 writeDatagrams 返回的所有 promise 都已解析时,才会调用 writeDatagrams。因此,只有当
Web
开发人员关注 WritableStreamDefaultWriter.ready 时,时间戳和过期持续时间才能很好地工作。
要 sendDatagrams,给定一个
WebTransport 对象
transport 和一个 WebTransportDatagramsWritable 对象
writable,将一个网络任务入队,使用 transport 运行以下步骤:
-
设 queue 为 writable.
[[OutgoingDatagramsQueue]]的副本。注意: 上述副本以及将网络任务排队以运行这些步骤都可以进行优化。
-
设 maxSize 为 transport.
[[Datagrams]].[[OutgoingMaxDatagramSize]]。 -
设 duration 为 transport.
[[Datagrams]].[[OutgoingDatagramsExpirationDuration]]。 -
如果 duration 为 null,则将 duration 设置为一个 实现定义的值。
-
并行运行以下步骤:
-
当 queue 不为空时:
-
如果 transport.
[[State]]不是"connected",则返回。 -
当 queue 不为空时:
-
设 bytes、timestamp 和 promise 为 queue 的第一个元素。
-
如果 bytes 的长度 ≤ maxSize:
-
如果无法立即将 bytes 发送到网络,则跳出此循环。
-
发送一个数据报,使用 transport.
[[Session]]和 bytes。
-
-
从 queue 中移除第一个元素。
-
-
对于任何 WebTransport 对象,用户代理必须:其
[[State]] 为 "connecting" 或
"connected",在与其关联的 WebTransportDatagramsWritable 对象的子集(由 发送顺序规则确定)上运行 sendDatagrams,并且只要算法能够取得进展,就应尽快执行此操作。
发送顺序规则是,通常,发送可能与先前排队的流和数据报的发送交错进行,以及尚未排队以通过此传输发送的流和数据报,但发送必须暂停,直到所有在具有相同
[[SendGroup]]
和更高
[[SendOrder]]
的流和数据报上排队等待发送的字节,这些流和数据报既没有 出错,也没有被 流量控制阻止,已经被发送。
注意: 允许在传输的 [[State]]
为 "connecting" 时写入数据报。数据报存储在
[[OutgoingDatagramsQueue]]
中,并且可以像在 "connected" 状态下一样丢弃它们。一旦传输的 [[State]] 变为 "connected",它将开始发送排队的数据报。
5. WebTransportDatagramDuplexStream 接口
一个 WebTransportDatagramDuplexStream 是一个通用的双工流。
[Exposed =(Window ,Worker ),SecureContext ]interface WebTransportDatagramDuplexStream {WebTransportDatagramsWritable createWritable (optional WebTransportSendOptions = {});options readonly attribute ReadableStream readable ;readonly attribute unsigned long maxDatagramSize ;attribute unrestricted double ?incomingMaxAge ;attribute unrestricted double ?outgoingMaxAge ;attribute unrestricted double incomingHighWaterMark ;attribute unrestricted double outgoingHighWaterMark ; };
5.1. 内部插槽
| 内部槽位 | 描述(非规范性) |
|---|---|
[[Transport]]
| WebTransport
拥有的这个 WebTransportDatagramDuplexStream。
|
[[Readable]]
| 用于接收数据报的 ReadableStream。
|
[[ReadableType]]
| 用于接收数据报的 ReadableStreamType。
|
[[Writables]]
| 一个 有序集合
的 WebTransportDatagramsWritable
流,初始为空。
|
[[IncomingDatagramsQueue]]
| 包含接收数据报及时间戳对的队列。 |
[[IncomingDatagramsPullPromise]]
| 由 pullDatagrams 设置的 promise,用于等待接收数据报。 |
[[IncomingDatagramsHighWaterMark]]
| 用于接收数据报的
unrestricted double
,表示其 高水位线。
|
[[IncomingDatagramsExpirationDuration]]
| 用于接收数据报的
unrestricted double
,表示过期持续时间(毫秒),或为 null。
|
[[OutgoingDatagramsHighWaterMark]]
| 用于发送数据报的
unrestricted double
,表示其 高水位线。
|
[[OutgoingDatagramsExpirationDuration]]
| 用于发送数据报的
unrestricted double
,表示过期持续时间(毫秒),或为 null。
|
[[OutgoingMaxDatagramSize]]
|
一个整数,表示外发数据报最大尺寸。
最大数据报尺寸取决于所使用的协议。
在 HTTP/3 [WEB-TRANSPORT-HTTP3] 中,该值与路径的
MTU 估算相关,
实现可能会因各种开销按需减少。
在 HTTP/2 [WEB-TRANSPORT-HTTP2] 中,没有对应的限制。
由于数据报的处理通常需要将整个报文驻留在内存中, 实现会对此大小有上限。 未来的协议扩展可能允许所有协议变体对这些大小限制进行信令协商。 |
用户代理可以随时更新任何 [[OutgoingMaxDatagramSize]]
,只要对应的 WebTransport
对象其
[[State]]
为 "connecting" 或 "connected"。
WebTransportDatagramDuplexStream
,给定一个 WebTransport
transport、readable 和 readableType,执行以下步骤。
-
令 stream 为一个 新的
WebTransportDatagramDuplexStream, 其各项为:[[Transport]]-
transport
[[Readable]]-
readable
[[ReadableType]]-
readableType
[[Writables]]-
一个空的 有序集合。
[[IncomingDatagramsQueue]]-
一个空队列
[[IncomingDatagramsPullPromise]]-
null
[[IncomingDatagramsHighWaterMark]]-
一个 实现定义的值
[[IncomingDatagramsExpirationDuration]]-
null
[[OutgoingDatagramsHighWaterMark]]-
一个 实现定义的值
此实现定义的值应根据传输速率进行调优,保证传输性能不影响数据时效性。
[[OutgoingDatagramsExpirationDuration]]-
null
[[OutgoingMaxDatagramSize]]-
一个 实现定义的整数。
-
返回 stream。
5.2. 方法
createWritable()-
创建一个
WebTransportDatagramsWritable。当调用createWritable()方法时,用户代理必须执行以下步骤:-
令 transport 为与 this 关联的
WebTransport对象。 -
如果 transport.
[[State]]为"closed"或"failed", 抛出一个InvalidStateError。 -
如果 sendGroup 不为 null 且 sendGroup.
[[Transport]]不等于 this.[[Transport]], 抛出 一个InvalidStateError。 -
返回创建一个
WebTransportDatagramsWritable的结果,参数为 transport、sendGroup 和 sendOrder。
-
5.3. 属性
readable, 类型为 ReadableStream, 只读-
getter 步骤如下:
-
返回 this.
[[Readable]]。
-
incomingMaxAge, 类型为 unrestricted double, 可为 null-
getter 步骤如下:
setter 步骤(给定 value)如下:
-
如果 value 为负数或 NaN,抛出
RangeError。 -
如果 value 等于
0,将 value 设为 null。 -
将 this.
[[IncomingDatagramsExpirationDuration]]设置为 value。
maxDatagramSize, 类型为 unsigned long, 只读-
可传递给
WebTransportDatagramsWritable的最大数据尺寸。getter 步骤为返回 this.[[OutgoingMaxDatagramSize]]。 outgoingMaxAge, 类型为 unrestricted double, 可为 null-
getter 步骤如下:
setter 步骤(给定 value)如下:
-
如果 value 为负数或 NaN,抛出
RangeError。 -
如果 value 等于
0,将 value 设为 null。 -
将 this.
[[OutgoingDatagramsExpirationDuration]]设置为 value。
incomingHighWaterMark, 类型为 unrestricted double-
getter 步骤如下:
setter 步骤(给定 value)如下:
-
如果 value 为负数或 NaN,抛出
RangeError。 -
如果 value 小于
1,将 value 设为1。 -
将 this.
[[IncomingDatagramsHighWaterMark]]设置为 value。
outgoingHighWaterMark, 类型为 unrestricted double-
getter 步骤如下:
setter 步骤(给定 value)如下:
-
如果 value 为负数或 NaN,抛出
RangeError。 -
如果 value 小于
1,将 value 设为1。 -
将 this.
[[OutgoingDatagramsHighWaterMark]]设置为 value。
5.4. 过程
要拉取数据报,给定
WebTransport
对象 transport,执行以下步骤:
-
令 datagrams 为 transport.
[[Datagrams]]。 -
断言:datagrams.
[[IncomingDatagramsPullPromise]]为 null。 -
令 queue 为 datagrams.
[[IncomingDatagramsQueue]]。 -
如果 queue 为空,则:
-
将 datagrams.
[[IncomingDatagramsPullPromise]]设为新 promise。 -
返回 datagrams.
[[IncomingDatagramsPullPromise]]。
-
-
令 datagram 和 timestamp 作为 出队 queue 的结果。
-
如果 datagrams.
[[ReadableType]]为"bytes",则:-
如果 datagrams.
[[Readable]]的 当前 BYOB 请求视图不为 null,则:-
令 view 为 datagrams.
[[Readable]]的 当前 BYOB 请求视图。 -
如果 view 的 字节长度 小于 datagram 的大小,返回 一个带有
RangeError的 reject promise。 -
令 elementSize 为 类型化数组构造函数表中 view.[[TypedArrayName]] 指定的元素大小。如果 view 没有 [[TypedArrayName]] 内部槽(即为
DataView),则 elementSize 为 0。
-
-
从字节拉取 datagram 到 datagrams.
[[Readable]]。
-
-
否则:
-
令 chunk 为一个代表 datagram 的新
Uint8Array对象。 -
入队 chunk 到 transport.
[[Datagrams]].[[Readable]]。
-
-
返回 一个已解决为 undefined 的 promise。
要接收数据报,给定 WebTransport
对象 transport,执行以下步骤:
-
令 timestamp 为当前时刻的时间戳。
-
令 queue 为 datagrams.
[[IncomingDatagramsQueue]]。 -
令 duration 为 datagrams.
[[IncomingDatagramsExpirationDuration]]。 -
如果 duration 为 null,则将 duration 设为实现定义的值。
-
令 session 为 transport.
[[Session]]。 -
只要 session 上有可用的接收数据报,则:
-
令 toBeRemoved 为 queue 的长度减去 datagrams.
[[IncomingDatagramsHighWaterMark]]。 -
只要 queue 不为空:
-
如果 queue 不为空且 datagrams.
[[IncomingDatagramsPullPromise]]非 null,则:-
令 bytes 和 timestamp 为 出队 queue 的结果。
-
令 promise 为 datagrams.
[[IncomingDatagramsPullPromise]]。 -
将 datagrams.
[[IncomingDatagramsPullPromise]]设为 null。 -
排队一个网络任务,以 transport 运行以下步骤:
-
令 chunk 为表示 bytes 的新
Uint8Array对象。 -
入队 chunk 到 datagrams.
[[Readable]]。 -
解决 promise,值为 undefined。
-
-
当算法可以取得进展时,对于任何 WebTransport
对象且其
[[State]]
为 "connected",用户代理应尽快运行 接收数据报。
6. WebTransport 接口
WebTransport 提供了一个 API,用于访问 [WEB-TRANSPORT-OVERVIEW] 中定义的底层传输功能。
[Exposed =(Window ,Worker ),SecureContext ]interface {WebTransport (constructor USVString ,url optional WebTransportOptions = {});options Promise <WebTransportConnectionStats >getStats (); [NewObject ]Promise <ArrayBuffer >exportKeyingMaterial (BufferSource ,label optional BufferSource );context readonly attribute Promise <undefined >ready ;readonly attribute WebTransportReliabilityMode reliability ;readonly attribute WebTransportCongestionControl congestionControl ; [EnforceRange ]attribute unsigned short ?anticipatedConcurrentIncomingUnidirectionalStreams ; [EnforceRange ]attribute unsigned short ?anticipatedConcurrentIncomingBidirectionalStreams ;readonly attribute DOMString protocol ;readonly attribute Promise <WebTransportCloseInfo >closed ;readonly attribute Promise <undefined >draining ;undefined close (optional WebTransportCloseInfo = {});closeInfo readonly attribute WebTransportDatagramDuplexStream datagrams ;Promise <WebTransportBidirectionalStream >createBidirectionalStream (optional WebTransportSendStreamOptions = {}); /* a ReadableStream of WebTransportBidirectionalStream objects */options readonly attribute ReadableStream incomingBidirectionalStreams ;Promise <WebTransportSendStream >createUnidirectionalStream (optional WebTransportSendStreamOptions = {}); /* a ReadableStream of WebTransportReceiveStream objects */options readonly attribute ReadableStream incomingUnidirectionalStreams ;WebTransportSendGroup createSendGroup ();static readonly attribute boolean supportsReliableOnly ; };enum {WebTransportReliabilityMode ,"pending" ,"reliable-only" , };"supports-unreliable"
6.1. 内部插槽
一个 WebTransport
对象具有以下内部槽位。
| 内部槽位 | 描述(非规范性) |
|---|---|
[[SendStreams]]
| 一个 有序集合,
包含该 WebTransportSendStream
拥有的流。
|
[[ReceiveStreams]]
| 一个 有序集合,
包含该
WebTransportReceiveStream
拥有的流。
|
[[IncomingBidirectionalStreams]]
| 一个 ReadableStream
,包含 WebTransportBidirectionalStream
对象。
|
[[IncomingUnidirectionalStreams]]
| 一个 ReadableStream
,包含 WebTransportReceiveStream。
|
[[State]]
| 一个枚举值,用于指示传输的状态。可为
"connecting"、
"connected"、"draining"、"closed" 或 "failed"。
|
[[Ready]]
| 当相关 WebTransport 会话 建立 时完成的 promise, 或建立过程失败则被拒绝。 |
[[Reliability]]
| 一个 WebTransportReliabilityMode
,表示首跳是否支持不可靠(UDP)传输或仅支持可靠(TCP 回退)传输。在连接建立前返回 "pending"。
|
[[CongestionControl]]
| 一个 WebTransportCongestionControl
,表示应用是否请求并由用户代理满足了针对吞吐量或低延迟优化的拥塞控制算法,或 "default"。
|
[[AnticipatedConcurrentIncomingUnidirectionalStreams]]
| 应用预期服务器将创建的并发打开的 入向单向流的数量,或为 null。 |
[[AnticipatedConcurrentIncomingBidirectionalStreams]]
| 应用预期服务器将创建的并发打开的 双向流的数量,或为 null。 |
[[Protocol]]
| 一个字符串,指示服务器选择的应用层协议(如有)。初始为空字符串。 |
[[Closed]]
| 当关联的 WebTransport
对象
被正常关闭时完成,或被异常关闭或初始化失败时被拒绝的 promise。
|
[[Draining]]
| 当相关 WebTransport 会话 被排空 时完成的 promise。 |
[[Datagrams]]
| 一个 WebTransportDatagramDuplexStream。
|
[[Session]]
| 该 WebTransport
对象对应的 WebTransport 会话,或为 null。
|
[[NewConnection]]
| 为 "no" 或 "yes-and-dedicated"。
|
[[RequireUnreliable]]
| 一个布尔值,指示是否需要 UDP。 |
[[ServerCertificateHashes]]
| 一个 列表,包含零个或多个 WebTransportHash
对象。
|
6.2. 构造函数
WebTransport()
构造函数被调用时,用户代理必须运行以下步骤:
-
令 baseURL 为 this 的 相关设置对象 的 API 基础 URL。
-
如果 url 失败,抛出 一个
SyntaxError异常。 -
如果 url 的 scheme 不是
https,抛出 一个SyntaxError异常。 -
如果 url 的 fragment 非空,抛出 一个
SyntaxError异常。 -
令 allowPooling 为
options的allowPooling。 -
令 dedicated 为 allowPooling 的否定。
-
令 serverCertificateHashes 为
options的serverCertificateHashes。 -
如果 dedicated 为 false 且 serverCertificateHashes 非空,则 抛出 一个
NotSupportedError异常。 -
令 newConnection 为当 dedicated 为 false 时的 "
no";否则为 "yes-and-dedicated"。 -
令 requireUnreliable 为
options的requireUnreliable。 -
令 congestionControl 为
options的congestionControl。 -
如果 congestionControl 不是
"default",且用户代理不支持任何针对 congestionControl 优化的拥塞控制算法(按 [RFC9002] 第 7 节 所允许),则将 congestionControl 设为"default"。 -
如果 protocols 中的任一值出现多次、未能满足 WebTransport 协议定义的协商应用协议值组成元素的要求,或其 isomorphic encoded 长度为 0 或超过 512,则 抛出 一个
SyntaxError异常。 [WEB-TRANSPORT-OVERVIEW] 第 3.1 节。 -
令 anticipatedConcurrentIncomingUnidirectionalStreams 为
options的anticipatedConcurrentIncomingUnidirectionalStreams。 -
令 anticipatedConcurrentIncomingBidirectionalStreams 为
options的anticipatedConcurrentIncomingBidirectionalStreams。 -
令 datagramsReadableType 为
options的datagramsReadableType。 -
令 incomingDatagrams 为一个新的 new
ReadableStream。 -
令 transport 为新构造的
WebTransport对象,其包含:[[SendStreams]]-
一个空的 有序集合
[[ReceiveStreams]]-
一个空的 有序集合
[[IncomingBidirectionalStreams]]-
一个新的
ReadableStream [[IncomingUnidirectionalStreams]]-
一个新的
ReadableStream [[State]]-
"connecting" [[Ready]]-
一个新的 promise
[[Reliability]]-
"pending"
[[CongestionControl]]-
congestionControl
[[AnticipatedConcurrentIncomingUnidirectionalStreams]]-
anticipatedConcurrentIncomingUnidirectionalStreams
[[AnticipatedConcurrentIncomingBidirectionalStreams]]-
anticipatedConcurrentIncomingBidirectionalStreams
[[Protocol]]-
一个空字符串
[[Closed]]-
一个新的 promise
[[Draining]]-
一个新的 promise
[[Datagrams]]-
未定义
[[Session]]-
null
[[NewConnection]]-
newConnection
[[RequireUnreliable]]-
requireUnreliable
[[ServerCertificateHashes]]-
serverCertificateHashes
-
将 transport.
[[Datagrams]]设置为通过 创建 一个WebTransportDatagramDuplexStream得到的结果,传入 transport、incomingDatagrams 和 datagramsReadableType。 -
令 pullDatagramsAlgorithm 为一个运行 pullDatagrams(参数为 transport) 的操作。
注:建议在数据报上使用 64 KiB 的缓冲区,因为有效的最大 WebTransport 数据报帧大小上限与 QUIC 最大数据报帧大小的推荐值相同,即 64 KiB(参见 [QUIC-DATAGRAM] 第 3 节)。这将确保流不会因数据报大于缓冲区而出错。
-
如果 datagramsReadableType 为
"bytes",则应为 incomingDatagrams 设置 字节读取支持,并将其 pullAlgorithm 设为 pullDatagramsAlgorithm,将 highWaterMark 设为 0。否则,按照常规为 incomingDatagrams 设置,将 pullAlgorithm 设为 pullDatagramsAlgorithm,并将 highWaterMark 设为 0。 -
令 pullBidirectionalStreamAlgorithm 为一个运行 pullBidirectionalStream(参数为 transport) 的操作。
-
为 transport.
[[IncomingBidirectionalStreams]]设置 pullAlgorithm 为 pullBidirectionalStreamAlgorithm,并将 highWaterMark 设为 0。 -
令 pullUnidirectionalStreamAlgorithm 为一个运行 pullUnidirectionalStream(参数为 transport) 的操作。
-
为 transport.
[[IncomingUnidirectionalStreams]]设置 pullAlgorithm 为 pullUnidirectionalStreamAlgorithm,并将 highWaterMark 设为 0。 -
令 client 为 transport 的 相关设置对象。
-
令 origin 为 client 的 origin。
-
令 request 为一个新的 request,其 URL 为 url,client 为 client,service-workers 模式 为 "
none", referrer 为 "no-referrer",mode 为 "webtransport", credentials mode 为 "omit", cache mode 为 "no-store", policy container 为 client 的 policy container,destination 为 "", origin 为 origin,并且 redirect mode 为 "error"。注:不会跟随重定向。由重定向引起的网络错误故意与其他网络错误不可区分。在跨源上下文中,这会泄露通常由 CORS 阻止的信息。在同源上下文中,可能会鼓励应用滥用握手作为传递信息的途径。
-
将 request 的 method 设置为 "
CONNECT",并将该 method 关联的:protocolpseudo-header 设置为"webtransport"。 -
如果 protocols 非空,在 request 的 header list 中设置一个结构化字段值,键为
WT-Available-Protocols,值为一个结构化 header 列表,其成员为 protocols 中按顺序的结构化 header 字符串项。 -
Fetch request,将 useParallelQueue 设为 true,并将 processResponse 设为在给定 response 时运行以下步骤:
-
用 response、origin、protocols 和 congestionControl 运行 处理 WebTransport fetch 响应。
-
-
返回 transport。
-
令 transport 为与 request 关联的
WebTransport对象。 -
令 url 为 request 的 当前 URL。
-
令 newConnection 为 transport.
[[NewConnection]]。 -
令 requireUnreliable 为 transport.
[[RequireUnreliable]]。 -
令 serverCertificateHashes 为 transport.
[[ServerCertificateHashes]]中的值。 -
令 connection 为使用 networkPartitionKey、url、false、newConnection 和 requireUnreliable 获取连接的结果。当获取连接时,如果 serverCertificateHashes 非空,则不要使用默认的证书验证算法;当满足 自定义证书要求 且对证书哈希的 验证 相对于 serverCertificateHashes 返回 true 时,才将证书视为有效。如果任一条件不满足,结果为失败。
-
如果 connection 为失败,返回失败。
-
等待 connection 接收第一个 SETTINGS 帧,并令 settings 为表示该 SETTINGS 帧的字典。
-
如果 settings 不包含
SETTINGS_ENABLE_CONNECT_PROTOCOL(0x08,见 RFC8441 第 3 节 用于 HTTP/2;0x08,见 RFC9220 第 3 节 用于 HTTP/3)且其值不是 1,则返回失败。 -
如果 settings 未指示服务器支持 WebTransport,则返回失败。 [WEB-TRANSPORT-OVERVIEW] 第 4.1 节。
-
在 HTTP/3 上,支持需要
SETTINGS_WT_MAX_SESSIONS的值大于 0,且需要SETTINGS_H3_DATAGRAM的值为 1。 [WEB-TRANSPORT-HTTP3] 第 3.1 节。 -
在 HTTP/2 上,潜在支持已由上文的
SETTINGS_ENABLE_CONNECT_PROTOCOL指示。 [WEB-TRANSPORT-HTTP2] 第 3.1 节。
注:
SETTINGS_WT_MAX_SESSIONS在 IETF 中仍在调整,可能会改回SETTINGS_ENABLE_WEBTRANSPORT。 -
-
返回 connection。
-
如果 response 是 网络错误,则中止剩余步骤并为 transport 排队一个网络任务 来运行这些步骤:
-
如果 transport.
[[State]]是"closed"或"failed",则中止这些步骤。 -
令 error 为新创建的一个 异常,类型为
WebTransportError,其source为"session"。 -
清理 transport,使用 error。
-
-
令 connection 为与 response 关联的底层连接。
-
遵循 [WEB-TRANSPORT-OVERVIEW] 第 4.1 节 中的任何限制,以在 connection 上使用服务器的 response 建立 一个 WebTransport 会话。
-
令 session 为刚刚在 connection 上 建立 的 WebTransport 会话。由此产生的底层传输流称为该会话的 CONNECT 流。
注:该步骤也完成了在 [QUIC-DATAGRAM] 中指定的传输参数交换。
-
如果上一步失败, 中止剩余步骤并为 transport 排队一个网络任务 来运行这些步骤:
-
如果 transport.
[[State]]是"closed"或"failed",则中止这些步骤。 -
令 error 为新创建的一个 异常,类型为
WebTransportError,其source为"session"。 -
清理 transport,使用 error。
-
-
如果用户代理支持多于一种拥塞控制算法,则为此 connection 选择一个适合 congestionControl 的算法用于发送数据。
-
为 transport 排队一个网络任务 来运行这些步骤:
-
断言:this 的
[[Datagrams]]的[[OutgoingMaxDatagramSize]]是一个整数。 -
如果 transport.
[[State]]不是"connecting": -
将 transport.
[[State]]设为"connected"。 -
将 transport.
[[Session]]设为 session。 -
将 transport.
[[Protocol]]设为协商得到的应用协议的字符串值(如果存在),按 [WEB-TRANSPORT-OVERVIEW] 第 3.1 节 的说明,否则设为""。 -
如果连接为 HTTP/3 连接,则将 transport.
[[Reliability]]设为"supports-unreliable"。 -
如果连接为 HTTP/2 连接 [WEB-TRANSPORT-HTTP2],则将 transport 的
[[Reliability]]设为"reliable-only"。
-
WebTransport
对象 transport 时,运行下列步骤。
-
如果 transport.
[[State]]为"connecting",则在 transport.[[Ready]]实现后 执行 以下步骤,并返回其结果:-
返回对 pullBidirectionalStream(参数为 transport) 的调用结果。
-
-
如果 transport.
[[State]]不是"connected",则返回一个新的被拒绝的 promise,拒绝原因为一个InvalidStateError。 -
令 session 为 transport.
[[Session]]。 -
令 p 为一个新的 promise。
-
并行运行以下步骤:
-
等待直到 session 中有一个 可用的传入双向流。
-
令 internalStream 为从 session 接收 到的双向流 的结果。
-
为 transport 排队一个网络任务 来运行这些步骤:
-
令 stream 为通过 创建 一个
WebTransportBidirectionalStream(参数为 internalStream 和 transport) 得到的结果。 -
将 stream 入队 到 transport.
[[IncomingBidirectionalStreams]]。 -
解析 p 为 undefined。
-
-
-
返回 p。
WebTransport
对象 transport 时,运行下列步骤。
-
如果 transport.
[[State]]为"connecting",则在 transport.[[Ready]]实现后 执行 以下步骤,并返回其结果:-
返回对 pullUnidirectionalStream(参数为 transport) 的调用结果。
-
-
如果 transport.
[[State]]不是"connected",则返回一个新的被拒绝的 promise,拒绝原因为一个InvalidStateError。 -
令 session 为 transport.
[[Session]]。 -
令 p 为一个新的 promise。
-
并行运行以下步骤:
-
等待直到 session 中有一个 可用的传入单向流。
-
令 internalStream 为从 session 接收 到的传入单向流 的结果。
-
为 transport 排队一个网络任务 来运行这些步骤:
-
令 stream 为通过 创建 一个
WebTransportReceiveStream(参数为 internalStream 和 transport) 得到的结果。 -
将 stream 入队 到 transport.
[[IncomingUnidirectionalStreams]]。 -
解析 p 为 undefined。
-
-
-
返回 p。
6.3. 属性
ready,类型为 Promise<undefined>,只读closed,类型为 Promise<WebTransportCloseInfo>,只读-
读取时,必须返回 this 的
[[Closed]]。 draining,类型为 Promise<undefined>,只读-
读取时,必须返回 this 的
[[Draining]]。 datagrams,类型为 WebTransportDatagramDuplexStream, 只读-
用于在本会话中收发数据报的单个双工流。
datagrams属性的 getter 步骤如下:-
返回 this 的
[[Datagrams]]。
-
incomingBidirectionalStreams, 类型为 ReadableStream,只读-
返回由服务器接收的
ReadableStream,其元素为WebTransportBidirectionalStream。注:传入流是否已有数据,取决于服务器行为。
incomingBidirectionalStreams属性的 getter 步骤如下: incomingUnidirectionalStreams, 类型为 ReadableStream,只读-
一个单向流的
ReadableStream, 每个流由一个WebTransportReceiveStream表示, 它们都来自服务器。注:传入流是否已有数据,取决于服务器行为。
incomingUnidirectionalStreams的 getter 步骤如下: reliability,类型为 WebTransportReliabilityMode, 只读-
表示连接是否支持不可靠(基于 UDP)传输或只支持可靠(TCP 回退)传输。 在未建立连接前返回
"pending"。 getter 步骤为返回 this 的[[Reliability]]。 congestionControl, 类型为 WebTransportCongestionControl, 只读-
应用层的偏好,如果在构造函数中指定并被用户代理满足,则该连接发送数据时使用针对吞吐量或低延迟优化的拥塞控制算法。如果请求了偏好但未被满足,则值为
"default"。 getter 步骤为返回 this 的[[CongestionControl]]。 supportsReliableOnly, 类型为 boolean,只读-
当用户代理支持仅通过可靠 WebTransport 会话和 连接 时返回 true,否则为 false。
anticipatedConcurrentIncomingUnidirectionalStreams, 类型为 unsigned short,可为 null-
允许应用可选地声明其预期服务器将创建的并发 传入单向流的数量。 如果非 null,用户代理在与服务器协商时应尝试将
[[AnticipatedConcurrentIncomingUnidirectionalStreams]]纳入考虑,从而减少未来往返次数。getter 步骤为返回 this 的
[[AnticipatedConcurrentIncomingUnidirectionalStreams]]。setter 步骤,给定 value,是将 this 的
[[AnticipatedConcurrentIncomingUnidirectionalStreams]]设置为 value。 anticipatedConcurrentIncomingBidirectionalStreams, 类型为 unsigned short,可为 null-
允许应用可选地声明其预期服务器将创建的并发 双向流的数量。 如果非 null,用户代理在与服务器协商时应尝试将
[[AnticipatedConcurrentIncomingBidirectionalStreams]]纳入考虑,从而减少未来的往返次数。getter 步骤为返回 this 的
[[AnticipatedConcurrentIncomingBidirectionalStreams]]。setter 步骤,给定 value,是将 this 的
[[AnticipatedConcurrentIncomingBidirectionalStreams]]设置为 value。
注:设置 anticipatedConcurrentIncomingUnidirectionalStreams
或
anticipatedConcurrentIncomingBidirectionalStreams
不能保证应用会收到预期数量的流。
protocol,类型为 DOMString,只读-
建立 WebTransport 会话 且在构造函数中
protocols选项为非空数组时,返回服务器选择的应用层协议(如有)。否则为空字符串。 getter 步骤为返回 this 的[[Protocol]]。
6.4. 方法
close(closeInfo)-
终止与该 WebTransport 对象关联的 WebTransport 会话。
当调用 close 时,用户代理必须运行以下步骤:
-
令 transport 为 this。
-
如果 transport.
[[State]]为"closed"或"failed",则中止这些步骤。 -
如果 transport.
[[State]]为"connecting":-
令 error 为新创建的一个 WebTransportError,其
source为"session"。 -
清理 transport,使用 error。
-
中止这些步骤。
-
-
令 session 为 transport.
[[Session]]。 -
令 code 为 closeInfo.
closeCode。 -
令 reasonString 为 closeInfo.
reason的最大 代码单元前缀,保证其 UTF-8 编码后长度不超过 1024。 -
令 reason 为 reasonString 的 UTF-8 编码值。
-
并行地,使用 code 和 reason 终止 session。
注:这也会对 transport.
[[SendStreams]]和[[ReceiveStreams]]中包含的 WebTransport 流 执行 中止发送 或 中止接收。 -
清理 transport,使用
AbortError和 closeInfo。
-
getStats()-
收集本
WebTransport的 底层连接 的统计数据并异步返回结果。当调用 getStats 时,用户代理必须运行以下步骤:
-
令 transport 为 this。
-
令 p 为一个新的 promise。
-
如果 transport.
[[State]]为"failed",则 拒绝 p,原因为InvalidStateError,并中止这些步骤。 -
并行运行以下步骤:
-
如果 transport.
[[State]]为"connecting",则等待其状态改变。 -
如果 transport.
[[State]]为"failed",则在 为 transport 排队一个网络任务后,拒绝 p,原因为InvalidStateError,然后中止这些步骤。 -
如果 transport.
[[State]]为"closed",则在 为 transport 排队一个网络任务后,解析 p,其值为当前连接的最新可用统计信息。实际收集统计的时间点为实现定义。 -
令 gatheredStats 为用于准确填充
WebTransportConnectionStats和WebTransportDatagramStats的 底层连接的统计数据列表。 -
为 transport 排队一个网络任务,运行下列步骤:
-
令 stats 为 新建 的
WebTransportConnectionStats对象。 -
令 datagramStats 为 新建 的
WebTransportDatagramStats对象。 -
将 stats["
datagrams"] 设为 datagramStats。 -
对于 stats 和 datagramStats 中代理欲公开的每个 字典成员 member,将 member 设为 gatheredStats 中对应的 条目。
-
解析 p,值为 stats。
-
-
-
返回 p。
-
exportKeyingMaterial(BufferSource label, optional BufferSource context)-
为唯一关联于此
WebTransport的 TLS 会话, 通过 TLS 会话密钥导出器 导出密钥材料。当调用
exportKeyingMaterial时,用户代理必须运行以下步骤:-
令 transport 为 this。
-
令 labelLength 为 label 的 字节长度。
-
如果 labelLength 超过 255,则返回 一个被拒绝的 promise,拒绝原因为
RangeError。 -
令 contextLength 为 0。
-
如果传入 context,则将 contextLength 设为 context 的 字节长度。
-
如果 contextLength 超过 255,则返回 一个被拒绝的 promise,拒绝原因为
RangeError。 -
令 p 为一个新的 promise。
-
并行运行以下步骤,但当 transport 的
[[State]]变为"closed"或"failed"时 中止,并且为 transport 排队一个网络任务, 拒绝 p,原因为InvalidStateError:-
令 keyingMaterial 为,根据 [WEB-TRANSPORT-OVERVIEW] 中第 4.1 节,使用 labelLength、label、contextLength 以及(如有)context 导出的 TLS 密钥材料。
-
-
返回 p。
-
createBidirectionalStream()-
创建一个用于发送的
WebTransportBidirectionalStream双向流对象。注意,仅创建该流时对端不会立即可见,直到该流被用来发送数据。注:在流被发送数据前,服务器不会感知该流。
当调用createBidirectionalStream时,用户代理必须运行以下步骤:-
如果 this.
[[State]]为"closed"或"failed", 则返回一个被拒绝的 promise,拒绝原因为InvalidStateError。 -
如果 sendGroup 不为 null,且 sendGroup.
[[Transport]]不等于 this,抛出InvalidStateError。 -
令 waitUntilAvailable 为
options的waitUntilAvailable。 -
令 p 为新 promise。
-
令 transport 为 this。
-
并行运行以下步骤,当 transport 的
[[State]]变为"closed"或"failed"时 中止 并为 transport 排队一个网络任务,拒绝 p,原因为InvalidStateError:-
令 streamId 为 transport.
[[Session]]的一个有效且唯一的新 stream ID(见 [QUIC] 第 19.11 节)。如果因资源耗尽而无法立即创建,可根据 waitUntilAvailable 等待;否则在 waitUntilAvailable 为 false 时, 排队网络任务,拒绝 p, 原因为QuotaExceededError。 -
令 internalStream 为使用 transport.
[[Session]]和 streamId 创建双向流结果。 -
为 transport 排队一个网络任务,运行下列步骤:
-
如果 transport.
[[State]]为"closed"或"failed", 拒绝 p,原因为InvalidStateError并中止这些步骤。 -
令 stream 为对 internalStream、transport、sendGroup 和 sendOrder 创建的
WebTransportBidirectionalStream。 -
解析 p,值为 stream。
-
-
-
返回 p。
-
createUnidirectionalStream()-
创建一个用于发送的
WebTransportSendStream单向流对象。注意,仅创建该流时服务器不会立即可见,直到该流被用来发送数据。注:在流被发送数据前,服务器不会感知该流。
当调用createUnidirectionalStream()方法时,用户代理必须运行以下步骤:-
如果 this.
[[State]]为"closed"或"failed", 返回一个被拒绝的 promise,拒绝原因为InvalidStateError。 -
如果 sendGroup 不为 null,且 sendGroup.
[[Transport]]不等于 this,抛出InvalidStateError。 -
令 waitUntilAvailable 为
options的waitUntilAvailable。 -
令 p 为新 promise。
-
令 transport 为 this。
-
并行运行以下步骤,当 transport 的
[[State]]变为"closed"或"failed"时 中止 并为 transport 排队一个网络任务,拒绝 p,原因为InvalidStateError:-
令 streamId 为 transport.
[[Session]]的有效且唯一的新 stream ID(见 [QUIC] 第 19.11 节)。如果因资源耗尽无法立即创建,根据 waitUntilAvailable 选择等待或直接 排队网络任务,拒绝 p,原因为QuotaExceededError。 -
令 internalStream 为通过 transport.
[[Session]]和 streamId 创建单向流的结果。 -
为 transport 排队一个网络任务,执行如下:
-
如果 transport.
[[State]]为"closed"或"failed", 拒绝 p,原因为InvalidStateError并中止步骤。 -
令 stream 为对 internalStream、transport、sendGroup、sendOrder 创建的
WebTransportSendStream。 -
解析 p,值为 stream。
-
-
-
返回 p。
-
createSendGroup()-
创建一个
WebTransportSendGroup。当调用createSendGroup()方法时,用户代理必须运行以下步骤:-
如果 this.
[[State]]为"closed"或"failed", 抛出InvalidStateError。 -
返回通过对 this 创建
WebTransportSendGroup的结果。
-
6.5. 过程
WebTransport
transport 并传入 error 及可选的 closeInfo,请执行以下步骤:
-
令 sendStreams 为 transport.
[[SendStreams]]的副本。 -
令 receiveStreams 为 transport.
[[ReceiveStreams]]的副本。 -
令 outgoingDatagramWritables 为 transport.
[[Datagrams]].[[Writables]]。 -
令 incomingDatagrams 为 transport.
[[Datagrams]].[[Readable]]。 -
令 ready 为 transport.
[[Ready]]。 -
令 closed 为 transport.
[[Closed]]。 -
令 incomingBidirectionalStreams 为 transport.
[[IncomingBidirectionalStreams]]。 -
令 incomingUnidirectionalStreams 为 transport.
[[IncomingUnidirectionalStreams]]。 -
将 transport.
[[SendStreams]]设为空的 集合。 -
将 transport.
[[ReceiveStreams]]设为空的 集合。 -
将 transport.
[[Datagrams]].[[OutgoingDatagramsQueue]]设为空的 队列。 -
将 transport.
[[Datagrams]].[[IncomingDatagramsQueue]]设为空的 队列。 -
如果给定 closeInfo,则将 transport.
[[State]]设为"closed"。 否则,将 transport.[[State]]设为"failed"。 -
对于 sendStreams 中每一个 stream,执行以下步骤:
-
如果 stream.
[[PendingOperation]]不为 null,拒绝 stream.[[PendingOperation]],原因为 error。 -
使流出错 stream, 原因为 error。
-
-
对于 receiveStreams 中每一个 stream, 使 stream 出错, 原因为 error。
注:脚本作者可以注入代码在 Promise 解析时同步运行。因此,从此处开始,不要再触碰 transport,因为它可能会被脚本不可预测地更改。 调用此过程的逻辑同样适用。
-
如果给定 closeInfo,则:
-
否则:
-
拒绝 closed,原因为 error。
-
将 closed.
[[PromiseIsHandled]]设为 true。 -
拒绝 ready,原因为 error。
-
将 ready.
[[PromiseIsHandled]]设为 true。 -
使 incomingBidirectionalStreams 出错,原因为 error。
-
使 incomingUnidirectionalStreams 出错,原因为 error。
-
对于 outgoingDatagramWritables 中的每一个 writable,使其出错,原因为 error。
-
使 incomingDatagrams 出错,原因为 error。
-
要排队一个网络任务,给定 WebTransport
transport 和一系列步骤 steps,请按以下步骤执行:
6.6. 并非由客户端发起的会话终止
WebTransport
transport 关联的 WebTransport session
被 terminated 时,可选地带有
code 和 reasonBytes,运行以下步骤:
-
为 transport 排队一个网络任务并运行以下步骤:
-
如果 transport.
[[State]]为"closed"或"failed",中止这些步骤。 -
令 error 为新创建的 WebTransportError,其
source为"session"。 -
令 closeInfo 为一个新的 WebTransportCloseInfo 对象。
-
如果提供了 code,则将 closeInfo 的
closeCode设为 code。 -
如果提供了 reasonBytes,则将 closeInfo 的
reason设为 reasonBytes 的 UTF-8 解码值。注: reasonBytes 不包含任何语言或方向元信息。 在展示该值时可以用 First-strong 启发式来判断方向。
-
清理 transport,并传入 error 和 closeInfo。
-
WebTransport
transport 的 底层连接 发生连接错误时,
运行以下步骤:
-
为 transport 排队一个网络任务并运行以下步骤:
-
如果 transport.
[[State]]为"closed"或"failed",中止这些步骤。 -
令 error 为新创建的 WebTransportError,其
source为"session"。 -
清理 transport,传入 error。
-
6.7. 上下文清理步骤
本规范将 上下文清理步骤
定义为以下步骤,传入
WebTransport
transport:
-
如果 transport.
[[State]]为"connected",则:-
将 transport.
[[State]]设为"failed"。 -
并行终止 transport.
[[Session]]。 -
排队一个网络任务,携带 transport,以运行以下步骤:
-
令 error 为新创建的
WebTransportError, 其source为"session"。 -
清理 transport,携带 error。
-
-
-
如果 transport.
[[State]]为"connecting",将 transport.[[State]]设为"failed"。这也需要在 worker 中完成。参见 #127 和 whatwg/html#6731。
6.8. 垃圾回收
当 WebTransport
对象的 [[State]]
为 "connecting" 时,如果
[[IncomingBidirectionalStreams]]、
[[IncomingUnidirectionalStreams]]、
任意
WebTransportReceiveStream,
或 [[Datagrams]].[[Readable]]
处于锁定状态,或 ready、
draining、
或 closed
promise 被监视时,禁止被垃圾回收。
当 WebTransport
对象的 [[State]]
为 "connected" 时,如果
[[IncomingBidirectionalStreams]]、
[[IncomingUnidirectionalStreams]]、
任意
WebTransportReceiveStream,
或 [[Datagrams]].[[Readable]]
处于锁定状态,或 draining
或 closed
promise 被监视时,禁止被垃圾回收。
当 WebTransport
对象的 [[State]]
为 "draining" 时,如果
[[IncomingBidirectionalStreams]]、
[[IncomingUnidirectionalStreams]]、
任意
WebTransportReceiveStream,
或 [[Datagrams]].[[Readable]]
处于锁定状态,或 closed
promise 被监视时,禁止被垃圾回收。
当 WebTransport
对象已建立 WebTransport
session 且有待发送到网络的数据排队(包括 [[Datagrams]].[[OutgoingDatagramsQueue]]
中的数据报)时,禁止被垃圾回收。
如果 WebTransport
对象在 底层连接
仍然开启的情况下被垃圾回收,用户代理必须以 Application Error Code 为 0 且 Application Error Message 为 ""
终止
WebTransport session。
6.9. 配置
dictionary {WebTransportHash required DOMString ;algorithm required BufferSource ; };value dictionary WebTransportOptions {boolean allowPooling =false ;boolean requireUnreliable =false ;sequence <WebTransportHash >serverCertificateHashes = [];WebTransportCongestionControl congestionControl = "default"; [EnforceRange ]unsigned short ?anticipatedConcurrentIncomingUnidirectionalStreams =null ; [EnforceRange ]unsigned short ?anticipatedConcurrentIncomingBidirectionalStreams =null ;sequence <DOMString >protocols = [];ReadableStreamType datagramsReadableType ; };enum {WebTransportCongestionControl ,"default" ,"throughput" , };"low-latency"
WebTransportOptions 是一组参数的字典,
用于决定如何建立并使用WebTransport 会话。
allowPooling,类型为 boolean,默认值为false-
当设置为 true 时,WebTransport session 可以被池化,即其 底层连接 可以与其他 WebTransport session 共享。
requireUnreliable, 类型为 boolean,默认值为false-
当设置为 true 时,如果无法建立 HTTP/3 connection,则 WebTransport session 不得在 HTTP/2 connection 上建立。
serverCertificateHashes, 类型为 sequence<WebTransportHash>,默认值为[]-
此选项仅支持使用独占连接(dedicated connections)的传输协议。 对于不支持此特性的传输协议,若该字段非空,将抛出
NotSupportedError异常。如支持且非空,用户代理只有在可以成功 验证证书哈希 并满足 自定义证书要求 时才认为服务器证书可信。用户代理会忽略任何使用未知
algorithm的哈希。若 为空,用户代理应采用与普通 fetch 操作一致的证书校验流程。此选项不能与
allowPooling一同使用。 congestionControl, 类型为 WebTransportCongestionControl, 默认值为"default"-
可选地指定应用偏好的拥塞控制算法(如偏好高吞吐量或低延迟),在通过此连接发送数据时供用户代理参考。
anticipatedConcurrentIncomingUnidirectionalStreams, 类型为 unsigned short,可为 null,默认值为null-
允许应用可选地声明其预期服务器将创建多少并发 传入单向流。用户代理初始必须允许来自服务器的至少 100 个 传入单向流。 若非 null,用户代理在与服务器协商时应尽量减少 RTT,可将
[[AnticipatedConcurrentIncomingUnidirectionalStreams]]纳入考虑。 anticipatedConcurrentIncomingBidirectionalStreams, 类型为 unsigned short,可为 null,默认值为null-
允许应用可选地声明其预期服务器将创建多少并发 双向流。用户代理必须初始允许服务器创建至少 100 个双向流。 若非 null,用户代理在与服务器协商时应尽量减少 RTT,可将
[[AnticipatedConcurrentIncomingBidirectionalStreams]]纳入考虑。 protocols,类型为 sequence<DOMString>,默认值为[]-
可选的应用层协议名称数组。应用层协议的选择以及是否告知客户端由服务器自行决定。如果未提供合适协议,服务器可能会拒绝请求。
datagramsReadableType, 类型为 ReadableStreamType-
可选,指定应用偏好使用 可读字节流 作为传入数据报的流类型。否则,默认使用 可读流。
注:可读流 与数据报语义兼容, 可读字节流则不适用。数据报是零字节或多个字节的独立消息,可乱序到达,并非无分割的字节流;空数据报会丢失,且
min会丢失消息边界。
-
令 cert 为 certificate,其表示为 [RFC5280] 中定义的证书消息的 DER 编码。
-
计算 cert 的 SHA-256 哈希并返回计算得到的值。
-
令 certificate 为 certificate chain 中的第一个证书(叶子证书)。
-
令 referenceHash 为使用 certificate计算证书哈希的结果。
-
对于 hashes 中的每个哈希 hash:
-
若 hash.
value非 null 且 hash.algorithm与 "sha-256" 为ASCII 不区分大小写匹配:-
令 hashValue 为 hash.
value所表示的字节序列。 -
若 hashValue 等于 referenceHash,则返回 true。
-
-
-
返回 false。
自定义证书要求如下:证书必须是 [RFC5280] 中定义的 X.509v3 证书;在 Subject Public Key 字段中使用的密钥必须为允许的公钥算法之一;当前时间必须位于 [RFC5280] 第 4.1.2.5 节所定义的证书有效期内;且有效期总长度不得超过两周。用户代理可以对证书施加额外的 实现自定义要求。
在 Subject Public Key Info 字段(以及因此在 TLS CertificateVerify 消息中)使用的允许的公钥算法的确切列表是实现自定义的;但它必须包含使用 secp256r1(NIST P-256)命名椭圆曲线组的 ECDSA(参见 [RFC3279] 第 2.3.5 节;[RFC8422])以提供可互操作的默认值。不得包含 RSA 密钥(参见 [RFC3279] 第 2.3.1 节)。
6.10.
WebTransportCloseInfo 字典
WebTransportCloseInfo 字典包含用于在终止WebTransport 会话时设置错误码和原因的信息。
dictionary WebTransportCloseInfo {unsigned long closeCode = 0;USVString reason = ""; };
该字典应有以下属性:
closeCode,类型为 unsigned long,默认值为0-
传递给对端的错误码。
reason,类型为 USVString,默认值为""-
关闭
WebTransport的原因。
6.11. WebTransportSendOptions 字典
WebTransportSendOptions是一个基本参数字典,它会影响
createUnidirectionalStream、
createBidirectionalStream
以及
createWritable
方法的行为。
dictionary WebTransportSendOptions {WebTransportSendGroup ?sendGroup =null ;long long sendOrder = 0; };
该字典应具有以下属性:
sendGroup, 类型为 WebTransportSendGroup, nullable, 默认为null-
一个可选的
WebTransportSendGroup,用于对创建的流进行分组,或为 null。 sendOrder, 类型为 long long, 默认为0-
一个发送顺序号,如果提供,则选择创建的流参与严格排序。 当前在严格排序的流上排队的字节将优先于当前在其他严格排序的流上排队的字节发送,这些流是使用较低的发送顺序号创建的。
如果未提供发送顺序号,则用户代理从中发送字节的顺序相对于其他流是实现定义的。但是,强烈建议用户代理在所有未被较低发送顺序号饿死的流之间公平地分配带宽。
注意: 这是发送方的数据优先级,不保证接收顺序。
6.12. WebTransportSendStreamOptions 字典
WebTransportSendStreamOptions是一个参数字典,它会影响由
WebTransportSendStream创建的
createUnidirectionalStream
和
createBidirectionalStream的行为。
dictionary WebTransportSendStreamOptions :WebTransportSendOptions {boolean waitUntilAvailable =false ; };
该字典应具有以下属性:
waitUntilAvailable, 类型为 boolean, 默认为false-
如果为 true,则
createUnidirectionalStream或createBidirectionalStream调用返回的 promise 将不会解决, 直到底层连接具有足够的流量控制信用额度来创建流,或者连接达到无法再创建传出流的状态。如果为 false,则如果在调用时没有可用的流量控制窗口,则将拒绝该 promise。
6.13.
WebTransportConnectionStats 字典
WebTransportConnectionStats 字典包含关于WebTransport 会话的底层连接之 WebTransport 特定统计信息。
Note: 当使用池化时,多个池化在同一connection上的WebTransport 会话都会收到相同的信息,即这些信息会在持有相同network partition key的池化sessions间披露。
Note: 任何不可用的统计项将在WebTransportConnectionStats
字典中缺失。
dictionary WebTransportConnectionStats {unsigned long long bytesSent ;unsigned long long bytesSentOverhead ;unsigned long long bytesAcknowledged ;unsigned long long packetsSent ;unsigned long long bytesLost ;unsigned long long packetsLost ;unsigned long long bytesReceived ;unsigned long long packetsReceived ;DOMHighResTimeStamp smoothedRtt ;DOMHighResTimeStamp rttVariation ;DOMHighResTimeStamp minRtt ;required WebTransportDatagramStats ;datagrams unsigned long long ?estimatedSendRate =null ;boolean atSendCapacity =false ; };
该字典应具有以下属性:
bytesSent,类型为 unsigned long long-
在底层连接上发送的有效载荷字节数,不包括任何帧开销或重传部分。
bytesSentOverhead, 类型为 unsigned long longbytesAcknowledged, 类型为 unsigned long long-
通过 QUIC 的 ACK 机制,在底层连接上被服务器确认收到的有效载荷字节数。不包括任何帧开销。
注:通常落后于
bytesSent,但由于丢包可能永久少于它。 packetsSent,类型为 unsigned long long-
在底层连接上发送的数据包数量,包括已确定丢失的包。
bytesLost,类型为 unsigned long long-
在底层连接上丢失的字节数(不会单调递增,因为被判定为丢失的包后来仍可能收到)。 不包括 UDP 或其他外部帧开销。
packetsLost,类型为 unsigned long long-
在底层连接上丢失的包数(不会单调递增,因为被判定为丢失的包后来仍可能收到)。
bytesReceived,类型为 unsigned long long-
在底层连接上接收的总字节数(包括流的重复数据)。不包括 UDP 或其他外部帧开销。
packetsReceived,类型为 unsigned long long-
在底层连接上接收的总数据包数量,包括不可处理的数据包。
smoothedRtt,类型为 DOMHighResTimeStamprttVariation,类型为 DOMHighResTimeStampminRtt,类型为 DOMHighResTimeStampestimatedSendRate, 类型为 unsigned long long,可为 null,默认值为null-
用户代理队列数据的预计发送速率,单位为比特/秒。该速率适用于所有共享同一 WebTransport session 的流和数据报,由拥塞控制算法(可能由
congestionControl选择)计算。该估算排除了帧开销,代表应用有效负载的发送速率。如无可用估算,成员值必须为null。即使前次有值,后续也可为null。 atSendCapacity,类型为 boolean,默认值为false-
为 false 时,
estimatedSendRate可能受应用限制,即应用实际发送远低于拥塞控制允许的数据量。在受应用限制期间,拥塞控制器可能无法准确估算可用网络容量。为 true 时,表示应用已按网络容量发送数据,此时
estimatedSendRate反映了应用可用的网络容量。当atSendCapacity为true时,estimatedSendRate体现上限。只要应用发送速率持续,该估值会随网络变化自动调整,但即使atSendCapacity为 true,estimatedSendRate也允许为null。
6.14.
WebTransportDatagramStats 字典
WebTransportDatagramStats 字典包括
有关 底层连接
上数据报传输的统计信息。
dictionary WebTransportDatagramStats {unsigned long long droppedIncoming ;unsigned long long expiredIncoming ;unsigned long long expiredOutgoing ;unsigned long long lostOutgoing ; };
该字典应具有以下属性:
droppedIncoming, 类型为 unsigned long longexpiredIncoming, 类型为 unsigned long long-
由于在被从
datagrams的readable读取前已超过incomingMaxAge而被丢弃的入站数据报数量。 expiredOutgoing, 类型为 unsigned long long-
排队等待发送的数据报,由于在能够发送前已超过
outgoingMaxAge而被丢弃的数量。 lostOutgoing, 类型为 unsigned long long
7. 接口 WebTransportSendStream
WebTransportSendStream
是一个 WritableStream
,用于提供出向流特性,可以用于 出向单向或 双向
WebTransport 流。
它是一个 WritableStream
,元素类型为 Uint8Array
,可写入以向服务器发送数据。
[Exposed =(Window ,Worker ),SecureContext ,Transferable ]interface :WebTransportSendStream WritableStream {attribute WebTransportSendGroup ?sendGroup ;attribute long long sendOrder ;Promise <WebTransportSendStreamStats >getStats ();WebTransportWriter getWriter (); };
WebTransportSendStream始终由创建过程创建。
WebTransportSendStream的传输步骤和传输接收步骤是那些
WritableStream。
7.1. 属性
sendGroup, 类型为 WebTransportSendGroup,可为 null-
getter 步骤如下:
-
返回 this 的
[[SendGroup]]。
setter 步骤,给定 value:
-
如果 value 非 null,且 value.
[[Transport]]不等于 this.[[Transport]], 抛出InvalidStateError。 -
将 this.
[[SendGroup]]设为 value。
-
sendOrder, 类型为 long long-
getter 步骤如下:
-
返回 this 的
[[SendOrder]]。
setter 步骤,给定 value:
-
将 this.
[[SendOrder]]设为 value。
-
7.2. 方法
getStats()-
收集该
WebTransportSendStream性能相关的统计信息, 并以异步方式报告结果。调用 getStats 时,用户代理必须按如下步骤执行:
-
令 p 为一个新的 promise。
-
按 并行 执行以下步骤:
-
令 gatheredStats 为专用于 this
WebTransportSendStream,用于准确填充WebTransportSendStreamStats字典成员的统计信息 列表。 -
为 transport 排队一个网络任务,以执行以下步骤:
-
令 stats 为一个 新的
WebTransportSendStreamStats对象。 -
对于用户代理希望暴露的 stats 的每个 成员 member,设置 member 为 gatheredStats 中对应的 条目。
-
-
-
返回 p。
-
getWriter()-
此方法的实现必须与继承自
getWriter的实现方式一致,区别在于不创建WritableStreamDefaultWriter, 而是要 创建 一个以 this 为参数的WebTransportWriter。
7.3. 内部插槽
WebTransportSendStream
拥有以下内部槽。
| 内部槽 | 描述 (非规范性) |
|---|---|
[[InternalStream]]
| 一个出站单向或双向 WebTransport 流。 |
[[PendingOperation]]
| 表示正在挂起写入或关闭操作的 promise,或为 null。 |
[[Transport]]
| 拥有此 WebTransport
的 WebTransportSendStream。
|
[[SendGroup]]
| 可选的 WebTransportSendGroup,
或 null。
|
[[SendOrder]]
| 可选的发送顺序号,默认值为 0。 |
[[AtomicWriteRequests]]
| promise 的有序集合, 用于追踪在底层 sink 队列中要原子提交的写入请求子集。 |
[[BytesWritten]]
| 已经写入流的字节数。 |
[[CommittedOffset]]
| 流中的偏移量,记录即使在流中止发送时也会被交付给对端的字节数; 参见 [RELIABLE-RESET]。 |
7.4. 过程
要创建
一个WebTransportSendStream,
使用一个出向单向或双向
WebTransport 流
internalStream、一个WebTransport
transport、sendGroup和sendOrder,请执行以下步骤:
-
设stream为一个新的
WebTransportSendStream,具有:[[InternalStream]]-
internalStream
[[PendingOperation]]-
null
[[Transport]]-
transport
[[SendGroup]]-
sendGroup
[[SendOrder]]-
sendOrder
[[AtomicWriteRequests]]-
一个空的 ordered set,其元素是 promise。
[[BytesWritten]]-
0
[[CommittedOffset]]-
0
-
设writeAlgorithm为一个动作,该动作将chunk写入到stream,给定chunk。
-
设closeAlgorithm为一个动作,该动作关闭stream。
-
设abortAlgorithm为一个动作,该动作使用reason中止stream,给定reason。
-
设置stream,其中writeAlgorithm设置为writeAlgorithm,closeAlgorithm设置为closeAlgorithm, abortAlgorithm设置为abortAlgorithm。
-
设abortSignal为stream的[[controller]].[[abortController]].[[signal]]。
-
将以下步骤添加到abortSignal。
-
设pendingOperation为stream的
[[PendingOperation]]。 -
如果pendingOperation为 null,则中止这些步骤。
-
将stream的
[[PendingOperation]]设置为 null。 -
设reason为abortSignal的中止原因。
-
设promise为中止流与reason的结果。
-
-
将stream附加到transport的
[[SendStreams]]。 -
返回stream。
WebTransportSendStream
stream,执行以下步骤:
-
令 transport 为 stream.
[[Transport]]。 -
如果 chunk 不是
BufferSource, 返回 一个拒绝的 promise,错误为TypeError。 -
令 promise 为新建的 promise。
-
令 bytes 为 chunk 所表示的 字节序列的副本。
-
将 stream.
[[PendingOperation]]设为 promise。 -
令 inFlightWriteRequest 为 stream.inFlightWriteRequest。
-
如果 stream.
[[AtomicWriteRequests]]包含 inFlightWriteRequest,则令 atomic 为 true,否则为 false。 -
并行执行以下步骤:
-
如果 atomic 为 true 且当前 流控窗口不足以完整发送 bytes, 则终止后续步骤,并队列网络任务,传入 transport,执行:
-
将 stream.
[[PendingOperation]]设为 null。
-
-
否则,发送 bytes 到 stream.
[[InternalStream]], 并等待操作完成。 此发送可能与前面排队好的流和数据报的发送交错进行,也可能与尚未排队将要发送的数据交错进行。用户代理可以有缓冲区提升传输性能。此缓冲区应有固定上限,以便向
WebTransportSendStream的使用者传递背压信息。该发送操作在以下情况下必须饿死(starve):直到同组中所有
[[SendGroup]]且[[SendOrder]]值更高 且未出错且未被 流控阻塞的stream所有已排队字节都被发送后,当前流才能发送。此处的 stream.
[[SendOrder]]可被并行访问,用户代理应该监听这些值的动态变化,具体细节为 实现自定。注意: 重传的发送顺序为 实现自定,但强烈建议用户代理优先重传
[[SendOrder]]值较高的数据。除此之外,除非受 流控 或 错误影响,否则该发送不可被饿死。
用户代理应尽量公平分配带宽给所有未饿死的流。
注意: 这里所说的公平由 实现自定。
-
如果上一步因网络错误失败,则中止后续步骤。
注意: 此处不会拒绝 promise,因网络错误会在其他地方处理,相关步骤会拒绝 stream.
[[PendingOperation]]。 -
否则,队列网络任务,传入 transport,执行:
-
将 stream.
[[PendingOperation]]设为 null。 -
将 bytes 的长度加到 stream.
[[BytesWritten]]上。 -
如果 stream.
[[AtomicWriteRequests]]包含 inFlightWriteRequest, 移除 inFlightWriteRequest。 -
resolve promise,值为 undefined。
-
-
-
返回 promise。
注意: 本算法返回的 promise(或 write(chunk))
被 确认(fulfilled) 并不意味着该 chunk 已被服务器确认(acked),
很可能只是被加入了缓冲区。要确保 chunk 已送达服务器,服务器还需要应用层自己的确认消息。
WebTransportSendStream
stream,执行以下步骤:
-
令 transport 为 stream.
[[Transport]]。 -
令 promise 为新建的 promise。
-
移除 stream 从 transport.
[[SendStreams]]中。 -
将 stream.
[[PendingOperation]]设为 promise。 -
并行执行以下步骤:
-
发送 FIN 到 stream.
[[InternalStream]], 并等待操作完成。 -
等待 stream.
[[InternalStream]]进入 "all data committed" 状态。[QUIC] -
队列网络任务,传入 transport,执行:
-
将 stream.
[[PendingOperation]]设为 null。 -
resolve promise,值为 undefined。
-
-
-
返回 promise。
WebTransportSendStream
stream,并传入 reason,执行以下步骤:
-
令 transport 为 stream.
[[Transport]]。 -
令 promise 为新建的 promise。
-
令 code 为 0。
-
移除 stream 从 transport.
[[SendStreams]]中。 -
如果 reason 是
WebTransportError且 reason.[[StreamErrorCode]]不为 null,则将 code 设为 reason.[[StreamErrorCode]]。 -
如果 code < 0,则置为 0。
-
如果 code > 4294967295,则置为 4294967295。
-
令 committedOffset 为 stream.
[[CommittedOffset]]。注意: code 的有效取值为 0 到 4294967295(含)。如果 底层连接 使用 HTTP/3,code 会按 [WEB-TRANSPORT-HTTP3] 描述编码到 [0x52e4a40fa8db, 0x52e5ac983162] 区间。
-
并行执行以下步骤:
-
中止发送 stream.
[[InternalStream]],传入 code 和 committedOffset。
-
-
返回 promise。
WebTransportSendStream
stream,执行以下步骤:
-
令 writeRequests 为 stream.writeRequests。
-
令 requestsToAbort 为 stream.
[[AtomicWriteRequests]]。 -
如果 writeRequests 包含 存在于 requestsToAbort 之外的 promise, 则报错 stream,错误为
AbortError,并中止这些步骤。 -
对于 requestsToAbort 中的每个 promise, 拒绝 promise,错误为
AbortError。
7.5. 接收来自服务器的中止信号
WebTransportSendStream
stream 关联的 WebTransport stream
从服务器收到 receiving aborted 信号时,执行以下步骤:
-
令 transport 为 stream.
[[Transport]]。 -
令 code 为附加在 receiving aborted 信号上的应用协议错误码。
Note: code 的有效取值为 0 到 4294967295(含)之间的整数。若底层连接使用 HTTP/3,则该代码将被编码为 [0x52e4a40fa8db, 0x52e5ac983162] 范围内的数字,如 [WEB-TRANSPORT-HTTP3] 所述。
-
Queue a network task,携带 transport,以运行以下步骤:
-
如果 transport.
[[State]]为"closed"或"failed",则中止这些步骤。 -
Remove stream 自 transport.
[[SendStreams]]。 -
令 error 为新创建的
WebTransportError, 其source为"stream",且streamErrorCode为 code。 -
如果 stream.
[[PendingOperation]]非 null,则以 error 拒绝 stream.[[PendingOperation]]。 -
Error stream,并携带 error。
-
7.6. WebTransportSendStreamStats 字典
WebTransportSendStreamStats 字典
包括一个 WebTransportSendStream
的特定统计信息。
dictionary WebTransportSendStreamStats {unsigned long long bytesWritten ;unsigned long long bytesSent ;unsigned long long bytesAcknowledged ; };
该字典应具有以下属性:
bytesWritten, 类型为 unsigned long long-
应用已经成功写入此
WebTransportSendStream的总字节数。该数值只会递增。 bytesSent, 类型为 unsigned long long-
对应用写入此
WebTransportSendStream的字节有多少至少发送过一次的进度指标。该数值只会递增,且始终小于等于bytesWritten。注意: 此为仅本流应用层数据的发送进度,不包含任何网络开销。
bytesAcknowledged, 类型为 unsigned long long-
对应用写入此
WebTransportSendStream的字节已被服务端通过 QUIC 的 ACK 机制确认接收的进度指标。仅统计第一个未确认字节之前的所有连续字节。该数值只会递增,且始终小于等于bytesSent。注意: 当连接为 HTTP/2 时,该值会与
bytesSent保持一致。
8. 接口
WebTransportSendGroup
WebTransportSendGroup
是一个可选的组织对象,用于跟踪分布在许多个单独
(通常是 严格排序的)
WebTransportSendStream
上的数据传输。
WebTransportSendStream
可以在创建时或通过赋值其 sendGroup 属性,被归为最多一个 分组到一个
WebTransportSendGroup。默认情况下,它们是
未分组的。
用户代理在为发送 WebTransportSendStream
分配带宽时,
会将 WebTransportSendGroup
视为同等。
每个 WebTransportSendGroup
还会为评估 sendOrder
编号建立一个独立的数字空间。
[Exposed =(Window ,Worker ),SecureContext ]interface {WebTransportSendGroup Promise <WebTransportSendStreamStats >getStats (); };
一个 WebTransportSendGroup
总是通过 创建过程生成。
8.1. 方法
getStats()-
聚合属于 该 sendGroup 下所有
WebTransportSendStream的统计信息,并以异步方式报告结果。调用 getStats 时,用户代理必须运行如下步骤:
-
令 p 为一个新的 promise。
-
令 streams 为所有
WebTransportSendStream, 其[[SendGroup]]等于 this。 -
如下 并行运行:
-
令 gatheredStats 为 streams 中所有流的聚合统计信息 列表, 用于准确填充
WebTransportSendStreamStats的字典成员。 -
为 transport 排队一个网络任务,以运行如下步骤:
-
令 stats 为一个 新的
WebTransportSendStreamStats对象。 -
对于用户代理希望暴露的 stats 的每个 成员 member, 设置 member 为 gatheredStats 中对应的条目。
-
-
-
返回 p。
-
8.2. 内部槽
一个 WebTransportSendGroup
拥有以下内部槽。
| 内部槽 | 描述 (非规范性) |
|---|---|
[[Transport]]
| 拥有此 WebTransport
对象的 WebTransportSendGroup。
|
8.3. 过程
要创建
WebTransportSendGroup,
并指定 WebTransport
transport,请执行以下步骤:
-
令 sendGroup 为 新建的
WebTransportSendGroup, 其中:[[Transport]]-
transport
-
返回 sendGroup。
9. 接口 WebTransportReceiveStream
WebTransportReceiveStream
是一个 ReadableStream
,用于提供入向流特性,支持 入向单向或 双向
WebTransport 流。
它是一个 ReadableStream
,元素类型为 Uint8Array
,可读取以消费从服务器接收到的数据。WebTransportReceiveStream
是一个 可读字节流,
因此允许消费者使用 BYOB reader 以及 默认 reader。
[Exposed =(Window ,Worker ),SecureContext ,Transferable ]interface :WebTransportReceiveStream ReadableStream {Promise <WebTransportReceiveStreamStats >getStats (); };
一个 WebTransportReceiveStream
总是通过 创建过程生成。
WebTransportReceiveStream
的 传输步骤 和
接收传输步骤
与 ReadableStream 的步骤一致。
9.1. 方法
getStats()-
收集此
WebTransportReceiveStream的性能相关专用统计信息,并以异步方式报告结果。当调用 getStats 时,用户代理必须运行以下步骤:
-
令 p 为一个新的 promise。
-
以并行方式运行以下步骤:
-
令 gatheredStats 为针对 this
WebTransportReceiveStream的统计信息列表,用于准确填充WebTransportReceiveStreamStats的字典成员。 -
排队一个网络任务,携带 transport,以运行以下步骤:
-
-
返回 p。
-
9.2. 内部槽
WebTransportReceiveStream
拥有以下内部槽。
| 内部槽 | 描述(非规范性) |
|---|---|
[[InternalStream]]
| 一个入向单向或双向 WebTransport 流。 |
[[Transport]]
| 拥有此 WebTransport
对象的 WebTransportReceiveStream。
|
9.3. 过程
要创建一个
WebTransportReceiveStream,
在具有一个 入站单向或 双向的 WebTransport
stream
internalStream 和一个 WebTransport
transport 的情况下,执行以下步骤:
-
令 stream 为一个新建的
WebTransportReceiveStream,其包含:[[InternalStream]]-
internalStream
[[Transport]]-
transport
-
令 pullAlgorithm 为一个操作,用于从 stream中拉取字节。
-
令 cancelAlgorithm 为一个操作,给定 reason,用于以 reason取消 stream。
-
以字节读取支持进行设置 stream,其中 pullAlgorithm 设为 pullAlgorithm,且 cancelAlgorithm 设为 cancelAlgorithm。
-
将 stream 追加到 transport.
[[ReceiveStreams]]。 -
返回 stream。
要从一个 WebTransportReceiveStream
stream中拉取字节,执行以下步骤。
-
令 transport 为 stream.
[[Transport]]。 -
令 internalStream 为 stream.
[[InternalStream]]。 -
令 promise 为一个新的 promise。
-
令 buffer、offset 和 maxBytes 为 null。
-
如果 stream 的用于 stream 的当前 BYOB 请求视图不为 null:
-
将 offset 设为 stream 的当前 BYOB 请求视图.[[ByteOffset]]。
-
将 maxBytes 设为 stream 的当前 BYOB 请求视图的 字节长度。
-
将 buffer 设为 stream 的当前 BYOB 请求视图的 底层缓冲区。
-
-
否则:
-
将 offset 设为 0。
-
将 maxBytes 设为一个实现自定义大小。
-
将 buffer 设为一个新建的
ArrayBuffer, 大小为 maxBytes。如果分配该ArrayBuffer失败,返回一个被拒绝的 promise,携带RangeError。
-
-
以并行方式运行以下步骤:
-
将字节写入从 internalStream中读取到 buffer中,偏移为 offset,最多 maxBytes 字节。等待直到至少读取到一个字节或接收到 FIN。令 read 为已读取的字节数,令 hasReceivedFIN 表示是否伴随 FIN。
用户代理可以具有一个缓冲区以提升传输性能。该缓冲区应具有固定的上限,以将背压信息传递到服务器。
Note: 该操作可能在未填满整个 buffer 时返回。
-
如果前一步失败,则中止剩余步骤。
Note: 我们在此不拒绝 promise,因为我们在其他地方处理网络错误,而那些步骤会使 stream 出错,从而拒绝任何等待此次拉取的读取请求。
-
排队一个网络任务,携带 transport,以运行以下步骤:
Note: 如果上述缓冲区在运行此过程的事件循环中可用,则以下步骤可能会立即运行。
-
如果 read > 0:
-
将 view 设为一个新的
Uint8Array, 以 buffer、offset 和 read 构造。 -
入队 view 到 stream。
-
-
如果 hasReceivedFIN 为 true:
-
从 transport.
[[ReceiveStreams]]中移除 stream。 -
关闭 stream。
-
-
解析 promise 为 undefined。
-
-
-
返回 promise。
要以 reason取消一个 WebTransportReceiveStream
stream,执行以下步骤。
-
令 transport 为 stream.
[[Transport]]。 -
令 internalStream 为 stream.
[[InternalStream]]。 -
令 promise 为一个新的 promise。
-
令 code 为 0。
-
如果 reason 是一个
WebTransportError且 reason.[[StreamErrorCode]]不为 null,则将 code 设为 reason.[[StreamErrorCode]]。 -
如果 code < 0,则将 code 设为 0。
-
如果 code > 4294967295,则将 code 设为 4294967295。
Note: code 的有效取值为 0 到 4294967295(含)。如果底层连接使用 HTTP/3,则该代码将被编码为 [0x52e4a40fa8db, 0x52e5ac983162] 范围内的数字,如 [WEB-TRANSPORT-HTTP3] 所述。
-
从 transport.
[[SendStreams]]中移除 stream。 -
以并行方式运行以下步骤:
-
返回 promise。
9.4. 接收来自服务器的发送中止信号
WebTransportReceiveStream
stream 从服务器收到
sending aborted 信号时,执行以下步骤:
-
令 transport 为 stream 的
[[Transport]]。 -
令 code 为附加在 sending aborted 信号上的应用协议错误码。
Note: code 的有效取值为 0 到 4294967295(含)。如果 underlying connection 使用 HTTP/3,则该代码将被编码为 [0x52e4a40fa8db, 0x52e5ac983162] 范围内的数字,如 [WEB-TRANSPORT-HTTP3] 所述。
-
Queue a network task,携带 transport 以运行以下步骤:
-
如果 transport 的
[[State]]为"closed"或"failed",则中止这些步骤。 -
Remove 将 stream 从 transport 的
[[ReceiveStreams]]中移除。 -
令 error 为新创建的
WebTransportError, 其source为"stream",且streamErrorCode为 code。 -
Error 以 error 令 stream 出错。
-
9.5. WebTransportReceiveStreamStats 字典
WebTransportReceiveStreamStats 字典
包括一个 WebTransportReceiveStream
的特定统计信息。
dictionary WebTransportReceiveStreamStats {unsigned long long bytesReceived ;unsigned long long bytesRead ; };
字典应具有以下属性:
bytesReceived, 类型为 unsigned long long-
用于指示服务端应用发送到此
WebTransportReceiveStream的字节中,已成功接收的进度。 只统计第一个缺失字节之前的所有连续字节。该数值只会递增。注意: 仅为单条流中接收到的应用层数据进度,不包括任何网络开销。
bytesRead, 类型为 unsigned long long-
应用已从此
WebTransportReceiveStream成功读取的字节总数。该数值只会递增,且始终小于等于bytesReceived。
10. 接口 WebTransportBidirectionalStream
[Exposed =(Window ,Worker ),SecureContext ]interface {WebTransportBidirectionalStream readonly attribute WebTransportReceiveStream readable ;readonly attribute WebTransportSendStream writable ; };
10.1. 内部插槽
一个 WebTransportBidirectionalStream
具有以下内部槽。
| 内部槽 | 描述 (非规范性) |
|---|---|
[[Readable]]
| 一个 WebTransportReceiveStream。
|
[[Writable]]
| 一个 WebTransportSendStream。
|
[[Transport]]
| 拥有此 WebTransport
对象的 WebTransportBidirectionalStream。
|
10.2. 属性
readable, 类型为 WebTransportReceiveStream,只读-
getter 步骤为返回 this 的
[[Readable]]。 writable, 类型为 WebTransportSendStream,只读-
getter 步骤为返回 this 的
[[Writable]]。
10.3. 过程
WebTransportBidirectionalStream,
使用一个
双向
WebTransport stream internalStream、一个 WebTransport
对象 transport,以及一个 sendOrder,执行以下步骤。
-
令 readable 为创建一个
WebTransportReceiveStream的结果,给定 internalStream 和 transport。 -
令 writable 为创建一个
WebTransportSendStream的结果,给定 internalStream、transport,以及 sendOrder。 -
令 stream 为一个新建的
WebTransportBidirectionalStream,其包含:[[Readable]]-
readable
[[Writable]]-
writable
[[Transport]]-
transport
-
返回 stream。
11.
WebTransportWriter 接口
WebTransportWriter
是 WritableStreamDefaultWriter
的子类,添加了两个方法。
一个 WebTransportWriter
总是通过 创建
过程生成。
[Exposed=*,SecureContext ]interface :WebTransportWriter WritableStreamDefaultWriter {Promise <undefined >atomicWrite (optional any );chunk undefined commit (); };
11.1. 方法
atomicWrite(chunk)-
atomicWrite方法会拒绝无法在发送时当前的流量控制窗口内完整发送的 chunk。此行为旨在满足对流量控制死锁敏感的特定事务应用程序 ([RFC9308] 第4.4节)。注意:
atomicWrite可能在发送部分数据后仍然拒绝。虽然它在流量控制方面提供了原子性,但其他错误可能仍会发生。atomicWrite无法防止数据在多个数据包之间拆分或与其他数据交错。只有发送者才知道如果atomicWrite因缺乏可用流量控制信用而失败。注意: 原子写操作在排队到非原子写操作之后仍可能阻塞。如果原子写操作被拒绝,则此刻排队在其后的所有内容都将被拒绝。任何以这种方式被拒绝的非原子写操作将错误流。因此,建议应用程序始终等待原子写操作完成。
当调用
atomicWrite时,用户代理必须执行以下步骤:-
让 p 为在
write(chunk)上调用WritableStreamDefaultWriter的结果,并传递 chunk。 -
附加 p 到 stream.
[[AtomicWriteRequests]]。 -
返回对 p 的结果进行反应 (响应),并执行以下步骤:
-
如果 stream.
[[AtomicWriteRequests]]包含 p, 移除 p。 -
如果 p 因原因 r 被拒绝,则返回 一个被拒绝的 promise,理由为 r。
-
返回 undefined。
-
-
commit()-
commit方法会将流的[[CommittedOffset]]更新为已写入该流的字节数 ([[BytesWritten]])。 这样可以确保这些字节能够可靠地传递给对端,即使写入被中止,导致流中止发送。 该机制参见 [RELIABLE-RESET]。注意: 这无法保证连接失败时的数据可达,仅能保证当流中止发送时的可靠传递。
当为 stream 调用
commit时,用户代理必须执行以下步骤:-
将 transport 设为 stream.
[[Transport]]。 -
将 stream.
[[CommittedOffset]]设置为 stream.[[BytesWritten]]的值。
-
11.2. 过程
要创建一个
WebTransportWriter,
使用一个 WebTransportSendStream
stream,执行以下步骤:
-
令 writer 为一个新建的
WebTransportWriter。 -
运行 new WritableStreamDefaultWriter(stream) 构造步骤,其中将 writer 作为 this,stream 作为构造参数。
-
返回 writer。
12.
WebTransportError 接口
WebTransportError 是 DOMException
的子类,表示:
-
来自服务器或网络的错误,或
-
客户端发起的中止操作的原因。
[Exposed =(Window ,Worker ),Serializable ,SecureContext ]interface WebTransportError :DOMException {constructor (optional DOMString = "",message optional WebTransportErrorOptions = {});options readonly attribute WebTransportErrorSource source ;readonly attribute unsigned long ?streamErrorCode ; };dictionary {WebTransportErrorOptions WebTransportErrorSource = "stream"; [source Clamp ]unsigned long ?=streamErrorCode null ; };enum {WebTransportErrorSource ,"stream" , };"session"
12.1. 内部插槽
一个 WebTransportError
具有以下内部槽。
| 内部槽 | 描述 (非规范性) |
|---|---|
[[Source]]
| 一个 WebTransportErrorSource
,指示此错误的来源。
|
[[StreamErrorCode]]
| 此错误的应用协议错误代码,或 null。 |
12.2. 构造函数
new WebTransportError(message, options)
的构造步骤如下:
-
将 this 的 name 设为
"WebTransportError"。 -
将 this 的 message 设为 message。
-
将 this 的内部槽设置如下:
[[Source]]-
options.
source [[StreamErrorCode]]-
options.
streamErrorCode
12.3. 属性
source,类型为 WebTransportErrorSource,只读-
getter 步骤为返回 this 的
[[Source]]。 streamErrorCode,类型为 unsigned long,只读,可为 null-
getter 步骤为返回 this 的
[[StreamErrorCode]]。
12.4. 序列化
WebTransportError
对象是 可序列化对象。
它们的 序列化步骤,给定 value 和 serialized,如下:
-
运行
DOMException的 序列化步骤,给定 value 和 serialized。 -
将 serialized.
[[Source]]设置为 value.[[Source]]。 -
将 serialized.
[[StreamErrorCode]]设置为 value.[[StreamErrorCode]]。
它们的 反序列化步骤,给定 serialized 和 value,如下:
-
运行
DOMException的 反序列化步骤,给定 serialized 和 value。 -
将 value.
[[Source]]设置为 serialized.[[Source]]。 -
将 value.
[[StreamErrorCode]]设置为 serialized.[[StreamErrorCode]]。
13. 协议映射
此部分为非规范性内容。
本节描述了本规范中定义的方法的底层协议行为,使用 [WEB-TRANSPORT-OVERVIEW]。 由于缓冲,因果关系可能不会立即显现。
| WebTransport 协议行为 | API 效果 |
|---|---|
| 会话 耗尽 | 等待 wt.draining
|
如果 底层连接 使用 HTTP/3,则适用于从 [WEB-TRANSPORT-HTTP3] 的以下协议行为。
在 WebTransportError
错误中的应用 streamErrorCode
转换为 httpErrorCode,反之亦然,如 [WEB-TRANSPORT-HTTP3]
第4.3节 中所述。
| API 方法 | QUIC 协议行为 |
|---|---|
writable.abort(error)
| 中止发送到 STREAM,带 httpErrorCode 和与该 [[CommittedOffset]]
对应的 offset,以及任何流头部;参见 [RELIABLE-RESET]
|
writable.close()
| 发送 STREAM 并设置 FIN 位 |
writable.getWriter().write(chunk)()
| 发送 STREAM |
writable.getWriter().close()
| 发送 STREAM 并设置 FIN 位 |
writable.getWriter().abort(error)
| 中止发送到 STREAM,带 httpErrorCode 和与该 [[CommittedOffset]]
对应的 offset,以及任何流头部;参见 [RELIABLE-RESET]
|
readable.cancel(error)
| 中止接收 STREAM,带 httpErrorCode |
readable.getReader().cancel(error)
| 中止接收 STREAM,带 httpErrorCode |
wt.close(closeInfo)
| 终止会话,带 closeInfo |
| QUIC 协议行为 | API 效果 |
|---|---|
| 接收 STOP_SENDING,带 httpErrorCode | 报错 writable
,错误为 streamErrorCode
|
| 接收 STREAM | (await
readable.getReader().read()).value
|
| 接收 STREAM 并设置 FIN 位 | (await
readable.getReader().read()).done
|
| 接收 RESET_STREAM,带 httpErrorCode | 报错 readable
,错误为 streamErrorCode
|
| 会话正常终止,带 closeInfo | (await wt.closed).closeInfo,
并且
报错所有未关闭的流
|
| 网络错误 | (await wt.closed)
拒绝,并且
报错所有未关闭的流
|
注意: 如 [QUIC] RFC9000 §3.2 所述, 收到 RESET_STREAM 帧或 RESET_STREAM_AT 帧([RELIABLE-RESET]) 并不总是会通知应用层。 重置信号可以立即触发,导致流数据传递被中断,未消费的数据会被丢弃。 但协议不要求必须立即通知,信号可能会延迟,以便传递 RESET_STREAM_AT 帧中的 Reliable Size 字段所指示的数据。 如果流数据已完整接收但尚未被应用读取,则发送中止信号可被抑制。 WebTransport 始终使用 RESET_STREAM_AT 帧,以确保流头部能够可靠传递; 参见 §4.1 和 §4.2 [WEB-TRANSPORT-HTTP3]。
| HTTP/3 协议行为 | API 效果 |
|---|---|
| 会话draining | await wt.draining
|
如果底层连接使用 HTTP/2,则适用 [WEB-TRANSPORT-HTTP2] 中的协议行为。注意,与 HTTP/3 不同,流错误码不需要转换为 HTTP 错误码,反之亦然。
| API 方法 | HTTP/2 协议行为 |
|---|---|
writable.abort(error)
| 中止发送到 WT_STREAM,带 error |
writable.close()
| 发送 WT_STREAM 并设置 FIN 位 |
writable.getWriter().write()
| 发送 WT_STREAM |
writable.getWriter().close()
| 发送 WT_STREAM 并设置 FIN 位 |
writable.getWriter().abort(error)
| 中止发送到 WT_STREAM,带 error |
readable.cancel(error)
| 中止接收 WT_STREAM,带 error |
readable.getReader().cancel(error)
| 中止接收 WT_STREAM,带 error |
wt.close(closeInfo)
| 终止会话,带 closeInfo |
| HTTP/2 协议行为 | API 效果 |
|---|---|
| 接收 WT_STOP_SENDING,带 error | 报错 writable
,错误为 streamErrorCode
|
| 接收 WT_STREAM | (await
readable.getReader().read()).value
|
| 接收 WT_STREAM 并设置 FIN 位 | (await
readable.getReader().read()).done
|
| 接收 WT_RESET_STREAM,带 error | 报错 readable
,错误为 streamErrorCode
|
| 会话正常终止,带 closeInfo | (await wt.closed).closeInfo,
并且
报错所有未关闭的流
|
| 网络错误 | (await wt.closed)
拒绝,并且
报错所有未关闭的流
|
| 会话draining | await wt.draining
|
14. 隐私与安全注意事项
此部分为非规范性内容;它未指定任何新的行为,而是总结了规范其他部分中已经存在的信息。
14.1. 通信机密性
通信正在进行的事实无法对能够观察网络的对手隐瞒,因此这必须被视为公开信息。
本文件中描述的所有传输协议都使用 TLS [RFC8446] 或语义上等效的协议,从而提供了 TLS 的所有安全属性,包括流量的机密性和完整性。基于 HTTP 的 WebTransport 使用与出站 HTTP 请求相同的证书验证机制,因此依赖于相同的公钥基础设施来验证远程服务器的身份。在 WebTransport 中,证书验证错误是致命的;没有允许绕过证书验证的中间页面。
14.2. 状态持久性
WebTransport 本身不会创建任何新的唯一标识符或持久存储状态的新方法,也不会自动向服务器公开任何现有的持久状态。例如,[WEB-TRANSPORT-HTTP3] 和[WEB-TRANSPORT-HTTP2] 都不发送 Cookies,也不支持 HTTP 身份验证或缓存失效机制。由于它们确实使用 TLS,它们继承了 TLS 的持久状态,例如 TLS 会话票据,这虽然对被动网络观察者不可见,但可能会被服务器用于关联来自同一客户端的不同连接。
14.3. 协议安全性
WebTransport 强加了一组要求,如 [WEB-TRANSPORT-OVERVIEW] 中所述,包括:
-
确保远程服务器知晓正在使用 WebTransport 协议,并确认远程服务器愿意使用 WebTransport 协议。[WEB-TRANSPORT-HTTP3] 通过 ALPN 与 [RFC7301] 的组合、HTTP/3 的设置以及
:protocol的 伪首部字段 来标识 WebTransport 协议。[WEB-TRANSPORT-HTTP2] 则通过 ALPN、HTTP/2 的设置以及:protocol的 伪首部字段 来标识 WebTransport 协议。 -
允许服务器根据发起传输会话的资源的来源来过滤连接。会话建立请求中的
Origin首部字段携带此信息。
协议安全相关的注意事项,请参见 安全注意事项章节, [WEB-TRANSPORT-OVERVIEW] 第 6 节, [WEB-TRANSPORT-HTTP3] 第 8 节,以及 [WEB-TRANSPORT-HTTP2] 第 9 节。
网络 API 通常可用于扫描本地网络以查找可用主机,因此可用于指纹识别和其他形式的攻击。WebTransport 遵循 WebSocket 方法 解决此问题: 直到端点被验证为 WebTransport 端点之前,具体的连接错误不会返回;因此,Web 应用程序无法区分不存在的端点和不愿意接受 Web 连接的端点。
14.4. 使用证书哈希进行身份验证
通常,用户代理通过验证所提供的 TLS 服务器证书的有效性与 URL 中的服务器名称 [RFC9525] 相比来对其自身与远程端点之间的 TLS 连接进行身份验证。这是通过将服务器证书链接到用户代理维护的信任锚之一来实现的;相关的信任锚负责对证书中的服务器名称进行身份验证。我们将此系统称为 Web PKI。
此 API 为 Web 应用程序提供了一种连接到远程网络端点的能力,该端点通过指定的服务器证书而不是其服务器名称进行身份验证。此机制使连接到难以获取长期证书的端点成为可能,包括那些本质上是短暂的主机(例如短期虚拟机),或不可公开路由的主机。由于此机制替代了基于 Web PKI 的单个连接身份验证,我们需要比较两者的安全属性。
只有在远程服务器拥有与指定证书的公钥相对应的私钥时,它才能成功执行 TLS 握手。API 使用其哈希值来标识证书。只要所使用的加密哈希函数具有第二原像抗性,这种方法才是安全的。本文档中唯一定义的函数是 SHA-256;API 提供了一种通过允许指定多个算法-哈希对来引入新哈希函数的方法。
需要注意的是,Web PKI 除了简单地为服务器名称建立信任链之外,还提供了额外的安全机制。其中之一是处理证书吊销。在使用的证书是短暂的情况下,这种机制没有必要。在其他情况下,Web 应用程序必须考虑证书哈希值的供应机制;例如,如果哈希值作为缓存的 HTTP 资源提供,则在相应证书因泄露而被轮换时需要使缓存失效。Web PKI 提供的另一个安全功能是针对密钥生成的某些问题的保障,例如拒绝具有已知弱密钥的证书;虽然本文档没有提供任何具体的指导,但浏览器可以作为实现定义的行为的一部分拒绝这些证书。
Web PKI 对证书实施了过期周期要求。此要求限制了潜在密钥泄露的范围;它还迫使服务器运营商设计支持并积极执行密钥轮换的系统。出于这个原因,WebTransport 对证书施加了类似的过期要求;由于证书预计是短暂或短期的,因此过期周期限制为两周。两周的限制是在尽可能低地设置过期限制以最大限度地减少密钥泄露的后果之间,以及保持其足够高以适应设备之间的时钟偏差,并降低客户端和服务器端同步证书的成本之间的平衡。
WebTransport API 允许应用程序一次指定多个证书哈希值,从而允许客户端在新证书推出期间接受多个证书。
与 WebRTC 中类似的机制不同,WebTransport 中的服务器证书哈希 API 不提供任何身份验证客户端的方法;客户端知道服务器证书是什么或如何联系它这一事实并不足够。应用程序如果需要,必须在带内建立客户端的身份。
14.5. 指纹识别与跟踪
此 API 使站点能够生成网络活动并密切观察此活动的效果。通过这种方式获取的信息可能是识别性的信息。
需要认识到其他 Web 平台 API(例如 fetch 和 [webrtc])提供了非常类似的网络功能。因此,添加 WebTransport 对隐私的不利影响微乎其微。本节中的注意事项同样适用于其他网络功能。
测量网络特性需要使用网络并测量该使用的效果,而这两者都由此 API 启用。WebTransport 为站点提供了向其选择的服务器生成网络活动并观察效果的能力。可以观察网络路径的稳定属性和网络使用的动态效果。
有关网络的信息可以通过服务器自己的网络堆栈直接获得,通过客户端消耗或传输数据的速率间接获得,或者作为由 API 提供的统计信息的一部分获得(参见 § 6.13 WebTransportConnectionStats Dictionary)。因此,对用户代理信息的限制并不是管理这些隐私风险的唯一机制。
14.5.1. 静态观察
站点可以观察用户代理与选定服务器之间的可用网络容量或往返时间(RTT)。当与其他跟踪矢量结合时,这些信息可能具有识别性。RTT 还可以揭示用户代理的物理位置,尤其是在可以从多个观察点进行多次测量的情况下。
尽管网络是共享的,但网络使用通常是零散的,这意味着站点通常可以观察未受争用或负载轻的网络路径的容量和往返时间。这些属性对于许多人来说是稳定的,因为他们的网络位置没有改变,网络瓶颈的位置--决定可用容量--可能靠近用户代理。
14.5.2. 共享网络
受争用的链接为站点提供了启用跨站点识别的机会,这可能会被用来执行未经授权的跟踪 [UNSANCTIONED-TRACKING]。 网络容量是有限的共享资源,因此用户代理同时访问不同站点可能会揭示每个站点呈现的身份之间的连接。
在一个站点上使用网络功能会减少其他站点可用的容量,可以使用网络 API 观察到这一点。网络使用和指标可能会动态变化,因此任何变化都可以实时观察到。这可能允许站点增加信心,即不同站点上的活动来自同一用户。
用户代理可以限制或降低对反馈机制(例如统计信息(§ 6.13 WebTransportConnectionStats Dictionary))的访问,针对不活跃或未获得焦点的站点(HTML § 6.6 Focus)。如所述,这并不能阻止服务器观察网络中的变化。
14.5.3. 池化会话
与共享网络场景类似,当会话在单个连接上池化时,一个会话的信息会受到另一个会话活动的影响。一个会话可以推断关于另一个会话活动的信息,例如另一个应用程序发送数据的速率。
使用共享连接已经允许服务器关联会话。使用 网络分区键 禁用池化,其中共享会话的使用可能启用不必要的跨站点识别。
15. 示例
15.1. 发送数据报缓冲区
此部分为非规范性内容。
可以通过使用
datagrams'
createWritable
方法以及生成的流的 writer 来发送数据报缓冲区。在以下示例中,仅当传输准备好发送时才发送数据报。
async function sendDatagrams( url, datagrams) { const wt= new WebTransport( url); const writable= wt. datagrams. createWritable(); const writer= writable. getWriter(); for ( const bytesof datagrams) { await writer. ready; writer. write( bytes). catch (() => {}); } await writer. close(); }
15.2. 以固定速率发送数据报
此部分为非规范性内容。
无论传输是否准备好发送,通过简单使用
datagrams'
createWritable
方法以及生成的流的 writer,而不等待 ready 属性即可以固定速率发送数据报。
// 每100毫秒发送数据报。 async function sendFixedRate( url, createDatagram, ms= 100 ) { const wt= new WebTransport( url); const writable= wt. datagrams. createWritable(); const writer= writable. getWriter(); const bytes= createDatagram(); setInterval(() => writer. write( bytes). catch (() => {}), ms); }
15.3. 接收数据报
此部分为非规范性内容。
可以通过从传输的
datagrams.readable
属性中读取来接收数据报。空值可能表示未能快速处理数据包。
async function receiveDatagrams( url) { const wt= new WebTransport( url); for await ( const datagramof wt. datagrams. readable) { // 处理数据报 } }
15.4. 使用 BYOB 读取器接收数据报
此部分为非规范性内容。
由于 datagrams
是可读字节流,你可以为它们获取一个
BYOB
读取器,
这样可以更精确地控制缓冲区分配,从而避免复制。下例将 datagram 读入一个 64 Kibibytes 的内存缓冲区中。
const wt= new WebTransport( url); for await ( const datagramof wt. datagrams. readable) { const reader= datagram. getReader({ mode: "byob" }); let array_buffer= new ArrayBuffer( 65536 ); const buffer= await readInto( array_buffer); } async function readInto( buffer) { let offset= 0 ; while ( offset< buffer. byteLength) { const { value: view, done} = await reader. read( new Uint8Array( buffer, offset, buffer. byteLength- offset)); buffer= view. buffer; if ( done) { break ; } offset+= view. byteLength; } return buffer; }
15.5. 发送流
此部分为非规范性内容。
可以通过使用
createUnidirectionalStream
函数以及生成的流的 writer 来发送数据作为单向流。
接收时不会保留写入的块边界,因为字节可能会在传输线上合并。因此建议应用程序提供自己的框架。
async function sendData( url, ... data) { const wt= new WebTransport( url); const writable= await wt. createUnidirectionalStream(); const writer= writable. getWriter(); for ( const bytesof data) { await writer. ready; writer. write( bytes). catch (() => {}); } await writer. close(); }
流规范 不建议 等待 write() 的 Promise。
编码也可以通过管道从一个 ReadableStream
进行,例如使用 TextEncoderStream。
async function sendText( url, readableStreamOfTextData) { const wt= new WebTransport( url); const writable= await wt. createUnidirectionalStream(); await readableStreamOfTextData. pipeThrough( new TextEncoderStream( "utf-8" )) . pipeTo( writable); }
15.6. 接收传入流
此部分为非规范性内容。
可以通过遍历
incomingUnidirectionalStreams
属性,然后通过遍历其块来消费每个 WebTransportReceiveStream
来读取传入流。
分块由用户代理决定,而不是发送方。
async function receiveData( url, processTheData) { const wt= new WebTransport( url); for await ( const readableof wt. incomingUnidirectionalStreams) { // 使用 IFFE 单独消费流,报告每个流的错误 (( async () => { try { for await ( const bytesof readable) { processTheData( bytes); } } catch ( e) { console. error( e); } })()); } }
解码也可以通过管道传输到新的 WritableStreams,例如使用
TextDecoderStream。
此示例假定文本输出不应交错,因此一次只读取一个流。
async function receiveText( url, createWritableStreamForTextData) { const wt= new WebTransport( url); for await ( const readableof wt. incomingUnidirectionalStreams) { // 顺序消费以避免输出交错,报告每个流的错误 try { await readable. pipeThrough( new TextDecoderStream( "utf-8" )) . pipeTo( createWritableStreamForTextData()); } catch ( e) { console. error( e); } } }
15.7. 使用 BYOB 读取器接收流
此部分为非规范性内容。
由于 WebTransportReceiveStream
是可读字节流,你可以为其获取一个
BYOB
reader,
这样可以更精确地控制缓冲区分配,以避免数据拷贝。下面的示例将 WebTransportReceiveStream
的前 1024 个字节读入一个内存缓冲区。
const wt= new WebTransport( url); const reader= wt. incomingUnidirectionalStreams. getReader(); const { value: recv_stream, done} = await reader. read(); const byob_reader= recv_stream. getReader({ mode: "byob" }); let array_buffer= new ArrayBuffer( 1024 ); const buffer= await readInto( array_buffer); async function readInto( buffer) { let offset= 0 ; while ( offset< buffer. byteLength) { const { value: view, done} = await reader. read( new Uint8Array( buffer, offset, buffer. byteLength- offset)); buffer= view. buffer; if ( done) { break ; } offset+= view. byteLength; } return buffer; }
15.8. 在流上发送事务性块
此部分为非规范性内容。
在单向流上发送事务性数据,仅当可以完全不阻塞 流控制 时,可以通过使用
getWriter
函数及其生成的 writer 来实现。
async function sendTransactionalData( wt, bytes) { const writable= await wt. createUnidirectionalStream(); const writer= writable. getWriter(); await writer. ready; try { await writer. atomicWrite( bytes); } catch ( e) { if ( e. name!= "AbortError" ) throw e; // 因避免阻塞流控制而被拒绝 // 只要没有待处理的非原子写入,可写流就保持无错误状态 } finally { writer. releaseLock(); } }
15.9. 使用服务器证书哈希
此部分为非规范性内容。
WebTransport 会话可以使用对提供给服务器的证书哈希的检查来覆盖客户端执行的默认信任评估。在下面的示例中,hashValue 是一个 BufferSource,
包含 底层连接
应视为有效的服务器证书的 SHA-256 哈希。
const wt= new WebTransport( url, { serverCertificateHashes: [ { algorithm: "sha-256" , value: hashValue, } ] }); await wt. ready;
15.10. 完整示例
此部分为非规范性内容。
此示例说明了 closed 和 ready promise 的使用、客户端或服务器打开单向和双向流,以及发送和接收数据报。
曾经存在于传输的 datagrams
上的 writable 属性很容易通过如下方式进行 polyfill:
wt.datagrams.writable ||= wt.datagrams.createWritable();
// Adds an entry to the event log on the page, optionally applying a specified // CSS class. let wt, streamNumber, datagramWriter; connect. onclick= async () => { try { const url= document. getElementById( 'url' ). value; wt= new WebTransport( url); wt. datagrams. writable||= wt. datagrams. createWritable(); addToEventLog( 'Initiating connection...' ); await wt. ready; addToEventLog( ` ${ ( wt. reliability== "reliable-only" ) ? "TCP" : "UDP" } ` + `connection ready.` ); wt. closed. then(() => addToEventLog( 'Connection closed normally.' )) . catch (() => addToEventLog( 'Connection closed abruptly.' , 'error' )); streamNumber= 1 ; datagramWriter= wt. datagrams. writable. getWriter(); readDatagrams(); acceptUnidirectionalStreams(); document. forms. sending. elements. send. disabled= false ; document. getElementById( 'connect' ). disabled= true ; } catch ( e) { addToEventLog( `Connection failed. ${ e} ` , 'error' ); } } sendData. onclick= async () => { const form= document. forms. sending. elements; const data= sending. data. value; const bytes= new TextEncoder( 'utf-8' ). encode( data); try { switch ( form. sendtype. value) { case 'datagram' : { await datagramWriter. ready; datagramWriter. write( bytes). catch (() => {}); addToEventLog( `Sent datagram: ${ data} ` ); break ; } case 'unidi' : { const writable= await wt. createUnidirectionalStream(); const writer= writable. getWriter(); writer. write( bytes). catch (() => {}); await writer. close(); addToEventLog( `Sent a unidirectional stream with data: ${ data} ` ); break ; } case 'bidi' : { const duplexStream= await wt. createBidirectionalStream(); const n= streamNumber++ ; readFromIncomingStream( duplexStream. readable, n); const writer= duplexStream. writable. getWriter(); writer. write( bytes). catch (() => {}); await writer. close(); addToEventLog( `Sent bidirectional stream # ${ n} with data: ${ data} ` ); break ; } } } catch ( e) { addToEventLog( `Error while sending data: ${ e} ` , 'error' ); } } // Reads datagrams into the event log until EOF is reached. async function readDatagrams() { try { const decoder= new TextDecoderStream( 'utf-8' ); for await ( const dataof wt. datagrams. readable. pipeThrough( decoder)) { addToEventLog( `Datagram received: ${ data} ` ); } addToEventLog( 'Done reading datagrams!' ); } catch ( e) { addToEventLog( `Error while reading datagrams: ${ e} ` , 'error' ); } } async function acceptUnidirectionalStreams() { try { for await ( const readableof wt. incomingUnidirectionalStreams) { const number= streamNumber++ ; addToEventLog( `New incoming unidirectional stream # ${ number} ` ); readFromIncomingStream( readable, number); } addToEventLog( 'Done accepting unidirectional streams!' ); } catch ( e) { addToEventLog( `Error while accepting streams ${ e} ` , 'error' ); } } async function readFromIncomingStream( readable, number) { try { const decoder= new TextDecoderStream( 'utf-8' ); for await ( const dataof readable. pipeThrough( decoder)) { addToEventLog( `Received data on stream # ${ number} : ${ data} ` ); } addToEventLog( `Stream # ${ number} closed` ); } catch ( e) { addToEventLog( `Error while reading from stream # ${ number} : ${ e} ` , 'error' ); addToEventLog( ` ${ e. message} ` ); } } function addToEventLog( text, severity= 'info' ) { const log= document. getElementById( 'event-log' ); const previous= log. lastElementChild; const entry= document. createElement( 'li' ); entry. innerText= text; entry. className= `log- ${ severity} ` ; log. appendChild( entry); // If the previous entry in the log was visible, scroll to the new element. if ( previous&& previous. getBoundingClientRect(). top< log. getBoundingClientRect(). bottom) { entry. scrollIntoView(); } }
16. 致谢
编辑们感谢工作组主席和团队联系人 Jan-Ivar Bruaroey、Will Law 和 Yves Lafon 的支持。
WebTransport
接口基于最初在 W3C ORTC CG 中描述的 QuicTransport
接口,并已为在本规范中使用而进行了调整。