使用 Web Bundle 的子资源加载

社区组草案报告,

该版本:
https://wicg.github.io/webpackage/subresource-loading.html
问题追踪:
GitHub
规范内
编辑:
(Google公司)
(Google)

摘要

UA 如何从 Web Bundle 加载子资源。

本文档状态

本规范由 Web Platform Incubator Community Group 发布。 这不是 W3C 标准,也未被纳入 W3C 标准路线。 请注意,根据 W3C Community Contributor License Agreement (CLA),存在有限的选择退出权及其他适用条件。 了解更多 W3C Community and Business Groups 信息。

1. 简介

本节为非规范性内容。

“使用 Web Bundle 的子资源加载”规范描述了一种利用支持多资源打包的格式 —— Web Bundles —— 高效加载大量资源的方法。该规范说明了 Web 浏览器如何加载这些资源。本规范作为对 [HTML][FETCH][CSP] 规范的补丁,调用这里定义的算法。

注意: 本规范正在建设中。参见 #708

2. 结构

已获取的 web bundle 指的是在 [draft-ietf-wpack-bundled-responses-latest] 中定义的 web bundle 格式的表示。

web bundle 获取条目 是一个包含以下 条目结构体

有更好的 web bundle 获取条目 名称吗?

web bundle 获取条目 entry文档 document被注册条目使用,如果 documentweb bundle 注册列表 包含一个 web bundle 注册,其 fetch entryentry

bundle 规则 是一个包含以下 条目结构体

web bundle 注册 是一个包含以下 条目结构体

web bundle 解析结果 是一个包含以下 条目结构体

每个 环境设置对象 都会获得一个 web bundle 注册列表 算法,返回 web bundle 注册列表

Document 具有 web bundle 注册列表, 是 web bundle 注册列表。初始为空。

设置 window 环境设置对象时,settings objectweb bundle 注册列表返回 window 所关联 web bundle 注册列表

设置 worker 环境设置对象时,settings objectweb bundle 注册列表返回一个空 列表

Document 具有 web bundle 获取条目列表, 是 web bundle 获取条目列表。初始为空。

虽然 列表 用于web bundle 获取条目列表,但顺序其实不重要。

尚不支持 workers。

3. HTML 补丁

为使 web bundles 在 prepare the script element 算法中能与现有脚本类型(即 classic 或 module)一致处理, 我们作如下更改:

注意: 因为没有让 web bundle 结果 成为 script 的子类, 其它与脚本执行相关的规范不会受影响。

3.1. 准备 script 元素

prepare the script element 算法中作如下更改:

注意: CSP 会在 prepare the script element 第15步应用于内联 web bundle,正如在 classic/module 脚本上一样。

准备 web bundle,给定 HTMLScriptElement element字符串 sourceTextURL baseURL 时:

  1. parse result解析 web bundle 字符串,给定 sourceTextbaseURL 的结果。

  2. 如果此操作抛出异常:

    1. 脚本结果设为新的 web bundle 结果,其 registration 为 null,等待抛出的错误为该异常。

    2. 标记为就绪

    3. 返回。

  3. documentelement节点文档

  4. fetch entry 为 null。

  5. documentweb bundle 获取条目列表 中的每个 r 执行:

    1. 如果 rsource 等于 parse resultsourcercredentials 等于 parse resultcredentials,那么:

      1. 如果 r 未被 注册条目使用document 中,令 fetch entryr

        注意: 这意味着另一个 script 元素,其 脚本结果registrationfetch entryr 已被移除。 这样可确保在具有相同 web bundle sourcecredentialsHTMLScriptElement 被删除和添加时,web bundle 获取条目不会被销毁和重新获取。

  6. 如果 fetch entry 为 null:

    1. fetch entry 设为新建的 web bundle 获取条目,其 sourceparse resultsourcecredentialsparse resultcredentialsstate 为 "fetching",fetched bundle 为 null。

    2. fetch entry 添加到 documentweb bundle 获取条目列表

    3. 并行地,获取 web bundle fetch entry

  7. registration 为新建的 web bundle 注册,其 fetch entryfetch entryruleparse resultrule

  8. registration 添加到 documentweb bundle 注册列表

  9. 脚本结果设为新的 web bundle 结果,其 registrationregistration等待抛出的错误为 null。

  10. 标记为就绪

3.2. 触发事件

执行 script 元素时,在步骤 6 添加如下分支:

处理 web bundle 事件,给定 HTMLScriptElement element

  1. resultelement脚本结果

  2. 断言:element脚本类型为 "webbundle"。

  3. 断言:resultweb bundle 结果

  4. 异步等待直到发生以下任一情况:

    注意: 不同于其他脚本类型,这里会异步等待获取 web bundle完成后再在 HTMLScriptElement 上触发 load 事件。 这里不会延迟 load 事件,因为会在标记为就绪时同步进行。 这是有意为之,因为获取 web bundle更类似于预加载(preload)。

  5. 如果 element脚本结果为 null,则返回。

    注意:element 在上一步骤中被移出文档时,可能会发生这种情况。

    注意: 该处理方式与 whatwg/html#2673 保持一致。 目前该情况下不会触发 error 事件。如果后续对于 whatwg/html#2673 的决策变为需要触发 error,此处也应相应更改。

  6. 断言:element节点文档等于 element准备时的文档

  7. 如果 result等待抛出的错误非 null,则:

    1. 报告异常,参数为 result等待抛出的错误

      这里没有相关的脚本, 因为web bundle 结果不是脚本。 这一点需要等 whatwg/html#958,才能修正。

    2. 返回。

  8. 断言:resultregistration不为 null。

  9. 如果 resultregistrationfetch entrystate为 "failed":

    1. element 上触发 error 事件

    2. 返回。

  10. 断言:resultregistrationfetch entrystate为 "fetched"。

  11. element 上触发 load 事件

3.3. 移除

如果 script 元素被移出文档,用户代理必须执行以下算法:

  1. 如果脚本类型不是 "webbundle",则返回。

  2. 如果脚本结果为 null,则返回。

  3. 断言:脚本结果web bundle 结果

  4. registration脚本结果registration

  5. 脚本结果设为 null。

  6. 如果 registration 为 null,则返回。

  7. document节点文档

  8. 断言:documentweb bundle 注册列表包含 registration

  9. documentweb bundle 注册列表移除 registration

  10. 入队微任务以执行以下步骤:

    1. fetch entryregistrationfetch entry

    2. 如果 fetch entry注册条目使用document,则返回。

    3. documentweb bundle 获取条目列表移除 fetch entry

      注意: 如果 fetch entry 被多个 script 元素的web bundle 注册使用,并且这些 script 元素被依次移除,那么在这一步之前, documentweb bundle 获取条目列表可能已经不包含 fetch entry

      注意: 此时,fetch entry 已不能再被后续的 子资源请求或准备 web bundle调用使用,但它的已获取的 web bundle仍可能被进行中的 fetch 使用。

4. Fetch 补丁

4.1. 补丁 fetch

fetch中,插入如下步骤到

  1. 令 taskDestination 为 null。

之前:

  1. 如果给定 request,调用查找匹配的 web bundle 注册的结果为 null,则将 requestservice-workers mode 设置为 "none"。

注意: 这意味着对于从 webbundle 加载的子资源,不会有 service worker 获得事件。

4.2. 补丁 fetch scheme

将 "uuid-in-package" 添加到fetch scheme 的支持列表中。

注意: 这确保导航算法会对 uuid-in-package: URL 使用 处理导航 fetch 算法。

注意: origin 为 "uuid-in-package" scheme 的 URL 是不透明 origin。

4.3. 补丁 HTTP-network-or-cache fetch

HTTP-network-or-cache fetch中,插入如下步骤到

8.22. 使用 httpRequest 计算 httpCache 分区。

之前:

  1. response 设为给定 httpRequest,调用从 web bundle 获取子资源的结果。

    1. 如果 response网络错误,返回网络错误

    2. 如果 response 非 null,则跳过 8.22-8.24 步骤,转到第 9 步。

      注意: 也就是说,从 webbundle 获取的子资源不会与 HttpCache 交互。未来计划作为特性增强支持 HttpCache。

5. CSP 补丁

5.1. 补丁“请求是否匹配源列表?”

重写 请求是否匹配源列表?,执行如下步骤:

  1. urlrequest当前 url

  2. 如果 urlscheme 为 "uuid-in-package",则:

    1. registration 为调用查找匹配的 web bundle 注册给定 request 的结果。

    2. 如果 registration 非 null,则将 url 设为 registrationfetch entrysource

  3. 返回调用url 是否与源列表和 origin、重定向次数匹配,参数为 urlsource listpolicyself-originrequestredirect count的结果。

注意: 这意味着 CSP 限制将作用于 bundle 的 URL,而非 uuid-in-package: URL。具体原因见 #651

5.2. 补丁“响应请求是否匹配源列表?”

重写 响应请求是否匹配源列表?,执行如下步骤:

  1. urlresponseurl

  2. 如果 urlscheme 为 "uuid-in-package",则:

    1. registration 为调用查找匹配的 web bundle 注册给定 request 的结果。

    2. 如果 registration 非 null,则将 url 设为 registrationfetch entrysource

  3. 返回调用url 是否与源列表和 origin、重定向次数匹配,参数为 urlsource listpolicyself-originrequestredirect count的结果。

注意: 这意味着 CSP 限制将应用于 bundle 的 URL,而非 uuid-in-package: URL。详细原因见 #651

6. 算法

6.1. 解析

解析 web bundle 字符串,给定 字符串 sourceTextURL baseURL

  1. parsed将 JSON 解析为 Infra 值,参数为 sourceText

  2. 如果 parsed 不是 map,那么抛出 TypeError ,表示顶层值需要是一个 JSON 对象。

  3. 如果 parsed["source"] 不存在,那么抛出 TypeError

  4. 如果 parsed["source"] 不是 字符串,那么抛出 TypeError

  5. source解析 parsed["source"],以 baseURL 为基准。

  6. 如果 source 为 null,则抛出 TypeError

  7. credentials 为 "same-origin"。

  8. 如果 parsed["credentials"] 存在,则:

    1. 如果 parsed["credentials"] 是 "omit",那么将 credentials 设为 "omit"。

    2. 否则,如果 parsed["credentials"] 是 "include",那么将 credentials 设为 "include"。

  9. resources 为一个空的 列表

  10. 如果 parsed["resources"] 存在,则:

    1. 如果 parsed["resources"] 不是 列表,那么抛出 TypeError

    2. resources 设为 解析 URL 列表 的结果,参数为 parsed["resources"] 和 source

  11. scopes 为一个空的 列表

  12. 如果 parsed["scopes"] 存在,则:

    1. 如果 parsed["scopes"] 不是 列表,那么抛出 TypeError

    2. scopes 设为 解析 URL 列表 的结果,参数为 parsed["scopes"] 和 source

  13. 如果 parsedkeys 中包含除 "source"、"credentials"、"resources" 或 "scopes" 以外的任何项,在控制台报告警告,说明 web bundle 字符串中有无效的顶级键。

    注意:这有助于检测拼写错误。这不是错误,否则将妨碍将来向后兼容地扩展。

  14. rulebundle 规则,其 resourcesresourcesscopesscopes

  15. 返回web bundle 解析结果,其sourcesourcecredentialscredentialsrulerule

解析 URL 列表,给定 列表 originalListURL baseURL

  1. parsed URL list 为一个空的 列表

  2. 遍历 originalList 的每个 item

    1. 如果 item字符串,则

      1. URL解析 item,以 baseURL 为基准得到的结果。

      2. 如果 URL 不为 null, URL 添加到 parsed URL list

  3. 返回 parsed URL list

6.2. 获取 web bundle

获取 web bundle,给定 web bundle 获取条目 fetch entryfetch params fetch params

  1. 断言:fetch entrystate 是 "fetching"。

  2. requestfetch paramsrequest

  3. requesturl 设为 fetch entrysource

    注意: source URL 根据文档 base URL 解析。

  4. requestdestination 设为 "webbundle",

  5. requestmode 设为 "cors",

  6. requestcredentials mode 设为 fetch entrycredentials

  7. requestservice-workers mode 设为 "none"。

  8. requestheader list 添加 header (“Accept”, “application/webbundle;v=b2”) 元组。

    注意: 最终 [draft-ietf-wpack-bundled-responses-latest] 使用版本 1,本规范追踪浏览器实际实现,仍用 draft 版本。

  9. fetch request,其 processResponse 算法设为 处理 web bundle 响应,该算法以 fetch entry 部分应用。

    注意: Chromium 当前实现不允许嵌套 bundle,即不会从其他 bundle 再取 web bundle。

6.3. 处理 web bundle 响应

处理 web bundle 响应,给定 web bundle 获取条目 fetch entryresponse response

  1. 如果 responsestatusok status

    1. responsebody 作为 Web Bundle 解析 ([draft-ietf-wpack-bundled-responses-latest])。

      注意: 此时 response 的 body 可能还未完全可用。UA 可以异步增量读取 body,以尽快提供子资源。

      注意: 解析时,Chromium 实验性实现只接受 "b2" 作为 bundle 格式版本号。

    2. 当解析算法异步完成时,将 fetch entryfetched bundle 设为解析结果,state 设为 "fetched"。若解析失败或不符合规范,则 fetched bundle 设为 null,state 设为 "failed"。

  2. 否则,将 fetch entrystate 设为 "failed"。

6.4. 从 web bundle 获取子资源

从 web bundle 获取子资源,给定 request httpRequest

  1. registration 为执行 查找匹配的 web bundle 注册(参数为 httpRequest)的结果。

  2. 如果 registration 不为 null:

    1. response从 web bundle 获取条目获取响应 的结果,参数为 httpRequesturlregistrationfetch entry

    2. 如果 response 为 null,则返回网络错误

      注意: 这意味着浏览器不会回退到从网络获取子资源。

    3. 否则,返回 response

  3. 返回 null。

注意: 返回 null 时会回退到 HTTP 缓存和常规网络请求;而上面返回网络错误则不会。

从 web bundle 获取条目获取响应,给定 url urlweb bundle 获取条目 fetch entry

  1. 如果 fetch entrystate 为 "fetching",则异步等待 直到 state 变为 "fetched" 或 "failed"。

  2. 如果 fetch entrystate 为 "failed",则返回 null。

  3. 断言:fetch entryfetched bundle 非 null。

  4. 返回 fetch entryfetched bundle 根据 url 返回的 response[draft-ietf-wpack-bundled-responses-latest])。如果 fetched bundle 未找到 url,则返回 null。

6.5. 查找匹配的注册

查找匹配的 web bundle 注册,给定 request httpRequest

  1. urlhttpRequesturl

  2. 对于 httpRequestclientweb bundle 注册列表 中的每个 registration

    1. ruleregistrationrule

    2. 如果 urlscheme 不是 "uuid-in-package",则

      1. 如果 urloriginregistrationfetch entrysourceorigin 不是 同源,则 continue

      2. allowed path缩短 registrationfetch entrysourcepath 的结果。

      3. 如果 urlpath 没有以 allowed path 开头,则 continue

    3. 如果 ruleresources 包含 url,则返回 registration

    4. 如果 urlrule 的任意 scopes 开头,则返回 registration

  3. 返回 null。

一致性

文档惯例

一致性要求通过描述性断言与 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" 与规范性文本区分, 如下所示:

注意:这是一个说明性注释。

索引

本规范定义的术语

引用文档定义的术语

参考文献

规范性引用

[CONSOLE]
Dominic Farolino; Robert Kowalski; Terin Stock. Console 标准. Living Standard. URL: https://console.spec.whatwg.org/
[CSP]
Mike West; Antonio Sartori. 内容安全策略 第3级. URL: https://w3c.github.io/webappsec-csp/
[DOM]
Anne van Kesteren. DOM 标准. Living Standard. URL: https://dom.spec.whatwg.org/
[FETCH]
Anne van Kesteren. Fetch 标准. Living Standard. URL: https://fetch.spec.whatwg.org/
[HTML]
Anne van Kesteren; et al. HTML 标准. Living Standard. URL: https://html.spec.whatwg.org/multipage/
[INFRA]
Anne van Kesteren; Domenic Denicola. Infra 标准. Living Standard. URL: https://infra.spec.whatwg.org/
[RFC2119]
S. Bradner. 用于 RFC 中表示需求级别的关键字. March 1997. Best Current Practice. URL: https://datatracker.ietf.org/doc/html/rfc2119
[URL]
Anne van Kesteren. URL 标准. Living Standard. URL: https://url.spec.whatwg.org/
[WEBIDL]
Edgar Chen; Timothy Gu. Web IDL 标准. Living Standard. URL: https://webidl.spec.whatwg.org/

参考性引用

[DRAFT-IETF-WPACK-BUNDLED-RESPONSES-LATEST]
Web Bundles. URL: https://wpack-wg.github.io/bundled-responses/draft-ietf-wpack-bundled-responses.html

问题索引

是否有更好的 web bundle 获取条目 名称?
虽然 列表 用于 web bundle 获取条目 列表,但顺序并不重要。
尚不支持 worker。
这里没有相关的 script, 因为 web bundle 结果 并不是 script。 这一点需要等待 whatwg/html#958 才能修复。