summaryrefslogtreecommitdiffstats
path: root/testing/web-platform/tests/shared-storage
diff options
context:
space:
mode:
authorDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-19 00:47:55 +0000
committerDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-19 00:47:55 +0000
commit26a029d407be480d791972afb5975cf62c9360a6 (patch)
treef435a8308119effd964b339f76abb83a57c29483 /testing/web-platform/tests/shared-storage
parentInitial commit. (diff)
downloadfirefox-26a029d407be480d791972afb5975cf62c9360a6.tar.xz
firefox-26a029d407be480d791972afb5975cf62c9360a6.zip
Adding upstream version 124.0.1.upstream/124.0.1
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'testing/web-platform/tests/shared-storage')
-rw-r--r--testing/web-platform/tests/shared-storage/add-module.tentative.https.sub.html25
-rw-r--r--testing/web-platform/tests/shared-storage/blob-module-script-url-invalid-mime-type.tentative.https.sub.html35
-rw-r--r--testing/web-platform/tests/shared-storage/blob-module-script-url.tentative.https.sub.html48
-rw-r--r--testing/web-platform/tests/shared-storage/combined-setters-and-operations.tentative.https.sub.html49
-rw-r--r--testing/web-platform/tests/shared-storage/embedder-context.tentative.https.sub.html109
-rw-r--r--testing/web-platform/tests/shared-storage/insecure-context.tentative.http.html10
-rw-r--r--testing/web-platform/tests/shared-storage/resources/cors-redirect.py21
-rw-r--r--testing/web-platform/tests/shared-storage/resources/credentials-test-helper.py22
-rw-r--r--testing/web-platform/tests/shared-storage/resources/delete-key.https.html19
-rw-r--r--testing/web-platform/tests/shared-storage/resources/delete-key.https.html.headers1
-rw-r--r--testing/web-platform/tests/shared-storage/resources/embedder-context-inner.https.html23
-rw-r--r--testing/web-platform/tests/shared-storage/resources/embedder-context-inner.https.html.headers1
-rw-r--r--testing/web-platform/tests/shared-storage/resources/embedder-context-module.js16
-rw-r--r--testing/web-platform/tests/shared-storage/resources/embedder-context-nested-iframe.https.html31
-rw-r--r--testing/web-platform/tests/shared-storage/resources/embedder-context-nested-inner.https.html33
-rw-r--r--testing/web-platform/tests/shared-storage/resources/embedder-context-nested-inner.https.html.headers1
-rw-r--r--testing/web-platform/tests/shared-storage/resources/frame0.html14
-rw-r--r--testing/web-platform/tests/shared-storage/resources/frame0.html.headers1
-rw-r--r--testing/web-platform/tests/shared-storage/resources/frame1.html14
-rw-r--r--testing/web-platform/tests/shared-storage/resources/frame1.html.headers1
-rw-r--r--testing/web-platform/tests/shared-storage/resources/register-service-worker-iframe.https.html66
-rw-r--r--testing/web-platform/tests/shared-storage/resources/report.py25
-rw-r--r--testing/web-platform/tests/shared-storage/resources/select-url-permissions-policy-helper.html18
-rw-r--r--testing/web-platform/tests/shared-storage/resources/sender0.html21
-rw-r--r--testing/web-platform/tests/shared-storage/resources/sender0.html.headers1
-rw-r--r--testing/web-platform/tests/shared-storage/resources/set-key-value.https.html20
-rw-r--r--testing/web-platform/tests/shared-storage/resources/shared-storage-permissions-policy-helper.html18
-rw-r--r--testing/web-platform/tests/shared-storage/resources/shared-storage-writable-fetch-request-fallback-to-network-iframe.https.html56
-rw-r--r--testing/web-platform/tests/shared-storage/resources/shared-storage-writable-fetch-request-fallback-to-network-worker.js15
-rw-r--r--testing/web-platform/tests/shared-storage/resources/shared-storage-writable-iframe-in-fenced-inner.https.sub.html29
-rw-r--r--testing/web-platform/tests/shared-storage/resources/shared-storage-writable-iframe-in-fenced-inner.https.sub.html.headers1
-rw-r--r--testing/web-platform/tests/shared-storage/resources/shared-storage-writable-pixel-write.pngbin0 -> 119 bytes
-rw-r--r--testing/web-platform/tests/shared-storage/resources/shared-storage-writable-pixel-write.png.sub.headers3
-rw-r--r--testing/web-platform/tests/shared-storage/resources/shared-storage-writable-pixel.pngbin0 -> 119 bytes
-rw-r--r--testing/web-platform/tests/shared-storage/resources/shared-storage-writable-pixel.png.sub.headers3
-rw-r--r--testing/web-platform/tests/shared-storage/resources/shared-storage-write-notify-parent.py23
-rw-r--r--testing/web-platform/tests/shared-storage/resources/shared-storage-write.py16
-rw-r--r--testing/web-platform/tests/shared-storage/resources/simple-module.js53
-rw-r--r--testing/web-platform/tests/shared-storage/resources/util.js217
-rw-r--r--testing/web-platform/tests/shared-storage/resources/util.sub.js117
-rw-r--r--testing/web-platform/tests/shared-storage/resources/verify-get-undefined-module.js17
-rw-r--r--testing/web-platform/tests/shared-storage/resources/verify-key-not-found.https.html34
-rw-r--r--testing/web-platform/tests/shared-storage/resources/verify-key-value.https.html34
-rw-r--r--testing/web-platform/tests/shared-storage/resources/verify-key-value.https.html.headers1
-rw-r--r--testing/web-platform/tests/shared-storage/resources/verify-shared-storage.https.html13
-rw-r--r--testing/web-platform/tests/shared-storage/resources/verify-storage-entries-module.js26
-rw-r--r--testing/web-platform/tests/shared-storage/run-operation-in-detached-frame.tentative.https.sub.html22
-rw-r--r--testing/web-platform/tests/shared-storage/run-operation-keep-alive.tentative.https.sub.html34
-rw-r--r--testing/web-platform/tests/shared-storage/run-operation.tentative.https.sub.html35
-rw-r--r--testing/web-platform/tests/shared-storage/run-url-selection-operation-without-add-module.tentative.https.sub.html30
-rw-r--r--testing/web-platform/tests/shared-storage/run-url-selection-operation.tentative.https.sub.html189
-rw-r--r--testing/web-platform/tests/shared-storage/same-origin-add-module-credentials-include.tentative.https.sub.html30
-rw-r--r--testing/web-platform/tests/shared-storage/same-origin-add-module-credentials-omit.tentative.https.sub.html30
-rw-r--r--testing/web-platform/tests/shared-storage/same-origin-add-module-credentials-same-origin.tentative.https.sub.html30
-rw-r--r--testing/web-platform/tests/shared-storage/same-origin-create-worklet-credentials-include.tentative.https.sub.html30
-rw-r--r--testing/web-platform/tests/shared-storage/same-origin-create-worklet-credentials-omit.tentative.https.sub.html30
-rw-r--r--testing/web-platform/tests/shared-storage/same-origin-create-worklet-credentials-same-origin.tentative.https.sub.html30
-rw-r--r--testing/web-platform/tests/shared-storage/select-url-keep-alive.tentative.https.sub.html53
-rw-r--r--testing/web-platform/tests/shared-storage/select-url-on-shared-storage-and-worklet-object-successively.tentative.https.sub.html44
-rw-r--r--testing/web-platform/tests/shared-storage/select-url-on-two-worklets.tentative.https.sub.html46
-rw-r--r--testing/web-platform/tests/shared-storage/select-url-permissions-policy-default.tentative.https.sub.html29
-rw-r--r--testing/web-platform/tests/shared-storage/select-url-permissions-policy-none.tentative.https.sub.html29
-rw-r--r--testing/web-platform/tests/shared-storage/select-url-permissions-policy-none.tentative.https.sub.html.headers1
-rw-r--r--testing/web-platform/tests/shared-storage/select-url-permissions-policy-self.tentative.https.sub.html29
-rw-r--r--testing/web-platform/tests/shared-storage/select-url-permissions-policy-self.tentative.https.sub.html.headers1
-rw-r--r--testing/web-platform/tests/shared-storage/select-url-report-event.tentative.https.sub.html65
-rw-r--r--testing/web-platform/tests/shared-storage/setters.tentative.https.sub.html76
-rw-r--r--testing/web-platform/tests/shared-storage/shared-storage-in-sandboxed-iframe.tentative.https.html41
-rw-r--r--testing/web-platform/tests/shared-storage/shared-storage-permissions-policy-default.tentative.https.sub.html29
-rw-r--r--testing/web-platform/tests/shared-storage/shared-storage-permissions-policy-none.tentative.https.sub.html29
-rw-r--r--testing/web-platform/tests/shared-storage/shared-storage-permissions-policy-none.tentative.https.sub.html.headers1
-rw-r--r--testing/web-platform/tests/shared-storage/shared-storage-permissions-policy-self.tentative.https.sub.html29
-rw-r--r--testing/web-platform/tests/shared-storage/shared-storage-permissions-policy-self.tentative.https.sub.html.headers1
-rw-r--r--testing/web-platform/tests/shared-storage/shared-storage-writable-clear.tentative.https.sub.html50
-rw-r--r--testing/web-platform/tests/shared-storage/shared-storage-writable-delete.tentative.https.sub.html52
-rw-r--r--testing/web-platform/tests/shared-storage/shared-storage-writable-forbidden-header-tentative.https.html49
-rw-r--r--testing/web-platform/tests/shared-storage/shared-storage-writable-iframe-content-attribute.tentative.https.sub.html22
-rw-r--r--testing/web-platform/tests/shared-storage/shared-storage-writable-iframe-idl-attribute-included.tentative.https.sub.html37
-rw-r--r--testing/web-platform/tests/shared-storage/shared-storage-writable-iframe-idl-attribute-not-included.tentative.https.sub.html33
-rw-r--r--testing/web-platform/tests/shared-storage/shared-storage-writable-iframe-in-fenced.tentative.https.sub.html27
-rw-r--r--testing/web-platform/tests/shared-storage/shared-storage-writable-img-content-attribute.tentative.https.sub.html22
-rw-r--r--testing/web-platform/tests/shared-storage/shared-storage-writable-img-idl-attribute-included-bytes.tentative.https.sub.html39
-rw-r--r--testing/web-platform/tests/shared-storage/shared-storage-writable-img-idl-attribute-included.tentative.https.sub.html39
-rw-r--r--testing/web-platform/tests/shared-storage/shared-storage-writable-img-idl-attribute-not-included.tentative.https.sub.html37
-rw-r--r--testing/web-platform/tests/shared-storage/shared-storage-writable-insecure-context.tentative.http.sub.html22
-rw-r--r--testing/web-platform/tests/shared-storage/shared-storage-writable-multi-redirect.tentative.https.sub.html104
-rw-r--r--testing/web-platform/tests/shared-storage/shared-storage-writable-multi-redirect.tentative.https.sub.html.headers1
-rw-r--r--testing/web-platform/tests/shared-storage/shared-storage-writable-opaque-origin.tentative.https.sub.html41
-rw-r--r--testing/web-platform/tests/shared-storage/shared-storage-writable-permissions-policy-default.tentative.https.sub.html68
-rw-r--r--testing/web-platform/tests/shared-storage/shared-storage-writable-permissions-policy-none.tentative.https.sub.html33
-rw-r--r--testing/web-platform/tests/shared-storage/shared-storage-writable-permissions-policy-none.tentative.https.sub.html.headers1
-rw-r--r--testing/web-platform/tests/shared-storage/shared-storage-writable-permissions-policy-self.tentative.https.sub.html65
-rw-r--r--testing/web-platform/tests/shared-storage/shared-storage-writable-permissions-policy-self.tentative.https.sub.html.headers1
-rw-r--r--testing/web-platform/tests/shared-storage/shared-storage-writable-service-worker-fetch.tentative.https.sub.html109
-rw-r--r--testing/web-platform/tests/shared-storage/shared-storage-writable-service-worker-iframe.tentative.https.sub.html98
-rw-r--r--testing/web-platform/tests/shared-storage/shared-storage-writable-service-worker-img.tentative.https.sub.html107
-rw-r--r--testing/web-platform/tests/shared-storage/shared-storage-writable-setters.tentative.https.sub.html47
-rw-r--r--testing/web-platform/tests/shared-storage/verify-get-undefined.tentative.https.sub.html46
98 files changed, 3444 insertions, 0 deletions
diff --git a/testing/web-platform/tests/shared-storage/add-module.tentative.https.sub.html b/testing/web-platform/tests/shared-storage/add-module.tentative.https.sub.html
new file mode 100644
index 0000000000..7859e750c9
--- /dev/null
+++ b/testing/web-platform/tests/shared-storage/add-module.tentative.https.sub.html
@@ -0,0 +1,25 @@
+<!doctype html>
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+
+<body>
+<script>
+'use strict';
+
+promise_test(async t => {
+ return promise_rejects_dom(t, "DataError",
+ sharedStorage.worklet.addModule("https://"));
+}, 'addModule with invalid url');
+
+promise_test(async t => {
+ return promise_rejects_dom(t, "DataError",
+ sharedStorage.worklet.addModule("https://foo.com"));
+}, 'addModule with cross-origin url');
+
+promise_test(() => {
+ return sharedStorage.worklet.addModule(
+ "/shared-storage/resources/simple-module.js");
+}, 'addModule');
+
+</script>
+</body>
diff --git a/testing/web-platform/tests/shared-storage/blob-module-script-url-invalid-mime-type.tentative.https.sub.html b/testing/web-platform/tests/shared-storage/blob-module-script-url-invalid-mime-type.tentative.https.sub.html
new file mode 100644
index 0000000000..116facbcd5
--- /dev/null
+++ b/testing/web-platform/tests/shared-storage/blob-module-script-url-invalid-mime-type.tentative.https.sub.html
@@ -0,0 +1,35 @@
+<!doctype html>
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="/common/utils.js"></script>
+<script src="/shared-storage/resources/util.js"></script>
+<script src="/fenced-frame/resources/utils.js"></script>
+
+<body>
+<script>
+'use strict';
+
+promise_test(async t => {
+ let module_content = `
+ class TestURLSelectionOperation {
+ async run(urls, data) {
+ if (data && data.hasOwnProperty('mockResult')) {
+ return data['mockResult'];
+ }
+
+ return -1;
+ }
+ }
+
+ register('test-url-selection-operation', TestURLSelectionOperation);
+ `
+
+ let blob = new Blob([module_content], {type: 'text/plain'});
+
+ return promise_rejects_dom(t, "OperationError",
+ sharedStorage.worklet.addModule(URL.createObjectURL(blob))
+ );
+}, 'addModule() with a Blob URL that has an unsupported mime type');
+
+</script>
+</body>
diff --git a/testing/web-platform/tests/shared-storage/blob-module-script-url.tentative.https.sub.html b/testing/web-platform/tests/shared-storage/blob-module-script-url.tentative.https.sub.html
new file mode 100644
index 0000000000..53e47a0c87
--- /dev/null
+++ b/testing/web-platform/tests/shared-storage/blob-module-script-url.tentative.https.sub.html
@@ -0,0 +1,48 @@
+<!doctype html>
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="/common/utils.js"></script>
+<script src="/shared-storage/resources/util.js"></script>
+<script src="/fenced-frame/resources/utils.js"></script>
+
+<body>
+<script>
+'use strict';
+
+promise_test(async () => {
+ let module_content = `
+ class TestURLSelectionOperation {
+ async run(urls, data) {
+ if (data && data.hasOwnProperty('mockResult')) {
+ return data['mockResult'];
+ }
+
+ return -1;
+ }
+ }
+
+ register('test-url-selection-operation', TestURLSelectionOperation);
+ `
+
+ let blob = new Blob([module_content], {type: 'text/javascript'});
+
+ await sharedStorage.worklet.addModule(URL.createObjectURL(blob));
+
+ const ancestor_key = token();
+ let url0 = generateURL("/shared-storage/resources/frame0.html",
+ [ancestor_key]);
+ let url1 = generateURL("/shared-storage/resources/frame1.html",
+ [ancestor_key]);
+
+ let select_url_result1 = await sharedStorage.selectURL(
+ "test-url-selection-operation", [{url: url0}, {url: url1}],
+ {data: {'mockResult': 1}, resolveToConfig: true,
+ keepAlive: true});
+ assert_true(validateSelectURLResult(select_url_result1, /*resolve_to_config=*/true));
+ attachFencedFrame(select_url_result1, 'opaque-ads');
+ const result1 = await nextValueFromServer(ancestor_key);
+ assert_equals(result1, "frame1_loaded");
+}, 'addModule() with a Blob URL');
+
+</script>
+</body>
diff --git a/testing/web-platform/tests/shared-storage/combined-setters-and-operations.tentative.https.sub.html b/testing/web-platform/tests/shared-storage/combined-setters-and-operations.tentative.https.sub.html
new file mode 100644
index 0000000000..2c544b9b8e
--- /dev/null
+++ b/testing/web-platform/tests/shared-storage/combined-setters-and-operations.tentative.https.sub.html
@@ -0,0 +1,49 @@
+<!doctype html>
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="/common/utils.js"></script>
+<script src="/shared-storage/resources/util.js"></script>
+<script src="/fenced-frame/resources/utils.js"></script>
+
+<body>
+<script>
+'use strict';
+
+for (const resolve_to_config of [true, false]) {
+ promise_test(async () => {
+ const ancestor_key = token();
+ let url0 = generateURL("/shared-storage/resources/frame0.html",
+ [ancestor_key]);
+ let url1 = generateURL("/shared-storage/resources/frame1.html",
+ [ancestor_key]);
+ let url2 = generateURL("/shared-storage/resources/frame2.html",
+ [ancestor_key]);
+
+ await sharedStorage.set('key0-set-from-document', 'value0');
+ await addModuleOnce(
+ "/shared-storage/resources/verify-storage-entries-module.js");
+ await sharedStorage.run("set-key0-operation", {keepAlive: true});
+
+ let select_url_result = await sharedStorage.selectURL(
+ "verify-storage-entries-url-selection-operation",
+ [{url: url0,
+ reportingMetadata: {'click':
+ "/shared-storage/resources/frame0.html"}},
+ {url: url1,
+ reportingMetadata:
+ {'mouse interaction': "/shared-storage/resources/frame1.html",
+ 'click': "/shared-storage/resources/frame2.html"}}],
+ {resolveToConfig: resolve_to_config, keepAlive: resolve_to_config});
+
+ assert_true(validateSelectURLResult(select_url_result, resolve_to_config));
+ attachFencedFrame(select_url_result, 'opaque-ads');
+
+ // frame1_loaded implies that the setters and the operations were successful.
+ assert_equals(await nextValueFromServer(ancestor_key), "frame1_loaded");
+
+ }, 'verify-storage-entries-url-selection-operation selectURL() resolves to ' +
+ (resolve_to_config ? 'config' : 'urn:uuid'));
+}
+
+</script>
+</body>
diff --git a/testing/web-platform/tests/shared-storage/embedder-context.tentative.https.sub.html b/testing/web-platform/tests/shared-storage/embedder-context.tentative.https.sub.html
new file mode 100644
index 0000000000..44f45a7643
--- /dev/null
+++ b/testing/web-platform/tests/shared-storage/embedder-context.tentative.https.sub.html
@@ -0,0 +1,109 @@
+<!doctype html>
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="/common/utils.js"></script>
+<script src="/common/get-host-info.sub.js"></script>
+<script src="/shared-storage/resources/util.js"></script>
+<script src="/fenced-frame/resources/utils.js"></script>
+
+<body>
+<script>
+'use strict';
+
+promise_test(async () => {
+ const ancestorKey = token();
+
+ let fencedFrameConfig0 = await runSelectURL(
+ "/shared-storage/resources/embedder-context-inner.https.html",
+ [ancestorKey], true);
+ assert_true(validateSelectURLResult(fencedFrameConfig0, true));
+
+ fencedFrameConfig0.setSharedStorageContext("here is some context");
+
+ attachFencedFrame(fencedFrameConfig0, 'opaque-ads');
+ const result0 = await nextValueFromServer(ancestorKey);
+ assert_equals(result0, "embedder_context_inner_loaded");
+
+ let url0 = generateURL("/shared-storage/resources/frame0.html", [ancestorKey]);
+ let url1 = generateURL("/shared-storage/resources/frame1.html", [ancestorKey]);
+
+ let fencedFrameConfig1 = await sharedStorage.selectURL(
+ "verify-key-value", [{url: url0}, {url: url1}],
+ {data: {'expectedKey': ancestorKey,
+ 'expectedValue': 'here is some context'},
+ resolveToConfig: true,
+ keepAlive: true});
+ assert_true(validateSelectURLResult(fencedFrameConfig1, true));
+
+ attachFencedFrame(fencedFrameConfig1, 'opaque-ads');
+ const result1 = await nextValueFromServer(ancestorKey);
+ assert_equals(result1, "frame1_loaded");
+}, 'embedder sharedStorage.context');
+
+promise_test(async () => {
+ const ancestorKey = token();
+
+ let fencedFrameConfig0 = await runSelectURL(
+ "/shared-storage/resources/embedder-context-inner.https.html",
+ [ancestorKey], true);
+ assert_true(validateSelectURLResult(fencedFrameConfig0, true));
+
+ attachFencedFrame(fencedFrameConfig0, 'opaque-ads');
+ const result0 = await nextValueFromServer(ancestorKey);
+ assert_equals(result0, "embedder_context_inner_loaded");
+
+ let url0 = generateURL("/shared-storage/resources/frame0.html", [ancestorKey]);
+ let url1 = generateURL("/shared-storage/resources/frame1.html", [ancestorKey]);
+
+ let fencedFrameConfig1 = await sharedStorage.selectURL(
+ "verify-key-value", [{url: url0}, {url: url1}],
+ {data: {'expectedKey': ancestorKey, 'expectedValue': 'undefined'},
+ resolveToConfig: true,
+ keepAlive: true});
+ assert_true(validateSelectURLResult(fencedFrameConfig1, true));
+
+ attachFencedFrame(fencedFrameConfig1, 'opaque-ads');
+ const result1 = await nextValueFromServer(ancestorKey);
+ assert_equals(result1, "frame1_loaded");
+}, 'undefined embedder sharedStorage.context');
+
+promise_test(async () => {
+ const outerKey = token();
+ const innerKey0 = token();
+ const innerKey1 = token();
+
+ let fencedFrameConfig0 = await runSelectURL(
+ "/shared-storage/resources/embedder-context-nested-inner.https.html",
+ [outerKey, innerKey0, innerKey1], true);
+ assert_true(validateSelectURLResult(fencedFrameConfig0, true));
+
+ fencedFrameConfig0.setSharedStorageContext("here is some context");
+
+ attachFencedFrame(fencedFrameConfig0, 'opaque-ads');
+ const result0 = await nextValueFromServer(outerKey);
+ assert_equals(result0, "embedder_context_nested_inner_loaded");
+
+ let url0 = generateURL("/shared-storage/resources/frame0.html", [outerKey]);
+ let url1 = generateURL("/shared-storage/resources/frame1.html", [outerKey]);
+
+ let fencedFrameConfig1 = await sharedStorage.selectURL(
+ "verify-key-value", [{url: url0}, {url: url1}],
+ {data: {'expectedKey': innerKey0,
+ 'expectedValue': 'here is some context'},
+ resolveToConfig: true});
+ assert_true(validateSelectURLResult(fencedFrameConfig1, true));
+
+ attachFencedFrame(fencedFrameConfig1, 'opaque-ads');
+ const result1 = await nextValueFromServer(outerKey);
+ assert_equals(result1, "frame1_loaded");
+
+ let iframeURL =
+ generateURL("/shared-storage/resources/embedder-context-nested-iframe.https.html",
+ [outerKey, innerKey1]);
+ iframeURL = getRemoteOriginURL(iframeURL);
+ attachIFrame(iframeURL);
+ const result2 = await nextValueFromServer(outerKey);
+ assert_equals(result2, "embedder_context_nested_iframe_loaded");
+}, 'embedder sharedStorage.context with nested iframes');
+</script>
+</body>
diff --git a/testing/web-platform/tests/shared-storage/insecure-context.tentative.http.html b/testing/web-platform/tests/shared-storage/insecure-context.tentative.http.html
new file mode 100644
index 0000000000..7ddf02f861
--- /dev/null
+++ b/testing/web-platform/tests/shared-storage/insecure-context.tentative.http.html
@@ -0,0 +1,10 @@
+<!doctype html>
+<body>
+ <script src=/resources/testharness.js></script>
+ <script src=/resources/testharnessreport.js></script>
+ <script>
+ test(t => {
+ assert_equals(window.sharedStorage, undefined);
+ }, 'test window.sharedStorage in insecure context');
+ </script>
+</body>
diff --git a/testing/web-platform/tests/shared-storage/resources/cors-redirect.py b/testing/web-platform/tests/shared-storage/resources/cors-redirect.py
new file mode 100644
index 0000000000..a475ee4f96
--- /dev/null
+++ b/testing/web-platform/tests/shared-storage/resources/cors-redirect.py
@@ -0,0 +1,21 @@
+def main(request, response):
+ """Simple handler that causes redirection but also adds the
+ "Access-Control-Allow-Origin: *" header.
+
+ The request should typically have two query parameters:
+ status - The status to use for the redirection. Defaults to 302.
+ location - The resource to redirect to.
+ """
+ status = 302
+ if b"status" in request.GET:
+ try:
+ status = int(request.GET.first(b"status"))
+ except ValueError:
+ pass
+
+ response.status = status
+
+ location = request.GET.first(b"location")
+
+ response.headers.set(b"Location", location)
+ response.headers.append(b"Access-Control-Allow-Origin", b"*")
diff --git a/testing/web-platform/tests/shared-storage/resources/credentials-test-helper.py b/testing/web-platform/tests/shared-storage/resources/credentials-test-helper.py
new file mode 100644
index 0000000000..81a988e358
--- /dev/null
+++ b/testing/web-platform/tests/shared-storage/resources/credentials-test-helper.py
@@ -0,0 +1,22 @@
+def main(request, response):
+ """
+ A handler that does either one of the following based on the provided
+ "action" parameter:
+ 1) action="store-cookie": Stores the provided token and the request cookie
+ to the stash, and returns a regular module script content.
+ 2) action="get-cookie": Retrieves and returns the content stored in the
+ stash at the provided token.
+ """
+ token = request.GET[b"token"]
+ action = request.GET[b"action"]
+
+ response.status = 200
+ response.headers.append(b"Content-Type", b"text/javascript")
+
+ if action == b"store-cookie":
+ cookie = request.headers.get(b"Cookie", b"NO_COOKIE_HEADER")
+ request.server.stash.put(token, cookie)
+ return b""
+ else:
+ assert action == b"get-cookie"
+ return request.server.stash.take(token)
diff --git a/testing/web-platform/tests/shared-storage/resources/delete-key.https.html b/testing/web-platform/tests/shared-storage/resources/delete-key.https.html
new file mode 100644
index 0000000000..41595f3ee3
--- /dev/null
+++ b/testing/web-platform/tests/shared-storage/resources/delete-key.https.html
@@ -0,0 +1,19 @@
+<!DOCTYPE html>
+<html>
+<script src=/resources/testharness.js></script>
+<script src=/shared-storage/resources/util.js></script>
+<script src=/fenced-frame/resources/utils.js></script>
+<body>
+<script>
+
+async function init() {
+ const [outerKey] = parseKeylist();
+ const parsedData = parseExpectedKeyData();
+ await sharedStorage.delete(parsedData['expectedKey']);
+ await writeValueToServer(outerKey, "delete_key_loaded");
+}
+
+init();
+</script>
+</body>
+</html>
diff --git a/testing/web-platform/tests/shared-storage/resources/delete-key.https.html.headers b/testing/web-platform/tests/shared-storage/resources/delete-key.https.html.headers
new file mode 100644
index 0000000000..1b63235b7c
--- /dev/null
+++ b/testing/web-platform/tests/shared-storage/resources/delete-key.https.html.headers
@@ -0,0 +1 @@
+Supports-Loading-Mode: fenced-frame
diff --git a/testing/web-platform/tests/shared-storage/resources/embedder-context-inner.https.html b/testing/web-platform/tests/shared-storage/resources/embedder-context-inner.https.html
new file mode 100644
index 0000000000..e4b59f7f7a
--- /dev/null
+++ b/testing/web-platform/tests/shared-storage/resources/embedder-context-inner.https.html
@@ -0,0 +1,23 @@
+<!DOCTYPE html>
+<html>
+<script src="/shared-storage/resources/util.js"></script>
+<script src="/fenced-frame/resources/utils.js"></script>
+<body>
+<script>
+
+async function init() {
+ const [ancestorKey] = parseKeylist();
+
+ await addModuleOnce("/shared-storage/resources/embedder-context-module.js");
+ await sharedStorage.run("report-context",
+ {
+ data: {'ancestorKey': ancestorKey}
+ });
+
+ await writeValueToServer(ancestorKey, "embedder_context_inner_loaded");
+}
+
+init();
+</script>
+</body>
+</html>
diff --git a/testing/web-platform/tests/shared-storage/resources/embedder-context-inner.https.html.headers b/testing/web-platform/tests/shared-storage/resources/embedder-context-inner.https.html.headers
new file mode 100644
index 0000000000..1b63235b7c
--- /dev/null
+++ b/testing/web-platform/tests/shared-storage/resources/embedder-context-inner.https.html.headers
@@ -0,0 +1 @@
+Supports-Loading-Mode: fenced-frame
diff --git a/testing/web-platform/tests/shared-storage/resources/embedder-context-module.js b/testing/web-platform/tests/shared-storage/resources/embedder-context-module.js
new file mode 100644
index 0000000000..782b97aea9
--- /dev/null
+++ b/testing/web-platform/tests/shared-storage/resources/embedder-context-module.js
@@ -0,0 +1,16 @@
+// Copyright 2023 The Chromium Authors
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+class ReportContext {
+ async run(data) {
+ if (!data || !data.hasOwnProperty('ancestorKey')) {
+ return;
+ }
+ const ancestorKey = data['ancestorKey'];
+ const context = sharedStorage.context;
+ await sharedStorage.set(ancestorKey, context);
+ }
+}
+
+register('report-context', ReportContext);
diff --git a/testing/web-platform/tests/shared-storage/resources/embedder-context-nested-iframe.https.html b/testing/web-platform/tests/shared-storage/resources/embedder-context-nested-iframe.https.html
new file mode 100644
index 0000000000..2ba25d1ed9
--- /dev/null
+++ b/testing/web-platform/tests/shared-storage/resources/embedder-context-nested-iframe.https.html
@@ -0,0 +1,31 @@
+<!DOCTYPE html>
+<html>
+<script src="/resources/testharness.js"></script>
+<script src="/shared-storage/resources/util.js"></script>
+<script src="/fenced-frame/resources/utils.js"></script>
+<body>
+<script>
+
+async function init() {
+ const [outerKey, innerKey] = parseKeylist();
+ let url0 = generateURL("/shared-storage/resources/frame0.html", [innerKey]);
+ let url1 = generateURL("/shared-storage/resources/frame1.html", [innerKey]);
+
+ await addModuleOnce("simple-module.js");
+ let fencedFrameConfig = await sharedStorage.selectURL(
+ "verify-key-value", [{url: url0}, {url: url1}],
+ {data: {'expectedKey': innerKey, 'expectedValue': 'undefined'},
+ resolveToConfig: true});
+ assert_true(validateSelectURLResult(fencedFrameConfig, true));
+
+ attachFencedFrame(fencedFrameConfig, 'opaque-ads');
+ const result = await nextValueFromServer(innerKey);
+ assert_equals(result, "frame1_loaded");
+
+ await writeValueToServer(outerKey, "embedder_context_nested_iframe_loaded");
+}
+
+init();
+</script>
+</body>
+</html>
diff --git a/testing/web-platform/tests/shared-storage/resources/embedder-context-nested-inner.https.html b/testing/web-platform/tests/shared-storage/resources/embedder-context-nested-inner.https.html
new file mode 100644
index 0000000000..c704a00b73
--- /dev/null
+++ b/testing/web-platform/tests/shared-storage/resources/embedder-context-nested-inner.https.html
@@ -0,0 +1,33 @@
+<!DOCTYPE html>
+<html>
+<script src="/resources/testharness.js"></script>
+<script src="/common/get-host-info.sub.js"></script>
+<script src="/fenced-frame/resources/utils.js"></script>
+<body>
+<script>
+async function init() {
+ const [outerKey, innerKey0, innerKey1] = parseKeylist();
+ let url0 = generateURL(
+ "/shared-storage/resources/embedder-context-inner.https.html",
+ [innerKey0]);
+
+ attachIFrame(url0);
+ const result0 = await nextValueFromServer(innerKey0);
+ assert_equals(result0, "embedder_context_inner_loaded");
+
+ let url1 = generateURL(
+ "/shared-storage/resources/embedder-context-inner.https.html",
+ [innerKey1]);
+ url1 = getRemoteOriginURL(url1);
+
+ attachIFrame(url1);
+ const result1 = await nextValueFromServer(innerKey1);
+ assert_equals(result1, "embedder_context_inner_loaded");
+
+ await writeValueToServer(outerKey, "embedder_context_nested_inner_loaded");
+}
+
+init();
+</script>
+</body>
+</html>
diff --git a/testing/web-platform/tests/shared-storage/resources/embedder-context-nested-inner.https.html.headers b/testing/web-platform/tests/shared-storage/resources/embedder-context-nested-inner.https.html.headers
new file mode 100644
index 0000000000..1b63235b7c
--- /dev/null
+++ b/testing/web-platform/tests/shared-storage/resources/embedder-context-nested-inner.https.html.headers
@@ -0,0 +1 @@
+Supports-Loading-Mode: fenced-frame
diff --git a/testing/web-platform/tests/shared-storage/resources/frame0.html b/testing/web-platform/tests/shared-storage/resources/frame0.html
new file mode 100644
index 0000000000..c9b559fe83
--- /dev/null
+++ b/testing/web-platform/tests/shared-storage/resources/frame0.html
@@ -0,0 +1,14 @@
+<!DOCTYPE html>
+<html>
+<script src="/fenced-frame/resources/utils.js"></script>
+<body>
+<script>
+async function init() {
+ const [ancestor_key] = parseKeylist();
+ writeValueToServer(ancestor_key, "frame0_loaded");
+}
+
+init();
+</script>
+</body>
+</html>
diff --git a/testing/web-platform/tests/shared-storage/resources/frame0.html.headers b/testing/web-platform/tests/shared-storage/resources/frame0.html.headers
new file mode 100644
index 0000000000..1b63235b7c
--- /dev/null
+++ b/testing/web-platform/tests/shared-storage/resources/frame0.html.headers
@@ -0,0 +1 @@
+Supports-Loading-Mode: fenced-frame
diff --git a/testing/web-platform/tests/shared-storage/resources/frame1.html b/testing/web-platform/tests/shared-storage/resources/frame1.html
new file mode 100644
index 0000000000..a34990dc03
--- /dev/null
+++ b/testing/web-platform/tests/shared-storage/resources/frame1.html
@@ -0,0 +1,14 @@
+<!DOCTYPE html>
+<html>
+<script src="/fenced-frame/resources/utils.js"></script>
+<body>
+<script>
+async function init() {
+ const [ancestor_key] = parseKeylist();
+ writeValueToServer(ancestor_key, "frame1_loaded");
+}
+
+init();
+</script>
+</body>
+</html>
diff --git a/testing/web-platform/tests/shared-storage/resources/frame1.html.headers b/testing/web-platform/tests/shared-storage/resources/frame1.html.headers
new file mode 100644
index 0000000000..1b63235b7c
--- /dev/null
+++ b/testing/web-platform/tests/shared-storage/resources/frame1.html.headers
@@ -0,0 +1 @@
+Supports-Loading-Mode: fenced-frame
diff --git a/testing/web-platform/tests/shared-storage/resources/register-service-worker-iframe.https.html b/testing/web-platform/tests/shared-storage/resources/register-service-worker-iframe.https.html
new file mode 100644
index 0000000000..547ab1d93d
--- /dev/null
+++ b/testing/web-platform/tests/shared-storage/resources/register-service-worker-iframe.https.html
@@ -0,0 +1,66 @@
+<!doctype html>
+<body>
+ <script src=/resources/testharness.js></script>
+ <script src=/common/utils.js></script>
+ <script src=/fenced-frame/resources/utils.js></script>
+ <script src=/shared-storage/resources/util.js></script>
+ <script src=/shared-storage/resources/util.sub.js></script>
+ <script src=/service-workers/service-worker/resources/test-helpers.sub.js></script>
+ <script>
+ const INTERMEDIATE_FRAME_SUFFIX =
+ 'able-fetch-request-fallback-to-network-iframe.https.html'
+ const ORIGIN = new URL("", location.href).origin;
+
+ window.addEventListener('message', async function handler(event) {
+ const data = event.data;
+ if (data.script && data.scope && data.port) {
+ var absoluteScope = (new URL(data.scope, window.location).href);
+ let oldReg =await navigator.serviceWorker.getRegistration(data.scope);
+ if (oldReg && oldReg.scope === absoluteScope) {
+ await oldReg.unregister();
+ }
+ let reg = await navigator.serviceWorker.register(data.script,
+ { scope: data.scope });
+ let worker = reg.installing;
+ await new Promise(function(resolve) {
+ worker.addEventListener('statechange', function() {
+ if (worker.state == 'activated') {
+ resolve();
+ }
+ });
+ });
+ assert_not_equals(worker, null, 'worker is installing');
+
+ let result = await loadNestedSharedStorageFrameInNewFrame({
+ key: 'c', value: 'd',
+ hasSharedStorageWritableAttribute: true,
+ // Same-origin to this frame, cross-origin to top.
+ isSameOrigin: true,
+ });
+ const urls = [
+ {
+ "url": ORIGIN + data.scope + INTERMEDIATE_FRAME_SUFFIX,
+ "mode": "navigate",
+ "SSWHeader": "null"
+ },
+ {
+ "url": ORIGIN + "/resources/testharness.js",
+ "mode": "no-cors",
+ "SSWHeader": "null"
+ },
+ {
+ "url": ORIGIN + result.nestedFrameUrl,
+ "mode": "navigate",
+ "SSWHeader": "null"
+ },
+ ];
+ await checkInterceptedUrls(worker, urls);
+ await verifyKeyValueForOrigin('c', 'd', ORIGIN);
+ await deleteKeyForOrigin('c', ORIGIN);
+ data.port.postMessage({msg: 'test completed'});
+ reg.unregister()
+ window.removeEventListener('message', handler);
+ }
+ });
+ </script>
+</body>
diff --git a/testing/web-platform/tests/shared-storage/resources/report.py b/testing/web-platform/tests/shared-storage/resources/report.py
new file mode 100644
index 0000000000..7d0fa36019
--- /dev/null
+++ b/testing/web-platform/tests/shared-storage/resources/report.py
@@ -0,0 +1,25 @@
+def main(request, response):
+
+ # `token` should be a unique UUID request parameter for the duration of this
+ # request. It will get stored in the server stash and will be used later in
+ # a query request.
+ # `query` should be a request parameter indicating the request would like
+ # to know how many times the server has seen the request (with the
+ # same token).
+ token = request.GET.first(b"token", None)
+ is_query = request.GET.first(b"query", None) is not None
+ with request.server.stash.lock:
+ value = request.server.stash.take(token)
+ count = 0
+ if value is not None:
+ count = int(value)
+ if is_query:
+ request.server.stash.put(token, count)
+ else:
+ count += 1
+ request.server.stash.put(token, count)
+
+ headers = []
+ if is_query:
+ headers = [(b"Count", count)]
+ return (200, headers, b"")
diff --git a/testing/web-platform/tests/shared-storage/resources/select-url-permissions-policy-helper.html b/testing/web-platform/tests/shared-storage/resources/select-url-permissions-policy-helper.html
new file mode 100644
index 0000000000..b70d763ad4
--- /dev/null
+++ b/testing/web-platform/tests/shared-storage/resources/select-url-permissions-policy-helper.html
@@ -0,0 +1,18 @@
+<!doctype html>
+<body>
+ <script src="/resources/testharness.js"></script>
+ <script src="/resources/testharnessreport.js"></script>
+ <script src="/shared-storage/resources/util.js"></script>
+ <script>
+ 'use strict';
+
+ window.onload = async function() {
+ if (await IsSharedStorageSelectUrlAllowedByPermissionsPolicy()) {
+ parent.postMessage({ type: 'availability-result', enabled: true }, '*');
+ return;
+ }
+
+ parent.postMessage({ type: 'availability-result', enabled: false }, '*');
+ }
+ </script>
+</body>
diff --git a/testing/web-platform/tests/shared-storage/resources/sender0.html b/testing/web-platform/tests/shared-storage/resources/sender0.html
new file mode 100644
index 0000000000..e3d0475f12
--- /dev/null
+++ b/testing/web-platform/tests/shared-storage/resources/sender0.html
@@ -0,0 +1,21 @@
+<!DOCTYPE html>
+<html>
+<script src="/fenced-frame/resources/utils.js"></script>
+<body>
+<script>
+async function init() {
+ const [ancestor_key] = parseKeylist();
+
+ window.fence.reportEvent({
+ eventType: 'click',
+ eventData: "user clicked",
+ destination: ['shared-storage-select-url']
+ });
+
+ writeValueToServer(ancestor_key, "sender0_reported");
+}
+
+init();
+</script>
+</body>
+</html>
diff --git a/testing/web-platform/tests/shared-storage/resources/sender0.html.headers b/testing/web-platform/tests/shared-storage/resources/sender0.html.headers
new file mode 100644
index 0000000000..1b63235b7c
--- /dev/null
+++ b/testing/web-platform/tests/shared-storage/resources/sender0.html.headers
@@ -0,0 +1 @@
+Supports-Loading-Mode: fenced-frame
diff --git a/testing/web-platform/tests/shared-storage/resources/set-key-value.https.html b/testing/web-platform/tests/shared-storage/resources/set-key-value.https.html
new file mode 100644
index 0000000000..ba0a24ceb2
--- /dev/null
+++ b/testing/web-platform/tests/shared-storage/resources/set-key-value.https.html
@@ -0,0 +1,20 @@
+<!DOCTYPE html>
+<html>
+<script src=/resources/testharness.js></script>
+<script src=/shared-storage/resources/util.js></script>
+<script src=/fenced-frame/resources/utils.js></script>
+<body>
+<script>
+
+async function init() {
+ const [outerKey] = parseKeylist();
+ const parsedData = parseExpectedKeyAndValueData();
+ await sharedStorage.set(parsedData['expectedKey'],
+ parsedData['expectedValue']);
+ await writeValueToServer(outerKey, "set_key_value_loaded");
+}
+
+init();
+</script>
+</body>
+</html>
diff --git a/testing/web-platform/tests/shared-storage/resources/shared-storage-permissions-policy-helper.html b/testing/web-platform/tests/shared-storage/resources/shared-storage-permissions-policy-helper.html
new file mode 100644
index 0000000000..d87092aad1
--- /dev/null
+++ b/testing/web-platform/tests/shared-storage/resources/shared-storage-permissions-policy-helper.html
@@ -0,0 +1,18 @@
+<!doctype html>
+<body>
+ <script src="/resources/testharness.js"></script>
+ <script src="/resources/testharnessreport.js"></script>
+ <script src="/shared-storage/resources/util.js"></script>
+ <script>
+ 'use strict';
+
+ window.onload = async function() {
+ if (await AreSharedStorageMethodsAllowedByPermissionsPolicy()) {
+ parent.postMessage({ type: 'availability-result', enabled: true }, '*');
+ return;
+ }
+
+ parent.postMessage({ type: 'availability-result', enabled: false }, '*');
+ }
+ </script>
+</body>
diff --git a/testing/web-platform/tests/shared-storage/resources/shared-storage-writable-fetch-request-fallback-to-network-iframe.https.html b/testing/web-platform/tests/shared-storage/resources/shared-storage-writable-fetch-request-fallback-to-network-iframe.https.html
new file mode 100644
index 0000000000..3451d91477
--- /dev/null
+++ b/testing/web-platform/tests/shared-storage/resources/shared-storage-writable-fetch-request-fallback-to-network-iframe.https.html
@@ -0,0 +1,56 @@
+<!doctype html>
+<body>
+ <script src=/resources/testharness.js></script>
+ <script>
+ function loadImage(url, hasSharedStorageWritableAttribute) {
+ return new Promise(function(resolve, reject) {
+ var img = document.createElement('img');
+ document.body.appendChild(img);
+ img.onload = function() {
+ resolve(img);
+ };
+ img.onerror = function() {
+ reject(new Error('Image load failed'));
+ };
+ if (hasSharedStorageWritableAttribute) {
+ img.sharedStorageWritable = true;
+ }
+ img.src = url;
+ });
+ }
+
+ function loadFrame(url, hasSharedStorageWritableAttribute) {
+ return new Promise(function(resolve, reject) {
+ var frame = document.createElement('iframe');
+ document.body.appendChild(frame);
+ frame.onload = function() {
+ window.parent.postMessage({msg: 'iframe loaded'}, "*");
+ resolve(frame);
+ };
+ frame.onerror = function() {
+ reject(new Error('Nested iframe load failed'));
+ };
+ if (hasSharedStorageWritableAttribute) {
+ frame.sharedStorageWritable = true;
+ }
+ frame.src = url;
+ });
+ }
+
+ function fetchUrl(url, hasSharedStorageWritableAttribute) {
+ return new Promise(function(resolve, reject) {
+ fetch(url, {sharedStorageWritable:
+ hasSharedStorageWritableAttribute})
+ .then(response => {
+ if (!response.ok) {
+ throw new Error('Failed to fetch ' + url + '; '
+ + String(response.status) + ' ' + response.statusText);
+ }
+ resolve(response);
+ }).catch(error => {
+ reject(error);
+ });
+ });
+ }
+ </script>
+</body>
diff --git a/testing/web-platform/tests/shared-storage/resources/shared-storage-writable-fetch-request-fallback-to-network-worker.js b/testing/web-platform/tests/shared-storage/resources/shared-storage-writable-fetch-request-fallback-to-network-worker.js
new file mode 100644
index 0000000000..d304669ea1
--- /dev/null
+++ b/testing/web-platform/tests/shared-storage/resources/shared-storage-writable-fetch-request-fallback-to-network-worker.js
@@ -0,0 +1,15 @@
+var requests = [];
+
+self.addEventListener('message', function(event) {
+ event.data.port.postMessage({requests: requests});
+ requests = [];
+});
+
+self.addEventListener('fetch', function(event) {
+ let maybeHeader = event.request.headers.get('Sec-Shared-Storage-Writable');
+ requests.push({
+ url: event.request.url,
+ mode: event.request.mode,
+ SSWHeader: String(maybeHeader),
+ });
+});
diff --git a/testing/web-platform/tests/shared-storage/resources/shared-storage-writable-iframe-in-fenced-inner.https.sub.html b/testing/web-platform/tests/shared-storage/resources/shared-storage-writable-iframe-in-fenced-inner.https.sub.html
new file mode 100644
index 0000000000..87dbe81a2b
--- /dev/null
+++ b/testing/web-platform/tests/shared-storage/resources/shared-storage-writable-iframe-in-fenced-inner.https.sub.html
@@ -0,0 +1,29 @@
+<!doctype html>
+<body>
+ <script src=/resources/testharness.js></script>
+ <script src=/common/utils.js></script>
+ <script src=/fenced-frame/resources/utils.js></script>
+ <script src=/shared-storage/resources/util.js></script>
+ <script src=/shared-storage/resources/util.sub.js></script>
+ <script>
+
+async function init() {
+ const sameOrigin = new URL("", location.href).origin;
+ const [outerKey] = parseKeylist();
+ let {expectedKey, expectedValue} = parseExpectedKeyAndValueData();
+ const promise = navigateSharedStorageIframe({
+ hasSharedStorageWritableAttribute: true,
+ rawWriteHeader: `set;key=${expectedKey};value=${expectedValue}`,
+ isSameOrigin: true,
+ expectSharedStorageWritableHeader: true,
+ });
+ promise.then(() => {
+ verifyKeyValueForOrigin(expectedKey, expectedValue, sameOrigin);
+ deleteKeyForOrigin(expectedKey, sameOrigin);
+ writeValueToServer(outerKey, "writable_iframe_in_fenced_inner_loaded");
+ });
+}
+
+init();
+ </script>
+</body>
diff --git a/testing/web-platform/tests/shared-storage/resources/shared-storage-writable-iframe-in-fenced-inner.https.sub.html.headers b/testing/web-platform/tests/shared-storage/resources/shared-storage-writable-iframe-in-fenced-inner.https.sub.html.headers
new file mode 100644
index 0000000000..1b63235b7c
--- /dev/null
+++ b/testing/web-platform/tests/shared-storage/resources/shared-storage-writable-iframe-in-fenced-inner.https.sub.html.headers
@@ -0,0 +1 @@
+Supports-Loading-Mode: fenced-frame
diff --git a/testing/web-platform/tests/shared-storage/resources/shared-storage-writable-pixel-write.png b/testing/web-platform/tests/shared-storage/resources/shared-storage-writable-pixel-write.png
new file mode 100644
index 0000000000..818c71d03f
--- /dev/null
+++ b/testing/web-platform/tests/shared-storage/resources/shared-storage-writable-pixel-write.png
Binary files differ
diff --git a/testing/web-platform/tests/shared-storage/resources/shared-storage-writable-pixel-write.png.sub.headers b/testing/web-platform/tests/shared-storage/resources/shared-storage-writable-pixel-write.png.sub.headers
new file mode 100644
index 0000000000..9f2cb718aa
--- /dev/null
+++ b/testing/web-platform/tests/shared-storage/resources/shared-storage-writable-pixel-write.png.sub.headers
@@ -0,0 +1,3 @@
+Timing-Allow-Origin: *
+Access-Control-Allow-Origin: *
+Shared-Storage-Write: {{GET[write]}}
diff --git a/testing/web-platform/tests/shared-storage/resources/shared-storage-writable-pixel.png b/testing/web-platform/tests/shared-storage/resources/shared-storage-writable-pixel.png
new file mode 100644
index 0000000000..818c71d03f
--- /dev/null
+++ b/testing/web-platform/tests/shared-storage/resources/shared-storage-writable-pixel.png
Binary files differ
diff --git a/testing/web-platform/tests/shared-storage/resources/shared-storage-writable-pixel.png.sub.headers b/testing/web-platform/tests/shared-storage/resources/shared-storage-writable-pixel.png.sub.headers
new file mode 100644
index 0000000000..8b541e7b13
--- /dev/null
+++ b/testing/web-platform/tests/shared-storage/resources/shared-storage-writable-pixel.png.sub.headers
@@ -0,0 +1,3 @@
+Timing-Allow-Origin: *
+Access-Control-Allow-Origin: *
+Shared-Storage-Write: set;key={{GET[key]}};value={{GET[value]}}
diff --git a/testing/web-platform/tests/shared-storage/resources/shared-storage-write-notify-parent.py b/testing/web-platform/tests/shared-storage/resources/shared-storage-write-notify-parent.py
new file mode 100644
index 0000000000..63041218c8
--- /dev/null
+++ b/testing/web-platform/tests/shared-storage/resources/shared-storage-write-notify-parent.py
@@ -0,0 +1,23 @@
+from wptserve.utils import isomorphic_decode
+from wptserve.utils import isomorphic_encode
+from urllib.parse import unquote
+
+def unescape_query_value(query_value_bytes):
+ return isomorphic_encode(unquote(isomorphic_decode(query_value_bytes)))
+
+def main(request, response):
+ writable_header = request.headers.get(
+ b"Sec-Shared-Storage-Writable",
+ b"NO_SHARED_STORAGE_WRITABLE_HEADER")
+ response.headers.append(b"Content-Type", b"text/html")
+ response.headers.append(b"Access-Control-Allow-Origin", b"*")
+ response.headers.append(b"Supports-Loading-Mode", b"fenced-frame")
+ if writable_header == b"?1" and b'write' in request.GET:
+ write_header = unescape_query_value(request.GET[b'write'])
+ response.headers.append(b"Shared-Storage-Write", write_header)
+ response.content = b'''
+<script>
+ let parentOrOpener = window.opener || window.parent;
+ parentOrOpener.postMessage({ sharedStorageWritableHeader: '%s'}, "*");
+</script>
+''' % (writable_header)
diff --git a/testing/web-platform/tests/shared-storage/resources/shared-storage-write.py b/testing/web-platform/tests/shared-storage/resources/shared-storage-write.py
new file mode 100644
index 0000000000..fabe1eba26
--- /dev/null
+++ b/testing/web-platform/tests/shared-storage/resources/shared-storage-write.py
@@ -0,0 +1,16 @@
+from wptserve.utils import isomorphic_decode
+from wptserve.utils import isomorphic_encode
+from urllib.parse import unquote
+
+def unescape_query_value(query_value_bytes):
+ return isomorphic_encode(unquote(isomorphic_decode(query_value_bytes)))
+
+def main(request, response):
+ writable_header = request.headers.get(
+ b"Sec-Shared-Storage-Writable",
+ b"NO_SHARED_STORAGE_WRITABLE_HEADER")
+ response.headers.append(b"Access-Control-Allow-Origin", b"*")
+ if writable_header == b"?1" and b'write' in request.GET:
+ write_header = unescape_query_value(request.GET[b'write'])
+ response.headers.append(b"Shared-Storage-Write", write_header)
+ response.content = writable_header
diff --git a/testing/web-platform/tests/shared-storage/resources/simple-module.js b/testing/web-platform/tests/shared-storage/resources/simple-module.js
new file mode 100644
index 0000000000..620a3592f2
--- /dev/null
+++ b/testing/web-platform/tests/shared-storage/resources/simple-module.js
@@ -0,0 +1,53 @@
+// Copyright 2022 The Chromium Authors
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+var globalVar = 0;
+
+class TestURLSelectionOperation {
+ async run(urls, data) {
+ if (data && data.hasOwnProperty('mockResult')) {
+ return data['mockResult'];
+ }
+
+ return -1;
+ }
+}
+
+class IncrementGlobalVariableAndReturnOriginalValueOperation {
+ async run(urls, data) {
+ return globalVar++;
+ }
+}
+
+class VerifyKeyValue {
+ async run(urls, data) {
+ if (data && data.hasOwnProperty('expectedKey') &&
+ data.hasOwnProperty('expectedValue')) {
+ const expectedValue = data['expectedValue'];
+ const value = await sharedStorage.get(data['expectedKey']);
+ if (value === expectedValue) {
+ return 1;
+ }
+ }
+ return -1;
+ }
+}
+
+class VerifyKeyNotFound {
+ async run(urls, data) {
+ if (data && data.hasOwnProperty('expectedKey')) {
+ const value = await sharedStorage.get(data['expectedKey']);
+ if (typeof value === 'undefined') {
+ return 1;
+ }
+ }
+ return -1;
+ }
+}
+
+register('test-url-selection-operation', TestURLSelectionOperation);
+register('increment-global-variable-and-return-original-value-operation',
+ IncrementGlobalVariableAndReturnOriginalValueOperation);
+register('verify-key-value', VerifyKeyValue);
+register('verify-key-not-found', VerifyKeyNotFound);
diff --git a/testing/web-platform/tests/shared-storage/resources/util.js b/testing/web-platform/tests/shared-storage/resources/util.js
new file mode 100644
index 0000000000..4a7fcc4590
--- /dev/null
+++ b/testing/web-platform/tests/shared-storage/resources/util.js
@@ -0,0 +1,217 @@
+// META: script=/common/utils.js
+// META: script=/fenced-frame/resources/utils.js
+'use strict';
+
+async function IsSharedStorageSelectUrlAllowedByPermissionsPolicy() {
+ const errorMessage = 'The \"shared-storage-select-url\" Permissions Policy denied the usage of window.sharedStorage.selectURL().';
+ let allowedByPermissionsPolicy = true;
+ try {
+ // Run selectURL() with without addModule() and this should always fail.
+ // Check the error message to distinguish between the permissions policy
+ // error and the missing addModule() error.
+ await sharedStorage.selectURL("operation", [{url: "1.html"}]);
+ assert_unreached("did not fail");
+ } catch (e) {
+ if (e.message === errorMessage) {
+ allowedByPermissionsPolicy = false;
+ }
+ }
+
+ return allowedByPermissionsPolicy;
+}
+
+// Execute all shared storage methods and capture their errors. Return true if
+// the permissions policy allows all of them; return false if the permissions
+// policy disallows all of them. Precondition: only these two outcomes are
+// possible.
+async function AreSharedStorageMethodsAllowedByPermissionsPolicy() {
+ let permissionsPolicyDeniedCount = 0;
+ const errorMessage = 'The \"shared-storage\" Permissions Policy denied the method on window.sharedStorage.';
+
+ try {
+ await window.sharedStorage.worklet.addModule('/shared-storage/resources/simple-module.js');
+ } catch (e) {
+ assert_equals(e.message, errorMessage);
+ ++permissionsPolicyDeniedCount;
+ }
+
+ try {
+ await window.sharedStorage.run('operation');
+ } catch (e) {
+ assert_equals(e.message, errorMessage);
+ ++permissionsPolicyDeniedCount;
+ }
+
+ try {
+ // Run selectURL() with without addModule() and this should always fail.
+ // Check the error message to distinguish between the permissions policy
+ // error and the missing addModule() error.
+ await sharedStorage.selectURL("operation", [{url: "1.html"}]);
+ assert_unreached("did not fail");
+ } catch (e) {
+ if (e.message === errorMessage) {
+ ++permissionsPolicyDeniedCount;
+ }
+ }
+
+ try {
+ await window.sharedStorage.set('a', 'b');
+ } catch (e) {
+ assert_equals(e.message, errorMessage);
+ ++permissionsPolicyDeniedCount;
+ }
+
+ try {
+ await window.sharedStorage.append('a', 'b');
+ } catch (e) {
+ assert_equals(e.message, errorMessage);
+ ++permissionsPolicyDeniedCount;
+ }
+
+ try {
+ await window.sharedStorage.clear();
+ } catch (e) {
+ assert_equals(e.message, errorMessage);
+ ++permissionsPolicyDeniedCount;
+ }
+
+ try {
+ await window.sharedStorage.delete('a');
+ } catch (e) {
+ assert_equals(e.message, errorMessage);
+ ++permissionsPolicyDeniedCount;
+ }
+
+ if (permissionsPolicyDeniedCount === 0)
+ return true;
+
+ return false;
+}
+
+// Run sharedStorage.worklet.addModule once.
+// @param {string} module - The URL to the module.
+async function addModuleOnce(module) {
+ try {
+ await sharedStorage.worklet.addModule(module);
+ } catch (e) {
+ // Shared Storage needs to have a module added before we can operate on it.
+ // It is generated on the fly with this call, and since there's no way to
+ // tell through the API if a module already exists, wrap the addModule call
+ // in a try/catch so that if it runs a second time in a test, it will
+ // gracefully fail rather than bring the whole test down.
+ }
+}
+
+// Validate the type of the result of sharedStorage.worklet.selectURL.
+// @param result - The result of sharedStorage.worklet.selectURL.
+// @param {boolean} - Whether sharedStorage.worklet.selectURL is resolved to
+// a fenced frame config (true) or an urn:uuid (false).
+// @return {boolean} Whether sharedStorage.worklet.selectURL returns an expected
+// result type or not.
+function validateSelectURLResult(result, resolve_to_config) {
+ if (resolve_to_config) {
+ return result instanceof FencedFrameConfig;
+ }
+
+ return result.startsWith('urn:uuid:');
+}
+
+function updateUrlToUseNewOrigin(url, newOriginString) {
+ const origin = url.origin;
+ return new URL(url.toString().replace(origin, newOriginString));
+}
+
+function appendExpectedKeyAndValue(url, expectedKey, expectedValue) {
+ url.searchParams.append('expectedKey', expectedKey);
+ url.searchParams.append('expectedValue', expectedValue);
+ return url;
+}
+
+function parseExpectedKeyAndValueData() {
+ const url = new URL(location.href);
+ const key = url.searchParams.get('expectedKey');
+ const value = url.searchParams.get('expectedValue');
+ return {'expectedKey': key, 'expectedValue': value};
+}
+
+function appendExpectedKey(url, expectedKey) {
+ url.searchParams.append('expectedKey', expectedKey);
+ return url;
+}
+
+function parseExpectedKeyData() {
+ const url = new URL(location.href);
+ const key = url.searchParams.get('expectedKey');
+ return {'expectedKey': key};
+}
+
+async function verifyKeyValueForOrigin(key, value, origin) {
+ const outerKey = token();
+ const innerKey = token();
+ let iframeUrl = generateURL(
+ '/shared-storage/resources/verify-key-value.https.html',
+ [outerKey, innerKey]);
+ iframeUrl = updateUrlToUseNewOrigin(iframeUrl, origin);
+ iframeUrl = appendExpectedKeyAndValue(iframeUrl, key, value);
+
+ attachIFrame(iframeUrl);
+ const result = await nextValueFromServer(outerKey);
+ assert_equals(result, 'verify_key_value_loaded');
+}
+
+async function verifyKeyNotFoundForOrigin(key, origin) {
+ const outerKey = token();
+ const innerKey = token();
+ let iframeUrl = generateURL(
+ '/shared-storage/resources/verify-key-not-found.https.html',
+ [outerKey, innerKey]);
+ iframeUrl = updateUrlToUseNewOrigin(iframeUrl, origin);
+ iframeUrl = appendExpectedKey(iframeUrl, key);
+
+ attachIFrame(iframeUrl);
+ const result = await nextValueFromServer(outerKey);
+ assert_equals(result, 'verify_key_not_found_loaded');
+}
+
+async function setKeyValueForOrigin(key, value, origin) {
+ const outerKey = token();
+ let setIframeUrl = generateURL(
+ '/shared-storage/resources/set-key-value.https.html', [outerKey]);
+ setIframeUrl = updateUrlToUseNewOrigin(setIframeUrl, origin);
+ setIframeUrl = appendExpectedKeyAndValue(setIframeUrl, key, value);
+
+ attachIFrame(setIframeUrl);
+ const result = await nextValueFromServer(outerKey);
+ assert_equals(result, 'set_key_value_loaded');
+}
+
+async function deleteKeyForOrigin(key, origin) {
+ const outerKey = token();
+ let deleteIframeUrl = generateURL(
+ '/shared-storage/resources/delete-key.https.html', [outerKey]);
+ deleteIframeUrl = updateUrlToUseNewOrigin(deleteIframeUrl, origin);
+ deleteIframeUrl = appendExpectedKey(deleteIframeUrl, key);
+
+ attachIFrame(deleteIframeUrl);
+ const result = await nextValueFromServer(outerKey);
+ assert_equals(result, 'delete_key_loaded');
+}
+
+function getFetchedUrls(worker) {
+ return new Promise(function(resolve) {
+ var channel = new MessageChannel();
+ channel.port1.onmessage = function(msg) {
+ resolve(msg);
+ };
+ worker.postMessage({port: channel.port2}, [channel.port2]);
+ });
+}
+
+function checkInterceptedUrls(worker, expectedRequests) {
+ return getFetchedUrls(worker).then(function(msg) {
+ let actualRequests = msg.data.requests;
+ assert_equals(actualRequests.length, expectedRequests.length);
+ assert_equals(
+ JSON.stringify(actualRequests), JSON.stringify(expectedRequests));
+ });
+}
diff --git a/testing/web-platform/tests/shared-storage/resources/util.sub.js b/testing/web-platform/tests/shared-storage/resources/util.sub.js
new file mode 100644
index 0000000000..f147209d60
--- /dev/null
+++ b/testing/web-platform/tests/shared-storage/resources/util.sub.js
@@ -0,0 +1,117 @@
+function loadSharedStorageImage(data) {
+ let {key, value, hasSharedStorageWritableAttribute, isSameOrigin} = data;
+ const sameOriginSrc = `/shared-storage/resources/` +
+ `shared-storage-writable-pixel.png?key=${key}&value=${value}`;
+ const crossOriginSrc =
+ 'https://{{domains[www]}}:{{ports[https][0]}}' + sameOriginSrc;
+
+ let image = document.createElement('img');
+ image.src = isSameOrigin ? sameOriginSrc : crossOriginSrc;
+ if (hasSharedStorageWritableAttribute) {
+ image.sharedStorageWritable = true;
+ }
+
+ const promise = new Promise((resolve, reject) => {
+ image.addEventListener('load', () => {
+ resolve(image);
+ });
+ image.addEventListener('error', () => {
+ reject(new Error('Image load failed'));
+ });
+ });
+
+ document.body.appendChild(image);
+ return promise;
+}
+
+function navigateSharedStorageIframe(data) {
+ let {
+ hasSharedStorageWritableAttribute,
+ rawWriteHeader,
+ isSameOrigin,
+ expectSharedStorageWritableHeader
+ } = data;
+ const writeHeader = encodeURIComponent(rawWriteHeader);
+ const sameOriginSrc =
+ `/shared-storage/resources/shared-storage-write-notify-parent.py` +
+ `?write=${writeHeader}`;
+ const crossOriginSrc =
+ 'https://{{domains[www]}}:{{ports[https][0]}}' + sameOriginSrc;
+
+ let frame = document.createElement('iframe');
+ frame.src = isSameOrigin ? sameOriginSrc : crossOriginSrc;
+ if (hasSharedStorageWritableAttribute) {
+ frame.sharedStorageWritable = true;
+ }
+
+ const expectedResult = expectSharedStorageWritableHeader ?
+ '?1' :
+ 'NO_SHARED_STORAGE_WRITABLE_HEADER';
+
+ function checkExpectedResult(data) {
+ assert_equals(data.sharedStorageWritableHeader, expectedResult);
+ }
+
+ const promise = new Promise((resolve, reject) => {
+ window.addEventListener('message', async function handler(evt) {
+ if (evt.source === frame.contentWindow) {
+ checkExpectedResult(evt.data);
+ document.body.removeChild(frame);
+ window.removeEventListener('message', handler);
+ resolve();
+ }
+ });
+ window.addEventListener('error', () => {
+ reject(new Error('Navigation error'));
+ });
+ });
+
+ document.body.appendChild(frame);
+ return promise;
+}
+
+async function loadNestedSharedStorageFrameInNewFrame(data) {
+ const SCOPE = '/shared-storage/resources/shared-storage-writ';
+ const INTERMEDIATE_FRAME_SUFFIX =
+ 'able-fetch-request-fallback-to-network-iframe.https.html'
+ const CROSS_ORIGIN = 'https://{{domains[www]}}:{{ports[https][0]}}';
+
+ let {key, value, hasSharedStorageWritableAttribute, isSameOrigin} = data;
+
+ const windowPromise = new Promise((resolve, reject) => {
+ window.addEventListener('message', async function handler(evt) {
+ if (evt.data.msg && evt.data.msg === 'iframe loaded') {
+ window.removeEventListener('message', handler);
+ resolve();
+ }
+ });
+ window.addEventListener('error', () => {
+ reject(new Error('Navigation error'));
+ });
+ });
+
+ const framePromise = new Promise((resolve, reject) => {
+ let frame = document.createElement('iframe');
+ frame.src = SCOPE + INTERMEDIATE_FRAME_SUFFIX;
+ frame.onload = function() {
+ resolve(frame);
+ };
+ frame.onerror = function() {
+ reject(new Error('Iframe load failed'));
+ };
+ document.body.appendChild(frame);
+ });
+ let frame = await framePromise;
+
+ let rawWriteHeader = `set;key=${key};value=${value}`;
+ let writeHeader = encodeURIComponent(rawWriteHeader);
+ const sameOriginNestedSrc = `/shared-storage/resources/` +
+ `shared-storage-write.py?write=${writeHeader}`;
+ const nestedSrc =
+ isSameOrigin ? sameOriginNestedSrc : CROSS_ORIGIN + sameOriginNestedSrc;
+
+ let nestedFrame = frame.contentWindow.loadFrame(
+ nestedSrc, hasSharedStorageWritableAttribute);
+ await windowPromise;
+ return {frame: frame, nestedFrame: nestedFrame, nestedFrameUrl: nestedSrc};
+}
diff --git a/testing/web-platform/tests/shared-storage/resources/verify-get-undefined-module.js b/testing/web-platform/tests/shared-storage/resources/verify-get-undefined-module.js
new file mode 100644
index 0000000000..56bc2f51e2
--- /dev/null
+++ b/testing/web-platform/tests/shared-storage/resources/verify-get-undefined-module.js
@@ -0,0 +1,17 @@
+// Copyright 2023 The Chromium Authors
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+class VerifyGetUndefinedURLSelectionOperation {
+ async run(urls, data) {
+ if (await sharedStorage.get('key-not-previously-set') === undefined) {
+ return 1;
+ }
+
+ return -1;
+ }
+}
+
+register(
+ 'verify-get-undefined-url-selection-operation',
+ VerifyGetUndefinedURLSelectionOperation);
diff --git a/testing/web-platform/tests/shared-storage/resources/verify-key-not-found.https.html b/testing/web-platform/tests/shared-storage/resources/verify-key-not-found.https.html
new file mode 100644
index 0000000000..f1c7919c19
--- /dev/null
+++ b/testing/web-platform/tests/shared-storage/resources/verify-key-not-found.https.html
@@ -0,0 +1,34 @@
+<!DOCTYPE html>
+<html>
+<script src=/resources/testharness.js></script>
+<script src=/shared-storage/resources/util.js></script>
+<script src=/fenced-frame/resources/utils.js></script>
+<body>
+<script>
+
+async function init() {
+ const [outerKey, innerKey] = parseKeylist();
+ const parsedData = parseExpectedKeyData();
+ let url0 = generateURL("/shared-storage/resources/frame0.html", [innerKey]);
+ let url1 = generateURL("/shared-storage/resources/frame1.html", [innerKey]);
+
+ await addModuleOnce("/shared-storage/resources/simple-module.js");
+ let fencedFrameConfig = await sharedStorage.selectURL(
+ "verify-key-not-found", [{url: url0}, {url: url1}],
+ {data: parsedData, resolveToConfig: true});
+ assert_true(validateSelectURLResult(fencedFrameConfig, true));
+
+ attachFencedFrame(fencedFrameConfig, 'opaque-ads');
+ const result = await nextValueFromServer(innerKey);
+ const dataStr = JSON.stringify(parsedData);
+ assert_equals(result, "frame1_loaded",
+ `verifying key ${dataStr} not found for ${location.origin};`);
+
+ await writeValueToServer(outerKey,
+ "verify_key_not_found_loaded");
+}
+
+init();
+</script>
+</body>
+</html>
diff --git a/testing/web-platform/tests/shared-storage/resources/verify-key-value.https.html b/testing/web-platform/tests/shared-storage/resources/verify-key-value.https.html
new file mode 100644
index 0000000000..20c4694104
--- /dev/null
+++ b/testing/web-platform/tests/shared-storage/resources/verify-key-value.https.html
@@ -0,0 +1,34 @@
+<!DOCTYPE html>
+<html>
+<script src=/resources/testharness.js></script>
+<script src=/shared-storage/resources/util.js></script>
+<script src=/fenced-frame/resources/utils.js></script>
+<body>
+<script>
+
+async function init() {
+ const [outerKey, innerKey] = parseKeylist();
+ const parsedData = parseExpectedKeyAndValueData();
+ let url0 = generateURL("/shared-storage/resources/frame0.html", [innerKey]);
+ let url1 = generateURL("/shared-storage/resources/frame1.html", [innerKey]);
+
+ await addModuleOnce("/shared-storage/resources/simple-module.js");
+ let fencedFrameConfig = await sharedStorage.selectURL(
+ "verify-key-value", [{url: url0}, {url: url1}],
+ {data: parsedData, resolveToConfig: true});
+ assert_true(validateSelectURLResult(fencedFrameConfig, true));
+
+ attachFencedFrame(fencedFrameConfig, 'opaque-ads');
+ const result = await nextValueFromServer(innerKey);
+ const dataStr = JSON.stringify(parsedData);
+ assert_equals(result, "frame1_loaded",
+ `verifying key, value ${dataStr} found for ${location.origin};`);
+
+ await writeValueToServer(outerKey,
+ "verify_key_value_loaded");
+}
+
+init();
+</script>
+</body>
+</html>
diff --git a/testing/web-platform/tests/shared-storage/resources/verify-key-value.https.html.headers b/testing/web-platform/tests/shared-storage/resources/verify-key-value.https.html.headers
new file mode 100644
index 0000000000..1b63235b7c
--- /dev/null
+++ b/testing/web-platform/tests/shared-storage/resources/verify-key-value.https.html.headers
@@ -0,0 +1 @@
+Supports-Loading-Mode: fenced-frame
diff --git a/testing/web-platform/tests/shared-storage/resources/verify-shared-storage.https.html b/testing/web-platform/tests/shared-storage/resources/verify-shared-storage.https.html
new file mode 100644
index 0000000000..52c79e7e85
--- /dev/null
+++ b/testing/web-platform/tests/shared-storage/resources/verify-shared-storage.https.html
@@ -0,0 +1,13 @@
+<!DOCTYPE html>
+<html>
+<body>
+<script>
+ try {
+ window.sharedStorage;
+ window.parent.postMessage({ accessSharedStorageResult: 'success'}, "*");
+ } catch (error) {
+ window.parent.postMessage({ accessSharedStorageResult: 'failure'}, "*");
+ }
+</script>
+</body>
+</html>
diff --git a/testing/web-platform/tests/shared-storage/resources/verify-storage-entries-module.js b/testing/web-platform/tests/shared-storage/resources/verify-storage-entries-module.js
new file mode 100644
index 0000000000..ee0c636cd1
--- /dev/null
+++ b/testing/web-platform/tests/shared-storage/resources/verify-storage-entries-module.js
@@ -0,0 +1,26 @@
+// Copyright 2023 The Chromium Authors
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+class SetKey0Operation {
+ async run(data) {
+ sharedStorage.set('key0-set-from-worklet', 'value0');
+ }
+}
+
+class VerifyStorageEntriesURLSelectionOperation {
+ async run(urls, data) {
+ if (await sharedStorage.get('key0-set-from-worklet') === 'value0' &&
+ await sharedStorage.get('key0-set-from-document') === 'value0') {
+ return 1;
+ }
+
+ return -1;
+ }
+}
+
+register('set-key0-operation', SetKey0Operation);
+
+register(
+ 'verify-storage-entries-url-selection-operation',
+ VerifyStorageEntriesURLSelectionOperation);
diff --git a/testing/web-platform/tests/shared-storage/run-operation-in-detached-frame.tentative.https.sub.html b/testing/web-platform/tests/shared-storage/run-operation-in-detached-frame.tentative.https.sub.html
new file mode 100644
index 0000000000..a7ef103d00
--- /dev/null
+++ b/testing/web-platform/tests/shared-storage/run-operation-in-detached-frame.tentative.https.sub.html
@@ -0,0 +1,22 @@
+<!doctype html>
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+
+<body>
+ <iframe></iframe>
+ <script>
+ promise_test(async t => {
+ const iframe = document.querySelector('iframe');
+ const childSharedStorage = iframe.contentWindow.sharedStorage;
+ iframe.remove();
+
+ try {
+ await childSharedStorage.run("operation1");
+ } catch (e) {
+ assert_equals(e.name, 'InvalidAccessError');
+ return;
+ }
+ assert_unreached("did not reject");
+ }, 'run() when frame is detached');
+ </script>
+</body>
diff --git a/testing/web-platform/tests/shared-storage/run-operation-keep-alive.tentative.https.sub.html b/testing/web-platform/tests/shared-storage/run-operation-keep-alive.tentative.https.sub.html
new file mode 100644
index 0000000000..2756805485
--- /dev/null
+++ b/testing/web-platform/tests/shared-storage/run-operation-keep-alive.tentative.https.sub.html
@@ -0,0 +1,34 @@
+<!doctype html>
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="/shared-storage/resources/util.js"></script>
+
+<body>
+<script>
+'use strict';
+
+promise_test(async () => {
+ await addModuleOnce("/shared-storage/resources/simple-module.js");
+ await sharedStorage.run("operation1", {keepAlive: true});
+ return sharedStorage.run("operation1", {keepAlive: true});
+}, 'run() twice with keepAlive: true');
+
+promise_test(async () => {
+ await addModuleOnce("/shared-storage/resources/simple-module.js");
+ await sharedStorage.run("operation1", {keepAlive: true});
+ await sharedStorage.run("operation1", {keepAlive: false});
+ try {
+ await sharedStorage.run("operation1");
+ } catch (e) {
+ assert_equals(e.name, 'OperationError');
+ assert_equals(e.message, 'The sharedStorage worklet cannot execute' +
+ ' further operations because the previous' +
+ ' operation did not include the option' +
+ ' \'keepAlive: true\'.');
+ return;
+ }
+ assert_unreached("did not reject");
+}, 'run() with keepAlive: true, then keepAlive: false, then error');
+
+</script>
+</body>
diff --git a/testing/web-platform/tests/shared-storage/run-operation.tentative.https.sub.html b/testing/web-platform/tests/shared-storage/run-operation.tentative.https.sub.html
new file mode 100644
index 0000000000..1ef0d25b48
--- /dev/null
+++ b/testing/web-platform/tests/shared-storage/run-operation.tentative.https.sub.html
@@ -0,0 +1,35 @@
+<!doctype html>
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="/shared-storage/resources/util.js"></script>
+
+<body>
+<script>
+'use strict';
+
+promise_test(async t => {
+ await addModuleOnce("/shared-storage/resources/simple-module.js");
+ return sharedStorage.run("operation1", {keepAlive: true});
+}, 'run()');
+
+promise_test(async t => {
+ await addModuleOnce("/shared-storage/resources/simple-module.js");
+ return sharedStorage.run("operation1",
+ {data: {'custom-key': 'custom-value'},
+ keepAlive: true});
+}, 'run() with custom data');
+
+promise_test(async t => {
+ try {
+ await addModuleOnce("/shared-storage/resources/simple-module.js");
+ await sharedStorage.run("operation1", {data: window});
+ } catch (e) {
+ assert_equals(e.name, 'DataCloneError');
+ assert_equals(e.message, 'Failed to execute \'run\' on \'SharedStorage\': #<Window> could not be cloned.');
+ return;
+ }
+ assert_unreached("did not reject");
+}, 'run() with unsupported serializable type');
+
+</script>
+</body>
diff --git a/testing/web-platform/tests/shared-storage/run-url-selection-operation-without-add-module.tentative.https.sub.html b/testing/web-platform/tests/shared-storage/run-url-selection-operation-without-add-module.tentative.https.sub.html
new file mode 100644
index 0000000000..bead580706
--- /dev/null
+++ b/testing/web-platform/tests/shared-storage/run-url-selection-operation-without-add-module.tentative.https.sub.html
@@ -0,0 +1,30 @@
+<!doctype html>
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+
+<body>
+<script>
+'use strict';
+
+for (const resolve_to_config of [true, false]) {
+ promise_test(async t => {
+ return promise_rejects_dom(t, "OperationError",
+ sharedStorage.selectURL(
+ "test-url-selection-operation",
+ [{url: "/shared-storage/resources/frame0.html"}],
+ {resolveToConfig: resolve_to_config, keepAlive: true}));
+ }, 'sharedStorage.selectURL() without addModule, ' +
+ 'selectURL() resolves to ' + (resolve_to_config ? 'config' : 'urn:uuid'));
+
+ promise_test(async t => {
+ return promise_rejects_dom(t, "OperationError",
+ sharedStorage.worklet.selectURL(
+ "test-url-selection-operation",
+ [{url: "/shared-storage/resources/frame0.html"}],
+ {resolveToConfig: resolve_to_config, keepAlive: true}));
+ }, 'sharedStorage.worklet.selectURL() without addModule, ' +
+ 'selectURL() resolves to ' + (resolve_to_config ? 'config' : 'urn:uuid'));
+}
+
+</script>
+</body>
diff --git a/testing/web-platform/tests/shared-storage/run-url-selection-operation.tentative.https.sub.html b/testing/web-platform/tests/shared-storage/run-url-selection-operation.tentative.https.sub.html
new file mode 100644
index 0000000000..01cb9fdd39
--- /dev/null
+++ b/testing/web-platform/tests/shared-storage/run-url-selection-operation.tentative.https.sub.html
@@ -0,0 +1,189 @@
+<!doctype html>
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="/common/utils.js"></script>
+<script src="/shared-storage/resources/util.js"></script>
+<script src="/fenced-frame/resources/utils.js"></script>
+
+<body>
+<script>
+'use strict';
+
+for (const resolve_to_config of [true, false]) {
+ promise_test(async () => {
+ const ancestor_key = token();
+ let url0 = generateURL("/shared-storage/resources/frame0.html",
+ [ancestor_key]);
+ let url1 = generateURL("/shared-storage/resources/frame1.html",
+ [ancestor_key]);
+
+ await addModuleOnce("/shared-storage/resources/simple-module.js");
+
+ let select_url_result0 = await sharedStorage.selectURL(
+ "test-url-selection-operation", [{url: url0}, {url: url1}],
+ {data: {'mockResult': 0}, resolveToConfig: resolve_to_config,
+ keepAlive: true});
+ assert_true(validateSelectURLResult(select_url_result0, resolve_to_config));
+ attachFencedFrame(select_url_result0, 'opaque-ads');
+ const result0 = await nextValueFromServer(ancestor_key);
+ assert_equals(result0, "frame0_loaded");
+
+ let select_url_result1 = await sharedStorage.selectURL(
+ "test-url-selection-operation", [{url: url0}, {url: url1}],
+ {data: {'mockResult': 1}, resolveToConfig: resolve_to_config,
+ keepAlive: true});
+ assert_true(validateSelectURLResult(select_url_result1, resolve_to_config));
+ attachFencedFrame(select_url_result1, 'opaque-ads');
+ const result1 = await nextValueFromServer(ancestor_key);
+ assert_equals(result1, "frame1_loaded");
+
+ let select_url_result2 = await sharedStorage.selectURL(
+ "test-url-selection-operation", [{url: url0}, {url: url1}],
+ {data: {'mockResult': -1}, resolveToConfig: resolve_to_config,
+ keepAlive: true});
+ assert_true(validateSelectURLResult(select_url_result2, resolve_to_config));
+ attachFencedFrame(select_url_result2, 'opaque-ads');
+ const result2 = await nextValueFromServer(ancestor_key);
+ assert_equals(result2, "frame0_loaded");
+ }, 'selectURL() resolves to ' + (resolve_to_config ? 'config' : 'urn:uuid'));
+
+ promise_test(async t => {
+ try {
+ await addModuleOnce("/shared-storage/resources/simple-module.js");
+ await sharedStorage.selectURL(
+ "test-url-selection-operation",
+ [{url: "1"}, {url: "2"}, {url: "3"}, {url: "4"}, {url: "5"},
+ {url: "6"}, {url: "7"}, {url: "8"}, {url: "9"}],
+ {resolveToConfig: resolve_to_config, keepAlive: true});
+ } catch (e) {
+ assert_equals(e.name, 'DataError');
+ assert_equals(e.message, 'Length of the \"urls\" parameter is not valid.');
+ return;
+ }
+ assert_unreached("did not reject");
+ }, 'selectURL() with urls array length too big, ' +
+ 'selectURL() resolves to ' + (resolve_to_config ? 'config' : 'urn:uuid'));
+
+ promise_test(async t => {
+ try {
+ await addModuleOnce("/shared-storage/resources/simple-module.js");
+ await sharedStorage.selectURL(
+ "test-url-selection-operation",
+ [],
+ {resolveToConfig: resolve_to_config, keepAlive: true});
+ } catch (e) {
+ assert_equals(e.name, 'DataError');
+ assert_equals(e.message, 'Length of the \"urls\" parameter is not valid.');
+ return;
+ }
+ assert_unreached("did not reject");
+ }, 'selectURL() with empty urls array, ' +
+ 'selectURL() resolves to ' + (resolve_to_config ? 'config' : 'urn:uuid'));
+
+ promise_test(async t => {
+ try {
+ await addModuleOnce("/shared-storage/resources/simple-module.js");
+ await sharedStorage.selectURL(
+ "test-url-selection-operation", [{
+ reportingMetadata: {
+ 'click': "https://google.com"
+ }
+ }],
+ {resolveToConfig: resolve_to_config, keepAlive: true});
+ } catch (e) {
+ assert_equals(e.name, 'TypeError');
+ assert_equals(true, e.message.startsWith(
+ 'Failed to execute \'selectURL\' on \'SharedStorage\': ' +
+ 'Failed to read the \'url\' property from ' +
+ '\'SharedStorageUrlWithMetadata\':') &&
+ e.message.endsWith('Failed to read the \'url\' property from ' +
+ '\'SharedStorageUrlWithMetadata\': Required member is undefined.'));
+ return;
+ }
+ assert_unreached("did not reject");
+ }, 'selectURL() with missing url, ' +
+ 'selectURL() resolves to ' + (resolve_to_config ? 'config' : 'urn:uuid'));
+
+ promise_test(async t => {
+ try {
+ await addModuleOnce("/shared-storage/resources/simple-module.js");
+ await sharedStorage.selectURL(
+ "test-url-selection-operation", [{
+ url: "https://#"
+ }],
+ {resolveToConfig: resolve_to_config, keepAlive: true});
+ } catch (e) {
+ assert_equals(e.name, 'DataError');
+ assert_equals(e.message,
+ 'The url \"https://#\" is invalid.');
+ return;
+ }
+ assert_unreached("did not reject");
+ }, 'selectURL() with invalid url, ' +
+ 'selectURL() resolves to ' + (resolve_to_config ? 'config' : 'urn:uuid'));
+
+ promise_test(async t => {
+ try {
+ await addModuleOnce("/shared-storage/resources/simple-module.js");
+ await sharedStorage.selectURL(
+ "test-url-selection-operation", [{
+ url: "/shared-storage/resources/frame0.html",
+ reportingMetadata: {
+ 'click': "https://#"
+ }
+ }],
+ {resolveToConfig: resolve_to_config, keepAlive: true});
+ } catch (e) {
+ assert_equals(e.name, 'DataError');
+ assert_equals(e.message,
+ 'The metadata for the url at index 0 has an invalid ' +
+ 'or non-HTTPS report_url parameter \"https://#\".');
+ return;
+ }
+ assert_unreached("did not reject");
+ }, 'selectURL() with invalid report url ' +
+ 'selectURL() resolves to ' + (resolve_to_config ? 'config' : 'urn:uuid'));
+
+ promise_test(async t => {
+ try {
+ await addModuleOnce("/shared-storage/resources/simple-module.js");
+ await sharedStorage.selectURL(
+ "test-url-selection-operation", [{
+ url: "/shared-storage/resources/frame0.html",
+ reportingMetadata: {
+ 'click': "http://google.com"
+ }
+ }],
+ {resolveToConfig: resolve_to_config, keepAlive: true});
+ } catch (e) {
+ assert_equals(e.name, 'DataError');
+ assert_equals(e.message, 'The metadata for the url at index 0 has an ' +
+ 'invalid or non-HTTPS report_url parameter \"http://google.com\".');
+ return;
+ }
+ assert_unreached("did not reject");
+ }, 'selectURL() with http report url, ' +
+ 'selectURL() resolves to ' + (resolve_to_config ? 'config' : 'urn:uuid'));
+
+ promise_test(async t => {
+ try {
+ await addModuleOnce("/shared-storage/resources/simple-module.js");
+ await sharedStorage.selectURL(
+ "test-url-selection-operation", [{
+ url: "/shared-storage/resources/frame0.html",
+ reportingMetadata: {}
+ }],
+ {resolveToConfig: resolve_to_config, keepAlive: true});
+ } catch (e) {
+ assert_equals(e.name, 'DataError');
+ assert_equals(e.message, 'selectURL could not get reportingMetadata ' +
+ 'object attributes');
+ return;
+ }
+ assert_unreached("did not reject");
+ }, 'selectURL() with invalid reportingMetadata ' +
+ 'selectURL() resolves to ' + (resolve_to_config ? 'config' : 'urn:uuid'));
+}
+
+</script>
+</body>
diff --git a/testing/web-platform/tests/shared-storage/same-origin-add-module-credentials-include.tentative.https.sub.html b/testing/web-platform/tests/shared-storage/same-origin-add-module-credentials-include.tentative.https.sub.html
new file mode 100644
index 0000000000..a9082661a8
--- /dev/null
+++ b/testing/web-platform/tests/shared-storage/same-origin-add-module-credentials-include.tentative.https.sub.html
@@ -0,0 +1,30 @@
+<!doctype html>
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="/common/utils.js"></script>
+<script src="/shared-storage/resources/util.js"></script>
+<script src="/fenced-frame/resources/utils.js"></script>
+
+<body>
+<script>
+'use strict';
+
+promise_test(async () => {
+ const ancestor_key = token();
+ document.cookie = "key0=value0";
+ const helper_url = `/shared-storage/resources/credentials-test-helper.py`;
+
+ await sharedStorage.worklet.addModule(
+ helper_url + `?action=store-cookie&token=${ancestor_key}`,
+ { credentials: "include" });
+
+ const request_cookie_fetch_response =
+ await fetch(helper_url + `?action=get-cookie&token=${ancestor_key}`);
+
+ const request_cookie_text = await request_cookie_fetch_response.text();
+
+ assert_equals(request_cookie_text, "key0=value0");
+}, 'addModule() with same-origin module script and credentials "include"');
+
+</script>
+</body>
diff --git a/testing/web-platform/tests/shared-storage/same-origin-add-module-credentials-omit.tentative.https.sub.html b/testing/web-platform/tests/shared-storage/same-origin-add-module-credentials-omit.tentative.https.sub.html
new file mode 100644
index 0000000000..a5945725c0
--- /dev/null
+++ b/testing/web-platform/tests/shared-storage/same-origin-add-module-credentials-omit.tentative.https.sub.html
@@ -0,0 +1,30 @@
+<!doctype html>
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="/common/utils.js"></script>
+<script src="/shared-storage/resources/util.js"></script>
+<script src="/fenced-frame/resources/utils.js"></script>
+
+<body>
+<script>
+'use strict';
+
+promise_test(async () => {
+ const ancestor_key = token();
+ document.cookie = "key0=value0";
+ const helper_url = `/shared-storage/resources/credentials-test-helper.py`;
+
+ await sharedStorage.worklet.addModule(
+ helper_url + `?action=store-cookie&token=${ancestor_key}`,
+ { credentials: "omit" });
+
+ const request_cookie_fetch_response =
+ await fetch(helper_url + `?action=get-cookie&token=${ancestor_key}`);
+
+ const request_cookie_text = await request_cookie_fetch_response.text();
+
+ assert_equals(request_cookie_text, "NO_COOKIE_HEADER");
+}, 'addModule() with same-origin module script and credentials "omit"');
+
+</script>
+</body>
diff --git a/testing/web-platform/tests/shared-storage/same-origin-add-module-credentials-same-origin.tentative.https.sub.html b/testing/web-platform/tests/shared-storage/same-origin-add-module-credentials-same-origin.tentative.https.sub.html
new file mode 100644
index 0000000000..aea7626438
--- /dev/null
+++ b/testing/web-platform/tests/shared-storage/same-origin-add-module-credentials-same-origin.tentative.https.sub.html
@@ -0,0 +1,30 @@
+<!doctype html>
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="/common/utils.js"></script>
+<script src="/shared-storage/resources/util.js"></script>
+<script src="/fenced-frame/resources/utils.js"></script>
+
+<body>
+<script>
+'use strict';
+
+promise_test(async () => {
+ const ancestor_key = token();
+ document.cookie = "key0=value0";
+ const helper_url = `/shared-storage/resources/credentials-test-helper.py`;
+
+ await sharedStorage.worklet.addModule(
+ helper_url + `?action=store-cookie&token=${ancestor_key}`,
+ { credentials: "same-origin" });
+
+ const request_cookie_fetch_response =
+ await fetch(helper_url + `?action=get-cookie&token=${ancestor_key}`);
+
+ const request_cookie_text = await request_cookie_fetch_response.text();
+
+ assert_equals(request_cookie_text, "key0=value0");
+}, 'addModule() with same-origin module script and credentials "same-origin"');
+
+</script>
+</body>
diff --git a/testing/web-platform/tests/shared-storage/same-origin-create-worklet-credentials-include.tentative.https.sub.html b/testing/web-platform/tests/shared-storage/same-origin-create-worklet-credentials-include.tentative.https.sub.html
new file mode 100644
index 0000000000..2e1d9cf723
--- /dev/null
+++ b/testing/web-platform/tests/shared-storage/same-origin-create-worklet-credentials-include.tentative.https.sub.html
@@ -0,0 +1,30 @@
+<!doctype html>
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="/common/utils.js"></script>
+<script src="/shared-storage/resources/util.js"></script>
+<script src="/fenced-frame/resources/utils.js"></script>
+
+<body>
+<script>
+'use strict';
+
+promise_test(async () => {
+ const ancestor_key = token();
+ document.cookie = "key0=value0";
+ const helper_url = `/shared-storage/resources/credentials-test-helper.py`;
+
+ const worklet = await sharedStorage.createWorklet(
+ helper_url + `?action=store-cookie&token=${ancestor_key}`,
+ { credentials: "include" });
+
+ const request_cookie_fetch_response =
+ await fetch(helper_url + `?action=get-cookie&token=${ancestor_key}`);
+
+ const request_cookie_text = await request_cookie_fetch_response.text();
+
+ assert_equals(request_cookie_text, "key0=value0");
+}, 'createWorklet() with same-origin module script and credentials "include"');
+
+</script>
+</body>
diff --git a/testing/web-platform/tests/shared-storage/same-origin-create-worklet-credentials-omit.tentative.https.sub.html b/testing/web-platform/tests/shared-storage/same-origin-create-worklet-credentials-omit.tentative.https.sub.html
new file mode 100644
index 0000000000..ef90c02d64
--- /dev/null
+++ b/testing/web-platform/tests/shared-storage/same-origin-create-worklet-credentials-omit.tentative.https.sub.html
@@ -0,0 +1,30 @@
+<!doctype html>
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="/common/utils.js"></script>
+<script src="/shared-storage/resources/util.js"></script>
+<script src="/fenced-frame/resources/utils.js"></script>
+
+<body>
+<script>
+'use strict';
+
+promise_test(async () => {
+ const ancestor_key = token();
+ document.cookie = "key0=value0";
+ const helper_url = `/shared-storage/resources/credentials-test-helper.py`;
+
+ const worklet = await sharedStorage.createWorklet(
+ helper_url + `?action=store-cookie&token=${ancestor_key}`,
+ { credentials: "omit" });
+
+ const request_cookie_fetch_response =
+ await fetch(helper_url + `?action=get-cookie&token=${ancestor_key}`);
+
+ const request_cookie_text = await request_cookie_fetch_response.text();
+
+ assert_equals(request_cookie_text, "NO_COOKIE_HEADER");
+}, 'createWorklet() with same-origin module script and credentials "omit"');
+
+</script>
+</body>
diff --git a/testing/web-platform/tests/shared-storage/same-origin-create-worklet-credentials-same-origin.tentative.https.sub.html b/testing/web-platform/tests/shared-storage/same-origin-create-worklet-credentials-same-origin.tentative.https.sub.html
new file mode 100644
index 0000000000..6d9fd7c136
--- /dev/null
+++ b/testing/web-platform/tests/shared-storage/same-origin-create-worklet-credentials-same-origin.tentative.https.sub.html
@@ -0,0 +1,30 @@
+<!doctype html>
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="/common/utils.js"></script>
+<script src="/shared-storage/resources/util.js"></script>
+<script src="/fenced-frame/resources/utils.js"></script>
+
+<body>
+<script>
+'use strict';
+
+promise_test(async () => {
+ const ancestor_key = token();
+ document.cookie = "key0=value0";
+ const helper_url = `/shared-storage/resources/credentials-test-helper.py`;
+
+ const worklet = await sharedStorage.createWorklet(
+ helper_url + `?action=store-cookie&token=${ancestor_key}`,
+ { credentials: "same-origin" });
+
+ const request_cookie_fetch_response =
+ await fetch(helper_url + `?action=get-cookie&token=${ancestor_key}`);
+
+ const request_cookie_text = await request_cookie_fetch_response.text();
+
+ assert_equals(request_cookie_text, "key0=value0");
+}, 'createWorklet() with same-origin module script and credentials "same-origin"');
+
+</script>
+</body>
diff --git a/testing/web-platform/tests/shared-storage/select-url-keep-alive.tentative.https.sub.html b/testing/web-platform/tests/shared-storage/select-url-keep-alive.tentative.https.sub.html
new file mode 100644
index 0000000000..f3755538b9
--- /dev/null
+++ b/testing/web-platform/tests/shared-storage/select-url-keep-alive.tentative.https.sub.html
@@ -0,0 +1,53 @@
+<!doctype html>
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="/common/utils.js"></script>
+<script src="/shared-storage/resources/util.js"></script>
+<script src="/fenced-frame/resources/utils.js"></script>
+
+<body>
+<script>
+'use strict';
+
+promise_test(async () => {
+ const ancestor_key = token();
+ let url0 = generateURL("/shared-storage/resources/frame0.html",
+ [ancestor_key]);
+ let url1 = generateURL("/shared-storage/resources/frame1.html",
+ [ancestor_key]);
+
+ await addModuleOnce("/shared-storage/resources/simple-module.js");
+
+ let select_url_result0 = await sharedStorage.selectURL(
+ "test-url-selection-operation", [{url: url0}, {url: url1}],
+ {data: {'mockResult': 0}, resolveToConfig: true, keepAlive: true});
+ assert_true(validateSelectURLResult(select_url_result0, true));
+ attachFencedFrame(select_url_result0, 'opaque-ads');
+ const result0 = await nextValueFromServer(ancestor_key);
+ assert_equals(result0, "frame0_loaded");
+
+ let select_url_result1 = await sharedStorage.selectURL(
+ "test-url-selection-operation", [{url: url0}, {url: url1}],
+ {data: {'mockResult': 1}, resolveToConfig: true, keepAlive: false});
+ assert_true(validateSelectURLResult(select_url_result1, true));
+ attachFencedFrame(select_url_result1, 'opaque-ads');
+ const result1 = await nextValueFromServer(ancestor_key);
+ assert_equals(result1, "frame1_loaded");
+
+ try {
+ let select_url_result2 = await sharedStorage.selectURL(
+ "test-url-selection-operation", [{url: url0}, {url: url1}],
+ {data: {'mockResult': 0}, resolveToConfig: true});
+ } catch (e) {
+ assert_equals(e.name, 'OperationError');
+ assert_equals(e.message, 'The sharedStorage worklet cannot execute' +
+ ' further operations because the previous' +
+ ' operation did not include the option' +
+ ' \'keepAlive: true\'.');
+ return;
+ }
+ assert_unreached("did not reject");
+}, 'selectURL() with keepAlive: true, then keepAlive: false, then error');
+
+</script>
+</body>
diff --git a/testing/web-platform/tests/shared-storage/select-url-on-shared-storage-and-worklet-object-successively.tentative.https.sub.html b/testing/web-platform/tests/shared-storage/select-url-on-shared-storage-and-worklet-object-successively.tentative.https.sub.html
new file mode 100644
index 0000000000..5b920ae680
--- /dev/null
+++ b/testing/web-platform/tests/shared-storage/select-url-on-shared-storage-and-worklet-object-successively.tentative.https.sub.html
@@ -0,0 +1,44 @@
+<!doctype html>
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="/common/utils.js"></script>
+<script src="/shared-storage/resources/util.js"></script>
+<script src="/fenced-frame/resources/utils.js"></script>
+
+<body>
+<script>
+'use strict';
+
+promise_test(async () => {
+ const ancestor_key = token();
+ let url0 = generateURL("/shared-storage/resources/frame0.html",
+ [ancestor_key]);
+ let url1 = generateURL("/shared-storage/resources/frame1.html",
+ [ancestor_key]);
+
+ await addModuleOnce("/shared-storage/resources/simple-module.js");
+
+ let select_url_result0 = await sharedStorage.selectURL(
+ "increment-global-variable-and-return-original-value-operation",
+ [{url: url0}, {url: url1}], {resolveToConfig: true, keepAlive: true});
+ assert_true(validateSelectURLResult(select_url_result0, true));
+ attachFencedFrame(select_url_result0, 'opaque-ads');
+ const result0 = await nextValueFromServer(ancestor_key);
+ assert_equals(result0, "frame0_loaded");
+
+ let select_url_result1 = await sharedStorage.worklet.selectURL(
+ "increment-global-variable-and-return-original-value-operation",
+ [{url: url0}, {url: url1}], {resolveToConfig: true, keepAlive: true});
+ assert_true(validateSelectURLResult(select_url_result1, true));
+ attachFencedFrame(select_url_result1, 'opaque-ads');
+ const result1 = await nextValueFromServer(ancestor_key);
+
+ // This indicates that the prior sharedStorage.selectURL() and
+ // sharedStorage.worklet.selectURL() ran in the same worklet environment.
+ assert_equals(result1, "frame1_loaded");
+
+}, 'selectURL() on window.sharedStorage and window.sharedStorage.worklet ' +
+ 'successively. The two calls should run in the same worklet environment.');
+
+</script>
+</body>
diff --git a/testing/web-platform/tests/shared-storage/select-url-on-two-worklets.tentative.https.sub.html b/testing/web-platform/tests/shared-storage/select-url-on-two-worklets.tentative.https.sub.html
new file mode 100644
index 0000000000..feac45797d
--- /dev/null
+++ b/testing/web-platform/tests/shared-storage/select-url-on-two-worklets.tentative.https.sub.html
@@ -0,0 +1,46 @@
+<!doctype html>
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="/common/utils.js"></script>
+<script src="/shared-storage/resources/util.js"></script>
+<script src="/fenced-frame/resources/utils.js"></script>
+
+<body>
+<script>
+'use strict';
+
+promise_test(async () => {
+ const ancestor_key = token();
+ let url0 = generateURL("/shared-storage/resources/frame0.html",
+ [ancestor_key]);
+ let url1 = generateURL("/shared-storage/resources/frame1.html",
+ [ancestor_key]);
+
+ let worklet0 = await sharedStorage.createWorklet("/shared-storage/resources/simple-module.js");
+ let worklet1 = await sharedStorage.createWorklet("/shared-storage/resources/simple-module.js");
+
+ let select_url_result0 = await worklet0.selectURL(
+ "increment-global-variable-and-return-original-value-operation",
+ [{url: url0}, {url: url1}], {resolveToConfig: true, keepAlive: true});
+ assert_true(validateSelectURLResult(select_url_result0, true));
+ attachFencedFrame(select_url_result0, 'opaque-ads');
+ const result0 = await nextValueFromServer(ancestor_key);
+ assert_equals(result0, "frame0_loaded");
+
+ let select_url_result1 = await worklet1.selectURL(
+ "increment-global-variable-and-return-original-value-operation",
+ [{url: url0}, {url: url1}], {resolveToConfig: true, keepAlive: true});
+ assert_true(validateSelectURLResult(select_url_result1, true));
+ attachFencedFrame(select_url_result1, 'opaque-ads');
+ const result1 = await nextValueFromServer(ancestor_key);
+
+ // This indicates that the prior worklet0.selectURL and worklet1.selectURL ran
+ // in two different worklet environments, as they did not share the global
+ // variable.
+ assert_equals(result1, "frame0_loaded");
+
+}, 'selectURL() on two explicitly created SharedStorageWorklet. The two ' +
+ 'calls should run in two different worklet environments.');
+
+</script>
+</body>
diff --git a/testing/web-platform/tests/shared-storage/select-url-permissions-policy-default.tentative.https.sub.html b/testing/web-platform/tests/shared-storage/select-url-permissions-policy-default.tentative.https.sub.html
new file mode 100644
index 0000000000..67911388ec
--- /dev/null
+++ b/testing/web-platform/tests/shared-storage/select-url-permissions-policy-default.tentative.https.sub.html
@@ -0,0 +1,29 @@
+<!doctype html>
+<body>
+ <script src=/resources/testharness.js></script>
+ <script src=/resources/testharnessreport.js></script>
+ <script src=/permissions-policy/resources/permissions-policy.js></script>
+ <script src="/shared-storage/resources/util.js"></script>
+ <script>
+ 'use strict';
+ const same_origin_src = '/shared-storage/resources/select-url-permissions-policy-helper.html';
+ const cross_origin_src = 'https://{{domains[www]}}:{{ports[https][0]}}' +
+ same_origin_src;
+ const header = 'Default permissions policy';
+
+ promise_test(async t => {
+ const allowed = await IsSharedStorageSelectUrlAllowedByPermissionsPolicy();
+ assert_true(allowed);
+ }, header + ' allows sharedStorage.selectURL() in the current page.');
+
+ async_test(t => {
+ test_feature_availability('shared-storage-select-url', t, same_origin_src,
+ expect_feature_available_default);
+ }, header + ' allows sharedStorage.selectURL() in same-origin iframes.');
+
+ async_test(t => {
+ test_feature_availability('shared-storage-select-url', t, cross_origin_src,
+ expect_feature_available_default);
+ }, header + ' allows sharedStorage.selectURL() in cross-origin iframes.');
+ </script>
+</body>
diff --git a/testing/web-platform/tests/shared-storage/select-url-permissions-policy-none.tentative.https.sub.html b/testing/web-platform/tests/shared-storage/select-url-permissions-policy-none.tentative.https.sub.html
new file mode 100644
index 0000000000..6820edb084
--- /dev/null
+++ b/testing/web-platform/tests/shared-storage/select-url-permissions-policy-none.tentative.https.sub.html
@@ -0,0 +1,29 @@
+<!doctype html>
+<body>
+ <script src=/resources/testharness.js></script>
+ <script src=/resources/testharnessreport.js></script>
+ <script src=/permissions-policy/resources/permissions-policy.js></script>
+ <script src="/shared-storage/resources/util.js"></script>
+ <script>
+ 'use strict';
+ const same_origin_src = '/shared-storage/resources/select-url-permissions-policy-helper.html';
+ const cross_origin_src = 'https://{{domains[www]}}:{{ports[https][0]}}' +
+ same_origin_src;
+ const header = 'permissions policy header shared-storage-select-url=()';
+
+ promise_test(async t => {
+ const allowed = await IsSharedStorageSelectUrlAllowedByPermissionsPolicy();
+ assert_false(allowed);
+ }, header + ' disallows sharedStorage.selectURL() in the current page.');
+
+ async_test(t => {
+ test_feature_availability('shared-storage-select-url', t, same_origin_src,
+ expect_feature_unavailable_default);
+ }, header + ' disallows sharedStorage.selectURL() in same-origin iframes.');
+
+ async_test(t => {
+ test_feature_availability('shared-storage-select-url', t, cross_origin_src,
+ expect_feature_unavailable_default);
+ }, header + ' disallows sharedStorage.selectURL() in cross-origin iframes.');
+ </script>
+</body>
diff --git a/testing/web-platform/tests/shared-storage/select-url-permissions-policy-none.tentative.https.sub.html.headers b/testing/web-platform/tests/shared-storage/select-url-permissions-policy-none.tentative.https.sub.html.headers
new file mode 100644
index 0000000000..fdd2e3780b
--- /dev/null
+++ b/testing/web-platform/tests/shared-storage/select-url-permissions-policy-none.tentative.https.sub.html.headers
@@ -0,0 +1 @@
+Permissions-Policy: shared-storage-select-url=()
diff --git a/testing/web-platform/tests/shared-storage/select-url-permissions-policy-self.tentative.https.sub.html b/testing/web-platform/tests/shared-storage/select-url-permissions-policy-self.tentative.https.sub.html
new file mode 100644
index 0000000000..b79bc065c2
--- /dev/null
+++ b/testing/web-platform/tests/shared-storage/select-url-permissions-policy-self.tentative.https.sub.html
@@ -0,0 +1,29 @@
+<!doctype html>
+<body>
+ <script src=/resources/testharness.js></script>
+ <script src=/resources/testharnessreport.js></script>
+ <script src=/permissions-policy/resources/permissions-policy.js></script>
+ <script src="/shared-storage/resources/util.js"></script>
+ <script>
+ 'use strict';
+ const same_origin_src = '/shared-storage/resources/select-url-permissions-policy-helper.html';
+ const cross_origin_src = 'https://{{domains[www]}}:{{ports[https][0]}}' +
+ same_origin_src;
+ const header = 'permissions policy header shared-storage-select-url=(self)';
+
+ promise_test(async t => {
+ const allowed = await IsSharedStorageSelectUrlAllowedByPermissionsPolicy();
+ assert_true(allowed);
+ }, header + ' allows sharedStorage.selectURL() in the current page.');
+
+ async_test(t => {
+ test_feature_availability('shared-storage-select-url', t, same_origin_src,
+ expect_feature_available_default);
+ }, header + ' allows sharedStorage.selectURL() in same-origin iframes.');
+
+ async_test(t => {
+ test_feature_availability('shared-storage-select-url', t, cross_origin_src,
+ expect_feature_unavailable_default);
+ }, header + ' disallows sharedStorage.selectURL() in cross-origin iframes.');
+ </script>
+</body>
diff --git a/testing/web-platform/tests/shared-storage/select-url-permissions-policy-self.tentative.https.sub.html.headers b/testing/web-platform/tests/shared-storage/select-url-permissions-policy-self.tentative.https.sub.html.headers
new file mode 100644
index 0000000000..20d5451ba2
--- /dev/null
+++ b/testing/web-platform/tests/shared-storage/select-url-permissions-policy-self.tentative.https.sub.html.headers
@@ -0,0 +1 @@
+Permissions-Policy: shared-storage-select-url=(self)
diff --git a/testing/web-platform/tests/shared-storage/select-url-report-event.tentative.https.sub.html b/testing/web-platform/tests/shared-storage/select-url-report-event.tentative.https.sub.html
new file mode 100644
index 0000000000..b2ad2d1b2a
--- /dev/null
+++ b/testing/web-platform/tests/shared-storage/select-url-report-event.tentative.https.sub.html
@@ -0,0 +1,65 @@
+<!doctype html>
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="/common/utils.js"></script>
+<script src="/shared-storage/resources/util.js"></script>
+<script src="/fenced-frame/resources/utils.js"></script>
+
+<body>
+<script>
+'use strict';
+
+// Poll the server for the test result.
+async function waitForReportCount(id) {
+ const url = `/shared-storage/resources/report.py?query&token=${id}`;
+ for (let i = 0; i < 30; ++i) {
+ const response = await fetch(url);
+ let count = response.headers.get("Count");
+
+ if (!count || count === '0') {
+ await new Promise(resolve => step_timeout(resolve, 100));
+ continue;
+ }
+
+ return parseInt(count);
+ }
+ assert_true(false, 'timeout');
+}
+
+for (const resolve_to_config of [true, false]) {
+ promise_test(async () => {
+ const ancestor_key = token();
+ let url0 = generateURL("/shared-storage/resources/sender0.html",
+ [ancestor_key]);
+ let url1 = generateURL("/shared-storage/resources/sender1.html",
+ [ancestor_key]);
+
+ await addModuleOnce("/shared-storage/resources/simple-module.js");
+
+ const report_id = token();
+ const reportURL = `/shared-storage/resources/report.py?token=${report_id}`;
+ let select_url_result = await sharedStorage.selectURL(
+ "test-url-selection-operation", [
+ {url: url0,
+ reportingMetadata:
+ {
+ 'click': reportURL,
+ 'mouse interaction':
+ "/shared-storage/resources/receiver1.html"
+ }
+ }, {url: url1}
+ ], {data: {'mockResult': 0}, resolveToConfig: resolve_to_config,
+ keepAlive: resolve_to_config});
+ assert_true(validateSelectURLResult(select_url_result, resolve_to_config));
+ attachFencedFrame(select_url_result, 'opaque-ads');
+ const result0 = await nextValueFromServer(ancestor_key);
+ assert_equals(result0, "sender0_reported");
+
+ const reportCount = await waitForReportCount(report_id);
+ assert_equals(reportCount, 1, `Num reports received: ${reportCount}`);
+ }, 'selectURL() with reportEvent(), selectURL() resolves to ' +
+ (resolve_to_config ? 'config' : 'urn:uuid'));
+}
+
+</script>
+</body>
diff --git a/testing/web-platform/tests/shared-storage/setters.tentative.https.sub.html b/testing/web-platform/tests/shared-storage/setters.tentative.https.sub.html
new file mode 100644
index 0000000000..ffc4bfbd7d
--- /dev/null
+++ b/testing/web-platform/tests/shared-storage/setters.tentative.https.sub.html
@@ -0,0 +1,76 @@
+<!doctype html>
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+
+<body>
+<script>
+'use strict';
+
+promise_test(async t => {
+ return promise_rejects_js(t, TypeError, sharedStorage.set());
+}, 'sharedStorage.set with 0 argument');
+
+promise_test(async t => {
+ return promise_rejects_js(t, TypeError, sharedStorage.set("a"));
+}, 'sharedStorage.set with 1 argument');
+
+promise_test(() => {
+ return sharedStorage.set("a", "b");
+}, 'sharedStorage.set with 2 arguments');
+
+promise_test(() => {
+ return sharedStorage.set("a", "b", {ignoreIfPresent: true});
+}, 'sharedStorage.set with options');
+
+promise_test(async t => {
+ return promise_rejects_js(t, TypeError, sharedStorage.set("a", "b", "c"));
+}, 'sharedStorage.set with invalid options');
+
+promise_test(() => {
+ return sharedStorage.set('a'.repeat(1024), 'b'.repeat(1024));
+}, 'sharedStorage.set with max allowed key and value length');
+
+promise_test(async t => {
+ try {
+ await sharedStorage.set('', 'b');
+ } catch (e) {
+ assert_equals(e.name, 'DataError');
+ return;
+ }
+ assert_unreached("did not reject");
+}, 'sharedStorage.set with empty key');
+
+promise_test(async t => {
+ try {
+ await sharedStorage.set('a'.repeat(1025), 'b');
+ } catch (e) {
+ assert_equals(e.name, 'DataError');
+ return;
+ }
+ assert_unreached("did not reject");
+}, 'sharedStorage.set with key length too big');
+
+promise_test(async t => {
+ try {
+ await sharedStorage.set('a', 'b'.repeat(1025));
+ } catch (e) {
+ assert_equals(e.name, 'DataError');
+ return;
+ }
+ assert_unreached("did not reject");
+}, 'sharedStorage.set with value length too big');
+
+promise_test(() => {
+ return sharedStorage.append("a", "b");
+}, 'sharedStorage.append');
+
+promise_test(() => {
+ return sharedStorage.clear();
+}, 'sharedStorage.clear');
+
+promise_test(() => {
+ return sharedStorage.delete("a");
+}, 'sharedStorage.delete');
+
+</script>
+</body>
diff --git a/testing/web-platform/tests/shared-storage/shared-storage-in-sandboxed-iframe.tentative.https.html b/testing/web-platform/tests/shared-storage/shared-storage-in-sandboxed-iframe.tentative.https.html
new file mode 100644
index 0000000000..44512706bd
--- /dev/null
+++ b/testing/web-platform/tests/shared-storage/shared-storage-in-sandboxed-iframe.tentative.https.html
@@ -0,0 +1,41 @@
+<!doctype html>
+<body>
+ <script src=/resources/testharness.js></script>
+ <script src=/resources/testharnessreport.js></script>
+ <script src=/browsing-topics/resources/header-util.sub.js></script>
+ <script>
+ function test_shared_storage_in_sandboxed_iframe(test, sandbox_flags, expect_success) {
+ let frame = document.createElement('iframe');
+ frame.sandbox = sandbox_flags;
+ frame.src = '/shared-storage/resources/verify-shared-storage.https.html';
+
+ window.addEventListener('message', test.step_func(function handler(evt) {
+ if (evt.source === frame.contentWindow) {
+ if (expect_success) {
+ assert_equals(evt.data.accessSharedStorageResult, 'success');
+ } else {
+ assert_equals(evt.data.accessSharedStorageResult, 'failure');
+ }
+
+ document.body.removeChild(frame);
+ window.removeEventListener('message', handler);
+ test.done();
+ }
+ }));
+
+ document.body.appendChild(frame);
+ }
+
+ async_test(t => {
+ test_shared_storage_in_sandboxed_iframe(t,
+ /*sandbox_flags=*/'allow-scripts allow-same-origin',
+ /*expect_success=*/true);
+ }, 'test shared storage in sandboxed iframe with "allow-same-origin"');
+
+ async_test(t => {
+ test_shared_storage_in_sandboxed_iframe(t,
+ /*sandbox_flags=*/'allow-scripts',
+ /*expect_success=*/false);
+ }, 'test shared storage in sandboxed iframe without "allow-same-origin"');
+ </script>
+</body>
diff --git a/testing/web-platform/tests/shared-storage/shared-storage-permissions-policy-default.tentative.https.sub.html b/testing/web-platform/tests/shared-storage/shared-storage-permissions-policy-default.tentative.https.sub.html
new file mode 100644
index 0000000000..5439df2a06
--- /dev/null
+++ b/testing/web-platform/tests/shared-storage/shared-storage-permissions-policy-default.tentative.https.sub.html
@@ -0,0 +1,29 @@
+<!doctype html>
+<body>
+ <script src=/resources/testharness.js></script>
+ <script src=/resources/testharnessreport.js></script>
+ <script src=/permissions-policy/resources/permissions-policy.js></script>
+ <script src="/shared-storage/resources/util.js"></script>
+ <script>
+ 'use strict';
+ const same_origin_src = '/shared-storage/resources/shared-storage-permissions-policy-helper.html';
+ const cross_origin_src = 'https://{{domains[www]}}:{{ports[https][0]}}' +
+ same_origin_src;
+ const header = 'Default permissions policy';
+
+ promise_test(async t => {
+ const allowed = await AreSharedStorageMethodsAllowedByPermissionsPolicy();
+ assert_true(allowed);
+ }, header + ' allows sharedStorage in the current page.');
+
+ async_test(t => {
+ test_feature_availability('shared-storage', t, same_origin_src,
+ expect_feature_available_default);
+ }, header + ' allows sharedStorage in same-origin iframes.');
+
+ async_test(t => {
+ test_feature_availability('shared-storage', t, cross_origin_src,
+ expect_feature_available_default);
+ }, header + ' allows sharedStorage in cross-origin iframes.');
+ </script>
+</body>
diff --git a/testing/web-platform/tests/shared-storage/shared-storage-permissions-policy-none.tentative.https.sub.html b/testing/web-platform/tests/shared-storage/shared-storage-permissions-policy-none.tentative.https.sub.html
new file mode 100644
index 0000000000..17a4bf1803
--- /dev/null
+++ b/testing/web-platform/tests/shared-storage/shared-storage-permissions-policy-none.tentative.https.sub.html
@@ -0,0 +1,29 @@
+<!doctype html>
+<body>
+ <script src=/resources/testharness.js></script>
+ <script src=/resources/testharnessreport.js></script>
+ <script src=/permissions-policy/resources/permissions-policy.js></script>
+ <script src="/shared-storage/resources/util.js"></script>
+ <script>
+ 'use strict';
+ const same_origin_src = '/shared-storage/resources/shared-storage-permissions-policy-helper.html';
+ const cross_origin_src = 'https://{{domains[www]}}:{{ports[https][0]}}' +
+ same_origin_src;
+ const header = 'permissions policy header shared-storage=()';
+
+ promise_test(async t => {
+ const allowed = await AreSharedStorageMethodsAllowedByPermissionsPolicy();
+ assert_false(allowed);
+ }, header + ' disallows sharedStorage in the current page.');
+
+ async_test(t => {
+ test_feature_availability('shared-storage', t, same_origin_src,
+ expect_feature_unavailable_default);
+ }, header + ' disallows sharedStorage in same-origin iframes.');
+
+ async_test(t => {
+ test_feature_availability('shared-storage', t, cross_origin_src,
+ expect_feature_unavailable_default);
+ }, header + ' disallows sharedStorage in cross-origin iframes.');
+ </script>
+</body>
diff --git a/testing/web-platform/tests/shared-storage/shared-storage-permissions-policy-none.tentative.https.sub.html.headers b/testing/web-platform/tests/shared-storage/shared-storage-permissions-policy-none.tentative.https.sub.html.headers
new file mode 100644
index 0000000000..9903f7c578
--- /dev/null
+++ b/testing/web-platform/tests/shared-storage/shared-storage-permissions-policy-none.tentative.https.sub.html.headers
@@ -0,0 +1 @@
+Permissions-Policy: shared-storage=()
diff --git a/testing/web-platform/tests/shared-storage/shared-storage-permissions-policy-self.tentative.https.sub.html b/testing/web-platform/tests/shared-storage/shared-storage-permissions-policy-self.tentative.https.sub.html
new file mode 100644
index 0000000000..171325cdf8
--- /dev/null
+++ b/testing/web-platform/tests/shared-storage/shared-storage-permissions-policy-self.tentative.https.sub.html
@@ -0,0 +1,29 @@
+<!doctype html>
+<body>
+ <script src=/resources/testharness.js></script>
+ <script src=/resources/testharnessreport.js></script>
+ <script src=/permissions-policy/resources/permissions-policy.js></script>
+ <script src="/shared-storage/resources/util.js"></script>
+ <script>
+ 'use strict';
+ const same_origin_src = '/shared-storage/resources/shared-storage-permissions-policy-helper.html';
+ const cross_origin_src = 'https://{{domains[www]}}:{{ports[https][0]}}' +
+ same_origin_src;
+ const header = 'permissions policy header shared-storage=(self)';
+
+ promise_test(async t => {
+ const allowed = await AreSharedStorageMethodsAllowedByPermissionsPolicy();
+ assert_true(allowed);
+ }, header + ' allows sharedStorage in the current page.');
+
+ async_test(t => {
+ test_feature_availability('shared-storage', t, same_origin_src,
+ expect_feature_available_default);
+ }, header + ' allows sharedStorage in same-origin iframes.');
+
+ async_test(t => {
+ test_feature_availability('shared-storage', t, cross_origin_src,
+ expect_feature_unavailable_default);
+ }, header + ' disallows sharedStorage in cross-origin iframes.');
+ </script>
+</body>
diff --git a/testing/web-platform/tests/shared-storage/shared-storage-permissions-policy-self.tentative.https.sub.html.headers b/testing/web-platform/tests/shared-storage/shared-storage-permissions-policy-self.tentative.https.sub.html.headers
new file mode 100644
index 0000000000..36c95f2b08
--- /dev/null
+++ b/testing/web-platform/tests/shared-storage/shared-storage-permissions-policy-self.tentative.https.sub.html.headers
@@ -0,0 +1 @@
+Permissions-Policy: shared-storage=(self)
diff --git a/testing/web-platform/tests/shared-storage/shared-storage-writable-clear.tentative.https.sub.html b/testing/web-platform/tests/shared-storage/shared-storage-writable-clear.tentative.https.sub.html
new file mode 100644
index 0000000000..2d606d6bc1
--- /dev/null
+++ b/testing/web-platform/tests/shared-storage/shared-storage-writable-clear.tentative.https.sub.html
@@ -0,0 +1,50 @@
+<!doctype html>
+<body>
+ <script src=/resources/testharness.js></script>
+ <script src=/resources/testharnessreport.js></script>
+ <script src=/common/utils.js></script>
+ <script src=/common/get-host-info.sub.js></script>
+ <script src=/fenced-frame/resources/utils.js></script>
+ <script src=/shared-storage/resources/util.js></script>
+ <script>
+ 'use strict';
+
+ const sameOriginClearUrl =
+ `/shared-storage/resources/shared-storage-write.py?write=clear`;
+ const sameOrigin = generateURL(sameOriginClearUrl, []).origin;
+ const crossOrigin = 'https://{{domains[www]}}:{{ports[https][0]}}';
+ const crossOriginClearUrl = crossOrigin + sameOriginClearUrl;
+
+ promise_test(async t => {
+ await sharedStorage.set("hello", "there");
+ await verifyKeyValueForOrigin('hello', 'there', sameOrigin);
+
+ let response = await fetch(sameOriginClearUrl,
+ {sharedStorageWritable: true});
+ let sharedStorageWritableHeader = await response.text();
+ assert_equals(sharedStorageWritableHeader, "?1");
+
+ // JS does not see the `Shared-Storage-Write` response header.
+ assert_false(!!response.headers.get('Shared-Storage-Write'));
+
+ await verifyKeyNotFoundForOrigin('hello', sameOrigin);
+ }, 'Clearing from shared storage via the \'Shared-Storage-Write\' header '
+ + 'for a same-origin shared storage fetch request');
+
+ promise_test(async t => {
+ await setKeyValueForOrigin('hello', 'there', crossOrigin);
+ await verifyKeyValueForOrigin('hello', 'there', crossOrigin);
+
+ let response = await fetch(crossOriginClearUrl,
+ {sharedStorageWritable: true});
+ let sharedStorageWritableHeader = await response.text();
+ assert_equals(sharedStorageWritableHeader, "?1");
+
+ // JS does not see the `Shared-Storage-Write` response header.
+ assert_false(!!response.headers.get('Shared-Storage-Write'));
+
+ await verifyKeyNotFoundForOrigin('hello', crossOrigin);
+ }, 'Clearing from shared storage via the \'Shared-Storage-Write\' header '
+ + 'for a cross-origin shared storage fetch request');
+ </script>
+</body>
diff --git a/testing/web-platform/tests/shared-storage/shared-storage-writable-delete.tentative.https.sub.html b/testing/web-platform/tests/shared-storage/shared-storage-writable-delete.tentative.https.sub.html
new file mode 100644
index 0000000000..fc7f2fb90e
--- /dev/null
+++ b/testing/web-platform/tests/shared-storage/shared-storage-writable-delete.tentative.https.sub.html
@@ -0,0 +1,52 @@
+<!doctype html>
+<body>
+ <script src=/resources/testharness.js></script>
+ <script src=/resources/testharnessreport.js></script>
+ <script src=/common/utils.js></script>
+ <script src=/common/get-host-info.sub.js></script>
+ <script src=/fenced-frame/resources/utils.js></script>
+ <script src=/shared-storage/resources/util.js></script>
+ <script>
+ 'use strict';
+
+ const rawDeleteHeader = 'delete;key=hello';
+ const deleteHeader = encodeURIComponent(rawDeleteHeader);
+ const sameOriginDeleteUrl =
+ `/shared-storage/resources/shared-storage-write.py?write=${deleteHeader}`
+ const sameOrigin = generateURL(sameOriginDeleteUrl, []).origin;
+ const crossOrigin = 'https://{{domains[www]}}:{{ports[https][0]}}';
+ const crossOriginDeleteUrl = crossOrigin + sameOriginDeleteUrl;
+
+ promise_test(async t => {
+ await sharedStorage.set("hello", "there");
+ await verifyKeyValueForOrigin('hello', 'there', sameOrigin);
+
+ let response = await fetch(sameOriginDeleteUrl,
+ {sharedStorageWritable: true});
+ let sharedStorageWritableHeader = await response.text();
+ assert_equals(sharedStorageWritableHeader, "?1");
+
+ // JS does not see the `Shared-Storage-Write` response header.
+ assert_false(!!response.headers.get('Shared-Storage-Write'));
+
+ await verifyKeyNotFoundForOrigin('hello', sameOrigin);
+ }, 'Deleting from shared storage via the \'Shared-Storage-Write\' header '
+ + 'for a same-origin shared storage fetch request');
+
+ promise_test(async t => {
+ await setKeyValueForOrigin('hello', 'there', crossOrigin);
+ await verifyKeyValueForOrigin('hello', 'there', crossOrigin);
+
+ let response = await fetch(crossOriginDeleteUrl,
+ {sharedStorageWritable: true});
+ let sharedStorageWritableHeader = await response.text();
+ assert_equals(sharedStorageWritableHeader, "?1");
+
+ // JS does not see the `Shared-Storage-Write` response header.
+ assert_false(!!response.headers.get('Shared-Storage-Write'));
+
+ await verifyKeyNotFoundForOrigin('hello', crossOrigin);
+ }, 'Deleting from shared storage via the \'Shared-Storage-Write\' header '
+ + 'for a cross-origin shared storage fetch request');
+ </script>
+</body>
diff --git a/testing/web-platform/tests/shared-storage/shared-storage-writable-forbidden-header-tentative.https.html b/testing/web-platform/tests/shared-storage/shared-storage-writable-forbidden-header-tentative.https.html
new file mode 100644
index 0000000000..896fb79240
--- /dev/null
+++ b/testing/web-platform/tests/shared-storage/shared-storage-writable-forbidden-header-tentative.https.html
@@ -0,0 +1,49 @@
+<!doctype html>
+<body>
+ <script src=/resources/testharness.js></script>
+ <script src=/resources/testharnessreport.js></script>
+ <script src=/common/utils.js></script>
+ <script src=/fenced-frame/resources/utils.js></script>
+ <script src=/shared-storage/resources/util.js></script>
+ <script>
+ 'use strict';
+ const rawSetHeader = 'set;key=hello;value=world';
+ const setHeader = encodeURIComponent(rawSetHeader);
+ const sameOriginUrl =
+ `/shared-storage/resources/shared-storage-write.py?write=${setHeader}`;
+ const sameOrigin = generateURL(sameOriginUrl, []).origin;
+
+ promise_test(async t => {
+ const request = new Request(sameOriginUrl,
+ {
+ headers: {
+ 'Sec-Shared-Storage-Writable': '?1'
+ }
+ });
+ assert_equals(request.mode, 'cors');
+ let response = await fetch(request);
+ let sharedStorageWritableHeader = await response.text();
+ assert_equals(sharedStorageWritableHeader,
+ "NO_SHARED_STORAGE_WRITABLE_HEADER");
+ await verifyKeyNotFoundForOrigin('hello', sameOrigin);
+ }, 'The \'Sec-Shared-Storage-Writable\' header cannot successfully be '
+ + 'added directly via a JS fetch request with mode cors.');
+
+ promise_test(async t => {
+ const request = new Request(sameOriginUrl,
+ {
+ headers: {
+ 'Sec-Shared-Storage-Writable': '?1'
+ },
+ mode: 'no-cors'
+ });
+ assert_equals(request.mode, 'no-cors');
+ let response = await fetch(request);
+ let sharedStorageWritableHeader = await response.text();
+ assert_equals(sharedStorageWritableHeader,
+ "NO_SHARED_STORAGE_WRITABLE_HEADER");
+ await verifyKeyNotFoundForOrigin('hello', sameOrigin);
+ }, 'The \'Sec-Shared-Storage-Writable\' header cannot successfully be '
+ + 'added directly via a JS fetch request with mode no-cors.');
+ </script>
+</body>
diff --git a/testing/web-platform/tests/shared-storage/shared-storage-writable-iframe-content-attribute.tentative.https.sub.html b/testing/web-platform/tests/shared-storage/shared-storage-writable-iframe-content-attribute.tentative.https.sub.html
new file mode 100644
index 0000000000..f27c8548cb
--- /dev/null
+++ b/testing/web-platform/tests/shared-storage/shared-storage-writable-iframe-content-attribute.tentative.https.sub.html
@@ -0,0 +1,22 @@
+<!doctype html>
+<body>
+ <script src=/resources/testharness.js></script>
+ <script src=/resources/testharnessreport.js></script>
+ <script src=/common/utils.js></script>
+ <script src=/fenced-frame/resources/utils.js></script>
+ <script src=/shared-storage/resources/util.js></script>
+ <iframe src="/shared-storage/resources/shared-storage-write-notify-parent.py?write=set%3Bkey%3Dhello%3Bvalue%3Dworld" sharedstoragewritable></iframe>
+ <iframe src="/shared-storage/resources/shared-storage-write-notify-parent.py?write=set%3Bkey%3Dwont%3Bvalue%3Dset"></iframe>
+ <iframe src="/shared-storage/resources/shared-storage-write-notify-parent.py?write=set%3Bkey%3Dgoodnight%3Bvalue%3Dmoon" sharedstoragewritable></iframe>
+ <script>
+ const sameOrigin = new URL("", location.href).origin;
+
+ promise_test(async t => {
+ await verifyKeyValueForOrigin('hello', 'world', sameOrigin);
+ await verifyKeyNotFoundForOrigin('wont', sameOrigin);
+ await verifyKeyValueForOrigin('goodnight', 'moon', sameOrigin);
+ await deleteKeyForOrigin('hello', sameOrigin);
+ await deleteKeyForOrigin('goodnight', sameOrigin);
+ }, 'test <iframe sharedstoragewritable src=[url]> for same origin iframe');
+ </script>
+</body>
diff --git a/testing/web-platform/tests/shared-storage/shared-storage-writable-iframe-idl-attribute-included.tentative.https.sub.html b/testing/web-platform/tests/shared-storage/shared-storage-writable-iframe-idl-attribute-included.tentative.https.sub.html
new file mode 100644
index 0000000000..2947ea51e0
--- /dev/null
+++ b/testing/web-platform/tests/shared-storage/shared-storage-writable-iframe-idl-attribute-included.tentative.https.sub.html
@@ -0,0 +1,37 @@
+<!doctype html>
+<body>
+ <script src=/resources/testharness.js></script>
+ <script src=/resources/testharnessreport.js></script>
+ <script src=/common/utils.js></script>
+ <script src=/fenced-frame/resources/utils.js></script>
+ <script src=/shared-storage/resources/util.js></script>
+ <script src=/shared-storage/resources/util.sub.js></script>
+ <script>
+ const sameOrigin = new URL("", location.href).origin;
+ const crossOrigin = 'https://{{domains[www]}}:{{ports[https][0]}}';
+
+ promise_test(async () => {
+ await navigateSharedStorageIframe({
+ hasSharedStorageWritableAttribute: true,
+ rawWriteHeader: "set;key=a;value=b",
+ isSameOrigin: true,
+ expectSharedStorageWritableHeader: true,
+ });
+ await verifyKeyValueForOrigin('a', 'b', sameOrigin);
+ await deleteKeyForOrigin('a', sameOrigin);
+ }, 'test <iframe sharedstoragewritable src=[url]></iframe> via JS for'
+ + ' same origin iframe');
+
+ promise_test(async () => {
+ await navigateSharedStorageIframe({
+ hasSharedStorageWritableAttribute: true,
+ rawWriteHeader: "set;key=c;value=d",
+ isSameOrigin: false,
+ expectSharedStorageWritableHeader: true,
+ });
+ await verifyKeyValueForOrigin('c', 'd', crossOrigin);
+ await deleteKeyForOrigin('c', crossOrigin);
+ }, 'test <iframe sharedstoragewritable src=[url]></iframe> via JS for'
+ + ' cross origin iframe');
+ </script>
+</body>
diff --git a/testing/web-platform/tests/shared-storage/shared-storage-writable-iframe-idl-attribute-not-included.tentative.https.sub.html b/testing/web-platform/tests/shared-storage/shared-storage-writable-iframe-idl-attribute-not-included.tentative.https.sub.html
new file mode 100644
index 0000000000..13a45a275b
--- /dev/null
+++ b/testing/web-platform/tests/shared-storage/shared-storage-writable-iframe-idl-attribute-not-included.tentative.https.sub.html
@@ -0,0 +1,33 @@
+<!doctype html>
+<body>
+ <script src=/resources/testharness.js></script>
+ <script src=/resources/testharnessreport.js></script>
+ <script src=/common/utils.js></script>
+ <script src=/fenced-frame/resources/utils.js></script>
+ <script src=/shared-storage/resources/util.js></script>
+ <script src=/shared-storage/resources/util.sub.js></script>
+ <script>
+ const sameOrigin = new URL("", location.href).origin;
+ const crossOrigin = 'https://{{domains[www]}}:{{ports[https][0]}}';
+
+ promise_test(async () => {
+ await navigateSharedStorageIframe({
+ hasSharedStorageWritableAttribute: false,
+ rawWriteHeader: "set;key=e;value=f",
+ isSameOrigin: true,
+ expectSharedStorageWritableHeader: false,
+ });
+ await verifyKeyNotFoundForOrigin('e', sameOrigin);
+ }, 'test <iframe src=[url]></iframe> via JS for same origin iframe');
+
+ promise_test(async () => {
+ await navigateSharedStorageIframe({
+ hasSharedStorageWritableAttribute: false,
+ rawWriteHeader: "set;key=g;value=h",
+ isSameOrigin: false,
+ expectSharedStorageWritableHeader: false,
+ });
+ await verifyKeyNotFoundForOrigin('g', crossOrigin);
+ }, 'test <iframe src=[url]></iframe> via JS for cross origin iframe');
+ </script>
+</body>
diff --git a/testing/web-platform/tests/shared-storage/shared-storage-writable-iframe-in-fenced.tentative.https.sub.html b/testing/web-platform/tests/shared-storage/shared-storage-writable-iframe-in-fenced.tentative.https.sub.html
new file mode 100644
index 0000000000..e3a9803f01
--- /dev/null
+++ b/testing/web-platform/tests/shared-storage/shared-storage-writable-iframe-in-fenced.tentative.https.sub.html
@@ -0,0 +1,27 @@
+<!doctype html>
+<body>
+ <script src=/resources/testharness.js></script>
+ <script src=/resources/testharnessreport.js></script>
+ <script src=/common/utils.js></script>
+ <script src=/fenced-frame/resources/utils.js></script>
+ <script src=/shared-storage/resources/util.js></script>
+ <script src=/shared-storage/resources/util.sub.js></script>
+ <script>
+ promise_test(async t => {
+ const outerKey = token();
+ let url = generateURL(
+ '/shared-storage/resources/'
+ + 'shared-storage-writable-iframe-in-fenced-inner.https.sub.html',
+ [outerKey]);
+ url = appendExpectedKeyAndValue(url, 'a', 'b');
+
+ let fencedFrameConfig = await runSelectRawURL(url, true);
+ assert_true(validateSelectURLResult(fencedFrameConfig, true));
+
+ attachFencedFrame(fencedFrameConfig, 'opaque-ads');
+ const result = await nextValueFromServer(outerKey);
+ assert_equals(result, "writable_iframe_in_fenced_inner_loaded");
+ }, 'test <iframe sharedstoragewritable src=[url]></iframe> via JS inside'
+ + ' a fenced frame');
+ </script>
+</body>
diff --git a/testing/web-platform/tests/shared-storage/shared-storage-writable-img-content-attribute.tentative.https.sub.html b/testing/web-platform/tests/shared-storage/shared-storage-writable-img-content-attribute.tentative.https.sub.html
new file mode 100644
index 0000000000..5bce34d91a
--- /dev/null
+++ b/testing/web-platform/tests/shared-storage/shared-storage-writable-img-content-attribute.tentative.https.sub.html
@@ -0,0 +1,22 @@
+<!doctype html>
+<body>
+ <script src=/resources/testharness.js></script>
+ <script src=/resources/testharnessreport.js></script>
+ <script src=/common/utils.js></script>
+ <script src=/fenced-frame/resources/utils.js></script>
+ <script src=/shared-storage/resources/util.js></script>
+ <img src="/shared-storage/resources/shared-storage-writable-pixel.png?key=hello&value=world" sharedstoragewritable></img>
+ <img src="/shared-storage/resources/shared-storage-writable-pixel.png?key=wont&value=set"></img>
+ <img src="/shared-storage/resources/shared-storage-writable-pixel.png?key=goodnight&value=moon" sharedstoragewritable></img>
+ <script>
+ const sameOrigin = new URL("", location.href).origin;
+
+ promise_test(async t => {
+ await verifyKeyValueForOrigin('hello', 'world', sameOrigin);
+ await verifyKeyNotFoundForOrigin('wont', sameOrigin);
+ await verifyKeyValueForOrigin('goodnight', 'moon', sameOrigin);
+ await deleteKeyForOrigin('hello', sameOrigin);
+ await deleteKeyForOrigin('goodnight', sameOrigin);
+ }, 'test <img sharedstoragewritable src=[url]> for same origin img');
+ </script>
+</body>
diff --git a/testing/web-platform/tests/shared-storage/shared-storage-writable-img-idl-attribute-included-bytes.tentative.https.sub.html b/testing/web-platform/tests/shared-storage/shared-storage-writable-img-idl-attribute-included-bytes.tentative.https.sub.html
new file mode 100644
index 0000000000..b358e87e5c
--- /dev/null
+++ b/testing/web-platform/tests/shared-storage/shared-storage-writable-img-idl-attribute-included-bytes.tentative.https.sub.html
@@ -0,0 +1,39 @@
+<!doctype html>
+<body>
+ <script src=/resources/testharness.js></script>
+ <script src=/resources/testharnessreport.js></script>
+ <script src=/common/utils.js></script>
+ <script src=/fenced-frame/resources/utils.js></script>
+ <script src=/shared-storage/resources/util.js></script>
+ <script src=/shared-storage/resources/util.sub.js></script>
+ <script>
+ const sameOrigin = new URL("", location.href).origin;
+ const crossOrigin = 'https://{{domains[www]}}:{{ports[https][0]}}';
+
+ promise_test(async t => {
+ const promise = loadSharedStorageImage({
+ key: ':8J+YgA==:', value: ':4p2k:',
+ hasSharedStorageWritableAttribute: true,
+ isSameOrigin: true,
+ });
+ promise.then((img) => {
+ verifyKeyValueForOrigin('😀', '❤', sameOrigin);
+ deleteKeyForOrigin('😀', sameOrigin);
+ t.done();
+ });
+ }, 'test <img sharedstoragewritable src=[url]> via JS for same origin img with bytestring');
+
+ promise_test(async t => {
+ const promise = loadSharedStorageImage({
+ key: ':8J+MjQ==:', value: ':8J+PgQ==:',
+ hasSharedStorageWritableAttribute: true,
+ isSameOrigin: false,
+ });
+ promise.then((img) => {
+ verifyKeyValueForOrigin('🌍', '🏁', crossOrigin);
+ deleteKeyForOrigin('🌍', crossOrigin);
+ t.done();
+ });
+ }, 'test <img sharedstoragewritable src=[url]> via JS for cross origin img with bytestring');
+ </script>
+</body>
diff --git a/testing/web-platform/tests/shared-storage/shared-storage-writable-img-idl-attribute-included.tentative.https.sub.html b/testing/web-platform/tests/shared-storage/shared-storage-writable-img-idl-attribute-included.tentative.https.sub.html
new file mode 100644
index 0000000000..3e054146de
--- /dev/null
+++ b/testing/web-platform/tests/shared-storage/shared-storage-writable-img-idl-attribute-included.tentative.https.sub.html
@@ -0,0 +1,39 @@
+<!doctype html>
+<body>
+ <script src=/resources/testharness.js></script>
+ <script src=/resources/testharnessreport.js></script>
+ <script src=/common/utils.js></script>
+ <script src=/fenced-frame/resources/utils.js></script>
+ <script src=/shared-storage/resources/util.js></script>
+ <script src=/shared-storage/resources/util.sub.js></script>
+ <script>
+ const sameOrigin = new URL("", location.href).origin;
+ const crossOrigin = 'https://{{domains[www]}}:{{ports[https][0]}}';
+
+ promise_test(async t => {
+ const promise = loadSharedStorageImage({
+ key: 'a', value: 'b',
+ hasSharedStorageWritableAttribute: true,
+ isSameOrigin: true,
+ });
+ promise.then((img) => {
+ verifyKeyValueForOrigin('a', 'b', sameOrigin);
+ deleteKeyForOrigin('a', sameOrigin);
+ t.done();
+ });
+ }, 'test <img sharedstoragewritable src=[url]> via JS for same origin img');
+
+ promise_test(async t => {
+ const promise = loadSharedStorageImage({
+ key: 'c', value: 'd',
+ hasSharedStorageWritableAttribute: true,
+ isSameOrigin: false,
+ });
+ promise.then((img) => {
+ verifyKeyValueForOrigin('c', 'd', crossOrigin);
+ deleteKeyForOrigin('d', crossOrigin);
+ t.done();
+ });
+ }, 'test <img sharedstoragewritable src=[url]> via JS for cross origin img');
+ </script>
+</body>
diff --git a/testing/web-platform/tests/shared-storage/shared-storage-writable-img-idl-attribute-not-included.tentative.https.sub.html b/testing/web-platform/tests/shared-storage/shared-storage-writable-img-idl-attribute-not-included.tentative.https.sub.html
new file mode 100644
index 0000000000..56badca311
--- /dev/null
+++ b/testing/web-platform/tests/shared-storage/shared-storage-writable-img-idl-attribute-not-included.tentative.https.sub.html
@@ -0,0 +1,37 @@
+<!doctype html>
+<body>
+ <script src=/resources/testharness.js></script>
+ <script src=/resources/testharnessreport.js></script>
+ <script src=/common/utils.js></script>
+ <script src=/fenced-frame/resources/utils.js></script>
+ <script src=/shared-storage/resources/util.js></script>
+ <script src=/shared-storage/resources/util.sub.js></script>
+ <script>
+ const sameOrigin = new URL("", location.href).origin;
+ const crossOrigin = 'https://{{domains[www]}}:{{ports[https][0]}}';
+
+ promise_test(async t => {
+ const promise = loadSharedStorageImage({
+ key: 'f', value: 'g',
+ hasSharedStorageWritableAttribute: false,
+ isSameOrigin: true,
+ });
+ promise.then((img) => {
+ verifyKeyNotFoundForOrigin('f', sameOrigin);
+ t.done();
+ });
+ }, 'test <img src=[url]> via JS for same origin img');
+
+ promise_test(async t => {
+ const promise = loadSharedStorageImage({
+ key: 'h', value: 'i',
+ hasSharedStorageWritableAttribute: false,
+ isSameOrigin: false,
+ });
+ promise.then((img) => {
+ verifyKeyNotFoundForOrigin('h', crossOrigin);
+ t.done();
+ });
+ }, 'test <img src=[url]> via JS for cross origin img');
+ </script>
+</body>
diff --git a/testing/web-platform/tests/shared-storage/shared-storage-writable-insecure-context.tentative.http.sub.html b/testing/web-platform/tests/shared-storage/shared-storage-writable-insecure-context.tentative.http.sub.html
new file mode 100644
index 0000000000..debb6cf9c5
--- /dev/null
+++ b/testing/web-platform/tests/shared-storage/shared-storage-writable-insecure-context.tentative.http.sub.html
@@ -0,0 +1,22 @@
+<!doctype html>
+<body>
+ <script src=/resources/testharness.js></script>
+ <script src=/resources/testharnessreport.js></script>
+ <script>
+ 'use strict';
+
+ promise_test(async t => {
+ try {
+ new Request('./resources/simple-module.js',
+ {sharedStorageWritable: true});
+ } catch (e) {
+ assert_equals(e.name, 'TypeError');
+ assert_equals(e.message, `Failed to construct 'Request': `
+ + `sharedStorageWritable: sharedStorage operations `
+ + `are only available in secure contexts.`);
+ return;
+ }
+ assert_unreached("did not reject");
+ }, 'sharedStorageWritable not allowed in insecure context.');
+ </script>
+</body>
diff --git a/testing/web-platform/tests/shared-storage/shared-storage-writable-multi-redirect.tentative.https.sub.html b/testing/web-platform/tests/shared-storage/shared-storage-writable-multi-redirect.tentative.https.sub.html
new file mode 100644
index 0000000000..137b8f77b2
--- /dev/null
+++ b/testing/web-platform/tests/shared-storage/shared-storage-writable-multi-redirect.tentative.https.sub.html
@@ -0,0 +1,104 @@
+<!doctype html>
+<body>
+ <script src=/resources/testharness.js></script>
+ <script src=/resources/testharnessreport.js></script>
+ <script src=/permissions-policy/resources/permissions-policy.js></script>
+ <script src=/common/utils.js></script>
+ <script src=/fenced-frame/resources/utils.js></script>
+ <script src=/shared-storage/resources/util.js></script>
+ <script>
+ 'use strict';
+ const header = 'permissions policy header shared-storage=(self)';
+
+ const rawSetHeader = 'set;key=hello;value=world';
+ const setHeader = encodeURIComponent(rawSetHeader);
+ const sameOriginFetchUrl =
+ `/shared-storage/resources/shared-storage-write.py?write=${setHeader}`;
+ const sameOriginImageUrl =
+ `/shared-storage/resources/shared-storage-writable-pixel-write.png`
+ + `?write=${setHeader}`;
+ const sameOriginIframeUrl =
+ `/shared-storage/resources/shared-storage-write-notify-parent.py`
+ + `?write=${setHeader}`;
+ const sameOrigin = generateURL(sameOriginFetchUrl, []).origin;
+ const crossOrigin = 'https://{{domains[www]}}:{{ports[https][0]}}';
+
+ promise_test(async t => {
+ let redirectURL = crossOrigin
+ + '/shared-storage/resources/cors-redirect.py?location='
+ + sameOrigin + sameOriginFetchUrl;
+ let response = await fetch('/shared-storage/resources/cors-redirect.py'
+ + '?location=' + encodeURIComponent(redirectURL),
+ {sharedStorageWritable: true});
+ let sharedStorageWritableHeader = await response.text();
+ assert_equals(sharedStorageWritableHeader, "?1");
+
+ await verifyKeyValueForOrigin('hello', 'world', sameOrigin);
+ await deleteKeyForOrigin('hello', sameOrigin);
+ }, header + ' allows the \'Shared-Storage-Writable\' header to be sent '
+ + 'for the redirect of a shared storage fetch request, '
+ + 'where the redirect has a same-origin URL, even if an '
+ + 'intermediate redirect has a cross-origin URL.');
+
+ promise_test(async t => {
+ let redirectURL = crossOrigin
+ + '/shared-storage/resources/cors-redirect.py?location='
+ + sameOrigin + sameOriginImageUrl;
+ let image = document.createElement('img');
+ image.src = '/shared-storage/resources/cors-redirect.py?location='
+ + encodeURIComponent(redirectURL);
+ image.sharedStorageWritable = true;
+
+ const promise = new Promise((resolve, reject) => {
+ image.addEventListener('load', () => {
+ resolve(image);
+ });
+ image.addEventListener('error', () => {
+ reject(new Error('Image load failed'));
+ });
+ });
+ document.body.appendChild(image);
+
+ await promise;
+
+ await verifyKeyValueForOrigin('hello', 'world', sameOrigin);
+ await deleteKeyForOrigin('hello', sameOrigin);
+ }, header + ' allows the \'Shared-Storage-Writable\' header to be sent '
+ + 'for the redirect of a shared storage image request, '
+ + 'where the redirect has a same-origin URL, even if an '
+ + 'intermediate redirect has a cross-origin URL.');
+
+ promise_test(async t => {
+ let redirectURL = crossOrigin
+ + '/shared-storage/resources/cors-redirect.py?location='
+ + sameOrigin + sameOriginIframeUrl;
+ let frame = document.createElement('iframe');
+ frame.src = '/shared-storage/resources/cors-redirect.py?location='
+ + encodeURIComponent(redirectURL);
+ frame.sharedStorageWritable = true;
+
+ const promise = new Promise((resolve, reject) => {
+ window.addEventListener('message', async function handler(evt) {
+ if (evt.source === frame.contentWindow) {
+ assert_equals(evt.data.sharedStorageWritableHeader, '?1');
+ document.body.removeChild(frame);
+ window.removeEventListener('message', handler);
+ resolve();
+ }
+ });
+ window.addEventListener('error', () => {
+ reject(new Error('Navigation error'));
+ });
+ });
+ document.body.appendChild(frame);
+
+ await promise;
+
+ await verifyKeyValueForOrigin('hello', 'world', sameOrigin);
+ await deleteKeyForOrigin('hello', sameOrigin);
+ }, header + ' allows the \'Shared-Storage-Writable\' header to be sent '
+ + 'for the redirect of a shared storage iframe request, '
+ + 'where the redirect has a same-origin URL, even if an '
+ + 'intermediate redirect has a cross-origin URL.');
+ </script>
+</body>
diff --git a/testing/web-platform/tests/shared-storage/shared-storage-writable-multi-redirect.tentative.https.sub.html.headers b/testing/web-platform/tests/shared-storage/shared-storage-writable-multi-redirect.tentative.https.sub.html.headers
new file mode 100644
index 0000000000..36c95f2b08
--- /dev/null
+++ b/testing/web-platform/tests/shared-storage/shared-storage-writable-multi-redirect.tentative.https.sub.html.headers
@@ -0,0 +1 @@
+Permissions-Policy: shared-storage=(self)
diff --git a/testing/web-platform/tests/shared-storage/shared-storage-writable-opaque-origin.tentative.https.sub.html b/testing/web-platform/tests/shared-storage/shared-storage-writable-opaque-origin.tentative.https.sub.html
new file mode 100644
index 0000000000..4829af0e0c
--- /dev/null
+++ b/testing/web-platform/tests/shared-storage/shared-storage-writable-opaque-origin.tentative.https.sub.html
@@ -0,0 +1,41 @@
+<!doctype html>
+<body>
+ <script src=/resources/testharness.js></script>
+ <script src=/resources/testharnessreport.js></script>
+ <script>
+ 'use strict';
+ const rawSetHeader = 'set;key=hello;value=world';
+ const setHeader = encodeURIComponent(rawSetHeader);
+
+ promise_test(async t => {
+ const fetchUrl =
+ `/shared-storage/resources/shared-storage-write.py?write=${setHeader}`;
+ const fetchCode =
+ `try {
+ new Request(fetchUrl,{sharedStorageWritable: true});
+ } catch (e) {
+ assert_equals(e.name, 'TypeError');
+ assert_equals(e.message, "Failed to construct 'Request': "
+ + "sharedStorageWritable: sharedStorage operations "
+ + "are not available for opaque origins.");
+ return;
+ }
+ assert_unreached("did not catch an error");`
+
+ const dataURL = 'data:text/javascript;base64,'
+ + btoa(unescape(encodeURIComponent(fetchCode)));
+ let frame = document.createElement('iframe');
+ frame.src = dataURL;
+ const promise = new Promise((resolve, reject) => {
+ frame.addEventListener('load', () => {
+ resolve();
+ });
+ frame.addEventListener('error', () => {
+ reject(new Error('Navigation failed'));
+ });
+ });
+ document.body.appendChild(frame);
+ await promise;
+ }, 'shared storage fetch request disallowed for opaque origin');
+ </script>
+</body>
diff --git a/testing/web-platform/tests/shared-storage/shared-storage-writable-permissions-policy-default.tentative.https.sub.html b/testing/web-platform/tests/shared-storage/shared-storage-writable-permissions-policy-default.tentative.https.sub.html
new file mode 100644
index 0000000000..6dc2435b93
--- /dev/null
+++ b/testing/web-platform/tests/shared-storage/shared-storage-writable-permissions-policy-default.tentative.https.sub.html
@@ -0,0 +1,68 @@
+<!doctype html>
+<body>
+ <script src=/resources/testharness.js></script>
+ <script src=/resources/testharnessreport.js></script>
+ <script src=/permissions-policy/resources/permissions-policy.js></script>
+ <script src=/common/utils.js></script>
+ <script src=/fenced-frame/resources/utils.js></script>
+ <script src=/shared-storage/resources/util.js></script>
+ <script>
+ 'use strict';
+ const header = 'Default permissions policy';
+ const rawSetHeader = 'set;key=hello;value=world';
+ const setHeader = encodeURIComponent(rawSetHeader);
+ const sameOriginUrl =
+ `/shared-storage/resources/shared-storage-write.py?write=${setHeader}`;
+ const sameOrigin = generateURL(sameOriginUrl, []).origin;
+ const crossOrigin = 'https://{{domains[www]}}:{{ports[https][0]}}';
+ const crossOriginUrl = crossOrigin + sameOriginUrl;
+
+ promise_test(async t => {
+ let response = await fetch(sameOriginUrl,
+ {sharedStorageWritable: true});
+ let sharedStorageWritableHeader = await response.text();
+ assert_equals(sharedStorageWritableHeader, "?1");
+
+ await verifyKeyValueForOrigin('hello', 'world', sameOrigin);
+ await deleteKeyForOrigin('hello', sameOrigin);
+ }, header + ' allows the \'Sec-Shared-Storage-Writable\' header to be '
+ + 'sent for the same-origin shared storage fetch request.');
+
+ promise_test(async t => {
+ let response = await fetch(crossOriginUrl,
+ {sharedStorageWritable: true});
+ let sharedStorageWritableHeader = await response.text();
+ assert_equals(sharedStorageWritableHeader, "?1");
+
+ await verifyKeyValueForOrigin('hello', 'world', crossOrigin);
+ await deleteKeyForOrigin('hello', crossOrigin);
+ }, header + ' allows the \'Sec-Shared-Storage-Writable\' header to be '
+ + 'sent for the cross-origin shared storage fetch request.');
+
+ promise_test(async t => {
+ let response = await fetch('/common/redirect.py?location='
+ + sameOriginUrl,
+ {sharedStorageWritable: true});
+ let sharedStorageWritableHeader = await response.text();
+ assert_equals(sharedStorageWritableHeader, "?1");
+
+ await verifyKeyValueForOrigin('hello', 'world', sameOrigin);
+ await deleteKeyForOrigin('hello', sameOrigin);
+ }, header + ' allows the \'Sec-Shared-Storage-Writable\' header to be '
+ + 'sent for the redirect of a shared storage fetch request, '
+ + 'where the redirect has a same-origin URL.');
+
+ promise_test(async t => {
+ let response = await fetch('/common/redirect.py?location='
+ + crossOriginUrl,
+ {sharedStorageWritable: true});
+ let sharedStorageWritableHeader = await response.text();
+ assert_equals(sharedStorageWritableHeader, "?1");
+
+ await verifyKeyValueForOrigin('hello', 'world', crossOrigin);
+ await deleteKeyForOrigin('hello', crossOrigin);
+ }, header + ' allows the \'Sec-Shared-Storage-Writable\' header to be '
+ + 'sent for the redirect of a shared storage fetch request, '
+ + 'where the redirect has a cross-origin URL.');
+ </script>
+</body>
diff --git a/testing/web-platform/tests/shared-storage/shared-storage-writable-permissions-policy-none.tentative.https.sub.html b/testing/web-platform/tests/shared-storage/shared-storage-writable-permissions-policy-none.tentative.https.sub.html
new file mode 100644
index 0000000000..1a1e4076ca
--- /dev/null
+++ b/testing/web-platform/tests/shared-storage/shared-storage-writable-permissions-policy-none.tentative.https.sub.html
@@ -0,0 +1,33 @@
+<!doctype html>
+<body>
+ <script src=/resources/testharness.js></script>
+ <script src=/resources/testharnessreport.js></script>
+ <script src=/permissions-policy/resources/permissions-policy.js></script>
+ <script src=/shared-storage/resources/util.js></script>
+ <script>
+ 'use strict';
+ const header = 'permissions policy header shared-storage=()';
+ const sameOriginUrl =
+ '/shared-storage/resources/shared-storage-write.py';
+ const crossOrigin = 'https://{{domains[www]}}:{{ports[https][0]}}';
+ const crossOriginUrl = crossOrigin + sameOriginUrl;
+
+ promise_test(async t => {
+ let response = await fetch(sameOriginUrl,
+ {sharedStorageWritable: true});
+ let sharedStorageWritableHeader = await response.text();
+ assert_equals(sharedStorageWritableHeader,
+ "NO_SHARED_STORAGE_WRITABLE_HEADER");
+ }, header + ' disallows the \'Sec-Shared-Storage-Writable\' header to be '
+ + 'sent for the same-origin shared storage fetch request.');
+
+ promise_test(async t => {
+ let response = await fetch(crossOriginUrl,
+ {sharedStorageWritable: true});
+ let sharedStorageWritableHeader = await response.text();
+ assert_equals(sharedStorageWritableHeader,
+ "NO_SHARED_STORAGE_WRITABLE_HEADER");
+ }, header + ' disallows the \'Sec-Shared-Storage-Writable\' header to be '
+ + 'sent for the cross-origin shared storage fetch request.');
+ </script>
+</body>
diff --git a/testing/web-platform/tests/shared-storage/shared-storage-writable-permissions-policy-none.tentative.https.sub.html.headers b/testing/web-platform/tests/shared-storage/shared-storage-writable-permissions-policy-none.tentative.https.sub.html.headers
new file mode 100644
index 0000000000..9903f7c578
--- /dev/null
+++ b/testing/web-platform/tests/shared-storage/shared-storage-writable-permissions-policy-none.tentative.https.sub.html.headers
@@ -0,0 +1 @@
+Permissions-Policy: shared-storage=()
diff --git a/testing/web-platform/tests/shared-storage/shared-storage-writable-permissions-policy-self.tentative.https.sub.html b/testing/web-platform/tests/shared-storage/shared-storage-writable-permissions-policy-self.tentative.https.sub.html
new file mode 100644
index 0000000000..50d5c65cd5
--- /dev/null
+++ b/testing/web-platform/tests/shared-storage/shared-storage-writable-permissions-policy-self.tentative.https.sub.html
@@ -0,0 +1,65 @@
+<!doctype html>
+<body>
+ <script src=/resources/testharness.js></script>
+ <script src=/resources/testharnessreport.js></script>
+ <script src=/permissions-policy/resources/permissions-policy.js></script>
+ <script src=/common/utils.js></script>
+ <script src=/fenced-frame/resources/utils.js></script>
+ <script src=/shared-storage/resources/util.js></script>
+ <script>
+ 'use strict';
+ const header = 'permissions policy header shared-storage=(self)';
+
+ const rawSetHeader = 'set;key=hello;value=world';
+ const setHeader = encodeURIComponent(rawSetHeader);
+ const sameOriginUrl =
+ `/shared-storage/resources/shared-storage-write.py?write=${setHeader}`;
+ const sameOrigin = generateURL(sameOriginUrl, []).origin;
+ const crossOrigin = 'https://{{domains[www]}}:{{ports[https][0]}}';
+ const crossOriginUrl = crossOrigin + sameOriginUrl;
+
+ promise_test(async t => {
+ let response = await fetch(sameOriginUrl,
+ {sharedStorageWritable: true});
+ let sharedStorageWritableHeader = await response.text();
+ assert_equals(sharedStorageWritableHeader, "?1");
+
+ await verifyKeyValueForOrigin('hello', 'world', sameOrigin);
+ await deleteKeyForOrigin('hello', sameOrigin);
+ }, header + ' allows the \'Sec-Shared-Storage-Writable\' header to be sent '
+ + 'for the same-origin shared storage fetch request.');
+
+ promise_test(async t => {
+ let response = await fetch(crossOriginUrl,
+ {sharedStorageWritable: true});
+ let sharedStorageWritableHeader = await response.text();
+ assert_equals(sharedStorageWritableHeader,
+ "NO_SHARED_STORAGE_WRITABLE_HEADER");
+ }, header + ' disallows the \'Sec-Shared-Storage-Writable\' header to be '
+ + 'sent for the cross-origin shared storage fetch request.');
+
+ promise_test(async t => {
+ let response = await fetch('/common/redirect.py?location='
+ + sameOriginUrl,
+ {sharedStorageWritable: true});
+ let sharedStorageWritableHeader = await response.text();
+ assert_equals(sharedStorageWritableHeader, "?1");
+
+ await verifyKeyValueForOrigin('hello', 'world', sameOrigin);
+ await deleteKeyForOrigin('hello', sameOrigin);
+ }, header + ' allows the \'Sec-Shared-Storage-Writable\' header to be '
+ + 'sent for the redirect of a shared storage fetch request, '
+ + 'where the redirect has a same-origin URL.');
+
+ promise_test(async t => {
+ let response = await fetch('/common/redirect.py?location='
+ + crossOriginUrl,
+ {sharedStorageWritable: true});
+ let sharedStorageWritableHeader = await response.text();
+ assert_equals(sharedStorageWritableHeader,
+ "NO_SHARED_STORAGE_WRITABLE_HEADER");
+ }, header + ' disallows the \'Sec-Shared-Storage-Writable\' header to be '
+ + 'sent for the redirect of a shared storage fetch request, '
+ + 'where the redirect has a cross-origin URL.');
+ </script>
+</body>
diff --git a/testing/web-platform/tests/shared-storage/shared-storage-writable-permissions-policy-self.tentative.https.sub.html.headers b/testing/web-platform/tests/shared-storage/shared-storage-writable-permissions-policy-self.tentative.https.sub.html.headers
new file mode 100644
index 0000000000..36c95f2b08
--- /dev/null
+++ b/testing/web-platform/tests/shared-storage/shared-storage-writable-permissions-policy-self.tentative.https.sub.html.headers
@@ -0,0 +1 @@
+Permissions-Policy: shared-storage=(self)
diff --git a/testing/web-platform/tests/shared-storage/shared-storage-writable-service-worker-fetch.tentative.https.sub.html b/testing/web-platform/tests/shared-storage/shared-storage-writable-service-worker-fetch.tentative.https.sub.html
new file mode 100644
index 0000000000..ea7af527b5
--- /dev/null
+++ b/testing/web-platform/tests/shared-storage/shared-storage-writable-service-worker-fetch.tentative.https.sub.html
@@ -0,0 +1,109 @@
+<!doctype html>
+<body>
+ <script src=/resources/testharness.js></script>
+ <script src=/resources/testharnessreport.js></script>
+ <script src=/common/utils.js></script>
+ <script src=/fenced-frame/resources/utils.js></script>
+ <script src=/shared-storage/resources/util.js></script>
+ <script src=/service-workers/service-worker/resources/test-helpers.sub.js></script>
+ <script>
+ const SCOPE = '/shared-storage/resources/'
+ + 'shared-storage-writable-fetch-request-fallback-to-network-iframe.https.html';
+ const SCRIPT = '/shared-storage/resources/'
+ + 'shared-storage-writable-fetch-request-fallback-to-network-worker.js';
+ const SAME_ORIGIN = new URL("", location.href).origin;
+ const CROSS_ORIGIN = 'https://{{domains[www]}}:{{ports[https][0]}}';
+
+ async function fetchSharedStorageUrlInNewFrame(data) {
+ let {test, key, value, hasSharedStorageWritableAttribute, isSameOrigin}
+ = data;
+
+ const framePromise = new Promise((resolve, reject) => {
+ let frame = document.createElement('iframe');
+ frame.src = SCOPE;
+ frame.onload = function() {
+ resolve(frame);
+ };
+ frame.onerror = function() {
+ reject(new Error('Iframe load failed'));
+ };
+ test.add_cleanup(function() {
+ frame.remove();
+ });
+ document.body.appendChild(frame);
+ });
+ let frame = await framePromise;
+
+ let rawWriteHeader = `set;key=${key};value=${value}`;
+ let writeHeader = encodeURIComponent(rawWriteHeader);
+ const sameOriginSrc = `/shared-storage/resources/` +
+ `shared-storage-write.py?write=${writeHeader}`;
+ const src = isSameOrigin ?
+ sameOriginSrc :
+ CROSS_ORIGIN + sameOriginSrc;
+ return {
+ response: frame.contentWindow.fetchUrl(src,
+ hasSharedStorageWritableAttribute),
+ url: src,
+ };
+ }
+
+ promise_test(async t => {
+ await service_worker_unregister(t, SCOPE);
+ let reg = await navigator.serviceWorker.register(SCRIPT,
+ { scope: SCOPE });
+ t.add_cleanup(_ => reg.unregister());
+ let worker = reg.installing;
+ await wait_for_state(t, worker, 'activated');
+ assert_not_equals(worker, null, 'worker is installing');
+
+ let {response, url} = await fetchSharedStorageUrlInNewFrame({
+ test: t,
+ key: 'a', value: 'b',
+ hasSharedStorageWritableAttribute: true,
+ isSameOrigin: true,
+ });
+ checkInterceptedUrls(worker, [
+ {"url": SAME_ORIGIN + SCOPE, "mode": "navigate", "SSWHeader": "null"},
+ {
+ "url": SAME_ORIGIN + "/resources/testharness.js",
+ "mode": "no-cors",
+ "SSWHeader": "null"
+ },
+ {"url": SAME_ORIGIN + url, "mode": "cors", "SSWHeader": "null"},
+ ]);
+ await verifyKeyValueForOrigin('a', 'b', SAME_ORIGIN);
+ await deleteKeyForOrigin('a', SAME_ORIGIN);
+ }, 'test fetch(url, {sharedStorageWritable: true}) via JS from service '
+ + 'worker for same origin fetch');
+
+ promise_test(async t => {
+ await service_worker_unregister(t, SCOPE);
+ let reg = await navigator.serviceWorker.register(SCRIPT,
+ { scope: SCOPE });
+ t.add_cleanup(_ => reg.unregister());
+ let worker = reg.installing;
+ await wait_for_state(t, worker, 'activated');
+ assert_not_equals(worker, null, 'worker is installing');
+
+ let {response, url} = await fetchSharedStorageUrlInNewFrame({
+ test: t,
+ key: 'c', value: 'd',
+ hasSharedStorageWritableAttribute: true,
+ isSameOrigin: false,
+ });
+ checkInterceptedUrls(worker, [
+ {"url": SAME_ORIGIN + SCOPE, "mode": "navigate", "SSWHeader": "null"},
+ {
+ "url": SAME_ORIGIN + "/resources/testharness.js",
+ "mode": "no-cors",
+ "SSWHeader": "null"
+ },
+ {"url": url, "mode": "cors", "SSWHeader": "null"},
+ ]);
+ await verifyKeyValueForOrigin('c', 'd', CROSS_ORIGIN);
+ await deleteKeyForOrigin('c', CROSS_ORIGIN);
+ }, 'test fetch(url, {sharedStorageWritable: true}) via JS from service '
+ + 'worker for cross origin fetch');
+ </script>
+</body>
diff --git a/testing/web-platform/tests/shared-storage/shared-storage-writable-service-worker-iframe.tentative.https.sub.html b/testing/web-platform/tests/shared-storage/shared-storage-writable-service-worker-iframe.tentative.https.sub.html
new file mode 100644
index 0000000000..9eb2820145
--- /dev/null
+++ b/testing/web-platform/tests/shared-storage/shared-storage-writable-service-worker-iframe.tentative.https.sub.html
@@ -0,0 +1,98 @@
+<!doctype html>
+<body>
+ <script src=/resources/testharness.js></script>
+ <script src=/resources/testharnessreport.js></script>
+ <script src=/common/utils.js></script>
+ <script src=/fenced-frame/resources/utils.js></script>
+ <script src=/shared-storage/resources/util.js></script>
+ <script src=/shared-storage/resources/util.sub.js></script>
+ <script src=/service-workers/service-worker/resources/test-helpers.sub.js></script>
+ <script>
+ const SCOPE = '/shared-storage/resources/shared-storage-writ';
+ const INTERMEDIATE_FRAME_SUFFIX =
+ 'able-fetch-request-fallback-to-network-iframe.https.html'
+ const SCRIPT = '/shared-storage/resources/'
+ + 'shared-storage-writable-fetch-request-fallback-to-network-worker.js';
+ const WORKER_FRAME = '/shared-storage/resources/'
+ + 'register-service-worker-iframe.https.html';
+ const SAME_ORIGIN = new URL("", location.href).origin;
+ const CROSS_ORIGIN = 'https://{{domains[www]}}:{{ports[https][0]}}';
+
+ promise_test(async t => {
+ await service_worker_unregister(t, SCOPE);
+ let reg = await navigator.serviceWorker.register(SCRIPT,
+ { scope: SCOPE });
+ t.add_cleanup(_ => reg.unregister());
+ let worker = reg.installing;
+ await wait_for_state(t, worker, 'activated');
+ assert_not_equals(worker, null, 'worker is installing');
+
+ let {frame, nestedFrame, nestedFrameUrl} =
+ await loadNestedSharedStorageFrameInNewFrame({
+ key: 'a', value: 'b',
+ hasSharedStorageWritableAttribute: true,
+ isSameOrigin: true,
+ });
+ t.add_cleanup(function() {
+ frame.remove();
+ });
+ checkInterceptedUrls(worker, [
+ {
+ "url": SAME_ORIGIN + SCOPE + INTERMEDIATE_FRAME_SUFFIX,
+ "mode": "navigate",
+ "SSWHeader": "null"
+ },
+ {
+ "url": SAME_ORIGIN + "/resources/testharness.js",
+ "mode": "no-cors",
+ "SSWHeader": "null"
+ },
+ {
+ "url": SAME_ORIGIN + nestedFrameUrl,
+ "mode": "navigate",
+ "SSWHeader": "null"
+ },
+ ]);
+ await verifyKeyValueForOrigin('a', 'b', SAME_ORIGIN);
+ await deleteKeyForOrigin('a', SAME_ORIGIN);
+ }, 'test <iframe sharedstoragewritable src=[url]> via JS from service '
+ + 'worker for same origin iframe');
+
+ promise_test(async t => {
+ const workerFramePromise = new Promise((resolve, reject) => {
+ let workerFrame = document.createElement('iframe');
+ workerFrame.src = CROSS_ORIGIN + WORKER_FRAME;
+ workerFrame.id = 'worker_frame';
+ workerFrame.onload = function() {
+ resolve(workerFrame);
+ };
+ workerFrame.onerror = function() {
+ reject(new Error('Worker frame load failed'));
+ };
+ t.add_cleanup(function() {
+ workerFrame.remove();
+ });
+ document.body.appendChild(workerFrame);
+ });
+ let workerFrame = await workerFramePromise;
+
+ const messagePromise = new Promise((resolve, reject) => {
+ let channel = new MessageChannel();
+ channel.port1.onmessage = function(e) {
+ resolve(e.data);
+ };
+ let message = {
+ script: SCRIPT,
+ scope: SCOPE,
+ port: channel.port2,
+ };
+ document.getElementById('worker_frame').contentWindow
+ .postMessage(message, "*",
+ [channel.port2]);
+ });
+ let {msg} = await messagePromise;
+ assert_equals(msg, 'test completed');
+ }, 'test <iframe sharedstoragewritable src=[url]> via JS from service '
+ + 'worker for cross origin iframe');
+ </script>
+</body>
diff --git a/testing/web-platform/tests/shared-storage/shared-storage-writable-service-worker-img.tentative.https.sub.html b/testing/web-platform/tests/shared-storage/shared-storage-writable-service-worker-img.tentative.https.sub.html
new file mode 100644
index 0000000000..6d481559ee
--- /dev/null
+++ b/testing/web-platform/tests/shared-storage/shared-storage-writable-service-worker-img.tentative.https.sub.html
@@ -0,0 +1,107 @@
+<!doctype html>
+<body>
+ <script src=/resources/testharness.js></script>
+ <script src=/resources/testharnessreport.js></script>
+ <script src=/common/utils.js></script>
+ <script src=/fenced-frame/resources/utils.js></script>
+ <script src=/shared-storage/resources/util.js></script>
+ <script src=/service-workers/service-worker/resources/test-helpers.sub.js></script>
+ <script>
+ const SCOPE = '/shared-storage/resources/'
+ + 'shared-storage-writable-fetch-request-fallback-to-network-iframe.https.html';
+ const SCRIPT = '/shared-storage/resources/'
+ + 'shared-storage-writable-fetch-request-fallback-to-network-worker.js';
+ const SAME_ORIGIN = new URL("", location.href).origin;
+ const CROSS_ORIGIN = 'https://{{domains[www]}}:{{ports[https][0]}}';
+
+ async function loadSharedStorageImageInNewFrame(data) {
+ let {test, key, value, hasSharedStorageWritableAttribute, isSameOrigin}
+ = data;
+
+ const framePromise = new Promise((resolve, reject) => {
+ let frame = document.createElement('iframe');
+ frame.src = SCOPE;
+ frame.onload = function() {
+ resolve(frame);
+ };
+ frame.onerror = function() {
+ reject(new Error('Iframe load failed'));
+ };
+ test.add_cleanup(function() {
+ frame.remove();
+ });
+ document.body.appendChild(frame);
+ });
+ let frame = await framePromise;
+
+ const sameOriginImgSrc = `/shared-storage/resources/` +
+ `shared-storage-writable-pixel.png?key=${key}&value=${value}`;
+ const imgSrc = isSameOrigin ?
+ sameOriginImgSrc :
+ CROSS_ORIGIN + sameOriginImgSrc;
+ return {
+ loadedImage: frame.contentWindow.loadImage(imgSrc,
+ hasSharedStorageWritableAttribute),
+ imageUrl: imgSrc,
+ };
+ }
+
+ promise_test(async t => {
+ await service_worker_unregister(t, SCOPE);
+ let reg = await navigator.serviceWorker.register(SCRIPT,
+ { scope: SCOPE });
+ t.add_cleanup(_ => reg.unregister());
+ let worker = reg.installing;
+ await wait_for_state(t, worker, 'activated');
+ assert_not_equals(worker, null, 'worker is installing');
+
+ let {loadedImage, imageUrl} = await loadSharedStorageImageInNewFrame({
+ test: t,
+ key: 'a', value: 'b',
+ hasSharedStorageWritableAttribute: true,
+ isSameOrigin: true,
+ });
+ checkInterceptedUrls(worker, [
+ {"url": SAME_ORIGIN + SCOPE, "mode": "navigate", "SSWHeader": "null"},
+ {
+ "url": SAME_ORIGIN + "/resources/testharness.js",
+ "mode": "no-cors",
+ "SSWHeader": "null"
+ },
+ {"url": SAME_ORIGIN + imageUrl, "mode": "no-cors", "SSWHeader": "null"},
+ ]);
+ await verifyKeyValueForOrigin('a', 'b', SAME_ORIGIN);
+ await deleteKeyForOrigin('a', SAME_ORIGIN);
+ }, 'test <img sharedstoragewritable src=[url]> via JS from service worker '
+ + 'for same origin img');
+
+ promise_test(async t => {
+ await service_worker_unregister(t, SCOPE);
+ let reg = await navigator.serviceWorker.register(SCRIPT,
+ { scope: SCOPE });
+ t.add_cleanup(_ => reg.unregister());
+ let worker = reg.installing;
+ await wait_for_state(t, worker, 'activated');
+ assert_not_equals(worker, null, 'worker is installing');
+
+ let {loadedImage, imageUrl} = await loadSharedStorageImageInNewFrame({
+ test: t,
+ key: 'c', value: 'd',
+ hasSharedStorageWritableAttribute: true,
+ isSameOrigin: false,
+ });
+ checkInterceptedUrls(worker, [
+ {"url": SAME_ORIGIN + SCOPE, "mode": "navigate", "SSWHeader": "null"},
+ {
+ "url": SAME_ORIGIN + "/resources/testharness.js",
+ "mode": "no-cors",
+ "SSWHeader": "null"
+ },
+ {"url": imageUrl, "mode": "no-cors", "SSWHeader": "null"},
+ ]);
+ await verifyKeyValueForOrigin('c', 'd', CROSS_ORIGIN);
+ await deleteKeyForOrigin('c', CROSS_ORIGIN);
+ }, 'test <img sharedstoragewritable src=[url]> via JS from service worker '
+ + 'for cross origin img');
+ </script>
+</body>
diff --git a/testing/web-platform/tests/shared-storage/shared-storage-writable-setters.tentative.https.sub.html b/testing/web-platform/tests/shared-storage/shared-storage-writable-setters.tentative.https.sub.html
new file mode 100644
index 0000000000..066bf174de
--- /dev/null
+++ b/testing/web-platform/tests/shared-storage/shared-storage-writable-setters.tentative.https.sub.html
@@ -0,0 +1,47 @@
+<!doctype html>
+<body>
+ <script src=/resources/testharness.js></script>
+ <script src=/resources/testharnessreport.js></script>
+ <script src=/common/utils.js></script>
+ <script src=/common/get-host-info.sub.js></script>
+ <script src=/fenced-frame/resources/utils.js></script>
+ <script src=/shared-storage/resources/util.js></script>
+ <script>
+ 'use strict';
+
+ const rawSetterHeader = 'set;key=hello;value=world;ignore_if_present,'
+ + 'append;value=friend;key=hello';
+ const setterHeader = encodeURIComponent(rawSetterHeader);
+ const sameOriginSetterUrl =
+ `/shared-storage/resources/shared-storage-write.py?write=${setterHeader}`;
+ const sameOrigin = generateURL(sameOriginSetterUrl, []).origin;
+ const crossOrigin = 'https://{{domains[www]}}:{{ports[https][0]}}';
+ const crossOriginSetterUrl = crossOrigin + sameOriginSetterUrl;
+
+ promise_test(async t => {
+ let response = await fetch(sameOriginSetterUrl,
+ {sharedStorageWritable: true});
+ let sharedStorageWritableHeader = await response.text();
+ assert_equals(sharedStorageWritableHeader, "?1");
+
+ // JS does not see the `Shared-Storage-Write` response header.
+ assert_false(!!response.headers.get('Shared-Storage-Write'));
+
+ await verifyKeyValueForOrigin('hello', 'worldfriend', sameOrigin);
+ }, 'Writing to shared storage via the \'Shared-Storage-Write\' header '
+ + 'for a same-origin shared storage fetch request');
+
+ promise_test(async t => {
+ let response = await fetch(crossOriginSetterUrl,
+ {sharedStorageWritable: true});
+ let sharedStorageWritableHeader = await response.text();
+ assert_equals(sharedStorageWritableHeader, "?1");
+
+ // JS does not see the `Shared-Storage-Write` response header.
+ assert_false(!!response.headers.get('Shared-Storage-Write'));
+
+ await verifyKeyValueForOrigin('hello', 'worldfriend', crossOrigin);
+ }, 'Writing to shared storage via the \'Shared-Storage-Write\' header '
+ + 'for a cross-origin shared storage fetch request');
+ </script>
+</body>
diff --git a/testing/web-platform/tests/shared-storage/verify-get-undefined.tentative.https.sub.html b/testing/web-platform/tests/shared-storage/verify-get-undefined.tentative.https.sub.html
new file mode 100644
index 0000000000..501998bf61
--- /dev/null
+++ b/testing/web-platform/tests/shared-storage/verify-get-undefined.tentative.https.sub.html
@@ -0,0 +1,46 @@
+<!doctype html>
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="/common/utils.js"></script>
+<script src="/shared-storage/resources/util.js"></script>
+<script src="/fenced-frame/resources/utils.js"></script>
+
+<body>
+<script>
+'use strict';
+
+for (const resolve_to_config of [true, false]) {
+ promise_test(async () => {
+ const ancestor_key = token();
+ let url0 = generateURL("/shared-storage/resources/frame0.html",
+ [ancestor_key]);
+ let url1 = generateURL("/shared-storage/resources/frame1.html",
+ [ancestor_key]);
+
+ await addModuleOnce(
+ "/shared-storage/resources/verify-get-undefined-module.js");
+
+ let select_url_result = await sharedStorage.selectURL(
+ "verify-get-undefined-url-selection-operation",
+ [{url: url0,
+ reportingMetadata: {'click':
+ "/shared-storage/resources/frame0.html"}},
+ {url: url1,
+ reportingMetadata:
+ {'mouse interaction': "/shared-storage/resources/frame1.html",
+ 'click': "/shared-storage/resources/frame2.html"}}],
+ {resolveToConfig: resolve_to_config,
+ keepAlive: resolve_to_config});
+
+ assert_true(validateSelectURLResult(select_url_result, resolve_to_config));
+ attachFencedFrame(select_url_result, 'opaque-ads');
+
+ // frame1_loaded implies that the operation was successful.
+ assert_equals(await nextValueFromServer(ancestor_key), "frame1_loaded");
+
+}, 'verify-get-undefined-url-selection-operation selectURL() resolves to ' +
+ (resolve_to_config ? 'config' : 'urn:uuid'));
+}
+
+</script>
+</body>