diff options
author | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-19 00:47:55 +0000 |
---|---|---|
committer | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-19 00:47:55 +0000 |
commit | 26a029d407be480d791972afb5975cf62c9360a6 (patch) | |
tree | f435a8308119effd964b339f76abb83a57c29483 /testing/web-platform/tests/shared-storage | |
parent | Initial commit. (diff) | |
download | firefox-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')
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 Binary files differnew file mode 100644 index 0000000000..818c71d03f --- /dev/null +++ b/testing/web-platform/tests/shared-storage/resources/shared-storage-writable-pixel-write.png 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 Binary files differnew file mode 100644 index 0000000000..818c71d03f --- /dev/null +++ b/testing/web-platform/tests/shared-storage/resources/shared-storage-writable-pixel.png 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> |