@@ -85,7 +85,7 @@ function retrieveNextChunk(nextChunkInfo) {
85
85
86
86
<h2 id=infrastructure>Infrastructure</h2>
87
87
88
- <p> A user agent has various kinds of semi-persistent state:
88
+ <p> A <a for=/> user agent</a> has various kinds of semi-persistent state:
89
89
90
90
<dl>
91
91
<dt> Credentials
@@ -94,37 +94,228 @@ function retrieveNextChunk(nextChunkInfo) {
94
94
<dd><p> Permissions for various features, such as geolocation
95
95
<dt> Network
96
96
<dd><p> HTTP cache, cookies, authentication entries, TLS client certificates
97
- <dt> Storage
97
+ <dt id=site-storage > Storage
98
98
<dd> Indexed DB, Cache API, service worker registrations, <code> localStorage</code> ,
99
99
<code> history.pushState()</code> , application caches, notifications, etc.
100
100
</dl>
101
101
102
- <p> This standard primarily concerns itself with <dfn export id=site- storage>storage</dfn> .
102
+ <p> This standard primarily concerns itself with storage.
103
103
104
- <p> <a>Storage</a> consists of zero or more <dfn export id=site-storage-unit>storage units</dfn> .
105
104
106
- <p> Each <a for=/>origin</a> has an associated <a>storage unit</a> . A <a>storage unit</a> contains a
107
- single <dfn export id=bucket oldids=box>bucket</dfn> . [[HTML]]
105
+ <h3 id=storage-units>Storage units</h3>
108
106
107
+ <p> A <dfn>storage type</dfn> is "<code> storage</code> " or "<code> session-storage</code> ".
109
108
110
- <h3 id=buckets oldids=boxes>Buckets</h3>
109
+ <p> A <dfn>storage key</dfn> is an <a for=/>origin</a> . [[HTML]]
111
110
112
- <p> A <a>bucket</a> has <dfn export for=bucket oldids=box-mode>mode</dfn> which is either
113
- "<code title> best-effort</code> " or "<code title> persistent</code> ". A
114
- <dfn export oldids=persistent-box>persistent bucket</dfn> is a <a>bucket</a> whose
115
- <a for=bucket>mode</a> is "<code title> persistent</code> ". A
116
- <dfn export oldids=non-persistent-box>non-persistent bucket</dfn> is a <a>bucket</a> whose
117
- <a for=bucket>mode</a> is <em> not</em> "<code title> persistent</code> ".
111
+ <p class=XXX> This is expected to change, see
112
+ <a href="https://privacycg.github.io/storage-partitioning/">Client-Side Storage Partitioning</a> .
118
113
119
- <p> A <a>bucket</a> is considered to be an atomic unit. Whenever a <a>bucket</a> is cleared by the
120
- user agent, it must be cleared in its entirety.
114
+ <p> A <dfn id=site-storage-unit>storage unit</dfn> is the least granular unit of storage, other than
115
+ the user agent. It holds a <dfn for="storage unit">map</dfn> , which is a <a for=/>map</a> of
116
+ <a for=/>ASCII strings</a> to <a>abstract storage buckets</a> .
117
+ <!-- Not sure if this needs to be exported, but it was already. -->
118
+
119
+ <p> A <dfn>storage map</dfn> is a <a for=/>map</a> of <a>storage keys</a> to <a>storage units</a> . It
120
+ is initially empty.
121
+
122
+ <p> To <dfn>obtain a storage unit</dfn> , given a <a for=/>storage map</a> <var> map</var> , an
123
+ <a>environment settings object</a> <var> environment</var> , and a <a>storage type</a>
124
+ <var> type</var> , run these steps:
125
+
126
+ <ol>
127
+ <li><p> Let <var> key</var> be <var> environment</var> 's
128
+ <a for="environment settings object">origin</a> .
129
+
130
+ <li><p> If <var> key</var> is an <a>opaque origin</a> , then return failure.
131
+
132
+ <li><p> If the user has disabled storage, then return failure.
133
+
134
+ <li>
135
+ <p> If <var> map</var> [<var>key</var>] does not <a for=map>exist</a> , then:
136
+
137
+ <ol>
138
+ <li><p> Let <var> unit</var> be a new <a>storage unit</a> .
139
+
140
+ <li>
141
+ <p> Set <var> unit</var> 's <a for="storage unit">map</a> ["<code>default</code>"] to the result of
142
+ <a>create a storage bucket</a> with <var> type</var> .
143
+
144
+ <p class="note"> For now "<code> default</code> " is all that exists. See
145
+ <a href="https://github.com/whatwg/storage/issues/2">issue #2</a> .
146
+
147
+ <li><p> Set <var> map</var> [<var>key</var>] to <var> unit</var> .
148
+ </ol>
149
+
150
+ <li><p> Return <var> map</var> [<var>key</var>] .
151
+ </ol>
152
+
153
+ <hr>
154
+
155
+ <p> A <a for=/>user agent</a> holds a <dfn for="user agent">storage map</dfn> , which is a
156
+ <a for=/>storage map</a> .
157
+
158
+ <p> A browsing session holds a <dfn for="browsing session">storage map</dfn> , which is a
159
+ <a for=/>storage map</a> .
160
+
161
+ <p class=XXX> Browsing session is yet to be formally defined. For all intents and purposes it is a
162
+ <a>top-level browsing context</a> , except that it survives the <a>top-level browsing context</a>
163
+ being replaced due to a cross-origin opener policy.
164
+
165
+
166
+ <h3 id=storage-identifiers>Storage identifiers</h3>
167
+
168
+ <p> An <dfn>abstract storage identifier</dfn> is an <a for=/>ASCII string</a> .
169
+
170
+ <p> Each storage API has a <dfn export>storage identifier</dfn> , which is an
171
+ <a>abstract storage identifier</a> . The <dfn>registered storage identifiers</dfn> are:
172
+
173
+ <ol>
174
+ <li> "<code> caches</code> "
175
+ <li> "<code> indexedDB</code> "
176
+ <li> "<code> localStorage</code> "
177
+ <li> "<code> serviceWorkerRegistrations</code> "
178
+ </ol>
179
+
180
+ <p> Each session storage API has a <dfn export>session storage identifier</dfn> , which is an
181
+ <a>abstract storage identifier</a> . The <dfn>registered session storage identifiers</dfn> are
182
+ "<code> sessionStorage</code> ".
183
+
184
+
185
+ <h3 id=buckets oldids=boxes>Storage buckets</h3>
186
+
187
+ <p> An <dfn>abstract storage bucket</dfn> is a place for storage and session storage APIs to store
188
+ data. Whenever an <a>abstract storage bucket</a> is cleared by the user agent, it must be cleared in
189
+ its entirety.
190
+ <!-- This is probably better defined in some kind of storage lifetime section. -->
191
+
192
+ <p> An <dfn for="abstract storage bucket,storage bucket,session storage bucket">area</dfn> is a part
193
+ of an <a>abstract storage bucket</a> carved out for a particular storage API or session storage API.
194
+ An <a for="abstract storage bucket">area</a> has a
195
+ <dfn for="abstract storage bucket/area,storage bucket/area,session storage bucket/area">map</dfn> ,
196
+ which is an initially empty <a for=/>map</a> . An <a for="abstract storage bucket">area</a> also has
197
+ a
198
+ <dfn for="abstract storage bucket/area,storage bucket/area,session storage bucket/area">proxy map reference set</dfn> ,
199
+ which is an initially empty <a for=/>set</a> .
200
+ <!-- The idea is that storage area's map holds the actual storage. It's in a map because those are
201
+ easy to work with. How the map is persisted is implementation-defined. How to make it
202
+ available across process boundaries is implementation-defined. This note also applies to
203
+ session buckets below. -->
204
+
205
+ <p> An <a>abstract storage bucket</a> has a
206
+ <dfn for="abstract storage bucket,storage bucket,session storage bucket">map</dfn> of
207
+ <a>abstract storage identifiers</a> to <a for="abstract storage bucket">areas</a> .
208
+
209
+ <hr>
210
+
211
+ <p> A <dfn id=bucket oldids=box>storage bucket</dfn> is an <a>abstract storage bucket</a> for storage
212
+ APIs.
213
+
214
+ <p> A <a>storage bucket</a> has a
215
+ <dfn for="storage bucket" id=bucket-mode oldids=box-mode>mode</dfn> , which is
216
+ "<code> best-effort</code> " or "<code> persistent</code> ". It is initially "<code> best-effort</code> ".
217
+
218
+ <hr>
219
+
220
+ <p> A <dfn>session storage bucket</dfn> is an <a>abstract storage bucket</a> for session storage
221
+ APIs.
222
+
223
+ <hr>
224
+
225
+ <p> To <dfn>create a storage bucket</dfn> , given a <a>storage type</a> <var> type</var> , run these
226
+ steps:
227
+
228
+ <ol>
229
+ <li><p> Let <var> bucket</var> be null.
230
+
231
+ <li>
232
+ <p> If <var> type</var> is "<code> storage</code> ", then:
233
+
234
+ <ol>
235
+ <li><p> Set <var> bucket</var> to a new <a>storage bucket</a> .
236
+
237
+ <li><p> For each <var> identifier</var> of <a>registered storage identifiers</a> , set
238
+ <var> bucket</var> 's <a for="storage bucket">map</a> [<var>identifier</var>] to a new
239
+ <a for="storage bucket">area</a> .
240
+ </ol>
241
+
242
+ <li>
243
+ <p> Otherwise, if <var> type</var> is "<code> session-storage</code> ":
244
+
245
+ <ol>
246
+ <li><p> Set <var> bucket</var> to a new <a>session storage bucket</a> .
247
+
248
+ <li><p> For each <var> identifier</var> of <a>registered session storage identifiers</a> , set
249
+ <var> bucket</var> 's <a for="session storage bucket">map</a> [<var>identifier</var>] to a new
250
+ <a for="session storage bucket">area</a> .
251
+ </ol>
252
+
253
+ <li><p> Assert: <var> bucket</var> is an <a>abstract storage bucket</a> .
254
+
255
+ <li><p> Return <var> bucket</var> .
256
+ </ol>
257
+
258
+
259
+ <h3 id=storage-proxy-maps>Storage proxy maps</h3>
260
+
261
+ <p> A <dfn>storage proxy map</dfn> is equivalent to a <a for=/>map</a> , except that all operations
262
+ are instead performed on its <dfn for="storage proxy map">backing map</dfn> .
263
+
264
+ <p class="note"> This allows for the <a for="storage proxy map">backing map</a> to be replaced.
265
+
266
+ <hr>
267
+
268
+ <p> To <dfn export>obtain a storage bucket area map</dfn> , given an
269
+ <a for=/>environment settings object</a> <var> environment</var> , <a>storage type</a>
270
+ <var> type</var> , and <a>abstract storage identifier</a> <var> identifier</var> , run these steps:</p>
271
+
272
+ <ol>
273
+ <li><p> Let <var> map</var> be null.
274
+
275
+ <li><p> If <var> type</var> is "<code> storage</code> ", then set <var> map</var> to the user agent's
276
+ <a for="user agent">storage map</a> .
277
+
278
+ <li>
279
+ <p> Otherwise, if <var> type</var> is "<code> session-storage</code> ", then set <var> map</var> to
280
+ <var> environment</var> 's <span class=XXX>browsing session</span>' s
281
+ <a for="browsing session">storage map</a> .
282
+
283
+ <p class="XXX"> See
284
+ <a href="https://github.com/whatwg/html/issues/4782">whatwg/html issue #4782</a> and
285
+ <a href="https://github.com/whatwg/html/issues/5350">whatwg/html issue #5350</a> for defining
286
+ browsing session. It is roughly analogous to <a>top-level browsing context</a> except that it
287
+ cannot be replaced due to <code> Cross-Origin-Opener-Policy</code> or navigation.
288
+
289
+ <li><p> Assert: <var> map</var> is a <a for=/>storage map</a> .
290
+
291
+ <li><p> Let <var> unit</var> be the result of running <a>obtain a storage unit</a> , with
292
+ <var> map</var> , <var> environment</var> , and <var> type</var> .
293
+
294
+ <li><p> If <var> unit</var> is failure, then return failure.
295
+
296
+ <li><p> Let <var> bucket</var> be <var> unit</var> 's
297
+ <a for="storage unit">map</a> ["<code>default</code>"] .
298
+
299
+ <li><p> Let <var> area</var> be <var> bucket</var> 's
300
+ <a for="storage bucket">map</a> [<var>identifier</var>] .
301
+
302
+ <li><p> Let <var> proxyMap</var> be a new <a>storage proxy map</a> whose
303
+ <a for="storage proxy map">backing map</a> is <var> area</var> 's
304
+ <a for="storage bucket/area">map</a> .
305
+
306
+ <li><p> Append a reference to <var> proxyMap</var> to <var> area</var> 's
307
+ <a for="storage bucket/area">proxy map reference set</a> .
308
+
309
+ <li><p> Return <var> proxyMap</var> .
310
+ </ol>
121
311
122
312
123
313
124
314
<h2 id=persistence>Persistence permission</h2>
125
315
126
- <p> A <a>bucket</a> can only be turned into a <a>persistent bucket</a> if the user (or user agent
127
- on behalf of the user) has granted permission to use the {{"persistent-storage"}} feature.
316
+ <p> A <a>storage bucket</a> can only have its <a for="storage bucket">mode</a> change to
317
+ "<code> persistent</code> " if the user (or user agent on behalf of the user) has granted permission
318
+ to use the {{"persistent-storage"}} feature.
128
319
129
320
<p class="note"> When granted to an <a for=/>origin</a> , the persistence permission can be used to
130
321
protect storage from the user agent's clearing policies. The user agent cannot clear storage marked
@@ -142,29 +333,29 @@ locally.
142
333
143
334
<dt> <a>permission revocation algorithm</a> </dt>
144
335
<dd algorithm="permission-revocation"> If {{"persistent-storage"}} 's <a>permission state</a> is not
145
- {{"granted"}} , then set the current <a for=/>origin</a> ’s <a>storage unit</a> 's <a>bucket</a>' s
146
- <a for=bucket>mode</a> to "<code> best-effort</code> ".</dd>
336
+ {{"granted"}} , then set the current <a for=/>origin</a> ’s <a>storage unit</a> 's
337
+ <a>storage bucket</a> 's <a for="storage bucket">mode</a> to "<code> best-effort</code> ".</dd>
338
+ <!-- XXX -->
147
339
</dl>
148
340
149
341
150
342
151
343
<h2 id=usage-and-quota>Usage and quota</h2>
152
344
153
- <p> The <dfn export>storage usage</dfn> of an <a for=/>origin</a> <var> origin </var > is a rough
154
- estimate of the amount of bytes used in <var> origin </var> 's <a>storage unit</a> .
345
+ <p> The <dfn export>storage usage</dfn> of a <a>storage unit</a > is a rough estimate of the amount
346
+ of bytes used by it .
155
347
156
348
<p class=note> This cannot be an exact amount as user agents might, and are encouraged to, use
157
- deduplication, compression, and other techniques that obscure exactly how much bytes an
158
- <a for=/>origin </a> uses.
349
+ deduplication, compression, and other techniques that obscure exactly how much bytes a
350
+ <a>storage unit </a> uses.
159
351
160
- <p> The <dfn export>storage quota</dfn> of an <a for=/>origin</a> <var> origin </var > is a conservative
161
- estimate of the amount of bytes available to <var> origin </var> 's <a>storage unit</a> . This amount
162
- should be less than the total available storage space on the device to give users some wiggle room.
352
+ <p> The <dfn export>storage quota</dfn> of a <a>storage unit</a > is a conservative estimate of the
353
+ amount of bytes available to it . This amount should be less than the total available storage space
354
+ on the device to give users some wiggle room.
163
355
164
- <p class=note> User agents are strongly encouraged to provide "popular" <a for=/>origins</a> with a
165
- larger <a>storage quota</a> . Factors such as navigation frequency, recency of visits, bookmarking,
166
- and <a href="#persistence">permission</a> for {{"persistent-storage"}} can be used as indications of
167
- "popularity".
356
+ <p class=note> User agents are strongly encouraged to consider navigation frequency, recency of
357
+ visits, bookmarking, and <a href="#persistence">permission</a> for {{"persistent-storage"}} when
358
+ evaluating quotas.
168
359
169
360
170
361
@@ -229,19 +420,20 @@ these steps:
229
420
<ol>
230
421
<li><p> Let <var> promise</var> be a new promise.
231
422
232
- <li><p> Let <var> origin</var> be <a>context object</a> 's <a>relevant settings object</a>' s
233
- <a for="environment settings object">origin</a> .
423
+ <li><p> Let <var> unit</var> be the result of running <a>obtain a storage unit</a> with the user
424
+ agent's <a for="user agent">storage map</a> , <a>this</a> 's <a>relevant settings object</a> , and
425
+ "<code> storage</code> ".
234
426
235
- <li><p> If <var> origin</var> is an <a>opaque origin</a> , then reject <var> promise</var> with a
236
- {{TypeError}} .
427
+ <li><p> If <var> unit</var> is a failure, then reject <var> promise</var> with a {{TypeError}} .
237
428
238
429
<li>
239
430
<p> Otherwise, run these steps <a>in parallel</a> :
240
431
241
432
<ol>
242
433
<li>
243
- <p> Let <var> persisted</var> be true if <var> origin</var> 's <a>storage unit</a>' s <a>bucket</a>
244
- is a <a>persistent bucket</a> , and false otherwise.
434
+ <p> Let <var> persisted</var> be true if <var> unit</var> 's
435
+ <a for="storage unit">map</a> ["<code>default</code>"] 's <a for="storage bucket">mode</a> is
436
+ "<code> persistent</code> "; otherwise false.
245
437
246
438
<p class=note> It will be false when there's an internal error.
247
439
@@ -257,11 +449,11 @@ these steps:
257
449
<ol>
258
450
<li><p> Let <var> promise</var> be a new promise.
259
451
260
- <li><p> Let <var> origin</var> be <a>context object</a> 's <a>relevant settings object</a>' s
261
- <a for="environment settings object">origin</a> .
452
+ <li><p> Let <var> unit</var> be the result of running <a>obtain a storage unit</a> with the user
453
+ agent's <a for="user agent">storage map</a> , <a>this</a> 's <a>relevant settings object</a> , and
454
+ "<code> storage</code> ".
262
455
263
- <li><p> If <var> origin</var> is an <a>opaque origin</a> , then reject <var> promise</var> with a
264
- {{TypeError}} .
456
+ <li><p> If <var> unit</var> is a failure, then reject <var> promise</var> with a {{TypeError}} .
265
457
266
458
<li>
267
459
<p> Otherwise, run these steps <a>in parallel</a> :
@@ -275,18 +467,20 @@ these steps:
275
467
the same <a for=/>origin</a> around the same time and this algorithm is not equipped to handle
276
468
such a scenario.
277
469
470
+ <li><p> Let <var> bucket</var> be <var> unit</var> 's
471
+ <a for="storage unit">map</a> ["<code>default</code>"] .
472
+
278
473
<li>
279
- <p> Let <var> persisted</var> be true, if <var> origin </var> 's <a> storage unit</a>' s <a>bucket< /a>
280
- is a <a >persistent bucket</a> , and false otherwise .
474
+ <p> Let <var> persisted</var> be true if <var> bucket </var> 's <a for=" storage bucket">mode< /a> is
475
+ " <code > persistent</code> "; otherwise false.
281
476
282
477
<p class=note> It will be false when there's an internal error.
283
478
284
479
<li>
285
480
<p> If <var> persisted</var> is false and <var> permission</var> is {{"granted"}} , then:
286
481
287
482
<ol>
288
- <li><p> Set <var> origin</var> 's <a>storage unit</a>' s <a>bucket</a> 's <a>mode</a> to
289
- "<code> persistent</code> ".
483
+ <li><p> Set <var> bucket</var> 's <a for="storage bucket">mode</a> to "<code> persistent</code> ".
290
484
291
485
<li><p> If there was no internal error, then set <var> persisted</var> to true.
292
486
</ol>
@@ -303,19 +497,19 @@ these steps:
303
497
<ol>
304
498
<li><p> Let <var> promise</var> be a new promise.
305
499
306
- <li><p> Let <var> origin</var> be <a>context object</a> 's <a>relevant settings object</a>' s
307
- <a for="environment settings object">origin</a> .
500
+ <li><p> Let <var> unit</var> be the result of running <a>obtain a storage unit</a> with the user
501
+ agent's <a for="user agent">storage map</a> , <a>this</a> 's <a>relevant settings object</a> , and
502
+ "<code> storage</code> ".
308
503
309
- <li><p> If <var> origin</var> is an <a>opaque origin</a> , then reject <var> promise</var> with a
310
- {{TypeError}} .
504
+ <li><p> If <var> unit</var> is a failure, then reject <var> promise</var> with a {{TypeError}} .
311
505
312
506
<li>
313
507
<p> Otherwise, run these steps <a>in parallel</a> :
314
508
315
509
<ol>
316
- <li><p> Let <var> usage</var> be <a>storage usage</a> for <var> origin </var> .
510
+ <li><p> Let <var> usage</var> be <a>storage usage</a> for <var> unit </var> .
317
511
318
- <li><p> Let <var> quota</var> be <a>storage quota</a> for <var> origin </var> .
512
+ <li><p> Let <var> quota</var> be <a>storage quota</a> for <var> unit </var> .
319
513
320
514
<li><p> Let <var> dictionary</var> be a new {{StorageEstimate}} dictionary whose {{usage}} member
321
515
is <var> usage</var> and {{quota}} member is <var> quota</var> .
0 commit comments