WebDriver BiDi

W3C 工作草案,

关于本文档的更多细节
此版本:
https://www.w3.org/TR/2026/WD-webdriver-bidi-20261008/
最新发布版本:
https://www.w3.org/TR/webdriver-bidi/
编辑草案:
https://w3c.github.io/webdriver-bidi/
先前版本:
历史:
https://www.w3.org/standards/history/webdriver-bidi/
实现报告:
https://wpt.fyi/results/webdriver/tests/bidi
测试套件:
https://github.com/web-platform-tests/wpt/tree/master/webdriver/tests/bidi
反馈:
GitHub
规范内联
编辑者:
James Graham (Mozilla)
Alex Rudenko (Google)
Maksim Sadym (Google)
频道:
irc.w3.org 上的 #webdriver
维基:
W3C WebDriver 维基

摘要

本文档定义了双向 WebDriver 协议,这是一种用于远程控制用户代理的机制。

本文档状态

本节描述了本文档在其发布时的状态。当前 W3C 出版物列表,以及本技术报告的最新修订版本,可在 W3C 标准与草案索引中找到。

讨论本规范时首选使用 GitHub Issues。或者,你也可以将评论发送到 Browser Testing and Tools Working Group 的 邮件列表 public-browser-tools-testing@w3.org (归档)。

本文档由 Browser Testing and Tools Working Group 作为工作草案发布,并使用 推荐 标准轨道。

作为工作草案发布并不意味着 W3C 及其成员对其背书。

这是一份草案文档,可能会在任何时候由其他文档更新、替换或废弃。 除作为进行中的工作外,不宜引用本文档。

本文档由一个根据 W3C 专利政策运作的小组制作。 W3C 维护了一份与该小组交付物相关的任何 专利披露的公开列表;该页面还包括 披露专利的说明。实际知晓某项专利且认为该专利包含必要权利要求的个人, 必须按照 W3C 专利政策第 6 节披露该信息。

本文档受 2025 年 8 月 18 日 W3C 流程文档管辖。

1. 引言

本节是非规范性的。

WebDriver 定义了一种用于 自省和 远程控制用户代理的协议。本规范通过 引入双向通信来扩展 WebDriver。相较于 WebDriver 严格的 命令/响应格式,这允许事件从 用户代理流式传输到控制软件,从而更好地匹配浏览器 DOM 的事件驱动本质。

2. 基础设施

本规范依赖 Infra Standard。[INFRA]

网络协议消息使用 CDDL 定义。[RFC8610]

本规范定义了一个等待 队列,它是一个映射。

肯定有更好的 机制来做这种“等待事件”的事情。

当一个并行运行的算法 algorithm 等待一组 事件 events 和 resume id 时:

  1. 暂停 algorithm 的执行。

  2. 断言:等待 队列不包含 resume id。

  3. 将等待 队列[resume id] 设置为(events, algorithm)。

要用给定的 name、 id 和 parameters 来恢复:
  1. 如果等待队列不 包含 id,则返回。

  2. 令(events, algorithm)为等待队列[id]

  3. 对 events 中的每个 event:

    1. 如果 event 等于 name:

      1. 从等待队列中移除 id。

      2. 从 algorithm 被暂停的 位置恢复运行其中的步骤,并将 name 和 parameters 作为 等待的结果传入。

        我们是否应该有类似微任务的东西,以 确保它在事件循环上的任何其他任务之前 运行?

WebDriver 配置是一个具有以下内容的结构体:

WebDriver 配置具有一个关联类型, 它 是一个类型。

WebDriver 配置的 值要么是一个 其类型为该配置的关联类型的值,要么是 unset。

Unset 是一个值,表示某个特定配置 值尚未被设置。

注:此算法允许访问给定navigable 的 WebDriver 配置,方式是依次检查 navigables、然后是 user contexts,最后是 global 中的值。 如果配置未设置,则返回 unset。

要获取 WebDriver 配置 configuration 对于 navigable navigable 的 WebDriver 配置值:

  1. 令 top-level traversable 为 navigable 的顶级 traversable。

  2. 如果 configuration 的navigables 包含 top-level traversable:

    1. 令 navigable configuration value 为 configuration 的 navigables[top-level traversable]。

    2. 如果 navigable configuration value 不是 unset,则返回 navigable configuration value。

  3. 令 user context 为 navigable 的关联用户 上下文。

  4. 如果 configuration 的user contexts 包含 user context:

    1. 令 user context configuration value 为 configuration 的 user contexts[user context]。

    2. 如果 user context configuration value 不是 unset,则返回 user context configuration value。

  5. 返回 configuration 的 global。

注:这是一个用于按 target 存储 WebDriver 配置的通用算法,target 可以是 navigable、用户上下文,或者如果 target 为 null 或被省略,则全局存储。

要将 WebDriver 配置 configuration 的 值 value 存储到可选 target 中, 其中 target 是一个navigable、 一个用户上下文,或在未提供时为 null:

  1. 如果 target 为 null,则将 configuration 的 global 设置为 value。

  2. 如果 target 是一个用户上下文,则将 configuration 的 user contexts[target] 设置为 value。

  3. 如果 target 是一个navigable,则将 configuration 的 navigables[target] 设置为 value。

注:此通用算法将 WebDriver 配置的值 存储在 global、user contexts 或 navigables 中,具体取决于 command parameters 中是否存在 "userContexts" 和 "contexts"。这些 参数 是互斥的。如果两者都未提供,则配置会全局存储。

要针对给定的 command parameters 存储 WebDriver 配置 WebDriver 配置 configuration 的 值 value:

  1. 如果 command parameters 包含 "userContexts",且 command parameters 包含 "contexts",则返回带有错误 代码 invalid argument 的错误。

  2. 令 affected navigables 为空集合。

  3. 如果 command parameters 包含 "contexts":

    1. 令 navigables 为尝试用 command parameters["contexts"] 通过 id 获取有效顶级 traversables 的结果。

    2. 对于 navigables 中的每个 navigable:

      1. 将 navigable 追加到 affected navigables。

      2. 将 configuration 的 value 存储到 navigable 中。

  4. 否则,如果 command parameters 包含 "userContexts":

    1. 令 user contexts 为尝试用 command parameters["userContexts"] 获取有效用户上下文的结果。

    2. 对于 user contexts 中的每个 user context:

      1. 对于所有其 关联用户上下文为 user context 的顶级 traversable列表中的每个 top-level traversable:

        1. 将 top-level traversable 追加 到 affected navigables。

      2. 将 configuration 的 value 存储到 user context 中。

  5. 否则:

    1. 对于所有顶级 traversable中的每个 top-level traversable,将 top-level traversable 追加 到 affected navigables。

    2. 存储 configuration 的 value。

  6. 返回 affected navigables。

3. 协议

本节定义 WebDriver BiDi 协议的基本概念。这些术语不同于其在 传输层的表示。

协议使用 CDDL 定义来定义。为方便实现者,定义了两个单独的 CDDL 定义; 远端定义定义了 在本地端生成并由远端消费的消息格式,而 本地端 定义定义了在远端 生成并由本地端消费的消息格式

3.1. 定义

这是否应该作为 附录?

本节给出了 远端定义 和 本地端定义的初始内容。 这些内容由本规范其余部分中定义的定义片段 进行扩充。

Remote end definition

Command = {
  id: js-uint,
  CommandData,
  Extensible,
}

CommandData = (
  BrowserCommand //
  BrowsingContextCommand //
  EmulationCommand //
  InputCommand //
  NetworkCommand //
  ScriptCommand //
  SessionCommand //
  StorageCommand //
  WebExtensionCommand
)

EmptyParams = {
   Extensible
}

Local end definition

Message = (
  CommandResponse /
  ErrorResponse /
  Event
)

CommandResponse = {
  type: "success",
  id: js-uint,
  result: ResultData,
  Extensible
}

ErrorResponse = {
  type: "error",
  id: js-uint / null,
  error: ErrorCode,
  message: text,
  ? stacktrace: text,
  Extensible
}

ResultData = (
  BrowserResult /
  BrowsingContextResult /
  EmulationResult /
  InputResult /
  NetworkResult /
  ScriptResult /
  SessionResult /
  StorageResult /
  WebExtensionResult
)

EmptyResult = {
  Extensible
}

Event = {
  type: "event",
  EventData,
  Extensible
}

EventData = (
  BrowsingContextEvent //
  InputEvent //
  LogEvent //
  NetworkEvent //
  ScriptEvent
)

EmptyResult 是一种没有必需字段的结果 类型, 用作不会产生结果数据的命令的返回类型。

远端定义 和 本地端定义

Extensible = (*text => any)

js-int = -9007199254740991..9007199254740991
js-uint = 0..9007199254740991

3.2. 会话

WebDriver BiDi 扩展了 会话概念,该概念来自 WebDriver。

会话具有一个 BiDi 标志,除非另有说明,否则该标志为 false。

BiDi 会话是一个 会话,其 BiDi 标志 被设置为 true。

活动 BiDi 会话列表由以下步骤给出:
  1. 令 BiDi sessions 为一个新的列表。

  2. 对于活动会话中的每个 session:

    1. 如果 session 是一个 BiDi 会话,则将 session 追加到 BiDi sessions。

  3. 返回 BiDi sessions。

3.3. 模块

WebDriver BiDi 协议被组织为多个模块。

每个模块表示与用户 代理某一方面有关的一组相关 命令和事件。例如,模块可能包含用于检查和 操作 DOM,或用于脚本执行的功能。

每个模块都有一个模块名称,它是一个字符串。模块中定义的命令 和事件的命令名称和 事件名称 以模块名称开头,后跟一个句点 "."。

包含命令的模块定义 远端定义 片段。它们会为该模块的命令在 CommandData 组中提供选择项,也可以定义 额外的定义属性。它们 也可以定义 本地端定义 片段,为该模块中命令的结果 在 ResultData 组中提供额外选择项。

包含事件的模块定义 本地端定义 片段,这些片段是该模块事件在 Event 组中的 选择项。

实现可以定义扩展模块。这些扩展模块必须具有一个 包含单个冒号 ":" 字符的模块名称。 冒号之前的 部分是前缀;对于给定实现专用的所有 扩展模块, 这通常是相同的,并且对于 给定实现应当是唯一的。

其他规范可以定义自己的 WebDriver-BiDi 模块来扩展该协议。 这类模块的名称不得包含冒号(:)字符, 也不得定义包含该字符的命令名称、事件名称或属性 名称。

鼓励外部规范的作者添加新模块,而不是扩展 现有模块。如果希望扩展某个现有模块,最好将该 扩展直接整合到包含原始模块定义的规范中。

3.4. 命令

命令是一种异步 操作,由 本地端请求,并在远端运行, 最终将 结果或错误返回给本地端。 多个 命令可以同时运行,并且命令可能会 长时间运行。因此,命令可能会乱序完成。

每个命令由以下内容定义:

可以在没有活动会话的情况下运行的命令是静态 命令。除非在其定义中说明,否则命令不是静态命令。

当命令从本地端发送时,它们 具有命令 id。这是一个 标识符,本地端用它来识别来自特定 命令的响应。从远端 的角度看, 该标识符是不透明的,不能在内部用于识别命令。

注:这是因为命令 id 完全由本地端 控制,并且在一个会话的过程中不一定唯一。例如,一个本地端如果 忽略所有响应,就可以对每个命令使用相同的命令 id。

所有命令 名称的集合是一个集合,包含 所有已定义的命令名称,包括任何属于扩展模块的命令名称。

3.5. 错误

WebDriver BiDi 使用以下额外代码扩展了来自 WebDriver 的错误代码集合:

invalid web extension
尝试安装无效的 Web 扩展。
no such client window
尝试与未知的客户端窗口交互。
no such handle
尝试反序列化未知的 RemoteObjectReference。
no such history entry
尝试导航到未知的会话历史条目。
no such network collector
尝试移除未知的收集器。
no such intercept
尝试移除未知的网络拦截。
no such network data
尝试引用未知的网络数据。
no such node
尝试反序列化未知的 SharedReference。
no such request
尝试继续处理未知的请求。
无此屏幕录制
试图停止未知的屏幕录制。
no such script
尝试移除未知的预加载脚本。
no such storage partition
尝试访问不存在的存储分区中的数据。
no such user context
尝试引用未知的用户上下文。
no such web extension
尝试引用未知的 Web 扩展。
unable to close browser
尝试关闭浏览器,但未能做到。
unable to set cookie
尝试创建 cookie,但用户代理拒绝了它。
underspecified storage partition
尝试与未充分指定的存储分区中的数据交互。
unable to set file input
尝试设置文件输入,但未能做到。
unavailable network data
尝试获取未被收集或已被逐出的网络数据。
ErrorCode = "invalid argument" /
            "invalid selector" /
            "invalid session id" /
            "invalid web extension" /
            "move target out of bounds" /
            "no such alert" /
            "no such network collector" /
            "no such element" /
            "no such frame" /
            "no such handle" /
            "no such history entry" /
            "no such intercept" /
            "no such network data" /
            "no such node" /
            "no such request" /
            "no such screencast" /
            "no such script" /
            "no such storage partition" /
            "no such user context" /
            "no such web extension" /
            "session not created" /
            "unable to capture screen" /
            "unable to close browser" /
            "unable to set cookie" /
            "unable to set file input" /
            "unavailable network data" /
            "underspecified storage partition" /
            "unknown command" /
            "unknown error" /
            "unsupported operation"

3.6. 事件

事件是一个通知,由 远端 发送给本地端,表示远端上发生了值得关注的事情。

BiDi 会话具有订阅,它是一个列表,包含订阅。

BiDi 会话具有一个已知订阅 id,它是一个集合,包含 已发布给本地端但尚未被取消订阅的所有 订阅 id。

订阅是一个结构体,由一个 订阅 id(一个字符串)、 事件名称(一个事件名称的集合)、 顶级 traversable id(一个集合,包含顶级 traversable的 ID) 和 用户上下文 id(一个集合,包含用户上下文的 ID)。

如果 subscription 的顶级 traversable id是空集合, 且 subscription 的用户上下文 id是空集合,则订阅 subscription 是全局的。

给定 event name 和 navigables,启用了某个事件的会话 集合为:

  1. 令 sessions 为一个新的集合。

  2. 对于活动 BiDi 会话中的每个 session:

    1. 如果对于 session、event name 和 navigables,事件 已启用, 则将 session 追加到 sessions。

  3. 返回 sessions。

要在给定 session、 event name 和 navigables 的情况下判断某个事件 是否已启用:

注:navigables 是一个集合,因为共享 worker 可以关联 多个上下文。

  1. 令 top-level traversables 为使用 navigables 调用获取顶级 traversable 的结果。

  2. 对于 session 的订阅中的每个 subscription:

    1. 如果 subscription 的事件名称不包含 event name,则继续。

    2. 如果 subscription 是全局的,则返回 true。

    3. 如果用户上下文 id不为空:

      1. 对于 top-level traversables 中的每个 navigable:

        1. 如果 subscription 的用户上下文 id包含 navigable 的关联用户上下文的 用户上下文 id, 则返回 true。

    4. 否则:

      1. 令 subscription top-level traversables 为用 subscription 的顶级 traversable id 调用通过 id 获取 navigables 的结果。

      2. 如果 top-level traversables 与 subscription top-level traversables 的交集不是空,则返回 true。

  3. 返回 false。

给定 event name 和 session,启用了某个事件的顶级 traversable 集合 为:

  1. 令 result 为一个新的集合。

  2. 对于 session 的订阅中的每个 subscription:

    1. 如果 subscription 的事件名称不 包含 event name, 则继续。

    2. 如果 subscription 是全局的:

      1. 对于远端的顶级 traversable中的每个 traversable:

        1. 将 traversable 追加到 result。

      2. 中断。

    3. 否则,如果用户上下文 id不为空:

      1. 对于远端的顶级 traversable中的每个 traversable:

        1. 如果 subscription 的用户上下文 id包含 traversable 的关联用户上下文的 用户上下文 id,则将 traversable 追加到 result。

    4. 否则:

      1. 令 top-level traversables 为用 subscription 的顶级 traversable id 调用通过 id 获取 navigables 的结果。

      2. 将 top-level traversables 中的每一项追加到 result。

  3. 返回 result。

要在给定 name 的情况下获得一组 事件名称:
  1. 令 events 为空集合。

  2. 如果 name 包含 U+002E(句点):

    1. 如果 name 是某个事件的事件名称,则将 name 追加到 events 并返回带有数据 events 的成功。

    2. 返回一个带有错误代码 invalid argument 的错误

  3. 否则,将 name 解释为表示某个模块中的所有事件。 如果 name 不是模块名称,则返回一个错误,其 错误代码为 invalid argument。

  4. 将名称为 name 的模块中每个事件的事件 名称 追加到 events。

  5. 返回带有数据 events 的成功。

4. 传输

消息传输使用 WebSocket 协议提供。 [RFC6455]

注:按 WebSocket 协议的术语,本地端是 客户端,而远端是服务器 / 远程主机。

注:将命令和事件编码为消息的方式 类似于 JSON-RPC,但本规范并未规范性地 引用它。[JSON-RPC] 对远端的规范性要求 改为以精确处理模型的形式给出,而不对 本地端给出规范性要求。

WebSocket 监听器 是一个能够 接受传入 WebSocket 连接的网络端点。

WebSocket 监听器 具有一个host、一个port、一个secure flag,以及一个 WebSocket 资源 列表。

当创建 WebSocket 监听器 listener 时,远端 必须开始在 listener 的host 和port 所给定的主机和端口上监听 WebSocket 连接。如果 listener 的secure flag 已设置,则从 listener 建立的连接必须经过 TLS 加密。

远端具有一个集合,其中包含 WebSocket 监听器 活动 监听器,其初始为空。

远端具有一个集合,其中包含未与 会话关联的 WebSocket 连接,其初始为空。

WebSocket 连接是遵循 WebSocket 协议要求的网络连接

BiDi 会话具有一个集合,其中包含会话 WebSocket 连接,其元素是WebSocket 连接。这 初始为空。

BiDi 会话 session 与连接 关联 connection,如果 session 的会话 WebSocket 连接包含 connection。

注:每个 WebSocket 连接至多与一个 BiDi 会话关联。

当客户端通过连接到活动监听器集合之一的 listener 来建立 WebSocket 连接 connection 时, 实现必须按照 WebSocket 服务器端要求继续进行,并在决定是否 接受传入连接时运行以下步骤:

  1. 令 resource name 为读取客户端开启握手所得的资源名称。如果 resource name 不在 listener 的WebSocket 资源列表中,则停止 运行这些步骤,并表现为所请求的服务不可 用。

  2. 如果 resource name 是字节字符串 "/session", 且实现支持仅 BiDi 会话:

    1. 运行任何其他实现定义的步骤,以决定是否应当接受 该连接;如果不接受,则停止运行这些 步骤,并表现为所请求的服务不可用。

    2. 将该连接添加到未与会话关联的 WebSocket 连接。

    3. 返回。

  3. 用 resource name 获取 WebSocket 资源的会话 ID, 并令 session id 为该值。如果 session id 为 null,则 停止运行这些步骤,并表现为所请求的服务不可 用。

  4. 如果会话在活跃会话列表中,并且 session id 是其会话 ID,则令 session 为该 会话。否则,停止运行这些步骤,并表现得如同 所请求的服务不可用。

  5. 运行任何其他实现定义的步骤,以决定是否 应接受该连接;如果不接受,则停止运行这些 步骤,并表现为所请求的服务不可用。

  6. 否则,将 connection 追加到 session 的会话 WebSocket 连接,并在服务器选择接受传入连接时,继续执行 WebSocket 服务器端要求。

我们是否支持单个会话使用多于 1 个 连接?

当为 WebSocket 连接 connection 接收到 WebSocket 消息,其类型为 type 且数据为 data 时,远端 必须在给定 connection、 type 和 data 的情况下处理传入消息。

当对 WebSocket 连接 connection 开始 WebSocket 关闭握手,或当该WebSocket 连接关闭时, 远端必须在给定 connection 的情况下处理连接 关闭。

注:需要这两个条件,因为 WebSocket 连接可能在没有关闭握手的情况下被关闭。

要在给定会话 session 的情况下,构造 WebSocket 资源名称:

  1. 如果 session 为 null,返回 "/session"

  2. 返回将字符串 "/session/" 与 session 的会话 ID 连接起来的结果。

要在给定WebSocket 监听器 listener 和会话 session 的情况下,构造 WebSocket URL:

  1. 令 resource name 为以 session 调用构造 WebSocket 资源名称 的结果。

  2. 返回一个WebSocket URI,其构造方式为:将 host 设置为 listener 的主机,port 设置为 listener 的 端口,path 设置为 resource name;如果 listener 的安全标志已设置,则遵循 wss-URI 构造,否则遵循 ws-URL 构造。

要在给定 resource name 的情况下,获取 WebSocket 资源的会话 ID:

  1. 如果 resource name 不是以字节字符串 "/session/" 开头,则返回 null。

  2. 令 session id 为 resource name 中跟在 "/session/" 前缀之后的字节。

  3. 如果 session id 不是 UUID 的字符串表示,则返回 null。

  4. 返回 session id。

要在给定会话 session 的情况下,开始监听 WebSocket 连接:
  1. 如果远端想要重用活跃监听器中的某个现有WebSocket 监听器,则令 listener 为该 监听器。否则,令 listener 为一个新的WebSocket 监听器,其具有 由实现定义的主机、端口、 安全 标志,以及一个空的WebSocket 资源列表。

  2. 令 resource name 为以 session 调用构造 WebSocket 资源名称 的结果。

  3. 将 resource name 追加到 listener 的WebSocket 资源列表。

  4. 将 listener 追加到远端的活跃监听器。

  5. 返回 listener。

注:处理多个会话的中介节点可以使用一个 或多个 WebSocket 监听器。WebDriver 定义 端点节点一次最多支持一个会话,因此预期 它只会有单个监听器。

注:对于端点 节点,上述步骤中的host 通常会是 "localhost"。

要在给定 WebSocket 连接 connection、类型 type 和数据 data 的情况下处理 传入消息:
  1. 如果 type 不是text,则在给定 connection、 null 和invalid argument 的情况下发送错误响应,最后 返回。

  2. 断言:data 是一个标量值字符串,因为 WebSocket 处理 UTF-8 编码数据中的错误否则已经 会使 WebSocket 连接失败。

    似乎没有内容 定义 UTF-8 错误使用什么状态码。

  3. 如果存在一个BiDi 会话与连接关联 connection, 则令 session 为该会话。否则,如果 connection 在未与会话关联的 WebSocket 连接中,则令 session 为 null。否则,返回。

  4. 令 parsed 为在给定 data 的情况下将 JSON 解析为 Infra 值的结果。如果这抛出异常,则在给定 connection、 null 和invalid argument 的情况下发送错误响应,并 最后返回。

  5. 如果 session 非 null 且不在活动会话中,则返回。

  6. 将 parsed 与 远端定义匹配。 如果这产生 匹配:

    1. 令 matched 为表示匹配数据的映射。

    2. 断言:matched 包含 "id"、"method" 和 "params"。

    3. 令 command id 为 matched["id"]。

    4. 令 method 为 matched["method"]

    5. 令 command 为命令名称为 method 的命令。

    6. 如果 session 为 null 且 command 不是静态命令,则 在给定 connection、command id 和invalid session id 的情况下发送错误响应,并返回。

    7. 并行运行以下步骤:

      1. 令 result 为对于 command,在给定 session 和命令参数 matched["params"] 的情况下运行远端步骤所得的结果

      2. 如果 result 是一个错误,则在给定 connection、command id 和 result 的错误代码的情况下发送 错误响应,并最后 返回。

      3. 令 value 为 result 的数据。

      4. 断言:value 与结果类型的定义匹配, 该结果类型对应于命令 名称为 method 的命令。

      5. 如果 method 是 "session.new",则令 session 为 活动会话列表中的条目,其会话 ID等于 value 的 "sessionId" 属性;将 connection 追加 到 session 的会话 WebSocket 连接,并 从未与会话关联的 WebSocket 连接中移除 connection。

      6. 令 response 为一个新的映射,它与 CommandResponse 产生式匹配,该产生式在 本地端定义 中,其 id 字段设置为 command id,value 字段设置为 value。

      7. 令 serialized 为在给定 response 的情况下将 infra 值序列化为 JSON 字节的结果。

      8. 在 connection 上发送 WebSocket 消息,该消息由 serialized 组成。

  7. 否则:

    1. 令 command id 为 null。

    2. 如果 parsed 是一个映射, 且 parsed["id"] 存在并且是一个 大于或等于零的整数,则将 command id 设置为该整数。

    3. 令 error code 为invalid argument。

    4. 如果 parsed 是一个映射, 且 parsed["method"] 存在并且是一个 字符串,但 parsed["method"] 不在所有命令名称的集合中,则将 error code 设置为unknown command。

    5. 在给定 connection、command id 和 error code 的情况下发送错误响应。

要在给定设置对象 settings 的情况下获取相关 navigables:

  1. 令 related navigables 为空集合。

  2. 如果 settings 的相关全局对象是一个 Window:

    1. 令 navigable 为相关全局对象的关联 Document的节点 navigable。

    2. 如果 navigable 非 null,则将 navigable 追加到 related navigables。

  3. 否则,如果 settings 所指定的全局对象是一个 WorkerGlobalScope, 则对于该全局对象的 所有者集合中的每个 owner:

    1. 令 navigable 为 null。

    2. 如果 owner 是一个Document,则将 navigable 设置为 owner 的 节点 navigable。

    3. 如果 navigable 非 null,则将 navigable 追加到 related navigables。

  4. 返回 related navigables。

要在给定一个 context id navigable ids 的列表的情况下通过 id 获取 navigables:

  1. 令 result 为空集合。

  2. 对于 navigable ids 中的每个 navigable id:

    1. 如果存在 id 为 navigable id 的navigable,则令 navigable 为该 navigable,否则为 null。

    2. 如果 navigable 非 null,则将 navigable 追加到 result。

  3. 返回 result。

要在给定navigables navigables 的列表的情况下获取 顶级 traversables:

  1. 令 result 为空集合。

  2. 对于 navigables 中的每个 navigable:

    1. 将 navigable 的追加顶级 traversable到 result。

  3. 返回 result。

要在给定 context id navigable ids 的列表的情况下通过 id 获取有效 navigables:

  1. 令 result 为空集合。

  2. 对于 navigable ids 中的每个 navigable id:

    1. 令 navigable 为尝试用 navigable id 获取 navigable的结果。

    2. 将 navigable 追加到 result。

  3. 返回带有数据 result 的成功。

要在给定 context id navigable ids 的列表的情况下通过 id 获取有效顶级 traversables:

  1. 令 result 为空集合。

  2. 对于 navigable ids 中的每个 navigable id:

    1. 令 navigable 为尝试用 navigable id 获取 navigable的结果。

    2. 如果 navigable 不是顶级 traversable,则返回带有错误代码 invalid argument 的错误。

    3. 将 navigable 追加到 result。

  3. 返回带有数据 result 的成功。

要在给定 session 和 body 的情况下发出事件:
  1. 断言:body 与 Event 产生式匹配。

  2. 令 serialized 为在给定 body 的情况下将 infra 值序列化为 JSON 字节的结果。

  3. 对于 session 的会话 WebSocket 连接中的每个 connection:

    1. 在 connection 上发送 WebSocket 消息,该消息由 serialized 组成。

要在给定 WebSocket 连接 connection、command id 和 error code 的情况下发送错误 响应:
  1. 令 error data 为一个新的映射,与 本地端定义中的 ErrorResponse 产生式匹配, 其中 id 字段 设置为 command id,error 字段设置为 error code, message 字段设置为一个实现定义的字符串, 包含对所发生错误的人类可读定义,并且 stacktrace 字段可选地设置为一个实现定义的 字符串,包含错误发生时活动栈帧的栈跟踪报告。

  2. 令 response 为在给定 error data 的情况下将 infra 值序列化为 JSON 字节 的结果。

    注:command id 可以为 null,在 这种情况下,id 字段也会 被设置为 null,而不会从 response 中省略。

  3. 在 connection 上发送 WebSocket 消息,该消息由 response 组成。

要在给定 WebSocket 连接 connection 的情况下处理连接 关闭:

  1. 如果存在一个BiDi 会话与连接关联 connection:

    1. 令 session 为与连接关联 connection 的 BiDi 会话。

    2. 从 session 的会话 WebSocket 连接中移除 connection。

  2. 否则,如果未与会话关联的 WebSocket 连接 包含 connection,则从该集合中移除 connection。

注: 这不会结束任何会话。

需要挂接到 会话结束,以允许 UA 在需要时关闭 监听器。

要在给定 session 的情况下关闭 WebSocket 连接:

  1. 对于 session 的会话 WebSocket 连接中的每个 connection:

    1. 使用 connection 开始 WebSocket 关闭握手。

      注:这将导致 对 connection 运行处理连接关闭中的步骤, 这些步骤将清理与 connection 关联的资源。

4.1. 建立连接

WebDriver 客户端通过请求值为 true 的 WebSocket URL 能力,选择加入双向连接。

本规范定义的 WebDriver 新会话算法, 其参数为 session、capabilities 和 flags,如下:
  1. 如果 flags 包含 "bidi",则返回。

  2. 令 webSocketUrl 为从 capabilities 获取名为 "webSocketUrl" 的属性的结果。

  3. 如果 webSocketUrl 是 undefined,则返回。

  4. 断言:webSocketUrl 为 true。

  5. 令 listener 为在给定 session 的情况下开始监听 WebSocket 连接的结果。

  6. 将 webSocketUrl 设置为用 listener 和 session 构造 WebSocket URL的结果。

  7. 在 capabilities 上设置名为 "webSocketUrl" 的属性为 webSocketUrl。

  8. 将 session 的 BiDi 标志设置为 true。

  9. 将 "bidi" 追加到 flags。

实现还应允许客户端建立一个 不是 HTTP 会话的 BiDi 会话。在这种情况下,WebSocket 服务器的 URL 通过带外方式传达。允许这样做的实现支持 仅 BiDi 会话。当这样的实现准备好接受 启动 WebDriver 会话的请求时,它必须:

  1. 在给定 null 的情况下开始监听 WebSocket 连接。

5. 沙盒化脚本执行

自动化工具的一个常见需求是执行这样的脚本:它们可以 访问某个文档的 DOM,但没有关于包含该 文档的 navigable 中运行的脚本对 DOM API 所做任何更改的信息。

BiDi 会话具有一个沙盒映射,它是一个弱 映射,其中 键是 Window 对象,值是字符串与 SandboxWindowProxy 对象之间的映射。

注:这里对沙盒的定义,是试图 将现有实现的行为编纂成规范。它暴露了实现中 以前被规范视为内部的部分,尤其是 平台对象的内部状态(通常以浏览器 引擎主要实现语言中的原生对象来实现)与 ECMAScript 可见状态之间的 区别。由于现有沙盒 实现发生在引擎的低层,实现要在 所有细节上收敛到本规范可能是一个缓慢过程。在 此期间,鼓励实现者提供有关其与规范 差异的详细文档,并鼓励此特性的用户 显式测试在沙盒中运行的脚本是否能在所有实现中工作。

5.1. 沙盒 Realm

每个沙盒都是一个唯一的 ECMAScript Realm。但是,沙盒 realm 通过 SandboxProxy 对象提供对现有 Window realm 中平台对象的访问。

要在给定 name 和 navigable 的情况下获取或 创建沙盒 realm:
  1. 如果 name 为空字符串,则返回带有 错误代码 invalid argument 的错误。

  2. 令 window 为 navigable 的活动窗口。

  3. 如果沙盒映射不 包含 window,则将沙盒映射[window] 设置为新的映射。

  4. 令 sandboxes 为沙盒映射[window]。

  5. 如果 sandboxes 不包含 name,则将 sandboxes[name] 设置为用 navigable 调用创建沙盒 realm的结果。

  6. 返回带有数据 sandboxes[name] 的成功。

要用 window 创建沙盒 realm:

定义 沙盒 realm 的创建。这将返回一个 SandboxWindowProxy, 其包装 window。

要在给定 target realm 的情况下获取沙盒 名称:

  1. 令 realms maps 为获取沙盒映射的值所得的结果。

  2. 对于 realms maps 中的每个 realms map:

    1. 对于 realms map 中的每个 name → realm:

      1. 如果 realm 是 target realm,则返回 name。

  3. 返回 null。

5.2. 沙盒代理对象

SandboxProxy 对象是一个特异对象,用于调解对 另一个 realm 中对象的沙盒化 访问。沙盒代理对象被设计为强制执行 以下限制:

不存在 SandboxProxy 接口对象。

详细定义 SandboxProxy 如何工作

要获取解包装的 object:
  1. 只要 object 是 SandboxProxy 或 SandboxWindowProxy, 就将 object 设置为它的 被包装对象。

  2. 返回 object。

5.3. SandboxWindowProxy

SandboxWindowProxy 是一个特异对象,表示由 SandboxProxy 对象包装的 Window 对象。这提供了对 Window 全局中该数据的沙盒化 访问。

定义它如何工作。

6. 用户上下文

用户上下文表示 远端内零个或多个 顶级 traversable的集合。 每个用户上下文都有 一个关联的存储 分区,因此远端数据不会在不同的用户上下文之间 共享。

目前还不清楚这是不是 正式定义用户上下文概念或其与存储交互的 最佳方式。

注:Infra 规范使用术语“user agent”来指代 与用户上下文相同的概念。然而,这与 “user agent”用来表示包含多个用户上下文的整个 Web 客户端这一用法 不兼容。虽然这种差异对 Web 内容不可见, 但它可通过 WebDriver 被观察到,因此我们避免使用该术语。

用户上下文具有一个用户上下文 id, 它是在用户上下文创建时设置的唯一字符串。

navigable 具有一个关联用户上下文,它是一个用户上下文。

当新的顶级 traversable被创建时,其关联用户上下文 被设置为用户上下文集合中的某个用户上下文。

注:在某些情况下,用户上下文会在 顶级 traversable创建时由规范设置;但是在不存在此类 要求的情况下,关联用户上下文对于顶级 traversable是实现定义的。

我们是否应指定具有非 null opener 的顶级 traversable具有与其 opener 相同的关联用户上下文? 需要检查这是否是现有实现会强制执行的内容。

子 navigable 的关联用户上下文是 其 父级的关联用户上下文。

如果某个用户上下文不是任何 顶级 traversable的关联 用户上下文,则它是一个空用户上下文。

默认用户 上下文是一个用户 上下文,其用户上下文 id 为 "default"。

实现具有一个用户上下文集合,它是一个由用户上下文组成的集合。初始时,它 包含默认 用户上下文。

实现可以在任何时候将新的用户上下文追加到用户上下文集合, 例如响应用户操作。

注:这里的“任何时候”包括实现 启动期间,因此给定 实现可能总是在用户上下文集合中有多个条目。

实现可以在任何 时候从用户上下文集合中移除任何空用户上下文,但 默认用户 上下文除外。然而,它们并非必须移除这类用户上下文。不是空用户上下文的用户上下文不得从 用户 上下文集合中移除。

BiDi 会话具有一个 用户上下文到接受不安全 证书覆盖映射,它是 用户上下文与 boolean 之间的映射。

BiDi 会话具有一个用户 上下文到代理配置映射,它是 用户上下文与代理配置之间的映射。

模拟网络条件结构体是一个具有以下内容的结构体:

BiDi 会话具有模拟网络条件,它是 一个结构体,具有 一个名为 default network conditions 的项,它是 一个 模拟网络条件结构体或 null;一个 名为 user context network conditions 的项, 它 是用户 上下文与模拟网络条件结构体之间的弱映射; 以及一个名为 navigable network conditions 的项, 它是 navigable与模拟 网络条件结构体之间的 弱映射。

当用户上下文从 用户 上下文集合中被移除时,移除用户上下文订阅。

要移除 用户上下文订阅:

  1. 对于活动会话中的每个 session:

    1. 令 subscriptions to remove 为一个集合。

    2. 对于 session 的订阅中的每个 subscription:

      1. 如果 subscription 的用户上下文 id 包含 navigable 的关联用户上下文的用户上下文 id;

        1. 从 subscription 的用户上下文 id中移除 navigable 的关联用户上下文的 用户上下文 id。

        2. 如果 subscription 的用户上下文 id 为空:

          1. 将 subscription 追加到 subscriptions to remove。

    3. 从 session 的订阅中移除 subscriptions to remove。

要在给定 user context id 的情况下获取用户上下文:
  1. 对于用户上下文集合中的每个 user context:

  2. 如果 user context 的用户上下文 id等于 user context id:

    1. 返回 user context。

  3. 返回 null。

要在给定 user context ids 的情况下获取有效用户 上下文:

  1. 令 result 为空集合。

  2. 对于 user context ids 中的每个 user context id:

    1. 将 user context 设置为用 user context id 调用获取用户上下文的结果。

    2. 如果 user context 为 null,则返回带有 错误代码 no such user context 的错误。

    3. 将 user context 追加到 result。

  3. 返回 result。

7. 模块

7.1. session 模块

session 模块包含用于监控远端状态的命令和 事件。

7.1.1. 定义

远端定义

SessionCommand = (
  session.End //
  session.New //
  session.Status //
  session.Subscribe //
  session.Unsubscribe
)

本地端定义

SessionResult = (
  session.EndResult /
  session.NewResult /
  session.StatusResult /
  session.SubscribeResult /
  session.UnsubscribeResult
)
要在给定 session 的情况下结束会话:
  1. 从活动会话中移除 session。

  2. 如果活动会话为空,则将 webdriver-active 标志 设置为 false。

要在给定 session 的情况下清理 会话:

  1. 使用 session 关闭 WebSocket 连接。

  2. 对于用户上下文集合中的每个 user context:

    1. 移除 session 的 用户上下文到接受不安全证书覆盖映射[user context]。

    2. 移除 session 的 用户上下文到代理配置映射[user context]。

  3. 对于 session 的已阻塞请求映射中的每个 request id →(request、phase、response):

    1. 使用 "continue request"、request id 和(response、"incomplete")恢复。

  4. 对于 session 的网络收集器中的每个 collector:

    1. 令 collector id 为 collector 的收集器。

    2. 对于已收集的网络 数据中的每个 collected data,使用 collected data 和 collector id 从数据中移除收集器。

  5. 对于 session 的 屏幕录制映射中的每个 screencast recording:

    1. 给定 screencast recording,停止屏幕录制。

    2. 从屏幕录制映射中移除 screencast recording。

  6. 如果活动会话为空,则清理远端状态。

  7. 执行任何特定于实现的清理步骤。

要清理远端 状态。
  1. 清空发送请求前映射。

  2. 将默认缓存行为设置为 "default"。

  3. 清空navigable 缓存行为映射。

  4. 执行实现定义的步骤,以启用当前远端配置中通常启用的任何 特定于实现的资源缓存。

7.1.2. 类型

7.1.2.1. session.CapabilitiesRequest 类型
session.CapabilitiesRequest = {
  ? alwaysMatch: session.CapabilityRequest,
  ? firstMatch: [*session.CapabilityRequest]
}

session.CapabilitiesRequest 类型表示为会话请求的功能。

7.1.2.2. session.CapabilityRequest 类型

远程端定义 和 本地端定义

session.CapabilityRequest = {
  ? acceptInsecureCerts: bool,
  ? browserName: text,
  ? browserVersion: text,
  ? platformName: text,
  ? proxy: session.ProxyConfiguration,
  ? unhandledPromptBehavior: session.UserPromptHandler,
  Extensible
}

session.CapabilityRequest 类型表示一组特定的请求功能。

WebDriver BiDi 定义了附加 WebDriver 功能。下表列出了每个 实现必须为 WebDriver BiDi 支持的功能。

功能: WebSocket URL
键: "webSocketUrl"
值类型: boolean
描述: 定义当前会话对双向连接的支持。
附加功能反序列化 算法用于 "webSocketUrl" 功能,参数 value 为:
  1. 如果 value 不是布尔值,则返回错误,其代码 为无效参数。

  2. 返回成功,数据为 value。

"webSocketUrl" 功能的匹配功能序列化 算法, 参数 value 为:
  1. 如果 value 为 false,则返回成功 ,数据为 null。

  2. 返回成功,数据为 true。

7.1.2.3. session.CapabilityResponse 类型
session.CapabilityResponse = {
  acceptInsecureCerts: bool,
  browserName: text,
  browserVersion: text,
  platformName: text,
  setWindowRect: bool,
  userAgent: text,
  ? proxy: session.ProxyConfiguration,
  ? unhandledPromptBehavior: session.UserPromptHandler,
  ? webSocketUrl: text,
  Extensible
}

session.CapabilityResponse 类型表示新 会话所有协商后的功能。

7.1.2.4. session.ProxyConfiguration 类型

远程端定义 和 本地端定义

session.ProxyConfiguration = {
   session.AutodetectProxyConfiguration //
   session.DirectProxyConfiguration //
   session.ManualProxyConfiguration //
   session.PacProxyConfiguration //
   session.SystemProxyConfiguration
}

session.AutodetectProxyConfiguration = (
   proxyType: "autodetect",
   Extensible
)

session.DirectProxyConfiguration = (
   proxyType: "direct",
   Extensible
)

session.ManualProxyConfiguration = (
   proxyType: "manual",
   ? httpProxy: text,
   ? sslProxy: text,
   ? session.SocksProxyConfiguration,
   ? noProxy: [*text],
   Extensible
)

session.SocksProxyConfiguration = (
   socksProxy: text,
   socksVersion: 0..255,
)

session.PacProxyConfiguration = (
   proxyType: "pac",
   proxyAutoconfigUrl: text,
   Extensible
)

session.SystemProxyConfiguration = (
   proxyType: "system",
   Extensible
)

7.1.2.5. session.UserPromptHandler 类型

远程端定义 和 本地端定义

session.UserPromptHandler = {
  ? alert: session.UserPromptHandlerType,
  ? beforeUnload: session.UserPromptHandlerType,
  ? confirm: session.UserPromptHandlerType,
  ? default: session.UserPromptHandlerType,
  ? file: session.UserPromptHandlerType,
  ? prompt: session.UserPromptHandlerType,
}

session.UserPromptHandler 类型表示 用户提示处理程序的配置。

注: file 处理文件选择器。"accept" 和 "dismiss" 会关闭 选择器。"ignore" 会使选择器保持打开状态。

7.1.2.6. session.UserPromptHandlerType 类型

远程端定义 和 本地端定义

session.UserPromptHandlerType = "accept" / "dismiss" / "ignore";

session.UserPromptHandlerType 类型表示 用户提示处理程序的行为。

7.1.2.7. session.Subscription 类型
session.Subscription = text

session.Subscription 类型表示唯一的订阅标识符。

7.1.2.8. session.SubscribeParameters 类型
session.SubscribeParameters = {
  events: [+text],
  ? contexts: [+browsingContext.BrowsingContext],
  ? userContexts: [+browser.UserContext],
}

session.SubscribeParameters 类型表示 订阅一组特定事件的请求。

7.1.2.9. session.UnsubscribeByIDRequest 类型
session.UnsubscribeByIDRequest = {
  subscriptions: [+session.Subscription],
}

session.UnsubscribeByIDRequest 类型表示 移除由订阅 ID 标识的事件订阅的请求。

7.1.2.10. session.UnsubscribeByAttributesRequest 类型
session.UnsubscribeByAttributesRequest = {
  events: [+text],
}

session.UnsubscribeByAttributesRequest 类型表示 使用订阅属性取消订阅的请求。

7.1.3. 命令

7.1.3.1. session.status 命令

session.status 命令返回关于 远端是否处于可创建新会话状态的信息, 但也可以另外包含特定于实现的任意元信息。

这是一个静态命令。

命令类型
session.Status = (
  method: "session.status",
  params: EmptyParams,
)
返回类型
session.StatusResult = {
  ready: bool,
  message: text,
}

给定 session 和 command parameters 时,远端步骤为:

  1. 令 body 为一个具有以下属性的新映射:

    "ready"
    远端的就绪状态。
    "message"
    一个实现定义的字符串,用于解释远端的 就绪状态。
  2. 返回带有数据 body 的成功

7.1.3.2. session.new 命令

session.new 命令允许创建新的 BiDi 会话。

注:以这种方式创建的会话将不能 通过 HTTP 访问。

这是一个静态命令。

命令类型
session.New = (
  method: "session.new",
  params: session.NewParameters
)

session.NewParameters = {
  capabilities: session.CapabilitiesRequest
}
返回类型
session.NewResult = {
  sessionId: text,
  capabilities: session.CapabilityResponse
}

给定 session 和 command parameters 时,远端步骤为:

  1. 如果 session 不是 null,则返回一个错误,错误 代码为 session not created。

  2. 如果实现因任何原因无法启动新会话,则返回 一个错误,错误代码为 session not created。

  3. 令 flags 为一个包含 "bidi" 的集合。

  4. 令 capabilities json 为使用 command parameters 和 flags 尝试处理能力 所得的结果。

  5. 令 capabilities 为用 capabilities json 调用将 JSON 派生的 JavaScript 值转换为 Infra 值的结果。

  6. 令 session 为使用 capabilities 和 flags 尝试创建会话所得的结果。

  7. 将 session 的 BiDi 标志设置为 true。

    注:此会话的连接将由调用者设置为当前连接。

  8. 令 body 为一个新的映射, 它与 session.NewResult 产生式匹配, 其 sessionId 字段设置为 session 的会话 ID,并且 capabilities 字段设置为 capabilities。

  9. 返回带有数据 body 的成功。

7.1.3.3. session.end 命令

session.end 命令结束当前 会话。

命令类型
session.End = (
  method: "session.end",
  params: EmptyParams
)

返回类型
session.EndResult = EmptyResult

给定 session 和 command parameters 时,远端步骤为:

  1. 使用 session 结束会话。

  2. 返回带有数据 null 的成功,并并行运行以下 步骤:

    1. 等到发送 WebSocket 消息步骤已使用 对此命令的 响应被调用。

      这 是相当不精确的语言,但希望意图很清楚: 在开始关闭连接之前,我们要先发送命令响应。

    2. 使用 session 清理会话。

7.1.3.4. session.subscribe 命令

session.subscribe 命令会全局地或针对一组 navigable 启用某些事件。

这需要 泛化,以便也适用于 realm。

命令类型
session.Subscribe = (
  method: "session.subscribe",
  params: session.SubscribeParameters
)
返回类型
session.SubscribeResult = {
  subscription: session.Subscription,
}
给定 session 和 command parameters 时,远端步骤为:
  1. 令 event names 为空集合。

  2. 对于 command parameters["events"] 中的每个条目 name,令 event names 为 event names 与尝试用 name 获得一组 事件名称的结果的并集。

  3. 令 input user context ids 为用 command parameters[userContexts] 创建集合所得的结果。

  4. 令 input context ids 为用 command parameters[contexts] 创建集合所得的结果。

  5. 如果 input user context ids 非空且 input context ids 非空, 则返回带有错误 代码 invalid argument 的错误。

  6. 令 subscription navigables 为一个集合。

  7. 令 top-level traversable context ids 为一个集合。

  8. 如果 input context ids 非空:

    1. 令 navigables 为尝试用 input context ids 通过 id 获取有效 navigables的结果。

    2. 将 subscription navigables 设置为用 navigables 调用获取 顶级 traversables的结果。

    3. 对于 subscription navigables 中的每个 navigable:

      1. 将 navigable 的navigable id 追加到 top-level traversable context ids。

  9. 否则,如果 input user context ids 非空:

    1. 对于 input user context ids 中的每个 user context id:

      1. 令 user context 为用 user context id 调用获取用户上下文的结果。

      2. 如果 user context 为 null,则返回带有错误代码 no such user context 的错误。

      3. 对于所有其关联用户上下文为 user context 的顶级 traversable列表中的每个 top-level traversable:

        1. 将 top-level traversable 追加到 subscription navigables。

  10. 否则,将 subscription navigables 设置为远端中所有 顶级 traversable组成的集合。

  11. 令 subscription 为一个订阅,其 订阅 id设置为 UUID 的字符串表示, 事件名称设置为 event names, 顶级 traversable id设置为 top-level traversable context ids,并且 用户上下文 id设置为 input user context ids。

  12. 令 subscribe step events 为一个新的映射。

  13. 对于 event names 中的每个 event name:

    1. 如果事件(其事件 名称为 event name)没有定义远端订阅步骤, 则继续;

    2. 令 existing navigables 为使用 session 和 event name 调用启用了某个事件的顶级 traversable 集合的结果。

    3. 将 subscribe step events[event name] 设置为 subscription navigables 与 existing navigables 的差集。

  14. 将 subscription 追加到 session 的订阅。

  15. 将 subscription 的订阅 id追加到 session 的已知订阅 id。

  16. 使用以下小于算法,按升序排序 subscribe step events;给定两个键为 event name one 和 event name two 的条目:

    1. 令 event one 为名称为 event name one 的事件

    2. 令 event two 为名称为 event name two 的事件

    3. 如果 event one 的订阅 优先级小于 event two 的订阅优先级,则返回 true,否则返回 false。

  17. 如果 subscription 是全局的,则令 include global 为 true, 否则令 include global 为 false。

  18. 对于 subscribe step events 中的每个 event name → navigables:

    1. 对事件(其事件 名称为 event name)运行远端订阅步骤,给定 session、navigables 和 include global。

  19. 令 body 为一个新的映射, 它与 session.SubscribeResult 产生式匹配, 其 subscription 字段设置为 subscription 的订阅 id。

  20. 返回带有数据 body 的成功。

7.1.3.5. session.unsubscribe 命令

session.unsubscribe 命令会全局地或针对一组 navigable 禁用事件。

这需要 泛化,以便也适用于 realm。

命令类型
session.Unsubscribe = (
  method: "session.unsubscribe",
  params: session.UnsubscribeParameters,
)

session.UnsubscribeParameters = session.UnsubscribeByAttributesRequest / session.UnsubscribeByIDRequest
返回类型
session.UnsubscribeResult = EmptyResult
给定 session 和 command parameters 时,远端步骤为:
  1. 如果 command parameters 不包含 "subscriptions":

    注:该条件意味着 command parameters 与 session.UnsubscribeByAttributesRequest 产生式匹配。

    1. 令 event names 为空集合。

    2. 对于 command parameters["events"] 中的每个条目 name, 令 event names 为 event names 与尝试用 name 获得 一组事件名称所得结果的并集。

    3. 令 new subscriptions 为一个列表。

    4. 令 matched events 为一个集合。

    5. 对于 session 的订阅中的每个 subscription:

      1. 如果 subscription 的 事件名称与 event names 的交集是一个空集合:

        1. 将 subscription 追加到 new subscriptions。

        2. 继续。

      2. 如果 subscription 不是全局的:

        1. 将 subscription 追加到 new subscriptions。

        2. 继续。

      3. 令 subscription event names 为 subscription 的事件名称的克隆。

      4. 对于 event names 中的每个 event name:

        1. 如果 subscription event names 包含 event name:

          1. 将 event name 追加到 matched events。

          2. 从 subscription event names 中移除 event name。

      5. 如果 subscription event names 非空:

        1. 令 cloned subscription 为一个订阅,其 订阅 id设置 为 subscription 的订阅 id, 事件名称设置为一个新的 集合,其中包含 subscription event names。

        2. 将 cloned subscription 追加到 new subscriptions。

    6. 如果 matched events 不 等于 event names,则返回 错误,其 错误码 为 无效参数。

    7. 将 session 的订阅设置为 new subscriptions。

  2. 否则:

    1. 令 subscriptions 为用 command parameters[subscriptions] 创建 集合所得的结果。

    2. 令 unknown subscription ids 为 subscriptions 与 session 的已知订阅 id之间的差集。

    3. 如果 unknown subscription ids 非空:

      1. 返回带有错误代码 invalid argument 的错误。

    4. 令 subscriptions to remove 为空集合。

    5. 对于 session 的订阅中的每个 subscription:

      1. 如果 subscriptions 包含 subscription 的订阅 id:

        1. 将 subscription 追加到 subscriptions to remove。

    6. 将 session 的已知订阅 id设置为 session 的已知订阅 id与 subscriptions之间的差集。

    7. 从 session 的订阅中移除 subscriptions to remove 中的每一项。

  3. 返回带有数据 null 的成功。

7.2. browser 模块

browser 模块包含用于 管理远端浏览器进程的命令。

7.2.1. 定义

远端定义

BrowserCommand = (
  browser.Close //
  browser.CreateUserContext //
  browser.GetClientWindows //
  browser.GetUserContexts //
  browser.RemoveUserContext //
  browser.SetClientWindowState //
  browser.SetDownloadBehavior
)

本地端定义

BrowserResult = (
  browser.CloseResult /
  browser.CreateUserContextResult /
  browser.GetClientWindowsResult /
  browser.GetUserContextsResult /
  browser.RemoveUserContextResult /
  browser.SetClientWindowStateResult /
  browser.SetDownloadBehaviorResult
)

7.2.2. 窗口

每个顶级 traversable都关联到单个客户端 窗口,该窗口表示一个矩形区域,其中包含 用于在其可见性状态为 "visible" 时渲染该顶级 traversable的活动文档的视口,以及与显示该 traversable 相关联的任何浏览器特定用户界面元素 (例如任何 URL 栏、工具栏或 OS 窗口装饰)。

客户端窗口具有一个客户端窗口 id,它是唯一 标识该窗口的字符串。

客户端窗口具有一个x 坐标,它是 Web 暴露屏幕区域左边缘与窗口左边缘之间的 CSS 像素数,若这对于某个 特定窗口没有意义则为零。

客户端窗口具有一个y 坐标,它是 Web 暴露屏幕区域上边缘与窗口上边缘之间的 CSS 像素数,若这对于某个 特定窗口没有意义则为零。

客户端窗口具有一个宽度,它是 窗口矩形的宽度,以 CSS 像素计。

客户端窗口具有一个高度,它是 窗口矩形的高度,以 CSS 像素计。

要最大化 客户端窗口 window,实现应当要么 执行与平台最大化 window 概念相对应的步骤,要么 定位 window,使其x 坐标尽可能接近 0,其y 坐标尽可能接近 0, 其宽度尽可能接近 Web 暴露屏幕区域的宽度,且其高度尽可能接近 Web 暴露屏幕区域的高度。如果支持这两个选项中的任一个, 则支持最大化客户端窗口。

要最小化 客户端窗口 window,实现应当要么 执行与平台最小化 window 概念相对应的步骤,要么 以其他方式隐藏 window,使得与 window 关联的 顶级 traversable中的所有活动文档都具有 "hidden" 的可见性状态,并且 window 的宽度和高度都尽可能接近 0。如果支持这两个 选项中的任一个,则支持最小化客户端窗口。

要还原 客户端窗口 window,实现应确保它 既不处于平台定义的最大化状态,也不处于平台定义的 最小化状态,并且如果存在一个或多个与 window 关联的顶级 traversable, 其中至少一个具有处于 "visible" 状态的活动文档。如果支持这一点,则支持还原客户端 窗口。

要在给定 window 的情况下获取 客户端窗口状态:

  1. 令 documents 为空列表。

  2. 令 visible documents 为空列表。

  3. 对于每个顶级 traversable traversable:

    1. 如果 traversable 的客户端窗口不是 window,则 继续。

    2. 令 document 为 traversable 的活动文档。

    3. 将 document 追加到 documents。

    4. 如果 document 的可见性状态为 "visible", 则将 document 追加到 visible documents。

  4. 对于 visible documents 中的每个 document:

    1. 如果 document 的全屏元素不是 null,则返回 "fullscreen"。

  5. 如果 visible documents 为空但 documents 不是 空,或者如果 window 以其他方式处于特定于 OS 的 最小化状态,则返回 "minimized"。

    注:这通常但不一定意味着 window 的宽度和高度等于 0。

  6. 如果 window 处于特定于 OS 的最大化状态,则返回 "maximized"。

    注:这通常但不一定意味着 window 的宽度等于Web 暴露屏幕区域的宽度,并且 window 的高度等于 Web 暴露屏幕区域的高度。

  7. 返回 "normal"。

要在给定 window 和 state 的情况下设置 客户端窗口状态:

  1. 令 current state 为使用 window 获取客户端窗口状态的结果。

  2. 如果 current state 是 "fullscreen"、"maximized" 或 "minimized",且等于 state,则返回带有数据 null 的成功。

  3. 在以下条件及其关联步骤列表中,运行第一个关联条件为 true 的步骤集:

    "fullscreen"
    如果不支持全屏,则返回带有错误代码 unsupported operation 的错误。
    "normal"
    如果对于 window 不支持还原客户端窗口, 则返回带有 错误代码 unsupported operation 的错误。
    "maximize"
    如果对于 window 不支持最大化客户端窗口, 则返回带有 错误代码 unsupported operation 的错误。
    "minimize"
    如果对于 window 不支持最小化客户端窗口, 则返回带有 错误代码 unsupported operation 的错误。
  4. 令 documents 为空列表。

  5. 对于每个顶级 traversable traversable:

    1. 如果 traversable 的关联客户端窗口不是 window,则 继续。

    2. 令 document 为 traversable 的活动文档。

    3. 将 document 追加到 documents。

  6. 如果 documents 为空,则返回 带有错误 代码 no such client window 的错误。

  7. 如果 current state 是 "fullscreen":

    1. 对于 documents 中的每个 document:

      1. 使用 document 完全退出全屏。

        注:对于窗口中并非全屏的 文档,这是无操作。

  8. 如果 current state 是 "maximized" 或 "minimized":

    1. 还原客户端窗口 window。

  9. 根据 state 的值进行切换:

    "fullscreen"
    1. 对于 documents 中的每个 document:

      1. 如果 document 的可见性状态为 "visible", 则使用 document 的document element使元素全屏。

      2. 中断。

    "maximize"
    1. 最大化客户端窗口 window。
    "minimize"
    1. 最小化客户端窗口 window。
  10. 返回带有数据 null 的成功。

7.2.3. 类型

7.2.3.1. browser.ClientWindow 类型
browser.ClientWindow = text;

browser.ClientWindow 唯一标识一个客户端窗口。

7.2.3.2. browser.ClientWindowInfo 类型
browser.ClientWindowInfo = {
  active: bool,
  clientWindow: browser.ClientWindow,
  height: js-uint,
  state: "fullscreen" / "maximized" / "minimized" / "normal",
  width: js-uint,
  x: js-int,
  y: js-int,
}

browser.ClientWindowInfo 类型表示 客户端窗口的属性。

要在给定 client window 的情况下获取客户端 窗口信息:
  1. 令 client window id 为 client window 的客户端窗口 id。

  2. 令 state 为使用 client window 调用获取客户端窗口状态的结果。

  3. 如果 client window 能够接收从操作系统传送来的键盘输入, 则令 active 为 true,否则令 active 为 false。

    注:这可能意味着某个顶级 traversable(其客户端窗口是 client window)具有系统焦点,也可能意味着浏览器自身的 用户界面当前具有焦点。

  4. 令 client window info 为一个映射, 它与 browser.ClientWindowsInfo 产生式匹配,其 clientWindow 字段设置为 client window id,state 字段设置为 state,x 字段设置为 client window 的 x 坐标,y 字段设置为 client window 的y 坐标,width 字段设置 为 client window 的宽度,height 字段 设置为 client window 的高度,且 active 字段设置为 active。

  5. 返回 client window info

7.2.3.3. browser.UserContext 类型
browser.UserContext = text;

browser.UserContext 唯一标识一个用户 上下文。

7.2.3.4. browser.UserContextInfo 类型
browser.UserContextInfo = {
  userContext: browser.UserContext
}

browser.UserContextInfo 类型表示用户上下文的属性。

7.2.4. 命令

7.2.4.1. browser.close 命令

browser.close 命令终止所有 WebDriver 会话,并清理远程浏览器实例中的自动化状态。

命令类型
browser.Close = (
  method: "browser.close",
  params: EmptyParams,
)
返回类型
browser.CloseResult = EmptyResult
给定 session 和 command parameters 时,远端步骤为:
  1. 使用 session 结束会话。

  2. 如果活动会话不是空,实现可以 返回带有错误 代码 unable to close browser 的错误,然后 并行运行以下步骤:

    1. 等到发送 WebSocket 消息步骤已使用 对此命令的 响应被调用。

    2. 使用 session 清理会话。

    注:当浏览器具有多个自动化 会话时的行为目前未指定。可能是任何会话都可以关闭 浏览器,也可能只有最后一个打开的会话才能实际关闭浏览器, 或者只有第一个启动的会话可以。此行为可能会在本规范的未来版本中 完全指定。

  3. 对于活动会话中的每个 active session:

    1. 结束 会话 active session。

    2. 使用 active session 清理会话

  4. 返回带有数据 null 的成功,并并行运行以下步骤。

    1. 等到发送 WebSocket 消息步骤已使用 对此命令的 响应被调用。

    2. 使用 session 清理会话。

    3. 在不提示卸载的情况下关闭任何顶级 traversable。

    4. 执行实现定义的步骤,以清理与自动化控制下的远端关联的资源。

      注:例如,这可能包括 干净地关闭与自动化控制下的浏览器关联的任何 OS 级 进程、移除临时 状态(例如远端在自动化控制期间创建的用户配置文件数据), 或关闭WebSocket 监听器。由于 浏览器和操作系统之间存在差异,无法在这里详细 指定本地端可依赖的精确不变式。

7.2.4.2. browser.createUserContext 命令

browser.createUserContext 命令创建一个 用户上下文。

命令类型
browser.CreateUserContext = (
  method: "browser.createUserContext",
  params: browser.CreateUserContextParameters,
)

browser.CreateUserContextParameters = {
  ? acceptInsecureCerts: bool,
  ? proxy: session.ProxyConfiguration,
  ? unhandledPromptBehavior: session.UserPromptHandler
}
返回类型
browser.CreateUserContextResult = browser.UserContextInfo

给定 session 和 command parameters 时,远端步骤为:

  1. 令 user context 为一个新的用户上下文。

  2. 如果 command parameters 包含 "acceptInsecureCerts":

    注:如果设置了 "acceptInsecureCerts", 它会覆盖 接受不安全 TLS 标志的行为。

    1. 令 acceptInsecureCerts 为 command parameters["acceptInsecureCerts"]:

    2. 如果 acceptInsecureCerts 为 true,且端点节点不支持 接受不安全 TLS 连接,则返回带有 错误代码 unsupported operation 的错误。

    3. 将 session 的 用户上下文到接受不安全证书覆盖映射[user context] 设置为 acceptInsecureCerts。

  3. 如果 command parameters 包含 "unhandledPromptBehavior", 则将未处理提示行为覆盖 映射[user context] 设置为 command parameters["unhandledPromptBehavior"]。

  4. 如果 command parameters 包含 "proxy":

    1. 令 proxy configuration 为 command parameters["proxy"]。

    2. 如果远端无法按用户 上下文配置代理设置, 或无法用 proxy configuration 配置代理,则返回带有 错误代码 unsupported operation 的错误。

    3. 将 session 的 用户上下文到代理 配置映射[user context] 设置为 proxy configuration。

  5. 将 user context 追加到用户上下文集合。

  6. 令 user context info 为一个映射, 它与 browser.UserContextInfo 产生式匹配,其 userContext 字段设置为 user context 的用户上下文 id。

  7. 返回带有数据 user context info 的成功。

7.2.4.3. browser.getClientWindows 命令

browser.getClientWindows 命令返回 客户端窗口列表。

命令类型
browser.GetClientWindows = (
  method: "browser.getClientWindows",
  params: EmptyParams,
)
返回类型
browser.GetClientWindowsResult = {
  clientWindows: [ * browser.ClientWindowInfo]
}

远端步骤为:

  1. 令 client window ids 为空集合。

  2. 令 client windows 为空列表。

  3. 对于每个顶级 traversable traversable:

    1. 令 client window 为 traversable 的关联客户端 窗口

    2. 令 client window id 为 client window 的客户端窗口 id。

    3. 如果 client window ids 包含 client window id,则继续。

    4. 将 client window id 追加到 client window ids。

    5. 令 client window info 为使用 client window 调用获取 客户端窗口信息的结果。

    6. 将 client window info 追加到 client windows。

  4. 令 result 为一个映射, 它与 browser.GetClientWindowsResult 产生式匹配,其 clientWindows 字段设置为 client windows。

  5. 返回带有数据 result 的成功。

7.2.4.4. browser.getUserContexts 命令

browser.getUserContexts 命令返回 用户上下文列表。

命令类型
browser.GetUserContexts = (
  method: "browser.getUserContexts",
  params: EmptyParams,
)
返回类型
browser.GetUserContextsResult = {
  userContexts: [ + browser.UserContextInfo]
}

远端步骤为:

  1. 令 user contexts 为空列表。

  2. 对于用户上下文集合中的每个 user context:

    1. 令 user context info 为一个映射, 它与 browser.UserContextInfo 产生式匹配,其 userContext 字段设置为 user context 的用户 上下文 id。

    2. 将 user context info 追加到 user contexts。

  3. 令 result 为一个映射, 它与 browser.GetUserContextsResult 产生式匹配,其 userContexts 字段设置为 user contexts。

  4. 返回带有数据 result 的成功。

7.2.4.5. browser.removeUserContext 命令

browser.removeUserContext 命令关闭一个 用户上下文及其中的所有 navigable,且不运行 beforeunload 处理程序。

命令类型
browser.RemoveUserContext = (
  method: "browser.removeUserContext",
  params: browser.RemoveUserContextParameters
)

browser.RemoveUserContextParameters = {
  userContext: browser.UserContext
}
返回类型
browser.RemoveUserContextResult = EmptyResult

给定 command parameters 时,远端步骤为:

  1. 令 user context id 为 command parameters["userContext"]。

  2. 如果 user context id 是 "default",则返回带有错误代码 invalid argument 的错误。

  3. 将 user context 设置为用 user context id 调用获取用户上下文的结果。

  4. 如果 user context 为 null,则返回带有错误代码 no such user context 的错误。

  5. 对于每个顶级 traversable navigable:

    1. 如果 navigable 的关联用户上下文是 user context:

      1. 在不提示卸载的情况下关闭 navigable。

  6. 从用户上下文集合中移除 user context。

  7. 返回带有数据 null 的成功。

7.2.4.6. browser.setClientWindowState 命令

browser.setClientWindowState 命令设置 客户端 窗口的尺寸。

命令类型
browser.SetClientWindowState = (
  method: "browser.setClientWindowState",
  params: browser.SetClientWindowStateParameters
)

browser.SetClientWindowStateParameters = {
  clientWindow: browser.ClientWindow,
  (browser.ClientWindowNamedState // browser.ClientWindowRectState)
}

browser.ClientWindowNamedState = (
  state: "fullscreen" / "maximized" / "minimized"
)

browser.ClientWindowRectState = (
  state: "normal",
  ? width: js-uint,
  ? height: js-uint,
  ? x: js-int,
  ? y: js-int,
)
返回类型
browser.SetClientWindowStateResult = browser.ClientWindowInfo

给定 session 和 command parameters 时,远端步骤为:

  1. 如果实现完全不支持设置客户端窗口状态, 则返回带有错误 代码 unsupported operation 的错误。

  2. 如果存在一个客户端 窗口,其客户端窗口 id 为 command parameters["clientWindow"],则令 client window 为该客户端窗口。 否则返回带有错误 代码 no such client window 的错误。

  3. 尝试使用 client window 和 command parameters["state"] 设置客户端窗口状态。

  4. 如果 command parameters["state"] 是 "normal":

    1. 如果 command parameters 包含 "x",并且 实现支持定位客户端窗口,则将 client window 的x 坐标设置为尽可能接近 command parameters["x"] 的值。

    2. 如果 command parameters 包含 "y",并且 实现支持定位客户端窗口,则将 client window 的y 坐标设置为尽可能接近 command parameters["y"] 的值。

    3. 如果 command parameters 包含 "width",并且 实现支持调整客户端窗口大小,则将 client window 的宽度设置为尽可能接近 command parameters["width"] 的值。

    4. 如果 command parameters 包含 "width",并且 实现支持调整客户端窗口大小,则将 client window 的宽度设置为尽可能接近 command parameters["width"] 的值。

  5. 令 client window info 为使用 client window 调用获取客户端窗口信息的结果。

  6. 返回带有数据 client window info 的成功。

注:为简单起见,这里将所有客户端窗口 操作都建模为 同步。因此,返回的客户端窗口尺寸预期是 窗口达到其新状态之后的尺寸。

7.2.4.7. browser.setDownloadBehavior 命令

下载行为 结构体是一个具有以下内容的结构体:

远端具有一个下载行为,它是一个结构体,具有一个 名为 default download behavior 的项,它是一个 下载 行为结构体或 null,以及一个名为 user context download behavior 的项,它是 用户上下文与下载 行为结构体之间的弱映射。

命令类型
browser.SetDownloadBehavior = (
  method: "browser.setDownloadBehavior",
  params: browser.SetDownloadBehaviorParameters
)

browser.SetDownloadBehaviorParameters = {
  downloadBehavior: browser.DownloadBehavior / null,
  ? userContexts: [+browser.UserContext]
}

browser.DownloadBehavior = {
  (
    browser.DownloadBehaviorAllowed //
    browser.DownloadBehaviorDenied
  )
}

browser.DownloadBehaviorAllowed = (
  type: "allowed",
  destinationFolder: text
)

browser.DownloadBehaviorDenied = (
  type: "denied"
)
返回类型
browser.SetDownloadBehaviorResult = EmptyResult
要在给定 navigable 的情况下获取下载 行为:
  1. 令 user context 为 navigable 的关联用户 上下文。

  2. 如果下载 行为的user context download behavior 包含 user context,则返回下载行为的 user context download behavior[user context]。

  3. 返回下载 行为的default download behavior。

给定 session 和 command parameters 时,远端步骤为:

  1. 如果 command parameters["downloadBehavior"] 为 null,则令 download behavior 为 null。

  2. 否则:

    1. 如果 command parameters["downloadBehavior"]["type"] 是 "allowed",则令 allowed 为 true,否则令 allowed 为 false。

    2. 如果 command parameters["downloadBehavior"] 包含 "destinationFolder",则令 destinationFolder 为 command parameters["downloadBehavior"]["destinationFolder"], 否则令 destinationFolder 为 null。

    3. 令 download behavior 为一个下载 行为结构体,其 allowed 设置为 allowed, 且 destinationFolder 设置 为 destinationFolder。

  3. 如果实现不支持所需的 download behavior,则返回 带有错误 代码 unsupported operation 的错误。

  4. 如果 command parameters 的 userContexts 字段存在:

    1. 令 user contexts 为尝试用 command parameters["userContexts"] 获取有效用户上下文 所得的结果。

    2. 对于 user contexts 中的每个 user context:

      1. 如果 download behavior 为 null,则从下载行为的 user context download behavior中移除 user context。

      2. 否则,将下载 行为的 user context download behavior[user context] 设置为 download behavior。

  5. 否则,将下载行为的default download behavior设置为 download behavior。

  6. 返回带有数据 null 的成功。

7.3. browsingContext 模块

browsingContext 模块包含与navigable相关的命令和 事件。

注:由于历史原因,此模块称为 browsingContext 而不是 navigable,并且协议使用术语 context 来指代 navigable,尤其是作为命令 和响应参数中的字段时。

导航进度使用一个不可变结构体 WebDriver BiDi 导航状态来传达,它具有以下项:

id
该导航的导航 id,或者当导航在取得进展前被 取消时为 null。
status
一个状态码,其值为 "canceled"、 "pending" 或 "complete"。
url
导航中正在加载的 URL
suggestedFilename
如果导航是下载,则为建议的文件名,否则为 null。
downloadedFilepath
如果导航是已完成的下载,且下载文件可用,则为已下载文件的 绝对文件路径,否则为 null。
downloadResponse
如果导航是下载,则为响应, 否则为 null。

7.3.1. 定义

远端定义

BrowsingContextCommand = (
  browsingContext.Activate //
  browsingContext.CaptureScreenshot //
  browsingContext.Close //
  browsingContext.Create //
  browsingContext.GetTree //
  browsingContext.HandleUserPrompt //
  browsingContext.LocateNodes //
  browsingContext.Navigate //
  browsingContext.Print //
  browsingContext.Reload //
  browsingContext.SetBypassCSP //
  browsingContext.SetViewport //
  browsingContext.StartScreencast //
  browsingContext.StopScreencast //
  browsingContext.TraverseHistory
)

本地端定义

BrowsingContextResult = (
  browsingContext.ActivateResult /
  browsingContext.CaptureScreenshotResult /
  browsingContext.CloseResult /
  browsingContext.CreateResult /
  browsingContext.GetTreeResult /
  browsingContext.HandleUserPromptResult /
  browsingContext.LocateNodesResult /
  browsingContext.NavigateResult /
  browsingContext.PrintResult /
  browsingContext.ReloadResult /
  browsingContext.SetBypassCSPResult /
  browsingContext.SetViewportResult /
  browsingContext.StartScreencastResult /
  browsingContext.StopScreencastResult /
  browsingContext.TraverseHistoryResult
)

BrowsingContextEvent = (
  browsingContext.ContextCreated //
  browsingContext.ContextDestroyed //
  browsingContext.DomContentLoaded //
  browsingContext.DownloadEnd //
  browsingContext.DownloadWillBegin //
  browsingContext.FragmentNavigated //
  browsingContext.HistoryUpdated //
  browsingContext.Load //
  browsingContext.NavigationAborted //
  browsingContext.NavigationCommitted //
  browsingContext.NavigationFailed //
  browsingContext.NavigationStarted //
  browsingContext.UserPromptClosed //
  browsingContext.UserPromptOpened
)

远端具有device pixel ratio 覆盖,它是 navigable与 device pixel ratio 覆盖之间的弱映射。其初始为空。

注:此映射不会在最终会话 结束时清除;即 device pixel ratio 覆盖会比任何 WebDriver 会话存活更久。

viewport 尺寸是一个具有以下内容的结构体:

viewport 配置是一个具有以下内容的结构体:

未处理 提示行为结构体是一个具有以下内容的结构体:

远端具有viewport 覆盖映射,它是用户上下文与viewport 配置之间的弱映射。

远端具有locale 覆盖映射,它是 navigable或用户上下文与字符串之间的弱映射。

screen settings 是一个 结构体,具有 一个名为 height 的项,它是整数; 一个名为 width 的项,它是整数; 一个名为 x 的项,它是整数; 一个名为 y 的项,它是整数。

远端具有screen settings 覆盖,它是一个结构体,具有 一个名为 user context screen settings 的项, 它是用户 上下文与screen settings之间的弱映射, 以及一个名为 navigable screen settings 的项, 它是navigable与screen settings之间的弱映射。

远端具有timezone 覆盖映射,它是 navigable或用户上下文与字符串之间的弱映射。

远端具有一个未处理提示行为覆盖映射, 它是 用户上下文与 未处理提示行为结构体之间的 弱映射。

远端具有scripting enabled 覆盖映射,它是 navigable或用户上下文与 boolean 之间的弱映射。

一个远程端具有一个 下载 ID 映射,它是 响应和下载 ID 之间的弱映射。它初始为空。

一个 屏幕录制流 是 顶级可遍历的视口的抽象流,由一个 视频轨道组成, 其包含该顶级可遍历的文档视口的已渲染视觉输出, 以及可选的一个 音频轨道,其包含该 顶级可遍历的文档的音频输出。

一个 BiDi 会话具有一个 屏幕录制映射,它是一个映射,其中键是 UUID,值是 屏幕录制; 后者是一个具有 一个名为 stream 的项的结构体,该项是一个屏幕录制流, 一个名为 path 的项,该项是字符串, 一个名为 state 的项,该项是 "recording"、"stopping"、"stopped" 之一, 以及一个名为 writeError 的项,该项是字符串或 null。

要在给定屏幕录制 recording 和 mime type 的情况下,启动屏幕录制:
  1. 并行运行以下步骤:

    1. 开始使用 mime type 对 recording 的stream进行编码, 生成连续的编码数据块,作为字节 序列。 当 recording 的state 为 "recording" 时, 以实现定义的间隔生成一个新块。

    2. 对于为 recording 生成的每个块 bytes,运行以下 步骤:

      1. 将 bytes 追加到 recording 的path处的文件。 如果失败:

        1. 将 recording 的writeError 设为一个 描述写入失败的实现定义字符串。

        2. 给定 recording,停止屏幕录制。

要在给定屏幕录制 recording 的情况下,停止屏幕录制:
  1. 如果 recording 的state 不是 "recording",则 返回。

  2. 将 recording 的state 设为 "stopping"。

  3. 停止为 recording 生成新块,刷新任何剩余的已编码 数据作为最后一个块(按启动屏幕录制中的方式处理), 停止从 recording 的stream 捕获,并 释放其 视频轨道以及(如果存在)其 音频轨道,然后将 recording 的 state 设为 "stopped"。

  4. 等待,直到 recording 的state 为 "stopped"。

7.3.2. 类型

7.3.2.1. browsingContext.BrowsingContext 类型

远端定义 和 本地端定义

browsingContext.BrowsingContext = text;

每个navigable都具有一个关联的navigable id, 它是唯一标识该 navigable 的字符串。它会在 navigable 创建时被隐式设置。对于具有关联 WebDriver 窗口句柄的 navigable,navigable id 必须与 窗口句柄相同。

每个navigable还具有一个关联存储分区, 它是其用于持久化数据的存储 分区。

每个navigable还具有一个关联的original opener, 它是导致该 navigable 打开的navigable 或 null,初始设置为 null。

要在给定 navigable id 的情况下获取 navigable:
  1. 如果 navigable id 为 null,则返回带有数据 null 的成功。

  2. 如果不存在navigable id 为 navigable id 的 navigable,则返回 带有错误 代码 no such frame 的错误

  3. 令 navigable 为 id 为 navigable id 的navigable。

  4. 返回带有数据 navigable 的成功。

7.3.2.2. browsingContext.Info 类型

本地端定义

browsingContext.InfoList = [*browsingContext.Info]

browsingContext.BaseInfo = (
  children: browsingContext.InfoList / null,
  clientWindow: browser.ClientWindow,
  context: browsingContext.BrowsingContext,
  originalOpener: browsingContext.BrowsingContext / null,
  url: text,
  userContext: browser.UserContext,
  ? parent: browsingContext.BrowsingContext / null,
)

browsingContext.Info = {
  browsingContext.BaseInfo
}

browsingContext.Info 类型表示 navigable 的属性。

要在给定 navigable 的情况下获取子 navigable:

TODO:使其按文档顺序返回列表

  1. 令 child navigables 为一个集合, 包含所有作为 navigable 的子 navigable的 navigable。

  2. 返回 child navigables。

要在给定 navigable、 max depth 和 include parent id 的情况下获取 navigable 信息:
  1. 令 navigable id 为 navigable 的navigable id。

  2. 令 parent navigable 为 navigable 的父级。

  3. 如果 parent navigable 非 null,则令 parent id 为 parent navigable 的navigable id。否则令 parent id 为 null。

  4. 令 document 为 navigable 的活动文档。

  5. 令 url 为在给定 document 的URL的情况下运行 URL 序列化器所得的结果。

    注:这包括 URL 的片段组成部分。

  6. 令 child infos 为 null。

  7. 如果 max depth 为 null,或 max depth 大于 0:

    1. 令 child navigables 为给定 navigable 时调用获取子 navigable的结果。

    2. 如果 max depth 非 null,则令 child depth 为 max depth - 1, 否则为 null。

    3. 将 child infos 设置为空列表。

    4. 对于 child navigables 中的每个 child navigable:

      1. 令 info 为给定 child navigable、child depth 和 false 时调用获取 navigable 信息的结果。

      2. 将 info 追加到 child infos

  8. 令 user context 为 navigable 的关联用户 上下文。

  9. 如果 navigable 的original opener 非 null, 则令 opener id 为 navigable 的 original opener的navigable id, 否则为 null。

  10. 令 top-level traversable 为 navigable 的顶级 traversable。

  11. 令 client window id 为 top-level traversable 的关联客户端窗口的客户端窗口 id。

  12. 令 navigable info 为一个映射, 它与 browsingContext.Info 产生式匹配,其中 context 字段设置为 navigable id;如果 include parent id 为 true,则 parent 字段设置为 parent id,否则不设置; url 字段设置为 url;userContext 字段设置 为 user context 的用户上下文 id;originalOpener 字段 设置为 opener id;children 字段设置为 child infos;且 clientWindow 字段设置为 client window id。

  13. 返回 navigable info。

要在给定 navigable、request、wait condition, 以及可选的 history handling(默认值:"default")和 ignore cache(默认值:false)的情况下 等待导航:
  1. 令 navigation id 为一个基于真正随机数或 伪随机数的 UUID 的字符串表示。

  2. 用资源 request 导航 navigable, 并使用 navigable 的活动文档作为来源 Document, 导航时使用 navigation id navigation id 和 历史处理行为 history handling。如果 ignore cache 为 true, 则该导航不得从 HTTP 缓存加载资源。

    准确 指定 ignore cache 标志如何工作。这需要 考虑是否只有资源的首次加载会绕过缓存 (即这是否类似于最初清除缓存然后像 通常一样继续),或者不是由 HTML 解析器直接加载的资源 (例如由脚本或样式表发起的加载)是否也会绕过缓存。

  3. 令(event received、navigation status)为在给定 «"navigation started", "navigation failed", "fragment navigated"» 和 navigation id 的情况下进行 await 的结果。

  4. 断言:navigation status 的id 是 navigation id。

  5. 如果 navigation status 的status 是 "complete":

    1. 令 body 为一个映射, 它与 browsingContext.NavigateResult 产生式匹配,其中 navigation 字段设置为 navigation id,且 url 字段设置为在给定 navigation status 的url时运行 URL 序列化器所得的结果。

    2. 返回带有数据 body 的成功。

    注:如果导航仅导致片段 改变,就是这种情况。

  6. 如果 navigation status 的status 是 "canceled", 则返回带有错误 代码 unknown error 的错误。

    TODO:这是在这里处理错误的正确方式吗?

  7. 断言:navigation status 的status 是 "pending",并且 navigation id 不是 null。

  8. 如果 wait condition 是 "committed",则令 event name 为 "committed"。

  9. 否则,如果 wait condition 是 "interactive",则令 event name 为 "domContentLoaded"。

  10. 否则,令 event name 为 "load"。

  11. 令(event received、status)为在给定 «event name, "download started", "navigation aborted", "navigation failed"» 和 navigation id 的情况下进行 await 的结果。

  12. 如果 event received 是 "navigation failed", 则返回带有错误 代码 unknown error 的错误。

    我们在这里用 错误暴露了足够多关于失败内容和原因的信息吗? 我们想要什么错误代码?本地端是否会解析实现定义的字符串 来弄清楚实际出了什么问题,从而造成问题?

  13. 令 body 为一个映射, 它与 browsingContext.NavigateResult 产生式匹配,其中 navigation 字段设置为 status 的 id,且 url 字段设置为在给定 status 的 url 时运行 URL 序列化器所得的结果。

  14. 返回带有数据 body 的成功。

7.3.2.3. browsingContext.Locator 类型

远端定义 和 本地端定义

browsingContext.Locator = (
   browsingContext.AccessibilityLocator /
   browsingContext.CssLocator /
   browsingContext.ContextLocator /
   browsingContext.InnerTextLocator /
   browsingContext.XPathLocator
)

browsingContext.AccessibilityLocator = {
   type: "accessibility",
   value: {
    ? name: text,
    ? role: text,
   }
}

browsingContext.CssLocator = {
   type: "css",
   value: text
}

browsingContext.ContextLocator = {
  type: "context",
  value: {
    context: browsingContext.BrowsingContext,
  }
}

browsingContext.InnerTextLocator = {
   type: "innerText",
   value: text,
   ? ignoreCase: bool
   ? matchType: "full" / "partial",
   ? maxDepth: js-uint,
}

browsingContext.XPathLocator = {
   type: "xpath",
   value: text
}

browsingContext.Locator 类型提供关于在文档中 定位节点的策略的详细信息。

7.3.2.4. browsingContext.Navigation 类型

远端定义 和 本地端定义

browsingContext.Navigation = text;

browsingContext.Navigation 类型是唯一标识正在进行的 导航的字符串。

TODO:链接到 HTML 规范中的定义。

7.3.2.5. browsingContext.Download 类型

远程端定义 和 本地端定义

browsingContext.Download = text;

browsingContext.Download 类型是标识下载的唯一字符串。

7.3.2.6. browsingContext.NavigationInfo 类型

本地端定义:

browsingContext.BaseNavigationInfo = (
  context: browsingContext.BrowsingContext,
  navigation: browsingContext.Navigation / null,
  timestamp: js-uint,
  url: text,
  ? userContext: browser.UserContext,
)

browsingContext.NavigationInfo = {
  browsingContext.BaseNavigationInfo
}

browsingContext.NavigationInfo 类型提供正在进行的导航的详细信息。

要在给定navigable navigable 和 导航状态 navigation status 的情况下 获取 导航信息:
  1. 令 navigable id 为 navigable 的navigable id。

  2. 令 navigation id 为 navigation status 的id。

  3. 令 timestamp 为表示当前 UTC 日期和 时间的时间值。

  4. 令 url 为 navigation status 的url。

  5. 令 user context id 为 navigable 的关联用户上下文的用户上下文 id。

  6. 返回一个与 browsingContext.NavigationInfo 产生式匹配的映射,其中 context 字段设置为 navigable id, navigation 字段设置为 navigation id, timestamp 字段设置为 timestamp,url 字段设置为在给定 url 的情况下运行 URL 序列化器所得的结果,且 userContext 字段设置为 user context id。

7.3.2.7. browsingContext.ReadinessState 类型
browsingContext.ReadinessState = "none" / "interactive" / "complete"

browsingContext.ReadinessState 类型表示导航命令将返回时的 文档加载阶段。

7.3.2.8. browsingContext.UserPromptType 类型

远程端定义 和 本地端定义

browsingContext.UserPromptType = "alert" / "beforeunload" / "confirm" / "prompt";

browsingContext.UserPromptType 类型表示可能的用户 提示类型。

7.3.3. 命令

7.3.3.1. browsingContext.activate 命令

browsingContext.activate 命令会激活并聚焦给定的 顶级 traversable。

命令类型
browsingContext.Activate = (
  method: "browsingContext.activate",
  params: browsingContext.ActivateParameters
)

browsingContext.ActivateParameters = {
  context: browsingContext.BrowsingContext
}
返回类型
browsingContext.ActivateResult = EmptyResult

给定 command parameters 时,远端步骤为:

  1. 令 navigable id 为 command parameters["context"] 字段的值。

  2. 令 navigable 为使用 navigable id 尝试获取 navigable的结果。

  3. 如果 navigable 不是顶级 traversable,则返回带有错误 代码 invalid argument 的错误。

  4. 返回使用 navigable 调用激活 navigable的结果。

要在给定 navigable 的情况下激活 navigable:
  1. 运行特定于实现的步骤,使 navigable 的系统可见性状态变为visible。如果这不可能,则返回带有错误代码 unsupported operation 的错误。

    注:这可能会产生副作用,使当前 visible 的navigable变为hidden。

    注:这可能会通过导致窗口取消最小化, 或通过与改变系统可见性状态相关的其他副作用,来改变底层 OS 状态。

  2. 运行特定于实现的步骤,在 navigable 未聚焦时将系统焦点设置到 navigable 上。

    注:除非其他规范强制要求,否则这不会改变文档的聚焦区域。

  3. 返回带有数据 null 的成功。

7.3.3.2. browsingContext.captureScreenshot 命令

browsingContext.captureScreenshot 命令 捕获给定 navigable 的图像,并以 Base64 编码字符串形式返回。

命令类型
browsingContext.CaptureScreenshot = (
  method: "browsingContext.captureScreenshot",
  params: browsingContext.CaptureScreenshotParameters
)

browsingContext.CaptureScreenshotParameters = {
  context: browsingContext.BrowsingContext,
  ? origin: ("viewport" / "document") .default "viewport",
  ? format: browsingContext.ImageFormat,
  ? clip: browsingContext.ClipRectangle,
  ? imageSize: browsingContext.ImageSize,
}

browsingContext.ImageFormat = {
   type: text,
   ? quality: 0.0..1.0,
}

browsingContext.ImageSize = {
   ? maxWidth: (js-uint .ge 1),
   ? maxHeight: (js-uint .ge 1),
}

browsingContext.ClipRectangle = (
  browsingContext.BoxClipRectangle /
  browsingContext.ElementClipRectangle
)

browsingContext.ElementClipRectangle = {
  type: "element",
  element: script.SharedReference
}

browsingContext.BoxClipRectangle = {
   type: "box",
   x: float,
   y: float,
   width: float,
   height: float
}
返回类型
browsingContext.CaptureScreenshotResult = {
  data: text
}
要在给定 rect 的情况下规范化矩形:

注:这确保所得矩形具有 正的宽度尺寸和 高度尺寸。

  1. 令 x 为 rect 的x 坐标。

  2. 令 y 为 rect 的y 坐标。

  3. 令 width 为 rect 的宽度尺寸。

  4. 令 height 为 rect 的高度尺寸。

  5. 如果 width 小于 0,则将 x 设置为 x + width,然后 将 width 设置为 -width。

  6. 如果 height 小于 0,则将 y 设置为 y + height,然后 将 height 设置为 -height。

  7. 返回一个新的 DOMRectReadOnly, 其x 坐标为 x,y 坐标 为 y,宽度尺寸为 width,且高度尺寸为 height。

要在给定 rect1 和 rect2 的情况下求矩形 交集
  1. 令 rect1 为用 rect1 调用规范化矩形的结果。

  2. 令 rect2 为用 rect2 调用规范化矩形的结果。

  3. 令 x1_0 为 rect1 的x 坐标。

  4. 令 x2_0 为 rect2 的x 坐标。

  5. 令 x1_1 为 rect1 的x 坐标加上 rect1 的宽度尺寸。

  6. 令 x2_1 为 rect2 的x 坐标加上 rect2 的宽度尺寸。

  7. 令 x_0 为 «x1_0, x2_0» 的最大元素。

  8. 令 x_1 为 «x1_1, x2_1» 的最小元素。

  9. 令 y1_0 为 rect1 的y 坐标。

  10. 令 y2_0 为 rect2 的y 坐标。

  11. 令 y1_1 为 rect1 的y 坐标加上 rect1 的高度尺寸。

  12. 令 y2_1 为 rect2 的y 坐标加上 rect2 的高度尺寸。

  13. 令 y_0 为 «y1_0, y2_0» 的最大元素。

  14. 令 y_1 为 «y1_1, y2_1» 的最小元素。

  15. 如果 x_1 小于 x_0,则令 width 为 0。否则令 width 为 x_1 - x_0。

  16. 如果 y_1 小于 y_0,则令 height 为 0。否则令 height 为 y_1 - y_0。

  17. 返回一个新的 DOMRectReadOnly, 其x 坐标为 x_0,y 坐标 为 y_0,宽度尺寸为 width,且高度尺寸为 height。

给定 number,要舍入一个数:
  1. 如果 number 不是有限的,或者 number 是一个整数 Number,则返回 number。

  2. 如果 number < 0.5𝔽 且 number > +0𝔽,则返回 +0𝔽。

  3. 如果 number < -0𝔽 且 n ≥ -0.5𝔽,则返回 -0𝔽。

  4. 返回最接近 number 的整数 Number,如果距离相同,则优先选择 更接近 +∞ 的 Number。

给定 document、rect 和 image size,要将 文档渲染到画布:
  1. 令 ratio 为给定 document 的 默认视图时确定设备像素比的结果。

  2. 令 framebuffer width 为 rect 的宽度尺寸乘以 ratio,使其与以设备像素表示的 rect 宽度相匹配。

  3. 令 framebuffer height 为 rect 的高度尺寸乘以 ratio,使其与以设备像素表示的 rect 高度相匹配。

  4. 令 scale 为 1。

  5. 如果 image size 不为 null:

    1. 如果存在,则令 max width 为 image size 的 maxWidth 字段,否则为 null。

    2. 如果存在,则令 max height 为 image size 的 maxHeight 字段,否则为 null。

    3. 如果 max width 不为 null,且 max width 除以 framebuffer width 小于 scale,则将 scale 设置为 max width 除以 framebuffer width。

    4. 如果 max height 不为 null,且 max height 除以 framebuffer height 小于 scale,则将 scale 设置为 max height 除以 framebuffer height。

  6. 如果 scale 小于 1:

    1. 令 scale width 为给定 framebuffer width 乘以 scale 后对数字进行舍入的结果。

    2. 令 scale height 为给定 framebuffer height 乘以 scale 后对数字进行舍入的结果。

    3. 令 paint width 为 1 与 scale width 中的最大值。

    4. 令 paint height 为 1 与 scale height 中的最大值。

  7. 否则:

    1. 令 paint width 为 framebuffer width。

    2. 令 paint height 为 framebuffer height。

  8. 令 canvas 为一个新的 HTMLCanvasElement, 其 width 为 paint width,height 为 paint height。

  9. 令 canvas context 为使用 canvas 和 null 运行2D 上下文创建算法 的结果。

  10. 将 canvas 的上下文模式设置为 2D。

  11. 令 source x 为 rect 的x 坐标乘以 ratio,并且 令 source y 为 rect 的y 坐标乘以 ratio。

  12. 令 source rectangle 为四个角分别是以下四个点的矩形: (source x, source y)、(source x + framebuffer width, source y)、 (source x + framebuffer width, source y + framebuffer height),以及 (source x, source y + framebuffer height)。

  13. 令 destination rectangle 为四个角分别是以下四个 点的矩形:(0, 0)、(paint width, 0)、(paint width, paint height), 以及 (0, paint height)。

  14. 完成特定于实现的步骤,其效果等同于将 document 的帧缓冲区中由 source rectangle 指定的区域绘制到 canvas context 的输出位图中由 destination rectangle 指定的区域。

    当 destination rectangle 的尺寸小于 source rectangle 时, destination rectangle 中某一点处绘制的值通过 对 document 的帧缓冲区数据进行过滤来计算。用户代理可以使用 任何过滤算法(例如双线性插值或最近邻算法)。 当过滤算法需要帧缓冲区之外的像素值时, 必须改用最近边缘像素的值。(也就是说,过滤器使用 "clamp-to-edge" 行为。) 当过滤算法需要 source rectangle 之外 但位于帧缓冲区内的像素值时,则必须使用帧缓冲区中的值。

  15. 返回 canvas。

给定 canvas 和 format,要将画布编码 为 Base64:
  1. 如果 format 不为 null,则令 type 为 format 的 type 字段,并令 quality 为 format 的 quality 字段。

  2. 否则,令 type 为 "image/png",并令 quality 为 undefined。

  3. 令 file 为以 type 和 quality 对 canvas 进行的位图作为文件的序列化。

  4. 令 encoded string 为 file 的宽容式 Base64 编码。

  5. 返回数据为 encoded string 的成功结果。

给定 document 和 origin,要获取原点 矩形:
  1. 如果 origin 是 "viewport":

    1. 令 viewport 为 document 的可视视口。

    2. 令 viewport rect 为一个 DOMRectReadOnly, 其x 坐标 为 viewport 的页面左偏移,y 坐标 为 viewport 的页面顶部偏移,宽度尺寸 为 viewport 的宽度,并且高度尺寸为 viewport 的高度。

    3. 返回数据为 viewport rect 的成功结果。

  2. 断言:origin 是 "document"。

  3. 令 document element 为 document 的文档元素。

  4. 令 document rect 为一个 DOMRectReadOnly, 其x 坐标为 0,y 坐标为 0,宽度尺寸为 document element 的滚动高度, 并且高度尺寸为 document element 的滚动宽度。

  5. 返回数据为 document rect 的成功结果。

使用 session 和 command parameters 的远端步骤如下:

  1. 如果 command parameters 中存在 context 字段,则令 navigable id 为该字段的值, 否则为 null。

  2. 令 navigable 为使用 navigable id 尝试获取可导航对象 所得的结果。

  3. 如果实现由于任何原因无法捕获 navigable 的屏幕截图,则返回带有错误的结果,其错误 代码为不支持的操作。

  4. 令 document 为 navigable 的活动文档。

  5. 紧接着下一次为 document 调用运行动画帧回调算法之后:

    这里应当以 某种更加明确的方式集成到更新 渲染算法中。[w3c/webdriver-bidi Issue #1131]

  6. 如果 command parameters 中存在 context 字段,则令 origin 为该字段的值,否则为 "viewport"。

  7. 令 origin rect 为给定 origin 和 document 尝试获取 原点矩形 所得的结果。

  8. 令 clip rect 为 origin rect。

  9. 如果 command parameters 包含 "clip":

    1. 令 clip 为 command parameters["clip"]。

    2. 运行第一个匹配条件下的步骤:

      clip 匹配 browsingContext.ElementClipRectangle 产生式:
      1. 令 environment settings 为一个环境设置对象,其 相关全局对象的关联的 Document为 document。

      2. 令 realm 为 environment settings 的Realm 执行上下文的 Realm 组件。

      3. 令 element 为使用 clip["element"]、realm 和 session 尝试反序列化远程 引用 所得的结果。

      4. 如果 element 未实现 Element, 则返回带有错误的结果,其错误代码 为无此元素。

      5. 如果 element 的节点文档不是 document,则返回带有错误的结果,其 错误代码为无此元素。

      6. 令 viewport rect 为给定 "viewport" 和 document 获取原点矩形 所得的结果。

      7. 令 element rect 为针对 element 获取边界框所得的结果。

      8. 令 clip rect 为一个 DOMRectReadOnly, 其x 坐标为 element rect["x"] + viewport rect["x"], y 坐标为 element rect["y"] + viewport rect["y"],宽度为 element rect["width"], 高度为 element rect["height"]。

      clip 匹配 browsingContext.BoxClipRectangle 产生式:
      1. 令 clip x 为 clip["x"] 加上 origin rect 的x 坐标。

      2. 令 clip y 为 clip["y"] 加上 origin rect 的y 坐标。

      3. 令 clip rect 为一个 DOMRectReadOnly, 其x 坐标为 clip x, y 坐标为 clip y,宽度为 clip["width"],高度 为 clip["height"]。

  10. 注: 现在所有坐标都从 文档的原点开始测量。

  11. 令 rect 为 origin rect 和 clip rect 的矩形交集。

  12. 如果 rect 的宽度尺寸为 0,或者 rect 的高度尺寸为 0, 则返回带有错误的结果,其错误代码为无法捕获屏幕。

  13. 如果 command parameters 中存在 imageSize 字段,则令 image size 为该字段的值,否则为 null。

  14. 令 canvas 为使用 document、rect 和 image size 将文档渲染到画布所得的结果。

  15. 令 format 为 command parameters 的 format 字段。

  16. 令 encoding result 为使用 canvas 和 format 尝试将画布编码为 Base64所得的结果。

  17. 令 body 为一个匹配 browsingContext.CaptureScreenshotResult 产生式的映射,其中 data 字段被设置为 encoding result。

  18. 返回数据为 body 的成功结果。

7.3.3.3. browsingContext.close 命令

browsingContext.close 命令会关闭一个 顶级 traversable。

命令类型
browsingContext.Close = (
  method: "browsingContext.close",
  params: browsingContext.CloseParameters
)

browsingContext.CloseParameters = {
  context: browsingContext.BrowsingContext,
  ? promptUnload: bool .default false
}
返回类型
browsingContext.CloseResult = EmptyResult
给定 command parameters 时,远端步骤为:
  1. 令 navigable id 为 command parameters 的 context 字段的值。

  2. 令 prompt unload 为 command parameters 的 promptUnload 字段的值。

  3. 令 navigable 为用 navigable id 尝试获取 navigable 所得的结果。

  4. 断言:navigable 不是 null。

  5. 如果 navigable 不是顶级 traversable,则返回带有 错误代码 invalid argument 的错误。

  6. 如果 prompt unload 为 true:

    1. 关闭 navigable。

  7. 否则:

    1. 在不提示卸载的情况下关闭 navigable。

  8. 返回带有数据 null 的成功。

关于关闭最后一个 顶级 traversable时的行为,目前有一个开放的 讨论。我们可以预期关闭浏览器、关闭会话,或将其留给实现决定。[w3c/webdriver-bidi Issue #170]

7.3.3.4. browsingContext.create 命令

browsingContext.create 命令会创建一个新的 navigable,位于新标签页或新窗口中,并返回其 navigable id。

命令类型
browsingContext.Create = (
  method: "browsingContext.create",
  params: browsingContext.CreateParameters
)

browsingContext.CreateType = "tab" / "window"

browsingContext.CreateParameters = {
  type: browsingContext.CreateType,
  ? referenceContext: browsingContext.BrowsingContext,
  ? background: bool .default false,
  ? userContext: browser.UserContext
}
返回类型
browsingContext.CreateResult = {
  context: browsingContext.BrowsingContext,
  ? userContext: browser.UserContext
}
给定 command parameters 时,远端步骤为:
  1. 令 type 为 command parameters 的 type 字段的值。

  2. 令 reference navigable id 为 command parameters 的 referenceContext 字段的值(如果存在),否则为 null。

  3. 如果 reference navigable id 不为 null,则令 reference navigable 为 尝试使用 reference navigable id 获取可导航的结果。否则令 reference navigable 为 null。

  4. 如果 reference navigable 不为 null,且不是顶级可遍历, 则返回带有错误码 无效参数的错误。

  5. 如果实现由于任何原因无法创建新的顶级可遍历,则返回带有错误 码 不支持的操作的错误。

  6. 如果 reference navigable 为 null,则令 user context 为默认用户上下文,否则令其为 reference navigable 的关联用户 上下文。

  7. 令 user context id 为 command parameters 的 userContext 字段的值(如果存在), 否则为 null。

  8. 如果 user context id 不为 null,则将 user context 设为 尝试使用 user context id 获取用户上下文的结果。

  9. 如果 user context 为 null,则返回带有错误码 无此用户 上下文的错误。

  10. 如果实现由于任何原因无法创建具有关联用户上下文 user context 的新顶级可遍历,则返回带有 错误 码 不支持的操作的错误。

  11. 令 traversable 为尝试执行创建新的顶层可遍历对象 的步骤,以 null、空字符串、 null 和 false 作为参数,并将新创建的顶层可遍历对象的关联用户上下文设置为 user context 而得到的结果。新顶层可遍历对象被创建在哪个操作系统窗口中取决于 type 和 reference navigable:

    • 如果 type 为 "tab",且实现支持在同一 OS 窗口中存在多个顶级可遍历:

      • 新的顶级可遍历应复用 现有 OS 窗口(如果有)。

      • 如果 reference navigable 不为 null,则新的顶级可遍历应复用包含 reference navigable 的窗口(如果有)。如果 OS 窗口内的顶级可遍历具有确定的顺序, 则新的顶级可遍历应在该顺序中紧接在 reference navigable 的顶级可遍历之后。

    • 如果 type 为 "window",且实现支持在不同 OS 窗口中存在多个顶级可遍历,则创建的 顶级可遍历应位于新的 OS 窗口中。

    • 否则,如何向用户呈现该顶级可遍历的细节由实现定义。

  12. 如果 command parameters 的 background 字段的值为 false:

    1. 令 activate result 为使用新创建的可导航激活可导航的结果。

    2. 如果 activate result 是错误, 则返回 activate result。

    注:如果 background 为 true,则不要为创建的可导航调用聚焦步骤。

  13. 令 body 为一个匹配 browsingContext.CreateResult 产生式的映射, 其中 context 字段设为 traversable 的可导航 ID, 且 userContext 属性设为 traversable 的 关联用户上下文的用户 上下文 ID。

  14. 返回带有数据 body 的成功。

7.3.3.5. browsingContext.getTree 命令

browsingContext.getTree 命令返回一个 包含给定父级本身在内的所有后代 navigable 的树, 或在未提供父级时返回所有顶级 context。

命令类型
browsingContext.GetTree = (
  method: "browsingContext.getTree",
  params: browsingContext.GetTreeParameters
)

browsingContext.GetTreeParameters = {
  ? maxDepth: js-uint,
  ? root: browsingContext.BrowsingContext,
}
返回类型
browsingContext.GetTreeResult = {
  contexts: browsingContext.InfoList
}
给定 session 和 command parameters 时,远端步骤为:
  1. 令 root id 为 command parameters 的 root 字段的值, 如果存在的话;否则为 null。

  2. 令 max depth 为 command parameters 的 maxDepth 字段的值,如果存在的话;否则为 null。

  3. 令 navigables 为空列表。

  4. 如果 root id 不是 null,则将给定 root id 时 尝试获取 navigable所得的结果追加到 navigables。 否则将所有顶级 traversable追加到 navigables。

  5. 令 navigables infos 为空列表。

  6. 对于 navigables 中的每个 navigable:

    1. 令 info 为给定 navigable、max depth 和 true 时调用获取 navigable 信息所得的结果。

    2. 将 info 追加到 navigables infos

  7. 令 body 为一个与 browsingContext.GetTreeResult 产生式匹配的映射, 其中 contexts 字段设置为 navigables infos。

  8. 返回带有数据 body 的成功。

7.3.3.6. browsingContext.handleUserPrompt 命令

browsingContext.handleUserPrompt 命令允许关闭打开的提示

命令类型
browsingContext.HandleUserPrompt = (
  method: "browsingContext.handleUserPrompt",
  params: browsingContext.HandleUserPromptParameters
)

browsingContext.HandleUserPromptParameters = {
  context: browsingContext.BrowsingContext,
  ? accept: bool,
  ? userText: text,
}
返回类型
browsingContext.HandleUserPromptResult = EmptyResult

给定 session 和 command parameters 时,远端步骤为:

  1. 令 navigable id 为 command parameters 的 context 字段的值。

  2. 令 navigable 为用 navigable id 尝试获取 navigable 所得的结果。

  3. 令 accept 为 command parameters 的 accept 字段的值,如果存在的话;否则为 true。

  4. 令 userText 为 command parameters 的 userText 字段的值,如果存在的话;否则为空字符串。

  5. 如果 navigable 当前显示的是由调用 alert 产生的简单对话框,则 确认该提示。

    否则,如果 navigable 当前显示的是由调用 confirm 产生的简单对话框,则当 accept 为 true 时肯定响应, 或当 accept 为 false 时 否定响应。

    否则,如果 navigable 当前显示的是由调用 prompt 产生的简单对话框,则当 accept 为 true 时用字符串值 userText 响应,或当 accept 为 false 时中止。

    否则,如果 navigable 当前显示的是作为提示卸载步骤的一部分的提示,则当 accept 为 true 时确认该 导航,否则 拒绝该导航。

    否则,返回带有错误 代码 no such alert 的错误。

  6. 返回带有数据 null 的成功。

7.3.3.7. browsingContext.locateNodes 命令

browsingContext.locateNodes 命令返回 与指定定位器匹配的所有节点列表。

命令类型
browsingContext.LocateNodes = (
  method: "browsingContext.locateNodes",
  params: browsingContext.LocateNodesParameters
)

browsingContext.LocateNodesParameters = {
   context: browsingContext.BrowsingContext,
   locator: browsingContext.Locator,
   ? maxNodeCount: (js-uint .ge 1),
   ? serializationOptions: script.SerializationOptions,
   ? startNodes: [ + script.SharedReference ]
}
返回类型
browsingContext.LocateNodesResult = {
    nodes: [ * script.NodeRemoteValue ]
}
要在给定 navigable、context nodes、 selector、maximum returned node count 和 session 的情况下使用 CSS 定位节点:
  1. 令 returned nodes 为空列表。

  2. 令 parse result 为给定 selector 时解析选择器所得的结果。

  3. 如果 parse result 为 failure,则返回带有错误代码 invalid selector 的错误。

  4. 对于 context nodes 中的每个 context node:

    1. 令 elements 为用 parse result 和 navigable 的活动文档的根,并使用 作用域根 context node, 针对树匹配选择器所得的结果。

    2. 对于 elements 中的每个 element:

      1. 将 element 追加到 returned nodes。

      2. 如果 maximum returned node count 不是 null,且 returned nodes 的大小等于 maximum returned node count, 则返回带有数据 returned nodes 的成功。

  5. 返回带有数据 returned nodes 的成功。

要在给定 navigable 的情况下定位容器 元素:
  1. 令 returned nodes 为空列表。

  2. 如果 navigable 的容器不是 null, 则将 navigable 的容器追加到 returned nodes。

  3. 返回 returned nodes。

要在给定 navigable、context nodes、 selector 和 maximum returned node count 的情况下使用 XPath 定位节点:

注:由于 XPath 规范处于无人维护状态,本算法被表述为像是在调用 XPath DOM API。 然而,应将其理解为等价于直接访问底层算法的规范内部调用, 而不经过 ECMAScript 运行时。

  1. 令 returned nodes 为空列表。

  2. 对于 context nodes 中的每个 context node:

    1. 令 evaluate result 为在 navigable 的 活动文档上调用 evaluate,并以 selector、context node、null、 ORDERED_NODE_SNAPSHOT_TYPE 和 null 作为实参所得的结果。如果这抛出一个 "SyntaxError" DOMException,则返回带有 错误代码 invalid selector 的错误; 否则,如果这抛出任何其他异常,则返回带有 错误代码 unknown error 的错误。

    2. 令 index 为 0。

    3. 令 length 为从 evaluate result 获取 snapshotLength 属性所得的结果。

    4. 当 index 小于 length 时,重复:

      1. 令 node 为以 evaluate result 作为 this、以 index 作为实参调用 snapshotItem所得的结果。

      2. 将 node 追加到 returned nodes。

      3. 如果 maximum returned node count 不是 null,且 returned nodes 的大小等于 maximum returned node count, 则返回带有数据 returned nodes 的成功。

      4. 将 index 设置为 index + 1。

  3. 返回带有数据 returned nodes 的成功。

要在给定 context nodes、 selector、max depth、match type、ignore case 和 maximum returned node count 的情况下使用 inner text 定位节点:
  1. 如果 selector 是空字符串,则返回带有错误代码 invalid selector 的错误。

  2. 令 returned nodes 为空列表。

  3. 如果 ignore case 为 false,则令 search text 为 selector。否则, 令 search text 为按 Unicode 默认大小写转换算法对 selector 执行 toUppercase所得的结果。

  4. 对于 context nodes 中的每个 context node:

    1. 如果 context node 实现了 Document 或 DocumentFragment:

      注:遍历 document 或 document fragment 时,max depth 有意不减少,以使使用 document 和 document.documentElement 的搜索结果等价。

      1. 令 child nodes 为空列表。

      2. 对于 context node 的子节点中的每个节点 child。

        1. 将 child 追加到 child nodes。

      3. 用在给定 child nodes、selector、max depth、 match type、ignore case 和 maximum returned node count 的情况下尝试使用 inner text 定位节点 所得的结果扩展 returned nodes。

    2. 如果 context node 没有实现 HTMLElement, 则继续。

    3. 令 node inner text 为以 context node 作为 this 值调用 innerText getter 步骤所得的结果。

    4. 如果 ignore case 为 false,则令 node text 为 node inner text。否则, 令 node text 为按 Unicode 默认大小写转换算法对 node inner text 执行 toUppercase所得的结果。

    5. 如果 search text 是 node text 的码点子字符串, 则执行以下步骤:

      1. 令 child nodes 为空列表,并且 对于 context node 的 子节点中的每个节点 child:

        1. 将 child 追加到 child nodes。

      2. 如果 child nodes 的大小等于 0,或 max depth 等于 0, 则执行以下步骤:

        1. 如果 match type 是 "full" 且 node text 是 search text, 则将 context node 追加到 returned nodes。

        2. 否则,如果 match type 是 "partial",则将 context node 追加到 returned nodes。

      3. 否则,执行以下步骤:

        1. 如果 max depth 为 null,则令 child max depth 为 null, 否则为 max depth - 1。

        2. 令 child node matches 为用 child nodes、selector、child max depth、match type、 ignore case 和 maximum returned node count 调用使用 inner text 定位节点所得的结果。

        3. 如果 child node matches 的大小等于 0 且 match type 是 "partial",则将 context node 追加到 returned nodes。否则,用 child node matches 扩展 returned nodes。

  5. 如果 maximum returned node count 不是 null,则移除 returned nodes 中索引大于或等于 maximum returned node count 的所有条目。

  6. 返回带有数据 returned nodes 的成功。

要在给定 context nodes、selector、 maximum returned node count 和 returned nodes 的情况下使用无障碍属性收集节点:
  1. 如果 returned nodes 为 null:

    1. 将 returned nodes 设置为空列表。

  2. 对于 context nodes 中的每个 context node:

    1. 令 match 为 true。

    2. 如果 context node 实现了 Element:

      1. 如果 selector 包含 "role":

        1. 令 role 为 context node 的计算角色。

        2. 如果 selector["role"] 不是 role:

          1. 将 match 设置为 false。

      2. 如果 selector 包含 "name":

        1. 令 name 为 context node 的可访问名称。

        2. 如果 selector["name"] 不是 name:

          1. 将 match 设置为 false。

    3. 否则,将 match 设置为 false。

    4. 如果 match 为 true:

      1. 如果 maximum returned node count 不是 null,且 returned nodes 的大小等于 maximum returned node count, 则中断。

      2. 将 context node 追加到 returned nodes。

    5. 令 child nodes 为空列表,并且对于 context node 的 子节点中的每个节点 child:

      1. 如果 child 实现了 Element, 则将 child 追加到 child nodes。

    6. 尝试用 child nodes、selector、maximum returned node count 和 returned nodes 使用无障碍属性收集节点。

  3. 返回 returned nodes。

要在给定 context nodes、selector 和 maximum returned node count 的情况下使用无障碍属性定位节点:
  1. 如果 selector 不包含 "role",且 selector 不包含 "name",则返回 带有错误 代码 invalid selector 的错误。

  2. 返回用 context nodes、selector、maximum returned node count 和 null 调用使用无障碍属性收集节点所得的结果。

给定 session 和 command parameters 时,远端步骤为:
  1. 令 navigable id 为 command parameters["context"]。

  2. 令 navigable 为用 navigable id 尝试获取 navigable 所得的结果。

  3. 断言:navigable 不是 null。

  4. 令 realm 为用 navigable 的navigable id 和 null 尝试从 navigable 获取 realm 所得的结果。

  5. 令 locator 为 command parameters["locator"]。

  6. 如果 command parameters 包含 "startNodes",则令 start nodes parameter 为 command parameters["startNodes"]。 否则令 start nodes parameter 为 null。

  7. 如果 command parameters 包含 "maxNodeCount",则令 maximum returned node count 为 command parameters["maxNodeCount"]。 否则,令 maximum returned node count 为 null。

  8. 令 context nodes 为空列表。

  9. 如果 start nodes parameter 为 null,则将 navigable 的 活动文档追加到 context nodes。否则,对于 start nodes parameter 中的每个 serialized start node:

    1. 令 start node 为给定 serialized start node、realm 和 session 时 尝试反序列化共享引用所得的结果。

    2. 将 start node 追加到 context nodes。

  10. 断言 context nodes 的大小大于 0。

  11. 令 type 为 locator["type"]。

  12. 在以下条件及其关联步骤列表中,运行第一个其关联条件为 true 的 步骤集合:

    type 是字符串 "css"
    1. 令 selector 为 locator["value"]。

    2. 令 result nodes 为给定 navigable、context nodes、selector 和 maximum returned nodes 时尝试使用 css 定位节点所得的结果。

    type 是字符串 "xpath"
    1. 令 selector 为 locator["value"]。

    2. 令 result nodes 为给定 navigable、context nodes、selector 和 maximum returned nodes 时尝试使用 xpath 定位节点所得的结果。

    type 是字符串 "innerText"
    1. 令 selector 为 locator["value"]。

    2. 如果 locator 包含 maxDepth,则令 max depth 为 locator["maxDepth"]。否则,令 max depth 为 null。

    3. 如果 locator 包含 ignoreCase,则令 ignore case 为 locator["ignoreCase"]。否则,令 ignore case 为 false。

    4. 如果 locator 包含 matchType,则令 match type 为 locator["matchType"]。否则,令 match type 为 "full"。

    5. 令 result nodes 为给定 context nodes、selector、max depth、 match type、ignore case 和 maximum returned node count 时 尝试使用 inner text 定位节点所得的结果。

    type 是字符串 "accessibility"
    1. 令 selector 为 locator["value"]。

    2. 令 result nodes 为给定 context nodes、selector 和 maximum returned node count 时使用无障碍属性定位节点所得的结果。

    type 是字符串 "context"
    1. 如果 start nodes parameter 不是 null, 则返回带有错误代码 "invalid argument" 的错误。

    2. 令 selector 为 locator["value"]。

    3. 令 context id 为 selector["context"]。

    4. 令 child navigable 为用 context id 尝试获取 navigable 所得的结果。

    5. 如果 child navigable 的父级不是 navigable, 则返回带有错误代码 "invalid argument" 的错误。

    6. 令 result nodes 为给定 child navigable 时定位容器元素所得的结果。

    7. 断言:对于 result nodes 中的每个 node, node 的节点 navigable是 navigable。

  13. 断言:maximum returned node count 为 null,或 result nodes 的大小小于或等于 maximum returned node count。

  14. 如果 command parameters 包含 "serializationOptions", 则令 serialization options 为 command parameters["serializationOptions"]。 否则,令 serialization options 为一个与 script.SerializationOptions 产生式匹配、且各字段 设置为其默认值的映射。

  15. 令 result ownership 为 "none"。

  16. 令 serialized nodes 为空列表。

  17. 对于 result nodes 中的每个 result node:

    1. 令 serialized node 为用 result node、serialization options、result ownership、一个新的映射作为 serialization internal map、realm 和 session 序列化为远程值所得的结果。

    2. 将 serialized node 追加到 serialized nodes。

  18. 令 result 为一个与 browsingContext.LocateNodesResult 产生式匹配的映射, 其 nodes 字段设置为 serialized nodes。

  19. 返回带有数据 result 的成功。

7.3.3.8. browsingContext.navigate 命令

browsingContext.navigate 命令将一个 navigable 导航到给定 URL。

命令类型
browsingContext.Navigate = (
  method: "browsingContext.navigate",
  params: browsingContext.NavigateParameters
)

browsingContext.NavigateParameters = {
  context: browsingContext.BrowsingContext,
  url: text,
  ? wait: browsingContext.ReadinessState,
}
返回类型
browsingContext.NavigateResult = {
  navigation: browsingContext.Navigation / null,
  url: text,
}
给定 session 和 command parameters 时,远端步骤为:
  1. 令 navigable id 为 command parameters 的 context 字段的值。

  2. 令 navigable 为用 navigable id 尝试获取 navigable 所得的结果。

  3. 断言:navigable 不是 null。

  4. 令 wait condition 为 "committed"。

  5. 如果 command parameters 包含 wait 且 command parameters[wait] 不是 "none", 则将 wait condition 设置为 command parameters[wait]。

  6. 令 url 为 command parameters 的 url 字段的值。

  7. 令 document 为 navigable 的活动文档。

  8. 令 base 为 document 的基 URL。

  9. 令 url record 为以 基 URL base 将 URL 解析器应用于 url所得的结果。

  10. 如果 url record 为 failure,则返回带有错误代码 invalid argument 的错误。

  11. 令 request 为一个新的 request,其 URL 为 url record。

  12. 返回用 navigable、 request 和 wait condition 调用等待导航所得的结果。

7.3.3.9. browsingContext.print 命令

browsingContext.print 命令 创建文档的分页表示,并将其作为 表示为 Base64 编码字符串的 PDF 文档返回。

命令类型
browsingContext.Print = (
  method: "browsingContext.print",
  params: browsingContext.PrintParameters
)

browsingContext.PrintParameters = {
  context: browsingContext.BrowsingContext,
  ? background: bool .default false,
  ? margin: browsingContext.PrintMarginParameters,
  ? orientation: ("portrait" / "landscape") .default "portrait",
  ? page: browsingContext.PrintPageParameters,
  ? pageRanges: [*(js-uint / text)],
  ? scale: (0.1..2.0) .default 1.0,
  ? shrinkToFit: bool .default true,
}

browsingContext.PrintMarginParameters = {
  ? bottom: (float .ge 0.0) .default 1.0,
  ? left: (float .ge 0.0) .default 1.0,
  ? right: (float .ge 0.0) .default 1.0,
  ? top: (float .ge 0.0) .default 1.0,
}

; Minimum size is 1pt x 1pt. Conversion follows from
; https://www.w3.org/TR/css3-values/#absolute-lengths
browsingContext.PrintPageParameters = {
  ? height: (float .ge 0.0352) .default 27.94,
  ? width: (float .ge 0.0352) .default 21.59,
}
返回类型
browsingContext.PrintResult = {
  data: text
}

带有 session 和 command parameters 的远程端步骤如下:

  1. 令 navigable id 为 command parameters 的 context 字段的值。

  2. 令 navigable 为尝试使用 navigable id 获取 可导航的结果。

  3. 如果实现由于任何原因无法提供 navigable 的分页表示,则返回带有错误码 不支持的操作的错误。

  4. 令 margin 为 command parameters 的 margin 字段的值(如果存在),否则为一个匹配 browsingContext.PrintMarginParameters 且字段设为 其默认值的映射。

  5. 令 page size 为 command parameters 的 page 字段的值(如果存在),否则为一个匹配 browsingContext.PrintPageParameters 且字段设为 其默认值的映射。

注:最小页面尺寸为 1 点,按照绝对长度, 即 (2.54 / 72) cm。

  1. 令 page ranges 为 command parameters 的 pageRanges 字段的值(如果存在), 否则为空列表。

  2. 令 document 为 navigable 的活动文档。

  3. 在下一次为 document 调用运行动画帧回调 算法之后立即:

    这应当以某种更明确的方式 集成到更新 渲染算法中。 [w3c/webdriver-bidi 议题 #1131]

    1. 令 pdf data 为采用 UA 特定步骤生成 document 的分页表示的结果,其中 CSS 媒体类型设为 print,编码为 PDF,并具有以下纸张设置:

      属性 值
      宽度,单位 cm 如果 command parameters["orientation"] 为 "portrait",则为 page size["width"],否则为 page size["height"]
      高度,单位 cm 如果 command parameters["orientation"] 为 "portrait",则为 page size["height"],否则为 page size["width"]
      上边距,单位 cm margin["top"]
      下边距,单位 cm margin["bottom"]
      左边距,单位 cm margin["left"]
      右边距,单位 cm margin["right"]

      此外,UA 应应用以下格式化提示:

      如果 command parameters["scale"] 不等于 1:
      按因子 command parameters["scale"] 缩放内容大小
      如果 command parameters["background"] 为 false:
      抑制背景图像输出
      如果 command parameters["shrinkToFit"] 为 true:
      调整内容大小以匹配页面宽度,覆盖内容中指定的任何页面 宽度
    2. 如果 page ranges 不是空, 则令 pages 为 尝试使用 page ranges 和 pdf data 中包含的页数解析页面范围的结果,然后从 pdf data 中移除 任何其从 1 开始的索引未包含在 pages 中的页面。

    3. 令 encoding result 为对 pdf data 调用Base64 编码的结果。

    4. 令 encoded data 为 encoding result 的数据。

    5. 令 body 为一个匹配 browsingContext.PrintResult 产生式的映射, 其中 data 字段设为 encoded data。

    6. 返回带有数据 body 的成功。

7.3.3.10. browsingContext.reload 命令

browsingContext.reload 命令重载一个 navigable。

命令类型
browsingContext.Reload = (
  method: "browsingContext.reload",
  params: browsingContext.ReloadParameters
)

browsingContext.ReloadParameters = {
  context: browsingContext.BrowsingContext,
  ? ignoreCache: bool,
  ? wait: browsingContext.ReadinessState,
}
返回类型
browsingContext.ReloadResult = browsingContext.NavigateResult
给定 command parameters 时,远端步骤为:
  1. 令 navigable id 为 command parameters 的 context 字段的值。

  2. 令 navigable 为用 navigable id 尝试获取 navigable 所得的结果。

  3. 断言:navigable 不是 null。

  4. 令 ignore cache 为 command parameters 的 ignoreCache 字段的值(如果存在),否则为 false。

  5. 令 wait condition 为 "committed"。

  6. 如果 command parameters 包含 wait 且 command parameters[wait] 不是 "none", 则将 wait condition 设置为 command parameters[wait]。

  7. 令 document 为 navigable 的活动文档。

  8. 令 url 为 document 的URL。

  9. 令 request 为一个新的 request,其 URL 为 url。

  10. 返回用 navigable、 request、wait condition、历史处理 "reload" 和 ignore cache ignore cache 调用等待导航所得的结果。

7.3.3.11. browsingContext.setBypassCSP 命令

browsingContext.setBypassCSP 命令允许绕过 Content Security Policy 的强制执行。

注:启用 CSP 绕过时,所有 CSP 指令都会被 绕过,包括通常会阻止 eval()、new Function()、内联脚本和资源 加载的指令。

命令类型
browsingContext.SetBypassCSP = (
  method: "browsingContext.setBypassCSP",
  params: browsingContext.SetBypassCSPParameters
)

browsingContext.SetBypassCSPParameters = {
  bypass: true / null,
  ? contexts: [+browsingContext.BrowsingContext],
  ? userContexts: [+browser.UserContext],
}
返回类型
browsingContext.SetBypassCSPResult = EmptyResult

远端具有一个绕过 CSP 配置,它是 WebDriver 配置,其关联类型为 boolean。

给定 navigable navigable 时,WebDriver BiDi CSP 被绕过步骤为:

  1. 令 top-level traversable 为 navigable 的顶级 traversable。

  2. 令 bypass CSP enabled 为针对 top-level traversable 的 绕过 CSP 配置调用获取 WebDriver 配置值所得的结果。

  3. 断言:bypass CSP enabled 是 true 或 unset。

  4. 如果 bypass CSP enabled 是 unset,则返回 false。

  5. 返回 true。

给定 command parameters 时,远端步骤为:

  1. 令 bypass 为 command parameters["bypass"]。

  2. 如果 bypass 为 null,则将 bypass 设置为 unset。

  3. 尝试为 command parameters 存储 WebDriver 配置 绕过 CSP 配置 bypass。

  4. 返回带有数据 null 的成功。

7.3.3.12. browsingContext.setViewport 命令

browsingContext.setViewport 命令修改给定顶级 traversable 上的特定 viewport 特征(例如 viewport width 和 viewport height)。

命令类型
browsingContext.SetViewport = (
  method: "browsingContext.setViewport",
  params: browsingContext.SetViewportParameters
)

browsingContext.SetViewportParameters = {
  ? context: browsingContext.BrowsingContext,
  ? viewport: browsingContext.Viewport / null,
  ? devicePixelRatio: (float .gt 0.0) / null,
  ? userContexts: [+browser.UserContext],
}

browsingContext.Viewport = {
  width: js-uint,
  height: js-uint,
}
返回类型
browsingContext.SetViewportResult = EmptyResult
要在给定 navigable 和 device pixel ratio 的情况下设置 device pixel ratio 覆盖:
  1. 如果 device pixel ratio 不是 null:

    1. 对于当前加载在指定 navigable 中的document:

      1. 当运行从 source set 选择图像源步骤时, 在选择图像时,表现得如同实现的像素密度被设置为 device pixel ratio。

      2. 就 resolution 媒体特性而言,表现得如同 实现的 resolution 是按页面缩放缩放的 device pixel ratio dppx。

    2. 将device pixel ratio 覆盖[navigable] 设置为 device pixel ratio。

      注:这会因 § 8.3.1 确定 device pixel ratio 的补丁而生效。

  2. 否则:

    1. 对于当前加载在指定 navigable 中的document:

      1. 当运行从 source set 选择图像源步骤时,使用实现的默认行为, 不带有这些步骤先前调用所作的任何更改。

      2. 就 resolution 媒体特性而言,使用 实现的默认行为, 不带有这些步骤先前调用所作的任何更改。

    2. 从 device pixel ratio 覆盖中移除 navigable。

  3. 对当前加载在指定 navigable 中的document运行求值媒体查询并报告变化。

要在给定 navigable navigable 和 viewport viewport 的情况下 设置 viewport:
  1. 如果 viewport 不是 null,则将 navigable 的布局视口的宽度设置为 viewport 的width(以 CSS 像素计),并且 将 navigable 的布局视口的高度设置为 viewport 的height(以 CSS 像素计)。

  2. 否则,将 navigable 的布局视口设置为 实现定义的默认值。

在新的 navigable navigable 中创建 document 之后, 且在调用运行 WebDriver BiDi 预加载脚本算法之前:

TODO:改为将其移作 html 规范中的一个钩子。

  1. 令 user context 为 navigable 的关联用户 上下文。

  2. 如果 navigable 是顶级 traversable:

    1. 为 navigable 更新 geolocation 覆盖。

    2. 为 navigable 更新模拟 forced colors 主题。

    3. 如果 screen orientation 覆盖映射 包含 user context, 则用 navigable 和 screen orientation 覆盖 映射[user context] 设置模拟 screen orientation。

  3. 如果 viewport 覆盖映射 包含 user context:

    1. 如果 navigable 是顶级 traversable,且 viewport 覆盖映射[user context] 的 viewport 不是 null:

      1. 用 navigable 和 viewport 覆盖映射[user context] 的 viewport 设置 viewport。

    2. 如果 viewport 覆盖映射[user context] 的devicePixelRatio 不是 null:

      1. 用 navigable 和 viewport 覆盖映射[user context] 的 devicePixelRatio 设置 device pixel ratio 覆盖。

  4. 为 navigable 更新 scrollbar type 覆盖。

  5. 更新文本布局模式覆盖(针对 navigable)。

给定 command parameters 时,远端步骤为:

  1. 如果实现因任何原因无法用给定 command parameters 调整布局视口 参数,则返回带有错误 代码 unsupported operation 的错误。

  2. 如果 command parameters 包含 "userContexts" 且 command parameters 包含 "context", 则返回带有错误 代码 invalid argument 的错误。

  3. 令 navigables 为一个集合。

  4. 如果 command parameters 的 context 字段存在:

    1. 令 navigable id 为 command parameters 的 context 字段的值。

    2. 令 navigable 为用 navigable id 尝试获取 navigable所得的结果。

    3. 如果 navigable 不是顶级 traversable,则返回带有 错误代码 invalid argument 的错误。

    4. 将 navigable 追加到 navigables。

  5. 否则,如果 command parameters 的 userContexts 字段存在:

    1. 令 user contexts 为用 command parameters["userContexts"] 尝试获取有效用户上下文所得的结果。

    2. 对于 user contexts 中的每个 user context:

      1. 将viewport 覆盖映射[user context] 设置为一个结构体。

      2. 如果 command parameters 包含 "viewport":

        1. 将 viewport 覆盖 映射[user context] 的viewport 设置为 command parameters["viewport"]。

      3. 如果 command parameters 包含 "devicePixelRatio":

        1. 将 viewport 覆盖 映射[user context] 的devicePixelRatio 设置为 command parameters["devicePixelRatio"]。

      4. 对于所有顶级 traversable的列表中 其关联用户上下文为 user context 的每个 top-level traversable:

        1. 将 top-level traversable 追加到 navigables。

  6. 否则,返回带有错误 代码 invalid argument 的错误。

  7. 如果 command parameters 包含 viewport 字段:

    1. 令 viewport 为 command parameters["viewport"]。

    2. 对于 navigables 中的每个 navigable:

      1. 用 navigable 和 viewport 设置 viewport。

      2. 用 navigable 的活动文档运行 CSSOM View § 13.1 Resizing viewports 步骤。

  8. 如果 command parameters 包含 devicePixelRatio 字段:

    1. 令 device pixel ratio 为 command parameters["devicePixelRatio"]。

    2. 对于 navigables 中的每个 navigable:

      1. 对于 navigable 和所有后代 navigable:

        1. 用 navigable 和 device pixel ratio 设置 device pixel ratio 覆盖。

  9. 返回带有数据 null 的成功。

7.3.3.13. browsingContext.startScreencast 命令

browsingContext.startScreencast 命令 启动给定可导航的屏幕录制,并将其写入文件。

注:远程端 创建并写入屏幕录制文件,但不会删除它。 清理该文件留给本地端。在 某些配置中这可能不 可行——例如,如果远程端 对文件系统具有读/写访问权限,但 本地端只有只读访问权限。

命令类型
browsingContext.StartScreencast = (
  method: "browsingContext.startScreencast",
  params: browsingContext.StartScreencastParameters
)

browsingContext.StartScreencastParameters = {
  context: browsingContext.BrowsingContext,
  ? destinationFolder: text,
  ? mimeType: text,
  ? video: browsingContext.MediaTrackConstraints,
  ? audio: bool .default false,
}

browsingContext.MediaTrackConstraints = {
   ? width: js-uint,
   ? height: js-uint,
   ? frameRate: js-uint,
}

返回类型
browsingContext.StartScreencastResult = {
   screencast: browsingContext.Screencast,
   path: text
}

browsingContext.Screencast = text
给定 session 和 command parameters 时,远端步骤如下:
  1. 令 navigable id 为 command parameters["context"]。

  2. 令 navigable 为尝试使用 navigable id 获取可导航对象 的结果。

  3. 如果 navigable 不是顶层可遍历对象,则返回带有 错误,其 错误代码为 无效参数。

  4. 如果 command parameters 包含 destinationFolder 字段:

    1. 令 destination folder 为 command parameters["destinationFolder"]。

    2. 令 destination folder entry 为在给定 路径 destination folder 和 与文件系统根目录对应的 根的情况下,执行定位条目的结果。

    3. 如果 destination folder entry 为 null,则返回带有错误,其 错误代码为 无效参数。

    4. 令 path 为 destination folder entry 中用于存储录制内容的新文件的 实现定义文件路径。

  5. 否则,令 path 为用于存储录制内容的实现定义文件路径。

  6. 如果 command parameters 包含 mimeType 字段:

    1. 令 mime type 为 command parameters["mimeType"]。

  7. 否则,将 mime type 设置为实现定义的默认格式。

  8. 如果实现由于任何原因无法录制 navigable 的屏幕录制,则返回带有错误,其错误 代码为不支持的操作。

  9. 令 stream 为用于 navigable 的新屏幕录制流,按如下方式构造:

    1. 创建一个 video track,它必须实时捕获 浏览器的显示表面, 该显示表面对应于相关全局对象的关联的 `Document` 的 navigable 的 视口。

    2. 如果 command parameters 包含 "video":

      1. 令 video 为 command parameters["video"]。

      2. 如果 video 包含 width:

        1. 用户代理必须在硬件能力和指定的其他约束条件允许的情况下,尝试获取宽度尽可能 接近 video["width"] 的媒体。

      3. 如果 video 包含 height:

        1. 用户代理必须在硬件能力和指定的其他约束条件允许的情况下,尝试获取高度尽可能 接近 video["height"] 的媒体。

      4. 如果 video 包含 frameRate:

        1. 用户代理必须在硬件能力和指定的其他约束条件允许的情况下,尝试获取帧率尽可能 接近 video["frameRate"] 的媒体。

    3. 将 video track 视频轨道设置到 stream 中。

    4. 如果 command parameters["audio"] 为 true:

      1. 创建一个 audio track,其中包含由以下文档产生的合并音频之和: 相关全局对象的关联的 `Document` 的 navigable 的活动文档,以及该相关全局对象的关联的 `Document` 的 navigable 的嵌套浏览上下文中的所有活动文档。

      2. 将 audio track 音频轨道设置到 stream 中。

    5. 如果实现无法生成 stream,则返回带有错误,其 错误代码为未知错误。

  10. 令 screencast 为一个 UUID 的字符串表示形式。

  11. 令 recording 为一个新的屏幕录制记录,其 流为 stream, 路径为 path, 状态为 "recording", writeError 为 null。

  12. 将 session 的屏幕录制记录映射[screencast] 设置为 recording。

  13. 给定 recording 和 mime type,开始屏幕录制。

  14. 令 body 为一个新的映射, 与 browsingContext.StartScreencastResult 匹配,其中 screencast 字段设置为 screencast,且 path 字段设置为 path。

  15. 返回带有数据 body 的成功。

7.3.3.14. browsingContext.stopScreencast 命令

browsingContext.stopScreencast 命令 停止屏幕录制。

命令类型
browsingContext.StopScreencast = (
  method: "browsingContext.stopScreencast",
  params: browsingContext.StopScreencastParameters
)

browsingContext.StopScreencastParameters = {
  screencast: browsingContext.Screencast
}
返回类型
browsingContext.StopScreencastResult = {
   path: text,
   ? error: text
}
给定 session 和 command parameters 的远程端步骤如下:
  1. 令 screencast 为 command parameters 中 "screencast" 字段的值。

  2. 如果 session 的屏幕录制记录映射不包含 screencast,则返回带有错误,其错误代码为无此 屏幕录制。

  3. 令 screencast recording 为 session 的屏幕 录制映射[screencast]。

  4. 给定 screencast recording,停止屏幕录制。

  5. 从 session 的屏幕录制映射中移除 screencast。

  6. 令 error 为 screencast recording 的writeError。

  7. 令 path 为 screencast recording 的path。

  8. 令 body 为一个新的映射, 它匹配 browsingContext.StopScreencastResult, 其中 path 字段设为 path,如果 error 不为 null,则 error 字段设为 error,否则省略该字段。

  9. 返回带有数据 body 的成功。

7.3.3.15. browsingContext.traverseHistory 命令

browsingContext.traverseHistory 命令 按 delta 遍历给定 navigable 的历史。

命令类型
browsingContext.TraverseHistory = (
  method: "browsingContext.traverseHistory",
  params: browsingContext.TraverseHistoryParameters
)

browsingContext.TraverseHistoryParameters = {
  context: browsingContext.BrowsingContext,
  delta: js-int,
}
返回类型
browsingContext.TraverseHistoryResult = EmptyResult
使用 command parameters 时的远端步骤如下:
  1. 令 navigable 为尝试使用 command parameters["context"] 获取可导航对象 的结果。

  2. 如果 navigable 不是顶层可遍历对象,则返回带有错误,其 错误代码为无效参数。

  3. 断言:navigable 不为 null。

  4. 令 delta 为 command parameters["delta"]。

  5. 令 resume id 为唯一字符串。

  6. 在 navigable 的将任务排入队列的会话历史遍历队列上,以运行 以下步骤:

    1. 令 all steps 为针对 navigable 获取所有已使用历史步骤的结果。

    2. 令 current index 为 navigable 的当前会话历史步骤在 all steps 中的索引。

    3. 令 target index 为 current index 加上 delta。

    4. 如果 all steps[target index] 不存在,则令 valid entry 为 false, 否则为 true。

    5. 使用 "check history"、resume id 和 valid entry 恢复。

  7. 令 is valid entry 为使用 «"check history"» 和 resume id 进行等待的结果。

  8. 如果 is valid entry 为 false,则返回带有错误 代码错误 无此历史条目。

  9. 给定 delta 和 navigable,按增量遍历历史。

    按照当前写法,该算法中存在 竞态条件,因为当我们尝试导航时,目标会话历史条目可能已经 不存在。一旦我们支持等待历史导航完成,就可以更稳健地处理此 情况。

  10. TODO:支持等待历史遍历完成。

  11. 令 body 为与 browsingContext.TraverseHistoryResult 产生式匹配的映射。

  12. 返回带有数据 body 的成功。

给定 context 和 navigation status navigation status 时,WebDriver BiDi page show 步骤为:

我们是否想暴露 `browsingContext.pageShow` 事件?在这种情况下,我们需要 每当即将发出 `pageshow` 时调用它,而不仅仅是在 bfcache 恢复时调用,并且还要向数据中添加 persisted 状态。

  1. 令 navigation id 为 navigation status 的id。

  2. 用 "page show"、navigation id 和 navigation status 恢复。

给定 context 和 navigation status navigation status 时,WebDriver BiDi pop state 步骤为:

  1. 令 navigation id 为 navigation status 的id。

  2. 用 "pop state"、navigation id 和 navigation status 恢复。

7.3.4. 事件

7.3.4.1. browsingContext.contextCreated 事件
事件类型
browsingContext.ContextCreated = (
 method: "browsingContext.contextCreated",
 params: browsingContext.ContextCreatedParameters
)

browsingContext.ContextCreatedParameters = {
 browsingContext.BaseInfo,
 hasPlannedNavigation: bool,
}

browsingContext.ContextCreatedParameters 的 hasPlannedNavigation 指示可导航对象是否会在 browsingContext.contextCreated 事件分派后执行导航。

给定 session 和 navigable,要递归地发出上下文已创建事件:

  1. 使用 session、navigable 和 false 发出上下文已创建事件。

  2. 对于 navigable 的每个子可导航对象 child:

    1. 给定 session 和 child,递归地发出上下文 已创建事件。

给定 session、navigable 和 has planned navigation,要发出 上下文已创建事件:

  1. 令 params 为给定 navigable、0 和 true 获取可导航对象信息的结果。

  2. 将 params["hasPlannedNavigation"] 设置为 has planned navigation。

  3. 断言:params 匹配 browsingContext.ContextCreated 产生式。

  4. 令 body 为匹配 browsingContext.ContextCreated 产生式的映射, 其中 params 字段设置为 params。

  5. 使用 session 和 body 发出事件。

远端事件触发器是 给定可导航对象 navigable、布尔值 has planned navigation 和 可选可导航对象 opener navigable(默认值:null)的 WebDriver BiDi 可导航对象已创建步骤:

  1. 将 navigable 的原始打开者设置为 opener navigable。

  2. 如果使用 navigable 的可导航对象缓存行为 是 "bypass", 则执行由实现定义的步骤,以禁用由 navigable 发起的网络请求所使用的任何实现特定的 资源缓存。

  3. 令 related navigables 为包含 navigable 的集合。

  4. 对于给定 "browsingContext.contextCreated" 和 related navigables 的启用了某事件的会话 集合中的每个 session:

    1. 给定 session、navigable 和 has planned navigation,发出上下文已创建事件。

给定 session、navigables 和 include global,远端订阅步骤(订阅优先级为 1)如下:

  1. 对于 navigables 中的每个 navigable:

    1. 给定 session 和 navigable,递归地发出上下文 已创建事件。

7.3.4.2. browsingContext.contextDestroyed 事件
事件类型
browsingContext.ContextDestroyed = (
 method: "browsingContext.contextDestroyed",
 params: browsingContext.Info
)
远端事件触发器为:

远端事件触发器是给定 navigable navigable 时的WebDriver BiDi navigable destroyed 步骤:

  1. 令 params 为给定 navigable、null 和 true 时调用获取 navigable 信息所得的结果。

  2. 令 body 为一个与 browsingContext.ContextDestroyed 产生式匹配的映射, 其 params 字段设置为 params。

  3. 令 related navigables 为一个集合, 如果 navigable 的父级不是 null,则包含该父级; 否则为空集合。

  4. 对于给定 "browsingContext.contextDestroyed" 和 related navigables 时 事件已启用的会话集合 中的每个 session:

    1. 用 session 和 body 发出 事件。

    2. 令 subscriptions to remove 为一个集合。

    3. 对于 session 的订阅中的每个 subscription:

      1. 如果 subscription 的顶级 traversable ids 包含 navigable 的navigable id;

        1. 从 subscription 的顶级 traversable ids中移除 navigable 的navigable id。

        2. 如果 subscription 的顶级 traversable ids为空:

          1. 将 subscription 追加到 subscriptions to remove。

    4. 从 session 的订阅中移除 subscriptions to remove。

尚不清楚我们是否 应当只针对具有活动文档的 browsing context 触发此事件;导航也可能导致 context 变得不可访问,但由于 bfcache 尚未被丢弃。

7.3.4.3. browsingContext.navigationStarted 事件
事件类型
browsingContext.NavigationStarted = (
 method: "browsingContext.navigationStarted",
 params: browsingContext.NavigationInfo
)
远端事件触发器是 给定 navigable navigable 和 navigation status navigation status 时的WebDriver BiDi navigation started 步骤:
  1. 令 params 为给定 navigable 和 navigation status 时调用获取 navigation 信息所得的结果。

  2. 令 body 为一个与 browsingContext.NavigationStarted 产生式匹配的映射, 其 params 字段设置为 params。

  3. 令 navigation id 为 navigation status 的id。

  4. 令 related navigables 为一个包含 navigable 的集合。

  5. 用 "navigation started"、navigation id 和 navigation status 恢复。

  6. 对于给定 "browsingContext.navigationStarted" 和 related navigables 时 事件已启用的会话集合 中的每个 session:

    1. 用 session 和 body 发出 事件。

7.3.4.4. browsingContext.fragmentNavigated 事件
事件类型
browsingContext.FragmentNavigated = (
 method: "browsingContext.fragmentNavigated",
 params: browsingContext.NavigationInfo
)
远端事件触发器是 给定 navigable navigable 和 navigation status navigation status 时的WebDriver BiDi fragment navigated 步骤:
  1. 令 params 为给定 navigable 和 navigation status 时调用获取 navigation 信息所得的结果。

  2. 令 body 为一个与 browsingContext.FragmentNavigated 产生式匹配的映射, 其 params 字段设置为 params。

  3. 令 navigation id 为 navigation status 的id。

  4. 令 related navigable 为一个包含 navigable 的集合。

  5. 用 "fragment navigated"、navigation id 和 navigation status 恢复。

  6. 对于给定 "browsingContext.fragmentNavigated" 和 related navigable 时 事件已启用的会话集合 中的每个 session:

    1. 用 session 和 body 发出 事件。

7.3.4.5. browsingContext.historyUpdated 事件
事件类型
browsingContext.HistoryUpdated = (
  method: "browsingContext.historyUpdated",
  params: browsingContext.HistoryUpdatedParameters
)

browsingContext.HistoryUpdatedParameters = {
  context: browsingContext.BrowsingContext,
  timestamp: js-uint,
  url: text,
  ? userContext: browser.UserContext
}
远程端事件触发器是给定可导航 navigable 的 WebDriver BiDi 历史已更新步骤:
  1. 令 url 为运行URL 序列化器的结果, 给定 navigable 的活动浏览上下文的活动文档的URL。

  2. 令 user context id 为 navigable 的关联用户 上下文的用户 上下文 ID。

  3. 令 timestamp 为一个时间值,表示 UTC 中的当前日期 和时间。

  4. 令 params 为一个匹配 browsingContext.HistoryUpdatedParameters 产生式的映射, 其中 url 字段设为 url, timestamp 字段设为 timestamp, context 字段设为 navigable 的可导航 ID,且 userContext 字段设为 user context id。

  5. 令 body 为一个匹配 browsingContext.HistoryUpdated 产生式的映射, 其中 params 字段设为 params。

  6. 令 related browsing contexts 为一个集合, 包含 navigable 的活动浏览上下文。

  7. 对于给定 "browsingContext.historyUpdated" 和 related browsing contexts 的启用了事件的会话集合中的每个 session:

    1. 使用 session 和 body 发出 事件。

7.3.4.6. browsingContext.domContentLoaded 事件
事件类型
browsingContext.DomContentLoaded = (
 method: "browsingContext.domContentLoaded",
 params: browsingContext.NavigationInfo
)
远端事件触发器是 给定 navigable navigable 和 navigation status navigation status 时的WebDriver BiDi DOM content loaded 步骤:
  1. 令 params 为给定 navigable 和 navigation status 时调用获取 navigation 信息所得的结果。

  2. 令 body 为一个与 browsingContext.DomContentLoaded 产生式匹配的映射, 其 params 字段设置为 params。

  3. 令 related navigables 为一个包含 navigable 的集合。

  4. 令 navigation id 为 navigation status 的id。

  5. 用 "domContentLoaded"、navigation id 和 navigation status 恢复。

  6. 对于给定 "browsingContext.domContentLoaded" 和 related navigables 时 事件已启用的会话集合 中的每个 session:

    1. 用 session 和 body 发出 事件。

7.3.4.7. browsingContext.load 事件
事件类型
browsingContext.Load = (
 method: "browsingContext.load",
 params: browsingContext.NavigationInfo
)
远端事件触发器是给定 navigable navigable 和 navigation status navigation status 时的WebDriver BiDi load complete 步骤:
  1. 令 params 为给定 navigable 和 navigation status 时调用获取 navigation 信息所得的结果。

  2. 令 body 为一个与 browsingContext.Load 产生式匹配的映射, 其 params 字段设置为 params。

  3. 令 related navigables 为一个包含 navigable 的集合。

  4. 令 navigation id 为 navigation status 的id。

  5. 用 "load"、navigation id 和 navigation status 恢复。

  6. 对于给定 "browsingContext.load" 和 related navigables 时 事件已启用的会话集合 中的每个 session:

    1. 用 session 和 body 发出 事件。

7.3.4.8. browsingContext.downloadWillBegin 事件
事件类型
browsingContext.DownloadWillBegin = (
 method: "browsingContext.downloadWillBegin",
 params: browsingContext.DownloadWillBeginParams
)

browsingContext.DownloadWillBeginParams = {
  download: browsingContext.Download,
  suggestedFilename: text,
  browsingContext.BaseNavigationInfo
}
远程端事件触发器是给定可导航 navigable 和 导航状态 navigation status 的 WebDriver BiDi 下载将开始步骤:
  1. 令 navigation info 为给定 navigable 和 navigation status 获取导航 信息的结果。

  2. 令 download 为 UUID 的字符串表示。

  3. 将下载 ID 映射[navigation status 的downloadResponse] 设置为 download。

  4. 令 params 为一个匹配 browsingContext.DownloadWillBeginParams 产生式的映射, 其中 context 字段设为 navigation info["context"], navigation 字段设为 navigation info["navigation"], timestamp 字段设为 navigation info["timestamp"],url 字段设为 navigation info["url"],download 字段设为 download 且 suggestedFilename 字段设为 navigation status 的suggestedFilename。

  5. 令 body 为一个匹配 browsingContext.DownloadWillBegin 产生式的映射, 其中 params 字段设为 params。

  6. 令 navigation id 为 navigation status 的id。

  7. 令 related navigables 为一个集合, 包含 navigable。

  8. 使用 "download started"、navigation id 和 navigation status 恢复。

  9. 对于给定 "browsingContext.downloadWillBegin" 和 related navigables 的启用了事件的会话集合中的每个 session:

    1. 使用 session 和 body 发出 事件。

  10. 令 download behavior 为使用 navigable 获取下载行为的结果。

  11. 返回 download behavior。

7.3.4.9. browsingContext.downloadEnd 事件
事件类型
browsingContext.DownloadEnd = (
  method: "browsingContext.downloadEnd",
  params: browsingContext.DownloadEndParams
)

browsingContext.DownloadEndParams = {
  (
    browsingContext.DownloadCanceledParams //
    browsingContext.DownloadCompleteParams
  )
}

browsingContext.DownloadCanceledParams = (
  status: "canceled",
  download: browsingContext.Download,
  browsingContext.BaseNavigationInfo
)

browsingContext.DownloadCompleteParams = (
  status: "complete",
  download: browsingContext.Download,
  filepath: text / null,
  browsingContext.BaseNavigationInfo
)
远程端事件触发器是给定 可导航 navigable 和导航 状态 navigation status 的 WebDriver BiDi 下载结束步骤:
  1. 令 navigation info 为给定 navigable 和 navigation status 获取导航 信息的结果。

  2. 断言 navigation info["status"] 等于 "complete" 或 "canceled"。

  3. 令 download response 为 navigation status 的downloadResponse。

  4. 如果下载 ID 映射包含 download response,则令 download 为 下载 ID 映射[download response],否则令 download 为 UUID 的字符串表示。

  5. 如果 navigation info["status"] 为 "complete",则令 params 为一个匹配 browsingContext.DownloadCompleteParams 产生式的映射,其中 download 字段 设为 download,filepath 字段设为 navigation status 的downloadedFilepath, context 字段设为 navigation info["context"], navigation 字段设为 navigation info["navigation"], timestamp 字段设为 navigation info["timestamp"],且 url 字段设为 navigation info["url"]。

    注:对于已完成的下载,如果由于任何原因无法获得文件路径, filepath 可以为 null。

  6. 否则,令 params 为一个匹配 browsingContext.DownloadCanceledParams 产生式的映射, 其中 download 字段 设为 download,context 字段设为 navigation info["context"], navigation 字段设为 navigation info["navigation"], timestamp 字段设为 navigation info["timestamp"],且 url 字段设为 navigation info["url"]。

  7. 令 body 为一个匹配 browsingContext.DownloadEnd 产生式的映射, 其中 params 字段设为 params。

  8. 令 related navigables 为一个集合, 包含 navigable。

  9. 对于给定 "browsingContext.downloadEnd" 和 related navigables 的启用了事件的会话集合中的每个 session:

    1. 使用 session 和 body 发出 事件。

7.3.4.10. browsingContext.navigationAborted 事件
事件类型
browsingContext.NavigationAborted = (
 method: "browsingContext.navigationAborted",
 params: browsingContext.NavigationInfo
)
远端事件触发器是 给定 navigable navigable 和 navigation status navigation status 时的WebDriver BiDi navigation aborted 步骤:
  1. 令 params 为给定 navigable 和 navigation status 时调用获取 navigation 信息所得的结果。

  2. 令 body 为一个与 browsingContext.NavigationAborted 产生式匹配的映射, 其 params 字段设置为 params。

  3. 令 navigation id 为 navigation status 的id。

  4. 令 related navigables 为一个包含 navigable 的集合。

  5. 用 "navigation aborted"、navigation id 和 navigation status 恢复。

  6. 对于给定 "browsingContext.navigationAborted" 和 related navigables 时 事件已启用的会话集合 中的每个 session:

    1. 用 session 和 body 发出 事件。

7.3.4.11. browsingContext.navigationCommitted 事件
事件类型
browsingContext.NavigationCommitted = (
 method: "browsingContext.navigationCommitted",
 params: browsingContext.NavigationInfo
)
远端事件触发器是 给定 navigable navigable 和 navigation status navigation status 时的WebDriver BiDi navigation committed 步骤:
  1. 令 params 为给定 navigable 和 navigation status 时调用获取 navigation 信息所得的结果。

  2. 令 body 为一个与 browsingContext.NavigationCommitted 产生式匹配的映射, 其 params 字段设置为 params。

  3. 令 related navigables 为一个包含 navigable 的集合。

  4. 令 navigation id 为 navigation status 的id。

  5. 用 "navigation committed"、navigation id 和 navigation status 恢复。

  6. 对于给定 "browsingContext.navigationCommitted" 和 related navigables 时 事件已启用的会话集合 中的每个 session:

    1. 用 session 和 body 发出 事件。

7.3.4.12. browsingContext.navigationFailed 事件
事件类型
browsingContext.NavigationFailed = (
 method: "browsingContext.navigationFailed",
 params: browsingContext.NavigationInfo
)
远端事件触发器是 给定 navigable navigable 和 navigation status navigation status 时的WebDriver BiDi navigation failed 步骤:
  1. 令 params 为给定 navigable 和 navigation status 时调用获取 navigation 信息所得的结果。

  2. 令 body 为一个与 browsingContext.NavigationFailed 产生式匹配的映射, 其 params 字段设置为 params。

  3. 令 navigation id 为 navigation status 的id。

  4. 令 related navigables 为一个包含 navigable 的集合。

  5. 用 "navigation failed"、navigation id 和 navigation status 恢复。

  6. 对于给定 "browsingContext.navigationFailed" 和 related navigables 时 事件已启用的会话集合 中的每个 session:

    1. 用 session 和 body 发出 事件。

7.3.4.13. browsingContext.userPromptClosed 事件
事件类型
browsingContext.UserPromptClosed = (
  method: "browsingContext.userPromptClosed",
  params: browsingContext.UserPromptClosedParameters
)

browsingContext.UserPromptClosedParameters = {
  context: browsingContext.BrowsingContext,
  accepted: bool,
  type: browsingContext.UserPromptType,
  ? userContext: browser.UserContext,
  ? userText: text
}
远端事件触发器是给定 Window window、字符串 type、boolean accepted 和可选 text user text (默认值:null)时的WebDriver BiDi user prompt closed 步骤。
  1. 令 navigable 为 window 的navigable。

  2. 令 navigable id 为 navigable 的navigable id。

  3. 令 user context id 为 navigable 的关联用户 上下文的用户 上下文 id。

  4. 令 params 为一个与 browsingContext.UserPromptClosedParameters 产生式匹配的映射,其 context 字段设置为 navigable id,userContext 字段设置为 user context id,accepted 字段设置为 accepted, type 字段设置为 type,且如果 user text 不是 null,则将 userText 字段设置为 user text,否则省略。

  5. 令 body 为一个与 BrowsingContextUserPromptClosedEvent 产生式匹配的映射, 其 params 字段设置为 params。

  6. 令 related navigables 为一个包含 navigable 的集合。

  7. 对于给定 "browsingContext.userPromptClosed" 和 related navigables 时 事件已启用的会话集合 中的每个 session:

    1. 用 session 和 body 发出 事件。

7.3.4.14. browsingContext.userPromptOpened 事件
事件类型
browsingContext.UserPromptOpened = (
  method: "browsingContext.userPromptOpened",
  params: browsingContext.UserPromptOpenedParameters
)

browsingContext.UserPromptOpenedParameters = {
  context: browsingContext.BrowsingContext,
  handler: session.UserPromptHandlerType,
  message: text,
  type: browsingContext.UserPromptType,
  ? userContext: browser.UserContext,
  ? defaultValue: text
}
要在给定 type 和 navigable 的情况下获取 navigable 的用户提示处理器:
  1. 令 user context 为 navigable 的关联用户 上下文。

  2. 如果 未处理提示行为覆盖 映射 包含 user context:

    1. 令 unhandled prompt behavior override 为未处理提示行为 覆盖映射[user context]。

    2. 如果 unhandled prompt behavior override[type] 不是 null,则返回 unhandled prompt behavior override[type]。

    3. 如果 unhandled prompt behavior override["default"] 不是 null, 则返回 unhandled prompt behavior override["default"]。

  3. 令 handler configuration 为以 type 调用获取提示处理器所得的结果。

  4. 返回 handler configuration 的handler。

远端事件触发器是给定 Window window、字符串 type、字符串 message 和可选 text default value (默认值:null)时的WebDriver BiDi user prompt opened 步骤。
  1. 令 navigable 为 window 的navigable。

  2. 令 navigable id 为 navigable 的navigable id。

  3. 令 user context id 为 navigable 的关联用户 上下文的用户 上下文 id。

  4. 令 handler 为以 type 和 navigable 调用获取 navigable 的用户提示处理器所得的结果。

  5. 令 params 为一个与 browsingContext.UserPromptOpenedParameters 产生式匹配的映射,其 context 字段设置为 navigable id,userContext 字段设置为 user context id,type 字段设置为 type, message 字段设置为 message,如果 default value 不是 null,则将 defaultValue 字段设置为 default value,否则省略, 并将 handler 字段设置为 handler。

  6. 令 body 为一个与 browsingContext.UserPromptOpened 产生式匹配的映射, 其 params 字段设置为 params。

  7. 令 related navigables 为一个包含 navigable 的集合。

  8. 对于给定 "browsingContext.userPromptOpened" 和 related navigables 时 事件已启用的会话集合 中的每个 session:

    1. 用 session 和 body 发出 事件。

  9. 如果 handler 是 "ignore",则将 handler 设置为 "none"。

  10. 返回 handler。

7.4. emulation 模块

emulation 模块包含与浏览器 API 模拟相关的命令和事件。

7.4.1. 定义

remote end definition

EmulationCommand = (
  emulation.SetForcedColorsModeThemeOverride //
  emulation.SetGeolocationOverride //
  emulation.SetLocaleOverride //
  emulation.SetMediaFeaturesOverride //
  emulation.SetNetworkConditions //
  emulation.SetScreenOrientationOverride //
  emulation.SetScreenSettingsOverride //
  emulation.SetScriptingEnabled //
  emulation.SetScrollbarTypeOverride //
  emulation.SetTextLayoutModeOverride //
  emulation.SetTimezoneOverride //
  emulation.SetTouchOverride //
  emulation.SetUserAgentOverride //
  emulation.SetViewportMetaOverride
)

EmulationResult = (
  emulation.SetForcedColorsModeThemeOverrideResult /
  emulation.SetGeolocationOverrideResult /
  emulation.SetLocaleOverrideResult /
  emulation.SetMediaFeaturesOverrideResult /
  emulation.SetScreenOrientationOverrideResult /
  emulation.SetScriptingEnabledResult /
  emulation.SetScrollbarTypeOverrideResult /
  emulation.SetTextLayoutModeOverrideResult /
  emulation.SetTimezoneOverrideResult /
  emulation.SetTouchOverrideResult /
  emulation.SetUserAgentOverrideResult /
  emulation.SetViewportMetaOverrideResult
)

一个 BiDi 会话具有一个模拟用户代理,它是一个具有 一个名为 默认用户代理的项的结构体,该项是字符串或 null; 一个名为 用户上下文用户代理的项,该项是 用户上下文与 字符串之间的弱映射;以及一个名为 可导航用户代理的项,该项是 可导航与字符串之间的弱映射。

一个 BiDi 会话具有 模拟 maxTouchPoints,它是一个结构体,具有 一个名为 default 的项,该项是整数或 null,初始为 null; 一个名为 user contexts 的项,该项是 用户上下文与整数之间的弱映射, 初始为空; 以及一个名为 navigables 的项,该项是 可导航与整数之间的弱映射,初始为空。

屏幕 方向覆盖是一个具有以下内容的结构体:

一个远程端具有一个 屏幕方向覆盖映射,它是 用户上下文与 屏幕 方向覆盖之间的弱 映射。

7.4.2. 命令

7.4.2.1. emulation.setForcedColorsModeThemeOverride 命令

emulation.setForcedColorsModeThemeOverride 命令修改 给定顶级可遍历对象或用户上下文上的强制颜色模式主题特征。

命令类型
emulation.SetForcedColorsModeThemeOverride = (
  method: "emulation.setForcedColorsModeThemeOverride",
  params: emulation.SetForcedColorsModeThemeOverrideParameters
)

emulation.SetForcedColorsModeThemeOverrideParameters = {
  theme: emulation.ForcedColorsModeTheme / null,
  ? contexts: [+browsingContext.BrowsingContext],
  ? userContexts: [+browser.UserContext],
}

emulation.ForcedColorsModeTheme = "light" / "dark"
返回类型
emulation.SetForcedColorsModeThemeOverrideResult = EmptyResult

注:请参阅 ForcedColorsModeAutomationTheme, 了解 CSS 规范中对应的枚举映射。

一个远端具有一个强制颜色模式主题覆盖 配置,它是 一个WebDriver 配置,其关联类型为字符串。

要为可导航对象 navigable 更新模拟的强制颜色主题:
  1. 令 theme 为对 navigable 的 强制颜色模式主题 覆盖配置执行获取 WebDriver 配置值所得的结果。

  2. 断言:theme 是 "light"、"dark" 或 未设置。

  3. 如果 theme 为未设置,则将 theme 设置为 "none"。

  4. 使用 navigable 和 theme 设置模拟的强制颜色主题数据。

给定 command parameters 的远端步骤为:

  1. 令 theme 为 command parameters["theme"]。

  2. 如果 theme 为 null,则将 theme 设置为未设置。

  3. 如果实现不支持设置 theme,则返回带有错误的错误 代码 不支持的操作。

  4. 令 affected navigables 为尝试存储 WebDriver 配置 强制颜色模式主题 覆盖配置 theme(针对 command parameters)所得的结果。

  5. 对于 affected navigables 中的每个 navigable:

    1. 为 navigable 更新模拟的强制颜色 主题。

  6. 返回数据为 null 的成功。

7.4.2.2. emulation.setGeolocationOverride 命令

emulation.setGeolocationOverride 命令修改 给定顶级可遍历对象或用户上下文上的地理位置特征。

命令类型
emulation.SetGeolocationOverride = (
  method: "emulation.setGeolocationOverride",
  params: emulation.SetGeolocationOverrideParameters
)

emulation.SetGeolocationOverrideParameters = {
  (
    (coordinates: emulation.GeolocationCoordinates / null) //
    (error: emulation.GeolocationPositionError)
  ),
  ? contexts: [+browsingContext.BrowsingContext],
  ? userContexts: [+browser.UserContext],
}

emulation.GeolocationCoordinates = {
   latitude: -90.0..90.0,
   longitude: -180.0..180.0,
   ? accuracy: (float .ge 0.0) .default 1.0,
   ? altitude: float / null .default null,
   ? altitudeAccuracy: (float .ge 0.0) / null .default null,
   ? heading: (0.0...360.0) / null .default null,
   ? speed: (float .ge 0.0) / null .default null,
}

emulation.GeolocationPositionError = {
   type: "positionUnavailable"
}
返回类型
emulation.SetGeolocationOverrideResult = EmptyResult

地理位置 覆盖是一个具有以下成员的结构:

一个远端具有一个地理位置覆盖配置,它是 一个WebDriver 配置,其关联类型为地理位置覆盖。

要为可导航对象 navigable 更新 地理位置覆盖:
  1. 令 emulated position data 为对 navigable 的地理位置覆盖配置执行获取 WebDriver 配置值所得的结果。

  2. 如果 emulated position data 为未设置,则将 emulated position data 设置为 null。

  3. 使用 navigable 和 emulated position data 设置模拟的位置数据。

给定 command parameters 的远端步骤为:

  1. 如果 command parameters 包含 "coordinates",并且 command parameters["coordinates"] 包含 "altitudeAccuracy",并且 command parameters["coordinates"] 不包含 "altitude",则返回带有错误,其错误代码为 无效参数。

  2. 如果 command parameters 包含 "error":

    1. 断言 command parameters["error"]["type"] 等于 "positionUnavailable"。

    2. 令 emulated position data 为与 GeolocationPositionError 产生式匹配的映射, 其中 code 字段设置为POSITION_UNAVAILABLE 且 message 字段设置为空字符串。

      注:根据地理位置规范,message 将被 实现忽略。

  3. 否则,令 emulated position data 为 command parameters["coordinates"]。

  4. 如果 emulated position data 为 null,则将 emulated position data 设置为 未设置。

  5. 令 affected navigables 为尝试为 command parameters 存储 WebDriver 配置 地理位置覆盖配置 emulated position data 的结果。

  6. 对于 affected navigables 中的每个 navigable:

    1. 为 navigable 更新地理位置覆盖。

  7. 返回带有数据 null 的成功。

7.4.2.3. emulation.setLocaleOverride 命令

emulation.setLocaleOverride 命令修改 给定顶级可遍历对象或用户上下文上的区域设置。

命令类型
emulation.SetLocaleOverride = (
  method: "emulation.setLocaleOverride",
  params: emulation.SetLocaleOverrideParameters
)

emulation.SetLocaleOverrideParameters = {
  locale: text / null,
  ? contexts: [+browsingContext.BrowsingContext],
  ? userContexts: [+browser.UserContext],
}
返回类型
emulation.SetLocaleOverrideResult = EmptyResult

给定一个环境设置对象 environment settings 时,WebDriver BiDi 模拟语言步骤如下:

  1. 令 related navigables 为给定 environment settings 时获取相关可导航对象的结果。

  2. 对于 related navigables 中的每个 navigable:

    1. 令 top-level traversable 为 navigable 的 顶层可遍历对象。

    2. 令 user context 为 top-level traversable 的关联的 用户上下文。

    3. 如果区域设置覆盖映射包含 top-level traversable,则返回 区域设置覆盖映射[top-level traversable]。

    4. 如果区域设置覆盖映射包含 user context,则返回 区域设置覆盖映射[user context]。

  3. 返回 null

使用 command parameters 时的远端步骤如下:

  1. 如果 command parameters 包含 "userContexts" 且 command parameters 包含 "contexts", 则返回带有错误,其错误 代码为无效参数。

  2. 如果 command parameters 不包含 "userContexts" 且 command parameters 不包含 "contexts", 则返回带有错误,其错误 代码为无效参数。

  3. 令 emulated locale 为 command parameters["locale"]。

  4. 如果 emulated locale 不为 null,且 IsStructurallyValidLanguageTag(emulated locale) 返回 false,则返回带有错误,其错误 代码为无效参数。

  5. 令 navigables 为一个集合。

  6. 如果 command parameters 的 contexts 字段存在:

    1. 令 navigables 为尝试使用 command parameters["contexts"] 按 id 获取有效顶层 可遍历对象的结果。

  7. 否则:

    1. 断言 command parameters 的 userContexts 字段存在。

    2. 令 user contexts 为尝试使用 command parameters["userContexts"] 获取有效用户上下文 的结果。

    3. 对于 user contexts 中的每个 user context:

      1. 如果 emulated locale 为 null,则从区域设置覆盖映射中移除 user context。

      2. 否则,将区域设置 覆盖映射[user context] 设置为 emulated locale。

      3. 对于所有顶层可遍历对象的列表中,其关联的用户上下文为 user context 的每个 top-level traversable:

        1. 将 top-level traversable 追加到 navigables。

  8. 对于 navigables 中的每个 navigable:

    1. 如果 emulated locale 为 null,则从区域设置覆盖映射中移除 navigable。

    2. 否则,将区域设置覆盖映射[navigable] 设置为 emulated locale。

  9. 返回带有数据 null 的成功。

7.4.2.4. emulation.setMediaFeaturesOverride 命令

emulation.setMediaFeaturesOverride 命令 允许覆盖各种媒体特性的值。

命令类型
emulation.SetMediaFeaturesOverride = (
  method: "emulation.setMediaFeaturesOverride",
  params: emulation.SetMediaFeaturesOverrideParameters
)

emulation.SetMediaFeaturesOverrideParameters = {
  features: emulation.MediaFeatures / null,
  ? contexts: [+browsingContext.BrowsingContext],
  ? userContexts: [+browser.UserContext],
}

emulation.MediaFeatures = {
  ? "any-hover": "none" / "hover" / null,
  ? "any-pointer": "none" / "coarse" / "fine" / null,
  ? "color": js-uint / null,
  ? "color-gamut": "srgb" / "p3" / "rec2020" / null,
  ? "color-index": js-uint / null,
  ? "display-mode": "fullscreen" / "standalone" / "minimal-ui" / "browser" / "picture-in-picture" / null,
  ? "dynamic-range": "standard" / "high" / null,
  ? "environment-blending": "opaque" / "additive" / "subtractive" / null,
  ? "forced-colors": "none" / "active" / null,
  ? "grid": 0 / 1 / null,
  ? "horizontal-viewport-segments": js-uint / null,
  ? "hover": "none" / "hover" / null,
  ? "inverted-colors": "none" / "inverted" / null,
  ? "monochrome": js-uint / null,
  ? "nav-controls": "none" / "back" / null,
  ? "overflow-block": "none" / "scroll" / "optional-paged" / "paged" / null,
  ? "overflow-inline": "none" / "scroll" / null,
  ? "pointer": "none" / "coarse" / "fine" / null,
  ? "prefers-color-scheme": "light" / "dark" / null,
  ? "prefers-contrast": "no-preference" / "more" / "less" / "custom" / null,
  ? "prefers-reduced-data": "no-preference" / "reduce" / null,
  ? "prefers-reduced-motion": "no-preference" / "reduce" / null,
  ? "prefers-reduced-transparency": "no-preference" / "reduce" / null,
  ? "scan": "interlace" / "progressive" / null,
  ? "scripting": "none" / "initial-only" / "enabled" / null,
  ? "update": "none" / "slow" / "fast" / null,
  ? "vertical-viewport-segments": js-uint / null,
  ? "video-color-gamut": "srgb" / "p3" / "rec2020" / null,
  ? "video-dynamic-range": "standard" / "high" / null,
}

返回类型
emulation.SetMediaFeaturesOverrideResult = EmptyResult

一个远端具有一个媒体特性覆盖配置, 它是 一个WebDriver 配置,其关联类型为映射。

要获取 Document document 和媒体 特性名称 name 的 WebDriver BiDi 媒体特性值:
  1. 令 navigable 为 document 的节点可导航对象。

  2. 令 media features override map 为对 navigable 的媒体特性覆盖配置 执行获取 WebDriver 配置值所得的结果。

  3. 如果 media features override map 不是未设置 且 media features override map 包含 name,则返回 media features override map[name]。

  4. 返回 null。

给定 command parameters 的远端步骤为:

  1. 令 media features override 为 command parameters["features"]。

  2. 如果 media features override 为 null,则将 media features override 设置为 未设置。

  3. 令 media features override map 为一个空映射。

  4. 对于 media features override 中的每个 media feature:

    1. 将 media features override map[media feature["name"]] 设置为 media feature["value"]。

  5. 如果实现不支持覆盖 media features override map 中的任何媒体特性,则返回带有错误的错误代码 不支持的操作。

  6. 令 affected navigables 为针对 command parameters 存储 WebDriver 配置 媒体特性覆盖 配置 media features override map 所得的结果。

  7. 对于 affected navigables 中的每个 navigable:

    1. 对于当前加载在 navigable 或其后代可导航对象中的每个 document,逐一执行:

      1. 为 document 运行求值媒体 查询并报告更改。

  8. 返回数据为 null 的成功。

7.4.2.5. emulation.setNetworkConditions 命令

emulation.setNetworkConditions 命令 为给定浏览上下文或用户 上下文模拟特定网络条件。

命令类型
emulation.SetNetworkConditions = (
  method: "emulation.setNetworkConditions",
  params: emulation.SetNetworkConditionsParameters
)

emulation.SetNetworkConditionsParameters = {
  networkConditions: emulation.NetworkConditions / null,
  ? contexts: [+browsingContext.BrowsingContext],
  ? userContexts: [+browser.UserContext],
}

emulation.NetworkConditions = emulation.NetworkConditionsOffline

emulation.NetworkConditionsOffline = {
  type: "offline"
}
返回类型
emulation.SetNetworkConditionsResult = EmptyResult

要应用网络 条件:

  1. 对于每个 WebSocket 对象 webSocket:

    1. 令 realm 为 webSocket 的相关 Realm。

    2. 令 environment settings 为这样一个环境设置对象:其 Realm 执行上下文的 Realm 组件 为 realm。

    3. 如果使用 environment settings 执行WebDriver BiDi 网络处于离线状态 所得结果为 true:

      1. 使 webSocket 的 WebSocket 连接失败。

  2. 对于每个 WebTransport 对象 webTransport:

    1. 令 realm 为 webSocket 的相关 Realm。

    2. 令 environment settings 为这样一个环境设置对象:其 Realm 执行上下文的 Realm 组件 为 realm。

    3. 如果使用 environment settings 执行WebDriver BiDi 网络 处于离线状态所得结果为 true:

      1. 对 webTransport 清理 WebTransport。

使用 command parameters 和 session 时的远端步骤如下:

  1. 如果 command parameters 包含 "userContexts" 且 command parameters 包含 "context", 则返回带有错误,其错误 代码为无效参数。

  2. 令 emulated network conditions 为 null。

  3. 如果 command parameters["networkConditions"] 不为 null,且 command parameters["networkConditions"]["type"] 等于 "offline",则将 emulated network conditions 设置为一个新的 模拟网络条件结构体,其中 离线设置为 true。

  4. 如果 command parameters 的 contexts 字段存在:

    1. 令 navigables 为尝试使用 command parameters["contexts"] 按 id 获取有效顶层 可遍历对象的结果。

    2. 对于 navigables 中的每个 navigable:

      1. 如果 emulated network conditions 为 null,则从 session 的模拟网络 条件的 可导航对象 网络条件中移除 navigable

      2. 否则,将 session 的模拟网络 条件的 可导航对象 网络条件[navigable] 设置为 emulated network conditions。

  5. 如果 command parameters 的 userContexts 字段存在:

    1. 令 user contexts 为尝试使用 command parameters["userContexts"] 获取有效用户上下文 的结果。

    2. 对于 user contexts 中的每个 user context:

      1. 如果 emulated network conditions 为 null,则从 session 的模拟网络 条件的 用户 上下文网络条件中移除 user context。

      2. 否则,将 session 的模拟网络 条件的 用户 上下文网络条件[user context] 设置为 emulated network conditions。

  6. 如果 command parameters 不包含 "userContexts" 且 command parameters 不包含 "context", 则将 session 的模拟网络条件的 默认网络 条件 设置为 emulated network conditions。

  7. 应用网络条件。

  8. 返回带有数据 null 的成功。

7.4.2.6. emulation.setScreenSettingsOverride 命令

emulation.setScreenSettingsOverride 命令 模拟给定顶级可遍历对象或用户上下文的Web 暴露的屏幕区域和Web 暴露的可用屏幕区域。

命令类型
emulation.SetScreenSettingsOverride = (
  method: "emulation.setScreenSettingsOverride",
  params: emulation.SetScreenSettingsOverrideParameters
)

emulation.ScreenArea = {
  width: js-uint,
  height: js-uint
}

emulation.SetScreenSettingsOverrideParameters = {
  screenArea: emulation.ScreenArea / null,
  ? contexts: [+browsingContext.BrowsingContext],
  ? userContexts: [+browser.UserContext],
}
返回类型
emulation.SetScreenSettingsOverrideResult = EmptyResult

给定可导航对象 navigable 时,WebDriver BiDi 模拟可用屏幕 区域步骤如下:

  1. 令 top-level traversable 为 navigable 的顶层可遍历对象。

  2. 令 user context 为 top-level traversable 的关联的用户 上下文。

  3. 如果屏幕设置覆盖包含 top-level traversable,则返回 屏幕设置覆盖[top-level traversable]。

  4. 如果屏幕设置覆盖包含 user context,则返回 屏幕设置覆盖[user context]。

  5. 返回 null

给定可导航对象 navigable 时,WebDriver BiDi 模拟总屏幕区域步骤 如下:

  1. 令 top-level traversable 为 navigable 的顶层可遍历对象。

  2. 令 user context 为 top-level traversable 的关联的用户 上下文。

  3. 如果屏幕设置覆盖包含 top-level traversable,则返回 屏幕设置覆盖[top-level traversable]。

  4. 如果屏幕设置覆盖包含 user context,则返回 屏幕设置覆盖[user context]。

  5. 返回 null

使用 command parameters 时的远端步骤如下:

  1. 如果 command parameters 包含 "userContexts" 且 command parameters 包含 "contexts", 则返回带有错误,其错误 代码为无效参数。

  2. 如果 command parameters 不包含 "userContexts" 且 command parameters 不包含 "contexts", 则返回带有错误,其错误 代码为无效参数。

  3. 令 emulated screen area 为 command parameters["screenArea"]。

  4. 如果 emulated screen area 不为 null:

    1. 将 emulated screen area["x"] 设置为 0。

    2. 将 emulated screen area["y"] 设置为 0。

  5. 令 navigables 为一个集合。

  6. 如果 command parameters 的 contexts 字段存在:

    1. 令 navigables 为尝试使用 command parameters["contexts"] 按 id 获取有效顶层 可遍历对象的结果。

    2. 令 target 为可导航对象屏幕 设置。

    3. 对于 navigables 中的每个 navigable:

      1. 如果 emulated screen area 为 null,则从 target 中移除 navigable 。

      2. 否则,将 target[navigable] 设置 为 emulated screen area。

    4. 返回带有数据 null 的成功。

  7. 否则:

    1. 断言 command parameters 的 userContexts 字段存在。

    2. 令 user contexts 为尝试使用 command parameters["userContexts"] 获取有效用户上下文 的结果。

    3. 令 target 为用户上下文 屏幕设置。

    4. 对于 user contexts 中的每个 user context:

      1. 如果 emulated screen area 为 null,则从 target 中移除 user context。

      2. 否则,将 target[user context] 设置为 emulated screen area。

    5. 返回带有数据 null 的成功。

7.4.2.7. emulation.setScreenOrientationOverride 命令

emulation.setScreenOrientationOverride 命令 模拟给定顶级可遍历对象或用户 上下文的屏幕方向。

命令类型
emulation.SetScreenOrientationOverride = (
  method: "emulation.setScreenOrientationOverride",
  params: emulation.SetScreenOrientationOverrideParameters
)

emulation.ScreenOrientationNatural = "portrait" / "landscape"
emulation.ScreenOrientationType = "portrait-primary" / "portrait-secondary" / "landscape-primary" / "landscape-secondary"

emulation.ScreenOrientation = {
  natural: emulation.ScreenOrientationNatural,
  type: emulation.ScreenOrientationType
}

emulation.SetScreenOrientationOverrideParameters = {
  screenOrientation: emulation.ScreenOrientation / null,
  ? contexts: [+browsingContext.BrowsingContext],
  ? userContexts: [+browser.UserContext],
}
返回类型
emulation.SetScreenOrientationOverrideResult = EmptyResult

给定 navigable 和 emulated screen orientation,要设置 模拟屏幕方向:

将此算法移至 屏幕方向规范。

  1. 如果 emulated screen orientation 为 null:

    1. 将 navigable 的当前方向角度设置为 实现定义的默认值。

    2. 将 navigable 的当前方向类型设置为 实现定义的默认值。

  2. 否则:

    1. 令 emulated orientation type 为 emulated screen orientation["type"]。

    2. 令 emulated orientation angle 为在具有 emulated screen orientation["natural"] 方向的屏幕上 与 emulated orientation type 关联的角度,如屏幕方向值 列表中所定义。

    3. 将当前方向角度设置为 emulated orientation angle。

    4. 将当前方向类型设置为 emulated orientation type。

  3. 使用 navigable 的 活动文档运行屏幕方向更改步骤。

使用 command parameters 时的远端步骤如下:

  1. 如果实现由于任何原因无法使用给定的 command parameters 调整屏幕方向 参数,则返回带有错误,其错误 代码为不支持的操作。

  2. 如果 command parameters 包含 "userContexts" 且 command parameters 包含 "contexts", 则返回带有错误,其错误 代码为无效参数。

  3. 如果 command parameters 不包含 "userContexts" 且 command parameters 不包含 "contexts", 则返回带有错误,其错误 代码为无效参数。

  4. 令 emulated screen orientation 为 command parameters["screenOrientation"]。

  5. 令 navigables 为一个集合。

  6. 如果 command parameters 的 contexts 字段存在:

    1. 令 navigables 为尝试使用 command parameters["contexts"] 按 id 获取有效顶层 可遍历对象的结果。

  7. 否则,如果 command parameters 的 userContexts 字段 存在:

    1. 令 user contexts 为尝试使用 command parameters["userContexts"] 获取有效用户上下文 的结果。

    2. 对于 user contexts 中的每个 user context:

      1. 如果 emulated screen orientation 为 null,则从 屏幕方向覆盖 映射中移除 user context。

      2. 否则,将屏幕方向覆盖 映射[user context] 设置为 emulated screen orientation。

      3. 对于所有 顶层可遍历对象的列表中,其关联的用户上下文为 user context 的每个 top-level traversable:

        1. 将 top-level traversable 追加到 navigables。

  8. 对于 navigables 中的每个 navigable:

    1. 令 user context 为 navigable 的关联的 用户上下文。

    2. 如果 emulated screen orientation 为 null,且屏幕方向覆盖映射 包含 user context,则使用 navigable 和 屏幕方向覆盖 映射[user context] 设置模拟屏幕方向。

    3. 否则,使用 navigable 和 emulated screen orientation 设置模拟屏幕方向。

  9. 返回带有数据 null 的成功。

7.4.2.8. emulation.setUserAgentOverride 命令

emulation.setUserAgentOverride 命令修改 给定顶级可遍历对象、用户上下文或全局的 User-Agent。

命令类型
emulation.SetUserAgentOverride = (
  method: "emulation.setUserAgentOverride",
  params: emulation.SetUserAgentOverrideParameters
)

emulation.SetUserAgentOverrideParameters = {
  userAgent: text / null,
  ? contexts: [+browsingContext.BrowsingContext],
  ? userContexts: [+browser.UserContext],
}
返回类型
emulation.SetUserAgentOverrideResult = EmptyResult
给定 环境设置对象 environment settings 的 WebDriver BiDi 模拟 User-Agent步骤为:
  1. 令 related navigables 为使用 environment settings 获取相关 可导航对象所得的结果。

  2. 对于 related navigables 中的每个 navigable:

    1. 令 top-level navigable 为 navigable 的顶级可遍历对象。

    2. 令 user context 为 top-level navigable 的关联 用户上下文。

    3. 对于活动 BiDi 会话中的每个 session:

      1. 如果 session 的模拟用户代理的可导航对象用户 代理包含 top-level navigable,则返回 session 的模拟用户代理的 可导航对象用户 代理[top-level navigable]。

    4. 对于活动 BiDi 会话中的每个 session:

      1. 如果 session 的模拟用户代理的用户上下文用户 代理 包含 user context,则返回 session 的模拟用户代理的 用户上下文用户 代理[user context]。

  3. 对于活动 BiDi 会话中的每个 session:

    1. 令 default emulated user agent 为 session 的模拟用户代理的 默认用户代理。

    2. 如果 default emulated user agent 不为 null,则返回 default emulated user agent。

  4. 返回 null。

给定 session 和 command parameters 时,远端步骤如下:

  1. 如果 command parameters 包含 "userContexts" 且 command parameters 包含 "contexts", 则返回带有错误,其错误 代码为无效参数。

  2. 令 emulated user agent 为 command parameters["userAgent"]。

  3. 如果 command parameters 包含 "contexts":

    1. 令 navigables 为尝试使用 command parameters["contexts"] 按 id 获取有效顶层 可遍历对象的结果。

    2. 对于 navigables 中的每个 navigable:

      1. 如果 emulated user agent 为 null,则从 session 的模拟用户代理的可导航对象用户 代理中移除 navigable。

      2. 否则,将 session 的模拟用户代理的 可导航对象用户 代理[navigable] 设置为 emulated user agent。

    3. 返回带有数据 null 的成功。

  4. 如果 command parameters 包含 "userContexts":

    1. 令 user contexts 为尝试使用 command parameters["userContexts"] 获取有效用户上下文 的结果。

    2. 对于 user contexts 中的每个 user context:

      1. 如果 emulated user agent 为 null,则从 session 的模拟用户代理的用户上下文用户 代理中移除 user context。

      2. 否则,将 session 的模拟用户代理的 用户上下文用户 代理[user context] 设置为 emulated user agent。

    3. 返回带有数据 null 的成功。

  5. 将 session 的模拟用户 代理的默认用户代理设置为 emulated user agent。

  6. 返回带有数据 null 的成功。

7.4.2.9. emulation.setViewportMetaOverride 命令

emulation.setViewportMetaOverride 命令修改 浏览器是否遵循 <meta name=viewport> 标签。

命令类型
emulation.SetViewportMetaOverride = (
  method: "emulation.setViewportMetaOverride",
  params: emulation.SetViewportMetaOverrideParameters
)

emulation.SetViewportMetaOverrideParameters = {
  viewportMeta: true / null,
  ? contexts: [+browsingContext.BrowsingContext],
  ? userContexts: [+browser.UserContext],
}
返回类型
emulation.SetViewportMetaOverrideResult = EmptyResult

一个远端具有一个viewport meta 覆盖配置, 它是 一个WebDriver 配置,其关联类型为布尔值。

给定 Document document 的 WebDriver BiDi viewport meta 状态步骤为:

  1. 令 navigable 为 document 的节点可导航对象。

  2. 令 viewport meta override 为对 navigable 的viewport meta 覆盖配置 执行获取 WebDriver 配置值所得的结果。

  3. 如果 viewport meta override 为未设置,则返回 null。

  4. 返回 viewport meta override。

给定 command parameters 的远端步骤为:

  1. 令 viewport meta override 为 command parameters["viewportMeta"]。

  2. 如果 viewport meta override 为 null,则将 viewport meta override 设置为 未设置。

  3. 令 affected navigables 为尝试存储 WebDriver 配置 viewport meta 覆盖配置 viewport meta override(针对 command parameters)所得的结果。

  4. 对于 affected navigables 中的每个 navigable,为当前加载在指定 navigable 中的文档运行求值媒体查询并报告 更改。

  5. 返回数据为 null 的成功。

7.4.2.10. emulation.setScriptingEnabled 命令

emulation.setScriptingEnabled 命令模拟 在网页上禁用 JavaScript。

命令类型
emulation.SetScriptingEnabled = (
  method: "emulation.setScriptingEnabled",
  params: emulation.SetScriptingEnabledParameters
)

emulation.SetScriptingEnabledParameters = {
  enabled: false / null,
  ? contexts: [+browsingContext.BrowsingContext],
  ? userContexts: [+browser.UserContext],
}
返回类型
emulation.SetScriptingEnabledResult = EmptyResult

注:仅支持模拟禁用的 JavaScript。

给定 环境设置对象 settings 的 WebDriver BiDi 脚本已启用步骤为:
  1. 令 navigable 为 settings 的相关全局对象的 关联的 Document的节点可导航对象。

  2. 令 top-level traversable 为 navigable 的顶级可遍历对象。

  3. 如果脚本启用覆盖映射包含 top-level traversable,则返回 脚本启用覆盖 映射[top-level traversable]

  4. 令 user context 为 top-level traversable 的关联用户 上下文。

  5. 如果脚本启用覆盖映射包含 user context,则返回 脚本启用覆盖映射[user context]。

  6. 返回 true。

使用 command parameters 时的远端步骤如下:

  1. 如果 command parameters 包含 "userContexts" 且 command parameters 包含 "contexts", 则返回带有错误,其错误 代码为无效参数。

  2. 如果 command parameters 不包含 "userContexts" 且 command parameters 不包含 "contexts", 则返回带有错误,其错误 代码为无效参数。

  3. 令 emulated scripting enabled status 为 command parameters["enabled"]。

  4. 如果 command parameters 的 contexts 字段存在:

    1. 令 navigables 为尝试使用 command parameters["contexts"] 按 id 获取有效顶层 可遍历对象的结果。

    2. 对于 navigables 中的每个 navigable:

      1. 如果 emulated scripting enabled status 为 null,则从 脚本启用覆盖 映射中移除 navigable。

      2. 否则,将脚本启用覆盖 映射[navigable] 设置为 emulated scripting enabled status。

  5. 如果 command parameters 的 userContexts 字段存在:

    1. 令 user contexts 为尝试使用 command parameters["userContexts"] 获取有效用户上下文 的结果。

    2. 对于 user contexts 中的每个 user context:

      1. 如果 emulated scripting enabled status 为 null,则从 脚本启用覆盖 映射中移除 user context。

      2. 否则,将脚本启用覆盖 映射[user context] 设置为 emulated scripting enabled status。

  6. 返回带有数据 null 的成功。

7.4.2.11. emulation.setScrollbarTypeOverride 命令

emulation.setScrollbarTypeOverride 命令 修改 给定顶级可遍历对象、用户上下文或全局的滚动条类型。

命令类型
emulation.SetScrollbarTypeOverride = (
  method: "emulation.setScrollbarTypeOverride",
  params: emulation.SetScrollbarTypeOverrideParameters
)

emulation.SetScrollbarTypeOverrideParameters = {
  scrollbarType: "classic" / "overlay" / null,
  ? contexts: [+browsingContext.BrowsingContext],
  ? userContexts: [+browser.UserContext],
}
返回类型
emulation.SetScrollbarTypeOverrideResult = EmptyResult

一个远端具有一个滚动条类型覆盖配置, 它是 一个WebDriver 配置,其关联类型为字符串。

要为可导航对象 navigable 更新 滚动条类型覆盖:
  1. 令 scrollbar type override 为对 navigable 的滚动条类型覆盖配置 执行获取 WebDriver 配置值所得的结果。

  2. 断言:scrollbar type override 是 "classic"、 "overlay" 或 未设置。

  3. 如果 scrollbar type override 为 "classic",则运行实现定义的步骤,使 navigable 的活动文档使用经典滚动条,然后返回。

  4. 如果 scrollbar type override 为 "overlay",则运行实现定义的 步骤,使 navigable 的活动文档使用覆盖式滚动条,然后返回。

  5. 断言:scrollbar type override 为未设置。

  6. 运行实现定义的步骤,使 navigable 的活动文档 使用一种实现定义的默认滚动条类型。

给定 command parameters 时的远端步骤如下:

  1. 令 scrollbar type override 为 command parameters["scrollbarType"]。

  2. 如果 scrollbar type override 为 null,则将 scrollbar type override 设置为 未设置。

  3. 如果实现不支持设置 scrollbar type override,则返回错误 ,其错误代码为不支持的操作。

  4. 令 affected navigables 为尝试为 command parameters 存储 WebDriver 配置 滚动条类型覆盖 配置 scrollbar type override 的结果。

  5. 对于 affected navigables 中的每个 navigable:

    1. 为 navigable 更新滚动条类型覆盖。

  6. 返回带有数据 null 的成功。

7.4.2.12. emulation.setTextLayoutModeOverride 命令

emulation.setTextLayoutModeOverride 命令 修改 给定顶层可遍历对象、用户上下文或全局的文本布局模式。

命令类型
emulation.SetTextLayoutModeOverride = (
  method: "emulation.setTextLayoutModeOverride",
  params: emulation.SetTextLayoutModeOverrideParameters
)

emulation.SetTextLayoutModeOverrideParameters = {
  textLayoutMode: emulation.TextLayoutMode / null,
  ? contexts: [+browsingContext.BrowsingContext],
  ? userContexts: [+browser.UserContext],
}

emulation.TextLayoutMode = "mobile"
返回类型
emulation.SetTextLayoutModeOverrideResult = EmptyResult

一个远端具有一个文本布局模式覆盖 配置,它是具有WebDriver 配置,其关联类型为字符串。

要为可导航对象 navigable 更新 文本布局模式覆盖:

注:文本布局模式 "mobile" 会启用 文本自动调整大小(字体 膨胀),这是一种主要用于移动设备的算法,用于在将文本块适配到 较小视口时提高其可读性。这可确保 内容保持可读,而无需用户放大。此 行为通常通过 text-size-adjust CSS 属性控制。 参见 [CSS-SIZE-ADJUST-1]。

  1. 令 text layout mode override 为针对 navigable 的 文本布局模式覆盖 配置执行获取 WebDriver 配置值的结果。

  2. 断言:text layout mode override 为 "mobile" 或 未设置。

  3. 如果 text layout mode override 为 "mobile",则运行实现定义的步骤,使 navigable 的活动文档使用 "mobile" 文本布局 模式。

  4. 否则,运行实现定义的步骤,使 navigable 的活动文档 使用一个实现定义的默认文本布局模式。

给定 command parameters 时的远端步骤如下:

  1. 令 text layout mode override 为 command parameters["textLayoutMode"]。

  2. 如果 text layout mode override 为 null,则将 text layout mode override 设置为 未设置。

  3. 如果 text layout mode override 不是未设置 且实现不 支持设置文本布局模式覆盖,则返回带有错误,其错误代码为不支持的操作。

  4. 令 affected navigables 为尝试为 command parameters 存储 WebDriver 配置 文本布局模式覆盖 配置 text layout mode override 的结果。

  5. 对于 affected navigables 中的每个 navigable:

    1. 为 navigable 更新文本布局模式覆盖 。

  6. 返回带有数据 null 的成功。

7.4.2.13. emulation.setTimezoneOverride 命令

emulation.setTimezoneOverride 命令修改 给定顶层可遍历对象或用户上下文的时区。

命令类型
emulation.SetTimezoneOverride = (
  method: "emulation.setTimezoneOverride",
  params: emulation.SetTimezoneOverrideParameters
)

emulation.SetTimezoneOverrideParameters = {
  timezone: text / null,
  ? contexts: [+browsingContext.BrowsingContext],
  ? userContexts: [+browser.UserContext],
}
返回类型
emulation.SetTimezoneOverrideResult = EmptyResult
SystemTimeZoneIdentifier 算法是实现 定义的。WebDriver-BiDi 远端必须具有运行以下 步骤的实现:
  1. 令 emulated timezone 为 null。

  2. 令 realm 为当前 Realm 记录。

  3. 令 environment settings 为其 realm 执行上下文的 Realm 组件为 realm 的环境设置对象。

  4. 令 related navigables 为给定 environment settings 时获取相关 可导航对象的结果。

  5. 对于 related navigables 中的每个 navigable:

    1. 令 top-level traversable 为 navigable 的 顶层可遍历对象。

    2. 令 user context 为 top-level traversable 的关联的 用户上下文。

    3. 如果时区覆盖映射包含 top-level traversable,则将 emulated timezone 设置为时区覆盖映射[top-level traversable]。

    4. 否则,如果时区覆盖映射包含 user context,则将 emulated timezone 设置为 时区覆盖映射[user context]。

  6. 如果 emulated timezone 不为 null,则返回 emulated timezone。

  7. 返回按照 SystemTimeZoneIdentifier 规范要求执行实现定义步骤的结果。

使用 command parameters 时的远端步骤如下:

  1. 如果 command parameters 包含 "userContexts" 且 command parameters 包含 "contexts", 则返回带有错误,其错误 代码为无效参数。

  2. 如果 command parameters 不包含 "userContexts" 且 command parameters 不包含 "contexts", 则返回带有错误,其错误 代码为无效参数。

  3. 令 emulated timezone 为 command parameters["timezone"]。

  4. 如果 emulated timezone 不为 null,且 IsTimeZoneOffsetString(emulated timezone) 返回 false,并且 AvailableNamedTimeZoneIdentifiers 不包含 emulated timezone,则返回带有错误,其错误代码为无效参数。

  5. 令 navigables 为一个集合。

  6. 如果 command parameters 的 contexts 字段存在:

    1. 令 navigables 为尝试使用 command parameters["contexts"] 按 id 获取有效顶层 可遍历对象的结果。

  7. 否则:

    1. 断言 command parameters 的 userContexts 字段存在。

    2. 令 user contexts 为尝试使用 command parameters["userContexts"] 获取有效用户上下文 的结果。

    3. 对于 user contexts 中的每个 user context:

      1. 如果 emulated timezone 为 null,则从 时区覆盖映射中移除 user context。

      2. 否则,将时区 覆盖映射[user context] 设置为 emulated timezone。

      3. 对于所有 顶层可遍历对象的列表中,其关联的用户上下文为 user context 的每个 top-level traversable:

        1. 将 top-level traversable 追加到 navigables。

  8. 对于 navigables 中的每个 navigable:

    1. 如果 emulated timezone 为 null,则从时区覆盖映射中移除 navigable。

    2. 否则,将时区 覆盖映射[navigable] 设置为 emulated timezone。

  9. 返回带有数据 null 的成功。

7.4.2.14. emulation.setTouchOverride 命令

emulation.setTouchOverride 命令模拟 网页上已启用的触摸输入。

命令类型
emulation.SetTouchOverride = (
  method: "emulation.setTouchOverride",
  params: emulation.SetTouchOverrideParameters
)

emulation.SetTouchOverrideParameters = {
  maxTouchPoints: (js-uint .ge 1) / null,
  ? contexts: [+browsingContext.BrowsingContext],
  ? userContexts: [+browser.UserContext],
}
返回类型
emulation.SetTouchOverrideResult = EmptyResult
给定 环境设置对象 environment settings 时,WebDriver BiDi 模拟最大触摸点数步骤如下:
  1. 令 related navigables 为使用 environment settings 获取相关 可导航对象的结果。

  2. 对于 related navigables 中的每个 navigable:

    1. 令 top-level navigable 为 navigable 的顶层可遍历对象。

    2. 令 user context 为 top-level navigable 的关联的 用户上下文。

    3. 对于活动 BiDi 会话中的每个 session:

      1. 如果 session 的模拟 maxTouchPoints的 可导航对象包含 top-level navigable,则返回 session 的模拟 maxTouchPoints的 可导航对象[top-level navigable]。

    4. 对于活动 BiDi 会话中的每个 session:

      1. 如果 session 的模拟 maxTouchPoints的 用户上下文 包含 user context,则返回 session 的 模拟 maxTouchPoints的 用户 上下文[user context]。

  3. 对于活动 BiDi 会话中的每个 session:

    1. 令 emulated maxTouchPoints 为 session 的模拟 maxTouchPoints的 默认值。

    2. 如果 emulated maxTouchPoints 不为 null,则返回 emulated maxTouchPoints。

  4. 返回 null。

使用 session 和 command parameters 时的远端步骤如下:

注:存在一个旧版的公开旧版触摸事件 API, 某些现有 Web 内容仍可将其用作用户代理是支持触摸的“移动”设备的信号。即使该 API 是旧版 API,用户代理也可以运行实现定义的步骤,以在模拟 maxTouchPoints状态中遵循公开旧版触摸事件 API。

  1. 如果 command parameters 包含 "userContexts" 且 command parameters 包含 "contexts",则返回带有错误,其错误 代码为 无效参数。

  2. 令 maxTouchPoints 为 command parameters["maxTouchPoints"]。

  3. 如果 command parameters 的 contexts 字段存在:

    1. 令 navigables 为尝试使用 command parameters["contexts"] 按 id 获取有效顶层 可遍历对象的结果。

    2. 对于 navigables 中的每个 navigable:

      1. 如果 maxTouchPoints 为 null,则从 session 的 模拟 maxTouchPoints的 可导航对象中移除 navigable。

      2. 否则,将 session 的模拟 maxTouchPoints的 可导航对象[navigable] 设置为 maxTouchPoints。

    3. 返回带有数据 null 的成功。

  4. 如果 command parameters 的 userContexts 字段存在:

    1. 令 user contexts 为尝试使用 command parameters["userContexts"] 获取有效用户上下文的结果。

    2. 对于 user contexts 中的每个 user context:

      1. 如果 maxTouchPoints 为 null,则从 session 的 模拟 maxTouchPoints的 用户上下文中移除 user context。

      2. 否则,将 session 的模拟 maxTouchPoints的 用户 上下文[user context] 设置为 maxTouchPoints。

    3. 返回带有数据 null 的成功。

  5. 将 session 的模拟 maxTouchPoints的默认值 设置为 maxTouchPoints。

  6. 返回带有数据 null 的成功。

7.5. network 模块

network 模块包含与网络请求相关的命令和事件。

7.5.1. 定义

远程端定义

NetworkCommand = (
  network.AddDataCollector //
  network.AddIntercept //
  network.ContinueRequest //
  network.ContinueResponse //
  network.ContinueWithAuth //
  network.DisownData //
  network.FailRequest //
  network.GetData //
  network.ProvideResponse //
  network.RemoveDataCollector //
  network.RemoveIntercept //
  network.SetCacheBehavior //
  network.SetExtraHeaders
)

本地端定义

NetworkResult = (
  network.AddDataCollectorResult /
  network.AddInterceptResult /
  network.ContinueRequestResult /
  network.ContinueResponseResult /
  network.ContinueWithAuthResult /
  network.DisownDataResult /
  network.FailRequestResult /
  network.GetDataResult /
  network.ProvideResponseResult /
  network.RemoveDataCollectorResult /
  network.RemoveInterceptResult /
  network.SetCacheBehaviorResult /
  network.SetExtraHeadersResult
)

NetworkEvent = (
    network.AuthRequired //
    network.BeforeRequestSent //
    network.FetchError //
    network.ResponseCompleted //
    network.ResponseStarted
)

一个远端具有一个请求发送前映射,其初始为空 映射。它用于跟踪已经发送过 network.beforeRequestSent 事件的网络事件。

一个远端具有一个默认缓存行为,它是一个字符串。其 初始值为 "default"。

一个远端具有一个可导航对象缓存行为映射,它是 顶层可遍历对象与表示缓存 行为的字符串之间的弱映射。其初始为空。

一个BiDi 会话具有一个额外标头,它是一个 结构体,其中有 一个名为默认 标头的项,它是一个标头 列表(初始设置为空 标头列表);一个名为 用户上下文标头的项,它是 用户上下文与标头列表之间的弱映射;以及一个名为 可导航对象标头的项,它是 可导航对象与标头 列表之间的弱映射。

7.5.2. 网络数据收集

网络数据是一个具有以下内容的结构体:

collector 是一个具有以下内容的结构体:

注:max encoded item size 定义每项(响应或请求)的限制, 并不限制特定 collector 所收集的大小。所有已收集资源的总大小 由 最大总收集大小限制。

一个BiDi 会话具有网络收集器, 它是一个映射,映射于 network.Collector 与一个收集器之间。它 最初为空。

一个远端具有已收集的网络数据,它是一个由 网络数据组成的列表。它最初 为空。

一个远端具有一个最大已收集总大小,它是一个 js-uint, 表示 在已收集的网络数据中为收集网络数据而分配的大小。其 值由实现定义。

注:这允许实现设置资源使用 限制。 预期这些限制足够大,使用户可以依赖 收集已由浏览器完全解码和处理的数据, 例如网页中使用的图片和字体。

要在给定 request 的情况下获取 request 的 navigable:
  1. 令 navigable 为 null。

  2. 如果 request 的client 是一个环境设置对象:

    1. 令 environment settings 为 request 的client

    2. 如果存在一个navigable,其活动 window是 environment settings 的全局对象,则将 navigable 设置为该 navigable。

  3. 返回 navigable。

要在给定 collector 和 navigable 的情况下匹配 navigable 的 collector:
  1. 如果 collector 的contexts 不是空:

    1. 如果 collector 的contexts 包含 navigable 的navigable id,则返回 true。

    2. 否则,返回 false。

  2. 如果 collector 的user contexts 不是空:

    1. 令 user context 为 navigable 的关联 用户上下文。

    2. 如果 collector 的user contexts 包含 user context 的 用户上下文 id,则返回 true。

    3. 否则,返回 false。

  3. 返回 true。

给定 request request 时,WebDriver BiDi 克隆网络请求 body步骤为:
  1. 如果 request 的body 为 null,则返回。

  2. 对于 活动 BiDi 会话中的每个 session:

    1. 如果 session 的network collectors 不是空:

      1. 令 collected data 为一个network data,其中 bytes 设置为 null, cloned body 设置为 request 的body 的克隆, collectors 设置为空列表, pending 设置为 true, request 设置为 request 的request id, size 设置为 null, type 设置为 "request"。

      2. 将 collected data 追加到 collected network data。

      3. 返回。

给定 request 和 response body 时,WebDriver BiDi 克隆网络响应 body步骤为:
  1. 如果 response body 为 null,则返回。

  2. 对于 活动 BiDi 会话中的每个 session:

    1. 如果 session 的network collectors 不是空:

      1. 令 collected data 为一个network data,其中 bytes 设置为 null, cloned body 设置为 response body 的克隆, collectors 设置为空列表, pending 设置为 true, request 设置为 request 的 request id, size 设置为 null, type 设置为 "response"。

      2. 将 collected data 追加到 collected network data。

      3. 返回。

要在给定 request id 和 data type 的情况下获取 collected data。
  1. 对于 collected network data 中的每个 collected data:

    1. 如果 collected data 的request 是 request id,且 collected data 的type 是 data type,则返回 collected data。

  2. 返回 null。

要在给定 request 的情况下可能中止网络响应 body 收集:
  1. 令 collected data 为以 request 的request id 和 "response" 调用获取 collected data所得的结果。

  2. 如果 collected data 为 null,则返回。

  3. 将 collected data 的pending 设置为 false。

  4. 用 "network data collected" 和 (request 的request id, "response") 恢复。

要在给定 request 的情况下可能 收集网络请求 body:
  1. 令 collected data 为以 request 的request id 和 "request" 调用获取 collected data所得的结果。

  2. 如果 collected data 为 null,则返回。

    注:如果在创建请求时没有设置 collectors, 且 WebDriver BiDi 克隆网络请求 body未克隆对应的 body, 或者 body 一开始就是 null,则可能发生这种情况。

  3. 用 request、collected data、null 和 "request" 调用可能收集 network data。

要在给定 request 和 response 的情况下可能 收集网络响应 body:
  1. 如果 response 的status 是redirect status,则返回。

    注:对于重定向,仅存储最终响应 body。

  2. 令 collected data 为以 request 的request id 和 "response" 调用获取 collected data所得的结果。

  3. 如果 collected data 为 null,则返回。

    注:如果在创建响应时没有设置 collectors, 且 WebDriver BiDi 克隆网络 响应 body未克隆对应的 body, 或者 body 一开始就是 null,则可能发生这种情况。

  4. 令 size 为 response 的response body info 的encoded size。

    注:从 fetch stream 检索的 bytes 对应于已解码数据这一事实与为了计算大小限制而使用编码(网络)大小之间存在差异。 实现可以决定使用这样的存储模型:只要在 getData 中返回给客户端的数据与已解码数据相同, 其使用的大小就可以小于存储已解码数据所需的大小。存储与性能之间的潜在 取舍由实现决定。

  5. 用 request、collected data、size 和 "response" 调用可能收集 network data。

要在给定 request request、 network data collected data、js-uint size 和 network.DataType data type 的情况下可能收集 network data:
  1. 将 collected data 的pending 设置为 false。

  2. 令 navigable 为以 request 调用获取 request 的 navigable所得的结果。

  3. 如果 navigable 为 null:

    1. 从 collected network data中移除 collected data。

    2. 用 "network data collected" 和 (request 的request id, data type) 恢复。

    3. 返回。

    这会阻止 收集与 navigable 无关的数据。 我们仍然需要检索 navigable 以对照 collector 配置进行检查,但这里仍可接受 null。

  4. 令 top-level navigable 为 navigable 的顶级 traversable。

  5. 令 collectors 为空列表。

  6. 对于 活动 BiDi 会话中的每个 session:

    1. 对于 session 的network collectors 中的每个 collector:

      1. 如果 collector 的data types 包含 data type,且以 collector 和 top-level navigable 调用匹配 navigable 的 collector所得的结果为 true:

        1. 将 collector 追加到 collectors。

  7. 如果 collectors 为空:

    1. 从 collected network data中移除 collected data。

    2. 用 "network data collected" 和 (request 的request id, data type) 恢复。

    3. 返回。

  8. 令 bytes 为 null。

  9. 令给定 nullOrBytes 的 processBody 为此步骤:

    1. 如果 nullOrBytes 不是 null:

      1. 将 bytes 设置为用 nullOrBytes 调用序列化协议 bytes所得的结果。

      2. 如果 size 为 null,则将 size 设置为 bytes 的长度。

  10. 令 processBodyError 为此步骤:不执行任何操作。

  11. 给定 processBody 和 processBodyError,完全读取 collected data 的cloned body。

  12. 如果 bytes 不是 null:

    1. 对于 collectors 中的每个 collector:

      1. 如果 size 小于或等于 collector 的max encoded item size, 则将 collector 的collector 追加到 collected data 的 collectors。

    2. 如果 collected data 的collectors 不是空:

      1. 给定 size 分配大小以记录数据。

      2. 将 collected data 的bytes 设置为 bytes。

      3. 将 collected data 的size 设置为 size。

    3. 否则,从 collected network data中移除 collected data。

  13. 用 "network data collected" 和 (request 的request id, data type) 恢复。

要在给定 size 的情况下分配 大小以记录数据:
  1. 令 available size 为 max total collected size。

  2. 令 already collected data 为空列表。

  3. 对于 collected network data 中的每个 collected data:

    1. 如果 collected data 的bytes 不是 null:

      1. 将 available size 减少 collected data 的size。

      2. 将 collected data 追加到 already collected data

  4. 如果 size 大于 available size:

    1. 对于 already collected data 中的每个 collected data:

      1. 将 available size 增加 collected data 的size。

      2. 将 collected data 的bytes 字段 设置为 null。

      3. 将 collected data 的size 字段设置为 null。

      4. 如果 available size 大于或等于 size,则返回。

要在给定 collected data 和 collector id 的情况下从数据中移除 collector:
  1. 如果 collected data 的collectors 包含 collector id:

    1. 从 collected data 的collectors中移除 collector id。

    2. 如果 collected data 的collectors 为空:

      1. 从 collected network data中移除 collected data。

7.5.3. 网络拦截

一个网络拦截 是一种允许远端拦截 并修改网络请求和响应的机制。

一个BiDi 会话具有一个拦截映射,它是一个 映射, 映射于 拦截 ID 与一个具有字段 url patterns、 phases 和 contexts 的结构之间,这些字段定义活动网络拦截的属性。 它最初为空。

一个BiDi 会话具有一个被阻止请求 映射,用于跟踪 当前正在被阻止的请求。它是一个映射,映射于请求 ID 与一个具有字段 request、phase 和 response 的结构之间。 它最初为空。

要在给定 session、event、request 和 navigable id 的情况下,获取 网络拦截:

  1. 令 session intercepts 为 session 的拦截映射。

  2. 令 intercepts 为空列表。

  3. 运行第一个匹配条件下的步骤:

    event 为 "network.beforeRequestSent"
    将 phase 设为 "beforeRequestSent"。
    event 为 "network.responseStarted"
    将 phase 设为 "responseStarted"。
    event 为 "network.authRequired"
    将 phase 设为 "authRequired"。
    event 为 "network.responseCompleted"
    返回 intercepts。
  4. 令 url 为使用 request 的 URL 运行URL 序列化器的结果。

  5. 对于 session intercepts 中的每个 intercept id → intercept:

    1. 如果 intercept 的 contexts 不为 null:

      1. 如果 intercept 的 contexts 不包含 navigable id:

        1. 继续。

    2. 如果 intercept 的 phases 包含 phase:

      1. 令 url patterns 为 intercept 的 url patterns。

      2. 如果 url patterns 为空:

        1. 将 intercept id 追加到 intercepts。

        2. 继续。

      3. 对于 url patterns 中的每个 url pattern:

        1. 如果使用 url pattern 和 url 匹配 URL 模式:

          1. 将 intercept id 追加到 intercepts。

          2. 中断。

  6. 返回 intercepts。

给定 session、command 和 command parameters,要更新 响应:
  1. 令 blocked requests 为 session 的被阻止请求映射。

  2. 令 request id 为 command parameters["request"]。

  3. 如果 blocked requests 不包含 request id,则返回带有 错误,其错误 代码为无此请求。

  4. 令 (request, phase, response) 为 blocked requests[request id]。

  5. 如果 phase 为 "beforeRequestSent" 且 command 为 "continueResponse",则返回带有错误,其错误代码为 "invalid argument"。

    TODO:考虑使用其他错误

  6. 如果 response 为 null:

    1. 断言:phase 为 "beforeRequestSent"。

    2. 将 response 设置为一个新的响应。

  7. 如果 command parameters 包含 "statusCode":

    1. 将 responses 的状态设置为 command parameters["statusCode"]。

  8. 如果 command parameters 包含 "reasonPhrase":

    1. 将 responses 的状态消息设置为使用 command parameters["reasonPhrase"] 进行UTF-8 编码的结果。

  9. 如果 command parameters 包含 "headers":

    1. 令 headers 为尝试使用 command parameters["headers"] 创建标头列表的结果。

    2. 将 response 的标头列表设置为 headers。

  10. 如果 command parameters 包含 "cookies":

    1. 如果 command parameters 包含 "headers",则令 headers 为 response 的标头列表。

      否则:

      1. 令 headers 为一个空的标头列表。

      2. 对于 response 的标头列表中的每个 header:

        1. 令 name 为 header 的名称。

        2. 如果对 name 执行字节小写转换的结果不是 `set-cookie`:

          1. 将 header 追加到 headers

    2. 对于 command parameters["cookies"] 中的 cookie:

      1. 令 header value 为使用 cookie 序列化 set-cookie 标头的结果。

      2. 将 (`Set-Cookie`, header value) 追加到 headers。

      3. 将 response 的标头列表设置为 headers。

  11. 如果 command parameters 包含 "credentials":

    这里没有 取消身份验证的方法。

    1. 令 credentials 为 command parameters["credentials"]。

    2. 断言:credentials["type"] 为 "password"。

    3. 将 response 的身份验证凭据设置为 (credentials["username"], credentials["password"])

  12. 返回 response

7.5.4. 类型

7.5.4.1. network.AuthChallenge 类型
network.AuthChallenge = {
  scheme: text,
  realm: text,
}

要在给定 response 的情况下提取 challenges:

是否应包含 realm 之外的参数?

  1. 如果 response 的status 为 401,则令 header name 为 `WWW-Authenticate`。否则,如果 response 的status 为 407,则令 header name 为 `Proxy-Authenticate`。否则返回 null。

  2. 令 challenges 为一个新的列表。

  3. 对于 response 的header list中的每个 (name, value):

    与 Fetch 中一样, 尚不清楚这是否是处理多个 headers、解析问题等的正确方式。

    1. 如果 name 与 header name 按字节大小写不敏感匹配:

      1. 令 header challenges 为将 value 解析为 challenges 列表的结果,每个 challenge 由一个 scheme 和一个参数列表组成, 每个参数均为元组 (name, value),按照 [RFC9110] 的规则解析。

      2. 对于 header challenges 中的每个 header challenge:

        1. 令 scheme 为 header challenge 的 scheme。

        2. 令 realm 为空字符串。

        3. 对于 header challenge 的 parameters 中的每个 (param name, param value):

          1. 如果 param name 等于 `realm`,则令 realm 为 对 param value 进行UTF-8 decode所得的结果。

        4. 令 challenge 为一个新的映射,匹配 network.AuthChallenge 产生式,其中 scheme 字段设置为 scheme,且 realm 字段设置为 realm。

      3. 将 challenge 追加到 challenges。

  4. 返回 challenges。

7.5.4.2. network.AuthCredentials 类型
network.AuthCredentials = {
  type: "password",
  username: text,
  password: text,
}

network.AuthCredentials 类型表示对授权凭据请求的响应。

7.5.4.3. network.BaseParameters 类型
network.BaseParameters = (
    context: browsingContext.BrowsingContext / null,
    isBlocked: bool,
    navigation: browsingContext.Navigation / null,
    redirectCount: js-uint,
    request: network.RequestData,
    timestamp: js-uint,
    ? userContext: browser.UserContext / null,
    ? intercepts: [+network.Intercept]
)

network.BaseParameters 类型是一个抽象类型,表示 所有网络事件共有的数据。

考虑除 context 之外, 还包含发起请求的 document 节点的 `sharedId`。

要在给定 session、event 和 request 的情况下处理 network event:
  1. 令 request data 为以 request 调用获取 request data所得的结果。

  2. 令 navigation 为 request 的navigation id。

  3. 令 navigable id 为 null。

  4. 令 top-level navigable id 为 null。

  5. 令 user context id 为 null。

  6. 如果 request 的client 是一个环境设置对象:

    1. 令 environment settings 为 request 的client。

    2. 如果存在一个navigable,其活动 window是 environment settings 的全局对象,则将 navigable id 设置为该 navigable 的navigable id,将 top-level navigable id 设置为 该 navigable 的顶级 traversable 的navigable id,并 将 user context id 设置为该 navigable 的 关联用户上下文的用户上下文 id。

  7. 令 intercepts 为以 session、event、request 和 top-level navigable id 调用获取网络 拦截所得的结果。

  8. 令 redirect count 为 request 的redirect count。

  9. 令 timestamp 为一个时间值,表示 UTC 中的当前日期 和时间。

  10. 如果 intercepts 不是空,则令 is blocked 为 true,否则 令 is blocked 为 false。

  11. 令 params 为映射, 匹配 network.BaseParameters 产生式,其中 request 字段设置为 request data, navigation 字段设置为 navigation,context 字段设置为 navigable id,userContext 字段设置为 user context id,timestamp 字段设置为 timestamp, redirectCount 字段设置为 redirect count, isBlocked 字段设置为 is blocked,且如果 is blocked 为 true, 则 intercepts 字段设置为 intercepts,否则省略。

  12. 返回 params

7.5.4.4. network.BytesValue 类型
network.BytesValue = network.StringValue / network.Base64Value;

network.StringValue = {
  type: "string",
  value: text,
}

network.Base64Value = {
  type: "base64",
  value: text,
}

network.BytesValue 类型表示通过网络发送的二进制数据。有效的 UTF-8 用 network.StringValue 类型表示,任何其他数据均以 Base64 编码形式表示为 network.Base64Value。

要在给定 protocol bytes 的情况下反序列化 协议 bytes:

注:这接收编码为 network.BytesValue 的 bytes,并返回 字节序列。

  1. 如果 protocol bytes 匹配 network.StringValue 产生式, 则令 bytes 为对 protocol bytes["value"] 进行 UTF-8 encode所得的结果。

  2. 否则,如果 protocol bytes 匹配 network.Base64Value 产生式。令 bytes 为对 protocol bytes["value"] 进行forgiving-base64 decode所得的结果。

  3. 返回 bytes。

要在给定 bytes 的情况下,序列化 协议字节:

注:这会接受一个字节序列 并返回一个 network.BytesValue。

  1. 令 text 为对 bytes 执行不带 BOM 的 UTF-8 解码,否则失败所得的结果。

  2. 如果 text 为失败,则返回一个与 network.Base64Value 产生式匹配的映射, 其中 value 设置为对 bytes 执行宽容 base64 编码所得的结果。

  3. 返回一个与 network.StringValue 产生式匹配的映射, 其中 value 设置为 text。

7.5.4.5. network.Collector 类型

远程端定义 和 本地端定义

network.Collector = text

network.Collector 类型表示一个collector 的 ID。

7.5.4.6. network.CollectorType 类型

远程端定义 和 本地端定义

network.CollectorType = "blob"

注:将来我们可能还会支持 "stream" collector 类型,供希望通过流读取给定 collector 所收集数据的客户端使用。

network.CollectorType 类型表示可添加的数据 collector 的不同类型。

远程端定义 和 本地端定义

network.SameSite = "strict" / "lax" / "none" / "default"


network.Cookie = {
    name: text,
    value: network.BytesValue,
    domain: text,
    path: text,
    size: js-uint,
    httpOnly: bool,
    secure: bool,
    sameSite: network.SameSite,
    ? expiry: js-uint,
    Extensible,
}

network.Cookie 类型表示一个 cookie。

要在给定 stored cookie 的情况下序列化 cookie:
  1. 令 name 为使用 stored cookie 的 name 字段进行UTF-8 解码的结果。

  2. 令 value 为使用 stored cookie 的 value 对序列化协议字节的结果。

  3. 令 domain 为 stored cookie 的 domain 字段。

  4. 令 path 为 stored cookie 的 path 字段。

  5. 如果已设置,则令 expiry 为 stored cookie 的 expiry-time 字段表示为 unix 时间戳;否则为 null。

  6. 令 size 为将 stored cookie 序列化为它在 Cookie 标头中表示时所得结果的字节长度。

  7. 如果 stored cookie 的 http-only-flag 为 true,则令 http only 为 true,否则为 false。

  8. 如果 stored cookie 的 secure-only-flag 为 true,则令 secure 为 true,否则为 false。

  9. 如果 stored cookie 的 same-site-flag 为 "None",则令 same site 为 "none";如果为 "Lax",则为 "lax"; 如果为 "Strict",则为 "strict";如果为 "Default",则为 "default"

  10. 返回一个匹配 network.Cookie 产生式的映射, 其中 name 字段设为 name,value 字段 设为 value,domain 字段设为 domain,path 字段设为 path,如果 expiry 字段不为 null 则设为 expiry,否则省略;size 字段 设为 size,httpOnly 字段设为 http only,secure 字段设为 secure,且 sameSite 字段设为 same site。

7.5.4.8. network.CookieHeader 类型

远程端定义

network.CookieHeader = {
    name: text,
    value: network.BytesValue,
}

network.CookieHeader 类型表示 Cookie 请求标头中的 cookie 数据子集。

要在给定 protocol cookie 的情况下序列化 cookie 标头:
  1. 令 name 为对 protocol cookie["name"] 进行UTF-8 编码的结果。

  2. 令 value 为使用 protocol cookie["value"] 反序列化协议字节的结果。

  3. 令 header value 为通过连接 name、 `=` 和 value 形成的字节 序列

  4. 返回 header value。

7.5.4.9. network.DataType 类型

远程端定义 和 本地端定义

network.DataType = "request" / "response"

network.DataType 类型表示可以收集的网络数据的不同类型。

7.5.4.10. network.FetchTimingInfo 类型

远程端定义 和 本地端定义

network.FetchTimingInfo = {
    timeOrigin: float,
    requestTime: float,
    redirectStart: float,
    redirectEnd: float,
    fetchStart: float,
    dnsStart: float,
    dnsEnd: float,
    connectStart: float,
    connectEnd: float,
    tlsStart: float,

    requestStart: float,
    responseStart: float,

    responseEnd: float,
}

network.FetchTimingInfo 类型表示请求各部分相对于该请求的 客户端的时间原点的时间。

要在给定 request 的情况下,获取 fetch 计时:
  1. 令 global 为 request 的客户端。

  2. 如果 global 为 null,则返回一个匹配 network.FetchTimingInfo 产生式的映射,其中所有字段都设为 0。

  3. 令 time origin 为使用 global 获取时间原点时间戳的结果。

  4. 令 timings 为 request 的 fetch 计时信息。

  5. 如果 timings 的最终连接计时信息不为 null,则令 connection timing 为它;否则为一个新的连接计时信息。

  6. 令 request time 为给定 timings 的开始时间和 global 转换 fetch 时间戳的结果。

  7. 令 redirect start 为给定 timings 的 重定向开始时间和 global 转换 fetch 时间戳的结果。

  8. 令 redirect end 为给定 timings 的重定向结束时间和 global 转换 fetch 时间戳的结果。

  9. 令 fetch start 为给定 timings 的 重定向后开始时间和 global 转换 fetch 时间戳的结果。

  10. 令 DNS start 为给定 connection timing 的 域名查找开始时间 和 global 转换 fetch 时间戳的结果。

  11. 令 DNS end 为给定 connection timing 的 域名查找结束时间和 global 转换 fetch 时间戳的结果。

  12. 令 TLS start 为给定 connection timing 的 安全连接开始 时间和 global 转换 fetch 时间戳的结果。

  13. 令 connect start 为给定 connection timing 的连接开始时间和 global 转换 fetch 时间戳的结果。

  14. 令 connect end 为给定 connection timing 的 连接结束时间和 global 转换 fetch 时间戳的结果。

  15. 令 request start 为给定 timings 的最终网络请求开始 时间和 global 转换 fetch 时间戳的结果。

  16. 令 response start 为给定 timings 的最终网络响应 开始时间和 global 转换 fetch 时间戳的结果。

  17. 令 response end 为给定 timings 的 结束时间和 global 转换 fetch 时间戳的结果。

  18. 返回一个匹配 network.FetchTimingInfo 产生式的映射, 其中 timeOrigin 字段设为 time origin, requestTime 字段设为 request time, redirectStart 字段设为 redirect start, redirectEnd 字段设为 redirect end, fetchStart 字段设为 fetch start, dnsStart 字段设为 DNS start,dnsEnd 字段设为 DNS end,connectStart 字段设为 connect start,connectEnd 字段设为 connect end, tlsStart 字段设为 TLS start, requestStart 字段设为 request start, responseStart 字段设为 response start,且 responseEnd 字段设为 response end。

TODO:添加 service worker 字段

7.5.4.11. network.Header 类型

远程端定义 和 本地端定义

network.Header = {
  name: text,
  value: network.BytesValue,
}

network.Header 类型表示单个请求标头。

要在给定 name bytes 和 value bytes 的情况下序列化标头:
  1. 令 name 为使用 name bytes 进行UTF-8 解码的结果。

    断言:由于标头名称被约束为仅 ASCII,因此这不会失败。

  2. 令 value 为使用 value bytes 序列化协议字节的结果。

  3. 返回一个匹配 network.Header 产生式的映射,其中 name 字段设为 name,且 value 字段 设为 value。

要在给定 protocol header 的情况下反序列化 标头:
  1. 令 name 为对 protocol header["name"] 进行UTF-8 编码的结果。

  2. 令 value 为使用 protocol header["value"] 反序列化协议字节的结果。

  3. 返回一个标头 (name, value)。

给定 protocol headers,要创建标头 列表:
  1. 令 headers 为空标头列表。

  2. 对于 protocol headers 中的 header:

    1. 令 deserialized header 为使用 header 反序列化标头的结果。

    2. 如果 deserialized header 的名称与字段名称令牌 产生式不匹配,则返回带有错误,其 错误代码为 "invalid argument"。

    3. 如果 deserialized header 的值与标头 值 产生式不匹配,则返回带有错误,其 错误代码为 "invalid argument"。

    4. 将 deserialized header 追加到 headers。

  3. 返回带有数据 headers 的成功

7.5.4.12. network.Initiator 类型

远程端定义 和 本地端定义

network.Initiator = {
    ? columnNumber: js-uint,
    ? lineNumber: js-uint,
    ? request: network.Request,
    ? stackTrace: script.StackTrace,
    ? type: "parser" / "script" / "preflight" / "other"
}

network.Initiator 类型表示网络请求的来源。

注:type 字段被包含在 定义中是为了向后 兼容,但不再由获取 initiator步骤设置,并且将在本规范的未来修订中移除。预期其用途会被 network.RequestData 上的 initiatorType 和 destination 替代。

注:request 字段被包含在 定义中是为了向后 兼容,但不再由获取 initiator步骤设置,并且将在本规范的未来修订中移除。 network.Initiator 被包含在 network.BeforeRequestSentParameters 中,而后者也包含相同的 请求 ID,使得此信息成为冗余。参见 § 7.5.4.3 network.BaseParameters 类型。

要在给定 request 的情况下获取 initiator:
  1. 如果 request 的initiator type 为 "fetch" 或 "xmlhttprequest":

    1. 令 stack trace 为当前堆栈跟踪。

    2. 如果 stack trace 的大小为 1 或更大,则令 line number 为 stack trace[0] 中 lineNumber 字段的值,并令 column number 为 stack trace[0] 中 columnNumber 字段的值。否则 令 line number 和 column number 为 0。

    否则,令 stack trace、column number 和 line number 全部为 null。

    TODO:Chrome 会将当前解析器位置作为解析器插入资源的 column number / line number 包含进去。

  2. 返回一个匹配 network.Initiator 产生式的映射, 如果 columnNumber 字段不为 null,则设为 column number, 否则省略;如果 lineNumber 字段不为 null,则设为 line number, 否则省略;且如果 stackTrace 字段不为 null,则设为 stack trace,否则省略。

7.5.4.13. network.Intercept 类型

远程端定义 和 本地端定义

network.Intercept = text

network.Intercept 类型表示一个网络拦截的 ID。

7.5.4.14. network.Request 类型

远程端定义 和 本地端定义

network.Request = text;

每个网络请求都有一个关联的请求 ID,它是唯一标识该请求的字符串。由重定向产生的请求的标识符与发起它的请求相匹配。

7.5.4.15. network.RequestData 类型

远程端定义 和 本地端定义

network.RequestData = {
    request: network.Request,
    url: text,
    method: text,
    headers: [*network.Header],
    cookies: [*network.Cookie],
    headersSize: js-uint,
    bodySize: js-uint / null,
    destination: text,
    initiatorType: text / null,
    timings: network.FetchTimingInfo,
}

network.RequestData 类型表示正在进行的网络请求。

要在给定 request 的情况下获取请求 数据:

  1. 令 request id 为 request 的请求 ID。

  2. 令 url 为使用 request 的 URL 运行URL 序列化器的结果。

  3. 令 method 为 request 的方法。

  4. 令 body size 为 null。

  5. 令 body 为 request 的主体。

  6. 如果 body 是字节 序列,则将 body size 设为该序列的长度。 否则,如果 body 是主体,则将 body size 设为该主体的长度。

  7. 令 headers size 为 request 的标头列表按照 [HTTP11] 要求序列化时的字节大小。

    注:对于允许标头压缩的协议, 这是通过网络发送的标头的压缩 大小。

  8. 令 headers 为空列表。

  9. 令 cookies 为空列表。

  10. 对于 request 的标头列表中的每个 (name, value):

    1. 将使用 name 和 value 序列化标头的结果追加到 headers。

    2. 如果 name 与 "Cookie" 是字节大小写不敏感匹配,则:

      1. 对于用户代理的cookie 存储中包含在 request 中的每个 cookie:

        注:[COOKIES] 定义了一些关于存储中的哪些 cookie 可被包含在请求中的基线要求,但用户代理可以自由地施加额外约束。

        1. 将给定 cookie 序列化 cookie的结果追加到 cookies。

  11. 令 destination 为 request 的目标。

  12. 令 initiator type 为 request 的initiator type。

  13. 令 timings 为使用 request 获取 fetch 计时的结果。

  14. 返回一个匹配 network.RequestData 产生式的映射,其中 request 字段设为 request id,url 字段 设为 url,method 字段设为 method, headers 字段设为 headers,cookies 字段设为 cookies,headersSize 字段设为 headers size, bodySize 字段设为 body size,destination 字段设为 destination,initiatorType 字段设为 initiator type,且 timings 字段设为 timings。

7.5.4.16. network.ResponseContent 类型

远程端定义 和 本地端定义

network.ResponseContent = {
    size: js-uint
}

network.ResponseContent 类型表示对 网络请求的已解码响应。

要在给定 response 的情况下获取 响应内容信息。
  1. 返回一个匹配 network.ResponseContent 产生式的新映射,其中 size 字段设为 response 的响应主体信息的已解码大小

7.5.4.17. network.ResponseData 类型

远程端定义 和 本地端定义

network.ResponseData = {
    url: text,
    protocol: text,
    status: js-uint,
    statusText: text,
    fromCache: bool,
    headers: [*network.Header],
    mimeType: text,
    bytesReceived: js-uint,
    headersSize: js-uint / null,
    bodySize: js-uint / null,
    content: network.ResponseContent,
    ?authChallenges: [*network.AuthChallenge],
}

network.ResponseData 类型表示对网络 请求的响应。

要在给定 response 的情况下获取 协议:

  1. 令 protocol 为空字符串。

  2. 如果 response 的最终连接计时 信息不为 null,则将 protocol 设为 response 的最终连接计时 信息的ALPN 协商协议。

  3. 如果 protocol 为空字符串,或等于 "unknown":

    1. 将 protocol 设为 response 的url的方案

    2. 如果 protocol 等于 "http" 或 "https",且 response 具有关联的 HTTP Response。

      注:[FETCH] 没有明确说明 HTTP 网络响应与 response 对象之间的关系。

      1. 令 http version 为 HTTP Response 的 Status line 的 HTTP-version [HTTP11]。

      2. 如果 http version 以 "HTTP/" 开头:

        1. 令 version 为 http version 从 5 到 http version 的长度的码元子串。

        2. 如果 version 为 "0.9",则将 protocol 设为 "http/0.9";否则如果 version 为 "1.0", 则将 protocol 设为 "http/1.0";否则如果 version 为 "1.1",则将 protocol 设为 "http/1.1"。

  4. 返回 protocol。

要在给定 response 的情况下,获取响应 数据:
  1. 令 url 为使用 response 的 URL 运行URL 序列化器的结果。

  2. 将 protocol 设为给定 response 获取协议的结果。

  3. 令 status 为 response 的状态。

  4. 令 status text 为 response 的状态消息。

  5. 如果 response 的缓存状态为 "local",则令 from cache 为 true,否则令其为 false。

  6. 令 headers 为空列表。

  7. 令 mime type 为 response 的计算出的 MIME 类型的本质。

    注:这是浏览器实际使用的任何 MIME 类型, 即使它没有遵循 [MIMESNIFF] 规范中的精确算法。

  8. 对于 response 的标头列表中的每个 (name, value):

    1. 将使用 name 和 value 序列化标头的结果追加到 headers。

  9. 令 bytes received 为作为与 response 关联的 HTTP 响应的一部分传输的总字节数。

  10. 令 headers size 为作为 HTTP 响应的标头 字段部分传输的字节数。

  11. 令 body size 为 response 的响应主体信息的已编码大小。

  12. 令 content 为使用 response 获取 响应内容信息的结果。

  13. 令 auth challenges 为使用 response 提取质询的结果。

  14. 返回一个匹配 network.ResponseData 产生式的映射, 其中 url 字段设为 url,protocol 字段 设为 protocol,status 字段设为 status, statusText 字段设为 status text, fromCache 字段设为 from cache,headers 字段设为 headers,mimeType 字段设为 mime type, bytesReceived 字段设为 bytes received, headersSize 字段设为 headers size, bodySize 字段设为 body size,content 字段设为 content,且如果 authChallenges 字段不为 null,则设为 auth challenges,否则省略。

7.5.4.18. network.SetCookieHeader 类型

Remote end definition

network.SetCookieHeader = {
    name: text,
    value: network.BytesValue,
    ? domain: text,
    ? httpOnly: bool,
    ? expiry: text,
    ? maxAge: js-int,
    ? path: text,
    ? sameSite: network.SameSite,
    ? secure: bool,
}

network.SetCookieHeader 表示 Set-Cookie 响应 header 中的数据。

要在给定作为整数的 input 的情况下序列化 整数:

注:这会生成 input 作为十进制数字字符串的最短表示。

  1. 令 serialized 为空字符串。

  2. 令 value 为 input。

  3. 当 value 大于 0 时:

    1. 令 x 为 value 除以 10。

    2. 令 most significant digits 为 x 的整数部分。

    3. 令 y 为 most significant digits 乘以 10。

    4. 令 least significant digit 为 value - y。

    5. 断言:least significant digit 是 0 到 9(含)范围内的整数。

    6. 令 codepoint 为一个码 点,其值为 U+0030 DIGIT ZERO 的值 + least significant digit。

    7. 将 codepoint 前置到 serialized。

    8. 将 value 设置为 most significant digits。

  4. 返回 serialized。

给定 protocol cookie,要序列化 set-cookie 标头:
  1. 令 name 为对 protocol cookie["name"] 进行UTF-8 编码的结果。

  2. 令 value 为使用 protocol cookie["value"] 反序列化协议字节的结果。

  3. 令 header value 为通过连接 name、 `=` 和 value 形成的字节 序列。

  4. 如果 protocol cookie 包含 "expiry":

    1. 令 attribute 为 `;Expires=`

    2. 将对 protocol cookie["expiry"] 进行UTF-8 编码的结果追加到 attribute。

    3. 将 attribute 追加到 header value。

  5. 如果 protocol cookie 包含 "maxAge":

    1. 令 attribute 为 `;Max-Age=`

    2. 令 max age string 为对 protocol cookie["maxAge"] 序列化整数的结果。

    3. 将对 max age string 进行UTF-8 编码的结果追加到 attribute。

    4. 将 attribute 追加到 header value。

  6. 如果 protocol cookie 包含 "domain":

    1. 令 attribute 为 `;Domain=`

    2. 将对 protocol cookie["domain"] 进行UTF-8 编码的结果追加到 attribute。

    3. 将 attribute 追加到 header value。

  7. 如果 protocol cookie 包含 "path":

    1. 令 attribute 为 `;Path=`

    2. 将对 protocol cookie["path"] 进行UTF-8 编码的结果追加到 attribute。

    3. 将 attribute 追加到 header value。

  8. 如果 protocol cookie 包含 "secure" 且 protocol cookie["secure"] 为 true:

    1. 将 `;Secure` 追加到 header value。

  9. 如果 protocol cookie 包含 "httpOnly" 且 protocol cookie["httpOnly"] 为 true:

    1. 将 `;HttpOnly` 追加到 header value。

  10. 如果 protocol cookie 包含 "sameSite":

    1. 令 attribute 为 `;SameSite=`

    2. 将对 protocol cookie["sameSite"] 进行UTF-8 编码的结果追加到 attribute。

    3. 将 attribute 追加到 header value。

  11. 返回 header value。

7.5.4.19. network.UrlPattern 类型

Remote end definition

network.UrlPattern = (
  network.UrlPatternPattern /
  network.UrlPatternString
)

network.UrlPatternPattern = {
    type: "pattern",
    ?protocol: text,
    ?hostname: text,
    ?port: text,
    ?pathname: text,
    ?search: text,
}


network.UrlPatternString = {
    type: "string",
    pattern: text,
}

network.UrlPattern 表示用于为网络 拦截匹配请求 URL 的模式。

当 URL 与 network.UrlPattern 匹配时,会解析该 URL, 并在模式中存在对应字段时,将每个组成部分与该字段按相等性进行比较。 模式中缺失的字段始终匹配。

注:此语法在设计时考虑了未来的可扩展性。 特别是,该语法禁止在 [URLPattern] 规范中被特殊处理的字符。这些字符可以通过在其前面加上 U+005C (\) 字符进行转义。

给定 pattern,要取消 URL 模式转义
  1. 令 forbidden characters 为由代码点 «U+0028 ((), U+0029 ()), U+002A (*), U+007B ({), U+007D (})» 组成的集合

  2. 令 result 为空字符串。

  3. 令 is escaped character 为 false。

  4. 对于 pattern 中的每个 codepoint:

    1. 如果 is escaped character 为 false:

      1. 如果 forbidden characters 包含 codepoint,则返回带有错误 ,其错误代码为无效参数。

      2. 如果 codepoint 为 U+005C (\):

        1. 将 is escaped character 设置为 true。

        2. 继续。

    2. 将 codepoint 追加到 result。

    3. 将 is escaped character 设置为 false。

  5. 返回带有数据 result 的成功。

给定 pattern,要解析 URL 模式:
  1. 令 has protocol 为 true。

  2. 令 has hostname 为 true。

  3. 令 has port 为 true。

  4. 令 has pathname 为 true。

  5. 令 has search 为 true。

  6. 如果 pattern 与 network.UrlPatternPattern 产生式匹配:

    1. 令 pattern url 为空字符串。

    2. 如果 pattern 包含 "protocol":

      1. 如果 pattern["protocol"] 为空字符串,则返回带有错误 ,其错误代码为无效参数。

      2. 令 protocol 为尝试使用 pattern["protocol"] 取消 URL 模式转义的结果。

      3. 对于 protocol 中的每个 codepoint:

        1. 如果 codepoint 不是ASCII 字母数字字符,并且 «U+002B (+), U+002D (-), U+002E (.)» 不包含 codepoint:

          1. 返回带有错误,其错误代码为无效 参数。

      4. 将 protocol 追加到 pattern url。

    3. 否则:

      1. 将 has protocol 设置为 false。

      2. 将 "http" 追加到 pattern url。

    4. 令 scheme 为对 pattern url 进行ASCII 小写转换的结果。

    5. 将 ":" 追加到 pattern url。

    6. 如果 scheme 是 特殊方案,则将 "//" 追加到 pattern url。

    7. 如果 pattern 包含 "hostname":

      1. 如果 pattern["hostname"] 为空字符串,则返回带有错误 ,其错误代码为无效参数。

      2. 如果 scheme 为 "file",则返回带有错误,其错误代码为 无效参数。

      3. 令 hostname 为尝试使用 pattern["hostname"] 取消 URL 模式转义的结果。

      4. 令 inside brackets 为 false。

      5. 对于 hostname 中的每个 codepoint:

        1. 如果 «U+002F (/), U+003F (?), U+0023 (#)» 包含 codepoint:

          1. 返回带有错误,其错误代码为无效参数。

        2. 如果 inside brackets 为 false 且 codepoint 为 U+003A (:):

          1. 返回带有错误,其错误代码为无效参数。

        3. 如果 codepoint 为 U+005B ([),则将 inside brackets 设置为 true。

        4. 如果 codepoint 为 U+005D (]),则将 inside brackets 设置为 false。

      6. 将 hostname 追加到 pattern url。

    8. 否则:

      1. 如果 scheme 不是 "file",则将 "placeholder" 追加到 pattern url。

      2. 将 has hostname 设置为 false。

    9. 如果 pattern 包含 "port":

      1. 如果 pattern["port"] 为空字符串,则返回带有错误 ,其错误代码为无效参数。

      2. 令 port 为尝试使用 pattern["port"] 取消 URL 模式转义的结果。

      3. 将 ":" 追加到 pattern url。

      4. 对于 port 中的每个 codepoint:

        1. 如果 codepoint 不是ASCII 数字:

          1. 返回带有错误,其错误代码为无效参数。

      5. 将 port 追加到 pattern url。

    10. 否则:

      1. 将 has port 设置为 false。

    11. 如果 pattern 包含 "pathname":

      1. 令 pathname 为尝试使用 pattern["pathname"] 取消 URL 模式转义的结果。

      2. 如果 pathname 不以 U+002F (/) 开头,则 将 "/" 追加到 pattern url。

      3. 对于 pathname 中的每个 codepoint:

        1. 如果 «U+003F (?), U+0023 (#)» 包含 codepoint:

          1. 返回带有错误,其错误代码为无效参数。

      4. 将 pathname 追加到 pattern url。

    12. 否则:

      1. 将 has pathname 设置为 false。

    13. 如果 pattern 包含 "search":

      1. 令 search 为尝试使用 pattern["search"] 取消 URL 模式转义的结果。

      2. 如果 search 不以 U+003F (?) 开头,则 将 "?" 追加到 pattern url。

      3. 对于 search 中的每个 codepoint:

        1. 如果 codepoint 为 U+0023 (#):

          1. 返回带有错误,其错误代码为无效参数。

      4. 将 search 追加到 pattern url。

    14. 否则:

      1. 将 has search 设置为 false。

  7. 否则,如果 pattern 与 network.UrlPatternString 产生式匹配:

    1. 令 pattern url 为尝试使用 pattern["pattern"] 取消 URL 模式转义的结果。

  8. 令 url 为解析 pattern url 的结果。

  9. 如果 url 为失败,则返回带有错误,其错误代码为无效参数。

  10. 令 parsed 为具有以下字段的结构体:

    protocol
    如果 has protocol 为 true,则为 url 的方案,否则为 null。
    hostname
    如果 has hostname 为 true,则为 url 的主机,否则为 null。
    port
    1. 如果 has port 为 false:

      1. null。

    2. 否则:

      1. 如果 url 的方案是特殊方案,且 url 的方案的 默认端口不为 null,并且 url 的端口为 null 或 等于方案的默认端口:

        1. 空字符串。

      2. 否则,如果 url 的端口不为 null:

        1. 使用 url 的端口序列化整数。

      3. 否则:

        1. null。

    pathname
    1. 如果 has pathname 为 false:

      1. null。

    2. 否则:

      1. 如果 url 的路径不是空字符串且 不为空,则为使用 url 运行URL 路径序列化器的结果, 否则为 null。

    search
    1. 如果 has search 为 false:

      1. null。

    2. 否则:

      1. 如果 url 的查询为 null,则为空字符串,否则为 url 的查询。

  11. 返回带有数据 parsed 的成功。

要在给定 url pattern 和 url string 的情况下匹配 URL 模式:
  1. 令 url 为解析 url string的结果。

  2. 如果 url pattern 的 protocol 不为 null 且不等于 url 的 scheme,则返回 false。

  3. 如果 url pattern 的 hostname 不为 null 且不等于 url 的 host,则返回 false。

  4. 如果 url pattern 的 port 不为 null:

    1. 令 port 为 null。

    2. 如果 url 的scheme为 特殊,且 url 的 scheme的默认 端口不为 null,且 url 的port 为 null 或等于scheme的默认 端口:

      1. 将 port 设为空字符串。

    3. 否则,如果 url 的port不为 null:

      1. 将 port 设为使用 url 的port 序列化整数的结果。

    4. 如果 url pattern 的 port 不等于 port,则返回 false。

  5. 如果 url pattern 的 pathname 不为 null,且不等于 使用 url 运行URL 路径序列化器的结果,则返回 false。

  6. 如果 url pattern 的 search 不为 null:

    1. 令 url query 为 url 的query。

    2. 如果 url query 为 null,则将 url query 设为空字符串。

    3. 如果 url pattern 的 search 不等于 url query,则返回 false。

  7. 返回 true。

7.5.5. 命令

7.5.5.1. network.addDataCollector 命令

network.addDataCollector 会添加一个 collector。

命令类型
network.AddDataCollector = (
  method: "network.addDataCollector",
  params: network.AddDataCollectorParameters
)

network.AddDataCollectorParameters = {
  dataTypes: [+network.DataType],
  maxEncodedDataSize: js-uint,
  ? collectorType: network.CollectorType .default "blob",
  ? contexts: [+browsingContext.BrowsingContext],
  ? userContexts: [+browser.UserContext],
}
返回类型
network.AddDataCollectorResult = {
  collector: network.Collector
}
给定 session 和 command parameters 时,远端步骤如下:
  1. 令 collector id 为一个UUID 的字符串表示形式。

  2. 令 input context ids 为一个空集合。

  3. 如果 command parameters 的 contexts 字段存在, 则将 input context ids 设置为使用 command parameters[contexts] 创建集合 的结果。

  4. 令 data types 为使用 command parameters["dataTypes"] 创建集合 的结果。

  5. 令 max encoded item size 为 command parameters ["maxEncodedDataSize"]。

    注:maxEncodedDataSize 参数表示 最大编码项大小,并限制 给定收集器所收集的每个请求的大小,而不是收集器收集内容的总大小。

    注:不同实现可能 支持不同的编码,这意味着 浏览器之间的编码大小可能不同。因此,对于相同的数据收集器 配置,某些网络数据可能仅在部分实现中符合最大编码项大小。

  6. 令 collector type 为 command parameters ["collectorType"]。

  7. 令 input user context ids 为一个空集合。

  8. 如果 command parameters 的 userContexts 字段存在, 则将 input user context ids 设置为使用 command parameters[userContexts] 创建集合 的结果。

  9. 如果 input user context ids 不为空且 input context ids 不 为空,则返回带有错误,其错误 代码为无效参数。

  10. 如果 max encoded item size 为 0,或 max encoded item size 大于 最大总收集大小,则返回带有错误,其错误 代码为无效参数。

  11. 如果 input context ids 不为空:

    1. 令 navigables 为尝试使用 input context ids 按 id 获取有效可导航对象 的结果。

    2. 对于 navigables 中的每个 navigable:

      1. 如果 navigable 不是顶层可遍历对象,则返回带有错误 ,其错误代码为无效参数。

  12. 否则,如果 input user context ids 不为空:

    1. 对于 input user context ids 中的每个 user context id:

      1. 令 user context 为使用 user context id 获取用户上下文的结果。

      2. 如果 user context 为 null,则返回带有错误,其错误代码为无此用户上下文。

  13. 令 collector 为一个收集器,其 最大编码项大小字段设置为 max encoded item size, 数据类型字段设置为 data types, 收集器字段设置为 collector id, 收集器类型字段设置为 collector type, 上下文字段设置为 input context ids, 用户上下文字段设置为 input user context ids。

  14. 将 session 的网络收集器[collector id] 设置为 collector。

  15. 返回一个与 network.AddDataCollectorResult 产生式匹配的新映射,其中 collector 字段设置为 collector id。

7.5.5.2. network.addIntercept 命令

network.addIntercept 命令会添加一个 网络拦截。

命令类型
network.AddIntercept = (
  method: "network.addIntercept",
  params: network.AddInterceptParameters
)

network.AddInterceptParameters = {
  phases: [+network.InterceptPhase],
  ? contexts: [+browsingContext.BrowsingContext],
  ? urlPatterns: [*network.UrlPattern],
}

network.InterceptPhase = "beforeRequestSent" / "responseStarted" /
                         "authRequired"
返回类型
network.AddInterceptResult = {
  intercept: network.Intercept
}
给定 session 和 command parameters 时,远端步骤如下:
  1. 令 intercept 为一个UUID 的字符串表示形式。

  2. 如果 command parameters 的 urlPatterns 字段存在,则令 url patterns 为该字段,否则令其为空列表。

  3. 令 navigables 为 null。

  4. 如果 command parameters 的 contexts 字段存在:

    1. 将 navigables 设置为空集合。

    2. 对于 command parameters["contexts"] 中的每个 navigable id

      1. 令 navigable 为尝试使用 navigable id 获取可导航对象 的结果。

      2. 如果 navigable 不是顶层可遍历对象,则返回带有错误 ,其错误代码为无效参数。

      3. 将 navigable 追加到 navigables。

    3. 如果 navigables 是一个空集合,则返回带有错误,其 错误代码为 无效参数。

  5. 令 intercept map 为 session 的拦截映射。

  6. 令 parsed patterns 为空列表。

  7. 对于 url patterns 中的每个 url pattern:

    1. 令 parsed 为尝试使用 url pattern 解析 URL 模式的结果。

    2. 将 parsed 追加到 parsed patterns。

  8. 将 intercept map[intercept] 设置为一个结构体,其中 url patterns 为 parsed patterns,phases 为 command parameters["phases"],browsingContexts 为 navigables。

  9. 返回一个与 network.AddInterceptResult 产生式匹配的新映射,其中 intercept 字段设置为 intercept。

7.5.5.3. network.continueRequest 命令

network.continueRequest 命令继续执行 被网络拦截阻塞的请求。

命令类型
network.ContinueRequest = (
  method: "network.continueRequest",
  params: network.ContinueRequestParameters
)

network.ContinueRequestParameters = {
  request: network.Request,
  ?body: network.BytesValue,
  ?cookies: [*network.CookieHeader],
  ?headers: [*network.Header],
  ?method: text,
  ?url: text,
}
返回类型
network.ContinueRequestResult = EmptyResult
给定 session 和 command parameters 时,远端步骤如下:
  1. 令 blocked requests 为 session 的被阻止请求映射。

  2. 令 request id 为 command parameters["request"]。

  3. 如果 blocked requests 不包含 request id,则返回 带有错误,其错误 代码为无此请求。

  4. 令 (request, phase, response) 为 blocked requests[request id]。

  5. 如果 phase 不是 "beforeRequestSent",则返回带有错误 ,其错误代码为无效参数。

    考虑使用 "request already sent" 错误。

  6. 如果 command parameters 包含 "url":

    1. 令 url record 为将URL 解析器应用于 command parameters["url"] 的结果,其中基础 URL 为 null。

    2. 如果 url record 为失败,则返回带有错误,其 错误代码为无效参数。

      TODO:这里是否也应该恢复?

    3. 令 request 的url 为 url record。

  7. 如果 command parameters 包含 "method":

    1. 令 method 为 command parameters["method"]。

    2. 如果 method 与方法令牌产生式不匹配,则返回带有错误 ,其错误代码为 "invalid argument"。

    3. 令 request 的方法为 method。

  8. 如果 command parameters 包含 "headers":

    1. 令 headers 为一个空标头列表。

    2. 对于 command parameters["headers"] 中的 header:

      1. 令 deserialized header 为使用 header 反序列化 标头的结果。

      2. 如果 deserialized header 的名称与字段名称令牌 产生式不匹配,则返回带有错误,其错误代码为 "invalid argument"。

      3. 如果 deserialized header 的值与标头值 产生式不匹配,则返回带有错误,其错误代码为 "invalid argument"。

      4. 将 deserialized header 追加到 headers。

    3. 将 request 的标头列表设置为 headers。

  9. 如果 command parameters 包含 "cookies":

    1. 令 cookie header 为一个空字节 序列。

    2. 对于 command parameters["cookies"] 中的每个 cookie:

      1. 如果 cookie header 不为空,则将 `;` 追加到 cookie header。

      2. 将使用 cookie 序列化 cookie 标头的结果追加到 cookie header。

    3. 令 found cookie header 为 false。

    4. 对于 request 的标头列表中的每个 header:

      1. 令 name 为 header 的名称。

      2. 如果对 name 执行字节小写转换的结果为 `cookie`:

        1. 将 header 的值设置为 cookie header。

        2. 将 found cookie header 设置为 true。

        3. 中断。

    5. 如果 found cookie header 为 false:

      1. 将标头 (`Cookie`, cookie header) 追加到 request 的标头列表。

  10. 如果 command parameters 包含 "body":

    1. 令 body 为使用 command parameters["body"] 反序列化协议字节的结果。

    2. 将 request 的主体设置为 body。

  11. 使用 "continue request"、request id 和 (null, "incomplete") 恢复。

  12. 返回带有数据 null 的成功。

7.5.5.4. network.continueResponse 命令

network.continueResponse 命令继续执行 被网络拦截阻塞的响应。它可以在 responseStarted 阶段调用,用于修改该 响应的状态和标头,但仍提供网络响应主体。

命令类型
network.ContinueResponse = (
  method: "network.continueResponse",
  params: network.ContinueResponseParameters
)

network.ContinueResponseParameters = {
  request: network.Request,
  ?cookies: [*network.SetCookieHeader]
  ?credentials: network.AuthCredentials,
  ?headers: [*network.Header],
  ?reasonPhrase: text,
  ?statusCode: js-uint,
}
返回类型
network.ContinueResponseResult = EmptyResult
给定 session 和 command parameters 时,远端步骤如下:
  1. 令 request id 为 command parameters["request"]。

  2. 令 response 为尝试使用 session、"continueResponse" 和 command parameters 更新 响应的结果。

  3. 使用 "continue request"、request id 和 (response, "incomplete") 恢复。

  4. 返回带有数据 null 的成功。

7.5.5.5. network.continueWithAuth 命令

network.continueWithAuth 命令会继续一个在 authRequired 阶段被网络拦截阻塞的响应。

命令类型
network.ContinueWithAuth = (
  method: "network.continueWithAuth",
  params: network.ContinueWithAuthParameters
)

network.ContinueWithAuthParameters = {
  request: network.Request,
  (network.ContinueWithAuthCredentials // network.ContinueWithAuthNoCredentials)
}

network.ContinueWithAuthCredentials = (
  action: "provideCredentials", 
  credentials: network.AuthCredentials
)

network.ContinueWithAuthNoCredentials = (
  action: "default" / "cancel"
)
返回类型
network.ContinueWithAuthResult = EmptyResult
给定 session 和 command parameters 时,远端步骤如下:
  1. 令 blocked requests 为 session 的被阻止请求映射。

  2. 令 request id 为 command parameters["request"]。

  3. 如果 blocked requests 不包含 request id,则返回 带有错误,其错误 代码为无此请求。

  4. 令 (request, phase, response) 为 blocked requests[request id]。

  5. 如果 phase 不是 "authRequired",则返回带有错误 ,其错误代码为无效参数。

  6. 如果 command parameters "action" 为 "cancel",则将 response 的身份验证凭据设置为 "cancelled"。

  7. 如果 command parameters "action" 为 "provideCredentials":

    1. 令 credentials 为 command parameters["credentials"]。

    2. 断言:credentials["type"] 为 "password"。

    3. 将 response 的身份验证凭据设置为 (credentials["username"], credentials["password"])

  8. 使用 "continue request"、request id 和 (response, "incomplete") 恢复。

  9. 返回带有数据 null 的成功。

7.5.5.6. network.disownData 命令

network.disownData 命令会释放给定collector 的 已收集网络数据。

命令类型
network.DisownData = (
  method: "network.disownData",
  params: network.DisownDataParameters
)

network.DisownDataParameters = {
  dataType: network.DataType,
  collector: network.Collector,
  request: network.Request,
}
返回类型
network.DisownDataResult = EmptyResult
给定 session 和 command parameters 时,远端步骤如下:
  1. 令 data type 为 command parameters 中 "dataType" 字段的值。

  2. 令 collector id 为 command parameters 中 "collector" 字段的值。

  3. 令 request id 为 command parameters 中 "request" 字段的值。

  4. 令 collectors 为 session 的网络收集器。

  5. 如果 collectors 不包含 collector id,则返回 带有错误,其错误 代码为无此网络收集器。

  6. 令 collected data 为使用 request id 和 data type 获取已收集数据的结果。

  7. 如果 collected data 为 null,则返回带有错误,其错误代码为无此网络 数据。

  8. 使用 collected data 和 collector id 从数据中移除收集器。

  9. 返回带有数据null 的成功。

7.5.5.7. network.failRequest 命令

network.failRequest 命令使被网络拦截阻塞的 fetch 失败。

命令类型
network.FailRequest = (
  method: "network.failRequest",
  params: network.FailRequestParameters
)

network.FailRequestParameters = {
  request: network.Request,
}
返回类型
network.FailRequestResult = EmptyResult
给定 session 和 command parameters 时,远端步骤如下:
  1. 令 blocked requests 为 session 的被阻止请求映射。

  2. 令 request id 为 command parameters["request"]。

  3. 如果 blocked requests 不包含 request id,则返回 带有错误,其错误 代码为无此请求。

  4. 令 (request, phase, response) 为 blocked requests[request id]。

  5. 如果 phase 为 "authRequired",则返回带有错误 ,其错误代码为无效参数。

  6. 令 response 为一个新的网络错误。

    允许设置 错误的精确类型 [Issue #508]

  7. 使用 "continue request"、request id 和 (response, "complete") 恢复。

  8. 返回带有数据 null 的成功。

7.5.5.8. network.getData 命令

network.getData 命令在网络数据可用时获取该数据。

命令类型
network.GetData = (
  method: "network.getData",
  params: network.GetDataParameters
)

network.GetDataParameters = {
  dataType: network.DataType,
  ? collector: network.Collector,
  ? disown: bool .default false,
  request: network.Request,
}
返回类型
network.GetDataResult = {
  bytes: network.BytesValue,
}
给定 session 和 command parameters 时,远端步骤如下:
  1. 令 data type 为 command parameters["dataType"]。

  2. 令 request id 为 command parameters["request"]。

  3. 令 collector id 为 null。

  4. 如果 command parameters 包含 "collector":

    1. 令 collectors 为 session 的网络收集器。

    2. 如果 collectors 不包含 collector id,则返回 带有错误,其错误代码为无此网络收集器。

    3. 将 collector id 设置为 command parameters["collector"]。

  5. 令 disown 为 command parameters["disown"]。

  6. 如果 disown 为 true 且 collector id 为 null,则返回带有错误 ,其错误代码为无效参数。

  7. 令 collected data 为给定 request id 和 data type 时获取已收集数据的结果。

  8. 如果 collected data 为 null:

    1. 返回带有错误,其错误代码为无 此网络数据。

  9. 如果 collected data 的待处理为 true:

    1. 使用 "network data collected" 和 (request id, data type) 等待。

  10. 如果 collector id 不为 null,并且 collected data 的收集器 不包含 collector id:

    1. 返回带有错误,其错误代码为无 此网络数据。

  11. 令 bytes 为 collected data 的字节。

  12. 如果 bytes 为 null,

    1. 返回带有错误,其错误代码为不可用的网络数据。

  13. 令 body 为一个与 network.GetDataResult 产生式匹配的映射, 其中 bytes 字段设置为 bytes。

  14. 如果 disown 为 true,则使用 collected data 和 collector id 从数据中移除收集器。

  15. 返回带有数据 body 的成功。

7.5.5.9. network.provideResponse 命令

network.provideResponse 命令通过提供完整 响应,继续一个被网络拦截阻塞的请求。

注:这不会阻止该请求经历正常的请求 生命周期,因此在其推进过程中仍会发出其他事件。

命令类型
network.ProvideResponse = (
  method: "network.provideResponse",
  params: network.ProvideResponseParameters
)

network.ProvideResponseParameters = {
  request: network.Request,
  ?body: network.BytesValue,
  ?cookies: [*network.SetCookieHeader],
  ?headers: [*network.Header],
  ?reasonPhrase: text,
  ?statusCode: js-uint,
}
返回类型
network.ProvideResponseResult = EmptyResult
给定 session 和 command parameters 时,远端步骤如下:
  1. 令 request id 为 command parameters["request"]。

  2. 令 response 为尝试使用 session、"provideResponse" 和 command parameters 更新 响应的结果。

  3. 如果 command parameters 包含 "body":

    1. 令 body 为使用 command parameters["body"] 反序列化协议字节的结果。

    2. 将 response 的主体设置为作为主体的 body。

  4. 使用 "continue request"、request id 和 (response,"complete") 恢复。

  5. 返回带有数据 null 的成功。

7.5.5.10. network.removeDataCollector 命令

network.removeDataCollector 命令会移除一个 collector。

命令类型
network.RemoveDataCollector = (
  method: "network.removeDataCollector",
  params: network.RemoveDataCollectorParameters
)

network.RemoveDataCollectorParameters = {
  collector: network.Collector
}
返回类型
network.RemoveDataCollectorResult = EmptyResult
给定 session 和 command parameters 时,远端步骤如下:
  1. 令 collector id 为 command parameters 中 "collector" 字段的值。

  2. 令 collectors 为 session 的网络收集器。

  3. 如果 collectors 不包含 collector id,则返回 带有错误,其错误 代码为无此网络收集器。

  4. 从 session 的网络 收集器中移除 collector id。

  5. 对于已收集网络数据中的 collected data,使用 collected data 和 collector id 从数据中移除收集器。

  6. 返回带有数据null 的成功。

7.5.5.11. network.removeIntercept 命令

network.removeIntercept 命令移除一个 网络拦截。

命令类型
network.RemoveIntercept = (
  method: "network.removeIntercept",
  params: network.RemoveInterceptParameters
)

network.RemoveInterceptParameters = {
  intercept: network.Intercept
}
返回类型
network.RemoveInterceptResult = EmptyResult
给定 session 和 command parameters 时,远端步骤如下:
  1. 令 intercept 为 command parameters 中 "intercept" 字段的值。

  2. 令 intercept map 为 session 的拦截映射。

  3. 如果 intercept map 不包含 intercept,则返回 带有错误,其错误 代码为无此拦截。

  4. 从 intercept map 中移除 intercept。

注:移除拦截不会影响 已经被此拦截 阻止的请求。只有未来的请求或现有 请求的未来阶段会受到影响。

  1. 返回带有数据null 的成功。

7.5.5.12. network.setCacheBehavior 命令

network.setCacheBehavior 命令配置 某些请求的网络缓存行为。

命令类型
network.SetCacheBehavior = (
  method: "network.setCacheBehavior",
  params: network.SetCacheBehaviorParameters
)

network.SetCacheBehaviorParameters = {
  cacheBehavior: "default" / "bypass",
  ? contexts: [+browsingContext.BrowsingContext]
}
返回类型
network.SetCacheBehaviorResult = EmptyResult
给定请求 request 时,WebDriver BiDi 缓存行为步骤如下:
  1. 令 navigable 为 null。

  2. 如果 request 的客户端是一个环境设置对象:

    1. 令 environment settings 为 request 的客户端。

    2. 如果存在一个可导航对象,其活动窗口是 environment settings 的全局对象,则将 navigable 设置为该可导航对象的顶层可遍历对象。

  3. 如果 navigable 不为 null,且可导航对象 缓存行为映射包含 navigable,则返回可导航对象缓存行为 映射[navigable]。

  4. 返回默认缓存行为。

给定 navigable 时,可导航对象缓存 行为步骤如下:
  1. 令 top-level navigable 为 navigable 的顶层可遍历对象。

  2. 如果可导航对象缓存行为映射包含 top-level navigable,则返回 可导航对象缓存行为映射[top-level navigable]。

  3. 返回默认缓存行为。

给定 session 和 command parameters 时,远端步骤如下:
  1. 令 behavior 为 command parameters["cacheBehavior"]。

  2. 如果 command parameters 不包含 "contexts":

    1. 将默认缓存行为设置为 behavior。

    2. 清空可导航对象缓存行为映射。

    3. 根据 behavior 的值进行切换:

      "bypass"
      执行实现定义的步骤,以禁用任何 实现特定的资源缓存。
      "default"
      执行实现定义的步骤,以启用当前远端配置中通常启用的任何 实现特定的资源缓存。
    4. 返回带有数据 null 的成功。

  3. 令 navigables 为一个空集合。

  4. 对于 command parameters["contexts"] 中的每个 navigable id:

    1. 令 context 为尝试使用 navigable id 获取 可导航对象 的结果。

    2. 如果 context 不是顶层浏览上下文,则返回带有错误 ,其错误代码为无效参数。

    3. 将 context 追加到 navigables。

  5. 对于 navigables 中的每个 navigable:

    1. 如果可导航对象缓存行为映射包含 navigable,并且 可导航对象缓存行为 映射[navigable] 等于 behavior,则 继续。

    2. 根据 behavior 的值进行切换:

      "bypass"
      执行实现定义的步骤,以针对任何以 navigable 作为顶层浏览上下文的浏览 上下文所发起的网络请求,禁用任何实现特定的 资源缓存。
      "default"
      执行实现定义的步骤,以针对任何以 navigable 作为 顶层浏览上下文的浏览上下文所发起的网络请求, 启用当前远端配置中通常启用的任何 实现特定的资源缓存。
    3. 如果 behavior 等于默认缓存行为:

      1. 如果可导航对象缓存行为映射 包含 navigable,则 移除可导航对象缓存行为 映射[navigable]。

    4. 否则:

      1. 将可导航对象缓存行为 映射[navigable] 设置为 behavior。

  6. 返回带有数据 null 的成功。

7.5.5.13. network.setExtraHeaders 命令

network.setExtraHeaders 命令允许 指定用于扩展或覆盖现有请求标头的标头。

命令类型
network.SetExtraHeaders = (
  method: "network.setExtraHeaders",
  params: network.SetExtraHeadersParameters
)

network.SetExtraHeadersParameters = {
  headers: [*network.Header]
  ? contexts: [+browsingContext.BrowsingContext]
  ? userContexts: [+browser.UserContext]
}
返回类型
network.SetExtraHeadersResult = EmptyResult
要在给定 request 和 headers 的情况下,更新标头:
  1. 令 request headers 为 request 的标头列表。

  2. 对于 headers 中的每个 header:

    1. 在 request headers 中设置 header。

      注:这始终会覆盖 现有值(如果有)。特别是,它不会 将 cookie 追加到现有的 `Set-Cookie` 标头。

给定 session、request 和 related navigables,要更新请求 标头:
  1. 断言:related navigables 的大小为 0 或 1。

    注:这意味着这不适用于与多个 可导航对象关联的 worker。在这种情况下,不清楚应以什么顺序覆盖标头。

  2. 使用 request 和 session 的 额外 标头的默认标头更新标头

  3. 令 user context headers 为 session 的额外标头的 用户上下文标头。

  4. 对于 related navigables 中的 navigable:

    1. 令 user context 为 navigable 的关联 用户上下文。

    2. 如果 user context headers 包含 user context 则使用 request 和 user context headers[user context] 更新 标头

  5. 令 navigable headers 为 session 的额外标头的 可导航对象标头。

  6. 对于 related navigables 中的 navigable:

    1. 令 top-level traversable 为 navigable 的 顶级可遍历对象。

    2. 如果 navigable headers 包含 top-level traversable 则使用 request 和 navigable headers[top-level traversable] 更新 标头。

给定 session 和 command parameters 时,远端步骤如下:
  1. 如果 command parameters 包含 "userContexts" 且 command parameters 包含 "contexts", 则返回带有错误,其错误 代码为无效参数。

  2. 令 headers 为尝试使用 command parameters["headers"] 创建标头列表的结果。

  3. 如果 command parameters 包含 "userContexts":

    1. 令 user contexts 为一个空列表。

    2. 对于 command parameters["userContexts"] 中的 user context id:

      1. 令 user context 为使用 user context id 获取用户上下文的结果。

      2. 如果 user context 为 null,则返回带有错误,其错误代码为无此用户上下文。

      3. 将 user context 追加到 user contexts。

    3. 令 target 为 session 的额外标头的 用户上下文标头

    4. 对于 user contexts 中的 user context:

      1. 将 target[user context] 设置为 headers。

    5. 返回带有数据 null 的成功。

  4. 如果 command parameters 包含 "contexts":

    1. 令 navigables 为尝试使用 command parameters["contexts"] 按 id 获取有效顶层 可遍历对象 的结果。

    2. 令 target 为 session 的额外标头的 可导航对象标头

    3. 对于 navigables 中的 navigable:

      1. 将 target[navigable] 设置为 headers。

    4. 返回带有数据 null 的成功。

  5. 将 session 的额外标头的 默认标头设置为 headers。

  6. 返回带有数据 null 的成功。

7.5.6. 事件

7.5.6.1. network.authRequired 事件
事件类型
network.AuthRequired = (
  method: "network.authRequired",
  params: network.AuthRequiredParameters
)

network.AuthRequiredParameters = {
  network.BaseParameters,
  response: network.ResponseData
}

此事件会在用户代理即将提示输入授权 凭据时发出。

远程端事件触发器是给定请求 request 和响应 response 的 WebDriver BiDi auth required 步骤:
  1. 令 redirect count 为 request 的重定向计数。

  2. 断言:请求发送前映射[request] 等于 redirect count。

    注:这意味着每个调用方都需要 确保在这些步骤之前,已使用 request 调用WebDriver BiDi before request sent 步骤。

  3. 如果 request 的客户端不为 null,则令 related navigables 为使用 request 的获取相关可导航和 客户端的结果。否则,令 related navigables 为空 集合。

  4. 对于给定 "network.authRequired" 和 related navigables 的已启用事件的会话集合 中的每个 session:

    1. 令 params 为使用 session、 "network.authRequired" 和 request 处理 网络事件的结果。

    2. 令 response data 为使用 response 获取响应 数据的结果。

    3. 断言:response data 包含 "authChallenges"。

    4. 将 params 的 response 字段设为 response data。

    5. 断言:params 匹配 network.AuthRequiredParameters 产生式。

    6. 令 body 为匹配 network.AuthRequired 产生式的映射,其中 params 字段设为 params。

    7. 使用 session 和 body 发出 事件。

    8. 如果 params["isBlocked"] 为 true:

      1. 令 blocked requests 为 session 的已阻塞 请求映射。

      2. 令 request id 为 request 的请求 ID。

      3. 将 blocked requests[request id] 设为 (request, "authRequired", response)。

      4. 使用 «"continue request"» 和 request id 等待。

      5. 移除 blocked requests[request id]。

7.5.6.2. network.beforeRequestSent 事件
事件类型
network.BeforeRequestSent = (
  method: "network.beforeRequestSent",
  params: network.BeforeRequestSentParameters
 )

network.BeforeRequestSentParameters = {
  network.BaseParameters,
  ? initiator: network.Initiator,
}

此事件会在请求被发送之前发出(无论是通过网络发送,还是 在由 serviceworker 或本地缓存处理之前)。

给定 request 和 user context 时,用于检查请求是否源自用户上下文的步骤为:
  1. 令 settings 为 request 的client。

  2. 令 related navigables 为以 settings 调用获取相关 navigables所得的结果。

  3. 对于 related navigables 中的 navigable:

    1. 如果 navigable 的关联用户上下文是 user context,则返回 true。

  4. 返回 false。

给定 related navigables,获取模拟网络条件的步骤 为:
  1. 对于 related navigables 中的每个 navigable:

    1. 令 top-level traversable 为 navigable 的顶级可遍历对象。

    2. 令 user context 为 top-level traversable 的关联 用户上下文。

    3. 对于活动 BiDi 会话中的每个 session:

      1. 如果 session 的模拟网络 条件的 可导航对象 网络条件 包含 top-level traversable, 则返回 session 的 模拟网络 条件的 可导航对象 网络条件[top-level traversable]。

    4. 对于活动 BiDi 会话中的每个 session:

      1. 如果 session 的模拟网络 条件的 用户 上下文网络条件 包含 user context,则返回 session 的 模拟网络 条件的 用户 上下文网络条件[user context]。

    5. 对于活动 BiDi 会话中的每个 session:

      1. 如果 session 的模拟网络 条件的 默认 网络条件不为 null, 则返回 session 的模拟网络 条件的 默认 网络条件。

  2. 返回 null。

给定 环境设置对象 settings 的 WebDriver BiDi 网络处于离线状态步骤为:
  1. 令 navigable 为 settings 的相关全局对象的 关联的 Document的节点可导航对象。

  2. 令 emulated network conditions 为使用 [navigable] 获取模拟网络条件所得的结果。

  3. 如果 emulated network conditions 不为 null,且 emulated network conditions 的 offline 为 true,则返回 true。

  4. 返回 false。

给定请求 request 的远端事件触发器是WebDriver BiDi 请求发送前步骤:
  1. 对于用户上下文集合中的每个 user context:

    1. 如果使用 request 和 user context 执行请求源自用户 上下文步骤返回 true:

      1. 对于活动 BiDi 会话中的每个 session:

        注:user context 最多只能存在于一个 用户 上下文到接受不安全证书覆盖映射中。

        1. 如果 session 的用户 上下文到接受不安全证书覆盖映射 包含 user context:

          1. 令 accept insecure certificates 为 session 的 用户 上下文到接受不安全证书覆盖 映射[user context]。

          2. 如果 accept insecure certificates 为 true:

            1. 断言端点节点 支持接受不安全的 TLS 连接。

            2. 为 request 运行基本证书 处理步骤时,跳过步骤 a,以及任何其他 实现定义的证书验证步骤。

          3. 否则,为 request 运行基本证书处理 步骤时,执行所有步骤以及任何 实现定义的证书验证步骤。

        注:user context 最多只能存在于一个 用户上下文到代理 配置映射中。

        1. 如果 session 的用户上下文 到代理配置映射 包含 user context:

          1. 令 proxy configuration 为 session 的 用户 上下文到代理配置映射[user context]。

          2. 采取实现定义的步骤,以确保 request 使用 proxy configuration 定义的代理设置。

            注:这些 设置会在创建用户上下文时进行验证,因此 在此阶段假定其有效;访问 代理时发生的任何错误都将 在处理请求时作为网络错误报告。

  2. 使用 request 可能收集网络请求主体。

  3. 如果请求发送前映射不包含 request,则将请求发送前映射[request] 设置为一个 新集合。

  4. 令 redirect count 为 request 的重定向计数。

  5. 将 redirect count 添加到请求发送前映射[request]。

  6. 如果 request 的客户端不为 null,则令 related navigables 为使用 request 的 客户端获取相关可导航对象所得的结果。否则令 related navigables 为一个空 集合。

  7. 令 response 为 null。

  8. 令 response status 为 "incomplete"。

  9. 对于活动 BiDi 会话中的每个 session:

    1. 使用 session、request 和 related navigables 更新请求标头。

  10. 对于给定 "network.beforeRequestSent" 和 related navigables 的已启用某 事件的会话集合中的每个 session:

    1. 令 params 为使用 session、 "network.beforeRequestSent" 和 request 处理 网络事件所得的结果。

    2. 令 initiator 为使用 request 获取发起者所得的结果。

    3. 如果 initiator 不为空,则将 params 的 initiator 字段 设置为 initiator。

    4. 断言:params 与 network.BeforeRequestSentParameters 产生式匹配。

    5. 令 body 为一个与 network.BeforeRequestSent 产生式匹配的映射,其中 params 字段设置为 params。

    6. 使用 session 和 body 发出 事件。

    7. 如果 params["isBlocked"] 为 true,则:

      1. 令 blocked requests 为 session 的被阻止 请求映射。

      2. 令 request id 为 request 的请求 ID。

      3. 将 blocked requests[request id] 设置为 (request, "beforeRequestSent", null)。

      4. 令 (response, status) 为使用 «"continue request"» 和 request 的请求 ID等待所得的结果。

      5. 如果 status 为 "complete",则将 response status 设置为 status。

      6. 从 blocked requests 中移除 [request id]。

      注:等待期间,不会进一步 处理该请求。

  11. 令 emulated network conditions 为使用 related navigables 获取模拟网络条件所得的结果。

  12. 如果 emulated network conditions 不为 null,且 emulated network conditions 的offline 为 true,则返回 (网络错误, "complete")。

  13. 返回 (response, response status)。

在 Fetch 的“HTTP-network-or-cache fetch”算法中遵循返回值。

7.5.6.3. network.fetchError 事件
事件类型
network.FetchError = (
  method: "network.fetchError",
  params: network.FetchErrorParameters
 )

network.FetchErrorParameters = {
  network.BaseParameters,
  errorText: text,
}

此事件会在网络请求以错误结束时发出。

远端事件触发器是给定 request request 时的 WebDriver BiDi fetch error 步骤:
  1. 如果 before request sent map[request] 不包含 request 的 redirect count,则以 request 运行 WebDriver BiDi before request sent 步骤。

    注:这确保了 network.beforeRequestSent 总是可以在 network.fetchError 之前发出,而无需调用者在每条错误路径上显式调用 WebDriver BiDi before request sent 步骤。

  2. 如果 request 的client 不是 null,则令 related navigables 为以 request 的 client 调用获取相关 navigables所得的结果。否则令 related navigables 为空 集合。

  3. 以 request 调用可能中止网络响应体 收集。

  4. 对于给定 "network.fetchError" 和 related navigables 时的事件已启用的会话集合中的每个 session:

    1. 令 params 为以 session、 "network.fetchError" 和 request 调用处理 network event所得的结果。

    2. 将 params 的 errorText 字段设置为一个实现定义的 字符串, 用于描述导致请求中止的错误。

    3. 断言:params 匹配 network.FetchErrorParameters 产生式。

    4. 令 body 为一个匹配 network.FetchError 产生式的映射,其 params 字段设置为 params。

    5. 以 session 和 body 发出 事件。

7.5.6.4. network.responseCompleted 事件
事件类型
network.ResponseCompleted = (
  method: "network.responseCompleted",
  params: network.ResponseCompletedParameters
 )

network.ResponseCompletedParameters = {
  network.BaseParameters,
  response: network.ResponseData,
}

此事件会在接收到完整响应体之后发出。

远端事件触发器是给定 request request 和 response response 时的 WebDriver BiDi response completed 步骤:
  1. 令 redirect count 为 request 的redirect count。

  2. 断言:before request sent map[request] 包含 redirect count。

    注:这意味着每个调用者都需要确保在这些步骤之前, 先以 request 调用 WebDriver BiDi before request sent 步骤。

  3. 如果 request 的client 不是 null,则令 related navigables 为以 request 的 client 调用获取相关 navigables所得的结果。否则令 related navigables 为空 集合。

  4. 以 request 和 response 调用可能收集网络响应体。

  5. 令 sessions 为给定 "network.responseCompleted" 和 related navigables 时的事件已启用的会话集合。

  6. 对于 sessions 中的每个 session:

    1. 令 params 为以 session、 "network.responseCompleted" 和 request 调用处理 network event所得的结果。

    2. 断言:params["isBlocked"] 为 false。

    3. 令 response data 为以 response 调用获取 response data所得的结果。

    4. 将 params 的 response 字段设置为 response data。

    5. 断言:params 匹配 network.ResponseCompletedParameters 产生式。

    6. 令 body 为一个匹配 network.ResponseCompleted 产生式的映射,其 params 字段设置为 params。

    7. 以 session 和 body 发出 事件。

7.5.6.5. network.responseStarted 事件
事件类型
network.ResponseStarted = (
  method: "network.responseStarted",
  params: network.ResponseStartedParameters
 )

network.ResponseStartedParameters = {
  network.BaseParameters,
  response: network.ResponseData,
}

此事件会在接收到响应头之后、响应体完成之前发出。

远端事件触发器是给定 request request 和 response response 时的 WebDriver BiDi response started 步骤:
  1. 令 redirect count 为 request 的redirect count。

  2. 断言:before request sent map[request] 等于 redirect count。

    注:这意味着每个调用者都需要确保在这些步骤之前, 先以 request 调用 WebDriver BiDi before request sent 步骤。

  3. 如果 request 的client 不是 null,则令 related navigables 为以 request 的 client 调用获取相关 navigables所得的结果。否则令 related navigables 为空 集合。

  4. 令 response status 为 "incomplete"。

  5. 令 sessions 为给定 "network.responseStarted" 和 related navigables 时的事件已启用的会话集合。

  6. 对于 sessions 中的每个 session:

    1. 令 params 为以 session、 "network.responseStarted" 和 request 调用处理 network event所得的结果。

    2. 令 response data 为以 response 调用获取 response data所得的结果。

    3. 将 params 的 response 字段设置为 response data。

    4. 断言:params 匹配 network.ResponseStartedParameters 产生式。

    5. 令 body 为一个匹配 network.ResponseStarted 产生式的映射,其 params 字段设置为 params。

    6. 以 session 和 body 发出 事件。

    7. 如果 params["isBlocked"] 为 true:

      1. 令 blocked requests 为 session 的blocked request map。

      2. 令 request id 为 request 的request id。

      3. 将 blocked requests[request id] 设置为 (request, "beforeRequestSent", response)。

      4. 令 (response, status) 为以 «"continue request"» 和 request id 等待所得的结果。

      5. 如果 status 为 "complete",则将 response status 设置为 status。

      6. 移除 blocked requests[request id]。

  7. 返回 (response, response status)。

7.6. script 模块

script 模块包含与 script realm 和执行相关的命令与事件。

7.6.1. 定义

Remote end definition

ScriptCommand = (
  script.AddPreloadScript //
  script.CallFunction //
  script.Disown //
  script.Evaluate //
  script.GetRealms //
  script.RemovePreloadScript
)

local end definition

ScriptResult = (
  script.AddPreloadScriptResult /
  script.CallFunctionResult /
  script.DisownResult /
  script.EvaluateResult /
  script.GetRealmsResult /
  script.RemovePreloadScriptResult
)

ScriptEvent = (
  script.Message //
  script.RealmCreated //
  script.RealmDestroyed
)

7.6.2. 预加载脚本

预加载脚本是一个 在新的 Window 创建时运行, 且在任何作者定义脚本运行之前运行的脚本。

TODO:将其扩展到其他种类 realm 中的脚本。

一个 BiDi 会话具有一个 预加载脚本映射, 它是一个映射, 其中键为 UUID,值为具有以下项的结构体: 名为 function declaration 的项,它是字符串; 名为 arguments 的项,它是列表; 名为 contexts 的项,它是列表或 null; 名为 sandbox 的项,它是字符串或 null; 以及名为 user contexts 的项,它是一个集合。

注:如果执行预加载脚本失败,无论是由于语法 错误,还是 运行时异常,都会在其被执行的 realm 中报告一个 [ECMAScript] 异常,而其他预加载脚本会照常运行。

要在给定 environment settings 的情况下,运行 WebDriver BiDi 预加载脚本:
  1. 令 document 为 environment settings 的相关全局对象的 关联 Document。

  2. 令 navigable 为 document 的可导航。

  3. 令 user context 为 navigable 的关联用户 上下文。

  4. 令 user context id 为 user context 的用户 上下文 ID。

  5. 对于活动 BiDi 会话中的每个 session:

    1. 对于 session 的预加载脚本映射的 值中的每个 preload script:

      1. 如果 preload script 的 user contexts 的大小不为零:

        1. 如果 preload script 的 user contexts 不包含 user context id, 则继续。

      2. 如果 preload script 的 contexts 不为 null:

        1. 令 navigable id 为 navigable 的顶级可遍历的 id。

        2. 如果 preload script 的 contexts 不包含 navigable id, 则继续。

      3. 如果 preload script 的 sandbox 不为 null,则令 realm 为使用 preload script 的 sandbox 和 navigable 获取或创建沙盒 realm的结果。 否则,令 realm 为 environment settings 的 realm 执行上下文的 Realm 组件。

      4. 令 exception reporting global 为 environment settings 的 realm 执行上下文的 Realm 组件的全局对象。

      5. 令 arguments 为 preload script 的 arguments。

      6. 令 deserialized arguments 为空列表。

      7. 对于 arguments 中的每个 argument:

        1. 令 channel 为使用 session、realm 和 argument 创建 通道的结果。

        2. 将 channel 追加到 deserialized arguments。

      8. 令 base URL 为 environment settings 的API 基础 URL。

      9. 令 options 为默认脚本 fetch 选项。

      10. 令 function declaration 为 preload script 的 function declaration。

      11. 令 function body evaluation status 为使用 function declaration、 environment settings、base URL 和 options 求值函数体的结果。

      12. 如果 function body evaluation status 是突然完成,则为 exception reporting global 报告由异常 function body evaluation status.[[Value]] 给出的异常。

      13. 令 function object 为 function body evaluation status.[[Value]]。

      14. 如果 IsCallable(function object) 为 false:

        1. 令 error 为 realm 中新的 TypeError 对象。

        2. 为 exception reporting global 报告异常 error。

      15. 使用 environment settings 准备运行脚本。

      16. 将 evaluation status 设为 Call(function object, null, deserialized arguments)。

      17. 使用 environment settings 运行脚本后清理。

      18. 如果 evaluation status 是突然 完成,则为 exception reporting global 报告由异常 evaluation status.[[Value]] 给出的异常。

7.6.3. 类型

7.6.3.1. script.Channel 类型

远程端定义 和 本地端定义

script.Channel = text;

script.Channel 类型表示用于从远程端向 本地端发送自定义消息的特定通道的 ID。

7.6.3.2. script.ChannelValue 类型

远程端定义

script.ChannelValue = {
  type: "channel",
  value: script.ChannelProperties,
}

script.ChannelProperties = {
  channel: script.Channel,
  ? serializationOptions: script.SerializationOptions,
  ? ownership: script.ResultOwnership,
}

script.ChannelValue 类型表示一种 ArgumentValue,它可以被反序列化为一个函数,该函数用于从远程端向本地端发送 消息。

要在给定 session、realm 和 protocol value 的情况下创建 channel:

  1. 令 channel properties 为 protocol value["value"]。

  2. 令 steps 为给定参数 message 时的以下步骤:

    1. 令 current realm 为当前 Realm Record。

    2. 以 session、current realm、channel properties 和 message 发出 script message。

  3. 返回 CreateBuiltinFunction(steps, 1, "", « », realm)。

7.6.3.3. script.EvaluationResult 类型

远程端定义 和 本地端定义

script.EvaluationResult = (
  script.EvaluationResultSuccess /
  script.EvaluationResultException
)

script.EvaluationResultSuccess = {
  type: "success",
  result: script.RemoteValue,
  realm: script.Realm
}

script.EvaluationResultException = {
  type: "exception",
  exceptionDetails: script.ExceptionDetails
  realm: script.Realm
}

script.EvaluationResult 类型表示命令的返回值, 该命令执行脚本。script.EvaluationResultSuccess 变体用于 脚本正常完成的情况,而 script.EvaluationResultException 变体用于脚本 因抛出异常而完成的情况。

7.6.3.4. script.ExceptionDetails 类型

远程端定义 和 本地端定义

script.ExceptionDetails = {
  columnNumber: js-uint,
  exception: script.RemoteValue,
  lineNumber: js-uint,
  stackTrace: script.StackTrace,
  text: text,
}

script.ExceptionDetails 类型表示一个 JavaScript 异常。

给定一个 realm、一个完成记录 record、一个 ownership type 和一个 session,要获取异常 详细信息:

  1. 断言:record.[[Type]] 为 throw。

  2. 令 text 为由实现定义的、对 record 所表示错误的文本描述。

    TODO:收紧这里的要求;人们可能会尝试使用正则表达式或其他同样糟糕的方式解析 此数据。

  3. 令 serialization options 为一个与 script.SerializationOptions 产生式匹配的映射, 其字段设置为 各自的默认值。

  4. 令 exception 为使用 record.[[Value]]、serialization options、ownership type、 一个新的映射作为序列化内部映射、realm 和 session 序列化为 远程值所得的结果。

  5. 令 stack trace 为给定 record 的异常的栈跟踪。

  6. 如果 stack trace 的大小为 1 或更大,则令 line number 为 stack trace[0] 中 lineNumber 字段的值,并令 column number 为 stack trace[0] 中 columnNumber 字段的值。否则 令 line number 和 column number 均为 0。

  7. 令 exception details 为一个与 script.ExceptionDetails 产生式匹配的映射, 其中 text 字段设置为 text,exception 字段设置为 exception, lineNumber 字段设置为 line number, columnNumber 字段设置为 column number,并且 stackTrace 字段设置为 stack trace。

  8. 返回 exception details。

7.6.3.5. script.Handle 类型

远程端定义 和 本地端定义

script.Handle = text;

script.Handle 类型表示由 ECMAScript 运行时拥有的对象的句柄。该句柄仅在特定Realm中有效。

每个 ECMAScript Realm 都有一个对应的 句柄对象映射。这是一个 从句柄 ID 到其对应对象的强映射。

7.6.3.6. script.InternalId 类型

远程端定义 和 本地端定义

script.InternalId = text;

script.InternalId 类型表示在 序列化期间, 先前序列化的 script.RemoteValue 的 ID。

7.6.3.7. script.LocalValue 类型

远程端定义

script.LocalValue = (
  script.RemoteReference /
  script.PrimitiveProtocolValue /
  script.ChannelValue /
  script.ArrayLocalValue /
  { script.DateLocalValue } /
  script.MapLocalValue /
  script.ObjectLocalValue /
  { script.RegExpLocalValue } /
  script.SetLocalValue
)

script.ListLocalValue = [*script.LocalValue];

script.ArrayLocalValue = {
  type: "array",
  value: script.ListLocalValue,
}

script.DateLocalValue = (
  type: "date",
  value: text
)

script.MappingLocalValue = [*[(script.LocalValue / text), script.LocalValue]];

script.MapLocalValue = {
  type: "map",
  value: script.MappingLocalValue,
}

script.ObjectLocalValue = {
  type: "object",
  value: script.MappingLocalValue,
}

script.RegExpValue = {
  pattern: text,
  ? flags: text,
}

script.RegExpLocalValue = (
  type: "regexp",
  value: script.RegExpValue,
)

script.SetLocalValue = {
  type: "set",
  value: script.ListLocalValue,
}

script.LocalValue 类型表示可以被反序列化到 ECMAScript 中的值。 这包括原始值和非原始值,以及远程引用和 通道。

给定 serialized key-value list、realm 和 session,要反序列化 键值列表:

  1. 令 deserialized key-value list 为一个新列表。

  2. 对于 serialized key-value list 中的每个 serialized key-value:

    1. 如果 serialized key-value 的大小不是 2, 则返回带有错误,其错误代码为无效参数。

    2. 令 serialized key 为 serialized key-value[0]。

    3. 如果 serialized key 是 string, 则令 deserialized key 为 serialized key。

    4. 否则,令 deserialized key 为尝试给定 serialized key、realm 和 session 反序列化本地值的结果。

    5. 令 serialized value 为 serialized key-value[1]。

    6. 令 deserialized value 为尝试给定 serialized value、realm 和 session 反序列化本地值 的结果。

    7. 将 CreateArrayFromList(«deserialized key, deserialized value») 追加到 deserialized key-value list。

  3. 返回带有数据 deserialized key-value list 的成功。

给定 serialized value list、realm 和 session,要反序列化 值列表:

  1. 令 deserialized values 为一个新列表。

  2. 对于 serialized value list 中的每个 serialized value:

    1. 令 deserialized value 为尝试给定 serialized value、realm 和 session 反序列化本地值 的结果。

    2. 将 deserialized value 追加到 deserialized values;

  3. 返回带有数据 deserialized values 的成功。

给定 local protocol value、realm 和 session,要反序列化 本地值:

  1. 如果 local protocol value 与script.RemoteReference 产生式匹配,则返回 给定 local protocol value、realm 和 session 的反序列化远程引用结果。

  2. 如果 local protocol value 与script.PrimitiveProtocolValue 产生式匹配, 则返回 使用 local protocol value 反序列化原始协议值 的结果。

  3. 如果 local protocol value 与 script.ChannelValue 产生式匹配, 则返回使用 session、realm 和 local protocol value 创建 通道的结果。

  4. 令 type 为 local protocol value 的 type 字段的值;如果 不存在此字段,则为 undefined。

  5. 令 value 为 local protocol value 的 value 字段的值;如果 不存在此字段,则为 undefined。

  6. 在以下条件及相关步骤列表中,运行其相关条件为 true 的第一组步骤:

    type 是字符串 "array"
    1. 令 deserialized value list 为尝试给定 value、realm 和 session 反序列化值列表 的结果。

    2. 返回带有数据 CreateArrayFromList(deserialized value list) 的成功。

    type 是字符串 "date"
    1. 如果 value 与日期时间字符串格式不匹配,则返回 带有错误,其 错误代码为无效参数。

    2. 令 date result 为 Construct(Date, value)。

    3. 断言:date result 不是突然 完成。

    4. 返回带有数据 date result 的成功。

    type 是字符串 "map"
    1. 令 deserialized key-value list 为尝试使用 value、realm 和 session 反序列化键值列表的结果。

    2. 令 iterable 为 CreateArrayFromList(deserialized key-value list)

    3. 返回带有数据 Map(iterable) 的成功。

    type 是字符串 "object"
    1. 令 deserialized key-value list 为尝试使用 value、realm 和 session 反序列化键值列表的结果。

    2. 令 iterable 为 CreateArrayFromList(deserialized key-value list)

    3. 返回带有数据 Object.fromEntries(iterable) 的成功。

    type 是字符串 "regexp"
    1. 令 pattern 为 local protocol value 的 pattern 字段的值。

    2. 令 flags 为 local protocol value 的 flags 字段的值;如果 不存在此字段,则为 undefined。

    3. 令 regex_result 为 Regexp(pattern, flags)。如果这抛出异常,则返回带有错误 ,其错误代码为无效参数。

    4. 返回带有数据 regex_result 的成功。

    type 是字符串 "set"
    1. 令 deserialized value list 为尝试给定 value、realm 和 session 反序列化值列表 的结果。

    2. 令 iterable 为 CreateArrayFromList(deserialized key-value list)

    3. 返回带有数据 Set 对象(iterable) 的成功。

    否则
    返回带有错误,其错误代码为无效参数。
7.6.3.8. script.PreloadScript 类型

远程端定义 和 本地端定义

script.PreloadScript = text;

script.PreloadScript 类型表示将在 realm 创建时运行的脚本的句柄。

7.6.3.9. script.Realm 类型

远程端定义 和 本地端定义

script.Realm = text;

每个领域都有一个关联的领域 id,它是一个 唯一标识该领域的字符串。这会在创建领域时 隐式设置。

领域的领域 id是不透明的,并且 不得从句柄对象映射中相应全局对象的句柄 id 推导出来,或者在 相关情况下,不得从任何可导航对象的可导航对象 id 推导出来。

注:这是为了确保用户不会依赖 不同 id 之间特定于实现的 关系。

给定 realm id,要获取领域:
  1. 如果 realm id 为 null,则返回带有数据 null 的成功。

  2. 如果不存在领域,其id 为 realm id,则返回 带有错误,其错误 代码为无此框架

  3. 令 realm 为领域,其 id 为 realm id。

  4. 返回带有数据 realm 的成功

此处的 错误代码不正确

7.6.3.10. script.PrimitiveProtocolValue 类型

远程端定义 和 本地端定义

script.PrimitiveProtocolValue = (
  script.UndefinedValue /
  script.NullValue /
  script.StringValue /
  script.NumberValue /
  script.BooleanValue /
  script.BigIntValue
)

script.UndefinedValue = {
  type: "undefined",
}

script.NullValue = {
  type: "null",
}

script.StringValue = {
  type: "string",
  value: text,
}

script.SpecialNumber = "NaN" / "-0" / "Infinity" / "-Infinity";

script.NumberValue = {
  type: "number",
  value: number / script.SpecialNumber,
}

script.BooleanValue = {
  type: "boolean",
  value: bool,
}

script.BigIntValue = {
  type: "bigint",
  value: text,
}

script.PrimitiveProtocolValue 表示只能 由值表示而绝不由引用表示的值。

给定一个 value,要序列化原始协议值:

  1. 令 remote value 为 undefined。

  2. 在以下条件及其关联步骤的列表中,如果存在关联条件为 true 的项,则运行第一组 对应的步骤:

    Type(value) 为 undefined
    令 remote value 为一个与 script.UndefinedValue 产生式匹配的映射, 该产生式位于本地端定义中。
    Type(value) 为 Null
    令 remote value 为一个与 script.NullValue 产生式匹配的映射, 该产生式位于本地端定义中。
    Type(value) 为 String
    令 remote value 为一个与 script.StringValue 产生式匹配的映射, 该产生式位于本地端定义中, 其中 value 属性设置为 value。

    这里 未处理孤立代理项

    Type(value) 为 Number
    1. 根据 value 的值进行切换:

      NaN
      令 serialized 为 "NaN"
      -0
      令 serialized 为 "-0"
      Infinity
      令 serialized 为 "Infinity"
      -Infinity
      令 serialized 为 "-Infinity"
      否则:
      令 serialized 为 value
    2. 令 remote value 为一个与 script.NumberValue 产生式匹配的映射,该产生式位于本地端定义中, 其中 value 属性设置为 serialized。

    Type(value) 为 Boolean
    令 remote value 为一个与 script.BooleanValue 产生式匹配的映射, 该产生式位于本地端定义中, 其中 value 属性设置为 value。
    Type(value) 为 BigInt
    令 remote value 为一个与 script.BigIntValue 产生式匹配的映射, 该产生式位于本地端定义中, 其中 value 属性设置为对 value 运行ToString 操作所得的结果。
  3. 返回 remote value

给定一个 primitive protocol value,要反序列化原始协议值:

  1. 令 type 为 primitive protocol value 的 type 字段的值。

  2. 令 value 为 undefined。

  3. 如果 primitive protocol value 具有 value 字段:

    1. 令 value 为 primitive protocol value 的 value 字段的值。

  4. 在以下条件及相关步骤列表中,运行其相关条件为 true 的第一组步骤:

    type 是字符串 "undefined"
    返回带有数据undefined 的成功。
    type 是字符串 "null"
    返回带有数据null 的成功。
    type 是字符串 "string"
    返回带有数据 value 的成功。
    type 是字符串 "number"
    1. 如果 Type(value) 为 Number,则返回带有数据 value 的成功。

    2. 断言:Type(value) 为 String。

    3. 如果 value 是字符串 "NaN",则返回带有 数据 NaN 的成功。

    4. 令 number_result 为 StringToNumber(value)。

    5. 如果 number_result 为 NaN,则返回带有错误,其错误代码为无效参数

    6. 返回带有数据 number_result 的成功。

    type 是字符串 "boolean"
    返回带有数据 value 的成功。
    type 是字符串 "bigint"
    1. 令 bigint_result 为 StringToBigInt(value)。

    2. 如果 bigint_result 为 undefined,则返回带有错误,其错误代码为无效参数

    3. 返回带有数据 bigint_result 的成功。

  5. 返回带有错误,其错误 代码为无效参数

7.6.3.11. script.RealmInfo 类型

本地端定义

script.RealmInfo = (
  script.WindowRealmInfo /
  script.DedicatedWorkerRealmInfo /
  script.SharedWorkerRealmInfo /
  script.ServiceWorkerRealmInfo /
  script.WorkerRealmInfo /
  script.PaintWorkletRealmInfo /
  script.AudioWorkletRealmInfo /
  script.WorkletRealmInfo
)

script.BaseRealmInfo = (
  realm: script.Realm,
  origin: text
)

script.WindowRealmInfo = {
  script.BaseRealmInfo,
  type: "window",
  context: browsingContext.BrowsingContext,
  ? userContext: browser.UserContext,
  ? sandbox: text
}

script.DedicatedWorkerRealmInfo = {
  script.BaseRealmInfo,
  type: "dedicated-worker",
  owners: [script.Realm]
}

script.SharedWorkerRealmInfo = {
  script.BaseRealmInfo,
  type: "shared-worker"
}

script.ServiceWorkerRealmInfo = {
  script.BaseRealmInfo,
  type: "service-worker"
}

script.WorkerRealmInfo = {
  script.BaseRealmInfo,
  type: "worker"
}

script.PaintWorkletRealmInfo = {
  script.BaseRealmInfo,
  type: "paint-worklet"
}

script.AudioWorkletRealmInfo = {
  script.BaseRealmInfo,
  type: "audio-worklet"
}

script.WorkletRealmInfo = {
  script.BaseRealmInfo,
  type: "worklet"
}

注: script.RealmInfo 的变体与 script.RealmType 的值之间存在 1:1 关系。

script.RealmInfo 类型表示 realm 的属性。

给定 realm,要获取可导航对象:
  1. 令 global object 为 realm 的全局对象。

  2. 令 global object 为已解包的 global object。

  3. 如果 global object 不是 Window 对象,则返回 null。

  4. 令 document 为 global object 的已包装 Window 的 关联的 Document。

  5. 返回 document 的节点可导航对象。

给定 global object,要获取 worker 的 所有者:
  1. 断言:global object 是一个 WorkerGlobalScope 对象。

  2. 令 owners 为一个空列表。

  3. 对于 global object 的关联所有者集合中的每个 owner:

    1. 令 owner environment settings 为 owner 的相关设置对象。

    2. 令 owner realm info 为给定 owner environment settings 获取 Realm 信息 所得的结果。

    3. 如果 owner realm info 为 null,则继续。

    4. 将 owner realm info["id"] 追加到 owners。

  4. 返回 owners。

给定 environment settings,要获取 Realm 信息:
  1. 令 realm 为 environment settings 的Realm 执行上下文的 Realm 组件。

  2. 令 realm id 为 realm 的Realm ID。

  3. 令 origin 为给定 environment settings 的 origin 执行源的序列化所得的结果。

  4. 令 global object 为 environment settings 指定的全局对象

  5. 运行第一个匹配条件下的步骤:

    global object 是一个 Window 对象
    1. 令 document 为 environment settings 的相关全局对象的 关联的 Document。

    2. 令 navigable 为 document 的节点可导航对象。

    3. 如果 navigable 为 null,则返回 null。

    4. 令 navigable id 为 navigable 的可导航对象 ID。

    5. 令 user context id 为 navigable 的关联用户上下文的用户上下文 ID

    6. 令 realm info 为一个与 script.WindowRealmInfo 产生式匹配的映射, 其中 realm 字段设置为 realm id,origin 字段设置为 origin,context 字段设置为 navigable id,并且 userContext 字段设置为 user context id。

    global object 是一个 SandboxWindowProxy 对象
    TODO:不清楚这是否是处理沙箱的正确表述。
    1. 令 document 为 global object 的已包装 Window 的 关联的 Document。

    2. 令 navigable 为 document 的节点可导航对象。

    3. 如果 navigable 为 null,则返回 null。

    4. 令 navigable id 为 navigable 的可导航对象 ID。

    5. 令 user context id 为 navigable 的关联用户上下文的用户上下文 ID

    6. 令 sandbox name 为给定 realm 获取沙箱 名称所得的结果。

    7. 断言:sandbox name 不为 null。

    8. 令 realm info 为一个与 script.WindowRealmInfo 产生式匹配的映射, 其中 realm 字段设置为 realm id,origin 字段设置为 origin,context 字段设置为 navigable id, userContext 字段设置为 user context id,并且 sandbox 字段设置为 sandbox name。

    global object 是一个 DedicatedWorkerGlobalScope 对象
    1. 令 owners 为给定 global object 获取 worker 的所有者所得的结果。

    2. 断言:owners 恰好有一个项。

    3. 令 realm info 为一个与 script.DedicatedWorkerRealmInfo 产生式匹配的映射, 其中 realm 字段设置为 realm id,origin 字段 设置为 origin,并且 owners 字段设置为 owners。

    global object 是一个 SharedWorkerGlobalScope 对象
    1. 令 realm info 为一个与 script.SharedWorkerRealmInfo 产生式匹配的映射, 其中 realm 字段设置为 realm id,并且 origin 字段 设置为 origin。

    global object 是一个 ServiceWorkerGlobalScope 对象
    1. 令 realm info 为一个与 script.ServiceWorkerRealmInfo 产生式匹配的映射, 其中 realm 字段设置为 realm id,并且 origin 字段 设置为 origin。

    global object 是一个 WorkerGlobalScope 对象
    1. 令 realm info 为一个与 script.WorkerRealmInfo 产生式匹配的映射, 其中 realm 字段设置为 realm id,并且 origin 字段设置为 origin。

    global object 是一个 PaintWorkletGlobalScope 对象
    1. 令 realm info 为一个与 script.PaintWorkletRealmInfo 产生式匹配的映射, 其中 realm 字段设置为 realm id,并且 origin 字段设置为 origin。

    global object 是一个 AudioWorkletGlobalScope 对象
    1. 令 realm info 为一个与 script.AudioWorkletRealmInfo 产生式匹配的映射, 其中 realm 字段设置为 realm id,并且 origin 字段设置为 origin。

    global object 是一个 WorkletGlobalScope 对象
    1. 令 realm info 为一个与 script.WorkletRealmInfo 产生式匹配的映射, 其中 realm 字段设置为 realm id,并且 origin 字段设置为 origin。

    否则:
    1. 令 realm info 为 null。

  6. 返回 realm info

注:本规范的未来版本将 保持以下不变量: 对类型名称按 "-" 进行拆分后,最后一个组成部分 对于实现 WorkerGlobalScope 的全局对象始终为 "worker", 而对于实现 WorkletGlobalScope 的全局对象则为 "worklet"。

7.6.3.12. script.RealmType 类型

远程端定义 和 本地端定义

script.RealmType = "window" / "dedicated-worker" / "shared-worker" / "service-worker" /
                   "worker" / "paint-worklet" / "audio-worklet" / "worklet"

script.RealmType 类型表示 Realm 的不同类型。

7.6.3.13. script.RemoteReference 类型

远程端定义

script.RemoteReference = (
  script.SharedReference /
  script.RemoteObjectReference
)

script.SharedReference = {
   sharedId: script.SharedId

   ? handle: script.Handle,
   Extensible
}

script.RemoteObjectReference = {
   handle: script.Handle,

   ? sharedId: script.SharedId
   Extensible
}

script.RemoteReference 类型要么是 script.RemoteObjectReference,表示对给定Realm中句柄对象映射里 现有 ECMAScript 对象的远程引用,要么 是 script.SharedReference,表示对节点的引用。

处理“陈旧对象 引用”情形。

注:如果提供的引用同时具有 handle 和 sharedId,则该算法将忽略 handle,并且仅遵循 sharedId。

要在给定 remote reference、realm 和 session 的情况下,反序列化 远程引用:
  1. 断言 remote reference 匹配 script.RemoteReference 产生式。

  2. 如果 remote reference 匹配 script.SharedReference 产生式,则返回 使用 remote reference、realm 和 session 反序列化共享引用的结果。

  3. 返回使用 remote reference 和 realm 反序列化远程对象引用的结果。

给定 remote object reference 和 realm,要反序列化远程对象引用:
  1. 令 handle id 为 remote object reference 的 handle 字段的值。

  2. 令 handle map 为 realm 的句柄对象映射

  3. 如果 handle map 不包含 handle id,则返回带有错误,其 错误代码为无此句柄。

  4. 返回带有数据 handle map[handle id] 的成功。

给定 shared reference、realm 和 session,要反序列化 共享引用:
  1. 断言 shared reference 与 script.SharedReference 产生式匹配。

  2. 令 navigable 为使用 realm 获取可导航对象的结果。

  3. 如果 navigable 为 null,则返回带有错误,其错误代码为 无此 节点。

    注:当该领域不是 Window 全局对象时会发生这种情况。

  4. 令 shared id 为 shared reference 的 sharedId 字段的值。

  5. 令 node 为尝试使用 session、 navigable 和 shared id 获取节点的结果。

  6. 如果 node 为 null,则返回带有错误,其错误代码为 无此 节点。

  7. 令 environment settings 为其 realm 执行上下文的 Realm 组件为 realm 的环境设置对象。

  8. 如果 node 的节点文档的源与 environment settings 的源不是同源域, 则返回带有错误,其错误 代码为无此节点。

    注:这可确保 WebDriver-BiDi 不能用于在原本不允许脚本访问的 领域之间传递对象。

  9. 令 realm global object 为 realm 的全局对象。

  10. 如果 realm global object 是 SandboxWindowProxy 对象,则将 node 设置为 realm 中包装 node 的 SandboxProxy。

  11. 返回带有数据 node 的成功。

7.6.3.14. script.RemoteValue 类型

远程端定义 和 本地端定义

script.RemoteValue = (
  script.PrimitiveProtocolValue /
  script.SymbolRemoteValue /
  script.ArrayRemoteValue /
  script.ObjectRemoteValue /
  script.FunctionRemoteValue /
  script.RegExpRemoteValue /
  script.DateRemoteValue /
  script.MapRemoteValue /
  script.SetRemoteValue /
  script.WeakMapRemoteValue /
  script.WeakSetRemoteValue /
  script.GeneratorRemoteValue /
  script.ErrorRemoteValue /
  script.ProxyRemoteValue /
  script.PromiseRemoteValue /
  script.TypedArrayRemoteValue /
  script.ArrayBufferRemoteValue /
  script.NodeListRemoteValue /
  script.HTMLCollectionRemoteValue /
  script.NodeRemoteValue /
  script.WindowProxyRemoteValue
)

script.ListRemoteValue = [*script.RemoteValue];

script.MappingRemoteValue = [*[(script.RemoteValue / text), script.RemoteValue]];

script.SymbolRemoteValue = {
  type: "symbol",
  ? handle: script.Handle,
  ? internalId: script.InternalId,
}

script.ArrayRemoteValue = {
  type: "array",
  ? handle: script.Handle,
  ? internalId: script.InternalId,
  ? value: script.ListRemoteValue,
}

script.ObjectRemoteValue = {
  type: "object",
  ? handle: script.Handle,
  ? internalId: script.InternalId,
  ? value: script.MappingRemoteValue,
}

script.FunctionRemoteValue = {
  type: "function",
  ? handle: script.Handle,
  ? internalId: script.InternalId,
}

script.RegExpRemoteValue = {
  script.RegExpLocalValue,
  ? handle: script.Handle,
  ? internalId: script.InternalId,
}

script.DateRemoteValue = {
  script.DateLocalValue,
  ? handle: script.Handle,
  ? internalId: script.InternalId,
}

script.MapRemoteValue = {
  type: "map",
  ? handle: script.Handle,
  ? internalId: script.InternalId,
  ? value: script.MappingRemoteValue,
}

script.SetRemoteValue = {
  type: "set",
  ? handle: script.Handle,
  ? internalId: script.InternalId,
  ? value: script.ListRemoteValue
}

script.WeakMapRemoteValue = {
  type: "weakmap",
  ? handle: script.Handle,
  ? internalId: script.InternalId,
}

script.WeakSetRemoteValue = {
  type: "weakset",
  ? handle: script.Handle,
  ? internalId: script.InternalId,
}

script.GeneratorRemoteValue = {
  type: "generator",
  ? handle: script.Handle,
  ? internalId: script.InternalId,
}

script.ErrorRemoteValue = {
  type: "error",
  ? handle: script.Handle,
  ? internalId: script.InternalId,
}

script.ProxyRemoteValue = {
  type: "proxy",
  ? handle: script.Handle,
  ? internalId: script.InternalId,
}

script.PromiseRemoteValue = {
  type: "promise",
  ? handle: script.Handle,
  ? internalId: script.InternalId,
}

script.TypedArrayRemoteValue = {
  type: "typedarray",
  ? handle: script.Handle,
  ? internalId: script.InternalId,
}

script.ArrayBufferRemoteValue = {
  type: "arraybuffer",
  ? handle: script.Handle,
  ? internalId: script.InternalId,
}

script.NodeListRemoteValue = {
  type: "nodelist",
  ? handle: script.Handle,
  ? internalId: script.InternalId,
  ? value: script.ListRemoteValue,
}

script.HTMLCollectionRemoteValue = {
  type: "htmlcollection",
  ? handle: script.Handle,
  ? internalId: script.InternalId,
  ? value: script.ListRemoteValue,
}

script.NodeRemoteValue = {
  type: "node",
  ? sharedId: script.SharedId,
  ? handle: script.Handle,
  ? internalId: script.InternalId,
  ? value: script.NodeProperties,
}

script.NodeProperties = {
  nodeType: js-uint,
  childNodeCount: js-uint,
  ? attributes: {*text => text},
  ? children: [*script.NodeRemoteValue],
  ? localName: text,
  ? mode: "open" / "closed",
  ? namespaceURI: text,
  ? nodeValue: text,
  ? shadowRoot: script.NodeRemoteValue / null,
}

script.WindowProxyRemoteValue = {
  type: "window",
  value: script.WindowProxyProperties,
  ? handle: script.Handle,
  ? internalId: script.InternalId
}

script.WindowProxyProperties = {
  context: browsingContext.BrowsingContext
}

添加 WASM 类型?

WindowProxy 是否应该以类似 Node 的样式 获取属性?

是否要特殊处理 String / Number / 等包装器对象?

可从 ECMAScript 运行时访问的值由一个镜像对象表示, 其指定为 script.RemoteValue。值的类型由 type 属性指定。对于可用 JSON 表示的 原始值,它会在 value 属性中包含该值;对于 不可用 JSON 表示的原始值,value 属性 包含该值的字符串表示。

对于非原始对象,handle 属性在存在时 包含指向该对象的唯一字符串 handle。该 handle 对于每次 序列化都是唯一的。远端会让具有对应 handle 的对象 保持存活,直到以该 handle 调用 script.disown, 或 realm 本身将被丢弃(例如由于导航)。

对于某些非原始类型,value 属性包含 ECMAScript 对象中数据的表示;对于容器类型,这 可以包含更多 script.RemoteValue 实例。 如果存在重复对象,即该对象已经在当前 script.RemoteValue 中被序列化过(也许作为循环的一部分), 或者在达到最大序列化深度时,value 属性可以为 null 或被省略。

在同一 script.RemoteValue 中存在重复对象的情况下, 只为其中一个 remote value 提供 value,而 对于给定序列化中的所有重复对象,都会提供按 ECMAScript 对象唯一的 internalId。

Nodes 也由 script.RemoteValue 实例表示。它们在 value 属性中具有 node 的部分序列化。

重新考虑镜像对象的 生命周期。

注:镜像对象不会让运行时中的原始对象 保持存活。如果某个对象在运行时中被丢弃,随后尝试通过 协议访问它将导致错误。

要在给定 realm、ownership type 和 object 时,获取对象的 handle:
  1. 如果 ownership type 等于 "none",返回 null。

  2. 令 handle id 为 object 的新的、唯一的字符串 handle。

  3. 令 handle map 为 realm 的 handle object map

  4. 将 handle map[handle id] 设置为 object。

  5. 返回 handle id 作为结果。

要在给定 node 和 session 时获取 node 的 shared id:
  1. 令 node 为解包装的 node。

  2. 如果 node 未实现 Node, 返回 null。

  3. 令 navigable 为 node 的 node navigable。

  4. 如果 navigable 为 null,返回 null。

  5. 返回以 session、navigable 和 node 调用获取或创建 node 引用的结果。

要在给定 serialization internal map、 remote value 和 object 时必要时设置 internal ids:
  1. 如果 serialization internal map 不包含 object,则将 serialization internal map[object] 设置为 remote value。

  2. 否则,运行以下步骤:

    1. 令 previously serialized remote value 为 serialization internal map[object]。

    2. 如果 previously serialized remote value 没有 internalId 字段,则运行以下步骤:

      1. 令 internal id 为基于真正随机或伪随机数字的 UUID 的字符串表示。

      2. 将 previously serialized remote value 的 internalId 字段设置为 internal id。

    3. 将 remote value 的 internalId 字段设置为 previously serialized remote value 中的 internalId 字段。

要在给定 value、serialization options、 一个 ownership type、一个 serialization internal map、一个 realm 和一个 session 的情况下,序列化 为远程值:

  1. 令 remote value 为在给定 value 的情况下序列化原始协议值的结果。

  2. 如果 remote value 不是 undefined,则返回 remote value。

  3. 令 handle id 为使用 realm、 ownership type 和 value 对象的句柄。

  4. 将 ownership type 设为 "none"。

  5. 如果 value 在 serialization internal map 中,则令 known object 为 true,否则为 false。

  6. 在以下条件及关联步骤列表中,运行首个 关联条件为 true 的步骤集:

    Type(value) 为 Symbol
    令 remote value 为一个匹配 本地端定义中 script.SymbolRemoteValue 产生式的映射, 如果 handle id 不为 null,则将 handle 属性设为 handle id;否则省略该属性。
    IsArray(value)
    令 remote value 为使用 session、 script.ArrayRemoteValue、handle id、known object、 value、 serialization options、ownership type、serialization internal map、 realm 和 session 序列化类数组对象的结果。
    IsRegExp(value)
    1. 令 pattern 为 ToString(Get(value, "source"))。

    2. 令 flags 为 ToString(Get(value, "flags"))。

    3. 令 serialized 为一个匹配 本地端定义中 script.RegExpValue 产生式的映射, 其 pattern 属性设为 pattern,且 flags 属性设为 flags。

    4. 令 remote value 为一个匹配 本地端定义中 script.RegExpRemoteValue 产生式的映射, 如果 handle id 不为 null,则将 handle 属性设为 handle id;否则省略该属性,并且 value 属性设为 serialized。

    value 具有 [[DateValue]] 内部槽。
    1. 将 serialized 设为 Call(Date.prototype.toISOString, value)。

    2. 断言:serialized 不是抛出完成。

    3. 令 remote value 为一个匹配 本地端定义中 script.DateRemoteValue 产生式的映射, 如果 handle id 不为 null,则将 handle 属性设为 handle id;否则省略该属性,并且 值设为 serialized。

    value 具有 [[MapData]] 内部槽
    1. 令 remote value 为一个匹配 本地端定义中 script.MapRemoteValue 产生式的映射, 如果 handle id 不为 null,则将 handle 属性设为 handle id;否则 省略该属性。

    2. 使用 serialization internal map、 remote value 和 value 按需设置内部 ID。

    3. 令 serialized 为 null。

    4. 如果 known object 为 false,且 serialization options["maxObjectDepth"] 不为 0,则运行以下 步骤:

      1. 令 serialized 为使用 CreateMapIterator(value, key+value)、serialization options、 ownership type、serialization internal map、 realm 和 session 序列化为映射的结果。

    5. 如果 serialized 不为 null,则将 remote value 的字段 value 设为 serialized。

    value 具有 [[SetData]] 内部槽
    1. 令 remote value 为一个匹配 本地端定义中 script.SetRemoteValue 产生式的映射, 如果 handle id 不为 null,则将 handle 属性设为 handle id;否则 省略该属性。

    2. 使用 serialization internal map、 remote value 和 value 按需设置内部 ID。

    3. 令 serialized 为 null。

    4. 如果 known object 为 false,且 serialization options["maxObjectDepth"] 不为 0,则运行以下 步骤:

      1. 令 serialized 为使用 CreateSetIterator(value, value)、serialization options、 ownership type、serialization internal map、 realm 和 session 序列化为列表的结果。

    5. 如果 serialized 不为 null,则将 remote value 的字段 value 设为 serialized。

    value 具有 [[WeakMapData]] 内部槽
    令 remote value 为一个匹配 本地端定义中 script.WeakMapRemoteValue 产生式的映射, 如果 handle id 不为 null,则将 handle 属性设为 handle id;否则省略该属性。
    value 具有 [[WeakSetData]] 内部槽
    令 remote value 为一个匹配 本地端定义中 script.WeakSetRemoteValue 产生式的映射, 如果 handle id 不为 null,则将 handle 属性设为 handle id;否则省略该属性。
    value 具有 [[GeneratorState]] 内部槽或 [[AsyncGeneratorState]] 内部槽
    令 remote value 为一个匹配 本地端定义中 script.GeneratorRemoteValue 产生式的映射, 如果 handle id 不为 null,则将 handle 属性设为 handle id;否则省略该属性。
    value 具有 [[ErrorData]] 内部槽
    令 remote value 为一个匹配 本地端定义中 script.ErrorRemoteValue 产生式的映射, 如果 handle id 不为 null,则将 handle 属性设为 handle id;否则省略该属性。
    value 具有 [[ProxyHandler]] 内部槽和 [[ProxyTarget]] 内部槽
    令 remote value 为一个匹配 本地端定义中 script.ProxyRemoteValue 产生式的映射, 如果 handle id 不为 null,则将 handle 属性设为 handle id;否则省略该属性。
    IsPromise(value)
    令 remote value 为一个匹配 本地端定义中 script.PromiseRemoteValue 产生式的映射, 如果 handle id 不为 null,则将 handle 属性设为 handle id;否则省略该属性。
    value 具有 [[TypedArrayName]] 内部槽
    令 remote value 为一个匹配 本地端定义中 script.TypedArrayRemoteValue 产生式的映射, 如果 handle id 不为 null,则将 handle 属性设为 handle id;否则省略该属性。
    value 具有 [[ArrayBufferData]] 内部槽
    令 remote value 为一个匹配 本地端定义中 script.ArrayBufferRemoteValue 产生式的映射, 如果 handle id 不为 null,则将 handle 属性设为 handle id;否则省略该属性。
    value 是实现 NodeList 的平台对象
    令 remote value 为使用 script.NodeListRemoteValue、handle id、known object、 value、 serialization options、ownership type、serialization internal map、 realm 和 session 序列化类数组对象的结果。
    value 是实现 HTMLCollection 的平台对象
    令 remote value 为使用 script.HTMLCollectionRemoteValue、handle id、known object、value、 serialization options、ownership type、known object、 serialization internal map、 realm 和 session 序列化类数组对象的结果。
    value 是实现 Node 的平台对象
    1. 令 shared id 为使用 value 和 session 获取 节点的共享 ID。

    2. 令 remote value 为一个匹配 本地端定义中 script.NodeRemoteValue 产生式的映射, 如果 shared id 不为 null,则将 sharedId 属性设为 shared id;否则省略该属性,并且 如果 handle id 不为 null,则将 handle 属性设为 handle id;否则 省略该属性。

    3. 使用 serialization internal map、 remote value 和 value 按需设置内部 ID。

    4. 令 serialized 为 null。

    5. 如果 known object 为 false,则运行以下步骤:

      1. 令 serialized 为一个映射。

      2. 将 serialized["nodeType"] 设为 Get(value, "nodeType")。

      3. 将 node value 设为 Get(value, "nodeValue")。

      4. 如果 node value 不为 null,则将 serialized["nodeValue"] 设为 node value。

      5. 如果 value 实现 Element 或 Attr:

        1. 将 serialized["localName"] 设为 Get(value, "localName")。

        2. 将 serialized["namespaceURI"] 设为 Get(value, "namespaceURI")

      6. 令 child node count 为 value 的子节点的大小。

      7. 将 serialized["childNodeCount"] 设为 child node count。

      8. 如果 serialization options["maxDomDepth"] 等于 0,或者如果 value 实现 ShadowRoot 且 serialization options["includeShadowTree"] 为 "none", 或者如果 serialization options["includeShadowTree"] 为 "open" 且 value 的模式为 "closed",则令 children 为 null。

        否则,令 children 为空列表,并且对于 value 的子节点中的每个节点 child:

        1. 令 child serialization options 为 serialization options 的克隆。

        2. 如果 child serialization options["maxDomDepth"] 不为 null,则将 child serialization options["maxDomDepth"] 设为 child serialization options["maxDomDepth"] - 1。

        3. 令 serialized 为使用 child、child serialization options、 ownership type、 serialization internal map、realm 和 session 序列化为 远程值的结果。

        4. 将 serialized 追加到 children。

      9. 如果 children 不为 null,则将 serialized["children"] 设为 children。

      10. 如果 value 实现 Element:

        1. 令 attributes 为新的映射。

        2. 对于 value 的属性列表中的每个 attribute:

          1. 令 name 为 attribute 的限定 名称

          2. 令 value 为 attribute 的值。

          3. 将 attributes[name] 设为 value

        3. 将 serialized["attributes"] 设为 attributes。

        4. 令 shadow root 为 value 的影子根。

        5. 如果 shadow root 为 null,则令 serialized shadow 为 null。 否则运行以下子步骤:

          1. 令 serialized shadow 为使用 shadow root、 serialization options、ownership type、serialization internal map、 realm 和 session 序列化 为远程值的结果。

        6. 将 serialized["shadowRoot"] 设为 serialized shadow。

      11. 如果 value 实现 ShadowRoot, 则将 serialized["mode"] 设为 value 的模式。

    6. 如果 serialized 不为 null,则将 remote value 的字段 value 设为 serialized。

    value 是实现 WindowProxy 的平台对象
    1. 令 window 为 value 的 [[WindowProxy]] 内部 槽的值。

    2. 令 navigable 为 window 的可导航。

    3. 令 navigable id 为 navigable 的可导航 ID。

    4. 令 serialized 为一个匹配 本地端定义中 script.WindowProxyProperties 产生式的映射, 其 context 属性设为 navigable id。

    5. 令 remote value 为一个匹配 本地端定义中 script.WindowProxyRemoteValue 产生式的映射, 如果 handle id 不为 null,则将 handle 属性设为 handle id;否则省略该属性,并且 value 属性设为 serialized。

    value 是平台对象
    1. 令 remote value 为一个匹配 本地端定义中 script.ObjectRemoteValue 产生式的映射, 如果 handle id 不为 null,则将 handle 属性设为 handle id;否则省略该属性。
    IsCallable(value)
    令 remote value 为一个匹配 本地端定义中 script.FunctionRemoteValue 产生式的映射, 如果 handle id 不为 null,则将 handle 属性设为 handle id;否则省略该属性。
    否则:
    1. 断言:Type(value) 为 Object

    2. 令 remote value 为一个匹配 本地端定义中 script.ObjectRemoteValue 产生式的映射, 如果 handle id 不为 null,则将 handle 属性 设为 handle id;否则省略该属性。

    3. 使用 serialization internal map、 remote value 和 value 按需设置内部 ID。

    4. 令 serialized 为 null。

    5. 如果 known object 为 false,且 serialization options["maxObjectDepth"] 不为 0,则运行以下 步骤:

      1. 令 serialized 为使用 序列化为映射对 EnumerableOwnPropertyNames(value, key+value)、serialization options、 ownership type、serialization internal map、 realm 和 session 执行所得的结果。

    6. 如果 serialized 不为 null,则将 remote value 的字段 value 设为 serialized。

  7. 返回 remote value

children 和子节点是不同的东西。childNodeCount 要么应当 引用 childNodes,要么应当重命名为 childrenCount。

要在给定 production、handle id、known object、 value、serialization options、ownership type、serialization internal map、realm 和 session 时序列化 Array-like:
  1. 令 remote value 为一个映射, 其匹配 production,并将 handle 属性设置为 handle id(如果它不为 null),否则省略。

  2. 以 serialization internal map、 remote value 和 value 调用必要时设置 internal ids。

  3. 如果 known object 为 false,且 serialization options["maxObjectDepth"] 不为 0:

    1. 令 serialized 为以 CreateArrayIterator(value, value)、serialization options、ownership type、 serialization internal map、realm 和 session 调用序列化为 list的结果。

    2. 如果 serialized 不为 null,则将 remote value 的字段 value 设置为 serialized。

  4. 返回 remote value

要在给定 iterable、serialization options、ownership type、 serialization internal map、realm 和 session 时序列化为 list:
  1. 如果 serialization options["maxObjectDepth"] 不为 null, 断言:serialization options["maxObjectDepth"] 大于 0。

  2. 令 serialized 为一个新列表。

  3. 对于 IteratorToList(GetIterator(iterable, sync)) 中的每个 child value:

    1. 令 child serialization options 为 serialization options 的克隆。

    2. 如果 child serialization options["maxObjectDepth"] 不为 null,则将 child serialization options["maxObjectDepth"] 设置为 child serialization options["maxObjectDepth"] - 1。

    3. 令 serialized child 为以 child value、child serialization options、ownership type、 serialization internal map、realm 和 session 调用序列化为 remote value的结果。

    4. 将 serialized child 追加到 serialized。

  4. 返回 serialized

要在给定 iterable、serialization options、 ownership type、serialization internal map、realm 和 session 时序列化为 mapping:

  1. 如果 serialization options["maxObjectDepth"] 不为 null, 断言:serialization options["maxObjectDepth"] 大于 0。

  2. 令 serialized 为一个新列表。

  3. 对于 IteratorToList(GetIterator(iterable, sync)) 中的 item:

    1. 断言:IsArray(item)

    2. 令 property 为 CreateListFromArrayLike(item)

    3. 断言:property 是一个大小为 2 的列表

    4. 令 key 为 property[0],令 value 为 property[1]

    5. 令 child serialization options 为 serialization options 的克隆。

    6. 如果 child serialization options["maxObjectDepth"] 不为 null,则将 child serialization options["maxObjectDepth"] 设置为 child serialization options["maxObjectDepth"] - 1。

    7. 如果 Type(key) is String,则令 serialized key 为 child key, 否则令 serialized key 为以 child key、child serialization options、ownership type、 serialization internal map、realm 和 session 调用序列化为 remote value的结果。

    8. 令 serialized value 为以 value、child serialization options、ownership type、 serialization internal map、realm 和 session 调用序列化为 remote value的结果。

    9. 令 serialized child 为(«serialized key, serialized value»)。

    10. 将 serialized child 追加到 serialized。

  4. 返回 serialized

7.6.3.15. script.ResultOwnership 类型
script.ResultOwnership = "root" / "none"

script.ResultOwnership 指定如何处理已序列化值的 所有权。

7.6.3.16. script.SerializationOptions 类型

远程端定义

script.SerializationOptions = {
  ? maxDomDepth: (js-uint / null) .default 0,
  ? maxObjectDepth: (js-uint / null) .default null,
  ? includeShadowTree: ("none" / "open" / "all") .default "none",
}

script.SerializationOptions 允许指定 ECMAScript 对象将如何被序列化。

7.6.3.17. script.SharedId 类型

远程端定义 和 本地端定义

script.SharedId = text;

script.SharedId 类型表示对 DOM Node 的引用,该引用 可在任何 realm 中使用(包括 Sandbox Realms)。

7.6.3.18. script.StackFrame 类型

远程端定义 和 本地端定义

script.StackFrame = {
  columnNumber: js-uint,
  functionName: text,
  lineNumber: js-uint,
  url: text,
}

堆栈跟踪中的帧由一个 StackFrame 对象表示。它具有 url 属性,表示 脚本的 URL;具有 functionName 属性,表示正在 执行的函数的名称;并具有 lineNumber 和 columnNumber 属性,表示被执行代码的行号和列号。

7.6.3.19. script.StackTrace 类型

远程端定义 和 本地端定义

script.StackTrace = {
  callFrames: [*script.StackFrame],
}

script.StackTrace 类型表示脚本执行中某一点处的 JavaScript 堆栈。

注:关于如何获取堆栈帧列表的细节, 以及该列表的属性 规定不足,因此这里的细节由实现定义。

假定实现能够生成堆栈 帧列表,它是一个列表,其中每一项对应 JavaScript 调用堆栈中的每个条目,从最近的开始。每个条目都是一个单个堆栈 帧,对应于脚本 script 中语句或表达式的执行,并包含以下字段:

脚本 URL
包含 script 的资源的 URL
函数
正在执行的函数的名称
行号
被执行代码的从零开始的行号,相对于包含 script 的资源顶部。
列号
被执行代码的从零开始的列号,相对于 包含 script 的资源中该行的起始位置。

要使用堆栈帧列表 stack 构造 堆栈跟踪:

  1. 令 call frames 为一个新列表。

  2. 对于 stack 中从最近执行的帧开始的每个堆栈帧 frame, 运行以下步骤:

    1. 令 url 为在给定 frame 的脚本 URL的 URL 时,运行 URL 序列化器的结果。

    2. 令 frame info 为一个新的映射,其匹配 script.StackFrame 产生式,其中 url 字段设为 url, functionName 字段设为 frame 的函数, lineNumber 字段设为 frame 的行号, 且 columnNumber 字段设为 frame 的 列号。

  3. 将 frame info 追加到 call frames。

  4. 令 stack trace 为一个新的映射, 其匹配 script.StackTrace 产生式,其中 callFrames 属性设为 call frames。

  5. 返回 stack trace。

当前堆栈 跟踪 是在给定表示正在运行的 执行上下文的调用堆栈的堆栈 帧列表时,构造堆栈跟踪的结果。

带有异常或类型为 throw 的 Completion Record exception 的异常的堆栈 跟踪,由以下给出:

  1. 如果 exception 是作为异常被抛出的值,则令 record 为为抛出 exception 而创建的 Completion Record。否则令 record 为 exception。

  2. 令 stack 为与 创建 record 时所在点的执行相对应的堆栈帧列表。

  3. 返回在给定 stack 的情况下构造堆栈跟踪的结果。

7.6.3.20. script.Source 类型

本地端定义

script.Source = {
  realm: script.Realm,
  ? context: browsingContext.BrowsingContext,
  ? userContext: browser.UserContext
}

script.Source 类型表示一个 script.Realm, 以及可选的 browsingContext.BrowsingContext 和相关的 browser.UserContext,脚本相关事件在其中发生。

给定 source realm,要获取源:
  1. 令 realm 为 source realm 的Realm ID。

  2. 令 environment settings 为这样一个环境设置对象,其 Realm 执行上下文的 Realm 组件为 source realm。

  3. 如果 environment settings 有一个关联的 Document:

    1. 令 document 为 environment settings 的关联的 Document。

    2. 令 navigable 为 document 的节点可导航对象。

    3. 如果 navigable 不为 null,则令 navigable id 为 navigable 的可导航对象 ID。

    4. 令 user context id 为 navigable 的关联用户上下文的用户上下文 ID。

    否则令 navigable 为 null。

  4. 令 source 为一个与 script.Source 产生式匹配的映射,其中 realm 字段设置为 realm,如果 navigable 不为 null,则将 context 字段设置 为 navigable id,否则不设置, 并且如果 |navigable 不为 null,则将 userContext 字段设置为 user context id,否则不设置。

  5. 返回 source。

7.6.3.21. script.Target 类型

远程端定义

script.RealmTarget = {
  realm: script.Realm
}

script.ContextTarget = {
  context: browsingContext.BrowsingContext,
  ? sandbox: text
}

script.Target = (
  script.ContextTarget /
  script.RealmTarget
)

script.Target 类型表示一个要么是 script.Realm,要么是 browsingContext.BrowsingContext 的值。 这在可导航标识符可以代表与该可导航的活动文档 关联的 realm 的情况下很有用。

给定 navigable id 和 sandbox,要从可导航对象获取领域:
  1. 令 navigable 为尝试使用 navigable id 获取 可导航对象的结果。

  2. 如果 sandbox 为 null 或为空字符串:

    1. 令 document 为 navigable 的活动文档。

    2. 令 environment settings 为这样的环境设置对象,其 相关全局对象的关联的 Document 为 document。

    3. 令 realm 为 environment settings 的领域执行上下文的 Realm 组件。

  3. 否则:令 realm 为尝试给定 sandbox 和 navigable 获取或创建沙盒领域的结果。

  4. 返回带有数据 realm 的成功

此处的 错误代码不正确

给定 target,要从目标 获取领域:
  1. 如果 target 与 script.ContextTarget 产生式匹配:

    1. 令 sandbox 为 null。

    2. 如果 target 包含 "sandbox",则将 sandbox 设置为 target["sandbox"]。

    3. 令 realm 为使用 target["context"] 和 sandbox 从可导航对象获取领域的结果。

  2. 否则:

    1. 断言:target 与 script.RealmTarget 产生式匹配。

    2. 令 realm id 为 target 的 realm 字段的值。

    3. 令 realm 为给定 realm id 时获取领域的结果。

  3. 返回带有数据 realm 的成功

此处的 错误代码不正确

7.6.4. 命令

7.6.4.1. script.addPreloadScript 命令

script.addPreloadScript 命令添加一个预加载脚本。

命令类型
script.AddPreloadScript = (
  method: "script.addPreloadScript",
  params: script.AddPreloadScriptParameters
)

script.AddPreloadScriptParameters = {
  functionDeclaration: text,
  ? arguments: [*script.ChannelValue],
  ? contexts: [+browsingContext.BrowsingContext],
  ? userContexts: [+browser.UserContext],
  ? sandbox: text
}
返回类型
script.AddPreloadScriptResult = {
  script: script.PreloadScript
}
给定 session 和 command parameters 时,远端步骤如下:
  1. 如果 command parameters 包含 "userContexts" 且 command parameters 包含 "contexts", 则返回带有错误,其错误 代码为无效参数。

  2. 令 function declaration 为 command parameters 的 functionDeclaration 字段。

  3. 如果 command parameters 的 arguments 字段存在,则令 arguments 为该字段,否则为空列表。

  4. 令 user contexts 为一个集合。

  5. 令 navigables 为 null。

  6. 如果 command parameters 的 contexts 字段存在:

    1. 将 navigables 设置为一个空集合。

    2. 对于 command parameters["contexts"] 中的每个 navigable id

      1. 令 navigable 为尝试使用 navigable id 获取可导航对象 的结果。

      2. 如果 navigable 不是顶层可遍历对象,则返回带有错误,其错误代码为无效参数。

      3. 将 navigable 追加到 navigables。

  7. 否则,如果 command parameters 包含 userContexts:

    1. 将 user contexts 设置为使用 command parameters["userContexts"] 创建 集合的结果。

    2. 对于 user contexts 中的每个 user context id:

      1. 将 user context 设置为使用 user context id 获取用户上下文的结果。

      2. 如果 user context 为 null,则返回带有错误,其错误代码为无此用户上下文。

  8. 如果 command parameters 中存在 "sandbox" 字段,则令 sandbox 为该字段的值,否则为 null。

  9. 令 script 为一个UUID 的字符串表示形式。

  10. 令 preload script map 为 session 的预加载脚本映射。

  11. 将 preload script map[script] 设置为一个结构体,其中 function declaration 为 function declaration, arguments 为 arguments, contexts 为 navigables, sandbox 为 sandbox,且 user contexts 为 user contexts。

  12. 返回一个与 script.AddPreloadScriptResult 匹配的新映射,其中 script 字段设置为 script。

7.6.4.2. script.disown 命令

script.disown 命令解除对给定句柄的拥有。 这并不保证被句柄引用的对象会被垃圾收集,因为可能存在 其他句柄或强 ECMAScript 引用。

命令类型
script.Disown = (
  method: "script.disown",
  params: script.DisownParameters
)

script.DisownParameters = {
  handles: [*script.Handle]
  target: script.Target;
}
返回类型
script.DisownResult = EmptyResult
使用 command parameters 时的远端步骤如下:
  1. 令 realm 为尝试给定 command parameters 的 target 字段的值从目标获取领域 的结果。

  2. 令 handles 为 command parameters 的 handles 字段的值。

  3. 对于 handles 中的每个 handle id:

    1. 令 handle map 为 realm 的句柄对象映射

    2. 如果 handle map 包含 handle id,则从 handle map 中移除 handle id。

  4. 返回带有数据 null 的成功。

7.6.4.3. script.callFunction 命令

script.callFunction 命令在给定 realm 中使用给定实参调用提供的 函数。

RealmInfo 可以是 realm 或可导航。

注:在 functionDeclaration 中是箭头函数的情况下, this 实参不会影响函数的 this 绑定。

命令类型
script.CallFunction = (
  method: "script.callFunction",
  params: script.CallFunctionParameters
)

script.CallFunctionParameters = {
  functionDeclaration: text,
  awaitPromise: bool,
  target: script.Target,
  ? arguments: [*script.LocalValue],
  ? resultOwnership: script.ResultOwnership,
  ? serializationOptions: script.SerializationOptions,
  ? this: script.LocalValue,
  ? userActivation: bool .default false,
}
返回类型
script.CallFunctionResult = script.EvaluationResult

TODO:添加 timeout 实参, 如 script.evaluate 中所述。

给定 realm、serialized arguments list 和 session,要反序列化 参数:

  1. 令 deserialized arguments list 为一个空列表。

  2. 对于 serialized arguments list 中的每个 serialized argument:

    1. 令 deserialized argument 为尝试给定 serialized argument、realm 和 session 反序列化本地值的结果。

    2. 将 deserialized argument 追加到 deserialized arguments list。

  3. 返回带有数据 deserialized arguments list 的成功。

给定 function declaration、 environment settings、base URL 和 options,要求值函数 主体:

注:function declaration 会 被括在圆括号中并进行求值。

  1. 令 bypassDisabledScripting 为 true。

  2. 令 parenthesized function declaration 为连接 «"(", function declaration, ")"»

  3. 令 function script 为使用 parenthesized function declaration、environment settings、base URL、 options 和 bypassDisabledScripting 创建经典脚本的结果。

  4. 使用 environment settings 准备运行脚本。

  5. 令 function body evaluation status 为 ScriptEvaluation(function script 的记录)。

  6. 使用 environment settings 运行脚本后清理。

  7. 返回 function body evaluation status。

使用 session 和 command parameters 时的远端步骤如下:

  1. 令 realm 为尝试给定 command parameters 的 target 字段的值从目标获取领域 的结果。

  2. 令 realm id 为 realm 的领域 id。

  3. 令 environment settings 为其 领域执行上下文的 Realm 组件为 realm 的环境设置对象。

  4. 令 command arguments 为 command parameters 的 arguments 字段 的值。

  5. 令 deserialized arguments 为一个空列表。

  6. 如果 command arguments 不为 null,则将 deserialized arguments 设置为 尝试给定 realm、 command arguments 和 session 反序列化参数的结果。

  7. 令 this parameter 为 command parameters 的 this 字段 的值。

  8. 令 this object 为 null。

  9. 如果 this parameter 不为 null,则将 this object 设置为尝试给定 this parameter、realm 和 session 反序列化本地值的结果。

  10. 令 function declaration 为 command parameters 的 functionDeclaration 字段的值。

  11. 令 await promise 为 command parameters 的 awaitPromise 字段的值。

  12. 如果 command parameters 的 serializationOptions 字段存在,则令 serialization options 为该字段的值, 否则为一个与 script.SerializationOptions 产生式匹配且各字段设置为其默认值的映射。

  13. 如果 command parameters 的 resultOwnership 字段存在,则令 result ownership 为该字段的值,否则为 none。

  14. 令 base URL 为 environment settings 的API 基础 URL。

  15. 令 options 为默认脚本获取选项。

  16. 令 function body evaluation status 为使用 function declaration、 environment settings、base URL 和 options 求值函数主体的结果。

  17. 如果 function body evaluation status.[[Type]] 为 throw:

    1. 令 exception details 为给定 realm、function body evaluation status、result ownership 和 session 时获取异常 详细信息的结果。

    2. 返回一个与 script.EvaluationResultException 产生式匹配的新映射,其中 exceptionDetails 字段设置为 exception details。

  18. 令 function object 为 function body evaluation status.[[Value]]。

  19. 如果 IsCallable(function object) 为 false:

    1. 返回带有错误,其错误代码为无效参数

  20. 如果 command parameters["userActivation"] 为 true,则运行激活通知步骤。

  21. 使用 environment settings 准备运行脚本。

  22. 将 evaluation status 设置为 Call(function object, this object, deserialized arguments)。

  23. 如果 evaluation status.[[Type]] 为 normal,且 await promise 为 true,且 IsPromise(evaluation status.[[Value]]):

    1. 将 evaluation status 设置为 Await(evaluation status.[[Value]])。

  24. 使用 environment settings 运行脚本后清理。

  25. 如果 evaluation status.[[Type]] 为 throw:

    1. 令 exception details 为给定 realm、evaluation status、result ownership 和 session 时获取异常 详细信息的结果。

    2. 返回一个与 script.EvaluationResultException 产生式匹配的新映射,其中 exceptionDetails 字段设置为 exception details。

  26. 断言:evaluation status.[[Type]] 为 normal。

  27. 令 result 为使用 evaluation status.[[Value]]、serialization options、result ownership、 一个新的映射作为序列化内部映射、realm 和 session 序列化为 远程值的结果。

  28. 返回一个与 script.EvaluationResultSuccess 产生式匹配的新映射,其中 realm 字段设置为 realm id, 且 result 字段设置为 result。

7.6.4.4. script.evaluate 命令

script.evaluate 命令会在给定 realm 中求值所提供的 script。为方便起见,可以提供一个 navigable 来代替 realm;在这种情况下, 所使用的 realm 是该 browsing context 的 active document 的 realm。

该方法返回执行所提供 script 的值,除非它返回一个 promise 且 awaitPromise 为 true,在这种情况下会返回该 promise 的已解决值。

命令类型
script.Evaluate = (
  method: "script.evaluate",
  params: script.EvaluateParameters
)

script.EvaluateParameters = {
  expression: text,
  target: script.Target,
  awaitPromise: bool,
  ? resultOwnership: script.ResultOwnership,
  ? serializationOptions: script.SerializationOptions,
  ? userActivation: bool .default false,
}
返回类型
script.EvaluateResult = script.EvaluationResult

TODO:添加 timeout 参数。尚不完全清楚这应该如何工作;在 Chrome 中,timeout 似乎并不适用于 promise resolve 步骤,但 这可能并不是客户端想要的行为。

给定 session 和 command parameters 的远端步骤为:

  1. 令 realm 为尝试从目标获取 Realm (给定 command parameters 的 target 字段的值)所得的结果。

  2. 令 realm id 为 realm 的Realm ID。

  3. 令 environment settings 为这样一个环境设置对象,其 Realm 执行上下文的 Realm 组件为 realm。

  4. 令 source 为 command parameters 的 expression 字段的值。

  5. 令 await promise 为 command parameters 的 awaitPromise 字段的值。

  6. 如果存在,则令 serialization options 为 command parameters 的 serializationOptions 字段的值, 否则为一个与 script.SerializationOptions 产生式匹配且各字段均设置为其默认值的映射。

  7. 如果存在,则令 result ownership 为 command parameters 的 resultOwnership 字段的值,否则为 none。

  8. 令 options 为默认脚本获取选项。

  9. 令 base URL 为 environment settings 的API 基础 URL。

  10. 令 bypassDisabledScripting 为 true。

  11. 令 script 为使用 source、 environment settings、base URL、options 和 bypassDisabledScripting 创建经典脚本所得的结果。

  12. 如果 command parameters["userActivation"] 为 true,则运行激活通知步骤。

  13. 使用 environment settings 准备运行脚本。

  14. 将 evaluation status 设置为 ScriptEvaluation(script 的 record)。

  15. 如果 evaluation status.[[Type]] 为 normal,await promise 为 true,并且 IsPromise(evaluation status.[[Value]]):

    1. 将 evaluation status 设置为 Await(evaluation status.[[Value]])。

  16. 使用 environment settings 运行脚本后清理。

  17. 如果 evaluation status.[[Type]] 为 throw:

    1. 令 exception details 为使用 realm、evaluation status、result ownership 和 session 获取异常 详细信息所得的结果。

    2. 返回一个与 script.EvaluationResultException 产生式匹配的新映射,其中 realm 字段设置为 realm id,并且 exceptionDetails 字段设置为 exception details。

  18. 断言:evaluation status.[[Type]] 为 normal。

  19. 令 result 为使用 evaluation status.[[Value]]、serialization options、result ownership、 一个新的映射作为序列化内部映射、realm 和 session 序列化为 远程值所得的结果。

  20. 返回一个与 script.EvaluationResultSuccess 产生式匹配的新映射,其中 realm 字段设置为 realm id,并且 result 字段设置为 result。

7.6.4.5. script.getRealms 命令

script.getRealms 命令返回 所有领域的列表,可选择将其筛选为特定类型的领域,或筛选为与某个可导航对象的活动文档关联的领域。

命令类型
script.GetRealms = (
  method: "script.getRealms",
  params: script.GetRealmsParameters
)

script.GetRealmsParameters = {
  ? context: browsingContext.BrowsingContext,
  ? type: script.RealmType,
}
返回类型
script.GetRealmsResult = {
  realms: [*script.RealmInfo]
}
使用 session 和 command parameters 时的远端步骤如下:
  1. 令 environment settings 为所有其执行就绪标志已设置的环境设置对象组成的列表。

  2. 如果 command parameters 包含 context:

    1. 令 navigable 为尝试使用 command parameters["context"] 获取 可导航对象 的结果。

    2. 令 document 为 navigable 的活动文档。

    3. 令 navigable environment settings 为一个列表。

    4. 对于 environment settings 中的每个 settings:

      1. 如果满足以下任一条件:

        将 settings 追加到 navigable environment settings。

    5. 将 environment settings 设置为 navigable environment settings。

  3. 令 realms 为一个列表。

  4. 对于 environment settings 中的每个 settings:

    1. 令 realm info 为给定 settings 时获取领域信息 的结果。

    2. 如果 command parameters 包含 type,且 realm info["type"] 不等于 command parameters["type"],则继续。

    3. 如果 realm info 不为 null,则将 realm info 追加到 realms。

  5. 令 body 为一个与 script.GetRealmsResult 产生式匹配的映射, 其中 realms 字段设置为 realms。

  6. 返回带有数据 body 的成功。

是否还要扩展为 允许领域父级,例如用于嵌套 worker?或者获取所有祖先 worker。

我们可能希望采用 比简单的字面匹配更复杂的筛选系统。

7.6.4.6. script.removePreloadScript 命令

script.removePreloadScript 命令移除一个 预加载脚本。

命令类型
script.RemovePreloadScript = (
  method: "script.removePreloadScript",
  params: script.RemovePreloadScriptParameters
)

script.RemovePreloadScriptParameters = {
  script: script.PreloadScript
}
返回类型
script.RemovePreloadScriptResult = EmptyResult
给定 session 和 command parameters 时,远端步骤如下:
  1. 令 script 为 command parameters 中 "script" 字段的值。

  2. 令 preload script map 为 session 的预加载脚本映射。

  3. 如果 preload script map 不包含 script,则返回 带有错误,其错误 代码为无此脚本。

  4. 从 preload script map 中移除 script。

  5. 返回 null

7.6.5. 事件

7.6.5.1. script.message 事件
事件类型
script.Message = (
  method: "script.message",
  params: script.MessageParameters
 )

script.MessageParameters = {
  channel: script.Channel,
  data: script.RemoteValue,
  source: script.Source,
}
给定 session、realm、channel properties 和 message 时, 远端事件触发器是发出脚本 消息步骤:
  1. 令 environment settings 为其 领域执行上下文的 Realm 组件为 realm 的环境设置对象。

  2. 令 related navigables 为给定 environment settings 时获取相关 可导航对象的结果。

  3. 如果给定 session、"script.message" 和 related navigables 时事件已 启用:

    1. 如果 channel properties 包含 "serializationOptions",则令 serialization options 为 channel properties 的 serializationOptions 字段的值。否则,令 serialization options 为一个与 script.SerializationOptions 产生式匹配且各 字段设置为其默认值的映射。

    2. 令如果 channel properties 包含 "ownership",则令 ownership type 为 channel properties["ownership"]。 否则,令 ownership type 为 "none"。

    3. 令 data 为给定 message、serialization options、ownership type、一个新的 映射作为序列化 内部映射以及 realm 时序列化为远程值的结果。

    4. 令 source 为使用 realm 获取源的结果。

    5. 令 params 为一个与 script.MessageParameters 产生式匹配的映射,其中 channel 字段设置为 channel properties["channel"], data 字段设置为 data,且 source 字段设置为 source。

    6. 令 body 为一个与 script.Message 产生式匹配的映射,其中 params 字段设置为 params。

    7. 使用 session 和 body 发出 事件。

7.6.5.2. script.realmCreated 事件
事件类型
script.RealmCreated = (
 method: "script.realmCreated",
 params: script.RealmInfo
)
远程端事件触发器如下:

当调用设置窗口环境设置 对象、设置 worker 环境设置 对象或设置 worklet 环境设置 对象算法中的任一个时,在返回设置 对象之前立即执行:

  1. 令 environment settings 为新创建的环境设置对象。

  2. 令 realm info 为给定 environment settings 获取 Realm 信息所得的结果。

  3. 如果 realm info 为 null,则返回。

  4. 令 related navigables 为给定 environment settings 获取相关 可导航对象所得的结果。

  5. 令 body 为一个与 script.RealmCreated 产生式匹配的映射,其中 params 字段设置为 realm info。

  6. 对于给定 "script.realmCreated" 和 related navigables 的已启用某 事件的会话集合中的每个 session:

    1. 使用 session 和 body 发出 事件。

给定 session、navigables 和 include global,远端订阅步骤的订阅优先级为 2,步骤如下:

  1. 令 environment settings 为一个由所有环境设置对象组成的列表, 这些对象的执行就绪标志已设置。

  2. 对于 environment settings 中的每个 settings:

    1. 令 related navigables 为一个新的集合。

    2. 如果 settings 的 相关全局对象的关联的 Document是一个Document:

      1. 令 navigable 为 settings 的相关全局对象的 关联的 Document的 节点可导航对象。

      2. 如果 navigable 为 null,则继续。

      3. 令 top-level traversible 为 navigable 的顶级可遍历对象。

      4. 如果 top-level traversible 不在 navigables 中,则继续。

      5. 将 top-level traversible 追加到 related navigables。

      否则,如果 include global 为 false,则继续。

    3. 令 realm info 为给定 settings 获取 Realm 信息 所得的结果。

    4. 如果 realm info 为 null,则继续。

    5. 令 body 为一个与 script.RealmCreated 产生式匹配的映射,其中 params 字段设置为 realm info。

    6. 如果给定 session、 "script.realmCreated" 和 related navigables 时事件 已启用:

      1. 使用 session 和 body 发出 事件。

这里的顺序 是否应该定义得更明确?

7.6.5.3. script.realmDestroyed 事件
事件类型
script.RealmDestroyed = (
  method: "script.realmDestroyed",
  params: script.RealmDestroyedParameters
)

script.RealmDestroyedParameters = {
  realm: script.Realm
}

远程端事件触发器如下:
使用 document 定义以下卸载文档清理步骤:
  1. 令 related navigables 为空集合。

  2. 将 document 的可导航对象追加到 related navigables。

  3. 对于 document 的工作线程全局作用域中的每个 worklet global scope:

    1. 令 realm 为 worklet global scope 的相关 Realm。

    2. 令 realm id 为 realm 的Realm ID。

    3. 令 params 为一个匹配 script.RealmDestroyedParameters 产生式的映射,并将 realm 字段设置为 realm id。

    4. 令 body 为一个匹配 script.RealmDestroyed 产生式的映射,并将 params 字段设置为 params。

    5. 给定 "script.realmDestroyed" 和 related navigables,对于启用了 事件的会话集合中的每个 session:

      1. 使用 session 和 body 触发 事件。

  4. 令 environment settings 为一个环境设置对象,其 相关全局对象的关联的 Document为 document。

  5. 令 realm 为 environment settings 的Realm 执行上下文的 Realm 组件。

  6. 令 realm id 为 realm 的Realm ID。

  7. 令 params 为一个匹配 script.RealmDestroyedParameters 产生式的映射,并将 realm 字段设置为 realm id。

  8. 令 body 为一个匹配 script.RealmDestroyed 产生式的映射,并将 params 字段设置为 params。

  9. 给定 "script.realmDestroyed" 和 related navigables,对于启用了事件的 会话集合中的每个 session:

    1. 使用 session 和 body 触发 事件。

每当worker 事件循环 event loop 被销毁时,无论是 因为 worker 到达其生命周期的末尾,还是通过终止 worker算法提前终止:

  1. 令 environment settings 为一个环境设置对象,其中 event loop 是其负责的事件循环。

  2. 令 related navigables 为给定 environment settings 获取相关 可导航对象所得的结果。

  3. 令 realm 为 environment settings 的环境设置对象的 Realm。

  4. 令 realm id 为 realm 的Realm ID。

  5. 令 params 为一个匹配 script.RealmDestroyedParameters 产生式的映射, 并将 realm 字段设置为 realm id。

  6. 令 body 为一个匹配 script.RealmDestroyed 产生式的映射, 并将 params 字段设置为 params。

  7. 给定 "script.realmDestroyed" 和 related navigables,对于启用了 事件的会话集合中的每个 session:

    1. 使用 session 和 body 触发 事件。

7.7. storage 模块

storage 模块包含与存储相关的功能和 事件。

存储分区 是一个命名空间,用户代理可以在其中 组织持久数据,例如 cookies 和本地存储。

存储分区 键是一个映射,它唯一标识一个存储分区。

7.7.1. 定义

远程端定义

StorageCommand = (
  storage.DeleteCookies //
  storage.GetCookies //
  storage.SetCookie
)

本地端定义

StorageResult = (
  storage.DeleteCookiesResult /
  storage.GetCookiesResult /
  storage.SetCookieResult
)

7.7.2. 类型

7.7.2.1. storage.PartitionKey 类型

本地端定义

storage.PartitionKey = {
  ? userContext: text,
  ? sourceOrigin: text,
  Extensible,
}

storage.PartitionKey 类型表示一个存储分区键。

以下标准存储分区键 属性表 枚举了具有众所周知含义的属性,远程端 可以 选择支持这些属性。实现可以定义额外的扩展存储分区键属性。

属性 定义
"userContext" 一个用户上下文 ID
"sourceOrigin" 可以访问该存储分区的资源的源序列化

远端可以支持任意数量的扩展存储分区键 属性。为了避免与其他实现发生冲突,这些 属性必须以供应商和用户代理的唯一标识符开头, 后跟 U+003A (:)。

一个远端具有一个由零个或多个条目组成的存储 分区键属性的默认值映射。每个键必须是 标准存储分区键 属性表的成员,其中 存储分区 键对应于标准存储分区;如果不是,则必须是 扩展存储分区键属性, 而这些值表示当用户 未提供显式值时将使用的该分区键的默认值。具体条目由 实现定义,并由实现所采用的存储分区方式 决定。

一个远端具有一个由零个或多个条目组成的必需的分区键 属性列表。每个键必须是 标准存储分区键 属性表的成员,其中 存储分区 键对应于标准存储分区;如果不是,则必须是 扩展存储分区键属性。具体 条目由实现定义,并由实现所采用的存储 分区方式决定。此列表仅包含没有可用默认值的分区 键。因此,该列表不得与存储分区 键属性的默认值中的键共享任何 条目。

给定 filter,要反序列化 筛选器:
  1. 令 deserialized filter 为空映射。

  2. 对于 filter 中的每个 name → value:

    1. 令 deserialized name 为 cookie 转换表中与 JSON 键 name 对应的字段名称。

    2. 如果 name 为 "value",则将 deserialized value 设置为使用 value 反序列化协议字节的结果, 否则令 deserialized value 为 value。

    3. 将 deserialized filter[deserialized name] 设置为 deserialized value。

  3. 返回 deserialized filter。

给定 partition spec,要展开 存储分区规范:
  1. 如果 partition spec 为 null:

    1. 将 partition spec 设置为空映射。

  2. 否则,如果 partition spec["type"] 为 "context":

    1. 令 navigable 为尝试给定 partition spec["context"] 获取 可导航对象的结果。

    2. 令 partition key 为 navigable 的关联的存储分区的键。

    3. 返回带有数据 partition key 的成功。

  3. 令 partition key 为空映射。

  4. 对于存储 分区键属性的默认值中的每个 name → default value:

    1. 如果 partition spec[name] 存在,则令 value 为该值,否则为 default value。

    2. 将 partition key[name] 设置为 value。

  5. 对于远端的必需的分区键属性中的每个 name:

    1. 如果 partition spec[name] 存在:

      1. 将 partition key][name] 设置为 partition spec[name]。

    2. 否则:

      1. 返回带有错误,其错误代码为未充分指定的存储 分区。

  6. 返回带有数据 partition key 的成功。

给定 storage partition key,要获取 cookie 存储:
  1. 如果 storage partition key 唯一标识一个现存的存储分区:

    1. 令 store 为该存储分区的cookie 存储。

    2. 返回带有数据 store 的成功。

  2. 返回带有错误,其错误 代码为无此存储分区。

给定 stored cookie 和 filter,要匹配 cookie:
  1. 对于 filter 中的每个 name → value:

    1. 如果 stored cookie[name] 不等于 value:

      1. 返回 false。

  2. 返回 true。

给定 cookie store 和 filter,要获取匹配的 cookie:
  1. 令 cookies 为一个新列表。

  2. 将 deserialized filter 设置为使用 filter 反序列化筛选器的结果。

  3. 对于 cookie store 中的每个 stored cookie:

    1. 如果使用 stored cookie 和 deserialized filter 匹配 cookie的结果为 true:

      1. 将 stored cookie 追加到 cookies。

  4. 返回 cookies。

7.7.3. 命令

7.7.3.1. storage.getCookies 命令

storage.getCookies 命令检索零个或多个与一组提供的 参数匹配的 cookies。

命令类型
storage.GetCookies = (
  method: "storage.getCookies",
  params: storage.GetCookiesParameters
)


storage.CookieFilter = {
  ? name: text,
  ? value: network.BytesValue,
  ? domain: text,
  ? path: text,
  ? size: js-uint,
  ? httpOnly: bool,
  ? secure: bool,
  ? sameSite: network.SameSite,
  ? expiry: js-uint,
  Extensible,
}

storage.BrowsingContextPartitionDescriptor = {
  type: "context",
  context: browsingContext.BrowsingContext
}

storage.StorageKeyPartitionDescriptor = {
  type: "storageKey",
  ? userContext: text,
  ? sourceOrigin: text,
  Extensible,
}

storage.PartitionDescriptor = (
  storage.BrowsingContextPartitionDescriptor /
  storage.StorageKeyPartitionDescriptor
)

storage.GetCookiesParameters = {
  ? filter: storage.CookieFilter,
  ? partition: storage.PartitionDescriptor,
}
返回类型
storage.GetCookiesResult = {
  cookies: [*network.Cookie],
  partitionKey: storage.PartitionKey,
}
使用 session 和 command parameters 时的远端步骤如下:
  1. 如果 command parameters 的 filter 字段存在,则令 filter 为该字段的值, 否则令其为空映射。

  2. 如果 command parameters 的 partition 字段存在,则令 partition spec 为该字段的值,否则令其为 null。

  3. 令 partition key 为尝试使用 partition spec 展开存储分区规范的结果。

  4. 令 store 为尝试使用 partition key 获取 cookie 存储的结果。

  5. 令 cookies 为使用 store 和 filter 获取匹配的 cookie的结果。

  6. 令 serialized cookies 为一个新列表。

  7. 对于 cookies 中的每个 cookie:

    1. 令 serialized cookie 为给定 cookie 时序列化 cookie的结果。

    2. 将 serialized cookie 追加到 serialized cookies。

  8. 令 body 为一个与 storage.GetCookiesResult 产生式匹配的映射, 其中 cookies 字段设置为 serialized cookies,且 partitionKey 字段设置为 partition key。

  9. 返回带有数据 body 的成功。

7.7.3.2. storage.setCookie 命令

storage.setCookie 命令在 cookie 存储中创建一个新的 cookie, 替换该存储中根据 [COOKIES] 匹配的任何 cookie。

命令类型
storage.SetCookie = (
  method: "storage.setCookie",
  params: storage.SetCookieParameters,
)


storage.PartialCookie = {
  name: text,
  value: network.BytesValue,
  domain: text,
  ? path: text,
  ? httpOnly: bool,
  ? secure: bool,
  ? sameSite: network.SameSite,
  ? expiry: js-uint,
  Extensible,
}

storage.SetCookieParameters = {
  cookie: storage.PartialCookie,
  ? partition: storage.PartitionDescriptor,
}
返回类型
storage.SetCookieResult = {
  partitionKey: storage.PartitionKey
}
使用 session 和 command parameters 时的远端步骤如下:
  1. 令 cookie spec 为 command parameters 的 cookie 字段的值。

  2. 如果 command parameters 的 partition 字段存在,则令 partition spec 为该字段的值,否则令其为 null。

  3. 令 partition key 为尝试使用 partition spec 展开存储分区规范的结果。

  4. 令 store 为尝试使用 partition key 获取 cookie 存储的结果。

  5. 令 deserialized value 为使用 cookie spec["value"] 反序列化协议字节的结果。

  6. 在 store 中创建 cookie,使用cookie 名称 cookie spec["name"]、 cookie 值 deserialized value、cookie 域 cookie spec["domain"],以及由cookie 转换表中列出的以下 cookie 概念组成的属性值列表:

    Cookie 路径

    如果 cookie spec["path"] 存在,则为该值,否则为 "/"。

    Cookie 仅安全

    如果 cookie spec["secure"] 存在,则为该值,否则为 false。

    Cookie 仅 HTTP

    如果 cookie spec["httpOnly"] 存在,则为该值,否则为 false。

    Cookie 过期时间

    如果 cookie spec["expiry"] 存在,则为该值,否则保持未设置,以 表示这是一个会话 cookie。

    注:Cookie 的过期值 可能由远端根据Cookie 生命周期限制加以限制。

    Cookie 同站

    如果 cookie spec["sameSite"] 存在,则为该值,否则保持未设置,以 表示未定义同站策略。

    如果此步骤在未将 cookie 插入 cookie 存储的情况下中止,则返回 带有错误,其错误 代码为无法设置 cookie。

  7. 令 body 为一个与 storage.SetCookieResult 产生式匹配的映射, 其中 partitionKey 字段设置为 partition key。

  8. 返回带有数据 body 的成功。

7.7.3.3. storage.deleteCookies 命令

storage.deleteCookies 命令移除零个或多个与一组提供的 参数匹配的 cookies。

命令类型
storage.DeleteCookies = (
  method: "storage.deleteCookies",
  params: storage.DeleteCookiesParameters,
)

storage.DeleteCookiesParameters = {
  ? filter: storage.CookieFilter,
  ? partition: storage.PartitionDescriptor,
}
返回类型
storage.DeleteCookiesResult = {
  partitionKey: storage.PartitionKey
}
使用 session 和 command parameters 时的远端步骤如下:
  1. 如果 command parameters 的 filter 字段存在,则令 filter 为该字段的值, 否则令其为空映射。

  2. 如果 command parameters 的 partition 字段存在,则令 partition spec 为该字段的值,否则令其为 null。

  3. 令 partition key 为尝试使用 partition spec 展开存储分区规范的结果。

  4. 令 store 为尝试使用 partition key 获取 cookie 存储的结果。

  5. 令 cookies 为使用 store 和 filter 获取匹配的 cookie的结果。

  6. 对于 cookies 中的每个 cookie:

    1. 从 store 中移除 cookie。

  7. 令 body 为一个与 storage.DeleteCookiesResult 产生式匹配的映射, 其中 partitionKey 字段设置为 partition key。

  8. 返回带有数据 body 的成功。

7.8. log 模块

log 模块包含与日志记录相关的功能和事件。

BiDi 会话具有一个日志事件缓冲区,它 是一个从 可导航 ID到该上下文中尚未 发出的日志事件列表的映射。用户代理可以对此缓冲区施加最大大小,但须满足以下条件: 如果事件 A 和 B 发生在同一上下文中,且 A 发生在 B 之前,并且二者都被添加到缓冲区, 则 B 的条目不得在 A 的条目之前被移除。

要在给定 session、navigables 和 event 的情况下缓冲日志 事件:

  1. 令 buffer 为 session 的日志事件缓冲区。

  2. 令 navigable ids 为一个新列表。

  3. 对于 navigables 的每个 navigable:

    1. 将 navigable 的可导航 ID追加到 navigable ids。

  4. 对于 navigable ids 中的每个 navigable id:

    1. 令 other navigables 为空列表

    2. 对于 navigable ids 中的每个 other id:

    3. 如果 other id 不等于 navigable id,则将 other id 追加到 other navigables。

    4. 如果 buffer 不包含 navigable id,则令 buffer[navigable id] 为一个 新列表。

    5. 将 (event, other navigables) 追加到 buffer[navigable id]。

注:我们在此存储其他可导航,以便 每个事件只发出 一次。实践中,这只与可以关联到 多个可导航的 worker 有关。

我们是否希望以 浏览上下文还是顶级可遍历作为键? 区别在于,如果事件发生在一个 frame 中,而该 frame 在本地端订阅顶级可导航的日志事件之前发生导航,会出现什么情况。

7.8.1. 定义

本地端定义

LogEvent = (
  log.EntryAdded
)

7.8.2. 类型

7.8.2.1. log.LogEntry

本地端定义

log.Level = "debug" / "info" / "warn" / "error"

log.Entry = (
  log.GenericLogEntry /
  log.ConsoleLogEntry /
  log.JavascriptLogEntry
)

log.BaseLogEntry = (
  level: log.Level,
  source: script.Source,
  text: text / null,
  timestamp: js-uint,
  ? stackTrace: script.StackTrace,
)

log.GenericLogEntry = {
  log.BaseLogEntry,
  type: text,
}

log.ConsoleLogEntry = {
  log.BaseLogEntry,
  type: "console",
  method: text,
  args: [*script.RemoteValue],
}

log.JavascriptLogEntry = {
  log.BaseLogEntry,
  type: "javascript",
}

每个日志事件都由一个 log.Entry 对象表示。它具有一个 type 属性,表示所添加日志条目的类型;一个 level 属性,表示严重性;一个 source 属性,表示日志条目的来源;一个 text 属性, 带有日志消息字符串本身;以及一个 timestamp 属性, 对应于日志条目生成的时间。log.Entry 的特定变体 用于表示来自不同来源的日志,并 提供特定于条目类型的附加字段。

7.8.3. 事件

7.8.3.1. log.entryAdded 事件
事件类型
log.EntryAdded = (
 method: "log.entryAdded",
 params: log.Entry,
)

远程端事件触发器如下:

使用 method、args 和 options 定义以下控制台 步骤:

  1. 对于活动 BiDi 会话中的每个 session:

    1. 如果 method 为 "error" 或 "assert",则令 level 为 "error"。如果 method 为 "debug" 或 "trace", 则令 level 为 "debug"。如果 method 为 "warn",则令 level 为 "warn"。否则令 level 为 "info"。

    2. 令 timestamp 为一个表示当前 UTC 日期和时间的时间值。

    3. 令 text 为空字符串。

    4. 如果 Type(args[0]) 为 String,且 args[0] 包含一个 格式说明符,则令 formatted args 为 Formatter(args)。否则 令 formatted args 为 args。

      注:格式化器操作在控制台规范中的 定义并不充分, 不同实现之间的格式化可能不一致。

    5. 对于 formatted args 中的每个 arg:

      1. 如果 arg 不是 args 中的第一个条目,则向 text 追加一个 U+0020 SPACE。

      2. 如果 arg 是一个原始 ECMAScript 值,则向 text 追加 ToString(arg)。否则向 text 追加一个由实现定义的字符串。

    6. 令 realm 为当前 Realm 记录的Realm ID。

    7. 令 serialized args 为一个新列表。

    8. 令 serialization options 为一个与 script.SerializationOptions 产生式匹配的映射,其字段设置为 各自的默认值。

    9. 对于 args 中的每个 arg:

      1. 令 serialized arg 为使用 arg 作为值、serialization options、none 作为 所有权类型、一个新的映射作为序列化内部映射、 realm 和 session 序列化为远程值所得的结果。

      2. 将 serialized arg 添加到 serialized args。

    10. 令 source 为给定当前 Realm 记录获取源所得的结果。

    11. 令 stack 为当前栈跟踪。

    12. 令 entry 为一个与 log.ConsoleLogEntry 产生式匹配的映射, 其中 level 字段设置为 level,text 字段设置为 text,timestamp 字段设置为 timestamp, stackTrace 字段设置为 stack,method 字段设置 为 method, source 字段设置为 source, 并且 args 字段设置为 serialized args。

    13. 令 body 为一个与 log.EntryAdded 产生式匹配的映射,其中 params 字段设置为 entry。

    14. 令 settings 为当前设置对象

    15. 令 related navigables 为给定 settings 获取相关 可导航对象所得的结果。

    16. 如果使用 session、"log.entryAdded" 和 related navigables 时事件 已启用,则使用 session 和 body 发出事件。

      否则,使用 session、 related browsing contexts 和 body 缓冲日志事件。

使用参数 script、 line number、column number、message 和 handled 定义以下错误报告步骤:

  1. 如果 handled 为 true,则返回。

  2. 令 settings 为 script 的设置对象。

  3. 令 timestamp 为一个表示当前 UTC 日期和时间的时间值。

  4. 令 stack 为一个异常的栈跟踪,其中 异常 对应于正在报告的错误。

  5. 令 source 为给定当前 Realm 记录获取源所得的结果。

  6. 令 entry 为一个与 log.JavascriptLogEntry 产生式匹配的映射, 其中 level 设置为 "error",text 设置为 message,source 设置为 source,timestamp 设置为 timestamp,并且 stackTrace 字段设置为 stack。

  7. 令 body 为一个与 log.EntryAdded 产生式匹配的映射,其中 params 字段设置为 entry。

  8. 令 related navigables 为给定 settings 获取相关 可导航对象所得的结果。

  9. 对于活动 BiDi 会话中的每个 session:

    1. 如果使用 session、"log.entryAdded" 和 related navigables 时事件 已启用,则使用 session 和 body 发出事件。

      否则,使用 session、 related browsing contexts 和 body 缓冲日志事件。

还有许多其他内容 需要记录日志。CDP 的 LogEntryAdded 类型包括 xml、 javascript、network、storage、appcache、rendering、security、deprecation、 worker、violation、intervention、recommendation、other。这些类型是在 由不同方法表示的 js 异常和控制台 API 类型之外的其他类型。

允许 由实现定义的日志类型

给定 session、navigables 和 include global,远端订阅步骤的订阅优先级为 10,步骤如下:

  1. 对于 session 的日志事件 缓冲区中的每个 navigable id → events:

    1. 令 maybe context 为给定 navigable id 获取可导航对象所得的结果。

    2. 如果 maybe context 是一个错误, 则从日志事件缓冲区中移除 navigable id 并继续。

    3. 令 navigable 为 maybe context 的数据

    4. 令 top level navigable 为 navigable 的顶级可遍历对象。

    5. 如果 include global 为 true 且 top level navigable 不在 navigables 中, 或者如果 include global 为 false 且 top level navigable 在 navigables 中:

      1. 对于 events 中的每个 (event, other navigables):

        1. 使用 session 和 event 发出事件。

        2. 对于 other navigables 中的每个 other context id:

          1. 如果日志事件缓冲区包含 other context id,则从日志事件 缓冲区[other context id] 中移除 event。

7.9. input 模块

input 模块包含用于 模拟用户输入的功能。

7.9.1. 定义

远程端定义

InputCommand = (
  input.PerformActions //
  input.ReleaseActions //
  input.SetFiles
)
InputResult = (
  input.PerformActionsResult /
  input.ReleaseActionsResult /
  input.SetFilesResult
)

本地端定义

InputEvent = (
  input.FileDialogOpened
)

7.9.2. 类型

7.9.2.1. input.ElementOrigin

input.ElementOrigin 类型表示一个将被用作坐标原点的 Element。

input.ElementOrigin = {
  type: "element",
  element: script.SharedReference
}
给定 object 的 is input.ElementOrigin 步骤如下:
  1. 如果 object 是一个匹配 input.ElementOrigin 产生式的映射, 则返回 true。

  2. 返回 false。

给定 session,要从 input.ElementOrigin 步骤获取 Element:
  1. 返回以下步骤,给定 origin 和 navigable:

    1. 断言:origin 与 input.ElementOrigin 匹配。

    2. 令 document 为 navigable 的活动文档。

    3. 令 reference 为 origin["element"]

    4. 令 environment settings 为其相关全局对象的关联的 Document为 document 的环境设置对象。

    5. 令 realm 为 environment settings 的领域执行上下文的 Realm 组件。

    6. 令 element 为尝试 使用 reference、realm 和 session 反序列化远程引用 的结果。

    7. 如果 element 未实现 Element ,则返回带有错误,其错误代码为 无此元素。

    8. 返回带有数据 element 的成功。

7.9.3. 命令

7.9.3.1. input.performActions 命令

input.performActions 命令会执行指定的用户输入 actions 序列。

注:有关此命令行为的详细描述,请参见 actions section of [WEBDRIVER]。

命令类型
input.PerformActions = (
  method: "input.performActions",
  params: input.PerformActionsParameters
)

input.PerformActionsParameters = {
  context: browsingContext.BrowsingContext,
  actions: [*input.SourceActions]
}

input.SourceActions = (
  input.NoneSourceActions /
  input.KeySourceActions /
  input.PointerSourceActions /
  input.WheelSourceActions
)

input.NoneSourceActions = {
  type: "none",
  id: text,
  actions: [*input.NoneSourceAction]
}

input.NoneSourceAction = input.PauseAction

input.KeySourceActions = {
  type: "key",
  id: text,
  actions: [*input.KeySourceAction]
}

input.KeySourceAction = (
  input.PauseAction /
  input.KeyDownAction /
  input.KeyUpAction
)

input.PointerSourceActions = {
  type: "pointer",
  id: text,
  ? parameters: input.PointerParameters,
  actions: [*input.PointerSourceAction]
}

input.PointerType = "mouse" / "pen" / "touch"

input.PointerParameters = {
  ? pointerType: input.PointerType .default "mouse"
}

input.PointerSourceAction = (
  input.PauseAction /
  input.PointerDownAction /
  input.PointerUpAction /
  input.PointerMoveAction
)

input.WheelSourceActions = {
  type: "wheel",
  id: text,
  actions: [*input.WheelSourceAction]
}

input.WheelSourceAction = (
  input.PauseAction /
  input.WheelScrollAction
)

input.PauseAction = {
  type: "pause",
  ? duration: js-uint
}

input.KeyDownAction = {
  type: "keyDown",
  value: text
}

input.KeyUpAction = {
  type: "keyUp",
  value: text
}

input.PointerUpAction = {
  type: "pointerUp",
  button: js-uint,
}

input.PointerDownAction = {
  type: "pointerDown",
  button: js-uint,
  input.PointerCommonProperties
}

input.PointerMoveAction = {
  type: "pointerMove",
  x: float,
  y: float,
  ? duration: js-uint,
  ? origin: input.Origin,
  input.PointerCommonProperties
}

input.WheelScrollAction = {
  type: "scroll",
  x: js-int,
  y: js-int,
  deltaX: js-int,
  deltaY: js-int,
  ? duration: js-uint,
  ? origin: input.Origin .default "viewport",
}

input.PointerCommonProperties = (
  ? width: js-uint,
  ? height: js-uint,
  ? pressure: (0.0..1.0),
  ? tangentialPressure: (-1.0..1.0),
  ? twist: (0..359),
  ; 0 .. Math.PI / 2
  ? altitudeAngle: (0.0..1.5707963267948966),
  ; 0 .. 2 * Math.PI
  ? azimuthAngle: (0.0..6.283185307179586),
)

input.Origin = "viewport" / "pointer" / input.ElementOrigin
返回类型
input.PerformActionsResult = EmptyResult

使用 session 和 command parameters 时的远端步骤如下:

  1. 令 navigable id 为 command parameters 的 context 字段的值。

  2. 令 navigable 为尝试使用 navigable id 获取 可导航对象的结果。

  3. 令 input state 为使用 session 和 navigable 的 顶层可遍历对象获取输入状态的结果。

  4. 令 actions options 为一个新的操作选项,其是元素原点步骤设置为是 input.ElementOrigin,且其 获取元素原点步骤设置为给定 session 时从 input.ElementOrigin 获取 Element 步骤的结果。

  5. 令 actions by tick 为尝试使用 input state、command parameters 和 actions options 提取操作序列的结果。

  6. 尝试使用 input state、 actions by tick、 navigable 和 actions options 分派操作。

  7. 返回带有数据 null 的成功。

7.9.3.2. input.releaseActions 命令

input.releaseActions 命令重置与当前会话关联的输入 状态。

命令类型
input.ReleaseActions = (
  method: "input.releaseActions",
  params: input.ReleaseActionsParameters
)

input.ReleaseActionsParameters = {
  context: browsingContext.BrowsingContext,
}
返回类型
input.ReleaseActionsResult = EmptyResult

给定 session 和 command parameters 时的远端步骤如下:

  1. 令 navigable id 为 command parameters 的 context 字段的值。

  2. 令 navigable 为尝试使用 navigable id 获取 可导航对象的结果。

  3. 令 top-level traversable 为 navigable 的顶层可遍历对象。

  4. 令 input state 为使用 session 和 top-level traversable 获取输入状态的结果。

  5. 令 actions options 为一个新的操作选项,其是元素原点步骤设置为是 input.ElementOrigin,且其 获取元素原点步骤设置为给定 session 时从 input.ElementOrigin 获取 Element 步骤。

  6. 令 undo actions 为 input state 的输入取消列表,顺序反转。

  7. 尝试使用 undo actions、0、navigable 和 actions options 分派刻操作。

  8. 使用 session 和 top-level traversable 重置输入状态。

  9. 返回带有数据 null 的成功。

7.9.3.3. input.setFiles 命令

input.setFiles 命令将给定 input 元素(其 type 为 file)的 files 属性 设为一组文件路径。

命令类型
input.SetFiles = (
  method: "input.setFiles",
  params: input.SetFilesParameters
)

input.SetFilesParameters = {
  context: browsingContext.BrowsingContext,
  element: script.SharedReference,
  files: [*text]
}
返回类型
input.SetFilesResult = EmptyResult

给定 session 和 command parameters 时的远端步骤如下:

  1. 令 navigable id 为 command parameters["context"] 字段的值。

  2. 令 navigable 为尝试使用 navigable id 获取可 导航对象的结果。

  3. 令 document 为 navigable 的活动文档。

  4. 令 environment settings 为其 相关全局对象的关联的 Document 为 document 的环境设置对象。

  5. 令 realm 为 environment settings 的领域执行上下文的 Realm 组件。

  6. 令 element 为尝试使用 command parameters["element"]、realm 和 session 反序列化远程引用的结果。

  7. 如果 element 未实现 Element, 则返回带有错误,其错误 代码为 无此元素。

  8. 如果 element 未实现 HTMLInputElement, element 的 type 不处于文件上传状态,或者 element 已 禁用, 则返回带有错误,其错误 代码为无法设置文件输入。

  9. 如果 files 的大小大于 1,且 element 的 multiple 属性未设置,则返回带有错误,其错误代码为 无法设置文件输入。

  10. 令 files 为 command parameters["files"] 字段的值。

  11. 令 selected files 为 element 的选定文件。

  12. 如果 files 与 selected files 的交集的大小等于 selected files 的大小,并且等于 files 的大小,则给定 element,在用户交互任务源上将元素任务排入队列,以在 element 上触发名为 cancel 的事件,并将 bubbles 属性初始化为 true。

    注:浏览器中的取消通常 由文件选择的变化来确定。换言之,如果没有变化,则会发送 "cancel" 事件。

  13. 否则,将 files 作为 用户的选择,为 element 更新文件选择。

  14. 如果由于任何原因,远端无法将 element 的选定文件设置为 files 中给定路径的文件, 则返回错误,其错误代码为不支持的操作。

    注:例如,远端可能 无法将选定文件设置为文件系统中当前 不存在的文件。

  15. 返回带有数据 null 的成功。

7.9.4. 事件

7.9.4.1. input.fileDialogOpened 事件
事件类型
input.FileDialogOpened = (
   method: "input.fileDialogOpened",
   params: input.FileDialogInfo
)

input.FileDialogInfo = {
   context: browsingContext.BrowsingContext,
   ? userContext: browser.UserContext,
   ? element: script.SharedReference,
   multiple: bool,
}

WebDriver BiDi 文件选择器选项是一个结构体,具有一个名为 multiple 的项,其为 boolean。

给定元素 element 和 可选的WebDriver BiDi 文件选择器选项 file picker options(默认值:null)时,远端事件触发器是 WebDriver BiDi 文件对话框已打开步骤:

注:与其他用户提示处理程序不同,默认 行为是允许打开文件 对话框。

  1. 令 navigable 为 element 的节点文档的可导航对象。

  2. 令 navigable id 为 navigable 的可导航对象 id。

  3. 令 user context id 为 navigable 的关联的用户 上下文的用户 上下文 id。

  4. 令 multiple 为 false。

  5. 如果 element 不为 null,且 element 的 multiple 属性已设置, 则将 multiple 设置为 true。

  6. 如果 file picker options 不为 null,且 file picker options 的multiple 为 true,则将 multiple 设置为 true。

  7. 令 related navigables 为一个包含 navigable 的集合。

  8. 对于给定 "input.fileDialogOpened" 和 related navigables 时事件已启用的会话 集合中的每个 session:

    1. 令 params 为一个与 input.FileDialogInfo 产生式匹配的映射,其中 context 字段设置为 navigable id, userContext 字段设置为 user context id,且 multiple 字段设置为 multiple。

    2. 如果 element 不为 null:

      1. 令 shared id 为使用 element 和 session 获取 节点的共享 id的结果。

      2. 将 params["element"] 设置为 shared id。

    3. 令 body 为一个与 input.fileDialogOpened 产生式匹配的映射,其中 params 字段设置为 params。

    4. 使用 session 和 body 发出 事件。

  9. 令 dismissed 为 false。

  10. 对于活动 BiDi 会话中的每个 session:

    1. 令 user prompt handler 为 session 的用户提示处理程序。

    2. 如果 user prompt handler 不为 null:

    3. 断言 user prompt handler 是一个映射。

    4. 如果 user prompt handler 包含 "file":

      1. 如果 user prompt handler["file"] 不等于 "ignore",则将 dismissed 设置为 true。

    5. 否则,如果 user prompt handler 包含 "default",且 user prompt handler["default"] 不等于 "ignore",则将 dismissed 设置为 true。

  11. 返回 dismissed。

7.10. webExtension 模块

webExtension 模块包含用于 管理 Web 扩展以及与其交互的功能。

7.10.1. 定义

远程端定义

WebExtensionCommand = (
  webExtension.Install //
  webExtension.Uninstall
)

本地端定义

WebExtensionResult = (
  webExtension.InstallResult /
  webExtension.UninstallResult
)

7.10.2. 类型

7.10.2.1. webExtension.Extension 类型
webExtension.Extension = text

webExtension.Extension 类型表示远程端中的 Web 扩展 ID。

7.10.3. 命令

7.10.3.1. webExtension.install 命令

webExtension.install 命令在远端中安装 Web 扩展。

命令类型
webExtension.Install = (
   method: "webExtension.install",
   params: webExtension.InstallParameters
)

webExtension.InstallParameters = {
   extensionData: webExtension.ExtensionData,
}

webExtension.ExtensionData = (
   webExtension.ExtensionArchivePath /
   webExtension.ExtensionBase64Encoded /
   webExtension.ExtensionPath
)

webExtension.ExtensionPath = {
   type: "path",
   path: text,
}

webExtension.ExtensionArchivePath = {
   type: "archivePath",
   path: text,
}

webExtension.ExtensionBase64Encoded = {
   type: "base64",
   value: text,
}
返回类型
webExtension.InstallResult = {
  extension: webExtension.Extension
}
给定 bytes,要提取 zip 归档:
  1. 执行实现定义的步骤,使用 zip 压缩算法解码 bytes。TODO:为 zip 解码找到更好的引用。

  2. 如果上一步失败(例如,因为 bytes 不表示有效的 zip 压缩 数据),则返回带有错误代码错误 无效 Web 扩展。否则,令 entry 为包含已提取文件系统条目的目录条目。

  3. 返回 entry。

给定 extension data spec,要展开 Web 扩展数据规范:
  1. 令 type 为 extension data spec["type"]。

  2. 如果不支持使用 type 安装 Web 扩展,则返回带有错误,其错误 代码为不支持的操作。

  3. 在以下条件及相关步骤列表中,运行其相关条件为 true 的第一组步骤:

    type 是字符串 "path"
    1. 令 path 为 extension data spec["path"]。

    2. 令 locator 为一个目录定位器,其路径为 path,且根对应于文件 系统的根。

    3. 令 entry 为给定 locator 时定位条目的结果。

    type 是字符串 "archivePath"
    1. 令 archive path 为 extension data spec["path"]。

    2. 令 locator 为一个文件定位器,其路径为 archive path,且根对应于文件 系统的根。

    3. 令 archive entry 为给定 locator 时定位条目的结果。

    4. 如果 archive entry 为 null,则返回 null。

    5. 令 bytes 为 archive entry 的二进制数据。

    6. 令 entry 为尝试给定 bytes 时提取 zip 归档的结果。

    type 是字符串 "base64"
    1. 令 bytes 为对 extension data spec["value"] 进行宽容 base64 解码的结果。

    2. 如果 bytes 为失败,则返回 null。

    3. 令 entry 为尝试给定 bytes 时提取 zip 归档的结果。

  4. 返回 entry。

使用 command parameters 时的远端步骤如下:
  1. 如果不支持安装 Web 扩展,则返回带有错误 代码错误 不支持的操作。

  2. 令 extension data spec 为 command parameters["extensionData"]。

  3. 令 extension directory entry 为尝试使用 extension data spec 展开 Web 扩展数据规范的结果。

  4. 如果 extension directory entry 为 null,则返回带有错误,其错误代码为无效 Web 扩展。

  5. 执行实现定义的步骤,从 extension directory entry 安装 Web 扩展。如果失败,则返回带有错误,其错误代码为无效 Web 扩展。否则,令 extension id 为新安装 Web 扩展的唯一标识符。

  6. 令 result 为一个与 webExtension.InstallResult 产生式匹配的映射,其中 extension 字段设置为 extension id。

  7. 返回带有数据 result 的成功。

注:浏览器默认可能仅临时安装 Web 扩展, 以便 它们将在下次关闭期间自动卸载。

7.10.3.2. webExtension.uninstall 命令

webExtension.uninstall 命令为 远端卸载一个 Web 扩展。

命令类型
webExtension.Uninstall = (
   method: "webExtension.uninstall",
   params: webExtension.UninstallParameters
)

webExtension.UninstallParameters = {
   extension: webExtension.Extension,
}
返回类型
webExtension.UninstallResult = EmptyResult
使用 command parameters 时的远端步骤如下:
  1. 令 extension 为 command parameters["extension"]。

  2. 如果远端没有 id 等于 extension 的 Web 扩展,则返回带有错误,其错误代码为无此 Web 扩展。

  3. 执行任何实现定义的步骤,从远端移除该 Web 扩展。如果失败,则返回带有错误,其错误代码为未知错误。

  4. 返回带有数据 null 的成功。

8. 对其他规范的补丁

本规范要求对外部规范进行一些更改,以提供必要的 集成点。假定这些补丁将作为标准化流程的一部分提交到其他规范中。

8.1. HTML

report an error 算法被修改,在末尾增加一个步骤:

  1. 调用外部规范中定义的任何 error reporting steps,传入 script、line、col、message,以及如果错误已 处理则为 true,否则为 false。

8.2. Console

其他规范可以定义 console steps。

  1. 在以 参数 name、printerArgs 和 options(如果未提供该参数则为 undefined)调用 Printer 操作时,调用 外部规范中定义的任何 console steps,并传入参数 name、printerArgs 和 options。

8.3. CSS

8.3.1. 确定设备像素比

在 determine the device pixel ratio 算法的开头插入以下步骤:

  1. 如果设备像素比覆盖包含 window 的可导航对象,则返回设备像素 比覆盖[window 的可导航对象]。

8.3.2. 求值媒体查询

在 https://github.com/w3c/csswg-drafts/pull/13549 合并后移除。

[求值媒体 特性算法被修改以支持 WebDriver BiDi 覆盖。将步骤“结果是对指定媒体特性进行求值的结果”替换为:

要获取在给定Document document 中对媒体 特性 media feature 求值的结果:
  1. 令 media feature name 为 media feature 的mf-name。

  2. 令 emulated value 为获取 document 和 media feature name 的WebDriver BiDi 媒体特性值所得的 结果。

  3. 如果 emulated value 不为 null,则返回 emulated value。

  4. 否则,返回对指定 media feature 进行求值的结果。

8.3.3. viewport meta 元素

在 https://github.com/w3c/csswg-drafts/pull/13548 合并后移除。

[CSS-VIEWPORT-1] 规范的“Viewport meta element”章节被修改,以验证 WebDriver BiDi viewport meta 状态。

如果给定 `viewport` meta 元素的 节点文档的WebDriver BiDi viewport meta 状态为 true,则用户代理 MUST 使用 `viewport` meta 元素。

否则,用户代理 MAY 使用 `viewport` meta 元素。

9. 附录

本节为非规范性内容。

9.1. 外部规范

注:该列表并不详尽,且可能不是最新的。

以下外部规范定义了额外的 WebDriver BiDi 模块:

  1. Digital Credentials API

  2. Permissions

  3. nav-speculation

  4. User-Agent Client Hints

  5. Web Bluetooth

索引

由本规范定义的术语

由引用定义的术语

参考文献

规范性参考文献

[ACCNAME-1.1]
Joanmarie Diggs; Bryan Garaventa; Michael Cooper. 可访问 名称和描述计算 1.1. URL: https://w3c.github.io/accname/
[CONSOLE]
Dominic Farolino; Robert Kowalski; Terin Stock. 控制台 标准. 现行标准. URL: https://console.spec.whatwg.org/
[COOKIES]
A. Barth. HTTP 状态管理机制. 2011 年 4 月. 拟议标准. URL: https://httpwg.org/specs/rfc6265.html
[CORE-AAM-1.1]
Joanmarie Diggs; et al. 核心可访问性 API 映射 1.1. URL: https://w3c.github.io/core-aam/
[CSS-COLOR-ADJUST-1]
Elika Etemad; et al. CSS 颜色调整 模块第 1 级. URL: https://drafts.csswg.org/css-color-adjust-1/
[CSS-OVERFLOW-3]
Elika Etemad; Florian Rivoal. CSS 溢出模块 第 3 级. URL: https://drafts.csswg.org/css-overflow-3/
[CSS-PAINT-API-1]
Ian Kilpatrick; Dean Jackson. CSS 绘制 API 第 1 级. URL: https://drafts.css-houdini.org/css-paint-api-1/
[CSS-VIEWPORT-1]
Florian Rivoal; Emilio Cobos Álvarez. CSS 视口 模块第 1 级。URL:https://drafts.csswg.org/css-viewport/
[CSS2]
Bert Bos; et al. 层叠样式表第 2 级修订版 1 (CSS 2.1)规范. URL: https://drafts.csswg.org/css2/
[CSSOM-VIEW-1]
Simon Fraser; Emilio Cobos Álvarez. CSSOM 视图 模块. URL: https://drafts.csswg.org/cssom-view/
[DOM]
Anne van Kesteren. DOM 标准. 现行标准. URL: https://dom.spec.whatwg.org/
[ECMA-402]
ECMAScript 国际化 API 规范. URL: https://tc39.es/ecma402/
[ECMAScript]
ECMAScript 语言规范. URL: https://tc39.es/ecma262/multipage/
[ENCODING]
Anne van Kesteren. 编码标准. 现行 标准. URL: https://encoding.spec.whatwg.org/
[FETCH]
Anne van Kesteren. Fetch 标准. 现行 标准. URL: https://fetch.spec.whatwg.org/
[FS]
Austin Sullivan. 文件系统标准. 现行 标准. URL: https://fs.spec.whatwg.org/
[FULLSCREEN]
Philip Jägenstedt. 全屏 API 标准. 现行标准. URL: https://fullscreen.spec.whatwg.org/
[GEOLOCATION]
Marcos Caceres; Reilly Grant. 地理定位. URL: https://w3c.github.io/geolocation/
[GEOMETRY-1]
Sebastian Zartner; Yehonatan Daniv. 几何接口 模块第 1 级. URL: https://drafts.csswg.org/geometry/
[HR-TIME-3]
Yoav Weiss. 高精度时间. URL: https://w3c.github.io/hr-time/
[HTML]
Anne van Kesteren; et al. HTML 标准. 现行标准. URL: https://html.spec.whatwg.org/multipage/
[INFRA]
Anne van Kesteren; Domenic Denicola. Infra 标准. 现行标准. URL: https://infra.spec.whatwg.org/
[MEDIAQUERIES-5]
Tab Atkins Jr.;等。媒体查询第 5 级。URL:https://drafts.csswg.org/mediaqueries-5/
[MIMESNIFF]
Gordon P. Hemsley. MIME 嗅探标准. 现行标准. URL: https://mimesniff.spec.whatwg.org/
[RESOURCE-TIMING]
Yoav Weiss; Noam Rosenthal. 资源 计时. URL: https://w3c.github.io/resource-timing/
[RFC4648]
S. Josefsson. Base16、Base32 和 Base64 数据 编码. 2006 年 10 月. 拟议标准. URL: https://www.rfc-editor.org/info/rfc4648/
[RFC5280]
D. Cooper; et al. 互联网 X.509 公钥 基础设施证书和证书吊销列表(CRL)配置文件. 2008 年 5 月. 拟议标准. URL: https://www.rfc-editor.org/info/rfc5280/
[RFC6455]
I. Fette; A. Melnikov. WebSocket 协议. 2011 年 12 月. 拟议标准. URL: https://www.rfc-editor.org/info/rfc6455/
[RFC8610]
H. Birkholz; C. Vigano; C. Bormann. 简洁数据 定义语言(CDDL):用于表达简洁二进制对象表示 (CBOR)和 JSON 数据结构的记法约定. 2019 年 6 月. 拟议标准. URL: https://www.rfc-editor.org/info/rfc8610/
[RFC9110]
R. Fielding, Ed.; M. Nottingham, Ed.; J. Reschke, Ed.. HTTP 语义. 2022 年 6 月. 互联网 标准. URL: https://httpwg.org/specs/rfc9110.html
[RFC9562]
K. Davis; B. Peabody; P. Leach. 通用唯一 标识符(UUID). 2024 年 5 月. 拟议标准. URL: https://www.rfc-editor.org/info/rfc9562/
[SCREEN-CAPTURE]
Jan-Ivar Bruaroey; Elad Alon. 屏幕 捕获. URL: https://w3c.github.io/mediacapture-screen-share/
[SCREEN-ORIENTATION]
Marcos Caceres; Léonie Watson. 屏幕 方向。URL:https://w3c.github.io/screen-orientation/
[SELECTORS-4]
Elika Etemad; Tab Atkins Jr.. 选择器第 4 级. URL: https://drafts.csswg.org/selectors/
[SERVICE-WORKERS]
Monica CHINTALA; Yoshisato Yanagisawa. Service Workers Nightly. URL: https://w3c.github.io/ServiceWorker/
[UNICODE]
Unicode 标准. URL: https://www.unicode.org/versions/latest/
[URL]
Anne van Kesteren. URL 标准. 现行标准. URL: https://url.spec.whatwg.org/
[WEBAUDIO-1.0]
Paul Adenot; Hongchan Choi. Web Audio API. URL: https://webaudio.github.io/web-audio-api/
[WEBDRIVER]
Simon Stewart; David Burns. WebDriver. URL: https://w3c.github.io/webdriver/
[WEBIDL]
Edgar Chen; Timothy Gu. Web IDL 标准. 现行 标准. URL: https://webidl.spec.whatwg.org/
[WEBSOCKETS]
Adam Rice. WebSockets 标准. 现行 标准. URL: https://websockets.spec.whatwg.org/
[WEBTRANSPORT]
Jan-Ivar Bruaroey; Victor Vasiliev; Nidhi Jaju. WebTransport. URL: https://w3c.github.io/webtransport/

资料性参考文献

[CSS-SIZE-ADJUST-1]
CSS 移动端文本大小调整模块第 1 级。编辑草案。URL:https://drafts.csswg.org/css-size-adjust-1/
[CSS-VALUES-3]
Tab Atkins Jr.; Elika Etemad. CSS Values and Units Module Level 3. URL: https://drafts.csswg.org/css-values-3/
[HTTP11]
R. Fielding, Ed.; M. Nottingham, Ed.; J. Reschke, Ed.. HTTP/1.1. 2022 年 6 月. Internet 标准. URL: https://httpwg.org/specs/rfc9112.html
[JSON-RPC]
JSON-RPC Working Group. JSON-RPC 2.0 规范. 2013 年 1 月 4 日. URL: https://www.jsonrpc.org/specification
[RFC6265BIS]
Cookies:HTTP 状态 管理机制. 编辑草案. URL: https://datatracker.ietf.org/doc/html/draft-ietf-httpbis-rfc6265bis
[TOUCH-EVENTS]
Doug Schepers; et al. Touch Events. URL: https://w3c.github.io/touch-events/
[URLPattern]
Ben Kelly; Jeremy Roman; 宍戸俊哉 (Shunya Shishido). URL Pattern 标准. 现行标准. URL: https://urlpattern.spec.whatwg.org/

CDDL 索引

远端定义

Command = {
  id: js-uint,
  CommandData,
  Extensible,
}

CommandData = (
  BrowserCommand //
  BrowsingContextCommand //
  EmulationCommand //
  InputCommand //
  NetworkCommand //
  ScriptCommand //
  SessionCommand //
  StorageCommand //
  WebExtensionCommand
)

EmptyParams = {
   Extensible
}

Extensible = (*text => any)

js-int = -9007199254740991..9007199254740991
js-uint = 0..9007199254740991

SessionCommand = (
  session.End //
  session.New //
  session.Status //
  session.Subscribe //
  session.Unsubscribe
)

session.CapabilitiesRequest = {
  ? alwaysMatch: session.CapabilityRequest,
  ? firstMatch: [*session.CapabilityRequest]
}

session.CapabilityRequest = {
  ? acceptInsecureCerts: bool,
  ? browserName: text,
  ? browserVersion: text,
  ? platformName: text,
  ? proxy: session.ProxyConfiguration,
  ? unhandledPromptBehavior: session.UserPromptHandler,
  Extensible
}

session.CapabilityResponse = {
  acceptInsecureCerts: bool,
  browserName: text,
  browserVersion: text,
  platformName: text,
  setWindowRect: bool,
  userAgent: text,
  ? proxy: session.ProxyConfiguration,
  ? unhandledPromptBehavior: session.UserPromptHandler,
  ? webSocketUrl: text,
  Extensible
}

session.ProxyConfiguration = {
   session.AutodetectProxyConfiguration //
   session.DirectProxyConfiguration //
   session.ManualProxyConfiguration //
   session.PacProxyConfiguration //
   session.SystemProxyConfiguration
}

session.AutodetectProxyConfiguration = (
   proxyType: "autodetect",
   Extensible
)

session.DirectProxyConfiguration = (
   proxyType: "direct",
   Extensible
)

session.ManualProxyConfiguration = (
   proxyType: "manual",
   ? httpProxy: text,
   ? sslProxy: text,
   ? session.SocksProxyConfiguration,
   ? noProxy: [*text],
   Extensible
)

session.SocksProxyConfiguration = (
   socksProxy: text,
   socksVersion: 0..255,
)

session.PacProxyConfiguration = (
   proxyType: "pac",
   proxyAutoconfigUrl: text,
   Extensible
)

session.SystemProxyConfiguration = (
   proxyType: "system",
   Extensible
)


session.UserPromptHandler = {
  ? alert: session.UserPromptHandlerType,
  ? beforeUnload: session.UserPromptHandlerType,
  ? confirm: session.UserPromptHandlerType,
  ? default: session.UserPromptHandlerType,
  ? file: session.UserPromptHandlerType,
  ? prompt: session.UserPromptHandlerType,
}

session.UserPromptHandlerType = "accept" / "dismiss" / "ignore";

session.Subscription = text

session.SubscribeParameters = {
  events: [+text],
  ? contexts: [+browsingContext.BrowsingContext],
  ? userContexts: [+browser.UserContext],
}

session.UnsubscribeByIDRequest = {
  subscriptions: [+session.Subscription],
}

session.UnsubscribeByAttributesRequest = {
  events: [+text],
}

session.Status = (
  method: "session.status",
  params: EmptyParams,
)

session.New = (
  method: "session.new",
  params: session.NewParameters
)

session.NewParameters = {
  capabilities: session.CapabilitiesRequest
}

session.End = (
  method: "session.end",
  params: EmptyParams
)


session.Subscribe = (
  method: "session.subscribe",
  params: session.SubscribeParameters
)

session.Unsubscribe = (
  method: "session.unsubscribe",
  params: session.UnsubscribeParameters,
)

session.UnsubscribeParameters = session.UnsubscribeByAttributesRequest / session.UnsubscribeByIDRequest

BrowserCommand = (
  browser.Close //
  browser.CreateUserContext //
  browser.GetClientWindows //
  browser.GetUserContexts //
  browser.RemoveUserContext //
  browser.SetClientWindowState //
  browser.SetDownloadBehavior
)

browser.ClientWindow = text;

browser.ClientWindowInfo = {
  active: bool,
  clientWindow: browser.ClientWindow,
  height: js-uint,
  state: "fullscreen" / "maximized" / "minimized" / "normal",
  width: js-uint,
  x: js-int,
  y: js-int,
}

browser.UserContext = text;

browser.UserContextInfo = {
  userContext: browser.UserContext
}

browser.Close = (
  method: "browser.close",
  params: EmptyParams,
)

browser.CreateUserContext = (
  method: "browser.createUserContext",
  params: browser.CreateUserContextParameters,
)

browser.CreateUserContextParameters = {
  ? acceptInsecureCerts: bool,
  ? proxy: session.ProxyConfiguration,
  ? unhandledPromptBehavior: session.UserPromptHandler
}

browser.GetClientWindows = (
  method: "browser.getClientWindows",
  params: EmptyParams,
)

browser.GetUserContexts = (
  method: "browser.getUserContexts",
  params: EmptyParams,
)

browser.RemoveUserContext = (
  method: "browser.removeUserContext",
  params: browser.RemoveUserContextParameters
)

browser.RemoveUserContextParameters = {
  userContext: browser.UserContext
}

browser.SetClientWindowState = (
  method: "browser.setClientWindowState",
  params: browser.SetClientWindowStateParameters
)

browser.SetClientWindowStateParameters = {
  clientWindow: browser.ClientWindow,
  (browser.ClientWindowNamedState // browser.ClientWindowRectState)
}

browser.ClientWindowNamedState = (
  state: "fullscreen" / "maximized" / "minimized"
)

browser.ClientWindowRectState = (
  state: "normal",
  ? width: js-uint,
  ? height: js-uint,
  ? x: js-int,
  ? y: js-int,
)

browser.SetDownloadBehavior = (
  method: "browser.setDownloadBehavior",
  params: browser.SetDownloadBehaviorParameters
)

browser.SetDownloadBehaviorParameters = {
  downloadBehavior: browser.DownloadBehavior / null,
  ? userContexts: [+browser.UserContext]
}

browser.DownloadBehavior = {
  (
    browser.DownloadBehaviorAllowed //
    browser.DownloadBehaviorDenied
  )
}

browser.DownloadBehaviorAllowed = (
  type: "allowed",
  destinationFolder: text
)

browser.DownloadBehaviorDenied = (
  type: "denied"
)

BrowsingContextCommand = (
  browsingContext.Activate //
  browsingContext.CaptureScreenshot //
  browsingContext.Close //
  browsingContext.Create //
  browsingContext.GetTree //
  browsingContext.HandleUserPrompt //
  browsingContext.LocateNodes //
  browsingContext.Navigate //
  browsingContext.Print //
  browsingContext.Reload //
  browsingContext.SetBypassCSP //
  browsingContext.SetViewport //
  browsingContext.StartScreencast //
  browsingContext.StopScreencast //
  browsingContext.TraverseHistory
)

browsingContext.BrowsingContext = text;

browsingContext.Locator = (
   browsingContext.AccessibilityLocator /
   browsingContext.CssLocator /
   browsingContext.ContextLocator /
   browsingContext.InnerTextLocator /
   browsingContext.XPathLocator
)

browsingContext.AccessibilityLocator = {
   type: "accessibility",
   value: {
    ? name: text,
    ? role: text,
   }
}

browsingContext.CssLocator = {
   type: "css",
   value: text
}

browsingContext.ContextLocator = {
  type: "context",
  value: {
    context: browsingContext.BrowsingContext,
  }
}

browsingContext.InnerTextLocator = {
   type: "innerText",
   value: text,
   ? ignoreCase: bool
   ? matchType: "full" / "partial",
   ? maxDepth: js-uint,
}

browsingContext.XPathLocator = {
   type: "xpath",
   value: text
}

browsingContext.Navigation = text;

browsingContext.Download = text;

browsingContext.ReadinessState = "none" / "interactive" / "complete"

browsingContext.UserPromptType = "alert" / "beforeunload" / "confirm" / "prompt";

browsingContext.Activate = (
  method: "browsingContext.activate",
  params: browsingContext.ActivateParameters
)

browsingContext.ActivateParameters = {
  context: browsingContext.BrowsingContext
}

browsingContext.CaptureScreenshot = (
  method: "browsingContext.captureScreenshot",
  params: browsingContext.CaptureScreenshotParameters
)

browsingContext.CaptureScreenshotParameters = {
  context: browsingContext.BrowsingContext,
  ? origin: ("viewport" / "document") .default "viewport",
  ? format: browsingContext.ImageFormat,
  ? clip: browsingContext.ClipRectangle,
  ? imageSize: browsingContext.ImageSize,
}

browsingContext.ImageFormat = {
   type: text,
   ? quality: 0.0..1.0,
}

browsingContext.ImageSize = {
   ? maxWidth: (js-uint .ge 1),
   ? maxHeight: (js-uint .ge 1),
}

browsingContext.ClipRectangle = (
  browsingContext.BoxClipRectangle /
  browsingContext.ElementClipRectangle
)

browsingContext.ElementClipRectangle = {
  type: "element",
  element: script.SharedReference
}

browsingContext.BoxClipRectangle = {
   type: "box",
   x: float,
   y: float,
   width: float,
   height: float
}

browsingContext.Close = (
  method: "browsingContext.close",
  params: browsingContext.CloseParameters
)

browsingContext.CloseParameters = {
  context: browsingContext.BrowsingContext,
  ? promptUnload: bool .default false
}

browsingContext.Create = (
  method: "browsingContext.create",
  params: browsingContext.CreateParameters
)

browsingContext.CreateType = "tab" / "window"

browsingContext.CreateParameters = {
  type: browsingContext.CreateType,
  ? referenceContext: browsingContext.BrowsingContext,
  ? background: bool .default false,
  ? userContext: browser.UserContext
}

browsingContext.GetTree = (
  method: "browsingContext.getTree",
  params: browsingContext.GetTreeParameters
)

browsingContext.GetTreeParameters = {
  ? maxDepth: js-uint,
  ? root: browsingContext.BrowsingContext,
}

browsingContext.HandleUserPrompt = (
  method: "browsingContext.handleUserPrompt",
  params: browsingContext.HandleUserPromptParameters
)

browsingContext.HandleUserPromptParameters = {
  context: browsingContext.BrowsingContext,
  ? accept: bool,
  ? userText: text,
}

browsingContext.LocateNodes = (
  method: "browsingContext.locateNodes",
  params: browsingContext.LocateNodesParameters
)

browsingContext.LocateNodesParameters = {
   context: browsingContext.BrowsingContext,
   locator: browsingContext.Locator,
   ? maxNodeCount: (js-uint .ge 1),
   ? serializationOptions: script.SerializationOptions,
   ? startNodes: [ + script.SharedReference ]
}

browsingContext.Navigate = (
  method: "browsingContext.navigate",
  params: browsingContext.NavigateParameters
)

browsingContext.NavigateParameters = {
  context: browsingContext.BrowsingContext,
  url: text,
  ? wait: browsingContext.ReadinessState,
}

browsingContext.Print = (
  method: "browsingContext.print",
  params: browsingContext.PrintParameters
)

browsingContext.PrintParameters = {
  context: browsingContext.BrowsingContext,
  ? background: bool .default false,
  ? margin: browsingContext.PrintMarginParameters,
  ? orientation: ("portrait" / "landscape") .default "portrait",
  ? page: browsingContext.PrintPageParameters,
  ? pageRanges: [*(js-uint / text)],
  ? scale: (0.1..2.0) .default 1.0,
  ? shrinkToFit: bool .default true,
}

browsingContext.PrintMarginParameters = {
  ? bottom: (float .ge 0.0) .default 1.0,
  ? left: (float .ge 0.0) .default 1.0,
  ? right: (float .ge 0.0) .default 1.0,
  ? top: (float .ge 0.0) .default 1.0,
}

; Minimum size is 1pt x 1pt. Conversion follows from
; https://www.w3.org/TR/css3-values/#absolute-lengths
browsingContext.PrintPageParameters = {
  ? height: (float .ge 0.0352) .default 27.94,
  ? width: (float .ge 0.0352) .default 21.59,
}

browsingContext.Reload = (
  method: "browsingContext.reload",
  params: browsingContext.ReloadParameters
)

browsingContext.ReloadParameters = {
  context: browsingContext.BrowsingContext,
  ? ignoreCache: bool,
  ? wait: browsingContext.ReadinessState,
}

browsingContext.SetBypassCSP = (
  method: "browsingContext.setBypassCSP",
  params: browsingContext.SetBypassCSPParameters
)

browsingContext.SetBypassCSPParameters = {
  bypass: true / null,
  ? contexts: [+browsingContext.BrowsingContext],
  ? userContexts: [+browser.UserContext],
}

browsingContext.SetViewport = (
  method: "browsingContext.setViewport",
  params: browsingContext.SetViewportParameters
)

browsingContext.SetViewportParameters = {
  ? context: browsingContext.BrowsingContext,
  ? viewport: browsingContext.Viewport / null,
  ? devicePixelRatio: (float .gt 0.0) / null,
  ? userContexts: [+browser.UserContext],
}

browsingContext.Viewport = {
  width: js-uint,
  height: js-uint,
}

browsingContext.StartScreencast = (
  method: "browsingContext.startScreencast",
  params: browsingContext.StartScreencastParameters
)

browsingContext.StartScreencastParameters = {
  context: browsingContext.BrowsingContext,
  ? destinationFolder: text,
  ? mimeType: text,
  ? video: browsingContext.MediaTrackConstraints,
  ? audio: bool .default false,
}

browsingContext.MediaTrackConstraints = {
   ? width: js-uint,
   ? height: js-uint,
   ? frameRate: js-uint,
}


browsingContext.Screencast = text

browsingContext.StopScreencast = (
  method: "browsingContext.stopScreencast",
  params: browsingContext.StopScreencastParameters
)

browsingContext.StopScreencastParameters = {
  screencast: browsingContext.Screencast
}

browsingContext.TraverseHistory = (
  method: "browsingContext.traverseHistory",
  params: browsingContext.TraverseHistoryParameters
)

browsingContext.TraverseHistoryParameters = {
  context: browsingContext.BrowsingContext,
  delta: js-int,
}

EmulationCommand = (
  emulation.SetForcedColorsModeThemeOverride //
  emulation.SetGeolocationOverride //
  emulation.SetLocaleOverride //
  emulation.SetMediaFeaturesOverride //
  emulation.SetNetworkConditions //
  emulation.SetScreenOrientationOverride //
  emulation.SetScreenSettingsOverride //
  emulation.SetScriptingEnabled //
  emulation.SetScrollbarTypeOverride //
  emulation.SetTextLayoutModeOverride //
  emulation.SetTimezoneOverride //
  emulation.SetTouchOverride //
  emulation.SetUserAgentOverride //
  emulation.SetViewportMetaOverride
)


emulation.SetForcedColorsModeThemeOverride = (
  method: "emulation.setForcedColorsModeThemeOverride",
  params: emulation.SetForcedColorsModeThemeOverrideParameters
)

emulation.SetForcedColorsModeThemeOverrideParameters = {
  theme: emulation.ForcedColorsModeTheme / null,
  ? contexts: [+browsingContext.BrowsingContext],
  ? userContexts: [+browser.UserContext],
}

emulation.ForcedColorsModeTheme = "light" / "dark"

emulation.SetGeolocationOverride = (
  method: "emulation.setGeolocationOverride",
  params: emulation.SetGeolocationOverrideParameters
)

emulation.SetGeolocationOverrideParameters = {
  (
    (coordinates: emulation.GeolocationCoordinates / null) //
    (error: emulation.GeolocationPositionError)
  ),
  ? contexts: [+browsingContext.BrowsingContext],
  ? userContexts: [+browser.UserContext],
}

emulation.GeolocationCoordinates = {
   latitude: -90.0..90.0,
   longitude: -180.0..180.0,
   ? accuracy: (float .ge 0.0) .default 1.0,
   ? altitude: float / null .default null,
   ? altitudeAccuracy: (float .ge 0.0) / null .default null,
   ? heading: (0.0...360.0) / null .default null,
   ? speed: (float .ge 0.0) / null .default null,
}

emulation.GeolocationPositionError = {
   type: "positionUnavailable"
}

emulation.SetLocaleOverride = (
  method: "emulation.setLocaleOverride",
  params: emulation.SetLocaleOverrideParameters
)

emulation.SetLocaleOverrideParameters = {
  locale: text / null,
  ? contexts: [+browsingContext.BrowsingContext],
  ? userContexts: [+browser.UserContext],
}

emulation.SetMediaFeaturesOverride = (
  method: "emulation.setMediaFeaturesOverride",
  params: emulation.SetMediaFeaturesOverrideParameters
)

emulation.SetMediaFeaturesOverrideParameters = {
  features: emulation.MediaFeatures / null,
  ? contexts: [+browsingContext.BrowsingContext],
  ? userContexts: [+browser.UserContext],
}

emulation.MediaFeatures = {
  ? "any-hover": "none" / "hover" / null,
  ? "any-pointer": "none" / "coarse" / "fine" / null,
  ? "color": js-uint / null,
  ? "color-gamut": "srgb" / "p3" / "rec2020" / null,
  ? "color-index": js-uint / null,
  ? "display-mode": "fullscreen" / "standalone" / "minimal-ui" / "browser" / "picture-in-picture" / null,
  ? "dynamic-range": "standard" / "high" / null,
  ? "environment-blending": "opaque" / "additive" / "subtractive" / null,
  ? "forced-colors": "none" / "active" / null,
  ? "grid": 0 / 1 / null,
  ? "horizontal-viewport-segments": js-uint / null,
  ? "hover": "none" / "hover" / null,
  ? "inverted-colors": "none" / "inverted" / null,
  ? "monochrome": js-uint / null,
  ? "nav-controls": "none" / "back" / null,
  ? "overflow-block": "none" / "scroll" / "optional-paged" / "paged" / null,
  ? "overflow-inline": "none" / "scroll" / null,
  ? "pointer": "none" / "coarse" / "fine" / null,
  ? "prefers-color-scheme": "light" / "dark" / null,
  ? "prefers-contrast": "no-preference" / "more" / "less" / "custom" / null,
  ? "prefers-reduced-data": "no-preference" / "reduce" / null,
  ? "prefers-reduced-motion": "no-preference" / "reduce" / null,
  ? "prefers-reduced-transparency": "no-preference" / "reduce" / null,
  ? "scan": "interlace" / "progressive" / null,
  ? "scripting": "none" / "initial-only" / "enabled" / null,
  ? "update": "none" / "slow" / "fast" / null,
  ? "vertical-viewport-segments": js-uint / null,
  ? "video-color-gamut": "srgb" / "p3" / "rec2020" / null,
  ? "video-dynamic-range": "standard" / "high" / null,
}


emulation.SetNetworkConditions = (
  method: "emulation.setNetworkConditions",
  params: emulation.SetNetworkConditionsParameters
)

emulation.SetNetworkConditionsParameters = {
  networkConditions: emulation.NetworkConditions / null,
  ? contexts: [+browsingContext.BrowsingContext],
  ? userContexts: [+browser.UserContext],
}

emulation.NetworkConditions = emulation.NetworkConditionsOffline

emulation.NetworkConditionsOffline = {
  type: "offline"
}

emulation.SetScreenSettingsOverride = (
  method: "emulation.setScreenSettingsOverride",
  params: emulation.SetScreenSettingsOverrideParameters
)

emulation.ScreenArea = {
  width: js-uint,
  height: js-uint
}

emulation.SetScreenSettingsOverrideParameters = {
  screenArea: emulation.ScreenArea / null,
  ? contexts: [+browsingContext.BrowsingContext],
  ? userContexts: [+browser.UserContext],
}

emulation.SetScreenOrientationOverride = (
  method: "emulation.setScreenOrientationOverride",
  params: emulation.SetScreenOrientationOverrideParameters
)

emulation.ScreenOrientationNatural = "portrait" / "landscape"
emulation.ScreenOrientationType = "portrait-primary" / "portrait-secondary" / "landscape-primary" / "landscape-secondary"

emulation.ScreenOrientation = {
  natural: emulation.ScreenOrientationNatural,
  type: emulation.ScreenOrientationType
}

emulation.SetScreenOrientationOverrideParameters = {
  screenOrientation: emulation.ScreenOrientation / null,
  ? contexts: [+browsingContext.BrowsingContext],
  ? userContexts: [+browser.UserContext],
}

emulation.SetUserAgentOverride = (
  method: "emulation.setUserAgentOverride",
  params: emulation.SetUserAgentOverrideParameters
)

emulation.SetUserAgentOverrideParameters = {
  userAgent: text / null,
  ? contexts: [+browsingContext.BrowsingContext],
  ? userContexts: [+browser.UserContext],
}

emulation.SetViewportMetaOverride = (
  method: "emulation.setViewportMetaOverride",
  params: emulation.SetViewportMetaOverrideParameters
)

emulation.SetViewportMetaOverrideParameters = {
  viewportMeta: true / null,
  ? contexts: [+browsingContext.BrowsingContext],
  ? userContexts: [+browser.UserContext],
}

emulation.SetScriptingEnabled = (
  method: "emulation.setScriptingEnabled",
  params: emulation.SetScriptingEnabledParameters
)

emulation.SetScriptingEnabledParameters = {
  enabled: false / null,
  ? contexts: [+browsingContext.BrowsingContext],
  ? userContexts: [+browser.UserContext],
}

emulation.SetScrollbarTypeOverride = (
  method: "emulation.setScrollbarTypeOverride",
  params: emulation.SetScrollbarTypeOverrideParameters
)

emulation.SetScrollbarTypeOverrideParameters = {
  scrollbarType: "classic" / "overlay" / null,
  ? contexts: [+browsingContext.BrowsingContext],
  ? userContexts: [+browser.UserContext],
}

emulation.SetTextLayoutModeOverride = (
  method: "emulation.setTextLayoutModeOverride",
  params: emulation.SetTextLayoutModeOverrideParameters
)

emulation.SetTextLayoutModeOverrideParameters = {
  textLayoutMode: emulation.TextLayoutMode / null,
  ? contexts: [+browsingContext.BrowsingContext],
  ? userContexts: [+browser.UserContext],
}

emulation.TextLayoutMode = "mobile"

emulation.SetTimezoneOverride = (
  method: "emulation.setTimezoneOverride",
  params: emulation.SetTimezoneOverrideParameters
)

emulation.SetTimezoneOverrideParameters = {
  timezone: text / null,
  ? contexts: [+browsingContext.BrowsingContext],
  ? userContexts: [+browser.UserContext],
}

emulation.SetTouchOverride = (
  method: "emulation.setTouchOverride",
  params: emulation.SetTouchOverrideParameters
)

emulation.SetTouchOverrideParameters = {
  maxTouchPoints: (js-uint .ge 1) / null,
  ? contexts: [+browsingContext.BrowsingContext],
  ? userContexts: [+browser.UserContext],
}

NetworkCommand = (
  network.AddDataCollector //
  network.AddIntercept //
  network.ContinueRequest //
  network.ContinueResponse //
  network.ContinueWithAuth //
  network.DisownData //
  network.FailRequest //
  network.GetData //
  network.ProvideResponse //
  network.RemoveDataCollector //
  network.RemoveIntercept //
  network.SetCacheBehavior //
  network.SetExtraHeaders
)


network.AuthCredentials = {
  type: "password",
  username: text,
  password: text,
}

network.BytesValue = network.StringValue / network.Base64Value;

network.StringValue = {
  type: "string",
  value: text,
}

network.Base64Value = {
  type: "base64",
  value: text,
}

network.Collector = text

network.CollectorType = "blob"

network.SameSite = "strict" / "lax" / "none" / "default"


network.Cookie = {
    name: text,
    value: network.BytesValue,
    domain: text,
    path: text,
    size: js-uint,
    httpOnly: bool,
    secure: bool,
    sameSite: network.SameSite,
    ? expiry: js-uint,
    Extensible,
}

network.CookieHeader = {
    name: text,
    value: network.BytesValue,
}

network.DataType = "request" / "response"

network.Header = {
  name: text,
  value: network.BytesValue,
}

network.Intercept = text

network.Request = text;

network.SetCookieHeader = {
    name: text,
    value: network.BytesValue,
    ? domain: text,
    ? httpOnly: bool,
    ? expiry: text,
    ? maxAge: js-int,
    ? path: text,
    ? sameSite: network.SameSite,
    ? secure: bool,
}

network.UrlPattern = (
  network.UrlPatternPattern /
  network.UrlPatternString
)

network.UrlPatternPattern = {
    type: "pattern",
    ?protocol: text,
    ?hostname: text,
    ?port: text,
    ?pathname: text,
    ?search: text,
}


network.UrlPatternString = {
    type: "string",
    pattern: text,
}


network.AddDataCollector = (
  method: "network.addDataCollector",
  params: network.AddDataCollectorParameters
)

network.AddDataCollectorParameters = {
  dataTypes: [+network.DataType],
  maxEncodedDataSize: js-uint,
  ? collectorType: network.CollectorType .default "blob",
  ? contexts: [+browsingContext.BrowsingContext],
  ? userContexts: [+browser.UserContext],
}

network.AddIntercept = (
  method: "network.addIntercept",
  params: network.AddInterceptParameters
)

network.AddInterceptParameters = {
  phases: [+network.InterceptPhase],
  ? contexts: [+browsingContext.BrowsingContext],
  ? urlPatterns: [*network.UrlPattern],
}

network.InterceptPhase = "beforeRequestSent" / "responseStarted" /
                         "authRequired"

network.ContinueRequest = (
  method: "network.continueRequest",
  params: network.ContinueRequestParameters
)

network.ContinueRequestParameters = {
  request: network.Request,
  ?body: network.BytesValue,
  ?cookies: [*network.CookieHeader],
  ?headers: [*network.Header],
  ?method: text,
  ?url: text,
}

network.ContinueResponse = (
  method: "network.continueResponse",
  params: network.ContinueResponseParameters
)

network.ContinueResponseParameters = {
  request: network.Request,
  ?cookies: [*network.SetCookieHeader]
  ?credentials: network.AuthCredentials,
  ?headers: [*network.Header],
  ?reasonPhrase: text,
  ?statusCode: js-uint,
}

network.ContinueWithAuth = (
  method: "network.continueWithAuth",
  params: network.ContinueWithAuthParameters
)

network.ContinueWithAuthParameters = {
  request: network.Request,
  (network.ContinueWithAuthCredentials // network.ContinueWithAuthNoCredentials)
}

network.ContinueWithAuthCredentials = (
  action: "provideCredentials", 
  credentials: network.AuthCredentials
)

network.ContinueWithAuthNoCredentials = (
  action: "default" / "cancel"
)

network.DisownData = (
  method: "network.disownData",
  params: network.DisownDataParameters
)

network.DisownDataParameters = {
  dataType: network.DataType,
  collector: network.Collector,
  request: network.Request,
}

network.FailRequest = (
  method: "network.failRequest",
  params: network.FailRequestParameters
)

network.FailRequestParameters = {
  request: network.Request,
}

network.GetData = (
  method: "network.getData",
  params: network.GetDataParameters
)

network.GetDataParameters = {
  dataType: network.DataType,
  ? collector: network.Collector,
  ? disown: bool .default false,
  request: network.Request,
}

network.ProvideResponse = (
  method: "network.provideResponse",
  params: network.ProvideResponseParameters
)

network.ProvideResponseParameters = {
  request: network.Request,
  ?body: network.BytesValue,
  ?cookies: [*network.SetCookieHeader],
  ?headers: [*network.Header],
  ?reasonPhrase: text,
  ?statusCode: js-uint,
}

network.RemoveDataCollector = (
  method: "network.removeDataCollector",
  params: network.RemoveDataCollectorParameters
)

network.RemoveDataCollectorParameters = {
  collector: network.Collector
}

network.RemoveIntercept = (
  method: "network.removeIntercept",
  params: network.RemoveInterceptParameters
)

network.RemoveInterceptParameters = {
  intercept: network.Intercept
}

network.SetCacheBehavior = (
  method: "network.setCacheBehavior",
  params: network.SetCacheBehaviorParameters
)

network.SetCacheBehaviorParameters = {
  cacheBehavior: "default" / "bypass",
  ? contexts: [+browsingContext.BrowsingContext]
}

network.SetExtraHeaders = (
  method: "network.setExtraHeaders",
  params: network.SetExtraHeadersParameters
)

network.SetExtraHeadersParameters = {
  headers: [*network.Header]
  ? contexts: [+browsingContext.BrowsingContext]
  ? userContexts: [+browser.UserContext]
}

ScriptCommand = (
  script.AddPreloadScript //
  script.CallFunction //
  script.Disown //
  script.Evaluate //
  script.GetRealms //
  script.RemovePreloadScript
)

script.Channel = text;

script.ChannelValue = {
  type: "channel",
  value: script.ChannelProperties,
}

script.ChannelProperties = {
  channel: script.Channel,
  ? serializationOptions: script.SerializationOptions,
  ? ownership: script.ResultOwnership,
}

script.EvaluationResult = (
  script.EvaluationResultSuccess /
  script.EvaluationResultException
)

script.EvaluationResultSuccess = {
  type: "success",
  result: script.RemoteValue,
  realm: script.Realm
}

script.EvaluationResultException = {
  type: "exception",
  exceptionDetails: script.ExceptionDetails
  realm: script.Realm
}

script.ExceptionDetails = {
  columnNumber: js-uint,
  exception: script.RemoteValue,
  lineNumber: js-uint,
  stackTrace: script.StackTrace,
  text: text,
}

script.Handle = text;

script.InternalId = text;

script.LocalValue = (
  script.RemoteReference /
  script.PrimitiveProtocolValue /
  script.ChannelValue /
  script.ArrayLocalValue /
  { script.DateLocalValue } /
  script.MapLocalValue /
  script.ObjectLocalValue /
  { script.RegExpLocalValue } /
  script.SetLocalValue
)

script.ListLocalValue = [*script.LocalValue];

script.ArrayLocalValue = {
  type: "array",
  value: script.ListLocalValue,
}

script.DateLocalValue = (
  type: "date",
  value: text
)

script.MappingLocalValue = [*[(script.LocalValue / text), script.LocalValue]];

script.MapLocalValue = {
  type: "map",
  value: script.MappingLocalValue,
}

script.ObjectLocalValue = {
  type: "object",
  value: script.MappingLocalValue,
}

script.RegExpValue = {
  pattern: text,
  ? flags: text,
}

script.RegExpLocalValue = (
  type: "regexp",
  value: script.RegExpValue,
)

script.SetLocalValue = {
  type: "set",
  value: script.ListLocalValue,
}

script.PreloadScript = text;

script.Realm = text;

script.PrimitiveProtocolValue = (
  script.UndefinedValue /
  script.NullValue /
  script.StringValue /
  script.NumberValue /
  script.BooleanValue /
  script.BigIntValue
)

script.UndefinedValue = {
  type: "undefined",
}

script.NullValue = {
  type: "null",
}

script.StringValue = {
  type: "string",
  value: text,
}

script.SpecialNumber = "NaN" / "-0" / "Infinity" / "-Infinity";

script.NumberValue = {
  type: "number",
  value: number / script.SpecialNumber,
}

script.BooleanValue = {
  type: "boolean",
  value: bool,
}

script.BigIntValue = {
  type: "bigint",
  value: text,
}

script.RealmType = "window" / "dedicated-worker" / "shared-worker" / "service-worker" /
                   "worker" / "paint-worklet" / "audio-worklet" / "worklet"

script.RemoteReference = (
  script.SharedReference /
  script.RemoteObjectReference
)

script.SharedReference = {
   sharedId: script.SharedId

   ? handle: script.Handle,
   Extensible
}

script.RemoteObjectReference = {
   handle: script.Handle,

   ? sharedId: script.SharedId
   Extensible
}

script.RemoteValue = (
  script.PrimitiveProtocolValue /
  script.SymbolRemoteValue /
  script.ArrayRemoteValue /
  script.ObjectRemoteValue /
  script.FunctionRemoteValue /
  script.RegExpRemoteValue /
  script.DateRemoteValue /
  script.MapRemoteValue /
  script.SetRemoteValue /
  script.WeakMapRemoteValue /
  script.WeakSetRemoteValue /
  script.GeneratorRemoteValue /
  script.ErrorRemoteValue /
  script.ProxyRemoteValue /
  script.PromiseRemoteValue /
  script.TypedArrayRemoteValue /
  script.ArrayBufferRemoteValue /
  script.NodeListRemoteValue /
  script.HTMLCollectionRemoteValue /
  script.NodeRemoteValue /
  script.WindowProxyRemoteValue
)

script.ListRemoteValue = [*script.RemoteValue];

script.MappingRemoteValue = [*[(script.RemoteValue / text), script.RemoteValue]];

script.SymbolRemoteValue = {
  type: "symbol",
  ? handle: script.Handle,
  ? internalId: script.InternalId,
}

script.ArrayRemoteValue = {
  type: "array",
  ? handle: script.Handle,
  ? internalId: script.InternalId,
  ? value: script.ListRemoteValue,
}

script.ObjectRemoteValue = {
  type: "object",
  ? handle: script.Handle,
  ? internalId: script.InternalId,
  ? value: script.MappingRemoteValue,
}

script.FunctionRemoteValue = {
  type: "function",
  ? handle: script.Handle,
  ? internalId: script.InternalId,
}

script.RegExpRemoteValue = {
  script.RegExpLocalValue,
  ? handle: script.Handle,
  ? internalId: script.InternalId,
}

script.DateRemoteValue = {
  script.DateLocalValue,
  ? handle: script.Handle,
  ? internalId: script.InternalId,
}

script.MapRemoteValue = {
  type: "map",
  ? handle: script.Handle,
  ? internalId: script.InternalId,
  ? value: script.MappingRemoteValue,
}

script.SetRemoteValue = {
  type: "set",
  ? handle: script.Handle,
  ? internalId: script.InternalId,
  ? value: script.ListRemoteValue
}

script.WeakMapRemoteValue = {
  type: "weakmap",
  ? handle: script.Handle,
  ? internalId: script.InternalId,
}

script.WeakSetRemoteValue = {
  type: "weakset",
  ? handle: script.Handle,
  ? internalId: script.InternalId,
}

script.GeneratorRemoteValue = {
  type: "generator",
  ? handle: script.Handle,
  ? internalId: script.InternalId,
}

script.ErrorRemoteValue = {
  type: "error",
  ? handle: script.Handle,
  ? internalId: script.InternalId,
}

script.ProxyRemoteValue = {
  type: "proxy",
  ? handle: script.Handle,
  ? internalId: script.InternalId,
}

script.PromiseRemoteValue = {
  type: "promise",
  ? handle: script.Handle,
  ? internalId: script.InternalId,
}

script.TypedArrayRemoteValue = {
  type: "typedarray",
  ? handle: script.Handle,
  ? internalId: script.InternalId,
}

script.ArrayBufferRemoteValue = {
  type: "arraybuffer",
  ? handle: script.Handle,
  ? internalId: script.InternalId,
}

script.NodeListRemoteValue = {
  type: "nodelist",
  ? handle: script.Handle,
  ? internalId: script.InternalId,
  ? value: script.ListRemoteValue,
}

script.HTMLCollectionRemoteValue = {
  type: "htmlcollection",
  ? handle: script.Handle,
  ? internalId: script.InternalId,
  ? value: script.ListRemoteValue,
}

script.NodeRemoteValue = {
  type: "node",
  ? sharedId: script.SharedId,
  ? handle: script.Handle,
  ? internalId: script.InternalId,
  ? value: script.NodeProperties,
}

script.NodeProperties = {
  nodeType: js-uint,
  childNodeCount: js-uint,
  ? attributes: {*text => text},
  ? children: [*script.NodeRemoteValue],
  ? localName: text,
  ? mode: "open" / "closed",
  ? namespaceURI: text,
  ? nodeValue: text,
  ? shadowRoot: script.NodeRemoteValue / null,
}

script.WindowProxyRemoteValue = {
  type: "window",
  value: script.WindowProxyProperties,
  ? handle: script.Handle,
  ? internalId: script.InternalId
}

script.WindowProxyProperties = {
  context: browsingContext.BrowsingContext
}

script.ResultOwnership = "root" / "none"

script.SerializationOptions = {
  ? maxDomDepth: (js-uint / null) .default 0,
  ? maxObjectDepth: (js-uint / null) .default null,
  ? includeShadowTree: ("none" / "open" / "all") .default "none",
}

script.SharedId = text;

script.StackFrame = {
  columnNumber: js-uint,
  functionName: text,
  lineNumber: js-uint,
  url: text,
}

script.StackTrace = {
  callFrames: [*script.StackFrame],
}

script.RealmTarget = {
  realm: script.Realm
}

script.ContextTarget = {
  context: browsingContext.BrowsingContext,
  ? sandbox: text
}

script.Target = (
  script.ContextTarget /
  script.RealmTarget
)

script.AddPreloadScript = (
  method: "script.addPreloadScript",
  params: script.AddPreloadScriptParameters
)

script.AddPreloadScriptParameters = {
  functionDeclaration: text,
  ? arguments: [*script.ChannelValue],
  ? contexts: [+browsingContext.BrowsingContext],
  ? userContexts: [+browser.UserContext],
  ? sandbox: text
}

script.Disown = (
  method: "script.disown",
  params: script.DisownParameters
)

script.DisownParameters = {
  handles: [*script.Handle]
  target: script.Target;
}

script.CallFunction = (
  method: "script.callFunction",
  params: script.CallFunctionParameters
)

script.CallFunctionParameters = {
  functionDeclaration: text,
  awaitPromise: bool,
  target: script.Target,
  ? arguments: [*script.LocalValue],
  ? resultOwnership: script.ResultOwnership,
  ? serializationOptions: script.SerializationOptions,
  ? this: script.LocalValue,
  ? userActivation: bool .default false,
}

script.Evaluate = (
  method: "script.evaluate",
  params: script.EvaluateParameters
)

script.EvaluateParameters = {
  expression: text,
  target: script.Target,
  awaitPromise: bool,
  ? resultOwnership: script.ResultOwnership,
  ? serializationOptions: script.SerializationOptions,
  ? userActivation: bool .default false,
}

script.GetRealms = (
  method: "script.getRealms",
  params: script.GetRealmsParameters
)

script.GetRealmsParameters = {
  ? context: browsingContext.BrowsingContext,
  ? type: script.RealmType,
}

script.RemovePreloadScript = (
  method: "script.removePreloadScript",
  params: script.RemovePreloadScriptParameters
)

script.RemovePreloadScriptParameters = {
  script: script.PreloadScript
}

StorageCommand = (
  storage.DeleteCookies //
  storage.GetCookies //
  storage.SetCookie
)

storage.PartitionKey = {
  ? userContext: text,
  ? sourceOrigin: text,
  Extensible,
}

storage.GetCookies = (
  method: "storage.getCookies",
  params: storage.GetCookiesParameters
)


storage.CookieFilter = {
  ? name: text,
  ? value: network.BytesValue,
  ? domain: text,
  ? path: text,
  ? size: js-uint,
  ? httpOnly: bool,
  ? secure: bool,
  ? sameSite: network.SameSite,
  ? expiry: js-uint,
  Extensible,
}

storage.BrowsingContextPartitionDescriptor = {
  type: "context",
  context: browsingContext.BrowsingContext
}

storage.StorageKeyPartitionDescriptor = {
  type: "storageKey",
  ? userContext: text,
  ? sourceOrigin: text,
  Extensible,
}

storage.PartitionDescriptor = (
  storage.BrowsingContextPartitionDescriptor /
  storage.StorageKeyPartitionDescriptor
)

storage.GetCookiesParameters = {
  ? filter: storage.CookieFilter,
  ? partition: storage.PartitionDescriptor,
}

storage.SetCookie = (
  method: "storage.setCookie",
  params: storage.SetCookieParameters,
)


storage.PartialCookie = {
  name: text,
  value: network.BytesValue,
  domain: text,
  ? path: text,
  ? httpOnly: bool,
  ? secure: bool,
  ? sameSite: network.SameSite,
  ? expiry: js-uint,
  Extensible,
}

storage.SetCookieParameters = {
  cookie: storage.PartialCookie,
  ? partition: storage.PartitionDescriptor,
}

storage.DeleteCookies = (
  method: "storage.deleteCookies",
  params: storage.DeleteCookiesParameters,
)

storage.DeleteCookiesParameters = {
  ? filter: storage.CookieFilter,
  ? partition: storage.PartitionDescriptor,
}

InputCommand = (
  input.PerformActions //
  input.ReleaseActions //
  input.SetFiles
)

input.ElementOrigin = {
  type: "element",
  element: script.SharedReference
}

input.PerformActions = (
  method: "input.performActions",
  params: input.PerformActionsParameters
)

input.PerformActionsParameters = {
  context: browsingContext.BrowsingContext,
  actions: [*input.SourceActions]
}

input.SourceActions = (
  input.NoneSourceActions /
  input.KeySourceActions /
  input.PointerSourceActions /
  input.WheelSourceActions
)

input.NoneSourceActions = {
  type: "none",
  id: text,
  actions: [*input.NoneSourceAction]
}

input.NoneSourceAction = input.PauseAction

input.KeySourceActions = {
  type: "key",
  id: text,
  actions: [*input.KeySourceAction]
}

input.KeySourceAction = (
  input.PauseAction /
  input.KeyDownAction /
  input.KeyUpAction
)

input.PointerSourceActions = {
  type: "pointer",
  id: text,
  ? parameters: input.PointerParameters,
  actions: [*input.PointerSourceAction]
}

input.PointerType = "mouse" / "pen" / "touch"

input.PointerParameters = {
  ? pointerType: input.PointerType .default "mouse"
}

input.PointerSourceAction = (
  input.PauseAction /
  input.PointerDownAction /
  input.PointerUpAction /
  input.PointerMoveAction
)

input.WheelSourceActions = {
  type: "wheel",
  id: text,
  actions: [*input.WheelSourceAction]
}

input.WheelSourceAction = (
  input.PauseAction /
  input.WheelScrollAction
)

input.PauseAction = {
  type: "pause",
  ? duration: js-uint
}

input.KeyDownAction = {
  type: "keyDown",
  value: text
}

input.KeyUpAction = {
  type: "keyUp",
  value: text
}

input.PointerUpAction = {
  type: "pointerUp",
  button: js-uint,
}

input.PointerDownAction = {
  type: "pointerDown",
  button: js-uint,
  input.PointerCommonProperties
}

input.PointerMoveAction = {
  type: "pointerMove",
  x: float,
  y: float,
  ? duration: js-uint,
  ? origin: input.Origin,
  input.PointerCommonProperties
}

input.WheelScrollAction = {
  type: "scroll",
  x: js-int,
  y: js-int,
  deltaX: js-int,
  deltaY: js-int,
  ? duration: js-uint,
  ? origin: input.Origin .default "viewport",
}

input.PointerCommonProperties = (
  ? width: js-uint,
  ? height: js-uint,
  ? pressure: (0.0..1.0),
  ? tangentialPressure: (-1.0..1.0),
  ? twist: (0..359),
  ; 0 .. Math.PI / 2
  ? altitudeAngle: (0.0..1.5707963267948966),
  ; 0 .. 2 * Math.PI
  ? azimuthAngle: (0.0..6.283185307179586),
)

input.Origin = "viewport" / "pointer" / input.ElementOrigin

input.ReleaseActions = (
  method: "input.releaseActions",
  params: input.ReleaseActionsParameters
)

input.ReleaseActionsParameters = {
  context: browsingContext.BrowsingContext,
}

input.SetFiles = (
  method: "input.setFiles",
  params: input.SetFilesParameters
)

input.SetFilesParameters = {
  context: browsingContext.BrowsingContext,
  element: script.SharedReference,
  files: [*text]
}

WebExtensionCommand = (
  webExtension.Install //
  webExtension.Uninstall
)

webExtension.Extension = text

webExtension.Install = (
   method: "webExtension.install",
   params: webExtension.InstallParameters
)

webExtension.InstallParameters = {
   extensionData: webExtension.ExtensionData,
}

webExtension.ExtensionData = (
   webExtension.ExtensionArchivePath /
   webExtension.ExtensionBase64Encoded /
   webExtension.ExtensionPath
)

webExtension.ExtensionPath = {
   type: "path",
   path: text,
}

webExtension.ExtensionArchivePath = {
   type: "archivePath",
   path: text,
}

webExtension.ExtensionBase64Encoded = {
   type: "base64",
   value: text,
}

webExtension.Uninstall = (
   method: "webExtension.uninstall",
   params: webExtension.UninstallParameters
)

webExtension.UninstallParameters = {
   extension: webExtension.Extension,
}

Local end definition

Message = (
  CommandResponse /
  ErrorResponse /
  Event
)

CommandResponse = {
  type: "success",
  id: js-uint,
  result: ResultData,
  Extensible
}

ErrorResponse = {
  type: "error",
  id: js-uint / null,
  error: ErrorCode,
  message: text,
  ? stacktrace: text,
  Extensible
}

ResultData = (
  BrowserResult /
  BrowsingContextResult /
  EmulationResult /
  InputResult /
  NetworkResult /
  ScriptResult /
  SessionResult /
  StorageResult /
  WebExtensionResult
)

EmptyResult = {
  Extensible
}

Event = {
  type: "event",
  EventData,
  Extensible
}

EventData = (
  BrowsingContextEvent //
  InputEvent //
  LogEvent //
  NetworkEvent //
  ScriptEvent
)

Extensible = (*text => any)

js-int = -9007199254740991..9007199254740991
js-uint = 0..9007199254740991

ErrorCode = "invalid argument" /
            "invalid selector" /
            "invalid session id" /
            "invalid web extension" /
            "move target out of bounds" /
            "no such alert" /
            "no such network collector" /
            "no such element" /
            "no such frame" /
            "no such handle" /
            "no such history entry" /
            "no such intercept" /
            "no such network data" /
            "no such node" /
            "no such request" /
            "no such screencast" /
            "no such script" /
            "no such storage partition" /
            "no such user context" /
            "no such web extension" /
            "session not created" /
            "unable to capture screen" /
            "unable to close browser" /
            "unable to set cookie" /
            "unable to set file input" /
            "unavailable network data" /
            "underspecified storage partition" /
            "unknown command" /
            "unknown error" /
            "unsupported operation"

SessionResult = (
  session.EndResult /
  session.NewResult /
  session.StatusResult /
  session.SubscribeResult /
  session.UnsubscribeResult
)

session.CapabilitiesRequest = {
  ? alwaysMatch: session.CapabilityRequest,
  ? firstMatch: [*session.CapabilityRequest]
}

session.CapabilityRequest = {
  ? acceptInsecureCerts: bool,
  ? browserName: text,
  ? browserVersion: text,
  ? platformName: text,
  ? proxy: session.ProxyConfiguration,
  ? unhandledPromptBehavior: session.UserPromptHandler,
  Extensible
}

session.CapabilityResponse = {
  acceptInsecureCerts: bool,
  browserName: text,
  browserVersion: text,
  platformName: text,
  setWindowRect: bool,
  userAgent: text,
  ? proxy: session.ProxyConfiguration,
  ? unhandledPromptBehavior: session.UserPromptHandler,
  ? webSocketUrl: text,
  Extensible
}

session.ProxyConfiguration = {
   session.AutodetectProxyConfiguration //
   session.DirectProxyConfiguration //
   session.ManualProxyConfiguration //
   session.PacProxyConfiguration //
   session.SystemProxyConfiguration
}

session.AutodetectProxyConfiguration = (
   proxyType: "autodetect",
   Extensible
)

session.DirectProxyConfiguration = (
   proxyType: "direct",
   Extensible
)

session.ManualProxyConfiguration = (
   proxyType: "manual",
   ? httpProxy: text,
   ? sslProxy: text,
   ? session.SocksProxyConfiguration,
   ? noProxy: [*text],
   Extensible
)

session.SocksProxyConfiguration = (
   socksProxy: text,
   socksVersion: 0..255,
)

session.PacProxyConfiguration = (
   proxyType: "pac",
   proxyAutoconfigUrl: text,
   Extensible
)

session.SystemProxyConfiguration = (
   proxyType: "system",
   Extensible
)


session.UserPromptHandler = {
  ? alert: session.UserPromptHandlerType,
  ? beforeUnload: session.UserPromptHandlerType,
  ? confirm: session.UserPromptHandlerType,
  ? default: session.UserPromptHandlerType,
  ? file: session.UserPromptHandlerType,
  ? prompt: session.UserPromptHandlerType,
}

session.UserPromptHandlerType = "accept" / "dismiss" / "ignore";

session.Subscription = text

session.StatusResult = {
  ready: bool,
  message: text,
}

session.NewResult = {
  sessionId: text,
  capabilities: session.CapabilityResponse
}

session.EndResult = EmptyResult

session.SubscribeResult = {
  subscription: session.Subscription,
}

session.UnsubscribeResult = EmptyResult

BrowserResult = (
  browser.CloseResult /
  browser.CreateUserContextResult /
  browser.GetClientWindowsResult /
  browser.GetUserContextsResult /
  browser.RemoveUserContextResult /
  browser.SetClientWindowStateResult /
  browser.SetDownloadBehaviorResult
)

browser.ClientWindow = text;

browser.ClientWindowInfo = {
  active: bool,
  clientWindow: browser.ClientWindow,
  height: js-uint,
  state: "fullscreen" / "maximized" / "minimized" / "normal",
  width: js-uint,
  x: js-int,
  y: js-int,
}

browser.UserContext = text;

browser.UserContextInfo = {
  userContext: browser.UserContext
}

browser.CloseResult = EmptyResult

browser.CreateUserContextResult = browser.UserContextInfo

browser.GetClientWindowsResult = {
  clientWindows: [ * browser.ClientWindowInfo]
}

browser.GetUserContextsResult = {
  userContexts: [ + browser.UserContextInfo]
}

browser.RemoveUserContextResult = EmptyResult

browser.SetClientWindowStateResult = browser.ClientWindowInfo

browser.SetDownloadBehaviorResult = EmptyResult

BrowsingContextResult = (
  browsingContext.ActivateResult /
  browsingContext.CaptureScreenshotResult /
  browsingContext.CloseResult /
  browsingContext.CreateResult /
  browsingContext.GetTreeResult /
  browsingContext.HandleUserPromptResult /
  browsingContext.LocateNodesResult /
  browsingContext.NavigateResult /
  browsingContext.PrintResult /
  browsingContext.ReloadResult /
  browsingContext.SetBypassCSPResult /
  browsingContext.SetViewportResult /
  browsingContext.StartScreencastResult /
  browsingContext.StopScreencastResult /
  browsingContext.TraverseHistoryResult
)

BrowsingContextEvent = (
  browsingContext.ContextCreated //
  browsingContext.ContextDestroyed //
  browsingContext.DomContentLoaded //
  browsingContext.DownloadEnd //
  browsingContext.DownloadWillBegin //
  browsingContext.FragmentNavigated //
  browsingContext.HistoryUpdated //
  browsingContext.Load //
  browsingContext.NavigationAborted //
  browsingContext.NavigationCommitted //
  browsingContext.NavigationFailed //
  browsingContext.NavigationStarted //
  browsingContext.UserPromptClosed //
  browsingContext.UserPromptOpened
)

browsingContext.BrowsingContext = text;

browsingContext.InfoList = [*browsingContext.Info]

browsingContext.BaseInfo = (
  children: browsingContext.InfoList / null,
  clientWindow: browser.ClientWindow,
  context: browsingContext.BrowsingContext,
  originalOpener: browsingContext.BrowsingContext / null,
  url: text,
  userContext: browser.UserContext,
  ? parent: browsingContext.BrowsingContext / null,
)

browsingContext.Info = {
  browsingContext.BaseInfo
}

browsingContext.Locator = (
   browsingContext.AccessibilityLocator /
   browsingContext.CssLocator /
   browsingContext.ContextLocator /
   browsingContext.InnerTextLocator /
   browsingContext.XPathLocator
)

browsingContext.AccessibilityLocator = {
   type: "accessibility",
   value: {
    ? name: text,
    ? role: text,
   }
}

browsingContext.CssLocator = {
   type: "css",
   value: text
}

browsingContext.ContextLocator = {
  type: "context",
  value: {
    context: browsingContext.BrowsingContext,
  }
}

browsingContext.InnerTextLocator = {
   type: "innerText",
   value: text,
   ? ignoreCase: bool
   ? matchType: "full" / "partial",
   ? maxDepth: js-uint,
}

browsingContext.XPathLocator = {
   type: "xpath",
   value: text
}

browsingContext.Navigation = text;

browsingContext.Download = text;

browsingContext.BaseNavigationInfo = (
  context: browsingContext.BrowsingContext,
  navigation: browsingContext.Navigation / null,
  timestamp: js-uint,
  url: text,
  ? userContext: browser.UserContext,
)

browsingContext.NavigationInfo = {
  browsingContext.BaseNavigationInfo
}

browsingContext.UserPromptType = "alert" / "beforeunload" / "confirm" / "prompt";

browsingContext.ActivateResult = EmptyResult

browsingContext.CaptureScreenshotResult = {
  data: text
}

browsingContext.CloseResult = EmptyResult

browsingContext.CreateResult = {
  context: browsingContext.BrowsingContext,
  ? userContext: browser.UserContext
}

browsingContext.GetTreeResult = {
  contexts: browsingContext.InfoList
}

browsingContext.HandleUserPromptResult = EmptyResult

browsingContext.LocateNodesResult = {
    nodes: [ * script.NodeRemoteValue ]
}

browsingContext.NavigateResult = {
  navigation: browsingContext.Navigation / null,
  url: text,
}

browsingContext.PrintResult = {
  data: text
}

browsingContext.ReloadResult = browsingContext.NavigateResult

browsingContext.SetBypassCSPResult = EmptyResult

browsingContext.SetViewportResult = EmptyResult

browsingContext.StartScreencastResult = {
   screencast: browsingContext.Screencast,
   path: text
}


browsingContext.Screencast = text

browsingContext.StopScreencastResult = {
   path: text,
   ? error: text
}

browsingContext.TraverseHistoryResult = EmptyResult

browsingContext.ContextCreated = (
 method: "browsingContext.contextCreated",
 params: browsingContext.ContextCreatedParameters
)

browsingContext.ContextCreatedParameters = {
 browsingContext.BaseInfo,
 hasPlannedNavigation: bool,
}

browsingContext.ContextDestroyed = (
 method: "browsingContext.contextDestroyed",
 params: browsingContext.Info
)

browsingContext.NavigationStarted = (
 method: "browsingContext.navigationStarted",
 params: browsingContext.NavigationInfo
)

browsingContext.FragmentNavigated = (
 method: "browsingContext.fragmentNavigated",
 params: browsingContext.NavigationInfo
)

browsingContext.HistoryUpdated = (
  method: "browsingContext.historyUpdated",
  params: browsingContext.HistoryUpdatedParameters
)

browsingContext.HistoryUpdatedParameters = {
  context: browsingContext.BrowsingContext,
  timestamp: js-uint,
  url: text,
  ? userContext: browser.UserContext
}

browsingContext.DomContentLoaded = (
 method: "browsingContext.domContentLoaded",
 params: browsingContext.NavigationInfo
)

browsingContext.Load = (
 method: "browsingContext.load",
 params: browsingContext.NavigationInfo
)

browsingContext.DownloadWillBegin = (
 method: "browsingContext.downloadWillBegin",
 params: browsingContext.DownloadWillBeginParams
)

browsingContext.DownloadWillBeginParams = {
  download: browsingContext.Download,
  suggestedFilename: text,
  browsingContext.BaseNavigationInfo
}

browsingContext.DownloadEnd = (
  method: "browsingContext.downloadEnd",
  params: browsingContext.DownloadEndParams
)

browsingContext.DownloadEndParams = {
  (
    browsingContext.DownloadCanceledParams //
    browsingContext.DownloadCompleteParams
  )
}

browsingContext.DownloadCanceledParams = (
  status: "canceled",
  download: browsingContext.Download,
  browsingContext.BaseNavigationInfo
)

browsingContext.DownloadCompleteParams = (
  status: "complete",
  download: browsingContext.Download,
  filepath: text / null,
  browsingContext.BaseNavigationInfo
)

browsingContext.NavigationAborted = (
 method: "browsingContext.navigationAborted",
 params: browsingContext.NavigationInfo
)

browsingContext.NavigationCommitted = (
 method: "browsingContext.navigationCommitted",
 params: browsingContext.NavigationInfo
)

browsingContext.NavigationFailed = (
 method: "browsingContext.navigationFailed",
 params: browsingContext.NavigationInfo
)

browsingContext.UserPromptClosed = (
  method: "browsingContext.userPromptClosed",
  params: browsingContext.UserPromptClosedParameters
)

browsingContext.UserPromptClosedParameters = {
  context: browsingContext.BrowsingContext,
  accepted: bool,
  type: browsingContext.UserPromptType,
  ? userContext: browser.UserContext,
  ? userText: text
}

browsingContext.UserPromptOpened = (
  method: "browsingContext.userPromptOpened",
  params: browsingContext.UserPromptOpenedParameters
)

browsingContext.UserPromptOpenedParameters = {
  context: browsingContext.BrowsingContext,
  handler: session.UserPromptHandlerType,
  message: text,
  type: browsingContext.UserPromptType,
  ? userContext: browser.UserContext,
  ? defaultValue: text
}

EmulationResult = (
  emulation.SetForcedColorsModeThemeOverrideResult /
  emulation.SetGeolocationOverrideResult /
  emulation.SetLocaleOverrideResult /
  emulation.SetMediaFeaturesOverrideResult /
  emulation.SetScreenOrientationOverrideResult /
  emulation.SetScriptingEnabledResult /
  emulation.SetScrollbarTypeOverrideResult /
  emulation.SetTextLayoutModeOverrideResult /
  emulation.SetTimezoneOverrideResult /
  emulation.SetTouchOverrideResult /
  emulation.SetUserAgentOverrideResult /
  emulation.SetViewportMetaOverrideResult
)

emulation.SetForcedColorsModeThemeOverrideResult = EmptyResult

emulation.SetGeolocationOverrideResult = EmptyResult

emulation.SetLocaleOverrideResult = EmptyResult

emulation.SetMediaFeaturesOverrideResult = EmptyResult

emulation.SetNetworkConditionsResult = EmptyResult

emulation.SetScreenSettingsOverrideResult = EmptyResult

emulation.SetScreenOrientationOverrideResult = EmptyResult

emulation.SetUserAgentOverrideResult = EmptyResult

emulation.SetViewportMetaOverrideResult = EmptyResult

emulation.SetScriptingEnabledResult = EmptyResult

emulation.SetScrollbarTypeOverrideResult = EmptyResult

emulation.SetTextLayoutModeOverrideResult = EmptyResult

emulation.SetTimezoneOverrideResult = EmptyResult

emulation.SetTouchOverrideResult = EmptyResult

NetworkResult = (
  network.AddDataCollectorResult /
  network.AddInterceptResult /
  network.ContinueRequestResult /
  network.ContinueResponseResult /
  network.ContinueWithAuthResult /
  network.DisownDataResult /
  network.FailRequestResult /
  network.GetDataResult /
  network.ProvideResponseResult /
  network.RemoveDataCollectorResult /
  network.RemoveInterceptResult /
  network.SetCacheBehaviorResult /
  network.SetExtraHeadersResult
)

NetworkEvent = (
    network.AuthRequired //
    network.BeforeRequestSent //
    network.FetchError //
    network.ResponseCompleted //
    network.ResponseStarted
)


network.AuthChallenge = {
  scheme: text,
  realm: text,
}

network.BaseParameters = (
    context: browsingContext.BrowsingContext / null,
    isBlocked: bool,
    navigation: browsingContext.Navigation / null,
    redirectCount: js-uint,
    request: network.RequestData,
    timestamp: js-uint,
    ? userContext: browser.UserContext / null,
    ? intercepts: [+network.Intercept]
)

network.BytesValue = network.StringValue / network.Base64Value;

network.StringValue = {
  type: "string",
  value: text,
}

network.Base64Value = {
  type: "base64",
  value: text,
}

network.Collector = text

network.CollectorType = "blob"

network.SameSite = "strict" / "lax" / "none" / "default"


network.Cookie = {
    name: text,
    value: network.BytesValue,
    domain: text,
    path: text,
    size: js-uint,
    httpOnly: bool,
    secure: bool,
    sameSite: network.SameSite,
    ? expiry: js-uint,
    Extensible,
}

network.DataType = "request" / "response"

network.FetchTimingInfo = {
    timeOrigin: float,
    requestTime: float,
    redirectStart: float,
    redirectEnd: float,
    fetchStart: float,
    dnsStart: float,
    dnsEnd: float,
    connectStart: float,
    connectEnd: float,
    tlsStart: float,

    requestStart: float,
    responseStart: float,

    responseEnd: float,
}

network.Header = {
  name: text,
  value: network.BytesValue,
}

network.Initiator = {
    ? columnNumber: js-uint,
    ? lineNumber: js-uint,
    ? request: network.Request,
    ? stackTrace: script.StackTrace,
    ? type: "parser" / "script" / "preflight" / "other"
}

network.Intercept = text

network.Request = text;

network.RequestData = {
    request: network.Request,
    url: text,
    method: text,
    headers: [*network.Header],
    cookies: [*network.Cookie],
    headersSize: js-uint,
    bodySize: js-uint / null,
    destination: text,
    initiatorType: text / null,
    timings: network.FetchTimingInfo,
}

network.ResponseContent = {
    size: js-uint
}

network.ResponseData = {
    url: text,
    protocol: text,
    status: js-uint,
    statusText: text,
    fromCache: bool,
    headers: [*network.Header],
    mimeType: text,
    bytesReceived: js-uint,
    headersSize: js-uint / null,
    bodySize: js-uint / null,
    content: network.ResponseContent,
    ?authChallenges: [*network.AuthChallenge],
}

network.AddDataCollectorResult = {
  collector: network.Collector
}

network.AddInterceptResult = {
  intercept: network.Intercept
}

network.ContinueRequestResult = EmptyResult

network.ContinueResponseResult = EmptyResult

network.ContinueWithAuthResult = EmptyResult

network.DisownDataResult = EmptyResult

network.FailRequestResult = EmptyResult

network.GetDataResult = {
  bytes: network.BytesValue,
}

network.ProvideResponseResult = EmptyResult

network.RemoveDataCollectorResult = EmptyResult

network.RemoveInterceptResult = EmptyResult

network.SetCacheBehaviorResult = EmptyResult

network.SetExtraHeadersResult = EmptyResult

network.AuthRequired = (
  method: "network.authRequired",
  params: network.AuthRequiredParameters
)

network.AuthRequiredParameters = {
  network.BaseParameters,
  response: network.ResponseData
}

network.BeforeRequestSent = (
  method: "network.beforeRequestSent",
  params: network.BeforeRequestSentParameters
 )

network.BeforeRequestSentParameters = {
  network.BaseParameters,
  ? initiator: network.Initiator,
}

network.FetchError = (
  method: "network.fetchError",
  params: network.FetchErrorParameters
 )

network.FetchErrorParameters = {
  network.BaseParameters,
  errorText: text,
}

network.ResponseCompleted = (
  method: "network.responseCompleted",
  params: network.ResponseCompletedParameters
 )

network.ResponseCompletedParameters = {
  network.BaseParameters,
  response: network.ResponseData,
}

network.ResponseStarted = (
  method: "network.responseStarted",
  params: network.ResponseStartedParameters
 )

network.ResponseStartedParameters = {
  network.BaseParameters,
  response: network.ResponseData,
}

ScriptResult = (
  script.AddPreloadScriptResult /
  script.CallFunctionResult /
  script.DisownResult /
  script.EvaluateResult /
  script.GetRealmsResult /
  script.RemovePreloadScriptResult
)

ScriptEvent = (
  script.Message //
  script.RealmCreated //
  script.RealmDestroyed
)

script.Channel = text;

script.ChannelValue = {
  type: "channel",
  value: script.ChannelProperties,
}

script.ChannelProperties = {
  channel: script.Channel,
  ? serializationOptions: script.SerializationOptions,
  ? ownership: script.ResultOwnership,
}

script.EvaluationResult = (
  script.EvaluationResultSuccess /
  script.EvaluationResultException
)

script.EvaluationResultSuccess = {
  type: "success",
  result: script.RemoteValue,
  realm: script.Realm
}

script.EvaluationResultException = {
  type: "exception",
  exceptionDetails: script.ExceptionDetails
  realm: script.Realm
}

script.ExceptionDetails = {
  columnNumber: js-uint,
  exception: script.RemoteValue,
  lineNumber: js-uint,
  stackTrace: script.StackTrace,
  text: text,
}

script.Handle = text;

script.InternalId = text;

script.LocalValue = (
  script.RemoteReference /
  script.PrimitiveProtocolValue /
  script.ChannelValue /
  script.ArrayLocalValue /
  { script.DateLocalValue } /
  script.MapLocalValue /
  script.ObjectLocalValue /
  { script.RegExpLocalValue } /
  script.SetLocalValue
)

script.ListLocalValue = [*script.LocalValue];

script.ArrayLocalValue = {
  type: "array",
  value: script.ListLocalValue,
}

script.DateLocalValue = (
  type: "date",
  value: text
)

script.MappingLocalValue = [*[(script.LocalValue / text), script.LocalValue]];

script.MapLocalValue = {
  type: "map",
  value: script.MappingLocalValue,
}

script.ObjectLocalValue = {
  type: "object",
  value: script.MappingLocalValue,
}

script.RegExpValue = {
  pattern: text,
  ? flags: text,
}

script.RegExpLocalValue = (
  type: "regexp",
  value: script.RegExpValue,
)

script.SetLocalValue = {
  type: "set",
  value: script.ListLocalValue,
}

script.PreloadScript = text;

script.Realm = text;

script.PrimitiveProtocolValue = (
  script.UndefinedValue /
  script.NullValue /
  script.StringValue /
  script.NumberValue /
  script.BooleanValue /
  script.BigIntValue
)

script.UndefinedValue = {
  type: "undefined",
}

script.NullValue = {
  type: "null",
}

script.StringValue = {
  type: "string",
  value: text,
}

script.SpecialNumber = "NaN" / "-0" / "Infinity" / "-Infinity";

script.NumberValue = {
  type: "number",
  value: number / script.SpecialNumber,
}

script.BooleanValue = {
  type: "boolean",
  value: bool,
}

script.BigIntValue = {
  type: "bigint",
  value: text,
}

script.RealmInfo = (
  script.WindowRealmInfo /
  script.DedicatedWorkerRealmInfo /
  script.SharedWorkerRealmInfo /
  script.ServiceWorkerRealmInfo /
  script.WorkerRealmInfo /
  script.PaintWorkletRealmInfo /
  script.AudioWorkletRealmInfo /
  script.WorkletRealmInfo
)

script.BaseRealmInfo = (
  realm: script.Realm,
  origin: text
)

script.WindowRealmInfo = {
  script.BaseRealmInfo,
  type: "window",
  context: browsingContext.BrowsingContext,
  ? userContext: browser.UserContext,
  ? sandbox: text
}

script.DedicatedWorkerRealmInfo = {
  script.BaseRealmInfo,
  type: "dedicated-worker",
  owners: [script.Realm]
}

script.SharedWorkerRealmInfo = {
  script.BaseRealmInfo,
  type: "shared-worker"
}

script.ServiceWorkerRealmInfo = {
  script.BaseRealmInfo,
  type: "service-worker"
}

script.WorkerRealmInfo = {
  script.BaseRealmInfo,
  type: "worker"
}

script.PaintWorkletRealmInfo = {
  script.BaseRealmInfo,
  type: "paint-worklet"
}

script.AudioWorkletRealmInfo = {
  script.BaseRealmInfo,
  type: "audio-worklet"
}

script.WorkletRealmInfo = {
  script.BaseRealmInfo,
  type: "worklet"
}

script.RealmType = "window" / "dedicated-worker" / "shared-worker" / "service-worker" /
                   "worker" / "paint-worklet" / "audio-worklet" / "worklet"

script.RemoteReference = (
  script.SharedReference /
  script.RemoteObjectReference
)

script.SharedReference = {
   sharedId: script.SharedId

   ? handle: script.Handle,
   Extensible
}

script.RemoteObjectReference = {
   handle: script.Handle,

   ? sharedId: script.SharedId
   Extensible
}

script.RemoteValue = (
  script.PrimitiveProtocolValue /
  script.SymbolRemoteValue /
  script.ArrayRemoteValue /
  script.ObjectRemoteValue /
  script.FunctionRemoteValue /
  script.RegExpRemoteValue /
  script.DateRemoteValue /
  script.MapRemoteValue /
  script.SetRemoteValue /
  script.WeakMapRemoteValue /
  script.WeakSetRemoteValue /
  script.GeneratorRemoteValue /
  script.ErrorRemoteValue /
  script.ProxyRemoteValue /
  script.PromiseRemoteValue /
  script.TypedArrayRemoteValue /
  script.ArrayBufferRemoteValue /
  script.NodeListRemoteValue /
  script.HTMLCollectionRemoteValue /
  script.NodeRemoteValue /
  script.WindowProxyRemoteValue
)

script.ListRemoteValue = [*script.RemoteValue];

script.MappingRemoteValue = [*[(script.RemoteValue / text), script.RemoteValue]];

script.SymbolRemoteValue = {
  type: "symbol",
  ? handle: script.Handle,
  ? internalId: script.InternalId,
}

script.ArrayRemoteValue = {
  type: "array",
  ? handle: script.Handle,
  ? internalId: script.InternalId,
  ? value: script.ListRemoteValue,
}

script.ObjectRemoteValue = {
  type: "object",
  ? handle: script.Handle,
  ? internalId: script.InternalId,
  ? value: script.MappingRemoteValue,
}

script.FunctionRemoteValue = {
  type: "function",
  ? handle: script.Handle,
  ? internalId: script.InternalId,
}

script.RegExpRemoteValue = {
  script.RegExpLocalValue,
  ? handle: script.Handle,
  ? internalId: script.InternalId,
}

script.DateRemoteValue = {
  script.DateLocalValue,
  ? handle: script.Handle,
  ? internalId: script.InternalId,
}

script.MapRemoteValue = {
  type: "map",
  ? handle: script.Handle,
  ? internalId: script.InternalId,
  ? value: script.MappingRemoteValue,
}

script.SetRemoteValue = {
  type: "set",
  ? handle: script.Handle,
  ? internalId: script.InternalId,
  ? value: script.ListRemoteValue
}

script.WeakMapRemoteValue = {
  type: "weakmap",
  ? handle: script.Handle,
  ? internalId: script.InternalId,
}

script.WeakSetRemoteValue = {
  type: "weakset",
  ? handle: script.Handle,
  ? internalId: script.InternalId,
}

script.GeneratorRemoteValue = {
  type: "generator",
  ? handle: script.Handle,
  ? internalId: script.InternalId,
}

script.ErrorRemoteValue = {
  type: "error",
  ? handle: script.Handle,
  ? internalId: script.InternalId,
}

script.ProxyRemoteValue = {
  type: "proxy",
  ? handle: script.Handle,
  ? internalId: script.InternalId,
}

script.PromiseRemoteValue = {
  type: "promise",
  ? handle: script.Handle,
  ? internalId: script.InternalId,
}

script.TypedArrayRemoteValue = {
  type: "typedarray",
  ? handle: script.Handle,
  ? internalId: script.InternalId,
}

script.ArrayBufferRemoteValue = {
  type: "arraybuffer",
  ? handle: script.Handle,
  ? internalId: script.InternalId,
}

script.NodeListRemoteValue = {
  type: "nodelist",
  ? handle: script.Handle,
  ? internalId: script.InternalId,
  ? value: script.ListRemoteValue,
}

script.HTMLCollectionRemoteValue = {
  type: "htmlcollection",
  ? handle: script.Handle,
  ? internalId: script.InternalId,
  ? value: script.ListRemoteValue,
}

script.NodeRemoteValue = {
  type: "node",
  ? sharedId: script.SharedId,
  ? handle: script.Handle,
  ? internalId: script.InternalId,
  ? value: script.NodeProperties,
}

script.NodeProperties = {
  nodeType: js-uint,
  childNodeCount: js-uint,
  ? attributes: {*text => text},
  ? children: [*script.NodeRemoteValue],
  ? localName: text,
  ? mode: "open" / "closed",
  ? namespaceURI: text,
  ? nodeValue: text,
  ? shadowRoot: script.NodeRemoteValue / null,
}

script.WindowProxyRemoteValue = {
  type: "window",
  value: script.WindowProxyProperties,
  ? handle: script.Handle,
  ? internalId: script.InternalId
}

script.WindowProxyProperties = {
  context: browsingContext.BrowsingContext
}

script.ResultOwnership = "root" / "none"

script.SerializationOptions = {
  ? maxDomDepth: (js-uint / null) .default 0,
  ? maxObjectDepth: (js-uint / null) .default null,
  ? includeShadowTree: ("none" / "open" / "all") .default "none",
}

script.SharedId = text;

script.StackFrame = {
  columnNumber: js-uint,
  functionName: text,
  lineNumber: js-uint,
  url: text,
}

script.StackTrace = {
  callFrames: [*script.StackFrame],
}

script.Source = {
  realm: script.Realm,
  ? context: browsingContext.BrowsingContext,
  ? userContext: browser.UserContext
}

script.AddPreloadScriptResult = {
  script: script.PreloadScript
}

script.DisownResult = EmptyResult

script.CallFunctionResult = script.EvaluationResult

script.EvaluateResult = script.EvaluationResult

script.GetRealmsResult = {
  realms: [*script.RealmInfo]
}

script.RemovePreloadScriptResult = EmptyResult

script.Message = (
  method: "script.message",
  params: script.MessageParameters
 )

script.MessageParameters = {
  channel: script.Channel,
  data: script.RemoteValue,
  source: script.Source,
}

script.RealmCreated = (
 method: "script.realmCreated",
 params: script.RealmInfo
)

script.RealmDestroyed = (
  method: "script.realmDestroyed",
  params: script.RealmDestroyedParameters
)

script.RealmDestroyedParameters = {
  realm: script.Realm
}


StorageResult = (
  storage.DeleteCookiesResult /
  storage.GetCookiesResult /
  storage.SetCookieResult
)

storage.PartitionKey = {
  ? userContext: text,
  ? sourceOrigin: text,
  Extensible,
}

storage.GetCookiesResult = {
  cookies: [*network.Cookie],
  partitionKey: storage.PartitionKey,
}

storage.SetCookieResult = {
  partitionKey: storage.PartitionKey
}

storage.DeleteCookiesResult = {
  partitionKey: storage.PartitionKey
}

LogEvent = (
  log.EntryAdded
)

log.Level = "debug" / "info" / "warn" / "error"

log.Entry = (
  log.GenericLogEntry /
  log.ConsoleLogEntry /
  log.JavascriptLogEntry
)

log.BaseLogEntry = (
  level: log.Level,
  source: script.Source,
  text: text / null,
  timestamp: js-uint,
  ? stackTrace: script.StackTrace,
)

log.GenericLogEntry = {
  log.BaseLogEntry,
  type: text,
}

log.ConsoleLogEntry = {
  log.BaseLogEntry,
  type: "console",
  method: text,
  args: [*script.RemoteValue],
}

log.JavascriptLogEntry = {
  log.BaseLogEntry,
  type: "javascript",
}

log.EntryAdded = (
 method: "log.entryAdded",
 params: log.Entry,
)

InputResult = (
  input.PerformActionsResult /
  input.ReleaseActionsResult /
  input.SetFilesResult
)

InputEvent = (
  input.FileDialogOpened
)

input.PerformActionsResult = EmptyResult

input.ReleaseActionsResult = EmptyResult

input.SetFilesResult = EmptyResult

input.FileDialogOpened = (
   method: "input.fileDialogOpened",
   params: input.FileDialogInfo
)

input.FileDialogInfo = {
   context: browsingContext.BrowsingContext,
   ? userContext: browser.UserContext,
   ? element: script.SharedReference,
   multiple: bool,
}

WebExtensionResult = (
  webExtension.InstallResult /
  webExtension.UninstallResult
)

webExtension.Extension = text

webExtension.InstallResult = {
  extension: webExtension.Extension
}

webExtension.UninstallResult = EmptyResult

议题索引

肯定有一种更好的机制来实现这种“等待事件”的事情。 ↵
我们是否应该采用类似微任务的机制,以确保它在 事件循环中的任何其他任务之前运行? ↵
这是否应该作为附录? ↵
对于单个会话,我们是否支持 > 1 个连接? ↵
似乎没有任何内容定义 UTF-8 错误使用什么状态代码 。 ↵
需要挂接到会话结束过程,以允许 UA 在需要时关闭 监听器。 ↵
定义沙箱 Realm 的创建。这将返回一个 SandboxWindowProxy,包装 window。 ↵
详细定义 SandboxProxy 如何工作 ↵
定义其工作方式。 ↵
尚不清楚这是否是正式定义 用户上下文概念或其与存储交互的最佳方式。 ↵
我们是否应该规定具有非 null opener 的顶级 可遍历对象,与 其 opener 具有相同的关联用户上下文? 需要检查这是否是现有实现强制执行的行为。 ↵
这里的措辞相当不精确,但希望能清楚表达: 我们的意图是在开始关闭连接 之前先发送命令响应。 ↵
这也需要泛化为适用于 Realm。 ↵
这也需要泛化为适用于 Realm。 ↵
正确规定 ignore cache 标志如何工作。这需要 考虑是否只有资源的首次加载绕过缓存 (即,这是否类似于最初清除缓存后再正常 继续),或者不是由 HTML 解析器直接加载的资源 (例如由脚本或样式表发起的加载)是否也绕过缓存。 ↵
这里通过错误暴露的失败内容及其原因 是否提供了足够的信息?我们希望使用什么错误代码?是否会出现 本地端解析由实现定义的字符串,以确定 实际出错原因的问题? ↵
这应该以某种更明确的方式集成到更新 渲染算法中。 [w3c/webdriver-bidi 问题 #1131] ↵
关于关闭最后一个顶级 可遍历对象时的行为,目前存在一个开放讨论。我们可以选择关闭 浏览器、关闭会话,或将此留给实现决定。 [w3c/webdriver-bidi 问题 #170] ↵
这应该以某种更明确的方式集成到更新 渲染算法中。 [w3c/webdriver-bidi 问题 #1131] ↵
按当前写法,该算法存在竞态条件,因为当我们 尝试导航时,目标会话历史记录条目可能已经 不存在。一旦我们支持等待历史记录进行导航,就可以更 稳健地处理这一点。 ↵
我们是否要公开一个 `browsingContext.pageShow` event? 在这种情况下,我们 需要在每次即将发出 `pageshow` 时调用此项,而不仅仅是在 bfcache 恢复时,并且还要将 persisted 状态添加到数据中。 ↵
尚不清楚我们是否应该只为具有活动文档的浏览 上下文触发此事件;导航也可能导致上下文 变得不可访问,但由于 bfcache 尚未被丢弃。 ↵
将此算法移至屏幕方向规范。 ↵
这会阻止收集与可导航对象无关的数据。 我们仍然需要获取可导航对象,以根据收集器 配置进行检查,但这里仍然可以接受 null。 ↵
这里没有取消身份验证的方法。 ↵
我们是否应该包含 Realm 之外的参数? ↵
与 Fetch 中一样,尚不清楚这是否是处理多个 标头、解析问题等的正确方式。 ↵
考虑除了上下文之外,还包含发起 请求的文档节点的 `sharedId`。 ↵
考虑一个“request already sent”错误。 ↵
允许设置精确的错误类型 [问题 #508] ↵
遵循 Fetch 的“HTTP-network-or-cache fetch”算法中的返回值。 ↵
这里使用了错误的错误代码 ↵
这里没有处理孤立代理项 ↵
处理“stale object reference”情况。 ↵
添加 WASM 类型? ↵
WindowProxy 是否应该以类似 Node 的方式获取属性? ↵
是否要特殊处理 String / Number / 等包装对象? ↵
重新考虑镜像对象的生命周期。 ↵
children 与子节点是不同的东西。childNodeCount 应该 引用 childNodes,或者应将其重命名为 childrenCount。 ↵
这里使用了错误的错误代码 ↵
这里使用了错误的错误代码 ↵
TODO:添加 script.evaluate 中所述的超时参数。 ↵
扩展此项,使其也允许 Realm 父级,例如用于嵌套 worker?或者获取所有祖先 worker。 ↵
我们可能希望拥有一个比单纯字面值 匹配更复杂的过滤系统。 ↵
这里的顺序是否应该定义得更明确? ↵
我们要按浏览上下文还是按顶级可遍历对象对此进行键控? 区别在于:如果事件发生在某个框架中,而该框架随后 在本地端订阅顶级 可导航对象的日志事件之前发生导航,会出现什么情况。 ↵
还有很多东西需要记录日志。CDP 具有 LogEntryAdded 类型 xml、 javascript、network、storage、appcache、rendering、security、deprecation、 worker、violation、intervention、recommendation、other。除此之外,还有 由不同方法表示的 js 异常和 console API 类型。 ↵
允许由实现定义的日志类型 ↵
在 https://github.com/w3c/csswg-drafts/pull/13549 合并后移除。 ↵
在 https://github.com/w3c/csswg-drafts/pull/13548 合并后移除。 ↵