1. 简介
本节不是规范性的。为了防止跨站点用户跟踪,浏览器正在按顶级可遍历站点来分区所有形式的存储;参见客户端存储分区。但是,目前有许多 合法用例依赖未分区存储。
本文档引入一种新的存储 API,它有意不按顶级可遍历站点分区(但仍按上下文源分区),以服务于若干需要未分区存储的用例。为限制
对用户的跨站点重新识别,共享存储中的数据只能在两个受限环境中读取。一个这样的环境称为
worklet,而来自 worklet 的任何输出都以围栏框架或私有聚合报告的形式给出。随着时间推移,标准中可能会包含其他 worklet 输出
门控。
另一个受限环境位于围栏框架的内容中,即它解析对 disableUntrustedNetwork()
的调用之后,该调用会防止读取到的数据被共享到该框架之外。
a.example 以跨站点保持一致的方式随机将用户分配到组。
在 a.example iframe 内:
function generateSeed() { …} await window. sharedStorage. worklet. addModule( 'experiment.js' ); // 仅当尚不存在跨站点种子时,才将它写入 a.example 的存储。 window. sharedStorage. set( 'seed' , generateSeed(), { ignoreIfPresent: true }); let fencedFrameConfig= await window. sharedStorage. selectURL( 'select-url-for-experiment' , [ { url: "blob:https://a.example/123…" , reportingMetadata: { "click" : "https://report.example/1..." }}, { url: "blob:https://b.example/abc…" , reportingMetadata: { "click" : "https://report.example/a..." }}, { url: "blob:https://c.example/789…" } ], { data: { name: 'experimentA' } } ); // 假设围栏框架 'my-fenced-frame' 已经被附加。 document. getElementById( 'my-fenced-frame' ). config= fencedFrameConfig;
在 experiment.js worklet 脚本内部:
class SelectURLOperation{ hash( experimentName, seed) { …} async run( urls, data) { const seed= await this . sharedStorage. get( 'seed' ); return hash( data. name, seed) % urls. length; } } register( 'select-url-for-experiment' , SelectURLOperation);
2.
SharedStorageWorklet
接口
SharedStorageWorklet
对象允许开发者提供模块脚本来处理共享存储数据,然后通过一个或多个
输出门控输出结果。目前有两个输出门控,即私有
聚合输出门控和 URL 选择
输出门控。
typedef (USVString or FencedFrameConfig );SharedStorageResponse
[Exposed =(Window )]interface :SharedStorageWorklet Worklet {Promise <SharedStorageResponse >selectURL (DOMString ,name sequence <SharedStorageUrlWithMetadata >,urls optional SharedStorageRunOperationMethodOptions = {});options Promise <any >run (DOMString ,name optional SharedStorageRunOperationMethodOptions = {}); };options
每个 SharedStorageWorklet
都有一个关联的布尔值 addModule initiated,初始化为
false。
每个 SharedStorageWorklet
都有一个关联的 USVString
data origin,初始化为 "context-origin"。
每个 SharedStorageWorklet
都有一个关联的布尔值 has cross-origin data origin,
初始化为 false。
因为通过 addModule()
为同一个 SharedStorageWorklet
添加多个模块脚本,会让调用者能够将来自共享存储的数据存储在模块脚本中定义的全局变量里,然后通过之后对
addModule()
的调用泄露这些数据,因此每个 SharedStorageWorklet
只能调用一次 addModule()。
addModule initiated 布尔值使得强制执行此限制成为可能。
当为某个 worklet 调用 addModule()
时,它将运行check if addModule is allowed and update
state,并且如果结果是 "DisallowedDueToNonPreferenceError",或者如果结果是
"DisallowedDueToPreferenceError" 且该 worklet 的has cross-origin data origin 为
false,它将导致 addModule()
失败,详见 § 2.2.6 针对 addModule() 的猴子补丁。
-
根据需要使用 environment 和 origin 中可用的值,执行一个实现定义的算法,以返回 true 或 false。
-
如果 environment 不是安全上下文,则返回 false。
-
如果 allowedInOpaqueOriginContext 为 false,且 environment 的源是不透明源,则返回 false。
-
如果 origin 是不透明源,则返回 false。
-
断言:globalObject 是
Window或SharedStorageWorkletGlobalScope。 -
如果 globalObject 是
Window, 并且在 "shared-storage"、globalObject 的 关联文档和 origin 上运行Is feature enabled in document for origin? 的结果 返回 false,则返回 false。 -
如果以 origin 运行 obtain a site 的结果没有登记,则返回 false。
-
返回 true。
-
对于创建 worklet,environment 是与创建该 worklet 的
Window关联的环境设置对象,而 origin 是模块脚本 URL 的源。 -
对于在 worklet 上运行操作(来自
Window), environment 是与创建该 worklet 的Window关联的环境设置对象,而 origin 是该 worklet 的全局作用域[0] 的Realm的设置对象的源。 -
对于 § 6.4 设置器/删除器方法,environment 要么是当前上下文 (当从
Window调用时),要么是与创建该 worklet 的Window关联的环境设置对象(当从SharedStorageWorkletGlobalScope调用时),而 origin 是 environment 的源。 -
对于从
Window调用的get()(它只能在围栏框架中成功),environment 是当前上下文, 而 origin 是 environment 的源。 -
对于 § 9.4 共享存储 Fetch 相关算法, environment 是请求的window,而 origin 是请求的当前 URL的源。
-
对于 § 9.4 共享存储 Fetch 相关算法,对于使用值为
"script-origin"的 dataOrigin 选项调用并带有跨源 worklet 脚本的createWorklet()(这将导致 worklet 的 has cross-origin data origin 为 true),以及对于在 has cross-origin data origin 为 true 的 worklet 上操作的selectURL()和run(), allowedInOpaqueOriginContext 为 true。对于其他方法, allowedInOpaqueOriginContext 为 false。
SharedStorageWorklet
worklet 和 URL moduleURLRecord 的情况下,check if addModule
is allowed and update state,
运行以下步骤:
-
如果 worklet 的 addModule initiated 为 true, 返回 "DisallowedDueToNonPreferenceError"。
-
将 worklet 的 addModule initiated 设置为 true。
-
如果 worklet 的 data origin 是
"script-origin",将 workletDataOrigin 设置为 moduleURLRecord 的 源。 -
否则,如果 worklet 的 data origin 不是
"context-origin":-
令 customOriginUrl 为在 worklet 的 data origin 上运行 URL 解析器的结果。
-
如果 customOriginUrl 不是有效的 URL, 返回 "DisallowedDueToNonPreferenceError"。
-
将 workletDataOrigin 设置为 customOriginUrl 的源。
-
-
令 hasCrossOriginDataOrigin 为 false。
-
如果 workletDataOrigin 与当前设置对象的源不是同源,则将 hasCrossOriginDataOrigin 设置为 true。
-
令 allowedInOpaqueOriginContext 为 hasCrossOriginDataOrigin。
-
如果在给定当前设置对象、 workletDataOrigin 和 allowedInOpaqueOriginContext 的情况下运行 determine whether shared storage is allowed by context 的结果为 false,则返回 "DisallowedDueToNonPreferenceError"。
-
将 worklet 的 has cross-origin data origin 设置为 hasCrossOriginDataOrigin。
-
如果在给定当前设置对象和 workletDataOrigin 的情况下运行 check if user preference setting allows access to shared storage 的结果为 false,则返回 "DisallowedDueToPreferenceError"。
-
返回 "Allowed"。
此外,每个 SharedStorageWorklet
的
全局作用域列表(初始为空)最多只能包含其worklet 全局作用域类型的一个实例,即 SharedStorageWorkletGlobalScope。
2.1.
在 SharedStorageWorklet
上运行操作方法
SharedStorageWorklet
worklet、DOMString
operationName、list of strings urlList、源 workletDataOrigin、navigable navigable、SharedStorageRunOperationMethodOptions
options、预指定报告参数或 null
preSpecifiedParams 以及聚合协调者或 null
aggregationCoordinator 的情况下,get the
select-url result index,运行以下步骤。此算法将返回一个由如下内容组成的元组:
一个会解析为 unsigned long
的promise,其值是从 urlList 中选出的 URL 的索引;以及一个布尔值,指示是否应对顶级可遍历的预算进行计费。
-
令 promise 为一个新的promise。
-
令 window 为 worklet 的相关设置对象。
-
如果 window 的浏览上下文为 null,则返回由(以
TypeError拒绝的 promise,true)组成的元组。 -
如果 window 的关联文档不是完全活动的,返回由(以
TypeError拒绝的 promise,true)组成的元组。 -
令 globalScope 为 worklet 的全局作用域[0]。
-
令 moduleMapKeyTuples 为在 globalScope 的相关设置对象的模块映射上运行 get the keys 的结果。
-
令 moduleURLRecord 为 moduleMapKeyTuples[0][0]。
-
令 savedQueryName 为 options["
savedQuery"]。 -
如果 savedQueryName 是一个字符串且不是 空字符串,则:
-
令 callbackTask 为在给定 window、urlList 和 promise 的情况下运行 obtain a callback to process the saved index result 的结果。
-
令 savedIndex 为在 navigable、workletDataOrigin、moduleURLRecord、 operationName、savedQueryName 和 callbackTask 上运行 get the index for a saved query 的结果。
-
如果 savedIndex 是 "pending callback",则返回元组 (promise, false)。
注: callbackTask 现在被 存储起来,以便在先前获得的 worklet 代理完成其为此查询选择索引的操作时运行。当运行 callbackTask 的步骤时,promise 将被解析。
-
如果 savedIndex 是
unsigned long, 则: -
断言 savedIndex 是 "pending current operation"。
-
-
在 globalScope 的worklet 事件循环上排队一个任务来执行以下步骤:
-
令 operationMap 为 globalScope 的操作映射。
-
如果 operationMap 不包含 operationName,则在DOM 操作任务源上,给定 window,排队一个全局任务以用
TypeError拒绝 promise,并中止这些步骤。注: 如果
register()从未以 operationName 调用,则可能发生这种情况。 -
令 operation 为 operationMap[operationName],并转换为
RunFunctionForSharedStorageSelectURLOperation。 -
令 privateAggregationCompletionTask 为在给定 workletDataOrigin、 preSpecifiedParams 和 aggregationCoordinator 的情况下设置私有 聚合作用域的结果。
-
令 argumentsList 为列表 « urlList »。
-
令 indexPromise 为以 argumentsList 调用 operation 的结果。
-
对 indexPromise 作出反应:
- 如果它以值 index 兑现:
-
-
如果 index 大于 urlList 的大小,则:
-
如果 savedQueryName 是一个字符串且不是空 字符串,则使用 window、 navigable、workletDataOrigin、 moduleURLRecord、operationName、 savedQueryName 和默认 selectURL 索引运行 store the index for a saved query。
-
在DOM 操作 任务源上,给定 window,排队一个全局任务以用
TypeError拒绝 promise, 并中止这些步骤。
注: 结果 索引超出了输入 urls 的大小。这违反了 selectURL() 协议,我们不知道应选择哪个 url。
否则:
-
如果 savedQueryName 是一个字符串且不是空 字符串,则使用 window、 navigable、workletDataOrigin、 moduleURLRecord、operationName、 savedQueryName 和 index 运行 store the index for a saved query。
-
在DOM 操作 任务源上,给定 window,排队一个全局任务以用 index 解析 promise。
-
运行 privateAggregationCompletionTask。
-
-
- 如果它被拒绝:
-
-
如果 savedQueryName 是一个字符串且不是空字符串,则使用 window、navigable、 workletDataOrigin、moduleURLRecord、 operationName、savedQueryName 和默认 selectURL 索引运行 store the index for a saved query。
-
在DOM 操作任务 源上,给定 window,排队一个全局任务以用
TypeError拒绝 promise。注: 这表示 operationCtor 的 run() 方法遇到错误 (其中 operationCtor 是
register()中的参数),或者结果 index 是非整数值,这违反了 selectURL() 协议,我们不知道应选择哪个 url。 -
运行 privateAggregationCompletionTask。
-
-
-
返回元组 (promise, true)。
SharedStorageWorklet
worklet、环境设置对象 environment、Document
document、sequence
of SharedStorageUrlWithMetadata
urls、list of strings urlList、navigable navigable、SharedStorageRunOperationMethodOptions
options、围栏框架配置映射
fencedFrameConfigMapping、urn uuid urn、
布尔值
shouldChargeTopLevelBudgets、布尔值
shouldUseDefaultIndex,以及 unsigned long
resultIndex 的情况下,handle the result of selecting an index,执行以下步骤:
-
令 site 为使用 document 的源运行 obtain a site 的结果。
-
令 remainingBudget 为使用 environment 和 site 运行 determine remaining navigation budget 的结果。
-
令 pendingBits 为 urlList 的大小的以 2 为底的对数。
-
如果 shouldChargeTopLevelBudgets 为 true:
-
令 pageBudgetResult 为使用 navigable、 site 和 pendingBits 运行 charge shared storage top-level traversable budgets 的结果。
-
如果 pageBudgetResult 为 false,则将 shouldUseDefaultIndex 设置为 true。
-
-
如果 pendingBits 大于 remainingBudget,则将 shouldUseDefaultIndex 设置为 true。
-
如果 shouldUseDefaultIndex 为 true,则将 resultIndex 设置为默认 selectURL 索引。
-
令 finalConfig 为一个新的围栏框架配置。
-
将 finalConfig 的映射 URL设置为 urlList[resultIndex]。
-
将 finalConfig 的 a "pending shared storage budget debit" field 设置为 pendingBits。
-
在 fencedFrameConfigMapping 上使用 urn 和 finalConfig Finalize a pending config。
-
令 resultURLWithMetadata 为 urls[resultIndex]。
-
如果 resultURLWithMetadata 具有字段 "
reportingMetadata",则使用 resultURLWithMetadata["reportingMetadata"] 运行 register reporting metadata。 -
如果 options["
keepAlive"] 为 false,则使用 worklet 运行 terminate a worklet global scope。
selectURL(name, urls, options)
方法步骤为:
-
令 resultPromise 为一个新的promise。
-
如果 this 的 addModule initiated 为 false, 则返回一个以
TypeError拒绝的 promise。 -
令 context 为 window 的浏览上下文。
-
如果 context 为 null,则返回一个以
TypeError拒绝的 promise。 -
令 preSpecifiedParams 为在给定 options 和 context 的情况下 获得预指定报告 参数的结果。
-
如果 preSpecifiedParams 是
DOMException, 则返回一个以 preSpecifiedParams 拒绝的 promise。 -
令 aggregationCoordinator 为在给定 options 的情况下获得聚合协调者的结果。
-
如果 aggregationCoordinator 是
DOMException, 则返回一个以 aggregationCoordinator 拒绝的 promise。 -
令 document 为 context 的活动文档。
-
如果 this 的全局作用域为空,则 返回一个以
TypeError拒绝的 promise。注: 如果在
selectURL()之前调用addModule(), 就可能发生这种情况。 -
如果在 "shared-storage-select-url"、 document 和 workletDataOrigin 上运行Is feature enabled in document for origin? 的结果返回 false, 则返回一个以
TypeError拒绝的 promise。 -
如果对 globalScope 运行 check whether addModule is finished 的结果为 false,则返回一个以
TypeError拒绝的 promise。 -
如果 urls 为空,或者 urls 的大小大于 8,则返回一个以
TypeError拒绝的 promise。注: 此处选择 8,是为了使每次
selectURL()调用在结果围栏框架被点击时,最多只能泄露 log2(8) = 3 位信息。每次调用的信息量并不多。 -
令 urlList 为一个空列表。
-
对 urls 中的每个 urlWithMetadata 执行:
-
如果 urlWithMetadata 没有字段 "
url",则返回一个以TypeError拒绝的 promise。 -
否则,令 urlString 为 urlWithMetadata["
url"]。 -
令 serializedUrl 为使用 urlString 运行 get the canonical URL string if valid 的结果。
-
如果 serializedUrl 为 undefined,则返回一个以
TypeError拒绝的 promise。 -
否则,将 serializedUrl 附加到 urlList。
-
如果 urlWithMetadata 具有字段 "
reportingMetadata":-
令 reportingMetadata 为 urlWithMetadata["
reportingMetadata"]。 -
如果使用 reportingMetadata 运行 validate reporting metadata 的结果为 false,则以
TypeError拒绝 resultPromise 并中止这些步骤。
-
-
-
令 navigable 为 window 的关联文档的节点 navigable。
-
令 fencedFrameConfigMapping 为 navigable 的可遍历 navigable的围栏框架配置 映射。
-
令 pendingConfig 为一个新的围栏框架配置。
-
令 urn 为在 fencedFrameConfigMapping 上使用 pendingConfig 运行 store a pending config 的结果。
-
如果 urn 是 failure,则返回一个以
TypeError拒绝的 promise。 -
令 environment 为 window 的相关设置对象。
-
令 allowedInOpaqueOriginContext 为 this 的has cross-origin data origin。
-
如果在给定 environment、 workletDataOrigin 和 allowedInOpaqueOriginContext 的情况下运行 determine whether shared storage is allowed by context 的结果为 false,则返回一个以
TypeError拒绝的 promise。 -
如果在给定 environment 和 workletDataOrigin 的情况下运行 check if user preference setting allows access to shared storage 的结果为 false:
-
如果 this 的 has cross-origin data origin 为 false,则返回一个以
TypeError拒绝的 promise。
-
-
如果 options["
resolveToConfig"] 为 true,则用 pendingConfig 解析 resultPromise。 -
否则,用 urn 解析 resultPromise。
-
令 (indexPromise, shouldChargeTopLevelBudgets) 为在给定 this、name、urlList、 workletDataOrigin、navigable、options、 preSpecifiedParams 和 aggregationCoordinator 的情况下运行 get the select-url result index 的结果。
-
当 indexPromise 以 resultIndex 兑现时,在给定 worklet、environment、document、 urls、urlList、navigable、options、 fencedFrameConfigMapping、urn、shouldChargeTopLevelBudgets、 false 和 resultIndex 的情况下,运行 handle the result of selecting an index。
-
当 indexPromise 被拒绝时,在给定 worklet、environment、document、 urls、urlList、navigable、options、 fencedFrameConfigMapping、urn、shouldChargeTopLevelBudgets、 true 和默认 selectURL 索引的情况下,运行 handle the result of selecting an index。
-
返回 resultPromise。
run(name, options) 方法
步骤为:
-
令 promise 为一个新的promise。
-
如果 this 的 addModule initiated 为 false, 则返回一个以
TypeError拒绝的 promise。 -
令 context 为 window 的浏览上下文。
-
令 preSpecifiedParams 为在给定 options 和 context 的情况下获得预指定报告 参数的结果。
-
如果 preSpecifiedParams 是
DOMException, 则返回一个以 preSpecifiedParams 拒绝的 promise。 -
令 aggregationCoordinator 为在给定 options 的情况下获得聚合协调者的结果。
-
如果 aggregationCoordinator 是
DOMException, 则返回一个以 aggregationCoordinator 拒绝的 promise。 -
如果 this 的全局作用域为空,则 返回一个以
TypeError拒绝的 promise。注: 如果在
run()之前调用addModule(), 就可能发生这种情况。 -
如果对 globalScope 运行 check whether addModule is finished 的结果为 false,则返回一个以
TypeError拒绝的 promise。 -
令 allowedInOpaqueOriginContext 为 this 的has cross-origin data origin。
-
如果在给定 window、 workletDataOrigin 和 allowedInOpaqueOriginContext 的情况下运行 determine whether shared storage is allowed by context 的结果为 false,则以
TypeError拒绝 promise。 -
如果在给定 window 和 workletDataOrigin 的情况下运行 check if user preference setting allows access to shared storage 的结果为 false:
-
如果 this 的 has cross-origin data origin 为 false,则以
TypeError拒绝 promise。 -
否则,用 undefined 解析 promise。
-
返回 promise。
-
-
返回 promise,并立即在给定 window 的情况下获得 worklet 代理,并在该代理中运行这些步骤的其余部分:
注: promise 的解析 应该早于
SharedStorageWorkletGlobalScope内部的执行,并且不依赖于该执行。 这是因为共享存储是一种未分区存储,而SharedStorageWorkletGlobalScope可以访问跨站点数据,这些数据不应通过run()(通过其成功/错误结果)泄露。-
如果 globalScope 的相关设置对象的模块映射不是空:
-
令 operationMap 为 this 的
SharedStorageWorkletGlobalScope的 操作 映射。 -
如果 operationMap 包含 name:
-
令 privateAggregationCompletionTask 为在给定 workletDataOrigin、 preSpecifiedParams 和 aggregationCoordinator 的情况下设置私有聚合 作用域的结果。
-
令 argumentsList 为一个新的列表。
-
以 argumentsList 和 "
report" 调用 operation。 -
等待 operation 完成运行(如适用)。
-
运行 privateAggregationCompletionTask。
-
-
如果 options["
keepAlive"] 为 false:-
等待 operation 完成运行(如适用)。
-
SharedStorageRunOperationMethodOptions
options 的情况下,obtain
the aggregation coordinator,执行以下
步骤。它们返回一个聚合协调者、null 或 DOMException:
-
如果 options["
privateAggregationConfig"] 不存在,返回 null。 -
如果 options["
privateAggregationConfig"]["aggregationCoordinatorOrigin"] 不存在,返回 null。 -
返回在给定 options["
privateAggregationConfig"]["aggregationCoordinatorOrigin"] 的情况下获得私有聚合 协调者的结果。
SharedStorageRunOperationMethodOptions
options 和浏览上下文 context 的情况下,obtain the
pre-specified report parameters,执行以下步骤。它们
返回预指定报告参数、null,或 DOMException:
-
如果 options["
privateAggregationConfig"] 不存在,返回 null。 -
令 privateAggregationConfig 为 options["
privateAggregationConfig"]。 -
令 contextId 为 null。
-
如果 privateAggregationConfig["
contextId"] 存在,将 contextId 设置为 privateAggregationConfig["contextId"]。 -
如果 contextId 的长度大于 64,则返回一个名称为 "
DataError" 的新DOMException。 -
令 filteringIdMaxBytes 为默认过滤 ID 最大字节数。
-
如果 privateAggregationConfig["
filteringIdMaxBytes"] 存在,将 filteringIdMaxBytes 设置为 privateAggregationConfig["filteringIdMaxBytes"]。 -
如果 filteringIdMaxBytes 不包含 在有效过滤 ID 最大字节数范围中, 返回一个名称为 "
DataError" 的新DOMException。 -
如果 context 的围栏框架配置实例 不是 null:
-
如果 filteringIdMaxBytes 不是默认过滤 ID 最大字节数,或者 contextId 不是 null,则返回一个名称为 "
DataError" 的新DOMException。
-
-
令 maxContributions 为 null。
-
如果 privateAggregationConfig["
maxContributions"] 存在,将 maxContributions 设置为 privateAggregationConfig["maxContributions"]。 -
如果 maxContributions 为零,返回一个名称为 "
DataError" 的新DOMException。 -
返回一个新的预指定报告参数,其项目为:
- 上下文 ID
-
contextId
- 过滤 ID 最大字节数
-
filteringIdMaxBytes
- 最大贡献数
-
maxContributions
注: 返回的算法应在关联操作 完成时运行。
-
令 batchingScope 为一个新的批处理作用域。
-
令 debugScope 为一个新的调试作用域。
-
令 privateAggregationTimeout 为 null。
-
令 hasRunPrivateAggregationCompletionTask 为 false。
-
令 privateAggregationCompletionTask 为一个执行 以下步骤的算法:
-
如果 hasRunPrivateAggregationCompletionTask,返回。
-
将 hasRunPrivateAggregationCompletionTask 设置为 true。
-
给定 debugScope,Mark a debug scope complete。
-
给定 batchingScope、workletDataOrigin、 "
shared-storage" 和 privateAggregationTimeout,Process contributions for a batching scope。
-
-
如果 aggregationCoordinator 不为 null,给定 aggregationCoordinator 和 batchingScope set the aggregation coordinator for a batching scope。
-
如果 preSpecifiedParams 不为 null:
-
令 isDeterministicReport 为给定 preSpecifiedParams 运行 determine if a report should be sent deterministically 的结果。
-
如果 isDeterministicReport:
-
将 privateAggregationTimeout 设置为当前挂钟时间加上 确定性 操作超时持续时间。
-
-
给定 preSpecifiedParams 和 batchingScope,Set the pre-specified report parameters for a batching scope。
-
如果 isDeterministicReport,并行运行以下步骤:
-
等待直到 privateAggregationTimeout。
-
运行 privateAggregationCompletionTask。
-
-
-
返回 privateAggregationCompletionTask。
deterministic operation timeout duration 是一个实现定义的非负持续时间,它控制 如果共享存储操作正在触发确定性报告,那么该操作可以进行私有聚合贡献的时长,以及等价地, 该报告应在操作开始后何时发送。
2.2. 针对 Worklets 的猴子补丁
本规范将对 Worklet 标准作出一些修改,以适应共享存储的需要。
2.2.1. 针对 set up a worklet environment settings object 的猴子补丁
set up a worklet environment settings
object 算法将需要包含一个额外的参数:Worklet
worklet。定义 settingsObject 的源的步骤应修改如下:
-
令 settingsObject 为一个新的环境设置对象,其算法定义如下:
......
-
令 workletGlobalScope 为 realmExecutionContext 的 Realm 组件的全局对象。
-
如果 workletGlobalScope 不是
SharedStorageWorkletGlobalScope, 返回 origin。 -
断言 worklet 是一个
SharedStorageWorklet。 -
如果 worklet 的 data origin 是
"context-origin",返回 outsideSettings 的源。 -
否则,如果 data origin 是
"script-origin": -
否则,令 customOriginUrl 为在 data origin 上运行 URL 解析器的结果。
-
返回 customOriginUrl 的源。
......
-
2.2.2. 针对 create a worklet global scope 的猴子补丁
create a worklet global scope 算法将需要被修改,以传入 worklet 参数:
-
令 insideSettings 为在给定 realmExecutionContext、outsideSettings 和 worklet 的情况下,设置 worklet 环境 设置对象的结果。
2.2.3. 针对 fetch a worklet script graph 的猴子补丁
算法 fetch a worklet script graph 会调用 fetch a worklet/module worker script graph 算法,后者接受一个算法参数 processCustomFetchResponse。该 processCustomFetchResponse 参数的定义将需要在步骤 "5. Fetch request, ..." 之前包含以下步骤:
-
如果 fetchClient 的全局对象是
SharedStorageWorkletGlobalScope:-
将 request 的重定向模式设置为 "
error"。注: 对于共享存储,模块脚本请求不允许 重定向。有了这个限制,就有可能在
SharedStorageWorkletGlobalScope被创建后立即定义并使用获取 realm 的设置对象的源的算法(如 § 2.2.1 针对 set up a worklet environment settings object 的猴子补丁 中所述),因为该源不会改变。 此限制可能会在该设计未来的迭代中移除。如果允许重定向,大概获取 realm 的设置对象的源的算法应被更新为在收到最终请求的 响应之后,返回最终请求的URL 的源,并且用户偏好检查应只在该时点之后进行。
-
2.2.4.
`Shared-Storage-Cross-Origin-Worklet-Allowed`
HTTP 响应标头
`Shared-Storage-Cross-Origin-Worklet-Allowed`
HTTP 响应标头连同传统 CORS 标头,可用于授予跨源站点从模块脚本的 URL 的源创建 worklet 的权限,并允许在 worklet 上运行后续操作时,使用
模块脚本的 URL 的源作为
用于访问共享存储数据的 data partition origin,即在 § 2.2.1 针对 set up a
worklet environment settings object 的猴子补丁中设置的源,它会成为所有 SharedStorage
调用 obtain a shared storage bottle map 时使用的源。
加载跨源脚本的 worklet 依赖 CORS 作为基线权限机制,以指示受信任的外部源。然而,仅有 CORS
不足以创建一个带有跨源脚本且其data partition origin 为脚本源的 worklet。
不同于简单资源共享,worklet 允许创建者站点在目标源的上下文中执行 JavaScript。为了确保安全,
需要脚本源额外提供一个响应标头:
`Shared-Storage-Cross-Origin-Worklet-Allowed`。
2.2.5. 针对 HTTP fetch 的猴子补丁
将需要把步骤添加到 HTTP fetch 算法中。注: 谨慎考虑安全影响是服务模块脚本的站点的责任:
当模块脚本的 URL 的
源和 worklet 的创建者 Window
源不是同源时,
通过在模块脚本响应上发送宽松的 CORS 标头和
`Shared-Storage-Cross-Origin-Worklet-Allowed`
标头,服务器将授予 worklet 的创建及 worklet 上的后续操作,同时允许 worklet 使用该 worklet
的脚本的源作为
用于访问共享存储数据的源,即data
partition origin。例如,worklet 的
创建者 Window
可通过调用 selectURL()
或 run(),
污染并耗尽 worklet 源的站点的剩余导航预算,其中 worklet 源是全局作用域的Realm的设置对象的源。
2.2.6.
针对 addModule()
的猴子补丁
addModule()
方法对于 Worklet
的步骤将需要在步骤 "Let promise be a new promise" 之前包含以下步骤:
-
如果 this 的类型为
SharedStorageWorklet:-
令 addModuleAllowedResult 为在给定 this 和 moduleURLRecord 的情况下运行 check if addModule is allowed and update state 的结果。
-
如果 addModuleAllowedResult 是 "DisallowedDueToNonPreferenceError":
-
否则,如果 addModuleAllowedResult 是 "DisallowedDueToPreferenceError":
-
如果 this 的 has cross-origin data origin 为 false,则返回一个以
TypeError拒绝的 promise。
-
-
否则:
-
断言:addModuleAllowedResult 是 "Allowed"。
-
-
addModule()
将在早期阶段被中止。然而,只有对于同源 worklet(即发起者文档的源与模块脚本的源同源的情况),
该错误才会暴露给调用者。对于跨源 worklet,该错误将被隐藏。这是为了防止调用者知道用户已通过偏好
为哪些源禁用了共享存储(如果该浏览器供应商存在按源的偏好)。
调用者仍可能使用计时攻击来获知此信息,但这是一个较小的安全/隐私问题,因为现实中很少有用户会设置 这样的偏好,而进行大范围搜索会因启动 worklet 而产生显著性能成本。
此理由同样适用于 selectURL()
和 run()
对用户偏好错误的处理。
在步骤 "Let addedSuccessfully be false" 之后,我们需要包含以下步骤:
-
如果 this 的类型为
SharedStorageWorklet, has cross-origin data origin 为 true,且 data origin 不是"script-origin":-
断言 pendingTasks 为 1。
-
将 pendingTasks 设置为 2。
-
在网络任务源上,给定 workletGlobalScope,排队一个全局任务来执行以下步骤:
-
令 customOriginUrl 为在 data origin 上运行 URL 解析器的结果。
-
将 customOriginUrl 的路径设置为 ≪".well-known", "shared-storage", "trusted-origins"≫。
-
令 request 为一个新的请求,其URL 为 customOriginUrl,模式为
"cors",引荐来源为"client",目标 为"json",发起者类型为"script", 且客户端为 outsideSettings。 -
Fetch request,并将 processResponseConsumeBody 设为 以下算法,给定响应 response 和 null、failure 或字节序列 bodyBytes:
-
如果以下任一为 true:
则:
-
将 pendingTasks 设置为 −1。
-
用 "TypeError" DOMException 拒绝 promise。
-
中止这些步骤。
-
-
令 mimeType 为从 response 的标头列表提取 MIME 类型的结果。
-
如果 mimeType 不是 JSON MIME 类型,则:
-
将 pendingTasks 设置为 −1。
-
用 "TypeError" DOMException 拒绝 promise。
-
中止这些步骤。
-
-
令 sourceText 为对 bodyBytes 进行 UTF-8 解码的结果。
-
令 parsed 为在给定 sourceText 的情况下,将 JSON 字符串解析为 Infra 值的结果。
-
如果 parsed 不是列表 或者 parsed 为空,则:
-
将 pendingTasks 设置为 −1。
-
用 "TypeError" DOMException 拒绝 promise。
-
中止这些步骤。
-
-
令 doesMatch 为 false。
-
对于 parsed 的每个 item:
-
如果 item 不是有序映射,或者 item 不包含
scriptOrigin, 或者 item 不包含contextOrigin:-
将 pendingTasks 设置为 −1。
-
用 "TypeError" DOMException 拒绝 promise。
-
中止这些步骤。
-
-
令 doesMatch 为在 item[
scriptOrigin]、 moduleURLRecord 的源、 item[contextOrigin] 和 outsideSettings 的源上运行 check for script and context origin match 的结果。 -
如果 doesMatch 为 true:
-
在网络任务 源上,给定 this 的相关全局 对象,排队一个全局 任务来执行以下步骤:
-
如果 pendingTasks 不是 −1,则:
-
将 pendingTasks 设置为 pendingTasks − 1。
-
如果 pendingTasks 为 0,执行 以下步骤:
-
如果 workletGlobalScope 有 一个关联的布尔值 addModule success,将 workletGlobalScope 的 addModule success 设置为 true。
-
解析 promise。
-
-
-
-
中断。
-
-
-
如果 doesMatch 为 false,则:
-
将 pendingTasks 设置为 −1。
-
用 "TypeError" DOMException 拒绝 promise。
-
-
-
-
注: 如果 worklet 数据源不同于当前上下文和脚本源, 则会执行一项额外检查。这涉及从 worklet 数据源获取配置文件,以验证当前上下文是否被允许加载带有该脚本的 worklet 并执行操作。
倒数第二个步骤(即最后一个缩进的步骤),目前为 "If pendingTasks is 0, then resolve promise.",应更新为:
-
如果 pendingTasks 为 0,执行以下步骤:
-
如果 workletGlobalScope 有一个关联的布尔值 addModule success, 将 workletGlobalScope 的 addModule success 设置为 true。
-
解析 promise。
-
在最后一个步骤(目前为 "Return promise.")之前,添加以下步骤:
-
如果 this 是一个
SharedStorageWorklet, 则在 promise 兑现时或 promise 被拒绝时,运行以下步骤:-
令 privateAggregationObj 为 globalScopes[0] 的
privateAggregation。 -
将 privateAggregationObj 的allowed to use 设置为确定 this 的相关全局对象的关联文档是否允许使用 "
private-aggregation" 策略控制特性的结果。 -
将 privateAggregationObj 的作用域细节设置为一个 新的作用域细节,其项目为:
- get batching scope steps
-
一个算法,返回在 scope 中当前执行的调用返回时,计划传递给process contributions for a batching scope 的批处理作用域。
- get debug scope steps
-
一个算法,返回在 scope 中当前执行的调用返回时,计划传递给mark a debug scope complete 的调试作用域。
注: 多个操作调用可以同时 进行,每个调用都有不同的批处理作用域和调试作用域。然而, 当前只能有一个正在执行。
trusted origin type 是字符串或列表 of strings。
-
如果在给定 itemScriptOrigin 和 actualScriptOrigin 的情况下运行 check for trusted origin match 的结果为 false,则返回 false。
-
返回在给定 itemContextOrigin 和 actualContextOrigin 的情况下运行 check for trusted origin match 的结果。
-
如果 itemOrigin 是字符串,返回在给定 itemOrigin 和 actualOrigin 的情况下运行 check for trusted origin match on a string 的结果。
-
否则,对于 itemOrigin 中的每个 originString:
-
如果在给定 originString 和 actualOrigin 的情况下运行 check for trusted origin match on a string 的结果为 true,则返回 true。
-
-
返回 false。
为进程外 worklet 添加额外的猴子补丁部分。
2.3. SharedStorageWorkletGlobalScope
SharedStorageWorklet
的
worklet 全局作用域类型是 SharedStorageWorkletGlobalScope。
SharedStorageWorklet
的
worklet 目标类型是 "sharedstorageworklet"。
2.3.1. 针对 request destination 的猴子补丁
fetch 请求的 destination 字段还应将 "sharedstorageworklet" 作为一个有效值包含进来。
callback =RunFunctionForSharedStorageSelectURLOperation Promise <unsigned long >(sequence <USVString >,urls optional any );data
[Exposed =SharedStorageWorklet ,Global =SharedStorageWorklet ]interface :SharedStorageWorkletGlobalScope WorkletGlobalScope {undefined register (DOMString ,name Function );operationCtor readonly attribute SharedStorage sharedStorage ;readonly attribute PrivateAggregation ;privateAggregation Promise <sequence <StorageInterestGroup >>interestGroups ();readonly attribute SharedStorageWorkletNavigator navigator ; };
每个 SharedStorageWorkletGlobalScope
都有一个关联的环境设置对象 outside settings,它是关联的
SharedStorageWorklet
的
相关设置对象。
每个 SharedStorageWorkletGlobalScope
都有一个关联的布尔值
addModule success,它初始化为
false。
每个 SharedStorageWorkletGlobalScope
还有一个关联的 operation
map,它是一个映射,初始为空,从字符串(表示操作
名称)到函数对象。
每个 SharedStorageWorkletGlobalScope
都有一个关联的 SharedStorage
实例 shared storage
instance。
每个 SharedStorageWorkletGlobalScope
都有一个关联的 SharedStorageWorkletNavigator
实例 navigator instance。
2.3.2. SharedStorageWorkletGlobalScope
算法
register(name, operationCtor)
方法步骤为:
-
如果 name 缺失或为空,则抛出一个
TypeError。 -
令 operationMap 为此
SharedStorageWorkletGlobalScope的 operation map。 -
如果 operationCtor 缺失,则抛出一个
TypeError。 -
令 operationClassInstance 为不带参数构造 operationCtor 的结果。
-
令 runFunction 为 Get(operationClassInstance, "
run")。 重新抛出任何异常。 -
如果 IsCallable(runFunction) 为 false,则抛出一个
TypeError。 -
将 operationMap[name] 的值设置为 runFunction。
鉴于 WebIDL,这里的 "name" 和 "operationCtor" 不可能缺失。应当只检查默认/空值。[Issue #151]
interestGroups()
方法步骤为:
-
令 promise 为一个新的promise。
-
如果对
SharedStorage的关联SharedStorageWorkletGlobalScope运行 check whether addModule is finished 的结果为 false,则返回一个以TypeError拒绝的 promise。 -
令 context 为 globalObject 的浏览上下文。
-
如果 context 为 null,则返回一个以
TypeError拒绝的 promise。 -
如果 document 不是完全活动的,则返回一个以
TypeError拒绝的 promise。 -
并行运行以下步骤:
-
返回 promise。
sharedStorage getter 步骤为:
-
如果 this 的 addModule success 为 true,则返回 this 的 shared storage instance。
-
否则,抛出一个
TypeError。
-
返回 addModule success 的值。
2.4. SharedStorageUrlWithMetadata
和报告
dictionary {SharedStorageUrlWithMetadata required USVString ;url object ; };reportingMetadata
如果一个 SharedStorageUrlWithMetadata
字典包含非空的 reportingMetadata
object,
形式为一个字典,其键
是 FenceEvent
的
eventType,
且其值是会解析为有效 URL
的字符串,
则这些 eventType-URL
对将被注册,以便之后在加载由此 selectURL()
调用产生的 SharedStorageResponse
的任何围栏框架内访问。
reportingMetadata
应该是一个字典。[Issue
#141]
在一个围栏框架内,如果其中通过带有 reportingMetadata
object
的 selectURL()
已经注册了 eventType-URL
对,当在一个 FenceEvent
上调用 reportEvent(),
且其 destination
包含
"shared-storage-select-url" 并且该 FenceEvent
的
对应 eventType
被触发时,则该 FenceEvent
的
eventData
将作为一个 beacon
发送到为该 eventType
注册的 URL。
object
reportingMetadata 的情况下,validate
reporting metadata,运行以下步骤:
-
如果 reportingMetadata 不是字典,返回 false。
-
如果 reportingMetadata 为空, 返回 true。
-
对于每个 reportingMetadata 的 eventType → urlString,如果用 urlString 运行 get the canonical URL string if valid 的结果为 undefined,则返回 false。
-
返回 true。
object
reportingMetadata 和一个围栏
框架配置 fencedFrameConfigStruct 的情况下,register
reporting metadata,运行以下步骤:
将 reportingUrlMap 存储在与 fencedFrameConfigStruct 关联的围栏框架报告器类中。二者仍需添加到草案 [Fenced-Frame] 中。[Issue #144]
2.5. 熵预算
由于熵位可以通过 selectURL()
泄露,用户
代理将需要维护预算以限制这些泄露。
在调用 selectURL()
时,当这些预算中的任一耗尽,默认 selectURL 索引将被用于确定要选择哪个 URL。
sequence<USVString>
urls 的情况下,get the
default selectURL index,运行以下步骤:
-
返回 0。
注: 我们本可以选择返回从 0 到 urls 的大小的排他范围内的任意
unsigned long, 只要返回的索引独立于已注册操作类的 "run" 方法即可。
默认 selectURL
索引是在给定 sequence<USVString>
urls 的情况下,运行 get the default
selectURL index 所获得的索引。
2.5.1. 导航熵预算
如果用户激活一个围栏框架,其节点
文档的浏览上下文的围栏框架配置实例由 selectURL()
生成,并因此发起一个顶级可遍历 导航,这将向落地页面揭示其 URL
被选中,这是一种熵位泄露,最多为对 selectURL()
调用的输入 URL
数量以 2 为底的对数。为缓解此问题,用户代理将设置按站点的导航熵限额。
导航 熵限额是允许在给定调用站点的给定导航预算时期期间,通过围栏框架发起顶级可遍历导航而泄露的最大熵位限额。此限额由用户代理定义, 且与站点无关。
用户 代理将定义一个固定的预定持续时间 navigation budget lifetime。
导航预算 时期是任何时间间隔,其持续时间为 navigation budget lifetime。
为跟踪此导航熵限额如何被使用,用户 代理使用一个 共享存储导航预算表,它是从站点到导航熵账本的映射。
- bits
-
一个
double - timestamp
-
一个
DOMHighResTimeStamp(来自 Unix Epoch)
Bit debits,其timestamps早于 当前导航预算时期的开始,被称为过期。
当发生泄露时,其熵位值会被计算,并与当前时间作为timestamp 一起,作为bit debit 存储到该站点在共享存储导航预算表中。
每个站点都有一个关联的 double remaining navigation budget,其值为导航熵限额减去所有bit debits,这些 timestamps位于 当前导航预算时期内。
当一个站点没有足够的remaining
navigation budget 时,selectURL()
将返回 SharedStorageResponse
(即 FencedFrameConfig
或 urn
uuid),用于 SharedStorageUrlWithMetadata
中位于默认
selectURL 索引处的 url。
-
如果用户代理的共享存储导航预算 表不包含 site,则返回 maxBits。
-
否则,令 ledger 为用户代理的 共享存储导航预算 表[site]。
-
令 debitSum 为 0。
-
对于每个 ledger 中的项 bitDebit,执行以下步骤:
-
令 debit 为 bitDebit 的 bits。
-
如果使用 environment 和 bitDebit 运行 check whether a bit debit is expired 的结果为 false,则将 debitSum 增加 debit。
-
-
返回 maxBits − debitSum。
-
令 epochLength 为用户代理的 navigation budget lifetime。
-
令 currentTime 为 environment 的当前挂钟时间。
-
令 threshold 为 currentTime − epochLength。
-
如果 bitDebit 的timestamp 小于 threshold,则返回 true。
-
否则,返回 false。
对于每个由围栏框架发起的顶级可遍历导航,如果其节点
文档的浏览上下文的围栏框架配置实例是通过 selectURL()
生成的,则需要向共享存储导航预算表计费一个 bit debit,
因为这可能会泄露跨站点数据。由于要计费的 bits
是在调用 selectURL()
期间计算的,但只有当且仅当所得的围栏框架发起顶级可遍历导航时,才会实际记录到共享存储导航预算表中,因此在此之前,bits 必须作为 pending shared storage budget
debit 存储在
相应围栏框架的节点
文档的浏览上下文的围栏框架配置实例中。
将 pending shared storage budget debit 的定义移至 围栏框架配置实例,在草案 [Fenced-Frame] 规范中。[Issue #148]
在开始导航和结束导航之间,用户代理将执行 charge shared storage navigation budget 算法。
需要找到一种更好的方式 来指定导航预算计费的时机。[Issue #138]
Document
sourceDocument 的导航期间,charge shared storage navigation budget,运行以下步骤:
-
如果 navigable 不是顶级可遍历,则返回。
-
令 currentNavigable 为 sourceDocument 的节点 navigable。
-
只要 currentNavigable 不为 null:
-
令 site 为使用 currentNavigable 的活动文档的源运行 obtain a site 的结果。
-
将 currentNavigable 设置为 currentNavigable 的父级。
-
令 pendingBits 为 instance 的 pending shared storage budget debit。
-
如果 pendingBits 不大于 0,则继续。
-
令 ledger 为用户 代理的 共享存储导航 预算表[site]。
-
令 bitDebit 为一个新的 bit debit。
-
将 bitDebit 的 bits 设置为 pendingBits。
-
令 currentTime 为当前挂钟时间。
-
将 bitDebit 的timestamp 设置为 currentTime。
-
将 bitDebit 附加到 ledger。
-
将 pendingBits 设置为 0。
-
用户 代理可能希望设置一个定时器,以定期purge expired bit debits from all navigation entropy ledgers,因为过期的 bit debits 将不再需要。
-
对于每个用户代理的 共享存储导航预算 表的 origin → ledger:
-
对于每个 ledger 中的 bitDebit,如果 用 bitDebit 运行 check whether a bit debit is expired 的结果为 true,则从 ledger 中移除 bitDebit。
-
2.5.2. 顶级可遍历熵预算
短期内,当我们拥有限制较少的围栏框架时,有必要施加如下额外限制。
每个用户
代理将指定最大 整体页面熵限额和最大 站点页面熵
限额,其中前者是每个顶级可遍历允许因 selectURL()
泄露的总位数,后者是每个站点在每个顶级可遍历中允许因 selectURL()
泄露的总位数
- overall budget
-
一个
double - site budget map
- saved query map
-
一个从元组(源 data origin、URL worklet script URL、字符串 operation name、字符串 query name)到saved query data 的映射
2.5.2.1. 针对可遍历 Navigable 的猴子补丁
在 [HTML] 的 Traversable navigables 节中,添加以下内容:
除了navigable 的属性之外,可遍历 navigable 还具有:
-
page budget,一个共享存储页面预算或 null,初始为 null。
2.5.2.2. 针对 Navigables 的猴子补丁
通过在末尾添加以下步骤,修改 initialize the navigable 算法:
-
如果 parent 为 null 且 navigable 是可遍历 navigable,则:
-
令 newPageBudget 为一个具有空site budget map 的共享存储页面 预算。
-
将 newPageBudget 的overall budget设置为整体页面熵限额。
-
将 navigable 的page budget设置为 newPageBudget。
-
2.5.2.3. 已保存查询
-
令 topLevelTraversable 为对 navigable 运行 get the top-level traversable 的结果。
-
断言 topLevelTraversable 的page budget不是 null。
-
如果 topLevelTraversable 的page budget的saved query map不包含(origin, moduleURLRecord, operationName, savedQueryName),则:
-
将 topLevelTraversable 的page budget的saved query map[(origin, moduleURLRecord, operationName, savedQueryName)] 设置为一个新的saved query data 结构 queryData。
-
将 queryData 的index值设置为 -1。
-
返回 "pending current operation"。
-
-
令 savedIndex 为 topLevelTraversable 的page budget的saved query map[(origin, moduleURLRecord, operationName, savedQueryName)] 的index。
-
如果 savedIndex 为 -1:
-
返回 savedIndex。
注: get the index for
a saved query 算法返回 "pending current operation",表示索引值正在等待在 SharedStorageWorkletGlobalScope
的
worklet 事件循环上排队任务以执行已注册操作的结果。
注: get the index for
a saved query 算法返回 "pending callback",表示一个用于确定索引结果的任务此前已在 SharedStorageWorkletGlobalScope
的
worklet 事件循环上被排队,并且我们现在正在排队一个额外的
callbackTask,以便在原始任务完成时运行。
Window
window、navigable navigable、源
origin、URL moduleURLRecord、字符串 operationName、
字符串
savedQueryName 和 unsigned long
index 的情况下,store
the index for a saved query:
-
令 topLevelTraversable 为对 navigable 运行 get the top-level traversable 的结果。
-
断言 topLevelTraversable 的page budget不是 null。
-
令 queryData 为 topLevelTraversable 的page budget的saved query map[(origin, moduleURLRecord, operationName, savedQueryName)]。
Window
window、列表 of SharedStorageUrlWithMetadatas
urlList、promise promise 的情况下,obtain a
callback to process the saved index
result,执行以下步骤。它们返回一个算法。
2.5.2.4. 对顶级可遍历熵预算计费
-
令 topLevelTraversable 为对 navigable 运行 get the top-level traversable 的结果。
-
断言 topLevelTraversable 的page budget不是 null。
-
如果 pendingBits 大于 topLevelTraversable 的page budget的overall budget,则返回 false 并中止这些步骤。
-
如果 topLevelTraversable 的page budget的site budget map不包含 site,则将 topLevelTraversable 的page budget的site budget map [site] 设置为站点页面熵限额。
-
如果 pendingBits 大于 topLevelTraversable 的page budget的site budget map [site],则返回 false 并中止这些步骤。
-
将 topLevelTraversable 的page budget的site budget map [site] 减少 pendingBits。
-
将 topLevelTraversable 的page budget的overall budget减少 pendingBits。
-
返回 true。
3. 共享存储的后端
共享存储 API 将按如下方式通过注册新的存储端点,集成到 Storage API 中。3.1. 针对 存储模型的猴子补丁
用户
代理会为类型为 "shared" 的存储
端点持有一个共享存储棚。
本标准还将以 存储
标识符 "sharedStorage" 和配额 54 *
216 字节(即 39.0625 mebibytes),注册一个存储
端点,其类型为 "shared"。
此配额是根据当前实现计算出来的。
请考虑使当前实现与 "localStorage" 和 "sessionStorage" 存储
端点的规范保持一致,即
5 * 220 字节。例如,将每源条目限制
从 10,000 降低到 1,280 即可实现这一点。
注: 不同于以存储键为键的存储棚,共享存储棚直接使用源作为键。共享存储将被有意排除在客户端存储分区之外。
对于共享存储棚中的每个存储架,该存储架的桶
映射目前只有一个键 "default"。
-
令 allowedInOpaqueOriginContext 为 false。
-
如果在给定 environment、origin 和 allowedInOpaqueOriginContext 的情况下运行 determine whether shared storage is allowed by context 的结果为 false,则返回 failure。
-
如果在给定 environment 和 origin 的情况下运行 check if user preference setting allows access to shared storage 的结果为 false,则返回 failure。
-
如果 shed[origin] 不存在,则将 shed[origin] 设置为使用类型 "
shared" 运行 create a shared storage shelf 的结果。 -
返回 shed[origin]。
-
令 shelf 为一个新的存储 架。
-
将 shelf 的桶映射["
default"] 设置为运行 create a shared storage bucket 的结果。 -
返回 shelf。
注: 目前,共享存储桶的瓶
映射的大小为 1,因为只有一个存储
端点以类型
"shared" 注册。
3.2. 共享存储数据库
浏览上下文具有一个关联的 共享存储数据库,它提供用于存储、检索、删除、清除和清除过期数据的方法, 以及如下所述的其他方法。数据库中的数据采用条目的形式。
每个共享 存储数据库都有一个 shared storage database queue,它是启动一个新的并行队列的结果。此队列用于运行共享存储 数据库的每个方法,当这些方法的调用从该浏览上下文发起时。
每个 entry 由一个key和一个value struct组成。
用户 代理可以指定 key 的 maximum length。
由于 keys 用于组织和 高效检索entries,keys 在任何给定的共享存储数据库中最多只能出现一次。
entry 的 value struct 是一个结构,
由字符串 value 和 DOMHighResTimeStamp
last updated(来自 Unix Epoch)组成。
用户 代理可以指定 value 的 maximum length。
用户 代理可以指定 default entry lifetime,即一个entry 被存储到其过期之间的默认持续时间。如果 用户 代理指定了default entry lifetime,则它应当有一个定时器定期从数据库中清除过期条目。
3.3. 核心数据库算法
-
令 valueStruct 为一个新的value struct。
-
将 valueStruct 的value设置为 value。
-
令 currentTime 为 environment 的当前挂钟时间。
-
将 valueStruct 的last updated设置为 currentTime。
-
将 databaseMap[key] 设置为 valueStruct。
-
如果抛出了异常,则返回 false。
注: 根据实现,存储代理映射 databaseMap 的方法可能会产生错误。
-
否则,返回 true。
要在给定环境设置对象 environment 和value struct valueStruct 的情况下,determine whether an entry is expired,运行以下步骤:
-
令 lastUpdated 为 valueStruct 的last updated。
-
令 lifetime 为用户代理的 default entry lifetime。
-
令 expiration 为 lastUpdated 和 lifetime 之和。
-
令 currentTime 为 environment 的当前挂钟时间。
-
如果 expiration 小于或等于 currentTime,返回 true。
-
否则,返回 false。
3.4. 专门化数据库算法
这些算法不同于 § 3.3 核心数据库算法中的核心算法, 它们接受带有更专门启发式的参数,或者采用多步骤 过程,或者二者兼有,以处理更复杂的数据库操作。
要在给定 共享存储数据库 队列 queue、存储 代理映射 databaseMap、环境设置对象 environment、一个 键 key、一个值 value 和一个布尔值 ignoreIfPresent 的情况下,set an entry in the database,在 queue 上运行以下步骤:
-
如果 ignoreIfPresent:
-
令 currentValue 为使用 queue、databaseMap、 environment 和 key 运行 retrieve an entry from the database 的结果。
-
如果 currentValue 为 failure,则返回 false。
-
如果 currentValue 不是 undefined,则返回 true。
-
-
返回使用 queue、databaseMap、environment、 key 和 value 运行 store an entry in the database 的结果。
要在给定 共享存储数据库 队列 queue、存储 代理映射 databaseMap、环境设置对象 environment、一个 键 key 和一个值 value 的情况下,append an entry in the database, 在 queue 上运行以下步骤:
-
令 currentValue 为使用 queue、databaseMap、environment 和 key 运行 retrieve an entry from the database 的结果。
-
如果 currentValue 为 failure,则返回 false。
-
如果 currentValue 不是 undefined:
-
返回使用 queue、databaseMap、environment、 key 和 value 运行 store an entry in the database 的结果。
要在给定 共享存储数据库
队列 queue、存储
代理映射 databaseMap、环境设置对象 environment,
和一个由
SharedStorageModifierMethod
组成的列表
methods 的情况下,batch update entries in the
database,在 queue 上运行以下步骤:
-
令 originalDatabaseMap 为 databaseMap。
-
令 innerMethodFailed 为 false。
-
对于 methods 中的每个 method:
-
如果 method 是一个
SharedStorageSetMethod:-
令 key 为 method 的 key。
-
令 value 为 method 的 value。
-
令 ignoreIfPresent 为 method 的 ignore if present。
-
令 result 为使用 queue、databaseMap、 environment、key、value 和 ignoreIfPresent 运行 set an entry in the database 的结果。
-
如果 result 为 false:
-
将 innerMethodFailed 设置为 true。
-
中断。
-
-
-
否则,如果 method 是一个
SharedStorageAppendMethod:-
令 key 为 method 的 key。
-
令 value 为 method 的 value。
-
令 result 为使用 queue、databaseMap、 environment、key 和 value 运行 append an entry in the database 的结果。
-
如果 result 为 false:
-
将 innerMethodFailed 设置为 true。
-
中断。
-
-
-
否则,如果 method 是一个
SharedStorageDeleteMethod:-
令 key 为 method 的 key。
-
令 result 为使用 queue、 databaseMap、environment 和 key 运行 delete an entry from the database 的结果。
-
如果 result 为 false:
-
将 innerMethodFailed 设置为 true。
-
中断。
-
-
-
否则:
-
断言:method 是一个
SharedStorageClearMethod。 -
令 result 为使用 queue、 databaseMap 和 environment 运行 clear all entries in the database 的结果。
-
如果 result 为 false:
-
将 innerMethodFailed 设置为 true。
-
中断。
-
-
-
-
如果 innerMethodFailed:
-
将 databaseMap 设置为 originalDatabaseMap。
-
返回 false。
-
-
返回 true。
4. 对 Window
接口的扩展
每个 Window
对象都有一个关联的 SharedStorage
实例 sharedStorage,
如果共享存储已启用,
它将随 Window
一同创建,并具有如下getter。
partial interface Window { [SecureContext ]readonly attribute SharedStorage ?; };sharedStorage
sharedStorage
getter 步骤为:
-
如果 this 是完全活动的,则返回 this 的
sharedStorage。 -
否则,返回 null。
5. SharedStorageModifierMethod
接口组
SharedStorageSetMethod、
SharedStorageAppendMethod、
SharedStorageDeleteMethod、
SharedStorageClearMethod
接口分别对应于 set()、
append()、
delete()、
clear()
修改器方法。它们都继承基础 SharedStorageModifierMethod
接口。
[Exposed =(Window ,SharedStorageWorklet )]interface {}; [SharedStorageModifierMethod Exposed =(Window ,SharedStorageWorklet )]interface :SharedStorageSetMethod SharedStorageModifierMethod {constructor (DOMString ,key DOMString ,value optional SharedStorageSetMethodOptions = {}); }; [options Exposed =(Window ,SharedStorageWorklet )]interface :SharedStorageAppendMethod SharedStorageModifierMethod {constructor (DOMString ,key DOMString ,value optional SharedStorageModifierMethodOptions = {}); }; [options Exposed =(Window ,SharedStorageWorklet )]interface :SharedStorageDeleteMethod SharedStorageModifierMethod {constructor (DOMString ,key optional SharedStorageModifierMethodOptions = {}); }; [options Exposed =(Window ,SharedStorageWorklet )]interface :SharedStorageClearMethod SharedStorageModifierMethod {constructor (optional SharedStorageModifierMethodOptions = {}); };options dictionary {SharedStorageModifierMethodOptions DOMString ; };withLock dictionary :SharedStorageSetMethodOptions SharedStorageModifierMethodOptions {boolean ; };ignoreIfPresent
SharedStorageModifierMethod
具有以下关联字段:
- with lock
-
Null 或一个字符串。初始为 null。
SharedStorageSetMethod
具有以下关联字段:
SharedStorageAppendMethod
具有以下关联字段:
SharedStorageDeleteMethod
具有以下关联字段:
- key
-
一个字符串。初始为空。
new SharedStorageSetMethod(key, value, options)
构造器步骤为:
-
令 context 为 null。
-
如果 globalObject 是一个
Window:-
将 context 设置为 globalObject 的浏览上下文。
-
-
否则:
-
将 context 设置为 globalObject 的 outside settings 的 目标浏览 上下文。
-
如果对
SharedStorage的 关联SharedStorageWorkletGlobalScope运行 check whether addModule is finished 的结果为 false,则抛出一个TypeError。
-
-
如果 context 为 null,则抛出一个
TypeError。 -
令 databaseMap 为在给定 environment 和 environment 的源的情况下运行 obtain a shared storage bottle map 的结果。
-
如果 databaseMap 为 failure,则抛出一个
TypeError。 -
将 this 的ignore if present设置为 options["
ignoreIfPresent"]。
new SharedStorageAppendMethod(key, value, options)
构造器步骤为:
-
令 context 为 null。
-
如果 globalObject 是一个
Window:-
将 context 设置为 globalObject 的浏览上下文。
-
-
否则:
-
将 context 设置为 globalObject 的 outside settings 的目标浏览 上下文。
-
如果对
SharedStorage的 关联SharedStorageWorkletGlobalScope运行 check whether addModule is finished 的结果为 false,则抛出一个TypeError。
-
-
如果 context 为 null,则抛出一个
TypeError。 -
令 databaseMap 为在给定 environment 和 environment 的源的情况下运行 obtain a shared storage bottle map 的结果。
-
如果 databaseMap 为 failure,则抛出一个
TypeError。
new SharedStorageAppendMethod(key, options)
构造器步骤为:
-
令 context 为 null。
-
如果 globalObject 是一个
Window:-
将 context 设置为 globalObject 的浏览上下文。
-
-
否则:
-
将 context 设置为 globalObject 的 outside settings 的目标浏览 上下文。
-
如果对
SharedStorage的 关联SharedStorageWorkletGlobalScope运行 check whether addModule is finished 的结果为 false,则抛出一个TypeError。
-
-
如果 context 为 null,则抛出一个
TypeError。 -
令 databaseMap 为在给定 environment 和 environment 的源的情况下运行 obtain a shared storage bottle map 的结果。
-
如果 databaseMap 为 failure,则抛出一个
TypeError。
new SharedStorageClearMethod(options)
构造器步骤为:
-
令 context 为 null。
-
如果 globalObject 是一个
Window:-
将 context 设置为 globalObject 的浏览上下文。
-
-
否则:
-
将 context 设置为 globalObject 的 outside settings 的目标浏览 上下文。
-
如果对
SharedStorage的 关联SharedStorageWorkletGlobalScope运行 check whether addModule is finished 的结果为 false,则抛出一个TypeError。
-
-
如果 context 为 null,则抛出一个
TypeError。 -
令 databaseMap 为在给定 environment 和 environment 的源的情况下运行 obtain a shared storage bottle map 的结果。
-
如果 databaseMap 为 failure,则抛出一个
TypeError。
6. SharedStorage
接口
SharedStorage
接口暴露给 Window
和 SharedStorageWorklet。
允许设置和/或删除数据的方法同时暴露给 Window
和 SharedStorageWorklet,
尽管它们的实现可能会因其环境而异。这使得可以从多个上下文修改共享存储中的数据。
与此同时,用于发布操作以在 SharedStorageWorkletGlobalScope
内运行的方法(即 selectURL()
和 run()),
以及用于调用 addModule()
的 worklet
属性,仅暴露给 Window,
因为这些是 Window
与 SharedStorageWorklet
交互的手段。
另一方面,从共享存储数据库获取数据的方法仅暴露给 SharedStorageWorklet,
以便谨慎控制从数据库读取的数据流。唯一的例外
是 get()
暴露给 Window,
但仅当 determine if a navigable has fully
revoked network 算法的结果为 true 时才会成功。
注: determine if a navigable has fully
revoked network 算法确保 get()
仅对已成功解析对 disableUntrustedNetwork()
调用的围栏框架成功。
[Exposed =(Window ,SharedStorageWorklet )]interface {SharedStorage Promise <DOMString >get (DOMString );key Promise <any >set (DOMString ,key DOMString ,value optional SharedStorageSetMethodOptions = {});options Promise <any >append (DOMString ,key DOMString ,value optional SharedStorageModifierMethodOptions = {});options Promise <any >delete (DOMString ,key optional SharedStorageModifierMethodOptions = {});options Promise <any >clear (optional SharedStorageModifierMethodOptions = {});options Promise <any >batchUpdate (sequence <SharedStorageModifierMethod >,methods optional SharedStorageModifierMethodOptions = {}); [options Exposed =Window ]Promise <SharedStorageResponse >selectURL (DOMString ,name sequence <SharedStorageUrlWithMetadata >,urls optional SharedStorageRunOperationMethodOptions = {}); [options Exposed =Window ]Promise <any >run (DOMString ,name optional SharedStorageRunOperationMethodOptions = {}); [options Exposed =Window ]Promise <SharedStorageWorklet >createWorklet (USVString ,moduleURL optional SharedStorageWorkletOptions = {}); [options Exposed =Window ]readonly attribute SharedStorageWorklet ; [worklet Exposed =SharedStorageWorklet ]Promise <unsigned long >length (); [Exposed =SharedStorageWorklet ]Promise <double >remainingBudget (); [Exposed =SharedStorageWorklet ]async iterable <DOMString ,DOMString >; };dictionary {SharedStoragePrivateAggregationConfig USVString ;aggregationCoordinatorOrigin USVString ; [contextId EnforceRange ]unsigned long long ; [filteringIdMaxBytes EnforceRange ]unsigned long long ; };maxContributions dictionary {SharedStorageRunOperationMethodOptions object ;data boolean =resolveToConfig false ;boolean =keepAlive false ;SharedStoragePrivateAggregationConfig ;privateAggregationConfig DOMString ; };savedQuery dictionary :SharedStorageWorkletOptions WorkletOptions {USVString = "context-origin"; };dataOrigin
6.1. SharedStorage
上的运行操作方法
selectURL(name, urls, options)
方法步骤为:
6.2. 通过 SharedStorage
创建新的 worklet
createWorklet(moduleURL, options)
方法步骤为:
-
令 sharedStorageWorklet 为一个新的
SharedStorageWorklet。 -
如果 options 包含 "
dataOrigin", 则将 sharedStorageWorklet 的data origin 设置为 options["dataOrigin"]。 -
令 addModulePromise 为调用 sharedStorageWorklet.
addModule(moduleURL, options) 的结果。 -
令 resultPromise 为一个新的 promise。
-
当 addModulePromise 兑现时,将 resultPromise 解析为 sharedStorageWorklet。
-
返回 resultPromise。
6.3. BatchUpdate 方法
batchUpdate(methods, options)
方法步骤为:
-
令 promise 为一个新的 promise。
-
令 context 为 null。
-
如果 globalObject 是一个
Window:-
将 context 设置为 globalObject 的浏览上下文。
-
-
否则:
-
将 context 设置为 globalObject 的 outside settings 的目标浏览 上下文。
-
如果对
SharedStorage的 关联SharedStorageWorkletGlobalScope运行 check whether addModule is finished 的结果为 false,则返回一个以TypeError拒绝的 promise。
-
-
如果 context 为 null,则返回一个以
TypeError拒绝的 promise。 -
如果 context 的活动 window 的关联文档不是完全活动的,则返回一个以
TypeError拒绝的 promise。 -
对于 methods 中的每个 method:
-
-
返回一个以
TypeError拒绝的 promise。
注:
batchUpdate()作为事务性操作执行。为避免更细粒度锁定导致的潜在死锁,batchUpdate()内部的方法不能使用withLock选项。不是忽略此选项,而是抛出错误以 强制执行该限制并防止误用。 -
-
-
令 databaseMap 为在给定 environment 和 environment 的源的情况下,运行 obtain a shared storage bottle map 的结果。
-
如果 databaseMap 为 failure,则返回一个以
TypeError拒绝的 promise。 -
令 onLockGrantedCallback 为执行以下步骤的算法:
-
将以下步骤入队到 queue:
-
令 result 为使用 queue、 databaseMap、environment 和 methods 运行 batch update entries in the database 的结果。
-
如果 result 为 false,且如果 globalObject 是一个
SharedStorageWorkletGlobalScope:-
在DOM 操作任务 源上,给定 realm 的全局对象,排队一个全局任务以用
TypeError拒绝 promise。 -
中止这些步骤。
-
-
在DOM 操作任务 源上,给定 realm 的全局对象,排队一个全局任务以用 undefined 解析 promise。
-
-
-
如果 options["
withLock"] 存在,则在给定 environment 的源、options["withLock"]、 onLockGrantedCallback 的情况下,运行 handle callback within a shared storage lock。 -
否则,运行 onLockGrantedCallback。
-
返回 promise。
6.4. 设置器/删除器方法
set(key, value, options)
方法步骤为:
-
令 promise 为一个新的 promise。
-
令 context 为 null。
-
如果 globalObject 是一个
Window:-
将 context 设置为 globalObject 的浏览上下文。
-
-
否则:
-
将 context 设置为 globalObject 的 outside settings 的目标浏览 上下文。
-
如果对
SharedStorage的 关联SharedStorageWorkletGlobalScope运行 check whether addModule is finished 的结果为 false,则返回一个以TypeError拒绝的 promise。
-
-
如果 context 为 null,则返回一个以
TypeError拒绝的 promise。 -
如果 context 的活动 window 的关联文档不是完全活动的,则返回一个以
TypeError拒绝的 promise。 -
如果 key 的长度超过最大长度,则返回一个以
TypeError拒绝的 promise。 -
如果 value 的长度超过最大长度,则返回一个以
TypeError拒绝的 promise。 -
令 databaseMap 为在给定 environment 和 environment 的源的情况下,运行 obtain a shared storage bottle map 的结果。
-
如果 databaseMap 为 failure,则返回一个以
TypeError拒绝的 promise。 -
令 queue 为 context 的关联数据库的 shared storage database queue。
-
令 realm 为当前 Realm。
-
令 onLockGrantedCallback 为执行以下步骤的算法:
-
将以下步骤入队到 queue:
-
令 result 为使用 queue、databaseMap、 environment、key、value 和 options["
ignoreIfPresent"] 运行 set an entry in the database 的结果。 -
如果 result 为 false,且如果 globalObject 是一个
SharedStorageWorkletGlobalScope:-
在DOM 操作任务 源上,给定 realm 的全局对象,排队一个全局任务以用
TypeError拒绝 promise。 -
中止这些步骤。
-
-
在DOM 操作任务 源上,给定 realm 的全局对象,排队一个全局任务以用 undefined 解析 promise。
-
-
-
-
如果 options["
withLock"] 以 U+002D HYPHEN-MINUS (-) 开头,则返回一个以TypeError拒绝的 promise。 -
在给定 environment 的源、options["
withLock"]、 onLockGrantedCallback 的情况下,运行 handle callback within a shared storage lock。
-
-
否则,运行 onLockGrantedCallback。
-
返回 promise。
append(key, value, options)
方法步骤为:
-
令 promise 为一个新的 promise。
-
令 context 为 null。
-
如果 globalObject 是一个
Window:-
将 context 设置为 globalObject 的浏览上下文。
-
-
否则:
-
将 context 设置为 globalObject 的 outside settings 的目标浏览 上下文。
-
如果对
SharedStorage的 关联SharedStorageWorkletGlobalScope运行 check whether addModule is finished 的结果为 false,则返回一个以TypeError拒绝的 promise。
-
-
如果 context 为 null,则返回一个以
TypeError拒绝的 promise。 -
如果 context 的活动 window 的关联文档不是完全活动的,则返回一个以
TypeError拒绝的 promise。 -
如果 key 的长度超过最大长度,则返回一个以
TypeError拒绝的 promise。 -
如果 value 的长度超过最大长度,则返回一个以
TypeError拒绝的 promise。 -
令 databaseMap 为在给定 environment 和 environment 的源的情况下,运行 obtain a shared storage bottle map 的结果。
-
如果 databaseMap 为 failure,则返回一个以
TypeError拒绝的 promise。 -
令 queue 为 context 的关联数据库的 shared storage database queue。
-
令 realm 为当前 Realm。
-
令 onLockGrantedCallback 为执行以下步骤的算法:
-
将以下步骤入队到 queue:
-
令 result 为使用 queue、databaseMap、 environment、key 和 value 运行 append an entry in the database 的结果。
-
如果 result 为 false,且如果 globalObject 是一个
SharedStorageWorkletGlobalScope:-
在DOM 操作任务 源上,给定 realm 的全局对象,排队一个全局任务以用
TypeError拒绝 promise。 -
中止这些步骤。
-
-
在DOM 操作任务 源上,给定 realm 的全局对象,排队一个全局任务以用 undefined 解析 promise。
-
-
-
-
如果 options["
withLock"] 以 U+002D HYPHEN-MINUS (-) 开头,则返回一个以TypeError拒绝的 promise。 -
在给定 environment 的源、options["
withLock"]、 onLockGrantedCallback 的情况下,运行 handle callback within a shared storage lock。
-
-
否则,运行 onLockGrantedCallback。
-
返回 promise。
delete(key, options) 方法步骤
为:
-
令 promise 为一个新的 promise。
-
令 context 为 null。
-
如果 globalObject 是一个
Window:-
将 context 设置为 globalObject 的浏览上下文。
-
-
否则:
-
将 context 设置为 globalObject 的 outside settings 的目标浏览 上下文。
-
如果对
SharedStorage的 关联SharedStorageWorkletGlobalScope运行 check whether addModule is finished 的结果为 false,则返回一个以TypeError拒绝的 promise。
-
-
如果 context 为 null,则返回一个以
TypeError拒绝的 promise。 -
如果 context 的活动 window 的关联文档不是完全活动的,则返回一个以
TypeError拒绝的 promise。 -
如果 key 的长度超过最大长度,则返回一个以
TypeError拒绝的 promise。 -
令 databaseMap 为在给定 environment 和 environment 的源的情况下,运行 obtain a shared storage bottle map 的结果。
-
如果 databaseMap 为 failure,则返回一个以
TypeError拒绝的 promise。 -
令 queue 为 context 的关联数据库的 shared storage database queue。
-
令 realm 为当前 Realm。
-
令 onLockGrantedCallback 为执行以下步骤的算法:
-
将以下步骤入队到 queue:
-
令 result 为使用 queue、 databaseMap 和 key 运行 delete an entry from the database 的结果。
-
如果 result 为 false,且如果 globalObject 是一个
SharedStorageWorkletGlobalScope:-
在DOM 操作任务 源上,给定 realm 的全局对象,排队一个全局任务以用
TypeError拒绝 promise。 -
中止这些步骤。
-
-
在DOM 操作任务 源上,给定 realm 的全局对象,排队一个全局任务以用 undefined 解析 promise。
-
-
-
-
如果 options["
withLock"] 以 U+002D HYPHEN-MINUS (-) 开头,则返回一个以TypeError拒绝的 promise。 -
在给定 environment 的源、options["
withLock"]、 onLockGrantedCallback 的情况下,运行 handle callback within a shared storage lock。
-
-
否则,运行 onLockGrantedCallback。
-
返回 promise。
clear(options) 方法步骤为:
-
令 promise 为一个新的 promise。
-
令 context 为 null。
-
如果 globalObject 是一个
Window:-
将 context 设置为 globalObject 的浏览上下文。
-
-
否则:
-
将 context 设置为 globalObject 的 outside settings 的目标浏览 上下文。
-
如果对
SharedStorage的 关联SharedStorageWorkletGlobalScope运行 check whether addModule is finished 的结果为 false,则返回一个以TypeError拒绝的 promise。
-
-
如果 context 为 null,则返回一个以
TypeError拒绝的 promise。 -
如果 context 的活动 window 的关联文档不是完全活动的,则返回一个以
TypeError拒绝的 promise。 -
令 databaseMap 为在给定 environment 和 environment 的源的情况下,运行 obtain a shared storage bottle map 的结果。
-
如果 databaseMap 为 failure,则返回一个以
TypeError拒绝的 promise。 -
令 queue 为 context 的关联数据库的 shared storage database queue。
-
令 realm 为当前 Realm。
-
令 onLockGrantedCallback 为执行以下步骤的算法:
-
将以下步骤入队到 queue:
-
令 result 为使用 queue 和 databaseMap 运行 clear all entries in the database 的结果。
-
如果 result 为 false,且如果 globalObject 是一个
SharedStorageWorkletGlobalScope:-
在DOM 操作任务 源上,给定 realm 的全局对象,排队一个全局任务以用
TypeError拒绝 promise。 -
中止这些步骤。
-
-
在DOM 操作任务 源上,给定 realm 的全局对象,排队一个全局任务以用 undefined 解析 promise。
-
-
-
-
如果 options["
withLock"] 以 U+002D HYPHEN-MINUS (-) 开头,则返回一个以TypeError拒绝的 promise。 -
在给定 environment 的源、options["
withLock"]、 onLockGrantedCallback 的情况下,运行 handle callback within a shared storage lock。
-
-
否则,运行 onLockGrantedCallback。
-
返回 promise。
6.5. Getter 方法
get(key) 方法步骤为:
-
令 promise 为一个新的 promise。
-
令 context 为 null。
-
令 environment 为 null。
-
如果 globalObject 是一个
Window:-
将 context 设置为 globalObject 的浏览上下文。
-
如果 context 为 null,则返回一个以
TypeError拒绝的 promise。 -
令 allowedInOpaqueOriginContext 为 false。
-
如果在给定 environment、 environment 的源和 allowedInOpaqueOriginContext 的情况下运行 determine whether shared storage is allowed by context 的结果为 false,则返回一个以
TypeError拒绝的 promise。 -
如果在给定 environment 和 environment 的源的情况下运行 check if user preference setting allows access to shared storage 的结果为 false,则返回一个以
OperationError拒绝的 promise。 -
令 document 为 context 的活动文档。
-
如果在 "fenced-unpartitioned-storage-read"、 document 和 environment 的源上运行 Is feature enabled in document for origin? 的结果为 false,则返回一个以
OperationError拒绝的 promise。 -
令 navigable 为 document 的节点 navigable。
-
如果在给定 navigable 的情况下运行 determine if a navigable has fully revoked network 的结果为 false,则返回一个以
OperationError拒绝的 promise。
-
-
否则: 1 如果对
SharedStorage的 关联SharedStorageWorkletGlobalScope运行 check whether addModule is finished 的结果为 false,则返回一个以TypeError拒绝的 promise。-
将 context 设置为
SharedStorage的SharedStorageWorkletGlobalScope的 outside settings 的目标浏览 上下文。 -
如果 context 为 null,则返回一个以
TypeError拒绝的 promise。
-
-
如果 key 的长度超过最大长度,则返回一个以
TypeError拒绝的 promise。 -
如果 context 的活动 window 的关联文档不是完全活动的,则返回一个以
TypeError拒绝的 promise。 -
令 realm 为当前 Realm。
-
令 databaseMap 为在给定 environment 和 realm 的设置对象的源的情况下,运行 obtain a shared storage bottle map 的结果。
-
如果 databaseMap 为 failure,则返回一个以
TypeError拒绝的 promise。 -
令 queue 为 context 的关联数据库的 shared storage database queue。
-
将以下步骤入队到 queue:
-
返回 promise。
length() 方法步骤为:
-
令 promise 为一个新的 promise。
-
如果对
SharedStorage的 关联SharedStorageWorkletGlobalScope运行 check whether addModule is finished 的结果为 false,则返回一个以TypeError拒绝的 promise。 -
令 context 为
SharedStorage的SharedStorageWorkletGlobalScope的 outside settings 的目标浏览上下文。 -
如果 context 为 null,则返回一个以
TypeError拒绝的 promise。 -
如果 context 的活动 window 的关联文档不是完全活动的,则返回一个以
TypeError拒绝的 promise。 -
令 realm 为当前 Realm。
-
令 databaseMap 为在给定 environment 和 realm 的设置对象的源的情况下,运行 obtain a shared storage bottle map 的结果。
-
如果 databaseMap 为 failure,则返回一个以
TypeError拒绝的 promise。 -
令 queue 为 context 的关联数据库的 shared storage database queue。
-
将以下步骤入队到 queue:
-
返回 promise。
remainingBudget() 方法步骤为:
-
令 promise 为一个新的 promise。
-
如果对
SharedStorage的 关联SharedStorageWorkletGlobalScope运行 check whether addModule is finished 的结果为 false,则返回一个以TypeError拒绝的 promise。 -
令 context 为
SharedStorage的SharedStorageWorkletGlobalScope的 outside settings 的目标浏览上下文。 -
如果 context 为 null,则返回一个以
TypeError拒绝的 promise。 -
如果 context 的活动 window 的关联文档不是完全活动的,则返回一个以
TypeError拒绝的 promise。 -
令 realm 为当前 Realm。
-
令 allowedInOpaqueOriginContext 为 false。
-
如果在给定 environment、realm 的设置对象的源和 allowedInOpaqueOriginContext 的情况下运行 determine whether shared storage is allowed by context 的结果为 false,则返回一个以
TypeError拒绝的 promise。 -
如果在给定 environment 和 realm 的设置对象的源的情况下运行 check if user preference setting allows access to shared storage 的结果为 false,则返回一个以
TypeError拒绝的 promise。 -
令 site 为使用 realm 的设置对象的源运行 obtain a site 的结果。
-
令 queue 为 context 的关联数据库的 shared storage database queue。
-
将以下步骤入队到 queue:
-
返回 promise。
6.6. 迭代
每个 SharedStorage
异步迭代器实例都有一个由条目组成的队列 pending entries,初始为
空。
每个 SharedStorage
异步迭代器实例还都有一个 boolean
error,初始为 false。
下面定义的 asynchronous iterator initialization steps 和 get the next iteration result 算法对应于 Web IDL 标准中称为 asynchronous iterator initialization steps 和 get the next iteration result 的算法。
SharedStorage
异步迭代器 iterator 的
asynchronous iterator
initialization steps 为:
-
令 promise 为一个新的 promise。
-
如果对
SharedStorage的 关联SharedStorageWorkletGlobalScope运行 check whether addModule is finished 的结果为 false,则返回一个以TypeError拒绝的 promise。 -
令 context 为
SharedStorage的SharedStorageWorkletGlobalScope的 outside settings 的目标浏览上下文。 -
如果 context 为 null,则返回一个以
TypeError拒绝的 promise。 -
如果 context 的活动 window 的关联文档不是完全活动的,则返回一个以
TypeError拒绝的 promise。 -
令 realm 为当前 Realm。
-
令 databaseMap 为在给定 environment 和 realm 的设置对象的源的情况下,运行 obtain a shared storage bottle map 的结果。
-
如果 databaseMap 为 failure,则返回一个以
TypeError拒绝的 promise。 -
令 queue 为 context 的关联数据库的 shared storage database queue。
-
将以下步骤入队到 queue:
-
当 promise 兑现时,运行以下步骤:
-
令 promiseEntries 为 promise 的值。
-
对于每个 promiseEntries 中的条目 entry,将 entry 入队到 iterator 的pending entries。
-
SharedStorage
的
异步迭代器 iterator 的情况下,get the next iteration result,运行以下步骤:
-
令 promise 为一个新的 promise。
-
-
如果 iterator 的error 为 true,则返回一个以
TypeError拒绝的 promise。 -
如果 iterator 的pending entries 为空:
-
创建一个对象 doneObject。
-
在DOM 操作任务 源上,给定 realm 的全局对象,排队一个全局任务以用 doneObject 解析 promise。
-
中止这些步骤。
-
-
否则,令 entry 为从 iterator 的pending entries出队的结果。
-
-
返回 promise。
7. 通过 HTTP 响应标头触发操作
虽然设置器和删除器操作(例如 set()、
append()、
delete()、
clear())
可以通过上述用于 Window
或 SharedStorageWorkletGlobalScope
的 API 发起,但设置器/删除器操作也可以通过 HTTP 响应标头触发。
这将需要对 HTML 和 Fetch 规范进行猴子补丁。
8. HTML 猴子补丁
8.1. sharedStorageWritable
和
sharedstoragewritable
属性
定义以下接口 mixin,并将其包含到 HTMLIFrameElement
和 HTMLImageElement
的 IDL 接口中:
interface mixin { [HTMLSharedStorageWritableElementUtils CEReactions ,SecureContext ]attribute boolean ; };sharedStorageWritable HTMLIFrameElement includes HTMLSharedStorageWritableElementUtils ;HTMLImageElement includes HTMLSharedStorageWritableElementUtils ;
添加以下布尔内容属性:
-
iframe -
sharedstoragewritable -
img -
sharedstoragewritable
IDL 属性 sharedStorageWritable
必须反映相应的同名内容属性。
8.2. HTML 算法修改
8.2.1. 对 Update the image data 算法的修改
在以下步骤之后
将 request 的优先级设置为当前状态...
添加步骤
-
如果元素存在
sharedstoragewritable属性,则将 request 的shared storage writable 设置为 true。
8.2.2. 对 Create navigation params by fetching 算法的修改
在以下步骤之后
令 request 为一个新的请求,其中 ...
添加步骤
-
如果 navigable 的容器是一个
iframe元素,并且如果它具有sharedstoragewritable内容属性,则将 request 的shared storage writable 设置为 true。
9. Fetch 猴子补丁
9.1. sharedStorageWritable
键
请求具有一个关联的布尔值 shared storage writable。除非另有说明,否则它为 false。
RequestInit
字典包含一个 sharedStorageWritable
键:
partial dictionary RequestInit {boolean ; };sharedStorageWritable
9.2. Fetch 算法修改
9.2.1. 对 Request Constructor 算法的修改
在以下步骤之前
将 this 的请求设置为 request。
添加步骤
-
如果 init["
sharedStorageWritable"] 存在,则将 request 的shared storage writable 设置为它。
9.2.2. 对 HTTP network or cache fetch 算法的修改
9.2.3. 对 HTTP fetch 算法的修改
在以下步骤之前
添加步骤
-
如果 request 的目标为 "sharedstorageworklet":
-
令 dataOriginValue 为从 request 的标头列表获取 `
Sec-Shared-Storage-Data-Origin` 的结果。 -
如果 dataOriginValue 不是 null,则:
-
令 dataOriginUrl 为在 dataOriginValue 上运行 URL 解析器的结果。
-
断言 dataOriginUrl 不是 failure。
-
令 allowed 为 true。
-
如果 dataOriginUrl 的源和 request 的URL的源是同源的:
-
令 responseHeaders 为 internalResponse 的标头列表。
-
令 allowed 为在给定 `
Shared-Storage-Cross-Origin-Worklet-Allowed`、 "item" 和 responseHeaders 作为输入的情况下运行 get a structured field value 算法的结果。
-
-
如果 allowed 为 false,则返回一个网络错误。
-
-
-
在给定响应 internalResponse 和请求 request 作为输入的情况下,Handle a Shared-Storage-Write response。
9.3. 共享存储 HTTP 标头
9.3.1.
`Sec-Shared-Storage-Data-Origin`
请求标头
本规范定义了一个 Sec-Shared-Storage-Data-Origin HTTP 请求标头。
`Sec-Shared-Storage-Data-Origin`
请求标头的值是一个字符串。
当
`Sec-Shared-Storage-Data-Origin`
在 fetch a worklet/module worker script
graph 算法期间发送时,其值
被设置为拥有该 worklet 的共享存储数据的源的序列化形式。
9.3.2.
`Shared-Storage-Cross-Origin-Worklet-Allowed`
响应标头
本规范定义了一个 Shared-Storage-Cross-Origin-Worklet-Allowed HTTP 响应标头。
`Shared-Storage-Cross-Origin-Worklet-Allowed`
响应标头是一个结构化标头,其值必须是一个布尔值。
当一个响应具有
`Shared-Storage-Cross-Origin-Worklet-Allowed`
且值为 true 时,worklet 脚本的服务器已授权跨源站点使用来自 worklet 脚本源的共享存储数据来创建
worklet。
9.3.3.
`Sec-Shared-Storage-Writable`
请求标头
本规范定义了一个 Sec-Shared-Storage-Writable HTTP 请求标头。
`Sec-Shared-Storage-Writable`
请求标头是一个结构化标头,其值必须是一个布尔值。
当一个请求将
`Sec-Shared-Storage-Writable`
设置为 true 时,其响应将能够写入共享存储。
9.3.4.
`Shared-Storage-Write`
响应标头
本规范定义了一个 Shared-Storage-Write HTTP 响应标头。
`Shared-Storage-Write`
响应标头是一个结构化标头,其值必须是一个列表。定义了以下列表
成员。持有相同字符序列的Token 和字符串
被视为等价。还允许表示UTF-8 编码字节的字节序列,以便通过 HTTP
标头提供写入和删除非 ASCII Unicode 键和值的功能。
未知的列表成员,包括既不是字符串也不是字节序列的类型, 会被跳过,列表的其余部分会像它们不存在一样被处理。如果成员缺少必需的参数,或这些参数具有意外类型,也会被跳过。
-
set -
append -
delete -
clear
注: 我们允许字节序列以便 容纳 Unicode 键和值。任何字节序列都将被 假定为UTF-8 编码,否则将解析失败。
添加示例。
9.4. 共享存储 Fetch 相关算法
-
令 window 为 request 的window。
-
令 allowedInOpaqueOriginContext 为 true。
-
如果在给定 window、request 的当前 URL的源和 allowedInOpaqueOriginContext 的情况下运行 determine whether shared storage is allowed by context 的结果为 false,则返回 false。
-
如果在给定 window 和 request 的当前 URL的源的情况下运行 check if user preference setting allows access to shared storage 的结果为 false,则返回 false。
determine whether a request can currently use shared storage 算法需要考虑“选择加入特性”, 如 https://github.com/w3c/webappsec-permissions-policy/pull/499 中所阐述。
-
如果 request 的shared storage writable 不是 true, 则返回。
注: 在重定向时, request 的shared storage writable 可能为 true, 但重定向可能没有使用共享存储的权限,从而使对 request 运行 determine whether a request can currently use shared storage 的结果为 false。
-
如果对 request 运行 determine whether a request can currently use shared storage 的结果为 false,则从 request 的标头列表删除 `
Sec-Shared-Storage-Writable`。 -
否则,在 request 的标头列表中设置结构化字段值 (`
Sec-Shared-Storage-Writable`, true)。
-
令 sharedStorageWritable 为在给定 `
Sec-Shared-Storage-Writable`、 "item" 和 request 的标头列表作为输入的情况下运行 get a structured field value 算法的结果。 -
如果 sharedStorageWritable 为 null,或者 sharedStorageWritable 不是一个布尔值,或者 sharedStorageWritable 的值为 false,则返回。
-
令 window 为 request 的window。
-
令 sharedStorage 为 window 的全局对象的
sharedStorage。 -
如果 sharedStorage 为 null,则返回。
-
令 list 为 response 的标头列表。
-
令 operationsToParse 为在给定 `
Shared-Storage-Write`、 "list" 和 list 作为输入的情况下运行 get a structured field value 算法的结果。 -
如果 operationsToParse 为 null 或空,则 返回。
-
令 methods 为空列表。
-
令 batchWithLock 为 null。
-
对于 operationsToParse 中的每个元组(item, parameters),执行 以下步骤:
-
如果 item 是一个内部列表,则继续。
-
令 methodOrOptionsString 为对 item 运行 get the string value 的结果。
-
如果 methodOrOptionsString 为 failure,则继续。
-
对 methodOrOptionsString 进行切换:
- 如果 methodOrOptionsString 为 "
clear": -
执行以下步骤:
-
令 options 为一个新的
SharedStorageModifierMethodOptions。 -
令 withLock 为使用 parameters 和 "
with_lock" 运行 obtain a string-like parameter value 的结果。 -
如果 withLock 不是 null,且 withLock 不以 U+002D HYPHEN-MINUS (-) 开头,则将 options["
withLock"] 设置为 withLock。 -
令 method 为 new
SharedStorageClearMethod(options)。 -
如果抛出了异常, 则继续。
-
将 method 附加到 methods。
-
继续。
-
- 如果 methodOrOptionsString 为 "
delete": -
执行以下步骤:
-
令 key 为使用 parameters 和 "
key" 运行 obtain a string-like parameter value 的结果。 -
如果 key 为 null,则继续。
-
令 options 为一个新的
SharedStorageModifierMethodOptions。 -
令 withLock 为使用 parameters 和 "
with_lock" 运行 obtain a string-like parameter value 的结果。 -
如果 withLock 不是 null,且 withLock 不以 U+002D HYPHEN-MINUS (-) 开头,则将 options["
withLock"] 设置为 withLock。 -
令 method 为 new
SharedStorageDeleteMethod(key, options)。 -
如果抛出了异常, 则继续。
-
将 method 附加到 methods。
-
继续。
-
- 如果 methodOrOptionsString 为 "
append": -
执行以下步骤:
-
令 key 为使用 parameters 和 "
key" 运行 obtain a string-like parameter value 的结果。 -
如果 key 为 null,则继续。
-
令 value 为使用 parameters 和 "
value" 运行 obtain a string-like parameter value 的结果。 -
如果 value 为 null,则继续。
-
令 options 为一个新的
SharedStorageModifierMethodOptions。 -
令 withLock 为使用 parameters 和 "
with_lock" 运行 obtain a string-like parameter value 的结果。 -
如果 withLock 不是 null,且 withLock 不以 U+002D HYPHEN-MINUS (-) 开头,则将 options["
withLock"] 设置为 withLock。 -
令 method 为 new
SharedStorageAppendMethod(key, value, options)。 -
如果抛出了异常, 则继续。
-
将 method 附加到 methods。
-
继续。
-
- 如果 methodOrOptionsString 为 "
set": -
执行以下步骤:
-
令 key 为使用 parameters 和 "
key" 运行 obtain a string-like parameter value 的结果。 -
如果 key 为 null,则继续。
-
令 value 为使用 parameters 和 "
value" 运行 obtain a string-like parameter value 的结果。 -
如果 value 为 null,则继续。
-
令 options 为一个新的
SharedStorageSetMethodOptions。 -
如果使用 parameters 和 "
ignore_if_present" 运行 obtain a boolean parameter value 的结果为 true,则将 options["ignoreIfPresent"] 设置为 true。 -
令 withLock 为使用 parameters 和 "
with_lock" 运行 obtain a string-like parameter value 的结果。 -
如果 withLock 不是 null,且 withLock 不以 U+002D HYPHEN-MINUS (-) 开头,则将 options["
withLock"] 设置为 withLock。 -
令 method 为 new
SharedStorageSetMethod(key, value, options)。 -
如果抛出了异常, 则继续。
-
将 method 附加到 methods。
-
继续。
-
- 如果 methodOrOptionsString 为 "
options": -
执行以下步骤:
-
将 batchWithLock 设置为使用 parameters 和 "
with_lock" 运行 obtain a string-like parameter value 的结果。 -
继续。
-
- 如果 methodOrOptionsString 是其他任何内容:
- 继续。
- 如果 methodOrOptionsString 为 "
-
-
令 batchOptions 为一个新的
SharedStorageModifierMethodOptions。 -
如果 batchWithLock 不是 null,且 batchWithLock 不以 U+002D HYPHEN-MINUS (-) 开头,则将 batchOptions["
withLock"] 设置为 batchWithLock。 -
运行 sharedStorage.
batchUpdate(methods, batchOptions)。
-
如果 parameters 不包含 paramKey,则返回 null。
-
如果对 parameters[paramKey] 运行 check if string-like 的结果为 false,则返回 null。
-
返回为 parameters[paramKey] 运行 get the string value 的结果。
10. Web Locks 集成
10.1. 用户代理关联状态
shared storage lock managers map 是从源到锁管理器的映射。 它初始为空。
用户 代理具有一个关联的shared storage lock managers map。
注: 类似于其数据分区,共享存储具有自己的锁管理作用域, 独立于 Storage Buckets API。这些 web locks 不会与通过现有旧版 Web Locks API 从 Window 或 Worker 创建的 web locks 交互。
10.2. SharedStorageWorkletNavigator
接口
[Exposed =SharedStorageWorklet ]interface {};SharedStorageWorkletNavigator
10.3. Web Locks IDL 猴子补丁
将 NavigatorLocks
mixin 包含到 SharedStorageWorkletNavigator
中(即,让 SharedStorageWorkletNavigator
包含一个 LockManager
实例):
SharedStorageWorkletNavigator includes NavigatorLocks ;
LockManager
和 Lock 额外暴露给
SharedStorageWorklet:
[SecureContext ,Exposed =(Window ,Worker ,SharedStorageWorklet )]interface {};LockManager
[SecureContext ,Exposed =(Window ,Worker ,SharedStorageWorklet )]interface {};Lock
10.4. 对 lock manager 描述的猴子补丁
在定义 lock manager 的段落末尾添加以下句子: "此外,每个用户代理都包含一个shared storage lock managers map,用于 Web Locks API 与 Shared Storage API 的集成。"
10.5. 对 locks getter 步骤的猴子补丁
locks getter steps 应更新为以下步骤:
-
如果 globalObject 是一个
SharedStorageWorkletGlobalScope:-
如果 globalObject 的addModule success 为 false,则抛出一个
TypeError。
-
-
返回 this 的相关设置对象的
LockManager对象
10.6. 对 "obtain a lock manager" 算法的猴子补丁
应在 obtain a lock manager 算法前置以下步骤:
-
如果当前 Realm的全局对象是一个
SharedStorageWorkletGlobalScope:-
令 workletDataOrigin 为 environment 的源。
-
返回 shared storage lock managers map[workletDataOrigin]。
-
10.7. "Handle callback within a shared storage lock" 算法
-
令 lockManager 为 shared storage lock managers map[workletDataOrigin]。
-
令 promise 为一个新的 promise。
-
令 defaultOptions 为一个新的
LockOptions。 -
使用 promise、当前agent、environment 的id、lockManager、callback、 name、defaultOptions["
mode"]、 defaultOptions["ifAvailable"]、 defaultOptions["steal"]、 defaultOptions["signal"] 请求一个锁。
注: 使用默认的 LockOptions
时,
callback 最终会在锁被授予时被调用(即,锁请求不会失败)。
11. Permissions Policy 集成
本规范定义了三个策略控制特性,由以下字符串标识:
shared-storage" 门控对 Shared Storage 的一般访问。
"shared-storage-select-url" 为 selectURL()
增加一层额外权限
"fenced-unpartitioned-storage-read" 为
get()
增加一层额外权限,以确保它只有在从 Window
调用,且从 disableUntrustedNetwork()
返回的 Promise
已解析时,才能成功被调用。
对于这些特性中的每一个,默认允许列表都是 *。
12. Clear Site Data 集成
添加 Clear Site Data 集成的细节。13. 隐私考量
Shared Storage API 试图提供一种将跨站点数据用于一系列用例的能力,
其方式相比使用第三方 cookie 更能保护用户隐私。共享存储的主要隐私
保障是,对存储在其存储中的数据的读取访问只能在嵌入者的 SharedStorageWorklet
内发生。明确定义的限制将从 SharedStorageWorklet
输出的数据限制到最低限度。
特别是,嵌入者可以基于其共享存储中的数据,从一个简短的URL 列表中选择一个
URL,
然后在围栏框架中显示结果。除非通过将在长期内得到更好缓解的特定机制,
否则嵌入者将无法知道选择了哪个 URL。
目前,每当用户点击围栏框架以发起顶级可遍历导航,和/或围栏框架调用 reportEvent()
API 时,都可能泄漏少量熵。
嵌入者还能够通过私有聚合 API 发送可聚合报告,该 API 为实现差分隐私而添加噪声, 使用时间延迟来发送报告,对发送的报告数量施加限制,并将报告处理为聚合数据,从而保护个人隐私。