受控框架 API

社区组报告草案,

本版本:
https://wicg.github.io/controlled-frame/
问题跟踪:
GitHub
规范内联
编辑:
(Google LLC)
(Google LLC)
(Google LLC)

摘要

本文档定义了一种 API,用于仅在隔离 Web 应用(IWA)的上下文中 嵌入任意 Web 内容。被嵌入的 内容是在嵌入者内部并受其控制的一个新的顶级浏览上下文。

本文档的状态

本规范由 Web Platform Incubator Community Group 发布。 它不是 W3C 标准,也不在 W3C 标准轨道上。 请注意,根据 W3C 社区贡献者许可协议 (CLA) 存在有限的退出选择,并且适用其他条件。 了解更多关于 W3C 社区和业务组的信息。

1. 简介

本规范描述了一种内容嵌入 API,它满足 IWA 的一些 关键用例,而这些用例是 iframe 不支持的。该嵌入 环境应允许在没有被嵌入站点明确许可的情况下嵌入所有内容, 包括 iframe 无法嵌入的内容,并让 嵌入站点对这些被嵌入内容拥有更多控制。

由于这是一个特别强大的 API,其使用和可用性会使应用 成为各种类型黑客攻击的目标。因此,该 API 仅限用于 已具备额外安全 保障以保护用户和开发者的隔离 Web 应用(IWA)。IWA 不是普通的 Web 应用,并且只能存在于特殊的 'isolated-app:' 方案下。这意味着 按设计,该 API 不会对普通网页可用。

注:该 API 并不打算作为 iframe 的替代品或 代用品。所有 iframe 用例仍然有效,并且应继续使用 iframe, 包括在可能的情况下用于 IWA。

2. Fenced Frame 规范

为方便起见,Controlled Frame 规范假定 Fenced Frame 规范已经存在。Fenced Frame 规范中引入了一些概念,例如嵌套的顶级 traversable,这些概念在 Controlled Frame 的上下文中被引用时非常有用。

Fenced Frame 规范通过对某些规范(例如 HTML)打猴子 补丁来定义这些概念。本 Controlled Frame 规范的某些部分 也需要对规范打猴子补丁。

3. controlledframe 元素

类别:
流内容。
短语内容。
嵌入内容。
交互内容。
可感知内容。
可以使用该元素的上下文:
预期使用嵌入内容的位置。
内容模型:
无内容。
内容属性:
全局属性
src — 要嵌入的内容源 URL
partition — 用于保存与此内容相关数据的分区名称
无障碍考虑事项:
面向作者。
面向实现者。

注:这些链接指向 iframe 元素的无障碍 定义。 从无障碍的角度来看, controlledframe 应与 iframe 表现相同。

DOM 接口:
[Exposed=Window, IsolatedContext]
interface HTMLControlledFrameElement : HTMLElement {
    [HTMLConstructor] constructor();

    [CEReactions] attribute USVString src;
    attribute DOMString partition;

    readonly attribute WindowProxy? contentWindow;
    readonly attribute ContextMenus contextMenus;
    readonly attribute WebRequest request;

    // Navigation methods.
    Promise<boolean> back();
    Promise<boolean> canGoBack();
    Promise<boolean> forward();
    Promise<boolean> canGoForward();
    Promise<boolean> go(long relativeIndex);
    undefined reload();
    undefined stop();

    // Scripting methods.
    Promise<undefined> addContentScripts(sequence<ContentScriptDetails> contentScriptList);
    Promise<any> executeScript(optional InjectDetails details = {});
    Promise<undefined> insertCSS(optional InjectDetails details = {});
    Promise<undefined> removeContentScripts(optional sequence<DOMString> scriptNameList);

    // Configuration methods.
    Promise<undefined> clearData(
      optional ClearDataOptions options = {},
      optional ClearDataTypeSet types = {});
    Promise<boolean> getAudioState();
    Promise<long> getZoom();
    Promise<DOMString> getZoomMode();
    Promise<boolean> isAudioMuted();
    undefined setAudioMuted(boolean mute);
    Promise<undefined> setZoom(long zoomFactor);
    Promise<undefined> setZoomMode(DOMString zoomMode);

    // Capture methods.
    Promise<undefined> captureVisibleRegion(optional ImageDetails options = {});
    undefined print();

    // Events.
    attribute EventHandler onconsolemessage;
    attribute EventHandler oncontentload;
    attribute EventHandler ondialog;
    attribute EventHandler onloadabort;
    attribute EventHandler onloadcommit;
    attribute EventHandler onloadstart;
    attribute EventHandler onloadstop;
    attribute EventHandler onnewwindow;
    attribute EventHandler onpermissionrequest;
    attribute EventHandler onsizechanged;
    attribute EventHandler onzoomchange;
};

controlledframe 元素表示其嵌入的 navigable。

controlledframe 元素的后代不表示任何内容。

Controlled Frame 元素暴露给任何具有 "controlled-frame" 策略控制特性,且其 环境设置对象是隔离上下文的任何 Document。

IDL 属性 src 和 partition 必须反映 同名的相应内容属性。

每个 controlledframe 都关联有:

contentWindow 获取器 步骤是返回 this 的 contentWindow。

request 获取器步骤 是返回 this 的 request。

contextMenus 获取器 步骤是返回 this 的 contextMenus。

当 controlledframe 元素 element 被插入到一个文档中,且该文档的 浏览上下文为非 null 时,运行以下步骤:
  1. 如果 element 的 src 不为空,则:

    1. 给定 element,初始化 controlledframe。

当 controlledframe 元素 element 被从文档中移除时, 运行以下步骤:
  1. 给定 element 的 嵌入的 navigable,销毁一个顶级 traversable。

  2. 将 element 的嵌入的 navigable设置为 null。

要初始化一个 controlledframe 元素 element,运行 以下步骤:
  1. 断言 element 的嵌入的 navigable为 null。

  2. 令 group 为一个新的浏览上下文组。

  3. 令 document 为给定 element 的节点文档、element 和 group,创建新的浏览上下文和 文档的第二个返回值。

  4. 令 documentState 为一个新的文档状态,其文档 为 document。

  5. 令 traversable 为一个新的traversable navigable。

  6. 给定 documentState,初始化 navigable traversable。

  7. 将 traversable 的 controlledFrameEmbedderParent 设置为 element。

  8. 将 element 的嵌入的 navigable设置为 traversable。

  9. 令 initialHistoryEntry 为 traversable 的活动会话历史条目。

  10. 将 initialHistoryEntry 的步数设置为 0。

  11. 将 initialHistoryEntry 追加到 traversable 的会话历史条目。

    这些步骤 是在新的 navigable 中初始化 History.length 所必需的。这是 HTML 标准中的一个现有 议题。

  12. 将 element 的 contentWindow 设置为 document 的 WindowProxy。

  13. 给定 element 和 element 的 src, 导航 controlledframe。

要导航一个 controlledframe 元素 element,给定一个 USVString urlString,运行以下步骤:
  1. 如果 urlString 不是绝对 URL 字符串,则返回。

  2. 令 url 为给定 urlString 和 element 的节点文档,解析 URL的结果。

  3. 令 historyHandling 为 "auto"。

  4. 如果 element 的嵌入的 navigable的活动文档未 完全加载,则将 historyHandling 设置为 "replace"。

  5. 使用 element 的 节点文档,并以 historyHandling 作为 NavigationHistoryBehavior, 将 element 的嵌入的 navigable导航到 url。

HTMLControlledFrameElement() 构造器步骤为:
  1. 将 this 的request设置为一个新的 WebRequest。

  2. 将 this 的contextMenus设置为一个新的 ContextMenus。

3.1. 通用基础设施

要解决嵌入者 promise,给定一个 controlledframe controlledframe、一个 promise promise 以及一个可选的 value, 运行以下步骤:
  1. 在 controlledframe 的相关全局对象的 DOM 操作任务源上排队一个全局任务,以使用 value 解决 promise。

    注: controlledframe 的相关全局对象是 嵌入者的 Window 对象。

要拒绝嵌入者 promise,给定一个 controlledframe controlledframe、一个 promise promise 以及一个可选的 value, 运行以下步骤:
  1. 在 controlledframe 的相关全局对象的 DOM 操作任务源上排队一个全局任务,以使用 value 拒绝 promise。

    注: controlledframe 的相关全局对象是 嵌入者的 Window 对象。

如果以下步骤返回 true,则一个 URL url 匹配 URLPattern pattern:
  1. 令 result 为给定 pattern 和 url,匹配的结果。

  2. 如果 result 为 null,则返回 false。

  3. 返回 true。

3.2. 属性

partition 属性 接受一个标识符,用于指定与 Controlled Frame 实例相关的数据应存储在哪里。该标识符由一个字母数字字符组成的字符串构成。 嵌入的 navigable的所有数据都必须存储 在一个存储搁板中,该搁板由此分区字符串以及 创建该数据的源共同作为键。

默认情况下,所有存储的数据都必须保存在内存中的存储分区中,这样 当最后一个具有给定 partition 值的 Controlled Frame 元素被销毁时,该数据也会 被销毁。当数据保存在此分区中时,Controlled Frame 的 嵌入的 navigable中的任何数据都不得持久化。

如果 partition 属性标识符包含前缀 "persist:",则用户 代理必须使用基于磁盘的存储环境,而不是内存中的 存储分区。被嵌入内容不应能够检测其 存储是在内存中还是持久的。

如果多个 Controlled Frame 共享同一个分区标识符,则它们的所有 嵌入的 navigable实例必须共享同一个 存储分区。

注:下面会对 [STORAGE] 规范打猴子补丁,以基于 partition 属性的值对存储进行分区。

partition IDL 属性设置器步骤为:
  1. 如果 this 的嵌入的 navigable不是 null,则:

    1. 抛出一个 "NotSupportedError" DOMException。

  2. 将 this 的 partition 设置为给定值。

src 属性 反映 Controlled Frame 的嵌入的 navigable的当前会话历史条目的 URL。

src IDL 属性设置器步骤为:
  1. 如果 this 不在文档树中,则返回。

  2. 如果 this 的嵌入的 navigable为 null,则:

    1. 给定 this,初始化 controlledframe。

  3. 否则:

    1. 给定 this 和给定值,导航 controlledframe。

3.3. 导航方法

back()

在 Controlled Frame 中的 traversable navigable 的整体 会话历史条目列表中后退一步。

返回一个 promise,如果页面成功 后退导航,则解决为 true;如果导航失败或没有上一个 步骤,则解决为 false。

canGoBack()

返回一个 promise,如果当前会话历史条目不是 嵌入的 navigable的 会话历史条目中的第一个条目,则解决为 true。这意味着 该 navigable 还有前一个 会话历史条目。

forward()

在 Controlled Frame 中的 traversable navigable 的整体 会话历史条目列表中前进一步。

返回一个 promise,如果页面成功 前进导航,则解决为 true;如果导航失败或没有下一个 步骤,则解决为 false。

canGoForward()

返回一个 promise,如果当前会话历史条目不是 嵌入的 navigable的 会话历史条目中的最后一个条目,则解决为 true。这意味着 该 navigable 还有下一个 会话历史条目。

go()

重新加载当前页面。

go(relativeIndex)

在当前 traversable navigable 的整体 会话历史条目列表中,后退或前进 relativeIndex 个步骤。

相对索引为零时将重新加载当前页面。

返回一个 promise,如果页面成功 导航,则解决为 true;如果导航失败或提供的相对 索引超出范围,则解决为 false。

reload()

重新加载当前页面。

stop()

取消文档加载。

要增量遍历嵌入的 navigable 的历史, 给定一个 controlledframe controlledframe 和一个整数 delta,运行 以下步骤:
  1. 令 resultPromise 为一个新的 promise。

  2. 返回 resultPromise,并并行运行剩余步骤。

  3. 令 embeddedNavigable 为 controlledframe 的嵌入的 navigable。

  4. 如果 embeddedNavigable 为 null,则给定 controlledframe、resultPromise 和 false,解决嵌入者 promise,并中止这些 步骤。

  5. 如果 embeddedNavigable 的活动文档不是完全活动的, 则给定 controlledframe、resultPromise 和 false,解决嵌入者 promise,并中止这些步骤。

  6. 向 embeddedNavigable 追加以下会话历史 遍历步骤:

    1. 令 allSteps 为对 embeddedNavigable 获取所有已使用历史步骤 的结果。

    2. 令 currentStepIndex 为 embeddedNavigable 的 当前会话历史步骤在 allSteps 中的索引。

    3. 令 targetStepIndex 为 currentStepIndex + delta。

    4. 如果 allSteps[targetStepIndex] 不存在,则 给定 controlledframe、resultPromise 和 false,解决嵌入者 promise,并中止这些步骤。

    5. 令 result 为给定 "none" 的用户导航参与,将 遍历历史步骤 allSteps[targetStepIndex] 应用到 embeddedNavigable 的结果。

    6. 如果 result 不等于 "applied",则给定 controlledframe、resultPromise 和 false, 解决嵌入者 promise。

    7. 否则,给定 controlledframe、 resultPromise 和 true,解决嵌入者 promise。

canGoBack() 方法步骤为:
  1. 令 result 为一个新的 promise。

  2. 令 controlledframe 为 this。

  3. 令 embeddedNavigable 为 controlledframe 的嵌入的 navigable。

  4. 如果 embeddedNavigable 为 null,则用 false 解决 result 并返回 result。

  5. 在 embeddedNavigable 的节点文档的相关全局对象的导航和遍历任务源上 排队一个全局任务,它将运行以下步骤:

    1. 如果 embeddedNavigable 的 当前会话历史步骤 > 0, 则令 canGoBack 为 true,否则为 false。

    2. 给定 controlledframe、result 和 canGoBack,解决嵌入者 promise。

  6. 返回 result。

canGoForward() 方法步骤为:
  1. 令 result 为一个新的 promise。

  2. 令 controlledframe 为 this。

  3. 令 embeddedNavigable 为 controlledframe 的嵌入的 navigable。

  4. 如果 embeddedNavigable 为 null,则用 false 解决 result 并返回 result。

  5. 在 embeddedNavigable 的节点文档的相关全局对象的 导航和遍历任务源上 排队一个全局任务,它将运行以下步骤:

    1. 令 step 为 embeddedNavigable 的当前会话历史步骤。

    2. 令 steps 为给定 embeddedNavigable,获取所有已使用历史步骤 的结果。

    3. 如果 step + 1 < steps 的大小, 则令 canGoForward 为 true,否则为 false。

    4. 给定 controlledframe、result 和 canGoForward,解决嵌入者 promise。

  6. 返回 result。

back() 方法步骤为:
  1. 返回给定 this 和 -1,增量遍历嵌入的 navigable 的历史的结果。

forward() 方法步骤 为:
  1. 返回给定 this 和 1,增量遍历嵌入的 navigable 的历史的结果。

go(relativeIndex) 方法步骤为:
  1. 返回给定 this 和 relativeIndex,增量遍历嵌入的 navigable 的历史的结果。

reload() 步骤为:
  1. 令 embeddedNavigable 为 this 的嵌入的 navigable。

  2. 如果 embeddedNavigable 为 null,则返回。

  3. 在 embeddedNavigable 的节点文档的相关全局对象的 导航和遍历任务源上 排队一个全局任务,它将给定 "none" 的 用户导航参与,重新加载 embeddedNavigable。

stop() 步骤为:
  1. 令 embeddedNavigable 为 this 的嵌入的 navigable。

  2. 如果 embeddedNavigable 为 null,则返回。

  3. 在 embeddedNavigable 的节点文档的相关全局对象的 导航和遍历任务源上 排队一个全局任务,它将停止加载 embeddedNavigable。

3.4. 脚本方法

// One of |code| or |file| must be specified but not both.
dictionary InjectDetails {
  DOMString code;
  USVString file;
};

dictionary InjectionItems {
  DOMString code;
  sequence<USVString> files;
};

enum RunAt {
  "document-start",
  "document-end",
  "document-idle",
};

dictionary ContentScriptDetails {
  required DOMString name;
  InjectionItems js;
  InjectionItems css;
  required sequence<(URLPattern or URLPatternInput)> urlPatterns;
  sequence<(URLPattern or URLPatternInput)> excludeURLPatterns;
  boolean allFrames;
  boolean matchAboutBlank;
  RunAt runAt;
};

内容脚本 配置是一个具有以下 项的结构:

pendingFetchCount

一个表示待处理脚本/样式获取次数的 long。

js

一个 DOMString 的列表, 其中包含将被注入到文档中的 JavaScript。

css

一个 DOMString 的列表, 其中包含将被注入到 文档中的 CSS。

urlPatterns

一个 URLPattern 的列表。

注:如果文档的 URL 匹配这些模式中的任意一个,则内容可能会被注入到该文档中。

excludeURLPatterns

一个 URLPattern 的列表。

注:如果文档的 URL 匹配这些 模式中的任意一个,则内容不会被注入到该 文档中。这会覆盖 urlPattern;如果两个列表都包含 文档的 URL 所匹配的条目,则内容不会被 注入到该文档中。

allFrames

一个指示内容是否应被注入到页面中的所有 框架,还是仅顶级框架的布尔值。

matchAboutBlank

一个指示内容是否应被注入到 about:blank 页面的布尔值。

runAt

一个 RunAt, 指示 JavaScript 内容应在文档生命周期的何时执行。

要获取一个 注入项,给定一个 controlledframe controlledframe、一个 USVString urlString、一个 布尔值 isCss、一个 long index,以及一个接受 long、 一个 boolean 和一个 DOMString 的算法 completionSteps,运行以下步骤:

注:这里不能使用获取经典脚本,因为获取 需要使用 controlledframe 的相关设置对象,但 经典脚本是使用嵌入的 navigable的 活动文档的相关设置对象执行的。

  1. 如果 urlString 不是有效 URL 字符串,则:

    1. 给定 0、false 和 "",运行 completionSteps。

    2. 返回。

  2. 令 request 为一个具有以下字段的新请求:

    URL

    给定 urlString 和 controlledframe 的节点文档,解析 URL的结果。

    method

    "GET"

    destination

    如果 isCss 为 true,则为 "style",否则为 "script"

    client

    controlledframe 的相关设置对象

    mode

    "cors"

  3. 获取 request,并将 processResponseConsumeBody 设置为以下步骤,给定一个 响应 response 和一个 null、failure 或 字节序列 contents:

    1. 如果 response 的状态不是 200,或 contents 为 null 或 failure,则给定 0、false 和 "" 运行 completionSteps

    2. 否则,给定 index、true 和 contents 运行 completionSteps。

要验证并解析 ContentScriptDetails, 给定一个 controlledframe controlledframe 和一个 ContentScriptDetails details,运行以下步骤:
  1. 令 result 为一个新的 promise。

  2. 如果 details["js"] 和 details["css"] 均已定义,或均 未定义,则用 TypeError 拒绝 result,并返回它。

  3. 如果 details["urlPatterns"] 为空, 则用 TypeError 拒绝 result,并返回它。

  4. 令 isCss 为一个布尔值,如果 details["css"] 已定义,则等于 true,否则等于 false。

  5. 如果 isCss 为 true 且 details["runAt"] 不等于 "document-start", 则用 TypeError 拒绝 result,并返回它。

  6. 如果 isCss 为 true,则令 injectionItems 为 details["css"], 否则为 details["js"]。

  7. 如果 injectionItems["code"] 和 injectionItems["files"] 均已定义,或均 未定义,则用 TypeError 拒绝 result,并返回它。

  8. 返回 result,并并行运行剩余步骤。

  9. 令 config 为一个新的内容脚本配置,具有以下值:

    pendingFetchCount

    0

    urlPatterns

    «»

    excludeURLPatterns

    «»

    allFrames

    如果已定义,则为 details["allFrames"], 否则为 false

    matchAboutBlank

    如果已定义,则为 details["matchAboutBlank"], 否则为 false

    runAt

    如果已定义,则为 details["runAt"], 否则为 document-idle

  10. 对于 details["urlPatterns"] 中的每个 urlPattern:

    1. 如果 urlPattern 是一个 URLPattern, 则将 urlPattern 追加到 config 的urlPatterns。

    2. 否则,给定 urlPattern,将一个新的 URLPattern 追加到 config 的urlPatterns。

  11. 如果 details["excludeURLPatterns"] 已定义, 则:

    1. 对于 details["excludeURLPatterns"] 中的每个 urlPattern:

      1. 如果 urlPattern 是一个 URLPattern, 则将 urlPattern 追加到 config 的 excludeURLPatterns。

      2. 否则,给定 urlPattern,将一个新的 URLPattern 追加到 config 的 excludeURLPatterns。

  12. 令 completionSteps 为以下算法,其接受一个 long index、一个 布尔值 success 和一个 DOMString source:

    1. 如果 success 为 false,则给定 controlledframe、result 和 TypeError, 拒绝嵌入者 promise,并中止 这些步骤。

    2. 如果 isCss,则:

      1. 将 config 的 css[index] 设置为 source。

    3. 否则:

      1. 将 config 的 js[index] 设置为 source。

    4. 递减 config 的 pendingFetchCount。

    5. 如果 config 的 pendingFetchCount 大于 0,则返回。

    6. 将 controlledframe 的内容脚本 映射[details[name]] 设置为 config。

    7. 给定 controlledframe 和 result,解决嵌入者 promise。

  13. 如果 injectionItems["code"] 已定义,则:

    1. 给定 0、true 和 injectionItems ["code"],运行 completionSteps。

  14. 否则:

    1. 如果 injectionItems["files"] 为空,则 给定 controlledframe、result 和 TypeError,拒绝嵌入者 promise, 并中止这些步骤。

    2. 对于 injectionItems ["files"] 的每个 urlString:

      1. 给定 controlledframe、 urlString、isCss、config 的 pendingFetchCount 和 completionSteps,运行获取注入项。

      2. 递增 config 的 pendingFetchCount。

要确定一个内容脚本配置是否适用于某个文档, 给定一个内容 脚本配置 config、一个 URL url 和一个 布尔值 isTopLevel,运行以下步骤:
  1. 如果 isTopLevel 为 false,且 config 的 allFrames 为 false,则 返回 false。

  2. 如果 url 匹配 about:blank,且 config 的 matchAboutBlank 为 false,则返回 false。

  3. 令 urlString 为 序列化 url 的结果。

  4. 令 match 为 false。

  5. 对于 config 的 urlPatterns 的每个 pattern:

    1. 如果 urlString 匹配 URLPattern pattern,则将 match 设置为 true。

  6. 对于 config 的 excludeURLPatterns 的每个 pattern:

    1. 如果 urlString 匹配 URLPattern pattern,则将 match 设置为 false。

  7. 返回 match。

要将内容脚本注入到文档中,给定一个 Document document,以及一个 RunAt currentPhase,运行以下步骤:
  1. 令 embeddedNavigable 为 document 的节点 navigable的 traversable navigable。

  2. 如果 embeddedNavigable 为 null,或其 controlledFrameEmbedderParent 为 null,则 返回。

  3. 令 controlledframe 为 embeddedNavigable 的 controlledFrameEmbedderParent。

  4. 令 url 为 document 的 URL。

  5. 如果 document 的节点 navigable的 parent 为 null,则令 isTopLevel 为 true,否则为 false。

  6. 对于 controlledframe 的 内容脚本映射中的每个 config:

    1. 如果给定 config、url 和 isTopLevel,确定内容脚本配置是否适用于文档的结果等于 false,则继续。

    2. 如果 currentPhase 等于 document-start 且 config 的 css 不是空, 则:

      1. 对于 config 的 css 的每个 styleSource,给定 document 和 styleSource,运行将样式表注入到 文档中。

    3. 否则,如果 currentPhase 等于 config 的 runAt,则:

      1. 对于 config 的 js 的每个 scriptSource,给定 document、scriptSource 和一个 空 算法,运行将脚本注入到 文档中。

要将样式表注入到文档中,给定一个 Document document 和一个 DOMString styleSource,运行以下步骤:
  1. 令 styleSheet 为一个新的 CSS 样式表对象。

  2. 给定 styleSheet 和 styleSource,同步替换 CSSStyleSheet 的规则。

  3. 在 document 的全局对象的 DOM 操作任务源上排队一个全局任务,以给定 document 和 styleSheet,添加 CSS 样式表。

以下算法在 Document 的 环境中执行脚本,但这不是期望的行为。目标是让该 算法在一个与 Document 环境隔离、具有不同全局对象但共享对 DOM 的访问权限的环境中执行脚本;但使用当前 HTML 规范基础设施 无法对此进行规范化。这个执行环境在 Blink 中称为 Isolated World,它使用该环境在扩展中执行 内容脚本。关于其执行模型的更多详细信息,请参见此 图示。Gecko 使用一种类似的方法,称为 Xray vision。该算法最终应描述一种可被规范化、并可由所有浏览器实现的 这种隔离的实现。

要将 脚本注入到文档中,给定一个 Document document、 一个 DOMString scriptSource,以及一个接受 完成记录的算法 completionSteps,运行以下步骤:

注:执行 scriptSource 时会故意不设置 document.currentScript。

  1. 令 script 为给定 scriptSource、document 的相关设置对象、document 的 URL,以及默认脚本获取选项,创建经典脚本的结果。

  2. 在 document 的全局对象的 DOM 操作任务源上排队一个全局任务,该任务将运行以下步骤:

    1. 令 completionRecord 为给定 script,运行经典脚本 的结果。

    2. 令 controlledframe 为 document 的节点 navigable的 traversable navigable的controlledFrameEmbedderParent。

    3. 在 controlledframe 的相关全局对象的 DOM 操作任务源上排队一个全局任务,该任务将以 completionRecord 运行 completionSteps。

addContentScripts(contentScriptList) 方法步骤为:
  1. 如果 contentScriptList 为空,则返回 一个以 TypeError 拒绝的新 promise。

  2. 令 promises 为空列表。

  3. 对于 contentScriptList 中的每个 contentScript:

    1. 令 promise 为给定 contentScript,调用验证并解析 ContentScriptDetails的结果。

    2. 将 promise 追加到 promises。

  4. 返回给定 promises,获取一个等待所有 promise 的 promise 的结果。

removeContentScripts(scriptNameList) 方法步骤为:
  1. 令 result 为一个新的 promise。

  2. 令 controlledframe 为 this。

  3. 返回 result,并并行运行剩余步骤。

  4. 如果 scriptNameList 为 undefined,则:

    1. 清空 controlledframe 的内容脚本映射。

  5. 否则,对于 scriptNameList 的每个 name:

    1. 移除 controlledframe 的内容脚本 映射[name]。

  6. 给定 controlledframe 和 result,解决嵌入者 promise。

executeScript(details) 方法步骤为:
  1. 令 result 为一个新的 promise。

  2. 令 controlledframe 为 this。

  3. 返回 result,并并行运行剩余步骤。

  4. 如果 controlledframe 的嵌入的 navigable为 null,则给定 controlledframe、result 和一个 TypeError, 拒绝嵌入者 promise,并中止这些步骤。

  5. 如果 details["code"] 和 details"[file"] 两者都已定义或两者都 未定义,则给定 controlledframe、 result 和一个 TypeError,拒绝嵌入者 promise, 并中止这些步骤。

  6. 令 executionSteps 为以下算法,它接受一个 long 和 一个 DOMString 或 布尔值 scriptString:

    1. 如果 scriptString 不是 DOMString, 则给定 controlledframe、result 和一个 TypeError, 拒绝嵌入者 promise, 并中止这些步骤。

    2. 令 document 为 controlledframe 的嵌入的 navigable的 活动文档。

    3. 给定 document、scriptString 以及以下接受完成记录 completionRecord 的算法,将脚本注入到文档中:

      1. 如果 completionRecord 是正常 完成,则:

        1. 给定 controlledframe、 result 和 completionRecord.[[Value]],解决嵌入者 promise。

      2. 否则:

        1. 给定 controlledframe、 result 和 completionRecord.[[Value]],拒绝嵌入者 promise。

  7. 如果 details["code"] 已定义,则给定 0 和 details["code"],运行 executionSteps。

  8. 否则,给定 controlledframe、 details["file"]、 false、0 和 executionSteps,获取一个注入项。

insertCSS(details) 方法步骤为:
  1. 令 result 为一个新的 promise。

  2. 令 controlledframe 为 this。

  3. 返回 result,并并行运行剩余步骤。

  4. 如果 controlledframe 的嵌入的 navigable为 null,则 给定 controlledframe、result 和一个 TypeError, 拒绝嵌入者 promise, 并中止这些步骤。

  5. 如果 details["code"] 和 details["file"] 两者都已定义或两者都 未定义,则给定 controlledframe、 result 和一个 TypeError,拒绝嵌入者 promise, 并中止这些步骤。

  6. 令 executionSteps 为以下算法,它接受一个 long、 一个 布尔值 success 和一个 DOMString styleString:

    1. 如果 success 为 false,则给定 controlledframe、result 和一个 TypeError, 拒绝 嵌入者 promise,并中止这些 步骤。

    2. 令 document 为 controlledframe 的嵌入的 navigable的 活动文档。

    3. 给定 document 和 styleString,将样式表注入到 文档中。

    4. 给定 controlledframe 和 result,解决嵌入者 promise。

  7. 如果 details["code"] 已定义,则给定 0、true 和 details["code"],运行 executionSteps。

  8. 否则,给定 controlledframe、 details["file"]、 false、0 和 executionSteps,获取一个注入项。

3.5. 配置方法

dictionary ClearDataOptions {
  long since;
};

dictionary ClearDataTypeSet {
  boolean cache;
  boolean cookies;
  boolean fileSystems;
  boolean indexedDB;
  boolean localStorage;
  boolean persistentCookies;
  boolean sessionCookies;
};
要清空一个存储瓶,给定一个存储桶 bucket、 一个存储标识符 identifier,以及一个 long since,运行 以下步骤:

注:如果可能,用户代理应仅 移除在 since 之后最后使用的数据,其中 since 表示自 纪元以来的毫秒时间戳。并非所有用户代理都会跟踪所有 浏览数据的写入或访问时间。实现应尽其所能尊重 since, 但该 API 不保证其可用性。

  1. 令 bottle 为 bucket[identifier]。

  2. 清空 bottle 的映射。

  3. 将 bottle 的代理映射引用集合设置为一个新的集合。

clearData(options, types) 方法步骤为:
  1. 令 resultPromise 为一个新的 promise。

  2. 令 controlledframe 为 this。

  3. 返回 resultPromise,并并行运行剩余步骤。

  4. 令 clearSince 为 0。

  5. 如果 options["since"] 已定义,则将 clearSince 设置为 options|["since"]。

  6. 令 embeddingOrigin 为 controlledframe 的相关设置对象的顶级源。

  7. 令 partition 为 controlledframe 的 partition。

  8. 对于用户代理的 存储棚中的每个 storageKey → shelf:

    1. 如果 storageKey 的嵌入源不等于 embeddingOrigin,或 storageKey 的分区不 等于 partition,则继续。

    2. 令 bucket 为 shelf["default"]。

    3. 如果 types["fileSystems"] 为 true:

      1. 给定 bucket、"fileSystem" 和 clearSince,清空存储瓶。

    4. 如果 types["indexedDB"] 为 true:

      1. 给定 bucket、"indexedDB" 和 clearSince,清空存储瓶。

    5. 如果 types["localStorage"] 为 true:

      1. 给定 bucket、"localStorage" 和 clearSince,清空存储瓶。

  9. 如果 types["cookies"]、 types["persistentCookies"], 或 types["sessionCookies"] 为 true,则:

    [COOKIES] 规范不支持通过类似存储键的机制 对 cookie 进行分区。以下步骤 会清除所有 cookie,但其意图是仅删除 由此 Controlled Frame 当前 partition 中的 Controlled Frame 内容所 创建的 cookie。

    1. 对于用户代理的 cookie 存储中的每个 cookie:

      1. 如果 cookie 的 persistent-flag 已设置,则:

        1. 如果 types["cookies"] 和 types["persistentCookies"] 为 false, 则继续。

      2. 否则:

        1. 如果 types["cookies"] 和 types["sessionCookies"] 为 false, 则继续。

      3. 如果 cookie 的 last-access-time 表示为自 纪元以来的毫秒数小于 clearSince,则继续。

      4. 从用户代理的 cookie 存储中移除 cookie。

  10. 如果 types["cache"] 为 true,则:

    1. 对于 用户代理管理的每个 storageKey → cache:[HTTP-CACHING]

      1. 如果 storageKey 的嵌入源不等于 embeddingOrigin,或 storageKey 的分区不等于 partition, 则继续。

      2. 清空 cache。

  11. 给定 controlledframe 和 resultPromise,解决嵌入者 promise。

每个嵌入的 navigable都持有一个 muted 布尔值,默认值为 false。当 muted 为 true 时,用户代理必须 将源自嵌入的 navigable内的所有音频流静音。 muted 状态不应暴露给 嵌入的 navigable内的内容;当 muted 为 true 时,不应以任何脚本可见的方式更改音量状态,但 底层音频流不应被用户听到。

getAudioState() 方法步骤为:
  1. 令 resultPromise 为一个新的 promise。

  2. 令 controlledframe 为 this。

  3. 返回 resultPromise,并并行运行剩余步骤。

  4. 如果 controlledframe 的嵌入的 navigable为 null,则给定 controlledframe、resultPromise 和一个 TypeError, 拒绝嵌入者 promise,并中止这些步骤。

  5. 如果 controlledframe 的嵌入的 navigable内的任何内容(包括嵌套框架中的内容)当前正在 播放 音频,则令 playingAudio 为 true,否则为 false。

  6. 给定 controlledframe、resultPromise 和 playingAudio,解决嵌入者 promise。

isAudioMuted() 方法步骤为:
  1. 令 resultPromise 为一个新的 promise。

  2. 令 controlledframe 为 this。

  3. 返回 resultPromise,并并行运行剩余步骤。

  4. 如果 controlledframe 的嵌入的 navigable为 null,则给定 controlledframe、resultPromise 和一个 TypeError, 拒绝嵌入者 promise,并中止这些步骤。

  5. 给定 controlledframe、resultPromise 以及 controlledframe 的嵌入的 navigable的 muted 标志,解决嵌入者 promise。

setAudioMuted(mute) 方法步骤为:
  1. 如果 this 的嵌入的 navigable为 null,则抛出一个 TypeError。

  2. 将 this 的嵌入的 navigable的 muted 标志设置为 mute。

3.5.1. 缩放

enum ZoomMode {
  "per-origin",
  "per-view",
  "disabled"
};

用户代理持有一个 Controlled Frame 缩放映射,它是一个映射,其键为元组,值为浮点数。

每个 HTMLControlledFrameElement 都持有一个 ZoomMode zoomMode,其默认值为 per-origin。

每个 HTMLControlledFrameElement 都持有一个浮点数 currentZoom,初始设置为 1.0f。

给定 浮点数 zoomLevel,如何将缩放级别应用到文档, 由实现具体决定。

本节是非规范性的。

有效的 ZoomMode 值的行为如下:

per-origin

缩放更改会在嵌入文档的源中持久化,也就是说,位于同一 partition 中并导航到同一源的所有其他 HTMLControlledFrameElement 也会被缩放。

per-view

缩放更改仅在此 HTMLControlledFrameElement 中生效, 而其他 HTMLControlledFrameElement 中的缩放更改不会影响此 HTMLControlledFrameElement 的缩放。

disabled

禁用 HTMLControlledFrameElement 中的所有缩放。 内容会还原为默认缩放级别,并且所有尝试的缩放更改都会被 忽略。

要获取 按源缩放级别,给定 HTMLControlledFrameElement e,运行以下步骤:

  1. 令 result 为初始设置为 1.0f 的浮点数。

  2. 令 key 为给定与 e 的嵌入的 navigable的活动文档的当前设置对象相关联的环境,获取 Controlled Frame 存储键的结果。

  3. 如果 Controlled Frame 缩放映射[key] 存在,则将 result 设置为给定键 key,从 Controlled Frame 缩放映射获取 值的结果。

  4. 返回 result。

要设置 按源缩放级别,给定 HTMLControlledFrameElement e 和一个浮点数 zoomLevel,运行以下步骤:

  1. 令 key 为给定与 e 的嵌入的 navigable的活动文档的当前设置对象相关联的环境,获取 Controlled Frame 存储键的结果。

  2. 给定键 key 和值 zoomLevel,设置 值到 Controlled Frame 缩放映射。

要确定给定 HTMLControlledFrameElement e 时,当前文档是否具有按源缩放 级别,运行以下步骤:

  1. 令 key 为给定与 e 的嵌入的 navigable的活动文档的当前设置对象相关联的环境,获取 Controlled Frame 存储键的结果。

  2. 如果 Controlled Frame 缩放映射[key] 存在,返回 true。

  3. 返回 false。

getZoomMode() 方法 步骤为:

  1. 令 p 为一个新的 promise。

  2. 令 controlledframe 为 this。

  3. 返回 p,并并行运行剩余步骤。

  4. 给定 controlledframe、p 和 controlledframe 的zoomMode,解决嵌入者 promise。

setZoomMode(zoomMode) 方法步骤为:

  1. 令 p 为一个新的 promise。

  2. 令 controlledframe 为 this。

  3. 返回 p,并并行运行剩余步骤。

  4. 令 currentZoomMode 为给定 controlledframe,getZoomMode 的结果。

  5. 如果 currentZoomMode 等于 zoomMode,则给定 controlledframe 和 p,解决嵌入者 promise。

  6. 将 controlledframe 的 zoomMode 设置为 zoomMode。

  7. 如果 zoomMode 为 per-origin:

    1. 如果给定 controlledframe,当前文档具有 按源缩放级别为 true:

      1. 令 oldZoomFactor 为 controlledframe 的 currentZoom。

      2. 将 controlledframe 的 currentZoom 设置为给定 controlledframe,获取按源缩放级别 的结果。

      3. 如果 oldZoomFactor 不等于 controlledframe 的 currentZoom:

        1. 给定 controlledframe 的 currentZoom,将缩放级别应用到 controlledframe 的嵌入文档。

        2. 使用 controlledframe、oldZoomFactor 和 controlledframe 的 currentZoom,触发 "zoomchange" 事件。

  8. 如果 zoomMode 为 disabled:

    1. 令 oldZoomFactor 为 controlledframe 的 currentZoom。

    2. 将 controlledframe 的 currentZoom 设置为 1.0f。

    3. 如果 oldZoomFactor 不等于 controlledframe 的 currentZoom:

      1. 给定 controlledframe 的 currentZoom,将缩放级别应用到 controlledframe 的嵌入文档。

      2. 使用 controlledframe、oldZoomFactor 和 controlledframe 的 currentZoom,触发 "zoomchange" 事件。

  9. 给定 controlledframe 和 p,解决嵌入者 promise。

getZoom() 方法步骤 为:

  1. 令 p 为一个新的 promise。

  2. 令 controlledframe 为 this。

  3. 返回 p,并并行运行剩余步骤。

  4. 令 embeddedNavigable 为 controlledframe 的嵌入的 navigable。

  5. 如果 embeddedNavigable 为 null,则给定 controlledframe、p 和一个 TypeError, 拒绝嵌入者 promise,并中止这些步骤。

  6. 给定 controlledframe、p 和 controlledframe 的 currentZoom,解决嵌入者 promise。

setZoom(zoomFactor) 方法 步骤为:

  1. 令 p 为一个新的 promise。

  2. 令 controlledframe 为 this。

  3. 返回 p,并并行运行剩余步骤。

  4. 令 embeddedNavigable 为 controlledframe 的嵌入的 navigable。

  5. 如果 embeddedNavigable 为 null,则给定 controlledframe、p 和一个 TypeError, 拒绝嵌入者 promise,并中止这些步骤。

  6. 如果 controlledframe 的 ZoomMode 为 disabled:

    1. 给定 controlledframe、p 和一个 TypeError, 拒绝嵌入者 promise, 并中止这些步骤。

  7. 如果 controlledframe 的 ZoomMode 为 per-origin:

    1. 令 oldZoomFactor 为 controlledframe 的 currentZoom。

    2. 给定 controlledframe 和 zoomFactor,设置按源缩放级别。

    3. 对于用户代理的 浏览上下文组集合中的每个 浏览上下文组 group:

      1. 对于 group 中的每个 顶级浏览上下文 browsingContext:

        1. 令 embeddedDocument 为 browsingContext 的 活动文档。

        2. 令 embedder 为 embeddedDocument 的节点 navigable的 controlledFrameEmbedderParent。

        3. 如果 embedder 为 null,则继续。

        4. 如果以下所有条件均为 true,则令 match 为 true:

        5. 如果 match 为 true,则:

          1. 将 embedder 的 currentZoom 设置为 zoomFactor。

          2. 给定 zoomFactor,将缩放级别应用到 embeddedDocument。

          3. 使用 embedder、 oldZoomFactor 和 zoomFactor,触发 "zoomchange" 事件。

  8. 如果 controlledframe 的 ZoomMode 为 per-view:

    1. 令 oldZoomFactor 为 controlledframe 的 currentZoom。

    2. 将 controlledframe 的 currentZoom 设置为 zoomFactor。

    3. 如果 oldZoomFactor 不等于 controlledframe 的 currentZoom:

      1. 给定 controlledframe 的 currentZoom,将缩放级别应用到 controlledframe 的嵌入文档。

      2. 使用 controlledframe、 oldZoomFactor、controlledframe 的currentZoom,触发 "zoomchange" 事件。

  9. 给定 controlledframe 和 p,解决嵌入者 promise。

3.6. 捕获方法

// One of |code| or |file| must be specified but not both.
dictionary ImageDetails {
  DOMString format;
  DOMString quality;
};
captureVisibleRegion(options) 方法步骤为:
  1. 令 resultPromise 为一个新的 promise。

  2. 令 controlledframe 为 this。

  3. 返回 resultPromise,并并行运行剩余步骤。

  4. 如果 controlledframe 的嵌入的 navigable为 null,则给定 controlledframe、resultPromise 和一个 TypeError, 拒绝嵌入者 promise,并中止这些步骤。

  5. 令 optionsFormat 默认为 "JPEG"。

  6. 令 optionsQuality 默认为 100。

  7. 如果 options 有字段 "format":

    1. 令 optionsFormat 为 options["format"]。

  8. 如果 optionsFormat 是无法识别的格式,则给定 controlledframe、 resultPromise 和一个 TypeError, 拒绝嵌入者 promise,并中止这些步骤。

  9. 如果 options 有字段 "quality":

    1. 令 optionsQuality 为 options["quality"]。

  10. 如果 optionsQuality 不是整数,或不在 0 到 100(含)之间, 则给定 controlledframe、 resultPromise 和一个 TypeError, 拒绝嵌入者 promise,并中止这些步骤。

  11. 令 imageData 为一张显示嵌入内容可见区域的图像,该图像以 optionsFormat 编码,质量为 optionsQuality。

    注:受支持图像格式的集合由实现定义, 但建议至少支持 "JPEG" 和 "PNG"。

  12. 给定 controlledframe、resultPromise 和一个包含 imageData 的 data: URL,解决嵌入者 promise。

print() 方法步骤为:
  1. 如果 this 的嵌入的 navigable为 null,则抛出一个 TypeError。

  2. 为嵌入内容启动浏览器打印页面功能。

3.7. 事件

HTMLControlledFrameElement 实现 EventTarget 并支持以下事件处理程序(以及它们对应的事件处理程序事件类型)。

事件处理程序 事件处理程序事件类型
onconsolemessage consolemessage
oncontentload contentload
ondialog dialog
onloadabort loadabort
onloadcommit loadcommit
onloadstart loadstart
onloadstop loadstop
onnewwindow newwindow
onpermissionrequest permissionrequest
onsizechanged sizechanged
onzoomchange zoomchange

交互事件:

UI 更改事件:

导航事件:

每个 HTMLControlledFrameElement 都有一个加载计数器, 它是一个初始值为零的数字。

每次 onloadstart 事件触发时,加载计数器 增加 1。

每次 onloadabort 事件触发时,加载计数器 减少 1。

每次 onloadcommit 事件触发时,加载计数器 减少 1。

当加载计数器从非零数字变为 0 时,触发 "loadstop" 事件。

3.7.1. consolemessage

[Exposed=Window, IsolatedContext]
interface ConsoleMessage {
  readonly attribute long level;
  readonly attribute DOMString message;
};

[Exposed=Window, IsolatedContext]
interface ConsoleMessageEvent : Event {
  constructor(DOMString type, optional ConsoleMessageEventInit eventInitDict = {});
  readonly attribute ConsoleMessage consoleMessage;
};

dictionary ConsoleMessageEventInit: EventInit {
  ConsoleMessage? consoleMessage;
};

要触发 ConsoleMessageEvent e,给定 controlledframe 元素 target、一个 long logLevel 和一个 DOMString message, 运行以下步骤:

  1. 令 consoleMessage 为一个新的 ConsoleMessage 对象。

  2. 设置 consoleMessage 的以下字段:

    level

    logLevel。

    message

    message。

  3. 将 e 的 consoleMessage 设置为 consoleMessage。

  4. 在 target 的相关全局对象的 DOM 操作任务源上排队一个全局任务,以在 target 上分派 e。

3.7.2. dialog

enum DialogType {
  "alert",
  "confirm",
  "prompt"
};

[Exposed=Window, IsolatedContext]
interface DialogController {
  undefined okay(optional DOMString response);
  undefined cancel();
};

[Exposed=Window, IsolatedContext]
interface DialogMessage {
  readonly attribute DialogType messageType;
  readonly attribute DOMString messageText;
  readonly attribute DialogController dialog;
};

[Exposed=Window, IsolatedContext]
interface DialogEvent : Event {
  constructor(DOMString type, optional DialogEventInit eventInitDict = {});
  readonly attribute DialogMessage dialogMessage;
};

dictionary DialogEventInit: EventInit {
  DialogMessage? dialogMessage;
};

每个 DialogController 都具有:

okay(response) 方法步骤为:

  1. 将 accept 设置为 true。

  2. 将 response 设置为 response。

cancel() 方法步骤为:

  1. 将 accept 设置为 false。

要触发 DialogEvent e,给定 controlledframe 元素 target、简单对话框类型 dialogType,以及 消息 message,运行以下步骤:

  1. 断言 e["dialogMessage"]["dialog"]["accept"] 等于 false。

  2. 令 dialogMessage 为一个新的 DialogMessage 对象。

  3. 令 dialog 为一个新的 DialogController 对象。

  4. 设置 dialogMessage 的以下字段:

    messageType

    dialogType。

    messageText

    message。

    dialog

    dialog。

  5. 将 e 的 dialogMessage 设置为 dialogMessage。

  6. 令 complete 为 false。

  7. 在 target 的相关全局对象的DOM 操作任务源上排队一个全局任务,以运行以下 步骤:

    1. 在 target 上分派 e。

    2. 将 complete 设置为 true。

  8. 同步等待 complete 为 true。

    注: 此处阻塞是有意为之,因为 由 "dialog" 事件表示的 alert、confirm 和 prompt 对话框会阻塞主线程,并且我们在这里调用的事件 处理程序会影响返回值。

  9. 返回 e["dialogMessage"]["dialog"]["accept"] 以及 e["dialogMessage"]["dialog"]["response"]。

3.7.3. newwindow

enum WindowOpenDisposition {
  "ignore",
  "save_to_disk",
  "current_tab",
  "new_background_tab",
  "new_foreground_tab",
  "new_window",
  "new_popup"
};

[Exposed=Window, IsolatedContext]
interface NewWindowController {
  undefined attach(HTMLControlledFrameElement newControlledFrame);
  undefined discard();
};

[Exposed=Window, IsolatedContext]
interface NewWindow {
  readonly attribute NewWindowController window;
  readonly attribute USVString targetUrl;
  readonly attribute DOMString name;
  readonly attribute WindowOpenDisposition windowOpenDisposition;
};

[Exposed=Window, IsolatedContext]
interface NewWindowEvent : Event {
  constructor(DOMString type, optional NewWindowEventInit eventInitDict = {});
  readonly attribute NewWindow newWindow;
};

dictionary NewWindowEventInit: EventInit {
  NewWindow? newWindow;
};

每个 NewWindowController 都有一个对 目标 navigable 的引用,该引用最初为 null。

attach(newControlledFrame) 方法步骤为:

  1. 将 newControlledFrame 的嵌入的 navigable设置为 this 的 目标 navigable。

discard() 方法步骤为:

  1. 如果 this 的目标 navigable不是 null,则给定 this 的 目标 navigable,关闭一个顶级 traversable。

要触发 NewWindowEvent e, 给定 controlledframe 元素 controlledFrame、USVString url、 DOMString target、navigable targetNavigable 和 WindowOpenDisposition windowOpenDisposition,运行以下步骤:

  1. 令 controller 为一个新的 NewWindowController 对象。

  2. 将 controller 的目标 navigable设置为 targetNavigable。

  3. 令 newWindow 为一个新的 NewWindow 对象。

  4. 设置 newWindow 的以下字段:

    window

    controller

    targetUrl

    url

    name

    target。

    windowOpenDisposition

    windowOpenDisposition

  5. 将 e 的 newWindow 设置为 newWindow。

  6. 在 controlledFrame 的相关全局对象的 DOM 操作任务源上排队一个全局任务,以在 controlledFrame 上分派 e。

3.7.4. permissionrequest

enum PermissionType {
  "media",
  "geolocation",
  "pointerLock",
  "download",
  "filesystem",
  "fullscreen",
  "hid",
};

[Exposed=Window, IsolatedContext]
interface PermissionRequestControllerBase {
  undefined allow();
  undefined cancel();
};

[Exposed=Window, IsolatedContext]
interface MediaPermissionRequestController: PermissionRequestControllerBase {
  readonly attribute USVString url;
};

[Exposed=Window, IsolatedContext]
interface GeolocationPermissionRequestController: PermissionRequestControllerBase {
  readonly attribute USVString url;
};

[Exposed=Window, IsolatedContext]
interface PointerLockPermissionRequestController: PermissionRequestControllerBase {
  readonly attribute boolean lastUnlockedBySelf;
  readonly attribute boolean userGesture;
  readonly attribute USVString url;
};

[Exposed=Window, IsolatedContext]
interface DownloadPermissionRequestController : PermissionRequestControllerBase {
  readonly attribute DOMString requestMethod;
  readonly attribute USVString url;
};

[Exposed=Window, IsolatedContext]
interface FileSystemPermissionRequestController : PermissionRequestControllerBase {
  readonly attribute USVString url;
};

[Exposed=Window, IsolatedContext]
interface FullscreenPermissionRequestController : PermissionRequestControllerBase {
  readonly attribute USVString origin;
};

[Exposed=Window, IsolatedContext]
interface HidPermissionRequestController : PermissionRequestControllerBase {
  readonly attribute USVString url;
};

[Exposed=Window, IsolatedContext]
interface PermissionRequest {
  readonly attribute PermissionType permission;
  readonly attribute PermissionRequestControllerBase request;
};

[Exposed=Window, IsolatedContext]
interface PermissionRequestEvent : Event {
  constructor(DOMString type, optional PermissionRequestEventInit eventInitDict = {});
  readonly attribute PermissionRequest permissionRequest;
};

dictionary PermissionRequestEventInit: EventInit {
  PermissionRequest? permissionRequest;
};

每个 PermissionRequestControllerBase 都有一个布尔值 allow,其初始值为 false。

allow() 方法步骤为:

  1. 将 allow 设置为 true。

cancel() 方法步骤为:

  1. 将 allow 设置为 false。

要触发 PermissionRequestEvent e,给定一个文档 embeddedDocument、 controlledframe 元素 target、DOMString type、USVString url、一个 可选字典 options,以及一个接受 布尔值的算法 completionSteps,运行以下步骤:

  1. 令 permissionRequest 为一个新的 PermissionRequest 对象。

  2. 如果 type 为 "media":

    1. 令 requestController 为一个具有以下属性的新的 MediaPermissionRequestController:

      url

      url

  3. 如果 type 为 "geolocation":

    1. 令 requestController 为一个具有以下属性的新的 GeolocationPermissionRequestController:

      url

      url

  4. 如果 type 为 "pointerLock":

    1. 令 requestController 为一个具有以下属性的新的 PointerLockPermissionRequestController:

      lastUnlockedBySelf

      options["lastUnlockedBySelf"]

      userGesture

      options["userGesture"]

      url

      url

  5. 如果 type 为 "download":

    1. 令 requestController 为一个具有以下属性的新的 DownloadPermissionRequestController:

      requestMethod

      options["requestMethod"]

      url

      url

  6. 如果 type 为 "filesystem":

    1. 令 requestController 为一个具有以下属性的新的 FileSystemPermissionRequestController:

      url

      url

  7. 如果 type 为 "fullscreen":

    1. 令 requestController 为一个具有以下属性的新的 FullscreenPermissionRequestController:

      origin

      url 的源

  8. 如果 type 为 "hid":

    1. 令 requestController 为一个具有以下属性的新的 HidPermissionRequestController:

      url

      url

  9. 设置 permissionRequest 的以下字段:

    request

    requestController

    permission

    type。

  10. 将 e 的 permissionRequest 设置为 permissionRequest。

  11. 在 target 的相关全局对象的 DOM 操作任务源上排队一个全局任务,以运行以下 步骤:

    1. 在 target 上分派 e。

    2. 在 embeddedDocument 的相关全局对象的 DOM 操作任务源上排队一个全局任务,该任务使用 e["permissionRequest"]["permission"]["allow"] 运行 completionSteps。

3.7.5. sizechanged

[Exposed=Window, IsolatedContext]
interface SizeChange {
  readonly attribute unsigned long oldWidth;
  readonly attribute unsigned long oldHeight;
  readonly attribute unsigned long newWidth;
  readonly attribute unsigned long newHeight;
};

[Exposed=Window, IsolatedContext]
interface SizeChangedEvent : Event {
  constructor(DOMString type, optional SizeChangedEventInit eventInitDict = {});
  readonly attribute SizeChange sizeChange;
};

dictionary SizeChangedEventInit: EventInit {
  SizeChange? sizeChange;
};

要触发一个 SizeChangedEvent e,给定 controlledframe 元素 target、4 个非负数 oldWidth、oldHeight、 newWidth、newHeight:

  1. 令 sizeChange 为一个新的 SizeChange 对象。

  2. 设置 sizeChange 的以下字段:

    oldWidth

    oldWidth。

    oldHeight

    oldHeight。

    newWidth

    newWidth。

    newHeight

    newHeight。

  3. 将 e 的 sizeChange 设置为 sizeChange。

  4. 在 target 的相关全局对象的 DOM 操作任务源上排队一个全局任务,以在 target 上分派 e。

3.7.6. zoomchange

[Exposed=Window, IsolatedContext]
interface ZoomChange {
  readonly attribute float oldZoomFactor;
  readonly attribute float newZoomFactor;
};

[Exposed=Window, IsolatedContext]
interface ZoomChangeEvent : Event {
  constructor(DOMString type, optional ZoomChangeEventInit eventInitDict = {});
  readonly attribute ZoomChange zoomChange;
};

dictionary ZoomChangeEventInit: EventInit {
  ZoomChange? zoomChange;
};

要触发 ZoomChangeEvent e,给定 controlledframe 元素 target、2 个 浮点数 oldZoomFactor、newZoomFactor:

  1. 令 zoomChange 为一个新的 ZoomChange 对象。

  2. 设置 zoomChange 的以下字段:

    oldZoomFactor

    oldZoomFactor。

    newZoomFactor

    newZoomFactor。

  3. 将 e 的 zoomChange 设置为 zoomChange。

  4. 在 target 的相关全局对象的 DOM 操作任务源上排队一个全局任务,以在 target 上分派 e。

3.7.7. contentload

[Exposed=Window, IsolatedContext]
interface ContentLoadEvent : Event {
  constructor(DOMString type, optional EventInit eventInitDict = {});
};

要触发 ContentLoadEvent e,给定 controlledframe 元素 target,运行以下步骤:

  1. 在 target 的相关全局对象的 DOM 操作任务源上排队一个全局任务,以在 target 上分派 e。

3.7.8. loadabort

[Exposed=Window, IsolatedContext]
interface LoadInfo {
  readonly attribute USVString url;
  readonly attribute boolean isTopLevel;
};

[Exposed=Window, IsolatedContext]
interface LoadAbortInfo : LoadInfo{
  readonly attribute long code;
  readonly attribute DOMString reason;
};

[Exposed=Window, IsolatedContext]
interface LoadRedirectInfo{
  readonly attribute USVString oldUrl;
  readonly attribute USVString newUrl;
  readonly attribute boolean isTopLevel;
};

[Exposed=Window, IsolatedContext]
interface LoadAbortEvent : Event {
  constructor(DOMString type, optional LoadAbortEventInit eventInitDict = {});
  readonly attribute LoadAbortInfo loadAbortInfo;
};

dictionary LoadAbortEventInit: EventInit {
  LoadAbortInfo? loadAbortInfo;
};

要触发一个 LoadAbortEvent e,给定 controlledframe 元素 target、 一个 USVString url、一个布尔值 isTopLevel、一个 long code, 以及一个 DOMString reason,运行以下步骤:

  1. 令 info 为一个具有以下属性的新的 LoadAbortInfo:

    url

    url

    isTopLevel

    isTopLevel

    code

    code

    reason

    reason

  2. 将 e 的 loadAbortInfo 设置为 info。

  3. 在 target 的相关全局对象的 DOM 操作任务源上排队一个全局任务,以在 target 上分派 e。

3.7.9. loadcommit

[Exposed=Window, IsolatedContext]
interface LoadCommitEvent : Event {
  constructor(DOMString type, optional LoadCommitEventInit eventInitDict = {});
  readonly attribute LoadInfo loadInfo;
};

dictionary LoadCommitEventInit: EventInit {
  LoadInfo? loadInfo;
};

要触发一个 LoadCommitEvent e,给定 controlledframe 元素 target、 一个 USVString url 和一个布尔值 isTopLevel,运行以下步骤:

  1. 令 info 为一个具有以下属性的新的 LoadInfo:

    url

    url

    isTopLevel

    isTopLevel

  2. 将 e 的 loadInfo 设置为 info。

  3. 在 target 的相关全局对象的 DOM 操作任务源上排队一个全局任务,以在 target 上分派 e。

3.7.10. loadstart

[Exposed=Window, IsolatedContext]
interface LoadStartEvent : Event {
  constructor(DOMString type, optional LoadStartEventInit eventInitDict = {});
  readonly attribute LoadInfo loadInfo;
};

dictionary LoadStartEventInit: EventInit {
  LoadInfo? loadInfo;
};

要触发一个 LoadStartEvent e,给定 controlledframe 元素 target、 一个 USVString url 和一个布尔值 isTopLevel,运行以下步骤:

  1. 令 info 为一个具有以下属性的新的 LoadInfo:

    url

    url

    isTopLevel

    isTopLevel

  2. 将 e 的 loadInfo 设置为 info。

  3. 在 target 的相关全局对象的 DOM 操作任务源上排队一个全局任务,以在 target 上分派 e。

3.7.11. loadstop

[Exposed=Window, IsolatedContext]
interface LoadStopEvent : Event {
  constructor(DOMString type, optional LoadStopEventInit eventInitDict = {});
};

dictionary LoadStopEventInit: EventInit {
};

要触发 LoadStopEvent e ,给定 controlledframe 元素 target,运行以下步骤:

  1. 在 target 的相关全局对象的 DOM 操作任务源上排队一个全局任务,以在 target 上分派 e。

3.7.12. loadredirect

[Exposed=Window, IsolatedContext]
interface LoadRedirectEvent : Event {
  constructor(DOMString type, optional LoadRedirectEventInit eventInitDict = {});
  readonly attribute LoadRedirectInfo loadRedirectInfo;
};

dictionary LoadRedirectEventInit: EventInit {
  LoadRedirectInfo? loadRedirectInfo;
};

要触发 LoadRedirectEvent e,给定 controlledframe 元素 target、一个 URL oldUrl、一个 URL newUrl,以及一个布尔值 isTopLevel,运行 以下步骤:

  1. 令 info 为一个具有以下属性的新的 LoadInfo:

    oldUrl

    给定 oldUrl,序列化 URL的结果

    newUrl

    给定 newUrl,序列化 URL的结果

    isTopLevel

    isTopLevel

  2. 将 e 的 loadRedirectInfo 设置为 info。

  3. 在 target 的相关全局对象的 DOM 操作任务源上排队一个全局任务,以在 target 上分派 e。

3.7.13. 猴子补丁

3.7.13.1. [HTML]

对于 alert:

  1. 将 message 设置为可选地截断 message 的结果。

  2. 令 controlledFrameEmbedderParent 为 window 的 navigable 的controlledFrameEmbedderParent。 。
  3. 如果 controlledFrameEmbedderParent 是一个 HTMLControlledFrameElement, 则使用 controlledFrameEmbedderParent、"alert" 和 message 触发 "dialog" 事件,并返回。

对于 confirm:

  1. 将 message 设置为可选地截断 message 的结果。

  2. 令 controlledFrameEmbedderParent 为 window 的 navigable 的controlledFrameEmbedderParent。 。
  3. 如果 controlledFrameEmbedderParent 是一个 HTMLControlledFrameElement, 则返回使用 controlledFrameEmbedderParent、"confirm" 和 message 触发 "dialog" 事件的结果。

对于 prompt:

  1. 将 default 设置为可选地截断 default 的结果。

  2. 令 controlledFrameEmbedderParent 为 window 的navigable 的controlledFrameEmbedderParent。 。
  3. 如果 controlledFrameEmbedderParent 是一个 HTMLControlledFrameElement, 则:
    1. 令 accept 和 response 为使用 controlledFrameEmbedderParent、"prompt" 和 message 触发 "dialog" 事件的结果。
    2. 如果 accept 等于 false,返回 null。
    3. 返回 response。

对于 window open steps:

  1. 令 windowOpenDisposition 为 "ignore"。
  2. 令 controlledFrameEmbedderParent 为 sourceDocument 的节点 navigable 的controlledFrameEmbedderParent。

...

14. 如果 targetNavigable 为 null,则返回 null。
  1. 如果 targetNavigable 为 null:
    1. 如果 controlledFrameEmbedderParent 不是 null:
      1. 使用 controlledFrameEmbedderParent、url、 target、targetNavigable 和 windowOpenDisposition,触发 "newwindow" 事件。
    2. 返回 null。
  2. 如果 windowType 为 "new and unrestricted" 或 "new with no opener", 则:

    1. 将 windowOpenDisposition 设置为以下之一: "new_background_tab"、 "new_foreground_tab", 或 "new_window"。

    注:该值取决于用户代理的行为支持 和用户设置。

    1. 将 targetNavigable 的活动浏览上下文的 is popup 设置为给定 tokenizedFeatures,检查是否请求了弹出窗口的结果。

    2. 如果 targetNavigable 的活动浏览上下文的 is popup 为 true,则将 windowOpenDisposition 设置为 "new_popup"。

    ...

  3. 否则:

    1. 将 windowOpenDisposition 设置为 "current_tab"。

    ...

注:步骤 15 和 16 也会导航 targetNavigable;在导航期间, windowOpenDisposition 也可能会被更新。例如,如果导航被 阻止,windowOpenDisposition 可能会被设置为 "ignore"。 如果导航响应导致 下载,则 windowOpenDisposition 可能会被设置为 "save_to_disk"。

  1. 如果 controlledFrameEmbedderParent 不是 null:
    1. 使用 controlledFrameEmbedderParent、url、 target、targetNavigable 和 windowOpenDisposition,触发 "newwindow" 事件。

对于完全完成加载:

  1. 否则,如果 container 非 null,则给定 container,在 DOM 操作任务源上排队一个元素任务, 以在 container 处触发名为 load 的事件。

  2. 令 controlledFrameEmbedderParent 为 document 的节点 navigable 的controlledFrameEmbedderParent。
  3. 如果 controlledFrameEmbedderParent 是 HTMLControlledFrameElement, 则使用 controlledFrameEmbedderParent 触发 "contentload" 事件。

用于 loadstart、loadabort 和 loadcommit 的猴子补丁如下所示:

  1. loadstart -> 在导航入口点:普通导航、重新加载、遍历。

  2. loadcommit -> 在通用导航完成点。

  3. loadabort -> 在 loadstart 和 loadcommit 之间算法的每个提前退出点。

对于这些事件中的每一个,检查 navigable 的顶级 traversable是否具有 HTMLControlledFrameElement 类型的 controlledFrameEmbedderParent, 如果是,则使用输入参数触发对应事件。

3.7.13.2. [FETCH]

对于 HTTP fetch(loadredirect):

  1. 如果 internalResponse 的状态是重定向状态:

    1. 如果 request 的 window window 是一个 环境设置对象,其全局对象是 Window 对象:
      1. 令 currentNavigable 为 window 的关联 navigable。
      2. 令 controlledFrameEmbedderParent 为 currentNavigable 的 顶级 traversable 的controlledFrameEmbedderParent。
      3. 如果 controlledFrameEmbedderParent 是一个 HTMLControlledFrameElement:

        1. 令 oldUrl 为 request 的关联 URL。

        1. 令 newUrl 为 response 的位置 URL。

        1. 令 isTopLevel 为 false;如果 currentNavigable 具有 null parent,则将 isTopLevel 设置为 true。

        1. 使用 controlledFrameEmbedderParent、oldUrl、newUrl 和 isTopLevel,触发 "loadredirect" 事件。

3.7.13.3. [Permissions]

定义新算法:

要确定一个 Document document 是否 被嵌入者允许使用某项 权限,给定 DOMString permission、一个可选字典 options,以及一个接受 布尔值的算法 completionSteps,运行以下步骤:

  1. 令 controlledFrameEmbedderParent 为 document 的节点 navigable 的controlledFrameEmbedderParent。

  2. 如果 controlledFrameEmbedderParent 不是 HTMLControlledFrameElement, 返回 true。

  3. 使用 document、 controlledFrameEmbedderParent、permission、document 的 URL、options 和 completionSteps,触发 "permissionrequest" 事件。

对于请求位置(geolocation):

  1. 如果 document 不被允许使用 "geolocation" 特性:

    1. 如果传入了 watchId,则从 watchIDs 中移除 watchId。

    2. 使用 errorCallback 和 PERMISSION_DENIED 回调错误。

    3. 终止此算法。

  2. 令 blockedByEmbedder 为 false。
  3. 检查 document 是否被嵌入者允许使用 "geolocation" 特性,给定一个算法,该算法将其 布尔值参数赋给 blockedByEmbedder 并继续执行这些步骤的剩余部分。
  4. 如果 blockedByEmbedder 为 true,则:
    1. 如果传入了 watchId,则从 watchIDs 中移除 watchId。
    2. 使用 errorCallback 和 PERMISSION_DENIED 回调错误。
    3. 终止此算法。
  5. 令 controlledFrameEmbedderParent 为 document 的节点 navigable 的controlledFrameEmbedderParent。
  6. 如果 controlledFrameEmbedderParent 是 HTMLControlledFrameElement:
    1. 令 nodeDocument 为 controlledFrameEmbedderParent 的节点文档。

    2. 如果 nodeDocument 为 null:
      1. 如果传入了 watchId,则从 watchIDs 中移除 watchId。
      2. 使用 errorCallback 和 PERMISSION_DENIED 回调错误。
      3. 终止此算法。
    3. 令 embedderNavigator 为 nodeDocument 的全局对象的 关联 Navigator。
    4. 令 embedderGeolocation 为 embedderNavigator 的 geolocation。
    5. 返回使用 embedderGeolocation、successCallback、errorCallback、 options 和 whatchId 请求位置的结果。

注:其他权限也会以类似于 geolocation 的方式打上猴子补丁。 但为了简洁起见,本文档省略了 细节。

3.7.13.4. [Console]

对于 Logger:

  1. 否则,执行 Printer(logLevel, Formatter(args))。

  2. 使用 logLevel、Formatter(args),触发 "consolemessage" 事件。

注:Console 默认不与 document 关联,因此我们无法跟踪关联的 HTMLControlledFrameElement。

3.8. 与其他规范的集成

本规范将对一些规范作出修改,以满足 Controlled Frame 的需求。

3.8.1. 猴子补丁

3.8.1.1. [HTML]

每个 navigable 都具有:

给定一个 navigable navigable 和一个可选的 navigable-or-null parent(默认为 null),初始化 navigable 算法 被猴子补丁如下:

  1. 将 navigable 的 parent 设置为 parent。

  2. 如果 parent 不是 null(navigable 不是 顶级 traversable),则:
    1. 令 topLevelTraversable 为 navigable 作为其后代的顶级 traversable。
    2. 将 navigable 的 frameId 设置为 topLevelTraversable 的 next frameId。
    3. 递增 topLevelTraversable 的 next frameId。

用于 Document document 到 readinessValue 的更新当前文档就绪状态算法被猴子补丁如下:

  1. 令 runAt 为将以下映射应用于 readinessValue 的结果:
    "loading"

    "document-start"

    "interactive"

    "document-end"

    "complete"

    "document-idle"

  2. 给定 document 和 runAt,将内容脚本注入到文档中。
  3. 在 document 处触发一个事件,其名称为 readystatechange。

3.8.1.2. [FETCH]

确定网络分区键算法被猴子扩展为 要求对源自 Controlled Frame 的嵌入的 navigable的网络请求 进行双键化。

要确定网络分区键,给定一个环境 environment:
  1. 令 topLevelSite 为给定 topLevelOrigin,获取站点的结果。

  2. 令 secondKey 为 null 或一个实现定义的值 。

  3. 令 controlledFrameEmbedderParent 为给定 environment,获取环境的 controlledFrameEmbedderParent的结果。
  4. 如果 controlledFrameEmbedderParent 不是 null,则将 secondKey 设置为一个元组,该元组由 controlledFrameEmbedderParent 的 相关设置对象的顶级源,以及 controlledFrameEmbedderParent 的 partition组成。
  5. 返回 (topLevelSite, secondKey)。

3.8.1.3. [STORAGE]

存储键被重新定义如下:

存储键是一个元组, 由 嵌入源(一个源或 null)、一个 分区(一个 DOMString 或 null),以及一个 源(一个源)组成。

注:将来一旦存储分区被完整规范化, 该定义将需要扩展为除源之外,还包括嵌入内容的 顶级源。

注:Controlled Frame 数据是用拥有 Controlled Frame 元素的文档的源进行三重键化,而不是用拥有它的顶级文档的源。

为非存储目的获取存储键算法被扩展为 要求对属于 controlledframe 的 嵌入的 navigable 的所有存储进行双键化。

要为非存储目的获取存储键,给定一个环境 environment,运行以下步骤:
  1. 如果 environment 是一个环境设置对象,则令 origin 为 environment 的源;否则为 environment 的创建 URL的源。

  2. 返回一个由 origin 组成的元组。
  3. 令 topLevelOrigin 和 partition 为 null。
  4. 令 controlledFrameEmbedderParent 为给定 environment,获取环境的 controlledFrameEmbedderParent的结果。
  5. 如果 controlledFrameEmbedderParent 不是 null,则:
    1. 将 topLevelOrigin 设置为 controlledFrameEmbedderParent 的相关设置对象的顶级源。
    2. 将 partition 设置为 controlledFrameEmbedderParent 的 partition。
  6. 返回一个由 topLevelOrigin、partition 和 origin 组成的元组。
要获取一个环境的 controlledFrameEmbedderParent,给定 一个环境 environment,运行以下步骤:
  1. 如果 environment 是一个环境设置对象,其 全局对象是一个 Window 对象,则:

    此算法 不适用于 Shared 或 Service Workers,因为 controlledFrameEmbedderParent 仅 定义在 navigable 上,并且 并不总是可以从非 Window 环境到达一个 navigable。

    1. 令 navigable 为 environment 的全局对象的 navigable。

    2. 令 top 为 navigable 的顶级 traversable。

    3. 如果 top 的 controlledFrameEmbedderParent 不是 null,则返回 top 的 controlledFrameEmbedderParent。

  2. 返回 null。

4. Web Request API

enum ResourceType {
  "main-frame",
  "sub-frame",
  "stylesheet",
  "script",
  "image",
  "font",
  "object",
  "xmlhttprequest",
  "ping",
  "csp-report",
  "media",
  "websocket",
  "other",
};

enum RequestedHeaders {
  "none",
  "cors",
  "all",
};

enum ConnectionState {
  "broken", "insecure", "secure"
};

dictionary Fingerprint {
  required DOMString sha256;
};

dictionary CertificateInfo {
  required Fingerprint fingerprint;
  Uint8Array rawDER;
};

dictionary SecurityInfo {
  required sequence<CertificateInfo> certificates;
  required ConnectionState state;
};

dictionary WebRequestInterceptorOptions {
  required sequence<(URLPattern or URLPatternInput)> urlPatterns;
  sequence<ResourceType> resourceTypes = [];
  boolean blocking = false;
  boolean includeRequestBody = false;
  RequestedHeaders includeHeaders = "none";
  boolean securityInfo = false;
  boolean securityInfoRawDer = false;
};

[Exposed=Window, IsolatedContext]
interface WebRequest {
  WebRequestInterceptor createWebRequestInterceptor(
      WebRequestInterceptorOptions options);
};

[Exposed=Window, IsolatedContext]
interface WebRequestInterceptor : EventTarget {
  attribute EventHandler onauthrequired;
  attribute EventHandler onbeforeredirect;
  attribute EventHandler onbeforerequest;
  attribute EventHandler onbeforesendheaders;
  attribute EventHandler oncompleted;
  attribute EventHandler onerroroccurred;
  attribute EventHandler onheadersreceived;
  attribute EventHandler onsendheaders;
  attribute EventHandler onresponsestarted;
};

enum DocumentLifecycle {
  "prerender",
  "active",
  "cached",
  "pending-deletion",
};

enum FrameType {
  "outermost-frame",
  "fenced-frame",
  "sub-frame",
};

[Exposed=Window, IsolatedContext]
interface UploadData {
  readonly attribute ArrayBuffer? bytes;
  readonly attribute DOMString? file;
};

[Exposed=Window, IsolatedContext]
interface RequestBody {
  readonly attribute DOMString? error;
  readonly attribute any formData;
  readonly attribute FrozenArray<UploadData>? raw;
};

[Exposed=Window, IsolatedContext]
interface WebRequestRequest {
  readonly attribute DOMString method;
  readonly attribute DOMString id;
  readonly attribute ResourceType type;
  readonly attribute USVString url;
  readonly attribute USVString? initiator;
  readonly attribute Headers? headers;
  readonly attribute RequestBody? body;
};

[Exposed=Window, IsolatedContext]
interface AuthChallenger {
  readonly attribute DOMString host;
  readonly attribute long port;
};

[Exposed=Window, IsolatedContext]
interface WebRequestAuthDetails {
  readonly attribute AuthChallenger challenger;
  readonly attribute boolean isProxy;
  readonly attribute DOMString scheme;
  readonly attribute DOMString? realm;
};

[Exposed=Window, IsolatedContext]
interface WebRequestResponse {
  readonly attribute long statusCode;
  readonly attribute DOMString statusLine;
  readonly attribute boolean fromCache;
  readonly attribute Headers? headers;
  readonly attribute DOMString? ip;
  readonly attribute USVString? redirectURL;
  readonly attribute WebRequestAuthDetails? auth;
};

[Exposed=Window, IsolatedContext]
interface WebRequestEvent : Event {
  readonly attribute WebRequestRequest request;
  readonly attribute long frameId;
  readonly attribute FrameType? frameType;
  readonly attribute DOMString? documentId;
  readonly attribute DocumentLifecycle? documentLifecycle;
  readonly attribute DOMString? parentDocumentId;
  readonly attribute long? parentFrameId;
};

dictionary WebRequestAuthCredentials {
  required DOMString username;
  required DOMString password;
};

dictionary WebRequestAuthOptions {
  AbortSignal signal;
};

[Exposed=Window, IsolatedContext]
interface WebRequestAuthRequiredEvent : WebRequestEvent {
  readonly attribute WebRequestResponse response;

  undefined setCredentials(
    Promise<WebRequestAuthCredentials> credentials,
    optional WebRequestAuthOptions options = {});
};

[Exposed=Window, IsolatedContext]
interface WebRequestBeforeRedirectEvent : WebRequestEvent {
  readonly attribute WebRequestResponse response;
};

[Exposed=Window, IsolatedContext]
interface WebRequestBeforeRequestEvent : WebRequestEvent {
  undefined redirect(USVString redirectURL);
};

[Exposed=Window, IsolatedContext]
interface WebRequestBeforeSendHeadersEvent : WebRequestEvent {
  undefined setRequestHeaders((Headers or HeadersInit) requestHeaders);
};

[Exposed=Window, IsolatedContext]
interface WebRequestCompletedEvent : WebRequestEvent {
  readonly attribute WebRequestResponse response;
};

[Exposed=Window, IsolatedContext]
interface WebRequestErrorOccurredEvent : WebRequestEvent {
  readonly attribute DOMString error;
};

[Exposed=Window, IsolatedContext]
interface WebRequestHeadersReceivedEvent : WebRequestEvent {
  readonly attribute WebRequestResponse response;
  readonly attribute SecurityInfo? securityInfo;

  undefined redirect(USVString redirectURL);
  undefined setResponseHeaders((Headers or HeadersInit) responseHeaders);
};

[Exposed=Window, IsolatedContext]
interface WebRequestResponseStartedEvent : WebRequestEvent {
  readonly attribute WebRequestResponse response;
};

[Exposed=Window, IsolatedContext]
interface WebRequestSendHeadersEvent : WebRequestEvent {};

每个 WebRequest 都有一个关联的:

注:拦截器将由 controlledframe 元素事件循环上的任务写入,但会在 fetch 期间并行读取。

在分派 WebRequest 事件之前,会创建 适用的 WebRequestInterceptors 的快照。 在处理事件时注册到 WebRequestInterceptor 上的事件监听器不会针对该事件触发。

每个 WebRequestInterceptor 都有一个关联的:

每个 UploadData 都有一个关联的:

每个 RequestBody 都有一个关联的:

每个 WebRequestRequest 都有一个关联的:

每个 AuthChallenger 都有一个关联的:

每个 WebRequestAuthDetails 都有一个关联的:

每个 WebRequestResponse 都有一个关联的:

每个 WebRequestEvent 都有一个关联的:

每个 WebRequestAuthRequiredEvent 都有一个关联的:

每个 WebRequestBeforeRedirectEvent 都有一个关联的:

每个 WebRequestCompletedEvent 都有一个关联的:

每个 WebRequestErrorOccurredEvent 都有一个关联的:

每个 WebRequestHeadersReceivedEvent 都有一个关联的:

每个 WebRequestResponseStartedEvent 都有一个关联的:

createWebRequestInterceptor(options) 方法步骤为:
  1. 令 interceptor 为一个新的 WebRequestInterceptor 对象。

  2. 在 interceptor 上设置以下字段:

    resourceTypes

    options["resourceTypes"]

    blocking

    options["blocking"]

    includeRequestBody

    options["includeRequestBody"]

    includeHeaders

    options["includeHeaders"]

    securityInfo

    options["securityInfo"]

    securityInfoRawDer

    options["securityInfoRawDer"]

  3. 对于 options["urlPatterns"] 中的每个 urlPattern:

    1. 如果 urlPattern 是一个 URLPattern, 则将 urlPattern 追加到 interceptor 的 urlPatterns。

    2. 否则,给定 urlPattern,将一个新的 URLPattern 追加到 interceptor 的 urlPatterns。

  4. 将 interceptor 追加到 this 的 拦截器。

  5. 返回 interceptor。

要获取一个请求 request 的适用的 WebRequestInterceptor, 运行以下步骤:
  1. 令 client 为 request 的客户端。

  2. 如果 client 为 null,则返回一个空列表和 false。

  3. 令 window 为给定 client,环境设置对象的所属 Window。

  4. 如果 window 为 null,则返回一个空列表和 false。

  5. 令 navigable 为 window 的navigable。

  6. 如果 navigable 或其 controlledFrameEmbedderParent 为 null,则返回一个空列表 和 false。

  7. 令 controlledFrame 为 navigable 的 controlledFrameEmbedderParent。

  8. 令 applicableInterceptors 为空列表。

  9. 对于 controlledFrame 的 request 的 拦截器中的每个 interceptor:

    1. 如果 request 不应被 interceptor 拦截, 则继续。

    2. 将 interceptor 追加到 applicableInterceptors。

  10. 返回 applicableInterceptors。

要确定一个请求 request 是否应被一个 WebRequestInterceptor 拦截, 运行以下步骤:
  1. 令 types 为 interceptor 的 resourceTypes。

  2. 如果 types 不是空, 且 types 不 包含给定 request 调用获取请求的 ResourceType的结果,则返回 false。

  3. 令 urlPatterns 为 interceptor 的 urlPatterns。

  4. 对于 urlPatterns 中的每个 urlPattern:

    1. 如果 request 的 URL 给定 urlPattern 匹配一个 URLPattern,则返回 true。

  5. 返回 false。

要获取一个环境设置对象的所属 Window, 给定一个环境设置对象 environment,运行 以下步骤:
  1. 令 global 为 environment 的全局对象。

  2. 如果 global 是一个 Window 对象,则返回 global。

  3. 如果 global 是一个 DedicatedWorkerGlobalScope 对象,则:

    1. 令 owner 为 global。

    2. 当 owner 是一个 DedicatedWorkerGlobalScope 对象时:

      1. 令 owner 为 owner 的所有者集合[0]。

    3. 如果 owner 是一个 Document 对象,则返回 owner 的 相关全局对象。

  4. 返回 null。

4.1. 事件

WebRequestInterceptor 触发以下事件:

事件名称 接口 触发时机...
authrequired WebRequestAuthRequiredEvent 一个被拦截的请求收到一个 HTTP 401(Unauthorized)407(Proxy Authentication Required)状态的响应时。
beforeredirect WebRequestBeforeRedirectEvent 一个被拦截的请求收到一个重定向响应时。
beforerequest WebRequestBeforeRequestEvent 一个被拦截的请求即将开始 处理时。
beforesendheaders WebRequestBeforeSendHeadersEvent 一个被拦截的 请求的请求标头即将发送时。
completed WebRequestCompletedEvent 一个被拦截的请求完成时。
erroroccurred WebRequestErrorOccurredEvent 处理一个被拦截的 请求时发生错误。
headersreceived WebRequestHeadersReceivedEvent 一个被拦截的请求收到 响应标头时。
sendheaders WebRequestSendHeadersEvent 一个被拦截的请求发送其请求 标头时。
responsestarted WebRequestResponseStartedEvent 一个被拦截的请求已开始 接收其响应时。

WebRequestInterceptor 支持以下事件处理程序(以及它们 对应的事件处理程序事件类型)作为事件处理程序 IDL 属性:

事件处理程序 事件处理程序事件类型
onauthrequired authrequired
onbeforeredirect beforeredirect
onbeforerequest beforerequest
onbeforesendheaders beforesendheaders
oncompleted completed
onerroroccurred erroroccurred
onheadersreceived headersreceived
onsendheaders sendheaders
onresponsestarted responsestarted

每个 WebRequestAuthRequiredEvent 都有一个关联的:

WebRequestAuthRequiredEvent 的 setCredentials(credentials, options) 方法步骤为:
  1. 将 this 的 authCredentials 设置为 credentials。

  2. 将 this 的 options 设置为 options。

WebRequestAuthRequiredEvent 的 preventDefault() 方法步骤为将 this 的 cancel 设置为 true。

每个 WebRequestBeforeRequestEvent 都有一个关联的:

WebRequestBeforeRequestEvent 的 redirect(redirectURL) 方法步骤为将 this 的 redirectURL 设置为 redirectURL。
WebRequestBeforeRequestEvent 的 preventDefault() 方法步骤为将 this 的 cancel 设置为 true。

每个 WebRequestBeforeSendHeadersEvent 都有一个关联的:

WebRequestBeforeSendHeadersEvent 的 setRequestHeaders(requestHeaders) 方法步骤为将 this 的 requestHeaders 设置为 requestHeaders。
WebRequestBeforeSendHeadersEvent 的 preventDefault() 方法步骤为将 this 的 cancel 设置为 true。

每个 WebRequestHeadersReceivedEvent 都有一个关联的:

WebRequestHeadersReceivedEvent 的 redirect(redirectURL) 方法步骤为将 this 的 redirectURL 设置为 redirectURL。
WebRequestHeadersReceivedEvent 的 setResponseHeaders(responseHeaders) 方法步骤为将 this 的 responseHeaders 设置为 responseHeaders。
WebRequestHeadersReceivedEvent 的 preventDefault() 方法步骤为将 this 的 cancel 设置为 true。

WebRequestEvent 结果是一个具有以下 项的结构:

cancel

一个布尔值,初始为 false

redirectURL

一个 USVString, 初始为 ""

authCredentials

一个 WebRequestAuthCredentials 或 null,初始为 null

requestHeaders

一个标头列表,初始为 «»

responseHeaders

一个标头列表,初始为 «»

要处理 beforeRequest 事件,给定一个请求 request, 运行以下步骤:
  1. 令 interceptors 为获取 request 的适用的 WebRequestInterceptors的结果。

  2. 令 result 为一个 WebRequestEvent 结果。

  3. 令 pendingHandlerCount 为 0。

  4. 令 controlledFrameEmbedderGlobal 为给定 request 的客户端,获取环境的 controlledFrameEmbedderParent的结果的相关全局对象。

  5. 如果 controlledFrameEmbedderGlobal 为 null,则返回。

  6. 对于 interceptors 中的每个 interceptor:

    1. 如果 interceptor 的 blocking 为 true, 则递增 pendingHandlerCount。

    2. 在 controlledFrameEmbedderGlobal 的 DOM 操作任务源上排队一个全局任务,该任务将运行以下步骤:

      1. 令 event 为一个新的、名为 beforerequest 的 WebRequestBeforeRequestEvent。

      2. 给定 event、request 和 "none",填充 WebRequestEvent。

      3. 如果 interceptor 的 includeRequestBody 为 true,且 request 的主体不是 null,则:

        1. 令 requestBody 为一个新的 RequestBody。

        2. 令 body 为 request 的主体。

          TODO:如果 body 的流存在,则对其进行序列化。

        3. 按 body 的源切换:

          字节序列

          将一个新的 UploadData 追加到 requestBody 的 raw,其 bytes 等于已序列化的 body 的源。

          Blob

          将一个新的 UploadData 追加到 requestBody 的 raw,其 bytes 等于已序列化的 body 的源。

          FormData
          1. 令 formData 为 «[]»。

          2. 对于 body 的源的 条目 列表中的每个 entry:

            1. 按 entry[1] 切换:

            File

            将一个新的 UploadData 追加到 requestBody 的 raw,其 file 等于 entry[1] 的 name。

            USVString
            1. 如果 formData[entry[0]] 不存在,则将 formData[entry[0]] 设置为空列表。

            2. 将 entry[1] 追加到 formData[entry[0]]。

          3. 将 requestBody 的 formData 设置为 formData。

        4. 将 event 的 request 的 body 设置为 requestBody。

      4. 将 event 分派给 interceptor。

      5. 如果 event 的 cancel 为 true, 则将 result 的 cancel 设置为 true。

      6. 如果 event 的 redirectURL 不为 null,且 result 的 redirectURL 为 "", 则将 result 的 redirectURL 设置为 event 的 redirectURL。

      7. 如果 interceptor 的 blocking 为 true, 则递减 pendingHandlerCount。

  7. 如果 pendingHandlerCount > 0,则并行等待 pendingHandlerCount 等于 0,然后排队一个全局任务,该任务将在 request 的客户端的全局对象的网络任务源,或这些步骤最初被调用所在的 并行上下文上继续运行此算法的剩余步骤, 具体取决于这些步骤在进入并行之前是如何运行的。

  8. 返回 result。

要处理 beforeSendHeaders 事件,给定一个请求 request, 运行以下步骤:
  1. 令 interceptors 为获取 request 的适用的 WebRequestInterceptors的结果。

  2. 令 result 为一个 WebRequestEvent 结果。

  3. 令 pendingHandlerCount 为 0。

  4. 令 controlledFrameEmbedderGlobal 为给定 request 的客户端,获取环境的 controlledFrameEmbedderParent的结果的相关全局对象。

  5. 如果 controlledFrameEmbedderGlobal 为 null,则返回。

  6. 对于 interceptors 中的每个 interceptor:

    1. 如果 interceptor 的 blocking 为 true, 则递增 pendingHandlerCount。

    2. 在 controlledFrameEmbedderGlobal 的 DOM 操作任务源上排队一个全局任务,该任务将运行以下步骤:

      1. 令 event 为一个新的、名为 beforesendheaders 的 WebRequestBeforeSendHeadersEvent。

      2. 给定 event、request,以及 interceptor 的 includeHeaders, 填充 WebRequestEvent。

      3. 将 event 分派给 interceptor。

      4. 如果 event 的 cancel 为 true, 则将 result 的 cancel 设置为 true。

      5. 如果 event 的 requestHeaders 不为 null,则:

        1. 如果 result 的 requestHeaders 为 null,则将其设置为一个新的 Headers。

        2. 对于 event 的 requestHeaders 中的每个 header:

          1. 将 header 追加到 result 的 requestHeaders。

      6. 如果 interceptor 的 blocking 为 true, 则递减 pendingHandlerCount。

  7. 如果 pendingHandlerCount > 0,则并行等待 pendingHandlerCount 等于 0,然后排队一个全局任务,该任务将在 request 的客户端的全局对象的网络任务源,或这些步骤最初被调用所在的 并行上下文上继续运行此算法的剩余步骤, 具体取决于这些步骤在进入并行之前是如何运行的。

  8. 返回 result。

要处理 sendHeaders 事件,给定一个请求 request, 运行以下步骤:
  1. 令 interceptors 为获取 request 的适用的 WebRequestInterceptors的结果。

  2. 令 controlledFrameEmbedderGlobal 为给定 request 的客户端,获取环境的 controlledFrameEmbedderParent的结果的相关全局对象。

  3. 如果 controlledFrameEmbedderGlobal 为 null,则返回。

  4. 对于 interceptors 中的每个 interceptor:

    1. 在 controlledFrameEmbedderGlobal 的 DOM 操作任务源上排队一个全局任务,该任务将运行以下步骤:

      1. 令 event 为一个新的、名为 sendheaders 的 WebRequestSendHeadersEvent。

      2. 给定 event、request,以及 interceptor 的 includeHeaders, 填充 WebRequestEvent。

      3. 将 event 分派给 interceptor。

要处理 headersReceived 事件,给定一个请求 request 和一个响应 response,运行以下步骤:
  1. 令 interceptors 为获取 request 的适用的 WebRequestInterceptors的结果。

  2. 令 result 为一个 WebRequestEvent 结果。

  3. 令 pendingHandlerCount 为 interceptor 的大小。

  4. 令 controlledFrameEmbedderGlobal 为给定 request 的客户端,获取环境的 controlledFrameEmbedderParent的结果的相关全局对象。

  5. 如果 controlledFrameEmbedderGlobal 为 null,则返回。

  6. 对于 interceptors 中的每个 interceptor:

    1. 如果 interceptor 的 blocking 为 true, 则递增 pendingHandlerCount。

    2. 在 controlledFrameEmbedderGlobal 的 DOM 操作任务源上排队一个全局任务,该任务将运行以下步骤:

      1. 令 event 为一个新的、名为 headersreceived 的 WebRequestHeadersReceivedEvent。

      2. 给定 event、request 和 "none", 填充 WebRequestEvent。

      3. 将 event 的 response 设置为给定 request、 response,以及 interceptor 的 includeHeaders, 创建 WebRequestResponse 对象的结果。

      4. 如果 interceptor 的 securityInfo 为 true,或 interceptor 的 securityInfoRawDer 为 true,则:

        1. 令 info 为给定 response 和 interceptor 的 securityInfoRawDer,获取 安全信息的结果。

        2. 将 event 的 securityInfo 设置为 info。

      5. 将 event 分派给 interceptor。

      6. 如果 event 的 cancel 为 true, 则将 result 的 cancel 设置为 true。

      7. 如果 event 的 redirectURL 不为 null,且 result 的 redirectURL 为 "", 则将 result 的 redirectURL 设置为 event 的 redirectURL。

      8. 如果 event 的 responseHeaders 不为 null,则:

        1. 如果 result 的 responseHeaders 为 null,则将其设置为一个新的 Headers。

        2. 对于 event 的 responseHeaders 中的每个 header:

          1. 将 header 追加到 result 的 responseHeaders。

      9. 如果 interceptor 的 blocking 为 true, 则递减 pendingHandlerCount。

  7. 如果 pendingHandlerCount > 0,则并行等待 pendingHandlerCount 等于 0,然后排队一个全局任务,该任务将在 request 的客户端的全局对象的网络任务源,或这些步骤最初被调用所在的 并行上下文上继续运行此算法的剩余步骤, 具体取决于这些步骤在进入并行之前是如何运行的。

  8. 返回 result。

要处理 authRequired 事件,给定一个请求 request 和一个响应 response,运行以下步骤:
  1. 令 challenger 为一个新的 AuthChallenger, 其 host 和 port 等于 response 的 URL 的主机和 端口。

  2. 如果 response 的状态为 401,则:

    1. 令 isProxy 为 false。

    2. 令 scheme 为来自 response 的 WWW-Authenticate 标头的 scheme, 按 [HTML] 规范中定义的方式解析;如果该标头 缺失或无效,则为 null。

    3. 令 realm 为来自 response 的 WWW-Authenticate 标头的 realm, 按 [HTML] 规范中定义的方式解析。

  3. 否则:

    1. 令 isProxy 为 true。

    2. 令 scheme 为来自 response 的 Proxy-Authenticate 标头的 scheme,按 [HTML] 规范中定义的方式解析;如果 该标头缺失或无效,则为 null。

    3. 令 realm 为来自 response 的 Proxy-Authenticate 标头的 realm, 按 [HTML] 规范中定义的方式解析。

  4. 如果 scheme 为 null,则返回 null。

  5. 令 interceptors 为获取 request 的适用的 WebRequestInterceptors的结果。

  6. 令 result 为一个 WebRequestEvent 结果。

  7. 令 pendingHandlerCount 为 0。

  8. 令 controlledFrameEmbedderGlobal 为给定 request 的客户端,获取环境的 controlledFrameEmbedderParent的结果的相关全局对象。

  9. 如果 controlledFrameEmbedderGlobal 为 null,则返回。

  10. 对于 interceptors 中的每个 interceptor:

    1. 如果 interceptor 的 blocking 为 true, 则递增 pendingHandlerCount。

    2. 在 controlledFrameEmbedderGlobal 的 DOM 操作任务源上排队一个全局任务,该任务将运行以下步骤:

      1. 令 event 为一个新的、名为 authrequired 的 WebRequestAuthRequiredEvent。

      2. 给定 event、request 和 "none", 填充 WebRequestEvent。

      3. 将 event 的 response 设置为给定 request、 response,以及 interceptor 的 includeHeaders, 创建 WebRequestResponse 对象的结果。

      4. 将 event 的 response 的 auth 设置为一个新的 WebRequestAuthDetails, 其 challenger、 isProxy、 scheme 和 realm 字段的值 分别为 challenger、isProxy、scheme 和 realm。

      5. 将 event 分派给 interceptor。

      6. 令 credentials 为 event 的 authCredentials。

      7. 如果 event 的 cancel 为 true, 则将 result 的 cancel 设置为 true。

      8. 否则,如果 credentials 是一个 Promise, 则:

        1. 令 signal 为 event 的 options["signal"]。

        2. 令 done 为 false。

        3. 如果 signal 是一个 AbortSignal, 则向 signal 添加 以下中止算法:

          1. 将 result 的 cancel 设置为 true。

          2. 将 done 设置为 true。

        4. 在 credentials 兑现时,运行以下接收 resolvedValue 的步骤:

          1. 如果 resolvedValue 是一个字典,且包含 两个等于 "username" 和 "password" 的键,并且 result 的 authCredentials 为 undefined,则将 result 的 authCredentials 设置为 resolvedValue。

          2. 将 done 设置为 true。

        5. 在 credentials 拒绝时,运行以下步骤:

          1. 将 done 设置为 true。

          注:被拒绝的 promise 不会取消请求,但不会向服务器 提供凭据。

        6. 并行等待 done 等于 true,然后在 controlledFrameEmbedderGlobal 的 DOM 操作任务 源上排队一个全局任务,该任务将继续运行 此算法的剩余步骤。

      9. 如果 interceptor 的 blocking 为 true, 则递减 pendingHandlerCount。

  11. 如果 pendingHandlerCount > 0,则并行等待 pendingHandlerCount 等于 0,然后排队一个全局任务,该任务将在 request 的客户端的全局对象的网络任务源,或这些步骤最初被调用所在的 并行上下文上继续运行此算法的剩余步骤, 具体取决于这些步骤在进入并行之前是如何运行的。

  12. 返回 result。

要处理 beforeRedirect 事件,给定一个请求 request 和一个响应 response,运行以下步骤:
  1. 令 interceptors 为获取 request 的适用的 WebRequestInterceptors的结果。

  2. 令 controlledFrameEmbedderGlobal 为给定 request 的客户端,获取环境的 controlledFrameEmbedderParent的结果的相关全局对象。

  3. 如果 controlledFrameEmbedderGlobal 为 null,则返回。

  4. 对于 interceptors 中的每个 interceptor:

    1. 在 controlledFrameEmbedderGlobal 的 DOM 操作任务源上排队一个全局任务,该任务将运行以下步骤:

      1. 令 event 为一个新的、名为 beforeredirect 的 WebRequestBeforeRedirectEvent。

      2. 给定 event、request 和 "none", 填充 WebRequestEvent。

      3. 将 event 的 response 设置为给定 request、 response,以及 interceptor 的 includeHeaders, 创建 WebRequestResponse 对象的结果。

      4. 令 internalResponse 为 response,如果 response 不是过滤后的响应;否则为 response 的内部响应。

      5. 将 event 的 response 的 redirectURL 设置为给定 request 的当前 URL的 片段,internalResponse 的 位置 URL。

      6. 将 event 分派给 interceptor。

要处理 responseStarted 事件,给定一个请求 request 和一个响应 response,运行以下步骤:
  1. 令 interceptors 为获取 request 的适用的 WebRequestInterceptors的结果。

  2. 令 controlledFrameEmbedderGlobal 为给定 request 的客户端,获取环境的 controlledFrameEmbedderParent的结果的相关全局对象。

  3. 如果 controlledFrameEmbedderGlobal 为 null,则返回。

  4. 对于 interceptors 中的每个 interceptor:

    1. 在 controlledFrameEmbedderGlobal 的 DOM 操作任务源上排队一个全局任务,该任务将运行以下步骤:

      1. 令 event 为一个新的、名为 responsestarted 的 WebRequestResponseStartedEvent。

      2. 给定 event、request 和 "none", 填充 WebRequestEvent。

      3. 将 event 的 response 设置为给定 request、 response,以及 interceptor 的 includeHeaders, 创建 WebRequestResponse 对象的结果。

      4. 将 event 分派给 interceptor。

要处理 completed 事件,给定一个请求 request 和一个响应 response,运行以下步骤:
  1. 令 interceptors 为获取 request 的适用的 WebRequestInterceptors的结果。

  2. 令 controlledFrameEmbedderGlobal 为给定 request 的客户端,获取环境的 controlledFrameEmbedderParent的结果的相关全局对象。

  3. 如果 controlledFrameEmbedderGlobal 为 null,则返回。

  4. 对于 interceptors 中的每个 interceptor:

    1. 在 controlledFrameEmbedderGlobal 的 DOM 操作任务源上排队一个全局任务,该任务将运行以下步骤:

      1. 令 event 为一个新的、名为 completed 的 WebRequestCompletedEvent。

      2. 给定 event、request 和 "none", 填充 WebRequestEvent。

      3. 将 event 的 response 设置为给定 request、 response,以及 interceptor 的 includeHeaders, 创建 WebRequestResponse 对象的结果。

      4. 将 event 分派给 interceptor。

要处理 errorOccurred 事件,给定一个请求 request 和一个响应 response,运行以下步骤:
  1. 令 interceptors 为获取 request 的适用的 WebRequestInterceptors的结果。

  2. 令 controlledFrameEmbedderGlobal 为给定 request 的客户端,获取环境的 controlledFrameEmbedderParent的结果的相关全局对象。

  3. 如果 controlledFrameEmbedderGlobal 为 null,则返回。

  4. 对于 interceptors 中的每个 interceptor:

    1. 在 controlledFrameEmbedderGlobal 的 DOM 操作任务源上排队一个全局任务,该任务将运行以下步骤:

      1. 令 event 为一个新的、名为 erroroccurred 的 WebRequestErrorOccurredEvent。

      2. 给定 event、request 和 "none", 填充 WebRequestEvent。

      3. 将 event 的 error 设置为一个 描述 response 中错误的实现定义的错误消息。

      4. 将 event 分派给 interceptor。

要填充一个 WebRequestEvent, 给定一个 WebRequestEvent event、一个请求 request,以及一个 RequestedHeaders requestedHeaders,运行以下步骤:
  1. 令 environmentSettingsObject 为 request 的客户端。

  2. 在 event 上设置以下字段:

    frameId

    -1

  3. 令 window 为给定 environmentSettingsObject, 环境设置对象的所属 Window。

  4. 如果 window 不为 null,则:

    1. 令 parentNavigable 为 window 的navigable 的 parent。

    2. 更新 event 的以下字段:

      documentId

      environmentSettingsObject 的id。

      documentLifecycle

      给定 window 的关联文档, 获取 Document 的 DocumentLifecycle的结果。

      frameId

      window 的navigable 的 frameId。

      frameType

      如果 window 的 浏览上下文的 fenced frame config instance 为非 null,则为 "fenced-frame"; 如果 parentNavigable 为 null,则为 "outermost-frame"; 否则为 "sub-frame"。

    3. 如果 parentNavigable 不为 null,则更新 event 的以下值:

      parentDocumentId

      parentNavigable 的活动文档的相关全局对象的 id。

      parentFrameId

      parentNavigable 的 frameId。

  5. 将 event 的 request 设置为一个具有以下字段的新的 WebRequestRequest:

    url

    request 的 URL 列表的最后一个元素。

    method

    request 的方法。

    initiator

    给定 request 的源,源的序列化。

    注:不透明源会导致 initiator 被设置为 DOMString "null"。

    type

    给定 request,调用获取请求的 ResourceType的结果。

    id

    request 的 requestId。

  6. 如果 requestedHeaders 不是 "none", 则将 event 的 request 的 headers 设置为给定 request 的标头列表、requestedHeaders,以及 isRequest 等于 true,调用将标头列表转换为 Headers 对象的结果。

要获取一个 Document 的 DocumentLifecycle, 给定 document, 运行以下步骤:
  1. 如果 document 的 unload counter > 0,则返回 "pending-deletion"。

  2. 如果 document 的节点 navigable为非 null,且是一个预渲染 navigable,则返回 "prerender"。

  3. 如果 document 是可抢救的,并且没有其 page showing, 则返回 "cached"。

  4. 返回 "active"。

要创建 一个 WebRequestResponse 对象,给定一个请求 request、一个响应 response,以及一个 RequestedHeaders requestedHeaders,运行以下步骤:
  1. 令 response 为一个具有以下字段的新的 WebRequestResponse:

    statusCode

    response 的状态。

    statusLine

    response 的状态消息。

    fromCache

    如果 response 的缓存状态为 "local",则为 true;否则为 false。

    ip

    如果该请求涉及网络请求,则为接收 response 来源的 IP 地址。

    [FETCH] 规范目前未指定存储发送 request 时使用的远程 IP 地址。

  2. 如果 requestedHeaders 不是 "none", 则将 response 的 headers 设置为 给定 response 的标头列表、requestedHeaders,以及 isRequest 等于 false,调用将标头列表转换为 Headers 对象的结果。

  3. 返回 response。

要获取安全信息, 给定一个响应 response 和一个布尔值 includeRawDER, 运行以下步骤:
  1. 令 info 为一个新的 SecurityInfo。

  2. 令 scheme 为 response 的url 的scheme。

  3. 如果 scheme 为 "http" 或 "ws":

    1. 将 info["state"] 设置为 "insecure"。

    2. 返回 info。

  4. 将 info["state"] 设置为 "secure"。

    注:浏览器通常会在证书错误时中断 连接。如果用户已明确允许,则状态可能改为设置 为 "broken"。

  5. 令 leafCert 为与 response 关联的服务器 X.509 证书(定义于 [RFC5280])。

  6. 令 derBytes 为对 leafCert 进行 DER 编码的结果(定义于 [X.690])。

  7. 令 certInfo 为一个新的 CertificateInfo。

  8. 令 fingerprint 为一个新的 Fingerprint。

  9. 计算 fingerprint 字符串:

    1. 令 hashBytes 为对 derBytes 执行 SHA-256 算法(定义于 [RFC6234])的结果。

    2. 令 hexString 为空字符串。

    3. 对于 hashBytes 中的每个字节 byte:

      1. 如果 hexString 非空,则将 U+003A (:) 追加到 hexString。

      2. 令 hexPair 为表示 byte 的两个 ASCII 大写十六进制数字组成的字符串。

      3. 将 hexPair 追加到 hexString。

    4. 将 fingerprint["sha256"] 设置为 hexString。

  10. 将 certInfo["fingerprint"] 设置为 fingerprint。

  11. 如果 includeRawDER 为 true:

    1. 令 arrayBuffer 为从 derBytes 创建 ArrayBuffer 的结果。

    2. 将 certInfo["rawDER"] 设置为一个新的、查看 arrayBuffer 的 Uint8Array 对象。

  12. 令 certList 为空列表。

  13. 将 certInfo 追加到 certList。

  14. 将 info["certificates"] 设置为 certList。

  15. 返回 info。

要将一个标头 列表转换为 Headers 对象,给定 一个标头列表 fetchHeaders、一个 RequestedHeaders requestedHeaders, 和一个布尔值 isRequest,运行以下步骤:
  1. 断言 requestedHeaders 不是 "none"。

  2. 令 headers 为一个新的 Headers 对象。

  3. 对于 fetchHeaders 中的每个 fetchHeader:

    1. 如果满足以下所有条件,则继续:

    2. 如果满足以下所有条件,则继续:

    3. 将 fetchHeader 追加到 headers。

  4. 返回 headers。

要获取一个 请求的 ResourceType, 给定一个请求 request,运行以下步骤:
  1. 如果 request 的url 的scheme 等于 "ws" 或 "wss", 则返回 "websocket"。

  2. 如果 request 的initiator 等于 "fetch" 或 "xmlhttprequest",则返回 "xmlhttprequest"。

  3. 如果 request 的destination 等于 "document", 则返回 "main-frame"。

  4. 如果 request 的destination 等于 "frame" 或 "iframe", 则返回 "sub-frame"。

  5. 如果 request 的destination 等于 "style" 或 "xslt", 则返回 "stylesheet"。

  6. 如果 request 的destination 等于 "script"、 "json"、 "audioworklet"、"paintworklet"、"serviceworker"、 "sharedworker" 或 "worker",则返回 "script"。

  7. 如果 request 的destination 等于 "image", 则返回 "image"。

  8. 如果 request 的destination 等于 "font", 则返回 "font"。

  9. 如果 request 的destination 等于 "object" 或 "embed", 则返回 "object"。

  10. 如果 request 的destination 等于 "audio"、 "track" 或 "video",则返回 "media"。

  11. 如果 request 的destination 等于 "report", 则返回 "csp-report"。

  12. 如果 request 的destination 等于 "",且 request 的 keepalive 为 true,则返回 "ping"。

  13. 返回 "other"。

要创建一个 重定向响应,给定一个 DOMString redirectUrl, 返回一个具有以下字段的响应:
状态

301

标头列表

« ("Location", redirectUrl) »

4.2. 猴子补丁

4.2.1. Fetch

一个请求具有关联的 requestId,它 是一个 不透明字符串,在请求创建时随机分配。

main fetch 算法被猴子补丁如下:

  1. 令 request 为 fetchParams 的 request。

  2. 令 response 为 null。

  3. 令 webRequestResult 为给定 request 调用处理 beforeRequest 事件的结果。
  4. 如果 webRequestResult 不为 null,则:
    1. 如果 webRequestResult 的 cancel 为 true,则将 response 设置为网络错误。
    2. 否则,如果 webRequestResult 的 redirectURL 不是一个空 DOMString, 则将 response 设置为 给定 webRequestResult 的 redirectURL 创建重定向响应的结果。

fetch response handover 算法被猴子补丁如下:

  1. 如果 response 不是网络错误,则给定 fetchParams 的 request 和 response,调用处理 responseStarted 事件。
  2. 令 timingInfo 为 fetchParams 的 timing info。

⋮

  1. 如果 fetchParams 的 process response consume body 非 null,则:

    …

  2. 如果 response 不是网络错误,则给定 fetchParams 的 request 和 response,调用处理 completed 事件。
  3. 否则,给定 fetchParams 的 request 和 response,调用 处理 errorOccurred 事件。

HTTP-network-or-cache fetch 算法被猴子 补丁如下:

  1. 令 revalidatingFlag 为未设置。

  2. 将 webRequestResult 设置为给定 request 调用处理 beforeSendHeaders 事件的结果。
  3. 如果 webRequestResult 不为 null,则:
    1. 如果 webRequestResult 的 cancel 为 true,则将 response 设置为网络错误。
    2. 否则,如果 webRequestResult 的 requestHeaders 是非空列表,则将 request 的 标头列表设置为 webRequestResult 的 requestHeaders 的标头列表。
  4. 如果 response 不为 null, 运行这些步骤,但在 fetchParams 被取消时中止:

    ⋮

  5. 如果已中止,则返回适合 fetchParams 的网络错误。

  6. 如果 response 为 null,则:

    1. 如果 httpRequest 的 cache mode 为 "only-if-cached",则返回一个 网络错误。

    2. 给定 request,调用处理 sendHeaders 事件。
    3. 令 forwardResponse 为给定 httpFetchParams、includeCredentials 和 isNewConnectionFetch,运行HTTP-network fetch的结果。

    4. 如果 forwardResponse 不是网络错误,令 webRequestResult 为给定 request 和 forwardResponse 调用处理 headersReceived 事件的结果; 否则为 null。
    5. 如果 webRequestResult 不为 null,则:
      1. 如果 webRequestResult 的 cancel 为 true,则将 response 设置为网络错误。
      2. 否则,如果 webRequestResult 的 redirectURL 不是空 DOMString, 则将 forwardResponse 设置为给定 webRequestResult 的 redirectURL 创建重定向响应的结果。
      3. 否则,如果 webRequestResult 的 responseHeaders 是非空 列表,则将 forwardResponse 的标头列表设置为 webRequestResult 的 responseHeaders 的 标头列表。

⋮

  1. 如果 response 的状态为 401,httpRequest 的 response tainting 不是 "cors",includeCredentials 为 true,且 request 的 window 是一个 环境设置对象,则:

    ⋮

    1. 如果 request 的 use-URL-credentials flag 未设置,或 isAuthenticationFetch 为 true,则:

      1. 如果 fetchParams 被取消,则返回适合 fetchParams 的网络 错误。

      2. 令 username 和 password 为 null。

      3. 令 webRequestResult 为给定 request 和 response 调用处理 authRequired 事件的结果。
      4. 如果 webRequestResult 不为 null,则:
        1. 如果 webRequestResult 的 cancel 为 true,则将 response 设置为网络错误。
        2. 否则,如果 webRequestResult 的 authCredentials 是一个 object, 则:
          1. 将 username 设置为 webRequestResult 的 authCredentials["username"]。
          2. 将 password 设置为 webRequestResult 的 authCredentials["password"]。
      5. 如果 username 和 password 为 null,则将它们分别设置为 在 request 的window 中提示最终用户输入用户名和密码的结果。
  2. 如果 response 的状态为 407,则:

    1. 令 webRequestResult 为给定 request 和 response 调用处理 authRequired 事件的结果。
    2. 如果 webRequestResult 不为 null,则:
      1. 如果 webRequestResult 的 cancel 为 true,则将 response 设置为网络错误。
      2. 否则,如果 webRequestResult 的 authCredentials 是一个 object, 则:
        1. 将 webRequestResult 的 authCredentials 存储为proxy-authentication entry。
    3. 否则, 适当地提示最终用户 ...

HTTP-redirect fetch 算法被猴子补丁如下:

  1. 给定 request 和 response,调用处理 beforeRedirect 事件。
  2. 令 request 为 fetchParams 的 request。

5. 上下文菜单 API

enum ContextType {
    "all",
    "page",
    "frame",
    "selection",
    "link",
    "editable",
    "image",
    "video",
    "audio",
};

enum ItemType {
    "normal",
    "checkbox",
    "radio",
    "separator",
};

dictionary ContextMenusProperties {
    boolean checked;
    sequence<ContextType> contexts;
    sequence<(URLPattern or URLPatternInput)> documentURLPatterns;
    boolean enabled;
    DOMString parentId;
    sequence<(URLPattern or URLPatternInput)> targetURLPatterns;
    DOMString title;
    ItemType type;
};

dictionary ContextMenusCreateProperties : ContextMenusProperties {
    required DOMString id;
};

[Exposed=Window, IsolatedContext]
interface ContextMenus : EventTarget {
    Promise<undefined> create(ContextMenusCreateProperties properties);
    Promise<undefined> remove(DOMString id);
    Promise<undefined> removeAll();
    Promise<undefined> update(DOMString id, optional ContextMenusProperties properties = {});

    attribute EventHandler onclick;
    attribute EventHandler onshow;
};

[Exposed=Window, IsolatedContext]
interface MenuItemDetails {
    readonly attribute DOMString id;
    readonly attribute DOMString? parentMenuId;
    readonly attribute boolean? checked;
    readonly attribute boolean? wasChecked;
};

[Exposed=Window, IsolatedContext]
interface ContextMenusClickEvent : Event {
  readonly attribute MenuItemDetails menuItem;

  // Details about the frame the context menu is opened within.
  readonly attribute long frameId;
  readonly attribute USVString frameURL;
  readonly attribute USVString pageURL;

  // Details about the element the context menu is opened within the context of.
  readonly attribute boolean editable;
  readonly attribute USVString? linkURL;
  readonly attribute DOMString? mediaType;
  readonly attribute DOMString? selectionText;
  readonly attribute USVString? srcURL;
};

每个 controlledframe 都有一个 contextMenus 成员,它是一个 ContextMenus。 每个 ContextMenus 管理一个 上下文菜单映射,其 键是 表示菜单项 id 的 DOMString, 其值是 ContextMenusProperties。

条目 中的每个上下文菜单映射表示一个 上下文菜单项。一个 上下文菜单项 表示上下文菜单中的一个条目。每个上下文菜单 项都具有关联的:

一个 上下文菜单表示一个实现定义的接口,可向用户显示 上下文菜单项。每个上下文菜单都具有关联的 上下文元素,即打开该上下文菜单 所处上下文中的 HTMLElement。

如果给定 item 确定该上下文菜单项是否会被显示返回 true,则应当作为实现定义的操作的结果,向用户显示上下文菜单项 item。

注:此 API 的意图是向用户公开依赖上下文的附加 操作。在桌面平台上,这可能表现为通过右键点击 Controlled Frame 内部内容来访问的上下文菜单中的条目; 在移动设备上,则可能通过长按 Controlled Frame 内部的某个项目来访问。在这些示例中,上下文 菜单的上下文元素会是用户右键点击或长按的元素。

上下文菜单映射的 值,即 ContextMenusProperties 对象,用于控制 上下文菜单项在何种条件下显示,以及这些项目的 特性和行为。

本节是非规范性的。

ContextMenusProperties 具有以下字段:

contexts

不同 ContextType 的列表。 如果它不是空, 则除非被点击以打开上下文菜单的元素等于其中一个 列表项,否则该 上下文菜单项不会显示。如果它是 空,则忽略此检查。

documentURLPatterns

URLPattern 或 URLPatternInput 的列表。 如果它不是 空,则除非嵌入文档的 URL 与其中一个列表项的 URLPattern 匹配,否则该上下文 菜单项不会显示。如果它是 空,则忽略此 检查。

targetURLPatterns

URLPattern 或 URLPatternInput 的列表。 如果它不是 空,则除非上下文菜单目标的 URL 与其中一个列表项的 URLPattern 匹配,否则该上下文 菜单项不会显示。如果它是 空,则忽略此检查。

注:Target 是 img/audio/video 标签的 "src" 属性 以及锚点标签的 "href"。

parentId

父上下文菜单项的 ID。该 上下文菜单项可以出现在父项的 子菜单下。

title

菜单项的标题。除非 type 是 "separator",否则这是必需的。

type

菜单项的类型。

checked

如果 type 为 checkbox, 该上下文菜单项最初是否被选中。

enabled

该上下文菜单项是否启用。

create(properties) 方法步骤为:

  1. 令 p 为一个新 promise。

  2. 令 controlledframe 为 this。

  3. 返回 p 并并行运行以下步骤。

  4. 令 contextMenusMap 为 controlledframe 的上下文 菜单映射。

  5. 令 id 为 properties["id"]。

  6. 如果 contextMenusMap[id] 存在,则给定 controlledframe、p 和 TypeError, 拒绝一个嵌入者 promise, 并中止这些步骤。

  7. 将 contextMenusMap[id] 设置为 properties。

  8. 给定 controlledframe 和 p,解决一个嵌入者 promise。

remove(id) 方法步骤为:

  1. 令 p 为一个新 promise。

  2. 令 controlledframe 为 this。

  3. 返回 p 并并行运行以下步骤。

  4. 令 contextMenusMap 为 controlledframe 的上下文 菜单映射。

  5. 移除 contextMenusMap[id]。

  6. 给定 controlledframe 和 p,解决一个嵌入者 promise。

removeAll() 方法步骤为:

  1. 令 p 为一个新 promise。

  2. 令 controlledframe 为 this。

  3. 返回 p 并并行运行以下步骤。

  4. 令 contextMenusMap 为 controlledframe 的上下文 菜单映射。

  5. 清空 contextMenusMap。

  6. 给定 controlledframe 和 p,解决一个嵌入者 promise。

update(id, properties) 方法 步骤为:

  1. 令 p 为一个新 promise。

  2. 令 controlledframe 为 this。

  3. 返回 p 并并行运行以下步骤。

  4. 令 contextMenusMap 为 controlledframe 的上下文 菜单映射。

  5. 如果 contextMenusMap[id] 不存在,则给定 controlledframe、p 和 TypeError, 拒绝一个嵌入者 promise, 并中止这些步骤。

  6. 将 contextMenusMap[id] 设置为 properties。

  7. 给定 controlledframe 和 p,解决一个嵌入者 promise。

本节是非规范性的。

ContextType 表示上下文菜单的上下文,可以是以下值:

frame

当用户在嵌套框架中上下文点击时适用,例如 iframe。

selection

当文档的一部分被选中时适用。

link

当用户在链接上上下文点击时适用。

editable

当用户在可编辑元素上上下文点击时适用,例如 textarea。

image

当用户在图像上上下文点击时适用。

video

当用户在 video 元素上上下文点击时适用。

audio

当用户在 audio 元素上上下文点击时适用。

page

当用户在页面中上下文点击,但其他页面上下文都不适用时适用(例如,该点击不在图像、 嵌套 iframe 或链接上)。

all

指定 all 等价于所有其他上下文的组合。

要确定该上下文菜单项是否会被显示 ,给定一个上下文菜单项 item:

  1. 令 properties 为 item 的properties。

  2. 令 element 为 item 的menu 的 上下文元素。

  3. 令 controlledframe 为 element 的节点 navigable的 controlledFrameEmbedderParent。

  4. 如果 controlledframe 为 null,则返回 false。

  5. 令 documentUrl 为 controlledframe 的嵌入的 navigable的活动文档的 URL。

  6. 令 targetUrl 为空字符串。

  7. 如果 element 是 HTMLImageElement 的实例,则将 targetUrl 设置为 element 的 src 属性。

  8. 如果 element 是 HTMLMediaElement 的实例,则将 targetUrl 设置为 element 的 src 属性。

  9. 如果 element 是 HTMLAnchorElement 的实例,则将 targetUrl 设置为 element 的 href 属性。

  10. 如果 properties["contexts"] 不是 空:

    1. 令 matchesContext 为初始值为 false 的布尔值。

    2. 对于 properties["contexts"] 中的每个 context:

      1. 如果 element 匹配 context,则将 matchesContext 设置为 true 并跳出;

        ContextType 的匹配行为尚未被指定,尽管上面的注释包含了一些期望行为的信息。

    3. 如果 matchesContext 为 false,则返回 false。

  11. 如果 properties["documentURLPatterns"] 不是空:

    1. 令 matchesDocumentUrl 为初始值为 false 的布尔值。

    2. 对于 properties["documentURLPatterns"] 中的每个 urlPattern:

      1. 如果 urlPattern 是一个 URLPatternInput, 则将 urlPattern 设置为给定 urlPattern 的 一个新的 URLPattern。

      2. 如果给定 urlPattern,documentUrl 匹配一个 URLPattern, 则将 matchesDocumentUrl 设置为 true 并跳出;

    3. 如果 matchesDocumentUrl 为 false,则返回 false。

  12. 如果 properties["targetURLPatterns"] 不是 空:

    1. 令 matchesTargetUrl 为初始值为 false 的布尔值。

    2. 对于 properties["targetURLPatterns"] 中的每个 urlPattern:

      1. 如果 urlPattern 是一个 URLPatternInput, 则将 urlPattern 设置为给定 urlPattern 的 一个新的 URLPattern。

      2. 如果给定 urlPattern,targetUrl 匹配一个 URLPattern,则 将 matchesTargetUrl 设置为 true 并跳出;

    3. 如果 matchesTargetUrl 为 false,则返回 false。

  13. 返回 true。

5.1. 事件

ContextMenus 触发以下事件:

事件名称 接口 触发时机...
show Event 向用户显示上下文菜单时。
click ContextMenusClickEvent 用户选择一个上下文菜单项时。

ContextMenus 支持以下事件处理程序(以及它们 对应的事件处理程序事件类型)作为事件处理程序 IDL 属性:

事件处理程序 事件处理程序事件类型
onshow show
onclick click

当 ContextMenus contextMenus 的一个或多个上下文菜单项被显示给用户时,向 contextMenus 分派一个 show 事件。

当一个上下文菜单项 item 被用户选中时, 给定 item 分派一个 click 事件。

要分派一个 show 事件, 给定一个 ContextMenus contextMenus,向 contextMenus 分派一个新的、名为 show 的 Event。
要分派一个 click 事件, 给定一个上下文菜单项 item,运行以下 步骤:
  1. 令 properties 为 item 的properties。

  2. 令 menu 为 item 的menu。

  3. 令 element 为 menu 的上下文 元素。

  4. 令 event 为一个新的、名为 click 的 ContextMenusClickEvent。

  5. 将 event["menuItem"] 设置为一个具有以下字段的新的 MenuItemDetails:

    id

    item 的id。

    parentMenuId

    properties["parentId"]。

    checked

    该上下文菜单项是否被选中。

    wasChecked

    复选框或单选项在被点击之前的状态。

  6. 设置 event 的以下字段:

    frameId

    element 的节点 navigable的 frameId。

    frameURL

    element 的节点 navigable的 URL。

    pageURL

    element 的traversable navigable的 URL。

    editable

    所选 element 是否可编辑,例如文本输入框。

    linkURL

    如果 element 是 HTMLAnchorElement 的实例,则为 element 的 href 属性。

    mediaType

    如果存在,则基于 element,为 "image"、"video" 或 "audio" 之一。

    selectionText

    上下文选择的文本,如果有。

    srcURL

    element 的 "src" 属性,如果存在。

  7. 在 menu 上分派 event。

6. 使用概述

Lorem ipsum。此处插入基本信息和示例。

7. 激励性应用

本节是非规范性的。

7.1. 虚拟化会话中的延迟敏感应用

在虚拟化环境中,用户通常有一个本地瘦客户端,用于渲染完整的虚拟桌面。 实际的桌面执行环境将在远程虚拟化服务器上运行。如果用户的浏览器导航到一个 延迟敏感应用(例如视频应用),所渲染的内容将具有额外延迟("lag"),从而使用户体验变得困难或 不可能。这也适用于会记录用户的应用,例如视频会议应用。在这些延迟敏感 应用中,虚拟桌面应用可以在本地渲染延迟敏感内容,并将其叠加在所渲染的远程内容之上, 以减少这种延迟。此用例也称为 "browser content redirection"。

7.2. 不受限制地嵌入第三方 Web 内容

在信息亭环境中,应用必须从第三方加载内容,并在其应用内的屏幕上 显示该内容。导航事件可能由教师触发,也可能由购物中心经理等管理员配置。 内容可能通过使用 X-Frame-Options 和 CSP 来禁止通过 iframe 嵌入。然而,controlled frame 应当能够加载所有内容,甚至包括禁止通过 iframe 嵌入的内容。

7.3. 远程显示和操纵 Web 内容

在信息亭环境中,应用必须确保内容持续显示在屏幕上,并且可能需要用它们自己提供的 行为打断内容。此行为应当在没有管理员本地值守的情况下工作,并且理想情况下可以通过网络远程管理。 例如,如果内容发生崩溃,这些应用应当观察并响应崩溃,在新的嵌入视图中重新加载内容。

7.4. 每个会话后清除用户内容

在某些环境中,某人只会短时间使用单个设备来完成其任务,例如在餐厅点餐。 当其任务完成时,嵌入者应用应当能够清除与该任务相关的所有本地用户数据, 然后重新启动嵌入实例。

7.5. 监控空闲会话

当用户与嵌入内容交互时,用户可能不会明确结束其会话。即使他们实际上已经完成或离开而没有完成任务, 该内容仍可能假定用户仍在场。嵌入者应用希望检测用户在超过其场景阈值时处于空闲状态, 并开始一个新的会话。

7.6. 任意阻止导航

在显示并非由嵌入者创作的嵌入式 Web 内容时,页面可能链接到被禁止的第三方 Web 内容。 允许嵌入者通过向 Web 内容中注入任意脚本来编辑嵌入内容中的元素,可以确保不会导航到被阻止的页面。 嵌入者还可以使用 Controlled Frame API 捕获导航事件,并确保只有获准站点的页面可以 在该 controlled frame 中加载。

8. 安全、隐私和可访问性考虑事项

本节是非规范性的。

8.1. 安全

Controlled Frame 基于 [Isolated-Web-Apps] (IWA), 并与核心安全规范集成

由于 Controlled Frame 是一个特别强大的 API,使用它,甚至只是让它可用, 都会使应用成为各种类型攻击的目标。因此,此 API 被限制在 IWA 中使用,IWA 具有额外的 保护措施来保护应用开发者和用户。Isolated Web App 解释器对此有如下说明:

"如果开发者需要访问会使应用成为 XSS 或服务器端攻击诱人目标的 API, 用户代理也可以强制应用采用这种威胁模型。"

Controlled Frame 正是这样一种诱人的目标,并且为了谨慎地公开它,我们选择加入 IWA,以防范某些攻击。一般来说, IWA 提供强大的安全保证,确保应用中的每项资源 在静态存储和传输中都是安全的。你可以在 IWA 解释器和 IWA [High-Watermark-Permissions] 解释器中阅读更多关于 IWA 安全性和权限的内容。

Controlled Frame 与 [Permissions-Policy] 和 [Permissions] 集成。 你可以阅读更多关于 Permissions Policy § 12. Privacy and Security 以及 Permissions § E Security considerations 的内容(注意该条目目前较为简略)。

攻击性网站可能显示原本不允许自身被嵌入的内容,并欺骗非 IWA 上的用户。

计划中的缓解措施:

一个 IWA 可能通过 Controlled Frame 嵌入另一个 IWA(或 自身),从而以某种方式操纵我们的 IWA 策略(例如,被 Controlled Frame 嵌入的 IWA 可能会因缺少 "controlled-frame" 策略控制特性而检测到自己正被嵌入)。

计划中的缓解措施:

Controlled Frame 可能获得对强大的 <controlledframe> 元素的访问权限。

不预期使用 Controlled Frame 的 IWA 可能尝试嵌入内容。

计划中的缓解措施:

IWA 可能尝试嵌入来自非 https scheme 的内容,例如 'http:' 或 'isolated-app:'

计划中的缓解措施:

恶意 Controlled Frame 可能访问嵌入者正在运行的进程(例如 Spectre 攻击)

计划中的缓解措施:

给定 "https origin" 的 Controlled Frame 可能与该 https origin 的用户自身存储数据 交互或产生干扰

计划中的缓解措施:

恶意 Controlled Frame 可能覆盖嵌入者存储的数据

计划中的缓解措施:

恶意 Controlled Frame 可能检测到自身被嵌入,并试图攻击嵌入者应用

计划中的缓解措施:

想法:

用户可能无法验证在 Controlled Frame 中查看的页面的源

想法:

Controlled Frame 可能利用过时浏览器引擎中的漏洞

已通过以下方式解决:

8.2. 隐私

Controlled Frame 与 Permissions Policy 和 Permissions 集成。你可以阅读更多关于 Permissions Policy § 12. Privacy and Security 的内容。你可以阅读更多关于 Permissions § E Security considerations 的内容。

对于 Controlled Frame,我们已识别出以下隐私考虑事项:

8.3. 可访问性

对于 Controlled Frame,我们已识别出以下可访问性考虑事项:

9. 致谢

以下人员为本文档的开发做出了贡献。

一致性

文档 约定

一致性要求通过描述性断言 与 RFC 2119 术语的组合来表达。 本文档规范性部分中的关键词 “MUST”、“MUST NOT”、“REQUIRED”、“SHALL”、“SHALL NOT”、“SHOULD”、“SHOULD NOT”、“RECOMMENDED”、 “MAY” 和 “OPTIONAL” 应按 RFC 2119 中所述进行解释。 然而,为了可读性, 这些词在本规范中并不全部以大写字母出现。

本规范的所有文本都是规范性的, 但明确标记为非规范性的章节、示例和注释除外。[RFC2119]

本规范中的示例以 “for example” 等词语引入, 或通过 class="example" 与规范性文本区分开来, 如下所示:

这是一个资料性示例的例子。

资料性注释以 “Note” 一词开头, 并通过 class="note" 与规范性文本区分开来, 如下所示:

Note,这是一个资料性注释。

索引

本规范定义的术语

由引用定义的术语

参考文献

规范性参考文献

[Console]
Dominic Farolino; Robert Kowalski; Terin Stock. Console 标准. 现行标准。URL:https://console.spec.whatwg.org/
[CSS-PAGE-FLOATS-3]
Johannes Wilm. CSS Page Floats. URL:https://drafts.csswg.org/css-page-floats/
[CSSOM-1]
Daniel Glazman; Emilio Cobos Álvarez. CSS 对象模型 (CSSOM). URL:https://drafts.csswg.org/cssom/
[DOM]
Anne van Kesteren. DOM 标准. 现行标准。 URL:https://dom.spec.whatwg.org/
[ECMASCRIPT]
ECMAScript 语言规范. URL:https://tc39.es/ecma262/multipage/
[FENCED-FRAME]
Fenced Frame. 社区组报告草案。 URL:https://wicg.github.io/fenced-frame/
[FETCH]
Anne van Kesteren. Fetch 标准. 现行 标准。URL:https://fetch.spec.whatwg.org/
[FileAPI]
Marijn Kruisselbrink. File API. URL:https://w3c.github.io/FileAPI/
[GEOLOCATION]
Marcos Caceres; Reilly Grant. Geolocation. URL:https://w3c.github.io/geolocation/
[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/
[ISOLATED-CONTEXTS]
Isolated Contexts. 社区组报告草案。URL:https://wicg.github.io/isolated-web-apps/isolated-contexts.html
[MANIFEST-APP-INFO]
Aaron Gustafson. Web App Manifest - Application Information. URL:https://w3c.github.io/manifest-app-info/
[Permissions]
Marcos Caceres; Mike Taylor. Permissions. URL: https://w3c.github.io/permissions/
[Permissions-Policy]
Ian Clelland. Permissions Policy. URL:https://w3c.github.io/webappsec-permissions-policy/
[RFC2119]
S. Bradner. 用于 RFC 中表示要求级别的 关键词. 1997 年 3 月。最佳当前实践。URL:https://datatracker.ietf.org/doc/html/rfc2119
[RFC5280]
D. Cooper; et al. Internet X.509 公钥 基础设施证书和证书吊销列表(CRL)配置文件. URL:https://datatracker.ietf.org/doc/html/rfc5280
[RFC6234]
D. Eastlake 3rd; T. Hansen. US Secure Hash Algorithms(SHA 以及基于 SHA 的 HMAC 和 HKDF). URL:https://datatracker.ietf.org/doc/html/rfc6234
[STORAGE]
Anne van Kesteren. Storage 标准. 现行 标准。URL:https://storage.spec.whatwg.org/
[URL]
Anne van Kesteren. URL 标准. 现行标准。 URL:https://url.spec.whatwg.org/
[URLPATTERN]
Ben Kelly; Jeremy Roman; 宍戸俊哉 (Shunya Shishido). URL Pattern 标准. 现行标准。URL:https://urlpattern.spec.whatwg.org/
[WEBIDL]
Edgar Chen; Timothy Gu. Web IDL 标准. 现行 标准。URL:https://webidl.spec.whatwg.org/
[X.690]
信息技术 - ASN.1 编码规则: 基本编码规则(BER)、规范编码规则(CER)和可辨别编码规则(DER)规范. URL:https://www.itu.int/rec/T-REC-X.690
[XHR]
Anne van Kesteren. XMLHttpRequest 标准. 现行 标准。URL:https://xhr.spec.whatwg.org/

资料性参考文献

[COOKIES]
A. Barth. HTTP 状态管理机制. 2011 年 4 月。提议标准。URL:https://httpwg.org/specs/rfc6265.html
[CSS-CASCADE-5]
Elika Etemad; Miriam Suzanne; Tab Atkins Jr.. CSS 层叠与继承 Level 5. URL:https://drafts.csswg.org/css-cascade-5/
[High-Watermark-Permissions]
Robbie McElrath. Isolated Web Apps High Watermark Permissions 解释器. URL:https://github.com/WICG/isolated-web-apps/blob/main/Permissions.md
[HTTP-CACHING]
R. Fielding, Ed.; M. Nottingham, Ed.; J. Reschke, Ed.. HTTP 缓存. 2022 年 6 月。互联网 标准。URL:https://httpwg.org/specs/rfc9111.html
[Isolated-Web-Apps]
Reilly Grant. Isolated Web Apps 解释器. URL:https://github.com/WICG/isolated-web-apps/blob/main/README.md

IDL 索引

[Exposed=Window, IsolatedContext]
interface HTMLControlledFrameElement : HTMLElement {
    [HTMLConstructor] constructor();

    [CEReactions] attribute USVString src;
    attribute DOMString partition;

    readonly attribute WindowProxy? contentWindow;
    readonly attribute ContextMenus contextMenus;
    readonly attribute WebRequest request;

    // Navigation methods.
    Promise<boolean> back();
    Promise<boolean> canGoBack();
    Promise<boolean> forward();
    Promise<boolean> canGoForward();
    Promise<boolean> go(long relativeIndex);
    undefined reload();
    undefined stop();

    // Scripting methods.
    Promise<undefined> addContentScripts(sequence<ContentScriptDetails> contentScriptList);
    Promise<any> executeScript(optional InjectDetails details = {});
    Promise<undefined> insertCSS(optional InjectDetails details = {});
    Promise<undefined> removeContentScripts(optional sequence<DOMString> scriptNameList);

    // Configuration methods.
    Promise<undefined> clearData(
      optional ClearDataOptions options = {},
      optional ClearDataTypeSet types = {});
    Promise<boolean> getAudioState();
    Promise<long> getZoom();
    Promise<DOMString> getZoomMode();
    Promise<boolean> isAudioMuted();
    undefined setAudioMuted(boolean mute);
    Promise<undefined> setZoom(long zoomFactor);
    Promise<undefined> setZoomMode(DOMString zoomMode);

    // Capture methods.
    Promise<undefined> captureVisibleRegion(optional ImageDetails options = {});
    undefined print();

    // Events.
    attribute EventHandler onconsolemessage;
    attribute EventHandler oncontentload;
    attribute EventHandler ondialog;
    attribute EventHandler onloadabort;
    attribute EventHandler onloadcommit;
    attribute EventHandler onloadstart;
    attribute EventHandler onloadstop;
    attribute EventHandler onnewwindow;
    attribute EventHandler onpermissionrequest;
    attribute EventHandler onsizechanged;
    attribute EventHandler onzoomchange;
};

// One of |code| or |file| must be specified but not both.
dictionary InjectDetails {
  DOMString code;
  USVString file;
};

dictionary InjectionItems {
  DOMString code;
  sequence<USVString> files;
};

enum RunAt {
  "document-start",
  "document-end",
  "document-idle",
};

dictionary ContentScriptDetails {
  required DOMString name;
  InjectionItems js;
  InjectionItems css;
  required sequence<(URLPattern or URLPatternInput)> urlPatterns;
  sequence<(URLPattern or URLPatternInput)> excludeURLPatterns;
  boolean allFrames;
  boolean matchAboutBlank;
  RunAt runAt;
};

dictionary ClearDataOptions {
  long since;
};

dictionary ClearDataTypeSet {
  boolean cache;
  boolean cookies;
  boolean fileSystems;
  boolean indexedDB;
  boolean localStorage;
  boolean persistentCookies;
  boolean sessionCookies;
};

enum ZoomMode {
  "per-origin",
  "per-view",
  "disabled"
};


// One of |code| or |file| must be specified but not both.
dictionary ImageDetails {
  DOMString format;
  DOMString quality;
};

[Exposed=Window, IsolatedContext]
interface ConsoleMessage {
  readonly attribute long level;
  readonly attribute DOMString message;
};

[Exposed=Window, IsolatedContext]
interface ConsoleMessageEvent : Event {
  constructor(DOMString type, optional ConsoleMessageEventInit eventInitDict = {});
  readonly attribute ConsoleMessage consoleMessage;
};

dictionary ConsoleMessageEventInit: EventInit {
  ConsoleMessage? consoleMessage;
};


enum DialogType {
  "alert",
  "confirm",
  "prompt"
};

[Exposed=Window, IsolatedContext]
interface DialogController {
  undefined okay(optional DOMString response);
  undefined cancel();
};

[Exposed=Window, IsolatedContext]
interface DialogMessage {
  readonly attribute DialogType messageType;
  readonly attribute DOMString messageText;
  readonly attribute DialogController dialog;
};

[Exposed=Window, IsolatedContext]
interface DialogEvent : Event {
  constructor(DOMString type, optional DialogEventInit eventInitDict = {});
  readonly attribute DialogMessage dialogMessage;
};

dictionary DialogEventInit: EventInit {
  DialogMessage? dialogMessage;
};


enum WindowOpenDisposition {
  "ignore",
  "save_to_disk",
  "current_tab",
  "new_background_tab",
  "new_foreground_tab",
  "new_window",
  "new_popup"
};

[Exposed=Window, IsolatedContext]
interface NewWindowController {
  undefined attach(HTMLControlledFrameElement newControlledFrame);
  undefined discard();
};

[Exposed=Window, IsolatedContext]
interface NewWindow {
  readonly attribute NewWindowController window;
  readonly attribute USVString targetUrl;
  readonly attribute DOMString name;
  readonly attribute WindowOpenDisposition windowOpenDisposition;
};

[Exposed=Window, IsolatedContext]
interface NewWindowEvent : Event {
  constructor(DOMString type, optional NewWindowEventInit eventInitDict = {});
  readonly attribute NewWindow newWindow;
};

dictionary NewWindowEventInit: EventInit {
  NewWindow? newWindow;
};


enum PermissionType {
  "media",
  "geolocation",
  "pointerLock",
  "download",
  "filesystem",
  "fullscreen",
  "hid",
};

[Exposed=Window, IsolatedContext]
interface PermissionRequestControllerBase {
  undefined allow();
  undefined cancel();
};

[Exposed=Window, IsolatedContext]
interface MediaPermissionRequestController: PermissionRequestControllerBase {
  readonly attribute USVString url;
};

[Exposed=Window, IsolatedContext]
interface GeolocationPermissionRequestController: PermissionRequestControllerBase {
  readonly attribute USVString url;
};

[Exposed=Window, IsolatedContext]
interface PointerLockPermissionRequestController: PermissionRequestControllerBase {
  readonly attribute boolean lastUnlockedBySelf;
  readonly attribute boolean userGesture;
  readonly attribute USVString url;
};

[Exposed=Window, IsolatedContext]
interface DownloadPermissionRequestController : PermissionRequestControllerBase {
  readonly attribute DOMString requestMethod;
  readonly attribute USVString url;
};

[Exposed=Window, IsolatedContext]
interface FileSystemPermissionRequestController : PermissionRequestControllerBase {
  readonly attribute USVString url;
};

[Exposed=Window, IsolatedContext]
interface FullscreenPermissionRequestController : PermissionRequestControllerBase {
  readonly attribute USVString origin;
};

[Exposed=Window, IsolatedContext]
interface HidPermissionRequestController : PermissionRequestControllerBase {
  readonly attribute USVString url;
};

[Exposed=Window, IsolatedContext]
interface PermissionRequest {
  readonly attribute PermissionType permission;
  readonly attribute PermissionRequestControllerBase request;
};

[Exposed=Window, IsolatedContext]
interface PermissionRequestEvent : Event {
  constructor(DOMString type, optional PermissionRequestEventInit eventInitDict = {});
  readonly attribute PermissionRequest permissionRequest;
};

dictionary PermissionRequestEventInit: EventInit {
  PermissionRequest? permissionRequest;
};


[Exposed=Window, IsolatedContext]
interface SizeChange {
  readonly attribute unsigned long oldWidth;
  readonly attribute unsigned long oldHeight;
  readonly attribute unsigned long newWidth;
  readonly attribute unsigned long newHeight;
};

[Exposed=Window, IsolatedContext]
interface SizeChangedEvent : Event {
  constructor(DOMString type, optional SizeChangedEventInit eventInitDict = {});
  readonly attribute SizeChange sizeChange;
};

dictionary SizeChangedEventInit: EventInit {
  SizeChange? sizeChange;
};


[Exposed=Window, IsolatedContext]
interface ZoomChange {
  readonly attribute float oldZoomFactor;
  readonly attribute float newZoomFactor;
};

[Exposed=Window, IsolatedContext]
interface ZoomChangeEvent : Event {
  constructor(DOMString type, optional ZoomChangeEventInit eventInitDict = {});
  readonly attribute ZoomChange zoomChange;
};

dictionary ZoomChangeEventInit: EventInit {
  ZoomChange? zoomChange;
};


[Exposed=Window, IsolatedContext]
interface ContentLoadEvent : Event {
  constructor(DOMString type, optional EventInit eventInitDict = {});
};


[Exposed=Window, IsolatedContext]
interface LoadInfo {
  readonly attribute USVString url;
  readonly attribute boolean isTopLevel;
};

[Exposed=Window, IsolatedContext]
interface LoadAbortInfo : LoadInfo{
  readonly attribute long code;
  readonly attribute DOMString reason;
};

[Exposed=Window, IsolatedContext]
interface LoadRedirectInfo{
  readonly attribute USVString oldUrl;
  readonly attribute USVString newUrl;
  readonly attribute boolean isTopLevel;
};

[Exposed=Window, IsolatedContext]
interface LoadAbortEvent : Event {
  constructor(DOMString type, optional LoadAbortEventInit eventInitDict = {});
  readonly attribute LoadAbortInfo loadAbortInfo;
};

dictionary LoadAbortEventInit: EventInit {
  LoadAbortInfo? loadAbortInfo;
};


[Exposed=Window, IsolatedContext]
interface LoadCommitEvent : Event {
  constructor(DOMString type, optional LoadCommitEventInit eventInitDict = {});
  readonly attribute LoadInfo loadInfo;
};

dictionary LoadCommitEventInit: EventInit {
  LoadInfo? loadInfo;
};


[Exposed=Window, IsolatedContext]
interface LoadStartEvent : Event {
  constructor(DOMString type, optional LoadStartEventInit eventInitDict = {});
  readonly attribute LoadInfo loadInfo;
};

dictionary LoadStartEventInit: EventInit {
  LoadInfo? loadInfo;
};


[Exposed=Window, IsolatedContext]
interface LoadStopEvent : Event {
  constructor(DOMString type, optional LoadStopEventInit eventInitDict = {});
};

dictionary LoadStopEventInit: EventInit {
};


[Exposed=Window, IsolatedContext]
interface LoadRedirectEvent : Event {
  constructor(DOMString type, optional LoadRedirectEventInit eventInitDict = {});
  readonly attribute LoadRedirectInfo loadRedirectInfo;
};

dictionary LoadRedirectEventInit: EventInit {
  LoadRedirectInfo? loadRedirectInfo;
};


enum ResourceType {
  "main-frame",
  "sub-frame",
  "stylesheet",
  "script",
  "image",
  "font",
  "object",
  "xmlhttprequest",
  "ping",
  "csp-report",
  "media",
  "websocket",
  "other",
};

enum RequestedHeaders {
  "none",
  "cors",
  "all",
};

enum ConnectionState {
  "broken", "insecure", "secure"
};

dictionary Fingerprint {
  required DOMString sha256;
};

dictionary CertificateInfo {
  required Fingerprint fingerprint;
  Uint8Array rawDER;
};

dictionary SecurityInfo {
  required sequence<CertificateInfo> certificates;
  required ConnectionState state;
};

dictionary WebRequestInterceptorOptions {
  required sequence<(URLPattern or URLPatternInput)> urlPatterns;
  sequence<ResourceType> resourceTypes = [];
  boolean blocking = false;
  boolean includeRequestBody = false;
  RequestedHeaders includeHeaders = "none";
  boolean securityInfo = false;
  boolean securityInfoRawDer = false;
};

[Exposed=Window, IsolatedContext]
interface WebRequest {
  WebRequestInterceptor createWebRequestInterceptor(
      WebRequestInterceptorOptions options);
};

[Exposed=Window, IsolatedContext]
interface WebRequestInterceptor : EventTarget {
  attribute EventHandler onauthrequired;
  attribute EventHandler onbeforeredirect;
  attribute EventHandler onbeforerequest;
  attribute EventHandler onbeforesendheaders;
  attribute EventHandler oncompleted;
  attribute EventHandler onerroroccurred;
  attribute EventHandler onheadersreceived;
  attribute EventHandler onsendheaders;
  attribute EventHandler onresponsestarted;
};

enum DocumentLifecycle {
  "prerender",
  "active",
  "cached",
  "pending-deletion",
};

enum FrameType {
  "outermost-frame",
  "fenced-frame",
  "sub-frame",
};

[Exposed=Window, IsolatedContext]
interface UploadData {
  readonly attribute ArrayBuffer? bytes;
  readonly attribute DOMString? file;
};

[Exposed=Window, IsolatedContext]
interface RequestBody {
  readonly attribute DOMString? error;
  readonly attribute any formData;
  readonly attribute FrozenArray<UploadData>? raw;
};

[Exposed=Window, IsolatedContext]
interface WebRequestRequest {
  readonly attribute DOMString method;
  readonly attribute DOMString id;
  readonly attribute ResourceType type;
  readonly attribute USVString url;
  readonly attribute USVString? initiator;
  readonly attribute Headers? headers;
  readonly attribute RequestBody? body;
};

[Exposed=Window, IsolatedContext]
interface AuthChallenger {
  readonly attribute DOMString host;
  readonly attribute long port;
};

[Exposed=Window, IsolatedContext]
interface WebRequestAuthDetails {
  readonly attribute AuthChallenger challenger;
  readonly attribute boolean isProxy;
  readonly attribute DOMString scheme;
  readonly attribute DOMString? realm;
};

[Exposed=Window, IsolatedContext]
interface WebRequestResponse {
  readonly attribute long statusCode;
  readonly attribute DOMString statusLine;
  readonly attribute boolean fromCache;
  readonly attribute Headers? headers;
  readonly attribute DOMString? ip;
  readonly attribute USVString? redirectURL;
  readonly attribute WebRequestAuthDetails? auth;
};

[Exposed=Window, IsolatedContext]
interface WebRequestEvent : Event {
  readonly attribute WebRequestRequest request;
  readonly attribute long frameId;
  readonly attribute FrameType? frameType;
  readonly attribute DOMString? documentId;
  readonly attribute DocumentLifecycle? documentLifecycle;
  readonly attribute DOMString? parentDocumentId;
  readonly attribute long? parentFrameId;
};

dictionary WebRequestAuthCredentials {
  required DOMString username;
  required DOMString password;
};

dictionary WebRequestAuthOptions {
  AbortSignal signal;
};

[Exposed=Window, IsolatedContext]
interface WebRequestAuthRequiredEvent : WebRequestEvent {
  readonly attribute WebRequestResponse response;

  undefined setCredentials(
    Promise<WebRequestAuthCredentials> credentials,
    optional WebRequestAuthOptions options = {});
};

[Exposed=Window, IsolatedContext]
interface WebRequestBeforeRedirectEvent : WebRequestEvent {
  readonly attribute WebRequestResponse response;
};

[Exposed=Window, IsolatedContext]
interface WebRequestBeforeRequestEvent : WebRequestEvent {
  undefined redirect(USVString redirectURL);
};

[Exposed=Window, IsolatedContext]
interface WebRequestBeforeSendHeadersEvent : WebRequestEvent {
  undefined setRequestHeaders((Headers or HeadersInit) requestHeaders);
};

[Exposed=Window, IsolatedContext]
interface WebRequestCompletedEvent : WebRequestEvent {
  readonly attribute WebRequestResponse response;
};

[Exposed=Window, IsolatedContext]
interface WebRequestErrorOccurredEvent : WebRequestEvent {
  readonly attribute DOMString error;
};

[Exposed=Window, IsolatedContext]
interface WebRequestHeadersReceivedEvent : WebRequestEvent {
  readonly attribute WebRequestResponse response;
  readonly attribute SecurityInfo? securityInfo;

  undefined redirect(USVString redirectURL);
  undefined setResponseHeaders((Headers or HeadersInit) responseHeaders);
};

[Exposed=Window, IsolatedContext]
interface WebRequestResponseStartedEvent : WebRequestEvent {
  readonly attribute WebRequestResponse response;
};

[Exposed=Window, IsolatedContext]
interface WebRequestSendHeadersEvent : WebRequestEvent {};

enum ContextType {
    "all",
    "page",
    "frame",
    "selection",
    "link",
    "editable",
    "image",
    "video",
    "audio",
};

enum ItemType {
    "normal",
    "checkbox",
    "radio",
    "separator",
};

dictionary ContextMenusProperties {
    boolean checked;
    sequence<ContextType> contexts;
    sequence<(URLPattern or URLPatternInput)> documentURLPatterns;
    boolean enabled;
    DOMString parentId;
    sequence<(URLPattern or URLPatternInput)> targetURLPatterns;
    DOMString title;
    ItemType type;
};

dictionary ContextMenusCreateProperties : ContextMenusProperties {
    required DOMString id;
};

[Exposed=Window, IsolatedContext]
interface ContextMenus : EventTarget {
    Promise<undefined> create(ContextMenusCreateProperties properties);
    Promise<undefined> remove(DOMString id);
    Promise<undefined> removeAll();
    Promise<undefined> update(DOMString id, optional ContextMenusProperties properties = {});

    attribute EventHandler onclick;
    attribute EventHandler onshow;
};

[Exposed=Window, IsolatedContext]
interface MenuItemDetails {
    readonly attribute DOMString id;
    readonly attribute DOMString? parentMenuId;
    readonly attribute boolean? checked;
    readonly attribute boolean? wasChecked;
};

[Exposed=Window, IsolatedContext]
interface ContextMenusClickEvent : Event {
  readonly attribute MenuItemDetails menuItem;

  // Details about the frame the context menu is opened within.
  readonly attribute long frameId;
  readonly attribute USVString frameURL;
  readonly attribute USVString pageURL;

  // Details about the element the context menu is opened within the context of.
  readonly attribute boolean editable;
  readonly attribute USVString? linkURL;
  readonly attribute DOMString? mediaType;
  readonly attribute DOMString? selectionText;
  readonly attribute USVString? srcURL;
};

议题索引

这些步骤是初始化新 navigable 中的 History.length 所必需的。这是 HTML 标准中已有的一个 议题。↵
此算法不适用于 Shared 或 Service Workers,因为 controlledFrameEmbedderParent 只 定义在 navigable 上,并且 并不总是能从一个非 Window 的环境转到一个 navigable。↵
ContextType 的匹配行为尚未指定,不过 上面的注释提供了一些关于期望行为的信息。↵