1. Introduction
This section is not normative.In order to prevent cross-site user tracking, browsers are partitioning all forms of storage by top-level traversable site; see Client-Side Storage Partitioning . But, there are many legitimate use cases currently relying on unpartitioned storage.
This
document
introduces
a
new
storage
API
that
is
intentionally
not
partitioned
by
top-level
traversable
site
(though
still
partitioned
by
context
origin),
in
order
to
serve
a
number
of
the
use
cases
needing
unpartitioned
storage.
To
limit
cross-site
reidentification
of
users,
data
in
Shared
Storage
may
only
be
read
in
two
restricted
environments.
One
such
environment
is
called
a
worklet,
and
any
output
from
the
worklet
is
in
the
form
of
a
fenced
frame
or
a
Private
Aggregation
report.
Over
time,
there
may
be
additional
worklet
output
gates
included
in
the
standard.
The
other
restricted
environment
is
within
a
fenced
frame
’s
content
after
it
resolves
a
call
to
disableUntrustedNetwork()
,
which
prevents
the
read
data
from
being
shared
outside
the
frame.
a.example
randomly
assigns
users
to
groups
in
a
way
that
is
consistent
cross-site.
Inside
an
a.example
iframe:
function generateSeed() { …} await window. sharedStorage. worklet. addModule( 'experiment.js' ); // Only write a cross-site seed to a.example’s storage if there isn’t one yet. 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' } } ); // Assumes that the fenced frame 'my-fenced-frame' has already been attached. document. getElementById( 'my-fenced-frame' ). config= fencedFrameConfig;
inside
the
experiment.js
worklet
script:
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.
The
SharedStorageWorklet
Interface
The
SharedStorageWorklet
object
allows
developers
to
supply
module
scripts
to
process
Shared
Storage
data
and
then
output
the
result
through
one
or
more
of
the
output
gates.
Currently
there
are
two
output
gates,
the
Private
Aggregation
output
gate
and
the
URL-selection
output
gate.
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
Each
SharedStorageWorklet
has
an
associated
boolean
addModule
initiated
,
initialized
to
false.
Each
SharedStorageWorklet
has
an
associated
USVString
data
origin
,
initialized
to
"context-origin"
.
Each
SharedStorageWorklet
has
an
associated
boolean
has
cross-origin
data
origin
,
initialized
to
false.
Because
adding
multiple
module
scripts
via
addModule()
for
the
same
SharedStorageWorklet
would
give
the
caller
the
ability
to
store
data
from
Shared
Storage
in
global
variables
defined
in
the
module
scripts
and
then
exfiltrate
the
data
through
later
call(s)
to
addModule()
,
each
SharedStorageWorklet
can
only
call
addModule()
once.
The
addModule
initiated
boolean
makes
it
possible
to
enforce
this
restriction.
When
addModule()
is
called
for
a
worklet,
it
will
run
check
if
addModule
is
allowed
and
update
state
,
and
if
the
result
is
"DisallowedDueToNonPreferenceError",
or
if
the
result
is
"DisallowedDueToPreferenceError"
and
the
worklet’s
has
cross-origin
data
origin
is
false,
it
will
cause
addModule()
to
fail,
as
detailed
in
the
§ 2.2.6
Monkey
Patch
for
addModule()
.
-
Using values available in environment and origin as needed, perform an implementation-defined algorithm to return either true or false.
-
If environment is not a secure context , then return false.
-
If allowedInOpaqueOriginContext is false and environment ’s origin is an opaque origin , then return false.
-
If origin is an opaque origin , then return false.
-
Let globalObject be the current realm ’s global object .
-
Assert : globalObject is a
Window
or aSharedStorageWorkletGlobalScope
. -
If globalObject is a
Window
, and if the result of running Is feature enabled in document for origin? on " shared-storage ", globalObject ’s associated document , and origin returns false, then return false. -
If the result of running obtain a site with origin is not enrolled , then return false.
-
Return true.
-
For creating a worklet, environment is the environment settings object associated with the
Window
that created the worklet, and origin is the module script url’s origin . -
For running operations on a worklet (from a
Window
), environment is the environment settings object associated with theWindow
that created the worklet, and origin is the worklet’s global scopes [0]'s realm ’s settings object ’s origin . -
For § 6.4 Setter/Deleter Methods , environment is either the current context (when called from a
Window
) or the environment settings object associated with theWindow
that created the worklet (when called from aSharedStorageWorkletGlobalScope
), and origin is environment ’s origin . -
For
get()
invoked from aWindow
(which can only succeed in a fenced frame ), environment is the current context, and origin is environment ’s origin . -
For § 9.4 Shared Storage Fetch-Related Algorithms , environment is the request’s window , and origin is the request’s current URL ’s origin .
-
For § 9.4 Shared Storage Fetch-Related Algorithms , for
createWorklet()
called with a cross-origin worklet script using the dataOrigin option with value"script-origin"
(which would result in a worklet where has cross-origin data origin is true), and forselectURL()
andrun()
that operate on a worklet where has cross-origin data origin is true, allowedInOpaqueOriginContext is true. For other methods, allowedInOpaqueOriginContext is false.
SharedStorageWorklet
worklet
and
a
URL
moduleURLRecord
,
run
the
following
steps:
-
If worklet ’s addModule initiated is true, return "DisallowedDueToNonPreferenceError".
-
Set worklet ’s addModule initiated to true.
-
Let workletDataOrigin be the current settings object ’s origin .
-
If worklet ’s data origin is
"script-origin"
, set workletDataOrigin to moduleURLRecord ’s origin . -
Otherwise, if worklet ’s data origin is not
"context-origin"
:-
Let customOriginUrl be the result of running a URL parser on worklet ’s data origin .
-
If customOriginUrl is not a valid URL , return "DisallowedDueToNonPreferenceError".
-
Set workletDataOrigin to customOriginUrl ’s origin .
-
-
Let hasCrossOriginDataOrigin be false.
-
If workletDataOrigin and the current settings object ’s origin are not same origin , then set hasCrossOriginDataOrigin to true.
-
Let allowedInOpaqueOriginContext be hasCrossOriginDataOrigin .
-
If the result of running determine whether shared storage is allowed by context given the current settings object , workletDataOrigin , and allowedInOpaqueOriginContext is false, return "DisallowedDueToNonPreferenceError".
-
Set worklet ’s has cross-origin data origin to hasCrossOriginDataOrigin .
-
If the result of running check if user preference setting allows access to shared storage given the current settings object and workletDataOrigin is false, return "DisallowedDueToPreferenceError".
-
Return "Allowed".
Moreover,
each
SharedStorageWorklet
’s
list
of
global
scopes
,
initially
empty,
can
contain
at
most
one
instance
of
its
worklet
global
scope
type
,
the
SharedStorageWorkletGlobalScope
.
2.1.
Run
Operation
Methods
on
SharedStorageWorklet
SharedStorageWorklet
worklet
,
DOMString
operationName
,
list
of
strings
urlList
,
an
origin
workletDataOrigin
,
a
navigable
navigable
,
SharedStorageRunOperationMethodOptions
options
,
a
pre-specified
report
parameters
or
null
preSpecifiedParams
and
an
aggregation
coordinator
or
null
aggregationCoordinator
,
run
the
following
steps.
This
algorithm
will
return
a
tuple
consisting
of
a
promise
that
resolves
into
an
unsigned
long
whose
value
is
the
index
of
the
URL
selected
from
urlList
and
a
boolean
indicating
whether
the
top-level
traversable’s
budgets
should
be
charged
.
-
Let promise be a new promise .
-
Let window be worklet ’s relevant settings object .
-
If window ’s browsing context is null, then return the tuple of a ( promise rejected with a
TypeError
, true). -
If window ’s associated document is not fully active , return the tuple of a ( promise rejected with a
TypeError
, true). -
Assert : worklet ’s global scopes ’s size is 1.
-
Let globalScope be worklet ’s global scopes [0].
-
Let moduleMapKeyTuples be the result of running get the keys on globalScope ’s relevant settings object ’s module map .
-
Let moduleURLRecord be moduleMapKeyTuples [0][0].
-
Let savedQueryName be options ["
savedQuery
"]. -
If savedQueryName is a string that is not the empty string, then:
-
Let callbackTask be the result of running obtain a callback to process the saved index result , given window , urlList , and promise .
-
Let savedIndex be the result of running get the index for a saved query on navigable , workletDataOrigin , moduleURLRecord , operationName , savedQueryName , and callbackTask .
-
If savedIndex is "pending callback", then return the tuple ( promise , false).
Note: callbackTask is now stored to be run when a previously obtained worklet agent completes its operation to select the index for this query. When the steps of callbackTask are run, promise will be resolved.
-
If savedIndex is an
unsigned long
, then:-
Queue a global task on the DOM manipulation task source , given window , to run the steps of callbackTask , given savedIndex .
Note: Running the steps of callbackTask will resolve promise .
-
Return the tuple ( promise , false).
-
-
Assert that savedIndex is "pending current operation".
-
-
Queue a task on globalScope ’s worklet event loop to perform the following steps:
-
Let operationMap be globalScope ’s operation map .
-
If operationMap does not contain operationName , then queue a global task on the DOM manipulation task source , given window , to reject promise with a
TypeError
, and abort these steps.Note: This could happen if
register()
was never called with operationName . -
Assert : operationMap [ operationName ]'s associated realm is this ’s relevant realm .
-
Let operation be operationMap [ operationName ], converted to
RunFunctionForSharedStorageSelectURLOperation
. -
Let privateAggregationCompletionTask be the result of setting up the Private Aggregation scopes given workletDataOrigin , preSpecifiedParams and aggregationCoordinator .
-
Let argumentsList be the list « urlList ».
-
Let indexPromise be the result of invoking operation with argumentsList .
-
React to indexPromise :
- If it was fulfilled with value index :
-
-
If index is greater than urlList ’s size , then:
-
If savedQueryName is a string that is not the empty string, then run store the index for a saved query with window , navigable , workletDataOrigin , moduleURLRecord , operationName , savedQueryName , and the default selectURL index .
-
Queue a global task on the DOM manipulation task source , given window , to reject promise with a
TypeError
, and abort these steps.
Note: The result index is beyond the input urls' size. This violates the selectURL() protocol, and we don’t know which url should be selected.
Otherwise:
-
If savedQueryName is a string that is not the empty string, then run store the index for a saved query with window , navigable , workletDataOrigin , moduleURLRecord , operationName , savedQueryName , and index .
-
Queue a global task on the DOM manipulation task source , given window , to resolve promise with index .
-
Run privateAggregationCompletionTask .
-
-
- If it was rejected:
-
-
If savedQueryName is a string that is not the empty string, then run store the index for a saved query with window , navigable , workletDataOrigin , moduleURLRecord , operationName , savedQueryName , and the default selectURL index .
-
Queue a global task on the DOM manipulation task source , given window , to reject promise with a
TypeError
.Note: This indicates that either operationCtor ’s run() method encounters an error (where operationCtor is the parameter in
register()
), or the result index is a non-integer value, which violates the selectURL() protocol, and we don’t know which url should be selected. -
Run privateAggregationCompletionTask .
-
-
-
Return the tuple ( promise , true).
SharedStorageWorklet
worklet
,
an
environment
settings
object
environment
,
a
Document
document
,
a
sequence
of
SharedStorageUrlWithMetadata
urls
,
a
list
of
strings
urlList
,
a
navigable
navigable
,
a
SharedStorageRunOperationMethodOptions
options
,
a
fenced
frame
config
mapping
fencedFrameConfigMapping
,
a
urn
uuid
urn
,
a
boolean
shouldChargeTopLevelBudgets
,
a
boolean
shouldUseDefaultIndex
,
and
an
unsigned
long
resultIndex
,
perform
the
following
steps:
-
Let site be the result of running obtain a site with document ’s origin .
-
Let remainingBudget be the result of running determine remaining navigation budget with environment and site .
-
Let pendingBits be the logarithm base 2 of urlList ’s size .
-
If shouldChargeTopLevelBudgets is true:
-
Let pageBudgetResult be the result of running charge shared storage top-level traversable budgets with navigable , site , and pendingBits .
-
If pageBudgetResult is false, set shouldUseDefaultIndex to true.
-
-
If pendingBits is greater than remainingBudget , set shouldUseDefaultIndex to true.
-
If shouldUseDefaultIndex is true, set resultIndex to the default selectURL index .
-
Let finalConfig be a new fenced frame config .
-
Set finalConfig ’s mapped url to urlList [ resultIndex ].
-
Set finalConfig ’s a "pending shared storage budget debit" field to pendingBits .
-
Finalize a pending config on fencedFrameConfigMapping with urn and finalConfig .
-
Let resultURLWithMetadata be urls [ resultIndex ].
-
If resultURLWithMetadata has field "
reportingMetadata
", run register reporting metadata with resultURLWithMetadata ["reportingMetadata
"]. -
If options ["
keepAlive
"] is false, run terminate a worklet global scope with worklet .
selectURL(
name
,
urls
,
options
)
method
steps
are:
-
Let resultPromise be a new promise .
-
If this ’s addModule initiated is false, then return a promise rejected with a
TypeError
. -
Let window be this ’s relevant settings object .
-
Let context be window ’s browsing context .
-
If context is null, then return a promise rejected with a
TypeError
. -
Let preSpecifiedParams be the result of obtaining the pre-specified report parameters given options and context .
-
If preSpecifiedParams is a
DOMException
, return a promise rejected with preSpecifiedParams . -
Let aggregationCoordinator be the result of obtaining the aggregation coordinator given options .
-
If aggregationCoordinator is a
DOMException
, return a promise rejected with aggregationCoordinator . -
Let document be context ’s active document .
-
If this ’s global scopes is empty , then return a promise rejected with a
TypeError
.Note: This can happen if
selectURL()
is called beforeaddModule()
. -
Assert : this ’s global scopes ’s size is 1.
-
Let globalScope be this ’s global scopes [0].
-
Let workletDataOrigin be globalScope ’s realm ’s settings object ’s origin .
-
If the result of running Is feature enabled in document for origin? on " shared-storage-select-url ", document , and workletDataOrigin returns false, return a promise rejected with a
TypeError
. -
If the result of running check whether addModule is finished for globalScope is false, return a promise rejected with a
TypeError
. -
If urls is empty or if urls ’s size is greater than 8, return a promise rejected with a
TypeError
.Note: 8 is chosen here so that each call of
selectURL()
can leak at most log2(8) = 3 bits of information when the result fenced frame is clicked. It’s not a lot of information per-call. -
Let urlList be an empty list .
-
For each urlWithMetadata in urls :
-
If urlWithMetadata has no field "
url
", return a promise rejected with aTypeError
. -
Otherwise, let urlString be urlWithMetadata ["
url
"]. -
Let serializedUrl be the result of running get the canonical URL string if valid with urlString .
-
If serializedUrl is undefined, return a promise rejected with a
TypeError
. -
Otherwise, append serializedUrl to urlList .
-
If urlWithMetadata has field "
reportingMetadata
":-
Let reportingMetadata be urlWithMetadata ["
reportingMetadata
"]. -
If the result of running validate reporting metadata with reportingMetadata is false, reject resultPromise with a
TypeError
and abort these steps.
-
-
-
Let navigable be window ’s associated document ’s node navigable .
-
Let fencedFrameConfigMapping be navigable ’s traversable navigable ’s fenced frame config mapping .
-
Let pendingConfig be a new fenced frame config .
-
Let urn be the result of running store a pending config on fencedFrameConfigMapping with pendingConfig .
-
If urn is failure, then return a promise rejected with a
TypeError
. -
Let environment be window ’s relevant settings object .
-
Let allowedInOpaqueOriginContext be this ’s has cross-origin data origin .
-
If the result of running determine whether shared storage is allowed by context given environment , workletDataOrigin , and allowedInOpaqueOriginContext is false, return a promise rejected with a
TypeError
. -
If the result of running check if user preference setting allows access to shared storage given environment and workletDataOrigin is false:
-
If this ’s has cross-origin data origin is false, return a promise rejected with a
TypeError
.
-
-
If options ["
resolveToConfig
"] is true, resolve resultPromise with pendingConfig . -
Otherwise, resolve resultPromise with urn .
-
Let ( indexPromise , shouldChargeTopLevelBudgets ) be the result of running get the select-url result index , given this , name , urlList , workletDataOrigin , navigable , options , preSpecifiedParams and aggregationCoordinator .
-
Upon fulfillment of indexPromise with resultIndex , run handle the result of selecting an index given worklet , environment , document , urls , urlList , navigable , options , fencedFrameConfigMapping , urn , shouldChargeTopLevelBudgets , false, and resultIndex .
-
Upon rejection of indexPromise , run handle the result of selecting an index given worklet , environment , document , urls , urlList , navigable , options , fencedFrameConfigMapping , urn , shouldChargeTopLevelBudgets , true, and the default selectURL index .
-
Return resultPromise .
run(
name
,
options
)
method
steps
are:
-
Let promise be a new promise .
-
If this ’s addModule initiated is false, then return a promise rejected with a
TypeError
. -
Let window be this ’s relevant settings object .
-
Let context be window ’s browsing context .
-
If context is null, then return a promise rejected with a
TypeError
. -
Let preSpecifiedParams be the result of obtaining the pre-specified report parameters given options and context .
-
If preSpecifiedParams is a
DOMException
, return a promise rejected with preSpecifiedParams . -
Let aggregationCoordinator be the result of obtaining the aggregation coordinator given options .
-
If aggregationCoordinator is a
DOMException
, return a promise rejected with aggregationCoordinator . -
If this ’s global scopes is empty , then return a promise rejected with a
TypeError
.Note: This can happen if
run()
is called beforeaddModule()
. -
Assert : this ’s global scopes ’s size is 1.
-
Let globalScope be this ’s global scopes [0].
-
If the result of running check whether addModule is finished for globalScope is false, return a promise rejected with a
TypeError
. -
Let workletDataOrigin be globalScope ’s realm ’s settings object ’s origin .
-
Let allowedInOpaqueOriginContext be this ’s has cross-origin data origin .
-
If the result of running determine whether shared storage is allowed by context given window , workletDataOrigin , and allowedInOpaqueOriginContext is false, reject promise with a
TypeError
. -
If the result of running check if user preference setting allows access to shared storage given window and workletDataOrigin is false:
-
If this ’s has cross-origin data origin is false, reject promise with a
TypeError
. -
Else, resolve promise with undefined.
-
Return promise .
-
-
Return promise , and immediately obtaining a worklet agent given window and run the rest of these steps in that agent:
Note: The promise ’s resolution should be before and not depend on the execution inside
SharedStorageWorkletGlobalScope
. This is because shared storage is a type of unpartitioned storage, and aSharedStorageWorkletGlobalScope
can have access to cross-site data, which shouldn’t be leaked viarun()
(via its success/error result).-
Queue a global task on the DOM manipulation task source , given window , to resolve promise with undefined.
-
If globalScope ’s relevant settings object ’s module map is not empty :
-
Let operationMap be this ’s
SharedStorageWorkletGlobalScope
’s operation map . -
If operationMap contains name :
-
Assert : operationMap [ name ]'s associated realm is this ’s relevant realm .
-
Let operation be operationMap [ name ], converted to
Function
. -
Let privateAggregationCompletionTask be the result of setting up the Private Aggregation scopes given workletDataOrigin , preSpecifiedParams and aggregationCoordinator .
-
Let argumentsList be a new list .
-
Invoke operation with argumentsList and "
report
". -
Wait for operation to finish running, if applicable.
-
Run privateAggregationCompletionTask .
-
-
-
If options ["
keepAlive
"] is false:-
Wait for operation to finish running, if applicable.
-
Run terminate a worklet global scope with this .
-
-
SharedStorageRunOperationMethodOptions
options
,
perform
the
following
steps.
They
return
an
aggregation
coordinator
,
null
or
a
DOMException
:
-
If options ["
privateAggregationConfig
"] does not exist , return null. -
If options ["
privateAggregationConfig
"]["aggregationCoordinatorOrigin
"] does not exist , return null. -
Return the result of obtaining the Private Aggregation coordinator given options ["
privateAggregationConfig
"]["aggregationCoordinatorOrigin
"].
SharedStorageRunOperationMethodOptions
options
and
a
browsing
context
context
,
perform
the
following
steps.
They
return
a
pre-specified
report
parameters
,
null,
or
a
DOMException
:
-
If options ["
privateAggregationConfig
"] does not exist , return null. -
Let privateAggregationConfig be options ["
privateAggregationConfig
"]. -
Let contextId be null.
-
If privateAggregationConfig ["
contextId
"] exists , set contextId to privateAggregationConfig ["contextId
"]. -
If contextId ’s length is greater than 64, return a new
DOMException
with name "DataError
". -
Let filteringIdMaxBytes be the default filtering ID max bytes .
-
If privateAggregationConfig ["
filteringIdMaxBytes
"] exists , set filteringIdMaxBytes to privateAggregationConfig ["filteringIdMaxBytes
"]. -
If filteringIdMaxBytes is not contained in the valid filtering ID max bytes range , return a new
DOMException
with name "DataError
". -
If context ’s fenced frame config instance is not null:
-
If filteringIdMaxBytes is not the default filtering ID max bytes or contextId is not null, return a new
DOMException
with name "DataError
".
-
-
Let maxContributions be null.
-
If privateAggregationConfig ["
maxContributions
"] exists , set maxContributions to privateAggregationConfig ["maxContributions
"]. -
If maxContributions is zero, return a new
DOMException
with name "DataError
". -
Return a new pre-specified report parameters with the items:
- context ID
-
contextId
- filtering ID max bytes
-
filteringIdMaxBytes
- max contributions
-
maxContributions
Note: The returned algorithm should be run when the associated operation is complete.
-
Let batchingScope be a new batching scope .
-
Let debugScope be a new debug scope .
-
Let privateAggregationTimeout be null.
-
Let hasRunPrivateAggregationCompletionTask be false.
-
Let privateAggregationCompletionTask be an algorithm to perform the following steps:
-
If hasRunPrivateAggregationCompletionTask , return.
-
Set hasRunPrivateAggregationCompletionTask to true.
-
Mark a debug scope complete given debugScope .
-
Process contributions for a batching scope given batchingScope , workletDataOrigin , "
shared-storage
" and privateAggregationTimeout .
-
-
If aggregationCoordinator is not null, set the aggregation coordinator for a batching scope given aggregationCoordinator and batchingScope .
-
If preSpecifiedParams is not null:
-
Let isDeterministicReport be the result of determining if a report should be sent deterministically given preSpecifiedParams .
-
If isDeterministicReport :
-
Set privateAggregationTimeout to the current wall time plus the deterministic operation timeout duration .
-
-
Set the pre-specified report parameters for a batching scope given preSpecifiedParams and batchingScope .
-
If isDeterministicReport , run the following steps in parallel :
-
Wait until privateAggregationTimeout .
-
Run privateAggregationCompletionTask .
-
-
-
Return privateAggregationCompletionTask .
The deterministic operation timeout duration is an implementation-defined non-negative duration that controls how long a Shared Storage operation may make Private Aggregation contributions if it is triggering a deterministic report and, equivalently, when that report should be sent after the operation begins.
2.2. Monkey Patch for Worklets
This specification will make some modifications to the Worklet standard to accommodate the needs of Shared Storage.
2.2.1. Monkey Patch for set up a worklet environment settings object
The
set
up
a
worklet
environment
settings
object
algorithm
will
need
to
include
an
additional
parameter:
Worklet
worklet
.
The
step
that
defines
the
settingsObject
’s
origin
should
be
modified
as
follows:
-
Let settingsObject be a new environment settings object whose algorithms are defined as follows:
......
The origin
-
Let workletGlobalScope be the global object of realmExecutionContext ’s Realm component.
-
If workletGlobalScope is not
SharedStorageWorkletGlobalScope
, return origin . -
Assert that worklet is a
SharedStorageWorklet
. -
If worklet ’s data origin is
"context-origin"
, return outsideSettings ’s origin . -
Otherwise, if data origin is
"script-origin"
:-
Let pendingAddedModules be a clone of worklet ’s added modules list .
-
Let moduleURL be pendingAddedModules [0].
-
Return moduleURL ’s origin .
-
-
Otherwise, let customOriginUrl be the result of running a URL parser on data origin .
-
Return customOriginUrl ’s origin .
......
-
2.2.2. Monkey Patch for create a worklet global scope
The create a worklet global scope algorithm will need to be modified to pass in the worklet parameter:
-
Let insideSettings be the result of setting up a worklet environment settings object given realmExecutionContext , outsideSettings , and worklet .
2.2.3. Monkey Patch for fetch a worklet script graph
The algorithm fetch a worklet script graph calls into the fetch a worklet/module worker script graph algorithm, which takes in an algorithm parameter processCustomFetchResponse . The definition of that processCustomFetchResponse parameter will need to include the following step before the step "5. Fetch request , ...":
-
If fetchClient ’s global object is
SharedStorageWorkletGlobalScope
:-
Set request ’s redirect mode to "
error
".Note: For shared storage, redirects are disallowed for the module script request. With this restriction, it’s possible to define and to use the algorithm that gets the realm ’s settings object ’s origin (as described in § 2.2.1 Monkey Patch for set up a worklet environment settings object ) as soon as the
SharedStorageWorkletGlobalScope
is created, as the origin won’t change. This restriction may be removed in a future iteration of the design. If redirects become allowed, presumably, the algorithm that gets the realm ’s settings object ’s origin should be updated to return the final request’s URL ’s origin after receiving the final request’s response, and the user preference checkings shall only be done after that point. -
If fetchClient ’s origin and settingsObject ’s origin are not same origin :
-
Let dataOriginValue be the serialization of settingsObject ’s origin .
-
Assert that dataOriginValue is not null.
-
Append the header (`
Sec-Shared-Storage-Data-Origin
`, dataOriginValue ) to request ’s header list .
-
-
2.2.4.
The
`
Shared-Storage-Cross-Origin-Worklet-Allowed
`
HTTP
response
header
The
`
Shared-Storage-Cross-Origin-Worklet-Allowed
`
HTTP
response
header,
along
with
the
traditional
CORS
headers,
can
be
used
to
grant
a
cross-origin
site
the
permission
to
create
a
worklet
from
the
module
script’s
URL
’s
origin
,
and
to
run
subsequent
operations
on
the
worklet
using
the
module
script’s
URL
’s
origin
as
the
data
partition
origin
for
accessing
shared
storage
data,
i.e.
the
origin
set
in
§ 2.2.1
Monkey
Patch
for
set
up
a
worklet
environment
settings
object
,
which
becomes
the
origin
used
in
all
SharedStorage
calls
to
obtain
a
shared
storage
bottle
map
.
Worklets
that
load
cross-origin
scripts
rely
on
CORS
as
a
baseline
permission
mechanism
to
indicate
trusted
external
origins.
However,
CORS
alone
is
insufficient
for
creation
of
a
worklet
with
cross-origin
script
whose
data
partition
origin
is
the
script
origin.
Unlike
simple
resource
sharing,
worklets
allow
the
creator
site
to
execute
JavaScript
within
the
context
of
the
target
origin.
To
ensure
security,
an
additional
response
header,
`
Shared-Storage-Cross-Origin-Worklet-Allowed
`,
is
required
from
the
script
origin.
2.2.5. Monkey Patch for HTTP fetch
Steps will need to be added to the HTTP fetch algorithm.
Note:
It
is
the
responsibility
of
the
site
serving
the
module
script
to
carefully
consider
the
security
implications:
when
the
module
script’s
URL
’s
origin
and
the
worklet’s
creator
Window
origin
are
not
same
origin
,
by
sending
permissive
CORS
headers
the
`
Shared-Storage-Cross-Origin-Worklet-Allowed
`
header
on
the
module
script
response,
the
server
will
be
granting
the
worklet’s
creation
and
subsequent
operations
on
the
worklet,
while
allowing
the
worklet
to
use
the
worklet’s
script’s
origin
as
the
origin
for
accessing
the
shared
storage
data,
i.e.
the
data
partition
origin
.
For
example,
the
worklet’s
creator
Window
could
poison
and
use
up
the
worklet
origin’s
site
’s
remaining
navigation
budget
by
calling
selectURL()
or
run()
,
where
the
worklet
origin
is
the
global
scope’s
realm
’s
settings
object
’s
origin
.
2.2.6.
Monkey
Patch
for
addModule()
The
addModule()
method
steps
for
Worklet
will
need
to
include
the
following
step
before
the
step
"Let
promise
be
a
new
promise":
-
If this is of type
SharedStorageWorklet
:-
Let addModuleAllowedResult be the result of running check if addModule is allowed and update state given this and moduleURLRecord .
-
If addModuleAllowedResult is "DisallowedDueToNonPreferenceError":
-
Return a promise rejected with a
TypeError
.
-
-
Else if addModuleAllowedResult is "DisallowedDueToPreferenceError":
-
If this ’s has cross-origin data origin is false, then return a promise rejected with a
TypeError
.
-
-
Else:
-
Assert : addModuleAllowedResult is "Allowed".
-
-
addModule()
will
be
aborted
at
an
early
stage.
However,
the
error
will
only
be
exposed
to
the
caller
for
a
same-origin
worklet
(i.e.
where
the
initiator
document’s
origin
is
same-origin
with
the
module
script’s
origin).
For
a
cross-origin
worklet,
the
error
will
be
hidden.
This
is
to
prevent
a
caller
from
knowing
which
origins
the
user
has
disabled
shared
storage
for
via
preferences
(if
a
per-origin
preference
exists
for
that
browser
vendor).
A caller may still use timing attacks to know this information, but this is a minor security/privacy issue, as in reality very few users would set such preferences, and doing a wide search would incur a significant performance cost spinning up the worklets.
This
rationale
also
applies
to
the
handling
for
user
preferences
error
for
selectURL()
and
run()
.
After the step "Let addedSuccessfully be false", we need to include the following step:
-
If this is of type
SharedStorageWorklet
, has cross-origin data origin is true, and data origin is not"script-origin"
:-
Assert pendingTasks is 1.
-
Set pendingTasks to 2.
-
Queue a global task on the networking task source given workletGlobalScope to perform the following steps:
-
Let customOriginUrl be the result of running a URL parser on data origin .
-
Set customOriginUrl ’s path to ≪".well-known", "shared-storage", "trusted-origins"≫.
-
Let request be a new request whose URL is customOriginUrl , mode is
"cors"
, referrer is"client"
, destination is"json"
, initiator type is"script"
, and client is outsideSettings . -
Fetch request with processResponseConsumeBody set to the following algorithm, given response response and null, failure or a byte sequence bodyBytes :
-
If any of the following are true:
then:
-
Set pendingTasks to −1.
-
Reject promise with an "TypeError" DOMException.
-
Abort these steps.
-
-
Let mimeType be the result of extracting a MIME type from response ’s header list .
-
If mimeType is not a JSON MIME type , then:
-
Set pendingTasks to −1.
-
Reject promise with an "TypeError" DOMException.
-
Abort these steps.
-
-
Let sourceText be the result of UTF-8 decoding bodyBytes .
-
Let parsed be the result of parsing a JSON string to an Infra value given sourceText .
-
If parsed is not a list or if parsed is empty , then:
-
Set pendingTasks to −1.
-
Reject promise with an "TypeError" DOMException.
-
Abort these steps.
-
-
Let doesMatch be false.
-
For each item of parsed :
-
If item is not an ordered map , or if item does not contain
scriptOrigin
, or if item does not containcontextOrigin
:-
Set pendingTasks to −1.
-
Reject promise with an "TypeError" DOMException.
-
Abort these steps.
-
-
Let doesMatch be the result of running check for script and context origin match on item [
scriptOrigin
], moduleURLRecord ’s origin , item [contextOrigin
], and outsideSettings ’s origin . -
If doesMatch is true:
-
Queue a global task on the networking task source given this ’s relevant global object to perform the following steps:
-
If pendingTasks is not −1, then:
-
Set pendingTasks to pendingTasks − 1.
-
If pendingTasks is 0, perform the following steps:
-
If workletGlobalScope has an associated boolean addModule success , set workletGlobalScope ’s addModule success to true.
-
Resolve promise .
-
-
-
-
Break.
-
-
-
If doesMatch is false, then:
-
Set pendingTasks to −1.
-
Reject promise with an "TypeError" DOMException.
-
-
-
-
Note: If the worklet data origin is different from the current context and the script origin, an additional check is performed. This involves fetching a configuration file from the worklet data origin to verify that the current context is allowed to load the worklet with the script and perform operations.
The penultimate step (i.e. the final indented step), currently "If pendingTasks is 0, then resolve promise .", should be updated to:
-
If pendingTasks is 0, perform the following steps:
-
If workletGlobalScope has an associated boolean addModule success , set workletGlobalScope ’s addModule success to true.
-
Resolve promise .
-
Just before the final step, currently "Return promise .", add the following step:
-
If this is a
SharedStorageWorklet
, upon fulfillment of promise or upon rejection of promise , run the following steps:-
Let globalScopes be this ’s global scopes .
-
Let privateAggregationObj be globalScopes [0]'s
privateAggregation
. -
Set privateAggregationObj ’s allowed to use to the result of determining whether this ’s relevant global object ’s associated document is allowed to use the "
private-aggregation
" policy-controlled feature .Consider adding an early return here if the permissions policy check is made first.
-
Set privateAggregationObj ’s scoping details to a new scoping details with the items:
- get batching scope steps
-
An algorithm that returns the batching scope that is scheduled to be passed to process contributions for a batching scope when the call currently executing in scope returns.
- get debug scope steps
-
An algorithm that returns the debug scope that is scheduled to be passed to mark a debug scope complete when the call currently executing in scope returns.
Note: Multiple operation invocations can be in-progress at the same time, each with a different batching scope and debug scope. However, only one can be currently executing.
-
A trusted origin type is a string or list of strings .
-
If the result of running check for trusted origin match , given itemScriptOrigin and actualScriptOrigin is false, return false.
-
Return the result of running check for trusted origin match , given itemContextOrigin and actualContextOrigin .
-
If itemOrigin is a string , return the result of running check for trusted origin match on a string , given itemOrigin and actualOrigin .
-
Otherwise, for each originString in itemOrigin :
-
If the result of running check for trusted origin match on a string given originString and actualOrigin is true, return true.
-
-
Return false.
-
If itemOrigin is
"*"
, return true. -
Let itemOriginUrl be the result of running a URL parser on itemOrigin .
-
If itemOriginUrl is not a valid URL , then return false.
-
If itemOriginUrl ’s origin and actualOrigin are same origin , return true.
-
Otherwise, return false.
Add additional monkey patch pieces for out-of-process worklets.
2.3.
The
SharedStorageWorkletGlobalScope
The
SharedStorageWorklet
’s
worklet
global
scope
type
is
SharedStorageWorkletGlobalScope
.
The
SharedStorageWorklet
’s
worklet
destination
type
is
"sharedstorageworklet".
2.3.1. Monkey Patch for request destination
The fetch request’s destination field should additionally include "sharedstorageworklet" as a valid value.
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 ; };
Each
SharedStorageWorkletGlobalScope
has
an
associated
environment
settings
object
outside
settings
,
which
is
the
associated
SharedStorageWorklet
’s
relevant
settings
object
.
Each
SharedStorageWorkletGlobalScope
has
an
associated
boolean
addModule
success
,
which
is
initialized
to
false.
Each
SharedStorageWorkletGlobalScope
also
has
an
associated
operation
map
,
which
is
a
map
,
initially
empty,
of
strings
(denoting
operation
names)
to
function
objects
.
Each
SharedStorageWorkletGlobalScope
has
an
associated
SharedStorage
instance
shared
storage
instance
.
Each
SharedStorageWorkletGlobalScope
has
an
associated
SharedStorageWorkletNavigator
instance
navigator
instance
.
2.3.2.
SharedStorageWorkletGlobalScope
algorithms
register(
name
,
operationCtor
)
method
steps
are:
-
If name is missing or empty, throw a
TypeError
. -
Let operationMap be this
SharedStorageWorkletGlobalScope
’s operation map . -
If operationMap contains an entry with key name , throw a
TypeError
. -
If operationCtor is missing, throw a
TypeError
. -
Let operationClassInstance be the result of constructing operationCtor , with no arguments.
-
Let runFunction be Get ( operationClassInstance , "
run
"). Rethrow any exceptions. -
If IsCallable ( runFunction ) is false, throw a
TypeError
. -
Set the value of operationMap [ name ] to runFunction .
The "name" and "operationCtor" cannot be missing here given WebIDL. Should just check for default/empty values. [Issue #151]
interestGroups()
method
steps
are:
-
Let promise be a new promise .
-
If the result of running check whether addModule is finished for
SharedStorage
’s associatedSharedStorageWorkletGlobalScope
is false, return a promise rejected with aTypeError
. -
Let globalObject be the current realm ’s global object .
-
Let context be globalObject ’s browsing context .
-
If context is null, return a promise rejected with a
TypeError
. -
Let document be context ’s active window ’s associated document .
-
If document is not fully active , return a promise rejected with a
TypeError
. -
Let workletDataOrigin be current realm ’s settings object ’s origin .
-
Run the following steps in parallel :
-
Let interestGroups be the result of running get storage interest groups for owner given workletDataOrigin .
-
If interestGroups is failure:
-
Queue a global task on the DOM manipulation task source , given realm ’s global object , to reject promise with a
TypeError
.
-
-
Otherwise:
-
Queue a global task on the DOM manipulation task source , given realm ’s global object , to resolve promise with interestGroups .
-
-
-
Return promise .
sharedStorage
getter
steps
are:
-
If this ’s addModule success is true, return this ’s shared storage instance .
-
Otherwise, throw a
TypeError
.
-
Return the value of addModule success .
2.4.
SharedStorageUrlWithMetadata
and
Reporting
dictionary {
SharedStorageUrlWithMetadata required USVString ;
url object ; };
reportingMetadata
If
a
SharedStorageUrlWithMetadata
dictionary
contains
a
non-
empty
reportingMetadata
object
in
the
form
of
a
dictionary
whose
keys
are
FenceEvent
’s
eventType
s
and
whose
values
are
strings
that
parse
to
valid
URLs
,
then
these
eventType
-
URL
pairs
will
be
registered
for
later
access
within
any
fenced
frame
that
loads
the
SharedStorageResponse
resulting
from
this
selectURL()
call.
reportingMetadata
should
be
a
dictionary
.
[Issue
#141]
Inside
a
fenced
frame
with
eventType
-
URL
pairs
that
have
been
registered
through
selectURL()
with
reportingMetadata
object
s,
if
reportEvent()
is
called
on
a
FenceEvent
with
a
destination
containing
"
shared-storage-select-url
"
and
that
FenceEvent
’s
corresponding
eventType
is
triggered,
then
the
FenceEvent
’s
eventData
will
be
sent
as
a
beacon
to
the
registered
URL
for
that
eventType
.
object
reportingMetadata
,
run
the
following
steps:
-
If reportingMetadata is not a dictionary , return false.
-
If reportingMetadata is empty , return true.
-
For each eventType → urlString of reportingMetadata , if the result of running get the canonical URL string if valid with urlString is undefined, return false.
-
Return true.
-
Let url be the result of running a URL parser on urlString .
-
If url is not a valid URL , return undefined.
-
Otherwise, return the result of running a URL serializer on url .
object
reportingMetadata
and
a
fenced
frame
config
fencedFrameConfigStruct
,
run
the
following
steps:
-
If reportingMetadata is empty , return.
-
Assert : reportingMetadata is a dictionary .
-
For each eventType → urlString of reportingMetadata :
-
Let url be the result of running a URL parser on urlString .
-
Set reportingUrlMap [ eventType ] to url .
-
Store reportingUrlMap inside a fenced frame reporter class associated with fencedFrameConfigStruct . Both of these still need to be added to the draft [Fenced-Frame] . [Issue #144]
2.5. Entropy Budgets
Because
bits
of
entropy
can
leak
via
selectURL()
,
the
user
agent
will
need
to
maintain
budgets
to
limit
these
leaks.
On
a
call
to
selectURL()
,
when
any
of
these
budgets
are
exhausted,
the
default
selectURL
index
will
be
used
to
determine
which
URL
to
select.
sequence
<
USVString
>
urls
,
run
the
following
steps:
-
Return 0.
Note: We could have chosen to return any
unsigned long
from the range from 0 to urls ’s size , exclusive, as long as the returned index was independent from the registered operation class’s "run
" method.
The
default
selectURL
index
is
the
index
obtained
by
running
get
the
default
selectURL
index
,
given
sequence
<
USVString
>
urls
.
2.5.1. Navigation Entropy Budget
If
a
user
activates
a
fenced
frame
whose
node
document
’s
browsing
context
’s
fenced
frame
config
instance
was
generated
by
selectURL()
and
thereby
initiates
a
top-level
traversable
navigation
,
this
will
reveal
to
the
landing
page
that
its
URL
was
selected,
which
is
a
leak
in
entropy
bits
of
up
to
logarithm
base
2
of
the
number
of
input
URLs
for
the
call
to
selectURL()
.
To
mitigate
this,
a
user
agent
will
set
a
per-
site
navigation
entropy
allowance
.
A navigation entropy allowance is a maximum allowance of entropy bits that are permitted to leak via fenced frames initiating top-level traversable navigations during a given navigation budget epoch for a given calling site . This allowance is defined by the user agent and is site -agnostic.
A user agent will define a fixed predetermined duration navigation budget lifetime .
An navigation budget epoch is any interval of time whose duration is the navigation budget lifetime .
To keep track of how this navigation entropy allowance is used, the user agent uses a shared storage navigation budget table , which is a map of sites to navigation entropy ledgers .
An navigation entropy ledger is a list of bit debits .
A bit debit is a struct with the following items :
- bits
-
a
double
- timestamp
-
a
DOMHighResTimeStamp
(from the Unix Epoch )
Bit debits whose timestamps precede the start of the current navigation budget epoch are said to be expired .
When a leak occurs, its value in entropy bits is calculated and stored for that site , along with the current time as a timestamp , together as a bit debit in the shared storage navigation budget table .
Each site has an associated double remaining navigation budget , whose value is the navigation entropy allowance minus any bit debits whose timestamps are within the current navigation budget epoch .
When
a
site
has
insufficient
remaining
navigation
budget
,
selectURL()
will
return
a
SharedStorageResponse
(i.e.
either
a
FencedFrameConfig
or
a
urn
uuid
)
for
the
url
in
the
SharedStorageUrlWithMetadata
at
the
default
selectURL
index
.
-
Assert : site is not an opaque origin .
-
Let maxBits be the user agent ’s navigation entropy allowance .
-
If the user agent ’s shared storage navigation budget table does not contain site , then return maxBits .
-
Otherwise, let ledger be user agent ’s shared storage navigation budget table [ site ].
-
Let debitSum be 0.
-
For each item bitDebit in ledger , do the following steps:
-
Let debit be bitDebit ’s bits .
-
If the result of running check whether a bit debit is expired with environment and bitDebit is false, then increment debitSum by debit .
-
-
Return maxBits − debitSum .
-
Let epochLength be the user agent ’s navigation budget lifetime .
-
Let currentTime be environment ’s current wall time .
-
Let threshold be currentTime − epochLength .
-
If bitDebit ’s timestamp is less than threshold , return true.
-
Otherwise, return false.
A
bit
debit
will
need
to
be
charged
to
the
shared
storage
navigation
budget
table
for
each
top-level
traversable
navigation
initiated
by
a
fenced
frame
whose
node
document
’s
browsing
context
’s
fenced
frame
config
instance
was
generated
via
selectURL()
,
as
this
can
leak
cross-site
data.
Since
the
bits
to
charge
is
calculated
during
the
call
to
selectURL()
but
only
actually
recorded
in
the
shared
storage
navigation
budget
table
if
and
when
the
resulting
fenced
frame
initiates
a
top-level
traversable
navigation
,
the
bits
must
be
stored
as
a
pending
shared
storage
budget
debit
in
the
corresponding
fenced
frame’s
node
document
’s
browsing
context
’s
fenced
frame
config
instance
until
this
time.
Move the definition of pending shared storage budget debit to fenced frame config instance in the draft [Fenced-Frame] specification. [Issue #148]
Between beginning navigation and ending navigation , a user agent will perform the charge shared storage navigation budget algorithm.
Need to find a better way to specify timing of the navigation budget charging. [Issue #138]
Document
sourceDocument
,
run
the
following
steps:
-
If navigable is not a top-level traversable , return.
-
Let currentNavigable be sourceDocument ’s node navigable .
-
While currentNavigable is not null:
-
Let site be the result of running obtain a site with currentNavigable ’s active document ’s origin .
-
Let instance be currentNavigable ’s node document ’s browsing context ’s fenced frame config instance .
-
Set currentNavigable to currentNavigable ’s parent .
-
If instance is null or site is an opaque origin , then continue .
-
Let pendingBits be instance ’s pending shared storage budget debit .
-
If pendingBits is not greater than 0, then continue .
-
Let ledger be user agent ’s shared storage navigation budget table [ site ].
-
Let bitDebit be a new bit debit .
-
Set bitDebit ’s bits to pendingBits .
-
Let currentTime be the current wall time .
-
Set bitDebit ’s timestamp to currentTime .
-
Append bitDebit to ledger .
-
Set pendingBits to 0.
-
A user agent may wish to set a timer to periodically purge expired bit debits from all navigation entropy ledgers , as the expired bit debits will no longer be needed.
-
For each origin → ledger of user agent ’s shared storage navigation budget table :
-
For each bitDebit in ledger , if the result of running check whether a bit debit is expired with bitDebit is true, remove bitDebit from ledger .
-
2.5.2. Top-Level Traversable Entropy Budgets
In the short term, while we have less-restrictive fenced frames , it is necessary to impose additional limits as follows.
Each
user
agent
will
specify
a
maximum
overall
page
entropy
allowance
and
a
maximum
site
page
entropy
allowance
,
where
the
former
is
the
total
number
of
bits
allowed
to
leak
for
selectURL()
per
top-level
traversable
,
where
the
latter
is
the
total
number
of
bits
allowed
to
leak
for
selectURL()
per
site
per
top-level
traversable
The shared storage page budget is a struct with the following items :
- overall budget
-
a
double
- site budget map
- saved query map
-
a map of tuples ( origin data origin , URL worklet script URL , string operation name , string query name ) to saved query data
The saved query data is a struct with the following items :
2.5.2.1. Monkey patch for Traversable Navigables
In [HTML] ’s Traversable navigables section, add the following:
In addition to the properties of a navigable , a traversable navigable has:
-
An page budget , a shared storage page budget or null, initially null.
2.5.2.2. Monkey patch for Navigables
Modify the initialize the navigable algorithm by adding the following steps at the end:
-
If parent is null and navigable is a traversable navigable , then:
-
Let newPageBudget be a shared storage page budget with an empty site budget map .
-
Set newPageBudget ’s overall budget to overall page entropy allowance .
-
Set navigable ’s page budget to newPageBudget .
-
2.5.2.3. Saved queries
-
Let topLevelTraversable be the result of running get the top-level traversable for navigable .
-
Assert that topLevelTraversable ’s page budget is not null.
-
If topLevelTraversable ’s page budget ’s saved query map does not contain ( origin , moduleURLRecord , operationName , savedQueryName ), then:
-
Set topLevelTraversable ’s page budget ’s saved query map [( origin , moduleURLRecord , operationName , savedQueryName )] to a new saved query data struct queryData .
-
Set queryData ’s index value to -1.
-
Return "pending current operation".
-
-
Let savedIndex be topLevelTraversable ’s page budget ’s saved query map [( origin , moduleURLRecord , operationName , savedQueryName )]'s index .
-
If savedIndex is -1:
-
Return savedIndex .
Note:
The
get
the
index
for
a
saved
query
algorithm
returns
"pending
current
operation"
to
indicate
that
the
index
value
is
pending
the
result
of
queueing
a
task
on
the
SharedStorageWorkletGlobalScope
’s
worklet
event
loop
to
perform
the
registered
operation.
Note:
The
get
the
index
for
a
saved
query
algorithm
returns
"pending
callback"
to
indicate
that
a
task
to
determine
the
result
of
the
index
was
previously
queued
on
the
SharedStorageWorkletGlobalScope
’s
worklet
event
loop
,
and
that
we
are
now
queueing
an
additional
callbackTask
to
be
run
when
the
original
task
has
completed.
Window
window
,
navigable
navigable
,
origin
origin
,
URL
moduleURLRecord
,
string
operationName
,
string
savedQueryName
,
and
unsigned
long
index
:
-
Let topLevelTraversable be the result of running get the top-level traversable for navigable .
-
Assert that topLevelTraversable ’s page budget is not null.
-
Let queryData be topLevelTraversable ’s page budget ’s saved query map [( origin , moduleURLRecord , operationName , savedQueryName )].
-
While queryData ’s callbacks is not empty:
-
Dequeue the next task callbackTask from queryData ’s callbacks , and queue a global task on the DOM manipulation task source , given window , to run the steps of callbackTask , given index .
-
Window
window
,
list
of
SharedStorageUrlWithMetadata
s
urlList
,
promise
promise
,
perform
the
following
steps.
They
return
an
algorithm.
-
Let processIndexTask be an algorithm to perform the following steps, given an
unsigned long
index :-
If index is greater than urlList ’s size , then queue a global task on the DOM manipulation task source , given window , to reject promise with a
TypeError
.Note: The result index is beyond the input urls' size. This violates the selectURL() protocol, and we don’t know which url should be selected.
-
Otherwise, queue a global task on the DOM manipulation task source , given window , to resolve promise with index .
-
-
Return processIndexTask .
2.5.2.4. Charging the Top-Level Traversable Entropy Budgets
-
Let topLevelTraversable be the result of running get the top-level traversable for navigable .
-
Assert that topLevelTraversable ’s page budget is not null.
-
If pendingBits is greater than topLevelTraversable ’s page budget ’s overall budget , then return false and abort these steps.
-
If topLevelTraversable ’s page budget ’s site budget map does not contain site , then set topLevelTraversable ’s page budget ’s site budget map [ site ] to site page entropy allowance .
-
If pendingBits is greater than topLevelTraversable ’s page budget ’s site budget map [ site ], then return false and abort these steps.
-
Decrement topLevelTraversable ’s page budget ’s site budget map [ site ] by pendingBits .
-
Decrement topLevelTraversable ’s page budget ’s overall budget by pendingBits .
-
Return true.
3. Shared Storage’s Backend
The Shared Storage API will integrate into the Storage API as below, via registering a new storage endpoint .3.1. Monkey Patch for the Storage Model
This
standard
will
add
a
new
storage
type
"
shared
"
to
the
Storage
Model
.
A
user
agent
holds
a
shared
storage
shed
for
storage
endpoints
of
type
"
shared
".
This
standard
will
also
register
a
storage
endpoint
of
type
"
shared
"
with
storage
identifier
"
sharedStorage
"
and
quota
5
4
*
2
16
bytes
(i.e.
39.0625
mebibytes).
This
quota
is
calculated
from
the
current
implementation.
Consider
bringing
the
current
implementation
in
line
with
the
spec
for
storage
endpoints
"
localStorage
"
and
"
sessionStorage
",
i.e.
5
*
2
20
bytes.
For
example,
decreasing
the
per-origin
entry
limit
from
10,000
to
1,280
would
achieve
this.
A shared storage shed is a map of origins to storage shelves . It is initially empty.
Note: Unlike storage sheds , whose keys are storage keys , shared storage sheds use origins as keys directly. Shared storage will be intentionally excluded from client-side storage partitioning .
For
each
storage
shelf
in
a
shared
storage
shed
,
the
storage
shelf
’s
bucket
map
currently
has
only
a
single
key
of
"
default
".
A user agent ’s shared storage shed holds all shared storage data.
-
Let allowedInOpaqueOriginContext be false.
-
If the result of running determine whether shared storage is allowed by context given environment , origin , and allowedInOpaqueOriginContext is false, then return failure.
-
If the result of running check if user preference setting allows access to shared storage given environment and origin is false, then return failure.
-
If shed [origin] does not exist, then set shed [origin] to the result of running create a shared storage shelf with type "
shared
". -
Return shed [ origin ].
-
Let shelf be a new storage shelf .
-
Set shelf ’s bucket map ["
default
"] to the result of running create a shared storage bucket . -
Return shelf .
A shared storage bucket is a storage bucket in one of a shared storage shed ’s shelves .
-
Let endpoint be the storage endpoint with storage identifier "
sharedStorage
". -
Let bucket be a new shared storage bucket .
-
Set bucket ’s bottle map ["
sharedStorage
"] to a new storage bottle whose quota is endpoint ’s quota . -
Return bucket .
Note:
Currently,
a
shared
storage
bucket
’s
bottle
map
has
size
1
,
since
there
is
only
one
storage
endpoint
registered
with
type
"
shared
".
-
Let shed be the user agent ’s shared storage shed .
-
Let shelf be the result of running obtain a shared storage shelf with shed , environment , and origin .
-
If shelf is failure, then return failure.
-
Let bucket be shelf ’s bucket map ["
default
"]. -
Let bottle be bucket ’s bottle map ["
sharedStorage
"]. -
Let proxyMap be a new storage proxy map whose backing map is bottle ’s map .
-
Append proxyMap to bottle ’s proxy map reference set .
-
Return proxyMap .
3.2. The Shared Storage Database
A browsing context has an associated shared storage database , which provides methods to store , retrieve , delete , clear , and purge expired data, and additional methods as below. The data in the database take the form of entries .
Each shared storage database has a shared storage database queue , which is the result of starting a new parallel queue . This queue is used to run each of the shared storage database ’s methods when calls to them are initiated from that browsing context .
Each entry consists of a key and a value struct .
User agents may specify the maximum length of a key .
Since keys are used to organize and efficiently retrieve entries , keys must appear at most once in any given shared storage database .
An
entry
’s
value
struct
is
a
struct
composed
of
string
value
and
DOMHighResTimeStamp
last
updated
(from
the
Unix
Epoch
).
User agents may specify the maximum length of a value .
User agents may specify a default entry lifetime , the default duration between when an entry is stored and when it expires. If the user agent specifies a default entry lifetime , then it should have a timer periodically purge expired entries from the database .
3.3. The Core Database Algorithms
-
Let valueStruct be a new value struct .
-
Set valueStruct ’s value to value .
-
Let currentTime be the environment ’s current wall time .
-
Set valueStruct ’s last updated to currentTime .
-
Set databaseMap [ key ] to valueStruct .
-
If an exception was thrown , then return false.
Note: Errors with storage proxy map databaseMap ’s methods are possible depending on its implementation.
-
Otherwise, return true.
-
If databaseMap does not contain key , return undefined.
-
Let valueStruct be the result of running Get on databaseMap with key .
-
If an exception was thrown , then return failure.
Note: Errors with storage proxy map databaseMap ’s methods are possible depending on its implementation.
-
If the result of running determine whether an entry is expired with environment and valueStruct is true, return undefined.
-
Return valueStruct ’s value .
-
Remove databaseMap [ key ].
-
If an exception was thrown , then return false.
Note: Errors with storage proxy map databaseMap ’s methods are possible depending on its implementation.
-
Return true.
-
Run Clear on databaseMap .
-
If an exception was thrown , then return false.
Note: Errors with storage proxy map databaseMap ’s methods are possible depending on its implementation.
-
Return true.
-
Let values be the result of running getting the values on databaseMap .
-
If an exception was thrown , then return failure.
Note: Errors with storage proxy map databaseMap ’s methods are possible depending on its implementation.
-
Return values .
-
Let size be databaseMap ’s size .
-
If an exception was thrown , then return failure.
Note: Errors with storage proxy map databaseMap ’s members are possible depending on its implementation.
-
Return size .
-
For each key key in databaseMap :
-
Let valueStruct be the result of running Get on databaseMap with key .
-
If an exception was thrown , then return false.
-
If the result of running determine whether an entry is expired with environment and valueStruct is true, Remove databaseMap [ key ].
-
If an exception was thrown , then return false.
-
-
Return true.
To determine whether an entry is expired , given an environment settings object environment and a value struct valueStruct , run the following steps:
-
Let lastUpdated be valueStruct ’s last updated .
-
Let lifetime be user agent ’s default entry lifetime .
-
Let expiration be the sum of lastUpdated and lifetime .
-
Let currentTime be the environment ’s current wall time .
-
If expiration is less than or equal to currentTime , return true.
-
Otherwise, return false.
3.4. The Specialized Database Algorithms
These algorithms, unlike the core algorithms in § 3.3 The Core Database Algorithms , either accept parameters with more specialized heuristics, or employ multi-step processes, or both, to handle more complex database operations.
To set an entry in the database , given a shared storage database queue queue , a storage proxy map databaseMap , an environment settings object environment , a key key , a value value , and a boolean ignoreIfPresent , run the following steps on queue :
If ignoreIfPresent :
Let currentValue be the result of running retrieve an entry from the database with queue , databaseMap , environment , and key .
If currentValue is failure, then return false.
If currentValue is not undefined, then return true.
Return the result of running store an entry in the database with queue , databaseMap , environment , key , and value .
To append an entry in the database , given a shared storage database queue queue , a storage proxy map databaseMap , an environment settings object environment , a key key , and a value value , run the following steps on queue :
Let currentValue be the result of running retrieve an entry from the database with queue , databaseMap , environment , and key .
If currentValue is failure, then return false.
If currentValue is not undefined:
Let list be a new list .
Append currentValue to list .
Append value to list .
Set value to the result of running concatenate on list .
Return the result of running store an entry in the database with queue , databaseMap , environment , key , and value .
4.
Extension
to
the
Window
interface
Each
Window
object
has
an
associated
SharedStorage
instance
sharedStorage
,
which
is
created
alongside
the
Window
if
Shared
Storage
is
enabled,
with
the
getter
below.
partial interface Window { [SecureContext ]readonly attribute SharedStorage ?; };
sharedStorage
sharedStorage
getter
steps
are:
-
If this is fully active , return this ’s
sharedStorage
. -
Otherwise, return null.
5.
The
SharedStorageModifierMethod
Interface
Group
The
SharedStorageSetMethod
,
SharedStorageAppendMethod
,
SharedStorageDeleteMethod
,
SharedStorageClearMethod
interfaces
correspond
to
the
set()
,
append()
,
delete()
,
clear()
modifier
methods.
They
all
inherit
the
base
SharedStorageModifierMethod
interface.
[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
A
SharedStorageModifierMethod
has
the
following
associated
fields:
- with lock
-
Null or a string . Initially null.
A
SharedStorageSetMethod
has
the
following
associated
fields:
- key
-
A string . Initially empty.
- value
-
A string . Initially empty.
- ignore if present
-
A boolean . Initially false.
A
SharedStorageAppendMethod
has
the
following
associated
fields:
A
SharedStorageDeleteMethod
has
the
following
associated
fields:
- key
-
A string . Initially empty.
The
new
SharedStorageSetMethod(
key
,
value
,
options
)
constructor
steps
are:
-
Let globalObject be the current realm ’s global object .
-
Let context be null.
-
If globalObject is a
Window
:-
Set context to globalObject ’s browsing context .
-
-
Else:
-
Set context to globalObject ’s outside settings ’s target browsing context .
-
If the result of running check whether addModule is finished for
SharedStorage
’s associatedSharedStorageWorkletGlobalScope
is false, throw aTypeError
.
-
-
If context is null, throw a
TypeError
. -
If context ’s active window ’s associated document is not fully active , throw a
TypeError
. -
If key ’s length exceeds the maximum length , throw a
TypeError
. -
If value ’s length exceeds the maximum length , throw a
TypeError
. -
Let environment be context ’s active window ’s relevant settings object .
-
Let databaseMap be the result of running obtain a shared storage bottle map given environment and environment ’s origin .
-
If databaseMap is failure, throw a
TypeError
. -
Set this ’s ignore if present to options ["
ignoreIfPresent
"].
The
new
SharedStorageAppendMethod(
key
,
value
,
options
)
constructor
steps
are:
-
Let globalObject be the current realm ’s global object .
-
Let context be null.
-
If globalObject is a
Window
:-
Set context to globalObject ’s browsing context .
-
-
Else:
-
Set context to globalObject ’s outside settings ’s target browsing context .
-
If the result of running check whether addModule is finished for
SharedStorage
’s associatedSharedStorageWorkletGlobalScope
is false, throw aTypeError
.
-
-
If context is null, throw a
TypeError
. -
If context ’s active window ’s associated document is not fully active , throw a
TypeError
. -
If key ’s length exceeds the maximum length , throw a
TypeError
. -
If value ’s length exceeds the maximum length , throw a
TypeError
. -
Let environment be context ’s active window ’s relevant settings object .
-
Let databaseMap be the result of running obtain a shared storage bottle map given environment and environment ’s origin .
-
If databaseMap is failure, throw a
TypeError
.
The
new
SharedStorageAppendMethod(
key
,
options
)
constructor
steps
are:
-
Let globalObject be the current realm ’s global object .
-
Let context be null.
-
If globalObject is a
Window
:-
Set context to globalObject ’s browsing context .
-
-
Else:
-
Set context to globalObject ’s outside settings ’s target browsing context .
-
If the result of running check whether addModule is finished for
SharedStorage
’s associatedSharedStorageWorkletGlobalScope
is false, throw aTypeError
.
-
-
If context is null, throw a
TypeError
. -
If context ’s active window ’s associated document is not fully active , throw a
TypeError
. -
If key ’s length exceeds the maximum length , throw a
TypeError
. -
Let environment be context ’s active window ’s relevant settings object .
-
Let databaseMap be the result of running obtain a shared storage bottle map given environment and environment ’s origin .
-
If databaseMap is failure, throw a
TypeError
.
The
new
SharedStorageClearMethod(
options
)
constructor
steps
are:
-
Let globalObject be the current realm ’s global object .
-
Let context be null.
-
If globalObject is a
Window
:-
Set context to globalObject ’s browsing context .
-
-
Else:
-
Set context to globalObject ’s outside settings ’s target browsing context .
-
If the result of running check whether addModule is finished for
SharedStorage
’s associatedSharedStorageWorkletGlobalScope
is false, throw aTypeError
.
-
-
If context is null, throw a
TypeError
. -
If context ’s active window ’s associated document is not fully active , throw a
TypeError
. -
Let environment be context ’s active window ’s relevant settings object .
-
Let databaseMap be the result of running obtain a shared storage bottle map given environment and environment ’s origin .
-
If databaseMap is failure, throw a
TypeError
.
6.
The
SharedStorage
Interface
The
SharedStorage
interface
is
exposed
to
Window
and
SharedStorageWorklet
.
Methods
that
allow
the
setting
and/or
deleting
of
data
are
exposed
to
both
the
Window
and
the
SharedStorageWorklet
,
although
their
implementations
may
vary
depending
on
their
environment
.
This
makes
it
possible
to
modify
the
data
in
Shared
Storage
from
multiple
contexts.
Meanwhile,
methods
for
posting
operations
to
run
inside
SharedStorageWorkletGlobalScope
(i.e.
selectURL()
and
run()
),
along
with
the
worklet
attribute
which
is
used
to
call
addModule()
,
are
exposed
to
the
Window
only,
as
these
are
the
means
by
which
the
Window
interacts
with
the
SharedStorageWorklet
.
On
the
other
hand,
methods
for
getting
data
from
the
shared
storage
database
are
exposed
to
the
SharedStorageWorklet
only,
in
order
to
carefully
control
the
flow
of
data
read
from
the
database
.
The
only
exception
is
that
get()
is
exposed
to
Window
,
but
will
only
succeed
if
the
result
of
the
determine
if
a
navigable
has
fully
revoked
network
algorithm
is
true.
Note:
The
determine
if
a
navigable
has
fully
revoked
network
algorithm
ensures
that
get()
only
succeeds
for
fenced
frames
that
have
successfully
resolved
a
call
to
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.
Run
Operation
Methods
on
SharedStorage
selectURL(
name
,
urls
,
options
)
method
steps
are:
run(
name
,
options
)
method
steps
are:
6.2.
Create
a
new
worklet
via
SharedStorage
createWorklet(
moduleURL
,
options
)
method
steps
are:
-
Let sharedStorageWorklet be a new
SharedStorageWorklet
. -
If options contains "
dataOrigin
", set sharedStorageWorklet ’s data origin to options ["dataOrigin
"]. -
Let addModulePromise be the result of invoking sharedStorageWorklet.
addModule
( moduleURL , options ). -
Let resultPromise be a new promise .
-
Upon fulfillment of addModulePromise , resolve resultPromise to sharedStorageWorklet .
-
Upon rejection of addModulePromise , reject resultPromise with a
TypeError
. -
Return resultPromise .
6.3. BatchUpdate Method
batchUpdate(
methods
,
options
)
method
steps
are:
-
Let promise be a new promise .
-
Let globalObject be the current realm ’s global object .
-
Let context be null.
-
If globalObject is a
Window
:-
Set context to globalObject ’s browsing context .
-
-
Else:
-
Set context to globalObject ’s outside settings ’s target browsing context .
-
If the result of running check whether addModule is finished for
SharedStorage
’s associatedSharedStorageWorkletGlobalScope
is false, return a promise rejected with aTypeError
.
-
-
If context is null, return a promise rejected with a
TypeError
. -
If context ’s active window ’s associated document is not fully active , return a promise rejected with a
TypeError
. -
Let environment be context ’s active window ’s relevant settings object .
-
Let databaseMap be the result of running obtain a shared storage bottle map given environment and environment ’s origin .
-
If databaseMap is failure, then return a promise rejected with a
TypeError
. -
Let unfinishedUpdatesCount be methods ’s size .
-
Let hasFailure be false.
-
Let onLockGrantedCallback be an algorithm to perform the following steps:
-
For each method in methods :
-
Let methodResultPromise be a new promise .
-
If method is a
SharedStorageSetMethod
:-
Let key be method ’s key .
-
Let value be method ’s value .
-
Let methodOptions be a new
SharedStorageSetMethodOptions
. -
Set methodOptions ["
ignoreIfPresent
"] to method ’s ignore if present . -
If method ’s with lock is not null, set methodOptions ["
withLock
"] to method ’s with lock . -
Set methodResultPromise to the result of invoking
set
( key , value , methodOptions ).
-
-
Else if method is a
SharedStorageAppendMethod
:-
Let key be method ’s key .
-
Let value be method ’s value .
-
Let methodOptions be a new
SharedStorageModifierMethodOptions
. -
If method ’s with lock is not null, set methodOptions ["
withLock
"] to method ’s with lock . -
Set methodResultPromise to the result of invoking
append
( key , value , methodOptions ).
-
-
Else if method is a
SharedStorageDeleteMethod
: -
Else:
-
Assert : method is a
SharedStorageClearMethod
. -
Let methodOptions be a new
SharedStorageModifierMethodOptions
. -
If method ’s with lock is not null, set methodOptions ["
withLock
"] to method ’s with lock . -
Set methodResultPromise to the result of invoking
clear
( methodOptions ).
-
-
Upon fulfillment of methodResultPromise :
-
Decrement unfinishedUpdatesCount by 1.
-
If unfinishedUpdatesCount is 0, run finish a batch update given promise and hasFailure .
-
-
Upon rejection of methodResultPromise :
-
Decrement unfinishedUpdatesCount by 1.
-
Set hasFailure to true.
-
If unfinishedUpdatesCount is 0, run finish a batch update given promise and hasFailure .
-
-
-
If unfinishedUpdatesCount is 0, run finish a batch update given promise and hasFailure .
-
-
If options ["
withLock
"] exists , run handle callback within a shared storage lock given environment ’s origin , options ["withLock
"], onLockGrantedCallback . -
Else, run onLockGrantedCallback .
-
Return promise .
6.4. Setter/Deleter Methods
set(
key
,
value
,
options
)
method
steps
are:
-
Let promise be a new promise .
-
Let globalObject be the current realm ’s global object .
-
Let context be null.
-
If globalObject is a
Window
:-
Set context to globalObject ’s browsing context .
-
-
Else:
-
Set context to globalObject ’s outside settings ’s target browsing context .
-
If the result of running check whether addModule is finished for
SharedStorage
’s associatedSharedStorageWorkletGlobalScope
is false, return a promise rejected with aTypeError
.
-
-
If context is null, return a promise rejected with a
TypeError
. -
If context ’s active window ’s associated document is not fully active , return a promise rejected with a
TypeError
. -
If key ’s length exceeds the maximum length , return a promise rejected with a
TypeError
. -
If value ’s length exceeds the maximum length , return a promise rejected with a
TypeError
. -
Let environment be context ’s active window ’s relevant settings object .
-
Let databaseMap be the result of running obtain a shared storage bottle map given environment and environment ’s origin .
-
If databaseMap is failure, then return a promise rejected with a
TypeError
. -
Let queue be context ’s associated database ’s shared storage database queue .
-
Let realm be the current realm .
-
Let onLockGrantedCallback be an algorithm to perform the following steps:
-
Enqueue the following steps on queue :
-
If options [" ignoreIfPresent "] is true:LetcurrentValueresult be the result of runningretrieveset an entryfromin the database with queue , databaseMap , environment ,andkey., value , and options ["ignoreIfPresent
"]. -
If
currentValueresult isfailurefalse and if globalObject is aSharedStorageWorkletGlobalScope
:-
Queue a global task on the DOM manipulation task source , given realm ’s global object , to reject promise with a
TypeError
. -
Abort these steps.
-
-
If currentValue is not undefined:Queue a global task on the DOM manipulation task source , given realm ’s global object , to resolve promise with undefined.Abort these steps. Let result be the result of running store an entry in the database with queue , databaseMap , environment , key , and value . If result is false and if globalObject is a SharedStorageWorkletGlobalScope : Queue a global task on the DOM manipulation task source , given realm ’s global object , to reject promise with a TypeError . Abort these steps. Queue a global task on the DOM manipulation task source , given realm ’s global object , to resolve promise with undefined.
-
-
-
If options ["
withLock
"] exists :-
If options ["
withLock
"] starts with U+002D HYPHEN-MINUS (-), return a promise rejected with aTypeError
. -
Run handle callback within a shared storage lock given environment ’s origin , options ["
withLock
"], onLockGrantedCallback .
-
-
Else, run onLockGrantedCallback .
-
Return promise .
append(
key
,
value
,
options
)
method
steps
are:
-
Let promise be a new promise .
-
Let globalObject be the current realm ’s global object .
-
Let context be null.
-
If globalObject is a
Window
:-
Set context to globalObject ’s browsing context .
-
-
Else:
-
Set context to globalObject ’s outside settings ’s target browsing context .
-
If the result of running check whether addModule is finished for
SharedStorage
’s associatedSharedStorageWorkletGlobalScope
is false, return a promise rejected with aTypeError
.
-
-
If context is null, return a promise rejected with a
TypeError
. -
If context ’s active window ’s associated document is not fully active , return a promise rejected with a
TypeError
. -
If key ’s length exceeds the maximum length , return a promise rejected with a
TypeError
. -
If value ’s length exceeds the maximum length , return a promise rejected with a
TypeError
. -
Let environment be context ’s active window ’s relevant settings object .
-
Let databaseMap be the result of running obtain a shared storage bottle map given environment and environment ’s origin .
-
If databaseMap is failure, then return a promise rejected with a
TypeError
. -
Let queue be context ’s associated database ’s shared storage database queue .
-
Let realm be the current realm .
-
Let onLockGrantedCallback be an algorithm to perform the following steps:
-
Enqueue the following steps on queue :
-
Let
currentValue be the result of running retrieve an entry from the database with queue , databaseMap , environment , and key . If currentValue is failure: If globalObject is a Window : Queue a global task on the DOM manipulation task source , given realm ’s global object , to resolve promise with undefined. Else: Queue a global task on the DOM manipulation task source , given realm ’s global object , to reject promise with a TypeError . Abort these steps. If currentValue is not undefined: Let list be a new list . Append currentValue to list . Append value to list . Set value to the result of running concatenate on list . Letresult be the result of runningstoreappend an entry in the database with queue , databaseMap , environment , key , and value . -
If result is false and if globalObject is a
SharedStorageWorkletGlobalScope
:-
Queue a global task on the DOM manipulation task source , given realm ’s global object , to reject promise with a
TypeError
. -
Abort these steps.
-
-
Queue a global task on the DOM manipulation task source , given realm ’s global object , to resolve promise with undefined.
-
-
-
If options ["
withLock
"] exists :-
If options ["
withLock
"] starts with U+002D HYPHEN-MINUS (-), return a promise rejected with aTypeError
. -
Run handle callback within a shared storage lock given environment ’s origin , options ["
withLock
"], onLockGrantedCallback .
-
-
Else, run onLockGrantedCallback .
-
Return promise .
delete(
key
,
options
)
method
steps
are:
-
Let promise be a new promise .
-
Let globalObject be the current realm ’s global object .
-
Let context be null.
-
If globalObject is a
Window
:-
Set context to globalObject ’s browsing context .
-
-
Else:
-
Set context to globalObject ’s outside settings ’s target browsing context .
-
If the result of running check whether addModule is finished for
SharedStorage
’s associatedSharedStorageWorkletGlobalScope
is false, return a promise rejected with aTypeError
.
-
-
If context is null, return a promise rejected with a
TypeError
. -
If context ’s active window ’s associated document is not fully active , return a promise rejected with a
TypeError
. -
If key ’s length exceeds the maximum length , return a promise rejected with a
TypeError
. -
Let environment be context ’s active window ’s relevant settings object .
-
Let databaseMap be the result of running obtain a shared storage bottle map given environment and environment ’s origin .
-
If databaseMap is failure, then return a promise rejected with a
TypeError
. -
Let queue be context ’s associated database ’s shared storage database queue .
-
Let realm be the current realm .
-
Let onLockGrantedCallback be an algorithm to perform the following steps:
-
Enqueue the following steps on queue :
-
Let result be the result of running delete an entry from the database with queue , databaseMap , and key .
-
If result is false and if globalObject is a
SharedStorageWorkletGlobalScope
:-
Queue a global task on the DOM manipulation task source , given realm ’s global object , to reject promise with a
TypeError
. -
Abort these steps.
-
-
Queue a global task on the DOM manipulation task source , given realm ’s global object , to resolve promise with undefined.
-
-
-
If options ["
withLock
"] exists :-
If options ["
withLock
"] starts with U+002D HYPHEN-MINUS (-), return a promise rejected with aTypeError
. -
Run handle callback within a shared storage lock given environment ’s origin , options ["
withLock
"], onLockGrantedCallback .
-
-
Else, run onLockGrantedCallback .
-
Return promise .
clear(
options
)
method
steps
are:
-
Let promise be a new promise .
-
Let globalObject be the current realm ’s global object .
-
Let context be null.
-
If globalObject is a
Window
:-
Set context to globalObject ’s browsing context .
-
-
Else:
-
Set context to globalObject ’s outside settings ’s target browsing context .
-
If the result of running check whether addModule is finished for
SharedStorage
’s associatedSharedStorageWorkletGlobalScope
is false, return a promise rejected with aTypeError
.
-
-
If context is null, return a promise rejected with a
TypeError
. -
If context ’s active window ’s associated document is not fully active , return a promise rejected with a
TypeError
. -
Let environment be context ’s active window ’s relevant settings object .
-
Let databaseMap be the result of running obtain a shared storage bottle map given environment and environment ’s origin .
-
If databaseMap is failure, then return a promise rejected with a
TypeError
. -
Let queue be context ’s associated database ’s shared storage database queue .
-
Let realm be the current realm .
-
Let onLockGrantedCallback be an algorithm to perform the following steps:
-
Enqueue the following steps on queue :
-
Let result be the result of running clear all entries in the database with queue and databaseMap .
-
If result is false and if globalObject is a
SharedStorageWorkletGlobalScope
:-
Queue a global task on the DOM manipulation task source , given realm ’s global object , to reject promise with a
TypeError
. -
Abort these steps.
-
-
Queue a global task on the DOM manipulation task source , given realm ’s global object , to resolve promise with undefined.
-
-
-
If options ["
withLock
"] exists :-
If options ["
withLock
"] starts with U+002D HYPHEN-MINUS (-), return a promise rejected with aTypeError
. -
Run handle callback within a shared storage lock given environment ’s origin , options ["
withLock
"], onLockGrantedCallback .
-
-
Else, run onLockGrantedCallback .
-
Return promise .
6.5. Getter Methods
get(
key
)
method
steps
are:
-
Let promise be a new promise .
-
Let globalObject be the current realm ’s global object .
-
Let context be null.
-
Let environment be null.
-
If globalObject is a
Window
:-
Set context to globalObject ’s browsing context .
-
If context is null, return a promise rejected with a
TypeError
. -
Set environment to context ’s active window ’s relevant settings object .
-
Let allowedInOpaqueOriginContext be false.
-
If the result of running determine whether shared storage is allowed by context given environment , environment ’s origin , and allowedInOpaqueOriginContext is false, return a promise rejected with a
TypeError
. -
If the result of running check if user preference setting allows access to shared storage given environment and environment ’s origin is false, return a promise rejected with an
OperationError
. -
Let document be context ’s active document .
-
If the result of running Is feature enabled in document for origin? on " fenced-unpartitioned-storage-read ", document , and environment ’s origin is false, return a promise rejected with an
OperationError
. -
Let navigable be document ’s node navigable .
-
If the result of running determine if a navigable has fully revoked network given navigable is false, return a promise rejected with an
OperationError
.
-
-
Else: 1 If the result of running check whether addModule is finished for
SharedStorage
’s associatedSharedStorageWorkletGlobalScope
is false, return a promise rejected with aTypeError
.-
Set context to
SharedStorage
’sSharedStorageWorkletGlobalScope
’s outside settings ’s target browsing context . -
If context is null, return a promise rejected with a
TypeError
. -
Set environment to context ’s active window ’s relevant settings object .
-
-
If key ’s length exceeds the maximum length , return a promise rejected with a
TypeError
. -
If context ’s active window ’s associated document is not fully active , return a promise rejected with a
TypeError
. -
Let realm be the current realm .
-
Let databaseMap be the result of running obtain a shared storage bottle map given environment and realm ’s settings object ’s origin .
-
If databaseMap is failure, then return a promise rejected with a
TypeError
. -
Let queue be context ’s associated database ’s shared storage database queue .
-
Enqueue the following steps on queue :
-
Let value be the result of running retrieve an entry from the database with queue , databaseMap , environment , and key .
-
If value is failure, queue a global task on the DOM manipulation task source , given realm ’s global object , to reject promise with a
TypeError
. -
Otherwise, if value is undefined, queue a global task on the DOM manipulation task source , given realm ’s global object , to resolve promise with undefined.
-
Otherwise, queue a global task on the DOM manipulation task source , given realm ’s global object , to resolve promise with value .
-
-
Return promise .
length()
method
steps
are:
-
Let promise be a new promise .
-
If the result of running check whether addModule is finished for
SharedStorage
’s associatedSharedStorageWorkletGlobalScope
is false, return a promise rejected with aTypeError
. -
Let context be
SharedStorage
’sSharedStorageWorkletGlobalScope
’s outside settings ’s target browsing context . -
If context is null, return a promise rejected with a
TypeError
. -
If context ’s active window ’s associated document is not fully active , return a promise rejected with a
TypeError
. -
Let environment be context ’s active window ’s relevant settings object .
-
Let realm be the current realm .
-
Let databaseMap be the result of running obtain a shared storage bottle map given environment and realm ’s settings object ’s origin .
-
If databaseMap is failure, then return a promise rejected with a
TypeError
. -
Let queue be context ’s associated database ’s shared storage database queue .
-
Enqueue the following steps on queue :
-
Let numEntries be the result of running count entries in the database with queue and environment .
-
If numEntries is failure, queue a global task on the DOM manipulation task source , given realm ’s global object , to reject promise with a
TypeError
. -
Otherwise, queue a global task on the DOM manipulation task source , given realm ’s global object , to resolve promise with numEntries .
-
-
Return promise .
remainingBudget()
method
steps
are:
-
Let promise be a new promise .
-
If the result of running check whether addModule is finished for
SharedStorage
’s associatedSharedStorageWorkletGlobalScope
is false, return a promise rejected with aTypeError
. -
Let context be
SharedStorage
’sSharedStorageWorkletGlobalScope
’s outside settings ’s target browsing context . -
If context is null, return a promise rejected with a
TypeError
. -
If context ’s active window ’s associated document is not fully active , return a promise rejected with a
TypeError
. -
Let environment be context ’s active window ’s relevant settings object .
-
Let realm be the current realm .
-
Let allowedInOpaqueOriginContext be false.
-
If the result of running determine whether shared storage is allowed by context given environment , realm ’s settings object ’s origin , and allowedInOpaqueOriginContext is false, return a promise rejected with a
TypeError
. -
If the result of running check if user preference setting allows access to shared storage given environment and realm ’s settings object ’s origin is false, return a promise rejected with a
TypeError
. -
Let site be the result of running obtain a site with realm ’s settings object ’s origin .
-
Assert : site is not an opaque origin .
-
Let queue be context ’s associated database ’s shared storage database queue .
-
Enqueue the following steps on queue :
-
Let remainingBudget be the result of running determine remaining navigation budget with site .
-
Resolve queue a global task on the DOM manipulation task source , given realm ’s global object , to resolve promise with remainingBudget .
-
-
Return promise .
6.6. Iteration
Each
SharedStorage
async
iterator
instance
has
a
queue
pending
entries
of
entries
,
initially
empty
.
Each
SharedStorage
async
iterator
instance
also
has
a
boolean
error
,
initially
false.
The asynchronous iterator initialization steps and get the next iteration result algorithms defined below correspond to those referred to as the asynchronous iterator initialization steps and get the next iteration result algorithms in the Web IDL Standard .
SharedStorage
async
iterator
iterator
are:
-
Let promise be a new promise .
-
If the result of running check whether addModule is finished for
SharedStorage
’s associatedSharedStorageWorkletGlobalScope
is false, return a promise rejected with aTypeError
. -
Let context be
SharedStorage
’sSharedStorageWorkletGlobalScope
’s outside settings ’s target browsing context . -
If context is null, return a promise rejected with a
TypeError
. -
If context ’s active window ’s associated document is not fully active , return a promise rejected with a
TypeError
. -
Let environment be context ’s active window ’s relevant settings object .
-
Let realm be the current realm .
-
Let databaseMap be the result of running obtain a shared storage bottle map given environment and realm ’s settings object ’s origin .
-
If databaseMap is failure, then return a promise rejected with a
TypeError
. -
Let queue be context ’s associated database ’s shared storage database queue .
-
Enqueue the following steps on queue :
-
Let entries be the result of running retrieve all entries from the database with queue and environment .
-
If entries is failure, queue a global task on the DOM manipulation task source , given realm ’s global object , to reject promise with a
TypeError
. -
Otherwise, queue a global task on the DOM manipulation task source , given realm ’s global object , to resolve promise with entries .
-
-
Upon fulfillment of promise , run the following:
-
Let promiseEntries be the value of promise .
-
For each entry entry in promiseEntries , enqueue entry in iterator ’s pending entries .
-
-
Upon rejection of promise , set iterator ’s error to true.
SharedStorage
’s
async
iterator
iterator
,
run
the
following
steps:
-
Let promise be a new promise .
-
-
If iterator ’s error is true, return a promise rejected with a
TypeError
. -
If iterator ’s pending entries is empty :
-
Create an object doneObject .
-
Queue a global task on the DOM manipulation task source , given realm ’s global object , to resolve promise with doneObject .
-
Abort these steps.
-
-
Otherwise, let entry be the result of dequeuing from iterator ’s pending entries .
-
Queue a global task on the DOM manipulation task source , given realm ’s global object , to resolve promise with entry .
-
-
Return promise .
7. Triggering Operations Via HTTP Response Header
While
setter
and
deleter
operations
(e.g..
set()
,
append()
,
delete()
,
clear()
)
can
be
initiated
via
the
above
APIs
for
Window
or
SharedStorageWorkletGlobalScope
,
setter/deleter
operations
can
alternatively
be
triggered
via
HTTP
response
header
.
This will require monkey patches to the HTML and Fetch specifications.
8. HTML Monkey Patches
8.1.
sharedStorageWritable
&
sharedstoragewritable
Attributes
Define
the
following
interface
mixin
and
include
it
in
the
IDL
interfaces
for
HTMLIFrameElement
and
HTMLImageElement
:
interface mixin { [
HTMLSharedStorageWritableElementUtils CEReactions ,SecureContext ]attribute boolean ; };
sharedStorageWritable HTMLIFrameElement includes HTMLSharedStorageWritableElementUtils ;HTMLImageElement includes HTMLSharedStorageWritableElementUtils ;
Add the following boolean content attributes :
-
iframe
-
sharedstoragewritable
-
img
-
sharedstoragewritable
The
IDL
attribute
sharedStorageWritable
must
reflect
the
respective
content
attribute
of
the
same
name.
8.2. HTML Algorithm Modifications
8.2.1. Modification to Update the image data Algorithm
After the step
Set request ’s priority to the current state...
add the step
-
If the element has the
sharedstoragewritable
attribute present, set request ’s shared storage writable to true.
8.2.2. Modification to Create navigation params by fetching Algorithm
After the step
Let request be a new request , with ...
add the step
-
If navigable ’s container is an
iframe
element, and if it has asharedstoragewritable
content attribute , then set request ’s shared storage writable to true.
9. Fetch Monkey Patches
9.1.
sharedStorageWritable
Key
A request has an associated boolean shared storage writable . Unless stated otherwise it is false.
The
RequestInit
dictionary
contains
a
sharedStorageWritable
key:
partial dictionary RequestInit {boolean ; };
sharedStorageWritable
9.2. Fetch Algorithm Modifications
9.2.1. Modification to the Request Constructor Algorithm
Before the step
Set this’s request to request .
add the step
-
If init ["
sharedStorageWritable
"] exists , then set request ’s shared storage writable to it.
9.2.2. Modification to HTTP network or cache fetch Algorithm
Before the step
Modify httpRequest ’s header list per HTTP. ...
add the step
-
Append or modify a Sec-Shared-Storage-Writable request header for httpRequest .
9.2.3. Modification to HTTP fetch Algorithm
Before the step
If internalResponse ’s status is a redirect status : ...
add the steps
-
If request ’s destination is "sharedstorageworklet":
-
Let dataOriginValue be the result of getting `
Sec-Shared-Storage-Data-Origin
` from request ’s header list . -
If dataOriginValue is not null, then:
-
Let dataOriginUrl be the result of running a URL parser on dataOriginValue .
-
Assert that dataOriginUrl is not failure.
-
Assert that request ’s origin and request ’s URL ’s origin are not same origin .
-
Let allowed be true.
-
If dataOriginUrl ’s origin and request ’s URL ’s origin are same origin :
-
Let responseHeaders be internalResponse ’s header list .
-
Let allowed be the result of running get a structured field value algorithm given `
Shared-Storage-Cross-Origin-Worklet-Allowed
`, "item", and responseHeaders as input.
-
-
If allowed is false, then return a network error .
-
-
-
Handle a Shared-Storage-Write response , given response internalResponse and request request as input.
9.3. Shared Storage HTTP Headers
9.3.1.
`
Sec-Shared-Storage-Data-Origin
`
Request
Header
This specification defines a Sec-Shared-Storage-Data-Origin HTTP request header .
The
`
Sec-Shared-Storage-Data-Origin
`
request
header
whose
value
is
a
string
.
When
the
`
Sec-Shared-Storage-Data-Origin
`
is
sent
during
the
fetch
a
worklet/module
worker
script
graph
algorithm,
its
value
is
set
to
the
serialized
origin
that
owns
the
worklet’s
shared
storage
data.
9.3.2.
`
Shared-Storage-Cross-Origin-Worklet-Allowed
`
Response
Header
This specification defines a Shared-Storage-Cross-Origin-Worklet-Allowed HTTP response header .
The
`
Shared-Storage-Cross-Origin-Worklet-Allowed
`
response
header
is
a
Structured
Header
whose
value
must
be
a
Boolean
.
When
a
response
has
`
Shared-Storage-Cross-Origin-Worklet-Allowed
`
with
value
true,
the
worklet
script’s
server
has
given
permission
for
a
cross-origin
site
to
create
a
worklet
using
shared
storage
data
from
the
worklet
script’s
origin
.
9.3.3.
`
Sec-Shared-Storage-Writable
`
Request
Header
This specification defines a Sec-Shared-Storage-Writable HTTP request header .
The
`
Sec-Shared-Storage-Writable
`
request
header
is
a
Structured
Header
whose
value
must
be
a
Boolean
.
When
a
request
sets
`
Sec-Shared-Storage-Writable
`
to
true
its
response
will
be
able
to
write
to
shared
storage
.
9.3.4.
`
Shared-Storage-Write
`
Response
Header
This specification defines a Shared-Storage-Write HTTP response header .
The
`
Shared-Storage-Write
`
response
header
is
a
Structured
Header
whose
value
must
be
a
List
.
The
following
list
members
are
defined.
Tokens
and
Strings
holding
the
same
sequence
of
characters
are
considered
equivalent.
Byte
Sequences
representing
UTF-8
encoded
bytes
are
also
allowed,
in
order
to
provide
functionality
for
writing
and
deleting
non-
ASCII
Unicode
keys
and
values
via
HTTP
headers.
Unknown list members, including types that are neither strings nor Byte Sequences , are skipped, and the rest of the list is processed as if they weren’t present. Members are also skipped if they’re missing required parameters or those parameters have unexpected types.
-
set
-
Required parameters :
-
key
( Token , String , or Byte Sequence ) -
value
( Token , String , or Byte Sequence )
-
-
Optional parameter :
-
ignore_if_present
( Boolean )
-
-
If the parameter value of
ignore_if_present
is null or false, or if the parameter value ofkey
does not already exist in the shared storage database for the responding server’s origin ,set
writes the entry consisting of the parameter values forkey
andvalue
, as the entry ’s key and entry ’s value struct ’s value respectively, in the shared storage database for the responding server’s origin . -
If the parameter value of
ignore_if_present
is true and the parameter value ofkey
already exists in the shared storage database for the responding server’s origin , thenset
is a no-op.
-
-
append
-
Required parameters :
-
key
( Token , String , or Byte Sequence ) -
value
( Token , String , or Byte Sequence )
-
-
If the parameter value of
key
already exists in the shared storage database for the responding server’s origin , thenappend
updates the key ’s entry ’s value struct ’s value by appending the parameter value forvalue
to it. -
If the parameter value of
key
does not already exist in the shared storage database for the responding server’s origin ,append
is equivalent toset
withignore_if_present
false, i.e.append
writes the entry consisting of the parameter values forkey
andvalue
, as the entry ’s key and entry ’s value struct ’s value respectively, in the shared storage database for the responding server’s origin .
-
-
delete
-
Required parameter :
-
key
( Token , String , or Byte Sequence )
-
-
delete
erases any entry in the shared storage database for the responding server’s origin for which the key is equal to the parameter value ofkey
.
-
-
clear
-
clear
erases all entries in the shared storage database for the responding server’s origin .
-
Note: We allow Byte Sequences in order to accommodate Unicode keys and values. Any Byte Sequence will be assumed to be UTF-8 encoded and will fail to parse otherwise.
Add examples.
9.4. Shared Storage Fetch-Related Algorithms
-
Let window to request ’s window .
-
If window is not an environment settings object whose global object is a
Window
, return false. -
Let allowedInOpaqueOriginContext be true.
-
If the result of running determine whether shared storage is allowed by context given window , request ’s current URL ’s origin , and allowedInOpaqueOriginContext is false, return false.
-
If the result of running check if user preference setting allows access to shared storage given window and request ’s current URL ’s origin is false, return false.
The determine whether a request can currently use shared storage algorithm needs to take into account "opt-in features", as articulated in https://github.com/w3c/webappsec-permissions-policy/pull/499 .
-
If request ’s shared storage writable is not true, then return.
Note: On a redirect, it is possible for request ’s shared storage writable to be true, but for the redirect not to have permission to use shared storage, making the result of running determine whether a request can currently use shared storage on request false.
-
If the result of running determine whether a request can currently use shared storage on request is false, delete `
Sec-Shared-Storage-Writable
` from request ’s header list . -
Otherwise, set a structured field value (`
Sec-Shared-Storage-Writable
`, true) in request ’s header list .
-
Let sharedStorageWritable the result of running get a structured field value algorithm given `
Sec-Shared-Storage-Writable
`, "item
", and request ’s header list as input. -
If sharedStorageWritable is null, or sharedStorageWritable is not a Boolean , or the value of sharedStorageWritable is false, return.
-
Let window to request ’s window .
-
Assert : window is an environment settings object whose global object is a
Window
. -
Let sharedStorage be window ’s global object ’s
sharedStorage
. -
If sharedStorage is null, then return.
-
Let list be response ’s header list .
-
Let operationsToParse be the result of running get a structured field value algorithm given `
Shared-Storage-Write
`, "list
", and list as input. -
If operationsToParse is null or empty , then return.
-
Let methods be an empty list .
-
Let batchWithLock be null.
-
For each tuple ( item , parameters ) in operationsToParse , perform the following steps:
-
If item is an Inner List , continue.
-
Let methodOrOptionsString be the result of running get the string value for item .
-
If methodOrOptionsString is failure, continue.
-
Switch on methodOrOptionsString :
-
If
methodOrOptionsString
is
"
clear
": -
Perform
the
following
steps:
-
Let options be a new
SharedStorageModifierMethodOptions
. -
Let withLock be the result of running obtain a string-like parameter value with parameters and "
with_lock
". -
If withLock is not null and withLock does not start with U+002D HYPHEN-MINUS (-), set options ["
withLock
"] to withLock . -
Let method be new
SharedStorageClearMethod
( options ). -
If an exception was thrown , continue.
-
Append method to methods .
-
Continue.
-
-
If
methodOrOptionsString
is
"
delete
": -
Perform
the
following
steps:
-
Let key be the result of running obtain a string-like parameter value with parameters and "
key
". -
If key is null, continue.
-
Let options be a new
SharedStorageModifierMethodOptions
. -
Let withLock be the result of running obtain a string-like parameter value with parameters and "
with_lock
". -
If withLock is not null and withLock does not start with U+002D HYPHEN-MINUS (-), set options ["
withLock
"] to withLock . -
Let method be new
SharedStorageDeleteMethod
( key , options ). -
If an exception was thrown , continue.
-
Append method to methods .
-
Continue.
-
-
If
methodOrOptionsString
is
"
append
": -
Perform
the
following
steps:
-
Let key be the result of running obtain a string-like parameter value with parameters and "
key
". -
If key is null, continue.
-
Let value be the result of running obtain a string-like parameter value with parameters and "
value
". -
If value is null, continue.
-
Let options be a new
SharedStorageModifierMethodOptions
. -
Let withLock be the result of running obtain a string-like parameter value with parameters and "
with_lock
". -
If withLock is not null and withLock does not start with U+002D HYPHEN-MINUS (-), set options ["
withLock
"] to withLock . -
Let method be new
SharedStorageAppendMethod
( key , value , options ). -
If an exception was thrown , continue.
-
Append method to methods .
-
Continue.
-
-
If
methodOrOptionsString
is
"
set
": -
Perform
the
following
steps:
-
Let key be the result of running obtain a string-like parameter value with parameters and "
key
". -
If key is null, continue.
-
Let value be the result of running obtain a string-like parameter value with parameters and "
value
". -
If value is null, continue.
-
Let options be a new
SharedStorageSetMethodOptions
. -
If the result of running obtain a boolean parameter value with parameters and "
ignore_if_present
" is true, set options ["ignoreIfPresent
"] to true. -
Let withLock be the result of running obtain a string-like parameter value with parameters and "
with_lock
". -
If withLock is not null and withLock does not start with U+002D HYPHEN-MINUS (-), set options ["
withLock
"] to withLock . -
Let method be new
SharedStorageSetMethod
( key , value , options ). -
If an exception was thrown , continue.
-
Append method to methods .
-
Continue.
-
-
If
methodOrOptionsString
is
"
options
": -
Perform
the
following
steps:
-
Set batchWithLock to the result of running obtain a string-like parameter value with parameters and "
with_lock
". -
Continue.
-
- If methodOrOptionsString is anything else:
- Continue.
-
If
methodOrOptionsString
is
"
-
-
Let batchOptions be a new
SharedStorageModifierMethodOptions
. -
If batchWithLock is not null and batchWithLock does not start with U+002D HYPHEN-MINUS (-), set batchOptions ["
withLock
"] to batchWithLock . -
Run sharedStorage .
batchUpdate
( methods , batchOptions ).
-
If the item is a String , Token , or Byte Sequence , return true.
-
Otherwise, return false.
-
If the result of running check if string-like on item is false, return failure.
-
Switch on the type of item :
-
If
item
is
a
Token
:
- If item is a String :
-
Perform
the
following
steps:
-
Assert : item is an ASCII string .
-
Return item .
-
- If item is a Byte Sequence :
-
Perform
the
following
steps:
-
Let fromUTF8 be the result of running UTF-8 decode on item .
-
If fromUTF8 is an error, return null.
-
Return fromUTF8 .
-
-
If
item
is
a
Token
:
-
If parameters does not contain paramKey , return null.
-
If the result of check if string-like for parameters [ paramKey ] is false, return null.
-
Return the result of running get the string value for parameters [ paramKey ].
10. Web Locks Integration
10.1. User Agent Associated State
A shared storage lock managers map is a map of origins to lock managers . It is initially empty.
A user agent has an associated shared storage lock managers map .
Note: Similar to its data partitioning, the shared storage has its own lock management scope, independent of the Storage Buckets API. These web locks will not interact with web locks created from Window or Worker via the existing, legacy Web Locks API.
10.2.
SharedStorageWorkletNavigator
interface
[Exposed =SharedStorageWorklet ]interface {};
SharedStorageWorkletNavigator
10.3. Web Locks IDLs Monkey Patches
Include
the
NavigatorLocks
mixin
in
SharedStorageWorkletNavigator
(i.e.,
let
SharedStorageWorkletNavigator
contain
a
LockManager
instance):
SharedStorageWorkletNavigator includes NavigatorLocks ;
The
LockManager
and
Lock
are
additionally
exposed
to
SharedStorageWorklet:
[SecureContext ,Exposed =(Window ,Worker ,SharedStorageWorklet )]interface {};
LockManager
[SecureContext ,Exposed =(Window ,Worker ,SharedStorageWorklet )]interface {};
Lock
10.4. Monkey Patch for lock manager’s description
Add the following sentence at the end of the paragraph that defines lock manager : "Additionally, each user agent includes one shared storage lock managers map for Web Locks API’s integration with the Shared Storage API."
10.5. Monkey Patch for locks getter steps
The locks getter steps should be updated to the following setps:
-
Let globalObject be the current realm ’s global object .
-
If globalObject is a
SharedStorageWorkletGlobalScope
:-
If the globalObject ’s addModule success is false, then throw a
TypeError
.
-
-
Return this ’s relevant settings object ’s
LockManager
object
10.6. Monkey Patch for the "obtain a lock manager" algorithm
The obtain a lock manager algorithm should be prepended with the following steps:
-
If current realm ’s global object is a
SharedStorageWorkletGlobalScope
:-
Let workletDataOrigin be environment ’s origin .
-
Return shared storage lock managers map [ workletDataOrigin ].
-
10.7. "Handle callback within a shared storage lock" algorithm
-
Let environment be this ’s relevant settings object .
-
Let lockManager be shared storage lock managers map [ workletDataOrigin ].
-
Let promise be a new promise .
-
Let defaultOptions be a new
LockOptions
. -
Request a lock with promise , the current agent , environment ’s id , lockManager , callback , name , defaultOptions ["
mode
"], defaultOptions ["ifAvailable
"], defaultOptions ["steal
"], defaultOptions ["signal
"].
Note:
With
the
default
LockOptions
,
callback
will
eventually
be
called
when
the
lock
is
granted
(i.e.,
the
lock
request
won’t
fail).
11. Permissions Policy Integration
This specification defines three policy-controlled features identified by the following strings:
shared-storage " gates access to Shared Storage in general.
"
shared-storage-select-url
"
adds
an
extra
permission
layer
to
selectURL()
"
fenced-unpartitioned-storage-read
"
adds
an
extra
permission
layer
to
get()
,
to
ensure
it
can
only
be
invoked
successfully
from
a
Window
if
the
Promise
returned
from
disableUntrustedNetwork()
has
resolved
.
For each of these, the default allowlist is *.
12. Clear Site Data Integration
Add details for Clear Site Data integration.13. Privacy Considerations
The
Shared
Storage
API
attempts
to
provide
the
ability
to
use
cross-site
data
for
a
range
of
use
cases
in
a
way
that
better
protects
user
privacy
than
the
use
of
third-party
cookies.
Shared
Storage’s
main
privacy
safeguard
is
that
read
access
of
the
data
stored
in
its
storage
may
only
occur
within
an
embedder’s
SharedStorageWorklet
.
Well-defined
limits
restrict
output
of
data
from
the
SharedStorageWorklet
to
a
minimum.
In
particular,
an
embedder
can
select
a
URL
from
a
short
list
of
URL
s
based
on
data
in
their
shared
storage
and
then
display
the
result
in
a
fenced
frame
.
The
embedder
will
not
be
able
to
know
which
URL
was
chosen
except
through
specific
mechanisms
that
will
be
better-mitigated
in
the
longer
term.
Currently,
a
few
bits
of
entropy
can
leak
each
time
that
the
user
clicks
on
the
fenced
frame
to
initiate
a
top-level
traversable
navigation
and/or
the
fenced
frame
calls
the
reportEvent()
API.
An embedder is also able to send aggregatable reports via the Private Aggregation API, which adds noise in order to achieve differential privacy, uses a time delay to send reports, imposes limits on the number of reports sent, and processes the reports into aggregate data so that individual privacy is protected.