summaryrefslogtreecommitdiffstats
path: root/testing/web-platform/tests/html/infrastructure/safe-passing-of-structured-data
diff options
context:
space:
mode:
authorDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-19 01:47:29 +0000
committerDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-19 01:47:29 +0000
commit0ebf5bdf043a27fd3dfb7f92e0cb63d88954c44d (patch)
treea31f07c9bcca9d56ce61e9a1ffd30ef350d513aa /testing/web-platform/tests/html/infrastructure/safe-passing-of-structured-data
parentInitial commit. (diff)
downloadfirefox-esr-0ebf5bdf043a27fd3dfb7f92e0cb63d88954c44d.tar.xz
firefox-esr-0ebf5bdf043a27fd3dfb7f92e0cb63d88954c44d.zip
Adding upstream version 115.8.0esr.upstream/115.8.0esr
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'testing/web-platform/tests/html/infrastructure/safe-passing-of-structured-data')
-rw-r--r--testing/web-platform/tests/html/infrastructure/safe-passing-of-structured-data/cross-origin-transfer-resizable-arraybuffer.html28
-rw-r--r--testing/web-platform/tests/html/infrastructure/safe-passing-of-structured-data/messagechannel.any.js16
-rw-r--r--testing/web-platform/tests/html/infrastructure/safe-passing-of-structured-data/resources/echo-iframe.html11
-rw-r--r--testing/web-platform/tests/html/infrastructure/safe-passing-of-structured-data/resources/echo-iframe.html.headers2
-rw-r--r--testing/web-platform/tests/html/infrastructure/safe-passing-of-structured-data/resources/echo-worker.js5
-rw-r--r--testing/web-platform/tests/html/infrastructure/safe-passing-of-structured-data/resources/echo-worker.js.headers1
-rw-r--r--testing/web-platform/tests/html/infrastructure/safe-passing-of-structured-data/resources/iframe-resizable-arraybuffer-helper.html11
-rw-r--r--testing/web-platform/tests/html/infrastructure/safe-passing-of-structured-data/resources/post-parent-type-error.html9
-rw-r--r--testing/web-platform/tests/html/infrastructure/safe-passing-of-structured-data/shared-array-buffers/blob-data.https.html132
-rw-r--r--testing/web-platform/tests/html/infrastructure/safe-passing-of-structured-data/shared-array-buffers/blob-data.https.html.headers2
-rw-r--r--testing/web-platform/tests/html/infrastructure/safe-passing-of-structured-data/shared-array-buffers/broadcastchannel-success-and-failure.https.html35
-rw-r--r--testing/web-platform/tests/html/infrastructure/safe-passing-of-structured-data/shared-array-buffers/broadcastchannel-success-and-failure.https.html.headers2
-rw-r--r--testing/web-platform/tests/html/infrastructure/safe-passing-of-structured-data/shared-array-buffers/broadcastchannel-success.https.html55
-rw-r--r--testing/web-platform/tests/html/infrastructure/safe-passing-of-structured-data/shared-array-buffers/broadcastchannel-success.https.html.headers2
-rw-r--r--testing/web-platform/tests/html/infrastructure/safe-passing-of-structured-data/shared-array-buffers/identity-not-preserved.https.html68
-rw-r--r--testing/web-platform/tests/html/infrastructure/safe-passing-of-structured-data/shared-array-buffers/identity-not-preserved.https.html.headers2
-rw-r--r--testing/web-platform/tests/html/infrastructure/safe-passing-of-structured-data/shared-array-buffers/nested-sharedworker-success.https.html8
-rw-r--r--testing/web-platform/tests/html/infrastructure/safe-passing-of-structured-data/shared-array-buffers/nested-sharedworker-success.https.html.headers2
-rw-r--r--testing/web-platform/tests/html/infrastructure/safe-passing-of-structured-data/shared-array-buffers/nested-worker-success.https.html8
-rw-r--r--testing/web-platform/tests/html/infrastructure/safe-passing-of-structured-data/shared-array-buffers/nested-worker-success.https.html.headers2
-rw-r--r--testing/web-platform/tests/html/infrastructure/safe-passing-of-structured-data/shared-array-buffers/no-coop-coep.https.any.js33
-rw-r--r--testing/web-platform/tests/html/infrastructure/safe-passing-of-structured-data/shared-array-buffers/no-transferring.https.html31
-rw-r--r--testing/web-platform/tests/html/infrastructure/safe-passing-of-structured-data/shared-array-buffers/no-transferring.https.html.headers2
-rw-r--r--testing/web-platform/tests/html/infrastructure/safe-passing-of-structured-data/shared-array-buffers/resources/blank.html2
-rw-r--r--testing/web-platform/tests/html/infrastructure/safe-passing-of-structured-data/shared-array-buffers/resources/blank.html.headers1
-rw-r--r--testing/web-platform/tests/html/infrastructure/safe-passing-of-structured-data/shared-array-buffers/resources/broadcastchannel-iframe.html22
-rw-r--r--testing/web-platform/tests/html/infrastructure/safe-passing-of-structured-data/shared-array-buffers/resources/broadcastchannel-iframe.html.headers2
-rw-r--r--testing/web-platform/tests/html/infrastructure/safe-passing-of-structured-data/shared-array-buffers/resources/broadcastchannel-sharedworker.js7
-rw-r--r--testing/web-platform/tests/html/infrastructure/safe-passing-of-structured-data/shared-array-buffers/resources/broadcastchannel-sharedworker.js.headers1
-rw-r--r--testing/web-platform/tests/html/infrastructure/safe-passing-of-structured-data/shared-array-buffers/resources/broadcastchannel-worker.js9
-rw-r--r--testing/web-platform/tests/html/infrastructure/safe-passing-of-structured-data/shared-array-buffers/resources/broadcastchannel-worker.js.headers1
-rw-r--r--testing/web-platform/tests/html/infrastructure/safe-passing-of-structured-data/shared-array-buffers/resources/iframe-domain-failure.sub.html14
-rw-r--r--testing/web-platform/tests/html/infrastructure/safe-passing-of-structured-data/shared-array-buffers/resources/iframe-domain-failure.sub.html.headers2
-rw-r--r--testing/web-platform/tests/html/infrastructure/safe-passing-of-structured-data/shared-array-buffers/resources/iframe-failure.html3
-rw-r--r--testing/web-platform/tests/html/infrastructure/safe-passing-of-structured-data/shared-array-buffers/resources/iframe-failure.html.headers2
-rw-r--r--testing/web-platform/tests/html/infrastructure/safe-passing-of-structured-data/shared-array-buffers/resources/iframe-messagechannel-complex.html6
-rw-r--r--testing/web-platform/tests/html/infrastructure/safe-passing-of-structured-data/shared-array-buffers/resources/iframe-messagechannel-complex.html.headers2
-rw-r--r--testing/web-platform/tests/html/infrastructure/safe-passing-of-structured-data/shared-array-buffers/resources/iframe-messagechannel-failure.html7
-rw-r--r--testing/web-platform/tests/html/infrastructure/safe-passing-of-structured-data/shared-array-buffers/resources/iframe-messagechannel-failure.html.headers2
-rw-r--r--testing/web-platform/tests/html/infrastructure/safe-passing-of-structured-data/shared-array-buffers/resources/iframe-messagechannel-site-failure.html7
-rw-r--r--testing/web-platform/tests/html/infrastructure/safe-passing-of-structured-data/shared-array-buffers/resources/iframe-messagechannel-site-failure.html.headers2
-rw-r--r--testing/web-platform/tests/html/infrastructure/safe-passing-of-structured-data/shared-array-buffers/resources/incrementer-iframe-messagechannel.html10
-rw-r--r--testing/web-platform/tests/html/infrastructure/safe-passing-of-structured-data/shared-array-buffers/resources/incrementer-iframe-messagechannel.html.headers2
-rw-r--r--testing/web-platform/tests/html/infrastructure/safe-passing-of-structured-data/shared-array-buffers/resources/incrementer-iframe.html10
-rw-r--r--testing/web-platform/tests/html/infrastructure/safe-passing-of-structured-data/shared-array-buffers/resources/incrementer-iframe.html.headers2
-rw-r--r--testing/web-platform/tests/html/infrastructure/safe-passing-of-structured-data/shared-array-buffers/resources/incrementer-popup.html10
-rw-r--r--testing/web-platform/tests/html/infrastructure/safe-passing-of-structured-data/shared-array-buffers/resources/incrementer-popup.html.headers2
-rw-r--r--testing/web-platform/tests/html/infrastructure/safe-passing-of-structured-data/shared-array-buffers/resources/incrementer-worker-with-channel.js7
-rw-r--r--testing/web-platform/tests/html/infrastructure/safe-passing-of-structured-data/shared-array-buffers/resources/incrementer-worker-with-channel.js.headers1
-rw-r--r--testing/web-platform/tests/html/infrastructure/safe-passing-of-structured-data/shared-array-buffers/resources/incrementer-worker.js4
-rw-r--r--testing/web-platform/tests/html/infrastructure/safe-passing-of-structured-data/shared-array-buffers/resources/incrementer-worker.js.headers1
-rw-r--r--testing/web-platform/tests/html/infrastructure/safe-passing-of-structured-data/shared-array-buffers/resources/nested-iframe-1.html5
-rw-r--r--testing/web-platform/tests/html/infrastructure/safe-passing-of-structured-data/shared-array-buffers/resources/nested-iframe-1.html.headers2
-rw-r--r--testing/web-platform/tests/html/infrastructure/safe-passing-of-structured-data/shared-array-buffers/resources/nested-iframe-2.html5
-rw-r--r--testing/web-platform/tests/html/infrastructure/safe-passing-of-structured-data/shared-array-buffers/resources/nested-iframe-2.html.headers2
-rw-r--r--testing/web-platform/tests/html/infrastructure/safe-passing-of-structured-data/shared-array-buffers/resources/nested-iframe-3.html5
-rw-r--r--testing/web-platform/tests/html/infrastructure/safe-passing-of-structured-data/shared-array-buffers/resources/nested-iframe-3.html.headers2
-rw-r--r--testing/web-platform/tests/html/infrastructure/safe-passing-of-structured-data/shared-array-buffers/resources/nested-iframe-4-incrementer.html10
-rw-r--r--testing/web-platform/tests/html/infrastructure/safe-passing-of-structured-data/shared-array-buffers/resources/nested-iframe-4-incrementer.html.headers2
-rw-r--r--testing/web-platform/tests/html/infrastructure/safe-passing-of-structured-data/shared-array-buffers/resources/nested-worker-success.js14
-rw-r--r--testing/web-platform/tests/html/infrastructure/safe-passing-of-structured-data/shared-array-buffers/resources/nested-worker-success.js.headers1
-rw-r--r--testing/web-platform/tests/html/infrastructure/safe-passing-of-structured-data/shared-array-buffers/resources/serviceworker-failure.js33
-rw-r--r--testing/web-platform/tests/html/infrastructure/safe-passing-of-structured-data/shared-array-buffers/resources/serviceworker-failure.js.headers1
-rw-r--r--testing/web-platform/tests/html/infrastructure/safe-passing-of-structured-data/shared-array-buffers/resources/sharedworker-failure.js18
-rw-r--r--testing/web-platform/tests/html/infrastructure/safe-passing-of-structured-data/shared-array-buffers/resources/sharedworker-failure.js.headers1
-rw-r--r--testing/web-platform/tests/html/infrastructure/safe-passing-of-structured-data/shared-array-buffers/resources/test-incrementer.js80
-rw-r--r--testing/web-platform/tests/html/infrastructure/safe-passing-of-structured-data/shared-array-buffers/resources/test-sab.js15
-rw-r--r--testing/web-platform/tests/html/infrastructure/safe-passing-of-structured-data/shared-array-buffers/serialization-via-history.https.html36
-rw-r--r--testing/web-platform/tests/html/infrastructure/safe-passing-of-structured-data/shared-array-buffers/serialization-via-history.https.html.headers2
-rw-r--r--testing/web-platform/tests/html/infrastructure/safe-passing-of-structured-data/shared-array-buffers/serialization-via-idb.any.js44
-rw-r--r--testing/web-platform/tests/html/infrastructure/safe-passing-of-structured-data/shared-array-buffers/serialization-via-notifications-api.any.js28
-rw-r--r--testing/web-platform/tests/html/infrastructure/safe-passing-of-structured-data/shared-array-buffers/window-domain-failure.https.sub.html49
-rw-r--r--testing/web-platform/tests/html/infrastructure/safe-passing-of-structured-data/shared-array-buffers/window-domain-failure.https.sub.html.headers2
-rw-r--r--testing/web-platform/tests/html/infrastructure/safe-passing-of-structured-data/shared-array-buffers/window-failure.https.html15
-rw-r--r--testing/web-platform/tests/html/infrastructure/safe-passing-of-structured-data/shared-array-buffers/window-failure.https.html.headers2
-rw-r--r--testing/web-platform/tests/html/infrastructure/safe-passing-of-structured-data/shared-array-buffers/window-iframe-messagechannel.https.html80
-rw-r--r--testing/web-platform/tests/html/infrastructure/safe-passing-of-structured-data/shared-array-buffers/window-iframe-messagechannel.https.html.headers2
-rw-r--r--testing/web-platform/tests/html/infrastructure/safe-passing-of-structured-data/shared-array-buffers/window-messagechannel-success.https.html22
-rw-r--r--testing/web-platform/tests/html/infrastructure/safe-passing-of-structured-data/shared-array-buffers/window-messagechannel-success.https.html.headers2
-rw-r--r--testing/web-platform/tests/html/infrastructure/safe-passing-of-structured-data/shared-array-buffers/window-serviceworker-failure.https.html56
-rw-r--r--testing/web-platform/tests/html/infrastructure/safe-passing-of-structured-data/shared-array-buffers/window-serviceworker-failure.https.html.headers2
-rw-r--r--testing/web-platform/tests/html/infrastructure/safe-passing-of-structured-data/shared-array-buffers/window-sharedworker-failure.https.html31
-rw-r--r--testing/web-platform/tests/html/infrastructure/safe-passing-of-structured-data/shared-array-buffers/window-sharedworker-failure.https.html.headers2
-rw-r--r--testing/web-platform/tests/html/infrastructure/safe-passing-of-structured-data/shared-array-buffers/window-simple-success.https.html72
-rw-r--r--testing/web-platform/tests/html/infrastructure/safe-passing-of-structured-data/shared-array-buffers/window-simple-success.https.html.headers2
-rw-r--r--testing/web-platform/tests/html/infrastructure/safe-passing-of-structured-data/structured-cloning-error-extra.html46
-rw-r--r--testing/web-platform/tests/html/infrastructure/safe-passing-of-structured-data/structured-cloning-error-stack-optional.sub.window.js106
-rw-r--r--testing/web-platform/tests/html/infrastructure/safe-passing-of-structured-data/structuredclone_0.html637
-rw-r--r--testing/web-platform/tests/html/infrastructure/safe-passing-of-structured-data/transfer-errors.window.js47
-rw-r--r--testing/web-platform/tests/html/infrastructure/safe-passing-of-structured-data/window-postmessage.window.js16
90 files changed, 2105 insertions, 0 deletions
diff --git a/testing/web-platform/tests/html/infrastructure/safe-passing-of-structured-data/cross-origin-transfer-resizable-arraybuffer.html b/testing/web-platform/tests/html/infrastructure/safe-passing-of-structured-data/cross-origin-transfer-resizable-arraybuffer.html
new file mode 100644
index 0000000000..2b21a1459d
--- /dev/null
+++ b/testing/web-platform/tests/html/infrastructure/safe-passing-of-structured-data/cross-origin-transfer-resizable-arraybuffer.html
@@ -0,0 +1,28 @@
+<!DOCTYPE html>
+<title>postMessage transfer ArrayBuffer cross origin iframe</title>
+<script src='/resources/testharness.js'></script>
+<script src='/resources/testharnessreport.js'></script>
+<script src='/common/get-host-info.sub.js'></script>
+
+<script>
+
+async_test(t => {
+ const oopif = document.createElement('iframe');
+
+ window.addEventListener('message', t.step_func((e) => {
+ if (e.data === 'started') {
+ const rab = new ArrayBuffer(32, { maxByteLength: 1024 });
+ oopif.contentWindow.postMessage(rab, '*', [rab]);
+ } else {
+ assert_equals(e.data, 'byteLength=32,maxByteLength=1024,resizable=true');
+ t.done();
+ }
+ }));
+
+ window.addEventListener('load', () => {
+ oopif.src = `${get_host_info().HTTP_REMOTE_ORIGIN}/html/infrastructure/safe-passing-of-structured-data/resources/iframe-resizable-arraybuffer-helper.html`;
+ document.body.appendChild(oopif);
+ });
+}, 'postMessaging resizable ArrayBuffer to OOPIF');
+
+</script>
diff --git a/testing/web-platform/tests/html/infrastructure/safe-passing-of-structured-data/messagechannel.any.js b/testing/web-platform/tests/html/infrastructure/safe-passing-of-structured-data/messagechannel.any.js
new file mode 100644
index 0000000000..6ba17f7a89
--- /dev/null
+++ b/testing/web-platform/tests/html/infrastructure/safe-passing-of-structured-data/messagechannel.any.js
@@ -0,0 +1,16 @@
+// META: global=window,worker
+// META: script=/common/sab.js
+// META: script=/html/webappapis/structured-clone/structured-clone-battery-of-tests.js
+// META: script=/html/webappapis/structured-clone/structured-clone-battery-of-tests-with-transferables.js
+// META: script=/html/webappapis/structured-clone/structured-clone-battery-of-tests-harness.js
+
+runStructuredCloneBatteryOfTests({
+ structuredClone(data, transfer) {
+ return new Promise(resolve => {
+ const channel = new MessageChannel();
+ channel.port2.onmessage = ev => resolve(ev.data.data);
+ channel.port1.postMessage({data, transfer}, transfer);
+ });
+ },
+ hasDocument : self.GLOBAL.isWindow()
+});
diff --git a/testing/web-platform/tests/html/infrastructure/safe-passing-of-structured-data/resources/echo-iframe.html b/testing/web-platform/tests/html/infrastructure/safe-passing-of-structured-data/resources/echo-iframe.html
new file mode 100644
index 0000000000..c4fd5824a1
--- /dev/null
+++ b/testing/web-platform/tests/html/infrastructure/safe-passing-of-structured-data/resources/echo-iframe.html
@@ -0,0 +1,11 @@
+<!DOCTYPE html>
+<meta charset="utf-8">
+<title>A test page that echos back anything postMessaged to it to its parent</title>
+
+<script>
+"use strict";
+
+window.onmessage = ({ data }) => {
+ parent.postMessage(data, "*");
+};
+</script>
diff --git a/testing/web-platform/tests/html/infrastructure/safe-passing-of-structured-data/resources/echo-iframe.html.headers b/testing/web-platform/tests/html/infrastructure/safe-passing-of-structured-data/resources/echo-iframe.html.headers
new file mode 100644
index 0000000000..4e798cd9f5
--- /dev/null
+++ b/testing/web-platform/tests/html/infrastructure/safe-passing-of-structured-data/resources/echo-iframe.html.headers
@@ -0,0 +1,2 @@
+Cross-Origin-Embedder-Policy: require-corp
+Cross-Origin-Resource-Policy: cross-origin
diff --git a/testing/web-platform/tests/html/infrastructure/safe-passing-of-structured-data/resources/echo-worker.js b/testing/web-platform/tests/html/infrastructure/safe-passing-of-structured-data/resources/echo-worker.js
new file mode 100644
index 0000000000..cbbde8a73c
--- /dev/null
+++ b/testing/web-platform/tests/html/infrastructure/safe-passing-of-structured-data/resources/echo-worker.js
@@ -0,0 +1,5 @@
+"use strict";
+
+self.onmessage = ({ data }) => {
+ self.postMessage(data);
+};
diff --git a/testing/web-platform/tests/html/infrastructure/safe-passing-of-structured-data/resources/echo-worker.js.headers b/testing/web-platform/tests/html/infrastructure/safe-passing-of-structured-data/resources/echo-worker.js.headers
new file mode 100644
index 0000000000..6604450991
--- /dev/null
+++ b/testing/web-platform/tests/html/infrastructure/safe-passing-of-structured-data/resources/echo-worker.js.headers
@@ -0,0 +1 @@
+Cross-Origin-Embedder-Policy: require-corp
diff --git a/testing/web-platform/tests/html/infrastructure/safe-passing-of-structured-data/resources/iframe-resizable-arraybuffer-helper.html b/testing/web-platform/tests/html/infrastructure/safe-passing-of-structured-data/resources/iframe-resizable-arraybuffer-helper.html
new file mode 100644
index 0000000000..378c953fbe
--- /dev/null
+++ b/testing/web-platform/tests/html/infrastructure/safe-passing-of-structured-data/resources/iframe-resizable-arraybuffer-helper.html
@@ -0,0 +1,11 @@
+<!DOCTYPE html>
+<script>
+
+window.addEventListener('message', (e) => {
+ const buffer = e.data;
+ e.source.postMessage(`byteLength=${buffer.byteLength},maxByteLength=${buffer.maxByteLength},resizable=${buffer.resizable}`, '*');
+});
+
+window.parent.postMessage('started', '*');
+
+</script>
diff --git a/testing/web-platform/tests/html/infrastructure/safe-passing-of-structured-data/resources/post-parent-type-error.html b/testing/web-platform/tests/html/infrastructure/safe-passing-of-structured-data/resources/post-parent-type-error.html
new file mode 100644
index 0000000000..d6713c4192
--- /dev/null
+++ b/testing/web-platform/tests/html/infrastructure/safe-passing-of-structured-data/resources/post-parent-type-error.html
@@ -0,0 +1,9 @@
+<!DOCTYPE html>
+<meta charset="utf-8">
+<title>Helper that posts its parent a TypeError</title>
+
+<script>
+window.doIt = () => {
+ parent.postMessage(new TypeError("!!"), "*");
+};
+</script>
diff --git a/testing/web-platform/tests/html/infrastructure/safe-passing-of-structured-data/shared-array-buffers/blob-data.https.html b/testing/web-platform/tests/html/infrastructure/safe-passing-of-structured-data/shared-array-buffers/blob-data.https.html
new file mode 100644
index 0000000000..bfcc8b61ca
--- /dev/null
+++ b/testing/web-platform/tests/html/infrastructure/safe-passing-of-structured-data/shared-array-buffers/blob-data.https.html
@@ -0,0 +1,132 @@
+<!doctype html>
+<meta charset=utf-8>
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<div id=log></div>
+<script>
+const url = new URL("./", self.location);
+
+function httpWorkerIncrementerTest(name) {
+ return `
+promise_test(t => {
+ const worker = new Worker("${url.href}resources/incrementer-worker.js");
+
+ return testSharingViaIncrementerScript(t, worker, "parent worker", worker, "sub-worker");
+}, "${name}: postMessaging to a dedicated HTTP sub-worker allows them to see each others' modifications");
+`;
+}
+
+function blobWorkerIncrementerTest(name, origin = "null") {
+ return `
+promise_test(t => {
+ const worker = new Worker(URL.createObjectURL(new Blob([\`
+const view = new Uint8Array(new SharedArrayBuffer(1));
+self.onmessage = () => {
+ const succeeded = (view[0] === 1);
+ self.postMessage({ succeeded });
+};
+self.postMessage({ origin: self.origin, view });
+\`], { type: "text/javascript" })));
+
+ return new Promise((resolve, reject) => {
+ /* Initially the sub-worker gives us an object containing an origin and a view on a shared
+ // buffer. We then modify the shared buffer through the buffer and tell the sub-worker to
+ // "continue". The sub-worker verifies the modification and relays whether it succeeded.
+ */
+ worker.onmessage = t.step_func(({ data }) => {
+ if ("succeeded" in data) {
+ assert_true(data.succeeded);
+ resolve();
+ } else {
+ assert_equals(data.origin, "${origin}");
+ assert_equals(data.view[0], 0);
+ data.view[0] = 1;
+ worker.postMessage("continue");
+ }
+ });
+ worker.onmessageerror = reject;
+ });
+}, "${name}: postMessaging to a dedicated blob sub-worker allows them to see each others' modifications");
+`;
+}
+
+function propertyTests(name, crossOriginIsolated) {
+ return `
+test(() => {
+ assert_equals(self.origin, self.location.origin);
+}, "${name}: self.origin");
+
+test(() => {
+ assert_equals(self.crossOriginIsolated, ${crossOriginIsolated});
+}, "${name}: self.crossOriginIsolated");
+
+test(() => {
+ assert_true(self.isSecureContext);
+}, "${name}: self.isSecureContext");
+`;
+}
+
+const workerScript = `
+importScripts("${url.origin}/resources/testharness.js");
+importScripts("${url.href}resources/test-incrementer.js");
+
+${httpWorkerIncrementerTest("blob worker")}
+
+${blobWorkerIncrementerTest("blob worker", self.location.origin)}
+
+${propertyTests("blob worker", true)}
+
+done();
+`;
+
+fetch_tests_from_worker(new Worker(URL.createObjectURL(new Blob([workerScript], { type: "text/javascript" }))));
+
+const frameScript = `
+<!doctype html>
+<script src=${url.origin}/resources/testharness.js><\/script>
+<script src=${url.href}resources/test-incrementer.js><\/script>
+<script>
+${httpWorkerIncrementerTest("blob frame")}
+
+${blobWorkerIncrementerTest("blob frame", self.location.origin)}
+
+${propertyTests("blob frame", true)}
+<\/script>
+`;
+
+const frame = document.body.appendChild(document.createElement("iframe"));
+frame.src = URL.createObjectURL(new Blob([frameScript], { type: "text/html" }));
+frame.style = "display:none";
+fetch_tests_from_window(frame.contentWindow);
+
+const dataWorkerScript = `
+importScripts("${url.origin}/resources/testharness.js?pipe=header(Cross-Origin-Resource-Policy,cross-origin)");
+
+/* Cannot use httpWorkerIncrementerTest() here as the HTTP URL is not same origin. */
+
+${blobWorkerIncrementerTest("data worker")}
+
+${propertyTests("data worker", false)}
+
+done();
+`;
+
+fetch_tests_from_worker(new Worker(`data:,${dataWorkerScript}`));
+
+const dataFrameScript = `
+<!doctype html>
+<script src=${url.origin}/resources/testharness.js?pipe=header(Cross-Origin-Resource-Policy,cross-origin)><\/script>
+<script>
+/* Cannot use httpWorkerIncrementerTest() here as the HTTP URL is not same origin. */
+
+${blobWorkerIncrementerTest("data frame")}
+
+${propertyTests("data frame", true)}
+<\/script>
+`;
+
+const dataFrame = document.body.appendChild(document.createElement("iframe"));
+dataFrame.src = `data:text/html,${dataFrameScript}`;
+dataFrame.style = "display:none";
+fetch_tests_from_window(dataFrame.contentWindow);
+</script>
diff --git a/testing/web-platform/tests/html/infrastructure/safe-passing-of-structured-data/shared-array-buffers/blob-data.https.html.headers b/testing/web-platform/tests/html/infrastructure/safe-passing-of-structured-data/shared-array-buffers/blob-data.https.html.headers
new file mode 100644
index 0000000000..63b60e490f
--- /dev/null
+++ b/testing/web-platform/tests/html/infrastructure/safe-passing-of-structured-data/shared-array-buffers/blob-data.https.html.headers
@@ -0,0 +1,2 @@
+Cross-Origin-Opener-Policy: same-origin
+Cross-Origin-Embedder-Policy: require-corp
diff --git a/testing/web-platform/tests/html/infrastructure/safe-passing-of-structured-data/shared-array-buffers/broadcastchannel-success-and-failure.https.html b/testing/web-platform/tests/html/infrastructure/safe-passing-of-structured-data/shared-array-buffers/broadcastchannel-success-and-failure.https.html
new file mode 100644
index 0000000000..8902de49cf
--- /dev/null
+++ b/testing/web-platform/tests/html/infrastructure/safe-passing-of-structured-data/shared-array-buffers/broadcastchannel-success-and-failure.https.html
@@ -0,0 +1,35 @@
+<!doctype html>
+<title>SharedArrayBuffer cannot cross agent clusters, BroadcastChannel edition</title>
+<script src=/resources/testharness.js></script>
+<script src=/resources/testharnessreport.js></script>
+<script>
+async_test(t => {
+ const channel = new BroadcastChannel("anne was here"),
+ dw = new Worker("resources/broadcastchannel-worker.js"),
+ sw = new SharedWorker("resources/broadcastchannel-sharedworker.js");
+ let startCounter = 0,
+ dwStatus = "unknown",
+ swStatus = "unknown";
+
+ channel.onmessage = t.step_func(({ data }) => {
+ if(data === "hi") {
+ startCounter++;
+ if(startCounter === 2) {
+ const sab = new SharedArrayBuffer();
+ channel.postMessage(sab);
+ } else if(startCounter > 2) {
+ assert_unreached();
+ }
+ } else if(data === "dw-success") {
+ dwStatus = "success";
+ } else if(data === "sw-success") {
+ swStatus = "success";
+ } else {
+ assert_unreached();
+ }
+ if(dwStatus === "success" && swStatus === "success") {
+ t.done();
+ }
+ });
+});
+</script>
diff --git a/testing/web-platform/tests/html/infrastructure/safe-passing-of-structured-data/shared-array-buffers/broadcastchannel-success-and-failure.https.html.headers b/testing/web-platform/tests/html/infrastructure/safe-passing-of-structured-data/shared-array-buffers/broadcastchannel-success-and-failure.https.html.headers
new file mode 100644
index 0000000000..63b60e490f
--- /dev/null
+++ b/testing/web-platform/tests/html/infrastructure/safe-passing-of-structured-data/shared-array-buffers/broadcastchannel-success-and-failure.https.html.headers
@@ -0,0 +1,2 @@
+Cross-Origin-Opener-Policy: same-origin
+Cross-Origin-Embedder-Policy: require-corp
diff --git a/testing/web-platform/tests/html/infrastructure/safe-passing-of-structured-data/shared-array-buffers/broadcastchannel-success.https.html b/testing/web-platform/tests/html/infrastructure/safe-passing-of-structured-data/shared-array-buffers/broadcastchannel-success.https.html
new file mode 100644
index 0000000000..d3e9956368
--- /dev/null
+++ b/testing/web-platform/tests/html/infrastructure/safe-passing-of-structured-data/shared-array-buffers/broadcastchannel-success.https.html
@@ -0,0 +1,55 @@
+<!DOCTYPE html>
+<meta charset="utf-8">
+<title>Structured cloning of SharedArrayBuffers: BroadcastChannel within the same agent cluster</title>
+<link rel="help" href="https://html.spec.whatwg.org/multipage/#structuredserialize">
+<link rel="help" href="https://html.spec.whatwg.org/multipage/#broadcasting-to-other-browsing-contexts">
+<link rel="author" title="Domenic Denicola" href="mailto:d@domenic.me">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="/common/utils.js"></script> <!-- Use token() to allow running tests in parallel -->
+
+<div id="log"></div>
+
+<script>
+"use strict";
+
+promise_test(t => {
+ const channelName = token();
+ return Promise.all([
+ createIFrame(`resources/broadcastchannel-iframe.html?channel=${channelName}&index=0`),
+ createIFrame(`resources/broadcastchannel-iframe.html?channel=${channelName}&index=1`),
+ createIFrame(`resources/broadcastchannel-iframe.html?channel=${channelName}&index=2`)
+ ]).then(() => {
+ const sab = new SharedArrayBuffer(3);
+ const view = new Uint8Array(sab);
+ const channel = new BroadcastChannel(channelName);
+
+ return new Promise(resolve => {
+ let soFar = 0;
+ channel.onmessage = t.step_func(({ data: { i } }) => {
+ assert_in_array(i, [0, 1, 2], "Any message events must come from expected sources");
+ ++soFar;
+
+ if (soFar === 3) {
+ assert_equals(view[0], 1, "The first iframe must have set view[0] to 1");
+ assert_equals(view[1], 2, "The second iframe must have set view[1] to 2");
+ assert_equals(view[2], 3, "The third iframe must have set view[2] to 3");
+ resolve();
+ }
+ });
+
+ channel.postMessage({ sab });
+ });
+ });
+});
+
+function createIFrame(src) {
+ return new Promise((resolve, reject) => {
+ const iframe = document.createElement("iframe");
+ iframe.src = src;
+ iframe.onload = () => resolve(iframe);
+ iframe.onerror = () => reject(`iframe with URL ${src} failed to load`);
+ document.body.appendChild(iframe);
+ });
+}
+</script>
diff --git a/testing/web-platform/tests/html/infrastructure/safe-passing-of-structured-data/shared-array-buffers/broadcastchannel-success.https.html.headers b/testing/web-platform/tests/html/infrastructure/safe-passing-of-structured-data/shared-array-buffers/broadcastchannel-success.https.html.headers
new file mode 100644
index 0000000000..63b60e490f
--- /dev/null
+++ b/testing/web-platform/tests/html/infrastructure/safe-passing-of-structured-data/shared-array-buffers/broadcastchannel-success.https.html.headers
@@ -0,0 +1,2 @@
+Cross-Origin-Opener-Policy: same-origin
+Cross-Origin-Embedder-Policy: require-corp
diff --git a/testing/web-platform/tests/html/infrastructure/safe-passing-of-structured-data/shared-array-buffers/identity-not-preserved.https.html b/testing/web-platform/tests/html/infrastructure/safe-passing-of-structured-data/shared-array-buffers/identity-not-preserved.https.html
new file mode 100644
index 0000000000..869f49043e
--- /dev/null
+++ b/testing/web-platform/tests/html/infrastructure/safe-passing-of-structured-data/shared-array-buffers/identity-not-preserved.https.html
@@ -0,0 +1,68 @@
+<!DOCTYPE html>
+<meta charset="utf-8">
+<title>SharedArrayBuffers, when cloned, do not give back the same object</title>
+<link rel="help" href="https://html.spec.whatwg.org/multipage/#structuredserialize">
+<link rel="author" title="Domenic Denicola" href="mailto:d@domenic.me">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="/common/utils.js"></script>
+<script src="resources/test-sab.js"></script>
+
+<div id="log"></div>
+
+<script>
+"use strict";
+
+async_test(t => {
+ const testId = token();
+ const sab = new SharedArrayBuffer(1);
+ window.addEventListener("message", t.step_func(({ data }) => {
+ if (data.testId !== testId) {
+ return;
+ }
+
+ assertSABsHaveSameBackingBlock(sab, data.sab);
+
+ t.done();
+ }));
+
+ window.postMessage({ testId, sab }, "*");
+}, "postMessaging to this window does not give back the same SharedArrayBuffer (but does use the same backing block)");
+
+async_test(t => {
+ const testId = token();
+ const sab = new SharedArrayBuffer();
+ const worker = new Worker("../resources/echo-worker.js");
+
+ worker.addEventListener("message", t.step_func(({ data }) => {
+ if (data.testId !== testId) {
+ return;
+ }
+
+ assert_not_equals(data.sab, sab);
+ t.done();
+ }));
+
+ worker.postMessage({ testId, sab });
+}, "postMessaging to a worker and back does not give back the same SharedArrayBuffer");
+
+async_test(t => {
+ const testId = token();
+ const sab = new SharedArrayBuffer();
+ window.addEventListener("message", t.step_func(({ data }) => {
+ if (data.testId !== testId) {
+ return;
+ }
+
+ assert_not_equals(data.sab, sab);
+ t.done();
+ }));
+
+ const iframe = document.createElement("iframe");
+ iframe.onload = t.step_func(() => {
+ iframe.contentWindow.postMessage({ testId, sab }, "*");
+ });
+ iframe.src = "../resources/echo-iframe.html";
+ document.body.appendChild(iframe);
+}, "postMessaging to an iframe and back does not give back the same SharedArrayBuffer");
+</script>
diff --git a/testing/web-platform/tests/html/infrastructure/safe-passing-of-structured-data/shared-array-buffers/identity-not-preserved.https.html.headers b/testing/web-platform/tests/html/infrastructure/safe-passing-of-structured-data/shared-array-buffers/identity-not-preserved.https.html.headers
new file mode 100644
index 0000000000..63b60e490f
--- /dev/null
+++ b/testing/web-platform/tests/html/infrastructure/safe-passing-of-structured-data/shared-array-buffers/identity-not-preserved.https.html.headers
@@ -0,0 +1,2 @@
+Cross-Origin-Opener-Policy: same-origin
+Cross-Origin-Embedder-Policy: require-corp
diff --git a/testing/web-platform/tests/html/infrastructure/safe-passing-of-structured-data/shared-array-buffers/nested-sharedworker-success.https.html b/testing/web-platform/tests/html/infrastructure/safe-passing-of-structured-data/shared-array-buffers/nested-sharedworker-success.https.html
new file mode 100644
index 0000000000..dd221502b6
--- /dev/null
+++ b/testing/web-platform/tests/html/infrastructure/safe-passing-of-structured-data/shared-array-buffers/nested-sharedworker-success.https.html
@@ -0,0 +1,8 @@
+<!doctype html>
+<meta charset=utf-8>
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<div id=log></div>
+<script>
+fetch_tests_from_worker(new SharedWorker("resources/nested-worker-success.js"));
+</script>
diff --git a/testing/web-platform/tests/html/infrastructure/safe-passing-of-structured-data/shared-array-buffers/nested-sharedworker-success.https.html.headers b/testing/web-platform/tests/html/infrastructure/safe-passing-of-structured-data/shared-array-buffers/nested-sharedworker-success.https.html.headers
new file mode 100644
index 0000000000..63b60e490f
--- /dev/null
+++ b/testing/web-platform/tests/html/infrastructure/safe-passing-of-structured-data/shared-array-buffers/nested-sharedworker-success.https.html.headers
@@ -0,0 +1,2 @@
+Cross-Origin-Opener-Policy: same-origin
+Cross-Origin-Embedder-Policy: require-corp
diff --git a/testing/web-platform/tests/html/infrastructure/safe-passing-of-structured-data/shared-array-buffers/nested-worker-success.https.html b/testing/web-platform/tests/html/infrastructure/safe-passing-of-structured-data/shared-array-buffers/nested-worker-success.https.html
new file mode 100644
index 0000000000..aeee3705ae
--- /dev/null
+++ b/testing/web-platform/tests/html/infrastructure/safe-passing-of-structured-data/shared-array-buffers/nested-worker-success.https.html
@@ -0,0 +1,8 @@
+<!doctype html>
+<meta charset=utf-8>
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<div id=log></div>
+<script>
+fetch_tests_from_worker(new Worker("resources/nested-worker-success.js"));
+</script>
diff --git a/testing/web-platform/tests/html/infrastructure/safe-passing-of-structured-data/shared-array-buffers/nested-worker-success.https.html.headers b/testing/web-platform/tests/html/infrastructure/safe-passing-of-structured-data/shared-array-buffers/nested-worker-success.https.html.headers
new file mode 100644
index 0000000000..63b60e490f
--- /dev/null
+++ b/testing/web-platform/tests/html/infrastructure/safe-passing-of-structured-data/shared-array-buffers/nested-worker-success.https.html.headers
@@ -0,0 +1,2 @@
+Cross-Origin-Opener-Policy: same-origin
+Cross-Origin-Embedder-Policy: require-corp
diff --git a/testing/web-platform/tests/html/infrastructure/safe-passing-of-structured-data/shared-array-buffers/no-coop-coep.https.any.js b/testing/web-platform/tests/html/infrastructure/safe-passing-of-structured-data/shared-array-buffers/no-coop-coep.https.any.js
new file mode 100644
index 0000000000..0db16fd6f7
--- /dev/null
+++ b/testing/web-platform/tests/html/infrastructure/safe-passing-of-structured-data/shared-array-buffers/no-coop-coep.https.any.js
@@ -0,0 +1,33 @@
+// META: global=window,worker
+
+test(() => {
+ // See https://github.com/whatwg/html/issues/5380 for why not `new SharedArrayBuffer()`
+ assert_equals(globalThis.SharedArrayBuffer, undefined);
+ assert_false("SharedArrayBuffer" in globalThis);
+}, "SharedArrayBuffer constructor does not exist without COOP+COEP");
+
+test(() => {
+ // See https://github.com/whatwg/html/issues/5380 for why not `new SharedArrayBuffer()`
+ const sab = new WebAssembly.Memory({ shared:true, initial:1, maximum:1 }).buffer;
+ const channel = new MessageChannel();
+ assert_throws_dom("DataCloneError", () => channel.port1.postMessage(sab));
+}, "SharedArrayBuffer over MessageChannel without COOP+COEP");
+
+test(() => {
+ // See https://github.com/whatwg/html/issues/5380 for why not `new SharedArrayBuffer()`
+ const sab = new WebAssembly.Memory({ shared:true, initial:1, maximum:1 }).buffer;
+ const channel = new BroadcastChannel("Is mir egal");
+ assert_throws_dom("DataCloneError", () => channel.postMessage(sab));
+}, "SharedArrayBuffer over BroadcastChannel without COOP+COEP");
+
+if (self.GLOBAL.isWindow()) {
+ test(() => {
+ // See https://github.com/whatwg/html/issues/5380 for why not `new SharedArrayBuffer()`
+ const sab = new WebAssembly.Memory({ shared:true, initial:1, maximum:1 }).buffer;
+ assert_throws_dom("DataCloneError", () => self.postMessage(sab));
+ }, "SharedArrayBuffer over postMessage() without COOP+COEP");
+}
+
+test(() => {
+ assert_false(self.crossOriginIsolated);
+}, "Bonus: self.crossOriginIsolated");
diff --git a/testing/web-platform/tests/html/infrastructure/safe-passing-of-structured-data/shared-array-buffers/no-transferring.https.html b/testing/web-platform/tests/html/infrastructure/safe-passing-of-structured-data/shared-array-buffers/no-transferring.https.html
new file mode 100644
index 0000000000..dfa57fa200
--- /dev/null
+++ b/testing/web-platform/tests/html/infrastructure/safe-passing-of-structured-data/shared-array-buffers/no-transferring.https.html
@@ -0,0 +1,31 @@
+<!DOCTYPE html>
+<meta charset="utf-8">
+<title>SharedArrayBuffers cannot be transferred</title>
+<link rel="help" href="https://html.spec.whatwg.org/#structuredclone">
+<link rel="author" title="Domenic Denicola" href="mailto:d@domenic.me">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+
+<script>
+"use strict";
+
+test(() => {
+ const sab = new SharedArrayBuffer();
+ assert_throws_dom("DataCloneError", () => window.postMessage(sab, "*", [sab]));
+ assert_throws_dom("DataCloneError", () => window.postMessage("test", "*", [sab]));
+}, "Trying to transfer a SharedArrayBuffer to this window throws");
+
+test(() => {
+ const sab = new SharedArrayBuffer();
+ const worker = new Worker("../resources/echo-worker.js");
+ assert_throws_dom("DataCloneError", () => worker.postMessage(sab, [sab]));
+ assert_throws_dom("DataCloneError", () => worker.postMessage("test", [sab]));
+}, "Trying to transfer a SharedArrayBuffer to a worker throws");
+
+test(() => {
+ const sab = new SharedArrayBuffer();
+ const channel = new MessageChannel();
+ assert_throws_dom("DataCloneError", () => channel.port1.postMessage(sab, [sab]));
+ assert_throws_dom("DataCloneError", () => channel.port1.postMessage("test", [sab]));
+}, "Trying to transfer a SharedArrayBuffer through a MessagePort throws");
+</script>
diff --git a/testing/web-platform/tests/html/infrastructure/safe-passing-of-structured-data/shared-array-buffers/no-transferring.https.html.headers b/testing/web-platform/tests/html/infrastructure/safe-passing-of-structured-data/shared-array-buffers/no-transferring.https.html.headers
new file mode 100644
index 0000000000..63b60e490f
--- /dev/null
+++ b/testing/web-platform/tests/html/infrastructure/safe-passing-of-structured-data/shared-array-buffers/no-transferring.https.html.headers
@@ -0,0 +1,2 @@
+Cross-Origin-Opener-Policy: same-origin
+Cross-Origin-Embedder-Policy: require-corp
diff --git a/testing/web-platform/tests/html/infrastructure/safe-passing-of-structured-data/shared-array-buffers/resources/blank.html b/testing/web-platform/tests/html/infrastructure/safe-passing-of-structured-data/shared-array-buffers/resources/blank.html
new file mode 100644
index 0000000000..eec1b2cc8e
--- /dev/null
+++ b/testing/web-platform/tests/html/infrastructure/safe-passing-of-structured-data/shared-array-buffers/resources/blank.html
@@ -0,0 +1,2 @@
+<!DOCTYPE html>
+<title>Used as a service worker-controlled iframe</title>
diff --git a/testing/web-platform/tests/html/infrastructure/safe-passing-of-structured-data/shared-array-buffers/resources/blank.html.headers b/testing/web-platform/tests/html/infrastructure/safe-passing-of-structured-data/shared-array-buffers/resources/blank.html.headers
new file mode 100644
index 0000000000..6604450991
--- /dev/null
+++ b/testing/web-platform/tests/html/infrastructure/safe-passing-of-structured-data/shared-array-buffers/resources/blank.html.headers
@@ -0,0 +1 @@
+Cross-Origin-Embedder-Policy: require-corp
diff --git a/testing/web-platform/tests/html/infrastructure/safe-passing-of-structured-data/shared-array-buffers/resources/broadcastchannel-iframe.html b/testing/web-platform/tests/html/infrastructure/safe-passing-of-structured-data/shared-array-buffers/resources/broadcastchannel-iframe.html
new file mode 100644
index 0000000000..02b9bcbbe8
--- /dev/null
+++ b/testing/web-platform/tests/html/infrastructure/safe-passing-of-structured-data/shared-array-buffers/resources/broadcastchannel-iframe.html
@@ -0,0 +1,22 @@
+<!DOCTYPE html>
+<meta charset="utf-8">
+<title>A test page that messes with a given SharedArrayBuffer sent from a BroadcastChannel</title>
+
+<script>
+"use strict";
+const query = new URLSearchParams(location.search);
+const channel = new BroadcastChannel(query.get("channel"));
+const i = Number(query.get("index"));
+
+channel.onmessage = e => {
+ const sab = e.data.sab;
+ if (sab === undefined) {
+ // We only care about "broadcasts" from the window
+ return;
+ }
+
+ const view = new Uint8Array(sab);
+ view[i] = i + 1;
+ channel.postMessage({ i });
+};
+</script>
diff --git a/testing/web-platform/tests/html/infrastructure/safe-passing-of-structured-data/shared-array-buffers/resources/broadcastchannel-iframe.html.headers b/testing/web-platform/tests/html/infrastructure/safe-passing-of-structured-data/shared-array-buffers/resources/broadcastchannel-iframe.html.headers
new file mode 100644
index 0000000000..4e798cd9f5
--- /dev/null
+++ b/testing/web-platform/tests/html/infrastructure/safe-passing-of-structured-data/shared-array-buffers/resources/broadcastchannel-iframe.html.headers
@@ -0,0 +1,2 @@
+Cross-Origin-Embedder-Policy: require-corp
+Cross-Origin-Resource-Policy: cross-origin
diff --git a/testing/web-platform/tests/html/infrastructure/safe-passing-of-structured-data/shared-array-buffers/resources/broadcastchannel-sharedworker.js b/testing/web-platform/tests/html/infrastructure/safe-passing-of-structured-data/shared-array-buffers/resources/broadcastchannel-sharedworker.js
new file mode 100644
index 0000000000..310e0e9358
--- /dev/null
+++ b/testing/web-platform/tests/html/infrastructure/safe-passing-of-structured-data/shared-array-buffers/resources/broadcastchannel-sharedworker.js
@@ -0,0 +1,7 @@
+const channel = new BroadcastChannel("anne was here");
+channel.onmessageerror = ({ data }) => {
+ if(data === null) {
+ channel.postMessage("sw-success");
+ }
+}
+channel.postMessage("hi");
diff --git a/testing/web-platform/tests/html/infrastructure/safe-passing-of-structured-data/shared-array-buffers/resources/broadcastchannel-sharedworker.js.headers b/testing/web-platform/tests/html/infrastructure/safe-passing-of-structured-data/shared-array-buffers/resources/broadcastchannel-sharedworker.js.headers
new file mode 100644
index 0000000000..6604450991
--- /dev/null
+++ b/testing/web-platform/tests/html/infrastructure/safe-passing-of-structured-data/shared-array-buffers/resources/broadcastchannel-sharedworker.js.headers
@@ -0,0 +1 @@
+Cross-Origin-Embedder-Policy: require-corp
diff --git a/testing/web-platform/tests/html/infrastructure/safe-passing-of-structured-data/shared-array-buffers/resources/broadcastchannel-worker.js b/testing/web-platform/tests/html/infrastructure/safe-passing-of-structured-data/shared-array-buffers/resources/broadcastchannel-worker.js
new file mode 100644
index 0000000000..36369cde50
--- /dev/null
+++ b/testing/web-platform/tests/html/infrastructure/safe-passing-of-structured-data/shared-array-buffers/resources/broadcastchannel-worker.js
@@ -0,0 +1,9 @@
+const channel = new BroadcastChannel("anne was here");
+channel.onmessage = ({ data }) => {
+ if(data === "hi" || data === "sw-success") {
+ return;
+ } else if(data instanceof SharedArrayBuffer) {
+ channel.postMessage("dw-success");
+ }
+}
+channel.postMessage("hi");
diff --git a/testing/web-platform/tests/html/infrastructure/safe-passing-of-structured-data/shared-array-buffers/resources/broadcastchannel-worker.js.headers b/testing/web-platform/tests/html/infrastructure/safe-passing-of-structured-data/shared-array-buffers/resources/broadcastchannel-worker.js.headers
new file mode 100644
index 0000000000..6604450991
--- /dev/null
+++ b/testing/web-platform/tests/html/infrastructure/safe-passing-of-structured-data/shared-array-buffers/resources/broadcastchannel-worker.js.headers
@@ -0,0 +1 @@
+Cross-Origin-Embedder-Policy: require-corp
diff --git a/testing/web-platform/tests/html/infrastructure/safe-passing-of-structured-data/shared-array-buffers/resources/iframe-domain-failure.sub.html b/testing/web-platform/tests/html/infrastructure/safe-passing-of-structured-data/shared-array-buffers/resources/iframe-domain-failure.sub.html
new file mode 100644
index 0000000000..0cdb8b5f59
--- /dev/null
+++ b/testing/web-platform/tests/html/infrastructure/safe-passing-of-structured-data/shared-array-buffers/resources/iframe-domain-failure.sub.html
@@ -0,0 +1,14 @@
+<!DOCTYPE html>
+<meta charset="utf-8">
+<title>A test page that postMessage a SharedArrayBuffer to the parent and also sets document.domain</title>
+
+<script>
+"use strict";
+
+document.domain = "{{host}}";
+parent.postMessage({name: "domain", value: document.domain}, "*");
+parent.postMessage(
+ {name: "crossOriginIsolated", value: self.crossOriginIsolated}, "*");
+parent.postMessage(
+ {name: "hasSharedArrayBuffer", value: Boolean(self.SharedArrayBuffer)}, "*");
+</script>
diff --git a/testing/web-platform/tests/html/infrastructure/safe-passing-of-structured-data/shared-array-buffers/resources/iframe-domain-failure.sub.html.headers b/testing/web-platform/tests/html/infrastructure/safe-passing-of-structured-data/shared-array-buffers/resources/iframe-domain-failure.sub.html.headers
new file mode 100644
index 0000000000..56d0ac3428
--- /dev/null
+++ b/testing/web-platform/tests/html/infrastructure/safe-passing-of-structured-data/shared-array-buffers/resources/iframe-domain-failure.sub.html.headers
@@ -0,0 +1,2 @@
+Cross-Origin-Embedder-Policy: require-corp
+Cross-Origin-Resource-Policy: same-site
diff --git a/testing/web-platform/tests/html/infrastructure/safe-passing-of-structured-data/shared-array-buffers/resources/iframe-failure.html b/testing/web-platform/tests/html/infrastructure/safe-passing-of-structured-data/shared-array-buffers/resources/iframe-failure.html
new file mode 100644
index 0000000000..2c33dba79a
--- /dev/null
+++ b/testing/web-platform/tests/html/infrastructure/safe-passing-of-structured-data/shared-array-buffers/resources/iframe-failure.html
@@ -0,0 +1,3 @@
+<script>
+parent.postMessage(new SharedArrayBuffer(10), "*");
+</script>
diff --git a/testing/web-platform/tests/html/infrastructure/safe-passing-of-structured-data/shared-array-buffers/resources/iframe-failure.html.headers b/testing/web-platform/tests/html/infrastructure/safe-passing-of-structured-data/shared-array-buffers/resources/iframe-failure.html.headers
new file mode 100644
index 0000000000..4e798cd9f5
--- /dev/null
+++ b/testing/web-platform/tests/html/infrastructure/safe-passing-of-structured-data/shared-array-buffers/resources/iframe-failure.html.headers
@@ -0,0 +1,2 @@
+Cross-Origin-Embedder-Policy: require-corp
+Cross-Origin-Resource-Policy: cross-origin
diff --git a/testing/web-platform/tests/html/infrastructure/safe-passing-of-structured-data/shared-array-buffers/resources/iframe-messagechannel-complex.html b/testing/web-platform/tests/html/infrastructure/safe-passing-of-structured-data/shared-array-buffers/resources/iframe-messagechannel-complex.html
new file mode 100644
index 0000000000..1666a98458
--- /dev/null
+++ b/testing/web-platform/tests/html/infrastructure/safe-passing-of-structured-data/shared-array-buffers/resources/iframe-messagechannel-complex.html
@@ -0,0 +1,6 @@
+<!DOCTYPE html>
+<script>
+ const channel = new MessageChannel();
+ window.parent.postMessage({ state: "port1", data: channel.port1 }, '*', [channel.port1]);
+ window.onmessage = () => window.parent.postMessage({ state: "port2", data: channel.port2 }, '*', [channel.port2]);
+</script>
diff --git a/testing/web-platform/tests/html/infrastructure/safe-passing-of-structured-data/shared-array-buffers/resources/iframe-messagechannel-complex.html.headers b/testing/web-platform/tests/html/infrastructure/safe-passing-of-structured-data/shared-array-buffers/resources/iframe-messagechannel-complex.html.headers
new file mode 100644
index 0000000000..4e798cd9f5
--- /dev/null
+++ b/testing/web-platform/tests/html/infrastructure/safe-passing-of-structured-data/shared-array-buffers/resources/iframe-messagechannel-complex.html.headers
@@ -0,0 +1,2 @@
+Cross-Origin-Embedder-Policy: require-corp
+Cross-Origin-Resource-Policy: cross-origin
diff --git a/testing/web-platform/tests/html/infrastructure/safe-passing-of-structured-data/shared-array-buffers/resources/iframe-messagechannel-failure.html b/testing/web-platform/tests/html/infrastructure/safe-passing-of-structured-data/shared-array-buffers/resources/iframe-messagechannel-failure.html
new file mode 100644
index 0000000000..c6896762bc
--- /dev/null
+++ b/testing/web-platform/tests/html/infrastructure/safe-passing-of-structured-data/shared-array-buffers/resources/iframe-messagechannel-failure.html
@@ -0,0 +1,7 @@
+<!DOCTYPE html>
+<script>
+ const channel = new MessageChannel();
+ window.parent.postMessage(channel.port2, '*', [channel.port2]);
+ channel.port1.onmessage = e => { alert(e.data); channel.port1.postMessage("message event received") };
+ channel.port1.onmessageerror = () => channel.port1.postMessage("messageerror event received");
+</script>
diff --git a/testing/web-platform/tests/html/infrastructure/safe-passing-of-structured-data/shared-array-buffers/resources/iframe-messagechannel-failure.html.headers b/testing/web-platform/tests/html/infrastructure/safe-passing-of-structured-data/shared-array-buffers/resources/iframe-messagechannel-failure.html.headers
new file mode 100644
index 0000000000..4e798cd9f5
--- /dev/null
+++ b/testing/web-platform/tests/html/infrastructure/safe-passing-of-structured-data/shared-array-buffers/resources/iframe-messagechannel-failure.html.headers
@@ -0,0 +1,2 @@
+Cross-Origin-Embedder-Policy: require-corp
+Cross-Origin-Resource-Policy: cross-origin
diff --git a/testing/web-platform/tests/html/infrastructure/safe-passing-of-structured-data/shared-array-buffers/resources/iframe-messagechannel-site-failure.html b/testing/web-platform/tests/html/infrastructure/safe-passing-of-structured-data/shared-array-buffers/resources/iframe-messagechannel-site-failure.html
new file mode 100644
index 0000000000..95a610f928
--- /dev/null
+++ b/testing/web-platform/tests/html/infrastructure/safe-passing-of-structured-data/shared-array-buffers/resources/iframe-messagechannel-site-failure.html
@@ -0,0 +1,7 @@
+<!DOCTYPE html>
+<script>
+ const channel = new MessageChannel();
+ window.parent.postMessage(channel.port2, '*', [channel.port2]);
+ channel.port1.onmessage = e => { channel.port1.postMessage("message event received") };
+ channel.port1.onmessageerror = () => channel.port1.postMessage("messageerror event received");
+</script>
diff --git a/testing/web-platform/tests/html/infrastructure/safe-passing-of-structured-data/shared-array-buffers/resources/iframe-messagechannel-site-failure.html.headers b/testing/web-platform/tests/html/infrastructure/safe-passing-of-structured-data/shared-array-buffers/resources/iframe-messagechannel-site-failure.html.headers
new file mode 100644
index 0000000000..56d0ac3428
--- /dev/null
+++ b/testing/web-platform/tests/html/infrastructure/safe-passing-of-structured-data/shared-array-buffers/resources/iframe-messagechannel-site-failure.html.headers
@@ -0,0 +1,2 @@
+Cross-Origin-Embedder-Policy: require-corp
+Cross-Origin-Resource-Policy: same-site
diff --git a/testing/web-platform/tests/html/infrastructure/safe-passing-of-structured-data/shared-array-buffers/resources/incrementer-iframe-messagechannel.html b/testing/web-platform/tests/html/infrastructure/safe-passing-of-structured-data/shared-array-buffers/resources/incrementer-iframe-messagechannel.html
new file mode 100644
index 0000000000..6f3f284ae2
--- /dev/null
+++ b/testing/web-platform/tests/html/infrastructure/safe-passing-of-structured-data/shared-array-buffers/resources/incrementer-iframe-messagechannel.html
@@ -0,0 +1,10 @@
+<!DOCTYPE html>
+<meta charset="utf-8">
+<title>A test page that messes with a given SharedArrayBuffer via MessageChannel</title>
+<script src="test-incrementer.js"></script>
+
+<script>
+ const channel = new MessageChannel();
+ window.parent.postMessage(channel.port2, '*', [channel.port2]);
+ setupDestinationIncrementer(channel.port1, channel.port1);
+</script>
diff --git a/testing/web-platform/tests/html/infrastructure/safe-passing-of-structured-data/shared-array-buffers/resources/incrementer-iframe-messagechannel.html.headers b/testing/web-platform/tests/html/infrastructure/safe-passing-of-structured-data/shared-array-buffers/resources/incrementer-iframe-messagechannel.html.headers
new file mode 100644
index 0000000000..4e798cd9f5
--- /dev/null
+++ b/testing/web-platform/tests/html/infrastructure/safe-passing-of-structured-data/shared-array-buffers/resources/incrementer-iframe-messagechannel.html.headers
@@ -0,0 +1,2 @@
+Cross-Origin-Embedder-Policy: require-corp
+Cross-Origin-Resource-Policy: cross-origin
diff --git a/testing/web-platform/tests/html/infrastructure/safe-passing-of-structured-data/shared-array-buffers/resources/incrementer-iframe.html b/testing/web-platform/tests/html/infrastructure/safe-passing-of-structured-data/shared-array-buffers/resources/incrementer-iframe.html
new file mode 100644
index 0000000000..6f27ad7d5b
--- /dev/null
+++ b/testing/web-platform/tests/html/infrastructure/safe-passing-of-structured-data/shared-array-buffers/resources/incrementer-iframe.html
@@ -0,0 +1,10 @@
+<!DOCTYPE html>
+<meta charset="utf-8">
+<title>A test page that messes with a given SharedArrayBuffer</title>
+<script src="test-incrementer.js"></script>
+
+<script>
+"use strict";
+
+setupDestinationIncrementer(self, parent, "*");
+</script>
diff --git a/testing/web-platform/tests/html/infrastructure/safe-passing-of-structured-data/shared-array-buffers/resources/incrementer-iframe.html.headers b/testing/web-platform/tests/html/infrastructure/safe-passing-of-structured-data/shared-array-buffers/resources/incrementer-iframe.html.headers
new file mode 100644
index 0000000000..4e798cd9f5
--- /dev/null
+++ b/testing/web-platform/tests/html/infrastructure/safe-passing-of-structured-data/shared-array-buffers/resources/incrementer-iframe.html.headers
@@ -0,0 +1,2 @@
+Cross-Origin-Embedder-Policy: require-corp
+Cross-Origin-Resource-Policy: cross-origin
diff --git a/testing/web-platform/tests/html/infrastructure/safe-passing-of-structured-data/shared-array-buffers/resources/incrementer-popup.html b/testing/web-platform/tests/html/infrastructure/safe-passing-of-structured-data/shared-array-buffers/resources/incrementer-popup.html
new file mode 100644
index 0000000000..e583b5c416
--- /dev/null
+++ b/testing/web-platform/tests/html/infrastructure/safe-passing-of-structured-data/shared-array-buffers/resources/incrementer-popup.html
@@ -0,0 +1,10 @@
+<!DOCTYPE html>
+<meta charset="utf-8">
+<title>A test page that messes with a given SharedArrayBuffer</title>
+<script src="test-incrementer.js"></script>
+
+<script>
+"use strict";
+
+setupDestinationIncrementer(self, opener, "*");
+</script>
diff --git a/testing/web-platform/tests/html/infrastructure/safe-passing-of-structured-data/shared-array-buffers/resources/incrementer-popup.html.headers b/testing/web-platform/tests/html/infrastructure/safe-passing-of-structured-data/shared-array-buffers/resources/incrementer-popup.html.headers
new file mode 100644
index 0000000000..63b60e490f
--- /dev/null
+++ b/testing/web-platform/tests/html/infrastructure/safe-passing-of-structured-data/shared-array-buffers/resources/incrementer-popup.html.headers
@@ -0,0 +1,2 @@
+Cross-Origin-Opener-Policy: same-origin
+Cross-Origin-Embedder-Policy: require-corp
diff --git a/testing/web-platform/tests/html/infrastructure/safe-passing-of-structured-data/shared-array-buffers/resources/incrementer-worker-with-channel.js b/testing/web-platform/tests/html/infrastructure/safe-passing-of-structured-data/shared-array-buffers/resources/incrementer-worker-with-channel.js
new file mode 100644
index 0000000000..c74fd26d3f
--- /dev/null
+++ b/testing/web-platform/tests/html/infrastructure/safe-passing-of-structured-data/shared-array-buffers/resources/incrementer-worker-with-channel.js
@@ -0,0 +1,7 @@
+"use strict";
+importScripts("./test-incrementer.js");
+
+self.onmessage = ({ data }) => {
+ // data will be a MessagePort
+ setupDestinationIncrementer(data, data);
+};
diff --git a/testing/web-platform/tests/html/infrastructure/safe-passing-of-structured-data/shared-array-buffers/resources/incrementer-worker-with-channel.js.headers b/testing/web-platform/tests/html/infrastructure/safe-passing-of-structured-data/shared-array-buffers/resources/incrementer-worker-with-channel.js.headers
new file mode 100644
index 0000000000..6604450991
--- /dev/null
+++ b/testing/web-platform/tests/html/infrastructure/safe-passing-of-structured-data/shared-array-buffers/resources/incrementer-worker-with-channel.js.headers
@@ -0,0 +1 @@
+Cross-Origin-Embedder-Policy: require-corp
diff --git a/testing/web-platform/tests/html/infrastructure/safe-passing-of-structured-data/shared-array-buffers/resources/incrementer-worker.js b/testing/web-platform/tests/html/infrastructure/safe-passing-of-structured-data/shared-array-buffers/resources/incrementer-worker.js
new file mode 100644
index 0000000000..5801bd2b97
--- /dev/null
+++ b/testing/web-platform/tests/html/infrastructure/safe-passing-of-structured-data/shared-array-buffers/resources/incrementer-worker.js
@@ -0,0 +1,4 @@
+"use strict";
+importScripts("./test-incrementer.js");
+
+setupDestinationIncrementer(self, self);
diff --git a/testing/web-platform/tests/html/infrastructure/safe-passing-of-structured-data/shared-array-buffers/resources/incrementer-worker.js.headers b/testing/web-platform/tests/html/infrastructure/safe-passing-of-structured-data/shared-array-buffers/resources/incrementer-worker.js.headers
new file mode 100644
index 0000000000..6604450991
--- /dev/null
+++ b/testing/web-platform/tests/html/infrastructure/safe-passing-of-structured-data/shared-array-buffers/resources/incrementer-worker.js.headers
@@ -0,0 +1 @@
+Cross-Origin-Embedder-Policy: require-corp
diff --git a/testing/web-platform/tests/html/infrastructure/safe-passing-of-structured-data/shared-array-buffers/resources/nested-iframe-1.html b/testing/web-platform/tests/html/infrastructure/safe-passing-of-structured-data/shared-array-buffers/resources/nested-iframe-1.html
new file mode 100644
index 0000000000..fe93cc0c4b
--- /dev/null
+++ b/testing/web-platform/tests/html/infrastructure/safe-passing-of-structured-data/shared-array-buffers/resources/nested-iframe-1.html
@@ -0,0 +1,5 @@
+<!DOCTYPE html>
+<meta charset="utf-8">
+<title>Nesting level 1</title>
+
+<iframe src="nested-iframe-2.html"></iframe>
diff --git a/testing/web-platform/tests/html/infrastructure/safe-passing-of-structured-data/shared-array-buffers/resources/nested-iframe-1.html.headers b/testing/web-platform/tests/html/infrastructure/safe-passing-of-structured-data/shared-array-buffers/resources/nested-iframe-1.html.headers
new file mode 100644
index 0000000000..4e798cd9f5
--- /dev/null
+++ b/testing/web-platform/tests/html/infrastructure/safe-passing-of-structured-data/shared-array-buffers/resources/nested-iframe-1.html.headers
@@ -0,0 +1,2 @@
+Cross-Origin-Embedder-Policy: require-corp
+Cross-Origin-Resource-Policy: cross-origin
diff --git a/testing/web-platform/tests/html/infrastructure/safe-passing-of-structured-data/shared-array-buffers/resources/nested-iframe-2.html b/testing/web-platform/tests/html/infrastructure/safe-passing-of-structured-data/shared-array-buffers/resources/nested-iframe-2.html
new file mode 100644
index 0000000000..fad52ce9de
--- /dev/null
+++ b/testing/web-platform/tests/html/infrastructure/safe-passing-of-structured-data/shared-array-buffers/resources/nested-iframe-2.html
@@ -0,0 +1,5 @@
+<!DOCTYPE html>
+<meta charset="utf-8">
+<title>Nesting level 2</title>
+
+<iframe src="nested-iframe-3.html"></iframe>
diff --git a/testing/web-platform/tests/html/infrastructure/safe-passing-of-structured-data/shared-array-buffers/resources/nested-iframe-2.html.headers b/testing/web-platform/tests/html/infrastructure/safe-passing-of-structured-data/shared-array-buffers/resources/nested-iframe-2.html.headers
new file mode 100644
index 0000000000..4e798cd9f5
--- /dev/null
+++ b/testing/web-platform/tests/html/infrastructure/safe-passing-of-structured-data/shared-array-buffers/resources/nested-iframe-2.html.headers
@@ -0,0 +1,2 @@
+Cross-Origin-Embedder-Policy: require-corp
+Cross-Origin-Resource-Policy: cross-origin
diff --git a/testing/web-platform/tests/html/infrastructure/safe-passing-of-structured-data/shared-array-buffers/resources/nested-iframe-3.html b/testing/web-platform/tests/html/infrastructure/safe-passing-of-structured-data/shared-array-buffers/resources/nested-iframe-3.html
new file mode 100644
index 0000000000..7971022b2c
--- /dev/null
+++ b/testing/web-platform/tests/html/infrastructure/safe-passing-of-structured-data/shared-array-buffers/resources/nested-iframe-3.html
@@ -0,0 +1,5 @@
+<!DOCTYPE html>
+<meta charset="utf-8">
+<title>Nesting level 3</title>
+
+<iframe src="nested-iframe-4-incrementer.html"></iframe>
diff --git a/testing/web-platform/tests/html/infrastructure/safe-passing-of-structured-data/shared-array-buffers/resources/nested-iframe-3.html.headers b/testing/web-platform/tests/html/infrastructure/safe-passing-of-structured-data/shared-array-buffers/resources/nested-iframe-3.html.headers
new file mode 100644
index 0000000000..4e798cd9f5
--- /dev/null
+++ b/testing/web-platform/tests/html/infrastructure/safe-passing-of-structured-data/shared-array-buffers/resources/nested-iframe-3.html.headers
@@ -0,0 +1,2 @@
+Cross-Origin-Embedder-Policy: require-corp
+Cross-Origin-Resource-Policy: cross-origin
diff --git a/testing/web-platform/tests/html/infrastructure/safe-passing-of-structured-data/shared-array-buffers/resources/nested-iframe-4-incrementer.html b/testing/web-platform/tests/html/infrastructure/safe-passing-of-structured-data/shared-array-buffers/resources/nested-iframe-4-incrementer.html
new file mode 100644
index 0000000000..d374515bdc
--- /dev/null
+++ b/testing/web-platform/tests/html/infrastructure/safe-passing-of-structured-data/shared-array-buffers/resources/nested-iframe-4-incrementer.html
@@ -0,0 +1,10 @@
+<!DOCTYPE html>
+<meta charset="utf-8">
+<title>A test page that messes with a given SharedArrayBuffer, nested 4 levels deep in iframes</title>
+<script src="test-incrementer.js"></script>
+
+<script>
+"use strict";
+
+setupDestinationIncrementer(self, parent.parent.parent.parent.parent, "*");
+</script>
diff --git a/testing/web-platform/tests/html/infrastructure/safe-passing-of-structured-data/shared-array-buffers/resources/nested-iframe-4-incrementer.html.headers b/testing/web-platform/tests/html/infrastructure/safe-passing-of-structured-data/shared-array-buffers/resources/nested-iframe-4-incrementer.html.headers
new file mode 100644
index 0000000000..4e798cd9f5
--- /dev/null
+++ b/testing/web-platform/tests/html/infrastructure/safe-passing-of-structured-data/shared-array-buffers/resources/nested-iframe-4-incrementer.html.headers
@@ -0,0 +1,2 @@
+Cross-Origin-Embedder-Policy: require-corp
+Cross-Origin-Resource-Policy: cross-origin
diff --git a/testing/web-platform/tests/html/infrastructure/safe-passing-of-structured-data/shared-array-buffers/resources/nested-worker-success.js b/testing/web-platform/tests/html/infrastructure/safe-passing-of-structured-data/shared-array-buffers/resources/nested-worker-success.js
new file mode 100644
index 0000000000..ffc3708acb
--- /dev/null
+++ b/testing/web-platform/tests/html/infrastructure/safe-passing-of-structured-data/shared-array-buffers/resources/nested-worker-success.js
@@ -0,0 +1,14 @@
+importScripts("/resources/testharness.js");
+importScripts("test-incrementer.js");
+
+promise_test(t => {
+ const worker = new Worker("incrementer-worker.js");
+
+ return testSharingViaIncrementerScript(t, worker, "parent worker", worker, "sub-worker");
+}, "postMessaging to a dedicated sub-worker allows them to see each others' modifications");
+
+test(() => {
+ assert_true(self.crossOriginIsolated);
+}, "Bonus: self.crossOriginIsolated");
+
+done();
diff --git a/testing/web-platform/tests/html/infrastructure/safe-passing-of-structured-data/shared-array-buffers/resources/nested-worker-success.js.headers b/testing/web-platform/tests/html/infrastructure/safe-passing-of-structured-data/shared-array-buffers/resources/nested-worker-success.js.headers
new file mode 100644
index 0000000000..6604450991
--- /dev/null
+++ b/testing/web-platform/tests/html/infrastructure/safe-passing-of-structured-data/shared-array-buffers/resources/nested-worker-success.js.headers
@@ -0,0 +1 @@
+Cross-Origin-Embedder-Policy: require-corp
diff --git a/testing/web-platform/tests/html/infrastructure/safe-passing-of-structured-data/shared-array-buffers/resources/serviceworker-failure.js b/testing/web-platform/tests/html/infrastructure/safe-passing-of-structured-data/shared-array-buffers/resources/serviceworker-failure.js
new file mode 100644
index 0000000000..4e8fba636c
--- /dev/null
+++ b/testing/web-platform/tests/html/infrastructure/safe-passing-of-structured-data/shared-array-buffers/resources/serviceworker-failure.js
@@ -0,0 +1,33 @@
+"use strict";
+self.importScripts("/resources/testharness.js");
+
+let state = "start in worker";
+
+self.onmessage = e => {
+ if (e.data === "start in window") {
+ assert_equals(state, "start in worker");
+ e.source.postMessage(state);
+ state = "we are expecting a messageerror due to the window sending us a SAB";
+ } else if (e.data === "we are expecting a messageerror due to the worker sending us a SAB") {
+ assert_equals(state, "onmessageerror was received in worker");
+ e.source.postMessage(new SharedArrayBuffer());
+ state = "done in worker";
+ } else {
+ e.source.postMessage(`worker onmessage was reached when in state "${state}" and data ${e.data}`);
+ }
+};
+
+self.onmessageerror = e => {
+ if (state === "we are expecting a messageerror due to the window sending us a SAB") {
+ assert_equals(e.constructor.name, "ExtendableMessageEvent", "type");
+ assert_equals(e.data, null, "data");
+ assert_equals(e.origin, self.origin, "origin");
+ assert_not_equals(e.source, null, "source");
+ assert_equals(e.ports.length, 0, "ports length");
+
+ state = "onmessageerror was received in worker";
+ e.source.postMessage(state);
+ } else {
+ e.source.postMessage(`worker onmessageerror was reached when in state "${state}" and data ${e.data}`);
+ }
+};
diff --git a/testing/web-platform/tests/html/infrastructure/safe-passing-of-structured-data/shared-array-buffers/resources/serviceworker-failure.js.headers b/testing/web-platform/tests/html/infrastructure/safe-passing-of-structured-data/shared-array-buffers/resources/serviceworker-failure.js.headers
new file mode 100644
index 0000000000..6604450991
--- /dev/null
+++ b/testing/web-platform/tests/html/infrastructure/safe-passing-of-structured-data/shared-array-buffers/resources/serviceworker-failure.js.headers
@@ -0,0 +1 @@
+Cross-Origin-Embedder-Policy: require-corp
diff --git a/testing/web-platform/tests/html/infrastructure/safe-passing-of-structured-data/shared-array-buffers/resources/sharedworker-failure.js b/testing/web-platform/tests/html/infrastructure/safe-passing-of-structured-data/shared-array-buffers/resources/sharedworker-failure.js
new file mode 100644
index 0000000000..8472318abd
--- /dev/null
+++ b/testing/web-platform/tests/html/infrastructure/safe-passing-of-structured-data/shared-array-buffers/resources/sharedworker-failure.js
@@ -0,0 +1,18 @@
+let state = "send-sw-failure"
+onconnect = initialE => {
+ let port = initialE.source;
+ port.postMessage(state)
+ port.onmessage = e => {
+ if(state === "" && e.data === "send-window-failure") {
+ port.postMessage(new SharedArrayBuffer())
+ } else {
+ port.postMessage("failure")
+ }
+ }
+ port.onmessageerror = e => {
+ if(state === "send-sw-failure") {
+ port.postMessage("send-sw-failure-success")
+ state = ""
+ }
+ }
+}
diff --git a/testing/web-platform/tests/html/infrastructure/safe-passing-of-structured-data/shared-array-buffers/resources/sharedworker-failure.js.headers b/testing/web-platform/tests/html/infrastructure/safe-passing-of-structured-data/shared-array-buffers/resources/sharedworker-failure.js.headers
new file mode 100644
index 0000000000..6604450991
--- /dev/null
+++ b/testing/web-platform/tests/html/infrastructure/safe-passing-of-structured-data/shared-array-buffers/resources/sharedworker-failure.js.headers
@@ -0,0 +1 @@
+Cross-Origin-Embedder-Policy: require-corp
diff --git a/testing/web-platform/tests/html/infrastructure/safe-passing-of-structured-data/shared-array-buffers/resources/test-incrementer.js b/testing/web-platform/tests/html/infrastructure/safe-passing-of-structured-data/shared-array-buffers/resources/test-incrementer.js
new file mode 100644
index 0000000000..9c3fb813ae
--- /dev/null
+++ b/testing/web-platform/tests/html/infrastructure/safe-passing-of-structured-data/shared-array-buffers/resources/test-incrementer.js
@@ -0,0 +1,80 @@
+"use strict";
+
+self.getViewValue = (view, index) => {
+ if(view instanceof DataView) {
+ return view.getInt8(index);
+ }
+ return view[index];
+};
+
+self.setViewValue = (view, index, value) => {
+ if(view instanceof DataView) {
+ view.setInt8(index, value);
+ } else {
+ view[index] = value;
+ }
+};
+
+self.maybeBigInt = (view, value) => {
+ if (view.constructor.name === "BigInt64Array" || view.constructor.name === "BigUint64Array") {
+ return BigInt(value);
+ }
+ return value;
+};
+
+self.testSharingViaIncrementerScript = (t, whereToListen, whereToListenLabel, whereToSend, whereToSendLabel, origin, type = "Int32Array") => {
+ return new Promise(resolve => {
+ const sab = new SharedArrayBuffer(8);
+ const view = new self[type](sab);
+ setViewValue(view, 0, maybeBigInt(view, 1));
+
+ whereToListen.onmessage = t.step_func(({ data }) => {
+ switch (data.message) {
+ case "initial payload received": {
+ assert_equals(data.value, maybeBigInt(view, 1), `The ${whereToSendLabel} must see the same value in the SharedArrayBuffer`);
+ break;
+ }
+
+ case "changed to 2": {
+ assert_equals(getViewValue(view, 0), maybeBigInt(view, 2), `The ${whereToListenLabel} must see changes made in the ${whereToSendLabel}`);
+
+ setViewValue(view, 0, maybeBigInt(view, 3));
+ whereToSend.postMessage({ message: "changed to 3" }, origin);
+
+ break;
+ }
+
+ case "changed to 3 received": {
+ assert_equals(data.value, maybeBigInt(view, 3), `The ${whereToSendLabel} must see changes made in the ${whereToListenLabel}`);
+ resolve();
+ break;
+ }
+ }
+ });
+
+ whereToSend.postMessage({ message: "initial payload", view }, origin);
+ });
+};
+
+self.setupDestinationIncrementer = (whereToListen, whereToSendBackTo, origin) => {
+ let view;
+ whereToListen.onmessage = ({ data }) => {
+ switch (data.message) {
+ case "initial payload": {
+ view = data.view;
+ whereToSendBackTo.postMessage({ message: "initial payload received", value: getViewValue(view, 0) }, origin);
+
+ setViewValue(view, 0, maybeBigInt(view, 2));
+ whereToSendBackTo.postMessage({ message: "changed to 2" }, origin);
+
+ break;
+ }
+
+ case "changed to 3": {
+ whereToSendBackTo.postMessage({ message: "changed to 3 received", value: getViewValue(view, 0) }, origin);
+
+ break;
+ }
+ }
+ };
+};
diff --git a/testing/web-platform/tests/html/infrastructure/safe-passing-of-structured-data/shared-array-buffers/resources/test-sab.js b/testing/web-platform/tests/html/infrastructure/safe-passing-of-structured-data/shared-array-buffers/resources/test-sab.js
new file mode 100644
index 0000000000..6d6efda00d
--- /dev/null
+++ b/testing/web-platform/tests/html/infrastructure/safe-passing-of-structured-data/shared-array-buffers/resources/test-sab.js
@@ -0,0 +1,15 @@
+"use strict";
+
+self.assertSABsHaveSameBackingBlock = (originalSAB, clonedSAB) => {
+ const originalView = new Uint8Array(originalSAB);
+ const clonedView = new Uint8Array(clonedSAB);
+
+ assert_not_equals(originalSAB, clonedSAB, "the clone must not be the same object");
+
+ assert_equals(originalView[0], 0, "originalView[0] starts 0");
+ assert_equals(clonedView[0], 0, "clonedView[0] starts 0");
+
+ originalView[0] = 5;
+ assert_equals(originalView[0], 5, "originalView[0] ends up 5");
+ assert_equals(clonedView[0], 5, "clonedView[0] ends up 5");
+};
diff --git a/testing/web-platform/tests/html/infrastructure/safe-passing-of-structured-data/shared-array-buffers/serialization-via-history.https.html b/testing/web-platform/tests/html/infrastructure/safe-passing-of-structured-data/shared-array-buffers/serialization-via-history.https.html
new file mode 100644
index 0000000000..28859f17cb
--- /dev/null
+++ b/testing/web-platform/tests/html/infrastructure/safe-passing-of-structured-data/shared-array-buffers/serialization-via-history.https.html
@@ -0,0 +1,36 @@
+<!DOCTYPE html>
+<meta charset="utf-8">
+<title>SharedArrayBuffers cloning via history's methods invoking StructuredSerializeForStorage</title>
+<link rel="help" href="https://html.spec.whatwg.org/multipage/#structuredserializeforstorage">
+<link rel="help" href="https://html.spec.whatwg.org/multipage/#dom-history-pushstate">
+<link rel="help" href="https://html.spec.whatwg.org/multipage/#dom-history-replacestate">
+<link rel="author" title="Domenic Denicola" href="mailto:d@domenic.me">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+
+<script>
+"use strict";
+
+for (const method of ["pushState", "replaceState"]) {
+ test(() => {
+ assert_throws_dom("DataCloneError", () => {
+ history[method](new SharedArrayBuffer(), "dummy title");
+ });
+ }, `history.${method}(): simple case`);
+
+ test(() => {
+ let getter1Called = false;
+ let getter2Called = false;
+ assert_throws_dom("DataCloneError", () => {
+ history[method]([
+ { get x() { getter1Called = true; return 5; } },
+ new SharedArrayBuffer(),
+ { get x() { getter2Called = true; return 5; } }
+ ], "dummy title");
+ });
+
+ assert_true(getter1Called, "The getter before the SAB must have been called");
+ assert_false(getter2Called, "The getter after the SAB must not have been called");
+ }, `history.${method}(): is interleaved correctly`);
+}
+</script>
diff --git a/testing/web-platform/tests/html/infrastructure/safe-passing-of-structured-data/shared-array-buffers/serialization-via-history.https.html.headers b/testing/web-platform/tests/html/infrastructure/safe-passing-of-structured-data/shared-array-buffers/serialization-via-history.https.html.headers
new file mode 100644
index 0000000000..63b60e490f
--- /dev/null
+++ b/testing/web-platform/tests/html/infrastructure/safe-passing-of-structured-data/shared-array-buffers/serialization-via-history.https.html.headers
@@ -0,0 +1,2 @@
+Cross-Origin-Opener-Policy: same-origin
+Cross-Origin-Embedder-Policy: require-corp
diff --git a/testing/web-platform/tests/html/infrastructure/safe-passing-of-structured-data/shared-array-buffers/serialization-via-idb.any.js b/testing/web-platform/tests/html/infrastructure/safe-passing-of-structured-data/shared-array-buffers/serialization-via-idb.any.js
new file mode 100644
index 0000000000..e317b150cc
--- /dev/null
+++ b/testing/web-platform/tests/html/infrastructure/safe-passing-of-structured-data/shared-array-buffers/serialization-via-idb.any.js
@@ -0,0 +1,44 @@
+// META: script=/IndexedDB/resources/support.js
+"use strict";
+
+async_test(t => {
+ const openReq = createdb(t);
+
+ openReq.onupgradeneeded = e => {
+ const db = e.target.result;
+ const store = db.createObjectStore("store", { keyPath: "key" });
+ // See https://github.com/whatwg/html/issues/5380 for why not `new SharedArrayBuffer()`
+ const sab = new WebAssembly.Memory({ shared:true, initial:1, maximum:1 }).buffer;
+
+ assert_throws_dom("DataCloneError", () => {
+ store.put({ key: 1, property: sab });
+ });
+ t.done();
+ };
+}, "SharedArrayBuffer cloning via IndexedDB: basic case");
+
+async_test(t => {
+ const openReq = createdb(t);
+
+ openReq.onupgradeneeded = e => {
+ const db = e.target.result;
+ const store = db.createObjectStore("store", { keyPath: "key" });
+ // See https://github.com/whatwg/html/issues/5380 for why not `new SharedArrayBuffer()`
+ const sab = new WebAssembly.Memory({ shared:true, initial:1, maximum:1 }).buffer;
+
+ let getter1Called = false;
+ let getter2Called = false;
+
+ assert_throws_dom("DataCloneError", () => {
+ store.put({ key: 1, property: [
+ { get x() { getter1Called = true; return 5; } },
+ sab,
+ { get x() { getter2Called = true; return 5; } }
+ ]});
+ });
+
+ assert_true(getter1Called, "The getter before the SAB must have been called");
+ assert_false(getter2Called, "The getter after the SAB must not have been called");
+ t.done();
+ };
+}, "SharedArrayBuffer cloning via the IndexedDB: is interleaved correctly");
diff --git a/testing/web-platform/tests/html/infrastructure/safe-passing-of-structured-data/shared-array-buffers/serialization-via-notifications-api.any.js b/testing/web-platform/tests/html/infrastructure/safe-passing-of-structured-data/shared-array-buffers/serialization-via-notifications-api.any.js
new file mode 100644
index 0000000000..4c1c1fdabb
--- /dev/null
+++ b/testing/web-platform/tests/html/infrastructure/safe-passing-of-structured-data/shared-array-buffers/serialization-via-notifications-api.any.js
@@ -0,0 +1,28 @@
+"use strict";
+
+test(() => {
+ assert_throws_dom("DataCloneError", () => {
+ // See https://github.com/whatwg/html/issues/5380 for why not `new SharedArrayBuffer()`
+ const sab = new WebAssembly.Memory({ shared:true, initial:1, maximum:1 }).buffer;
+ new Notification("Bob: Hi", { data: sab });
+ })
+}, "SharedArrayBuffer cloning via the Notifications API's data member: basic case");
+
+test(() => {
+ // See https://github.com/whatwg/html/issues/5380 for why not `new SharedArrayBuffer()`
+ const sab = new WebAssembly.Memory({ shared:true, initial:1, maximum:1 }).buffer;
+
+ let getter1Called = false;
+ let getter2Called = false;
+
+ assert_throws_dom("DataCloneError", () => {
+ new Notification("Bob: Hi", { data: [
+ { get x() { getter1Called = true; return 5; } },
+ sab,
+ { get x() { getter2Called = true; return 5; } }
+ ]});
+ });
+
+ assert_true(getter1Called, "The getter before the SAB must have been called");
+ assert_false(getter2Called, "The getter after the SAB must not have been called");
+}, "SharedArrayBuffer cloning via the Notifications API's data member: is interleaved correctly");
diff --git a/testing/web-platform/tests/html/infrastructure/safe-passing-of-structured-data/shared-array-buffers/window-domain-failure.https.sub.html b/testing/web-platform/tests/html/infrastructure/safe-passing-of-structured-data/shared-array-buffers/window-domain-failure.https.sub.html
new file mode 100644
index 0000000000..6fa196e094
--- /dev/null
+++ b/testing/web-platform/tests/html/infrastructure/safe-passing-of-structured-data/shared-array-buffers/window-domain-failure.https.sub.html
@@ -0,0 +1,49 @@
+<!DOCTYPE html>
+<meta charset="utf-8">
+<title>Structured cloning of SharedArrayBuffers into same-origin-domain windows</title>
+<link rel="help" href="https://html.spec.whatwg.org/multipage/#structuredserialize">
+<link rel="author" title="Domenic Denicola" href="mailto:d@domenic.me">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<body>
+<script>
+"use strict";
+document.domain = "{{host}}";
+
+async_test(t => {
+ const iframe = document.createElement("iframe");
+ t.add_cleanup(() => iframe.remove());
+ iframe.src = "//{{domains[www1]}}:{{location[port]}}/html/infrastructure/safe-passing-of-structured-data/shared-array-buffers/resources/iframe-domain-failure.sub.html";
+ let domain;
+ let childCrossOriginIsolated;
+ window.onmessage = t.step_func((e) => {
+ if (e.data.name === "domain") {
+ domain = e.data.value;
+ return;
+ }
+ if (e.data.name === "crossOriginIsolated") {
+ childCrossOriginIsolated = e.data.value;
+ return;
+ }
+ if (e.data.name === "hasSharedArrayBuffer") {
+ const hasSharedArrayBuffer = e.data.value;
+
+ // document.domain mutation is no-op because the surrounding agent
+ // cluster's cross-origin isolated is true.
+ assert_equals(domain, "{{domains[www1]}}");
+
+ // crossOriginIsolated is false in the nested frame because the frame is
+ // cross-origin and hence the cross-origin isolated capability is false.
+ // We use assert_equals instead of assert_false here to see if
+ // `childCrossOriginIsolated` is set.
+ assert_equals(childCrossOriginIsolated, false);
+
+ assert_false(hasSharedArrayBuffer);
+ t.done();
+ return;
+ }
+ assert_unreached("Got a message event, expected a messageerror event");
+ });
+ document.body.append(iframe);
+}, "SharedArrayBuffer and a same-origin-domain (but not same-origin) iframe");
+</script>
diff --git a/testing/web-platform/tests/html/infrastructure/safe-passing-of-structured-data/shared-array-buffers/window-domain-failure.https.sub.html.headers b/testing/web-platform/tests/html/infrastructure/safe-passing-of-structured-data/shared-array-buffers/window-domain-failure.https.sub.html.headers
new file mode 100644
index 0000000000..63b60e490f
--- /dev/null
+++ b/testing/web-platform/tests/html/infrastructure/safe-passing-of-structured-data/shared-array-buffers/window-domain-failure.https.sub.html.headers
@@ -0,0 +1,2 @@
+Cross-Origin-Opener-Policy: same-origin
+Cross-Origin-Embedder-Policy: require-corp
diff --git a/testing/web-platform/tests/html/infrastructure/safe-passing-of-structured-data/shared-array-buffers/window-failure.https.html b/testing/web-platform/tests/html/infrastructure/safe-passing-of-structured-data/shared-array-buffers/window-failure.https.html
new file mode 100644
index 0000000000..203a9f637f
--- /dev/null
+++ b/testing/web-platform/tests/html/infrastructure/safe-passing-of-structured-data/shared-array-buffers/window-failure.https.html
@@ -0,0 +1,15 @@
+<!doctype html>
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="/common/get-host-info.sub.js"></script>
+<div id=log></div>
+<script>
+async_test(t => {
+ const frame = document.createElement("iframe");
+ t.add_cleanup(() => frame.remove());
+ frame.src = get_host_info().HTTPS_NOTSAMESITE_ORIGIN + new URL("resources/iframe-failure.html", location).pathname;
+ window.onmessage = t.unreached_func("Got a message event, expected a messageerror event");
+ window.onmessageerror = t.step_func_done();
+ document.body.append(frame);
+}, "SharedArrayBuffer and a cross-site <iframe>");
+</script>
diff --git a/testing/web-platform/tests/html/infrastructure/safe-passing-of-structured-data/shared-array-buffers/window-failure.https.html.headers b/testing/web-platform/tests/html/infrastructure/safe-passing-of-structured-data/shared-array-buffers/window-failure.https.html.headers
new file mode 100644
index 0000000000..63b60e490f
--- /dev/null
+++ b/testing/web-platform/tests/html/infrastructure/safe-passing-of-structured-data/shared-array-buffers/window-failure.https.html.headers
@@ -0,0 +1,2 @@
+Cross-Origin-Opener-Policy: same-origin
+Cross-Origin-Embedder-Policy: require-corp
diff --git a/testing/web-platform/tests/html/infrastructure/safe-passing-of-structured-data/shared-array-buffers/window-iframe-messagechannel.https.html b/testing/web-platform/tests/html/infrastructure/safe-passing-of-structured-data/shared-array-buffers/window-iframe-messagechannel.https.html
new file mode 100644
index 0000000000..acef65cbdf
--- /dev/null
+++ b/testing/web-platform/tests/html/infrastructure/safe-passing-of-structured-data/shared-array-buffers/window-iframe-messagechannel.https.html
@@ -0,0 +1,80 @@
+<!DOCTYPE html>
+<meta charset="utf-8">
+<title>Structured cloning of SharedArrayBuffers into windows using MessageChannel</title>
+<link rel="help" href="https://html.spec.whatwg.org/multipage/#structuredserialize">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="resources/test-incrementer.js"></script>
+<script src="/common/get-host-info.sub.js"></script>
+
+<div id="log"></div>
+
+<script>
+promise_test(t => {
+ return new Promise(resolve => {
+ const iframe = document.createElement("iframe");
+ window.onmessage = t.step_func((message) => {
+ // data will be a MessagePort
+ resolve(testSharingViaIncrementerScript(t, message.data, "window", message.data, "iframe"));
+ });
+ iframe.src = "resources/incrementer-iframe-messagechannel.html";
+ document.body.appendChild(iframe);
+ });
+}, `postMessaging to a same-origin iframe via MessageChannel allows them to see each others' modifications`);
+
+promise_test(t => {
+ return new Promise(resolve => {
+ const iframe = document.createElement("iframe");
+ window.onmessage = t.step_func((message) => {
+ // data will be a MessagePort
+ message.data.postMessage(new SharedArrayBuffer(10));
+ message.data.onmessage = t.step_func(message => {
+ assert_equals(message.data, "messageerror event received");
+ resolve();
+ });
+ });
+ iframe.src = get_host_info().HTTPS_REMOTE_ORIGIN + new URL("resources/iframe-messagechannel-site-failure.html", window.location).pathname;
+ document.body.appendChild(iframe);
+ });
+}, "postMessaging to a same-site iframe via MessageChannel should fail");
+
+promise_test(t => {
+ return new Promise(resolve => {
+ const iframe = document.createElement("iframe");
+ window.onmessage = t.step_func(message => {
+ // data will be a MessagePort
+ message.data.postMessage(new SharedArrayBuffer(10));
+ message.data.onmessage = t.step_func(message => {
+ assert_equals(message.data, "messageerror event received");
+ resolve();
+ });
+ });
+ iframe.src = get_host_info().HTTPS_NOTSAMESITE_ORIGIN + new URL("resources/iframe-messagechannel-failure.html", window.location).pathname;
+ document.body.append(iframe);
+ });
+}, "postMessaging to a cross-site iframe via MessageChannel should fail");
+
+promise_test(t => {
+ return new Promise(resolve => {
+ const iframe = document.createElement("iframe");
+ let port = null;
+ window.onmessage = t.step_func(message => {
+ if (message.data.state === "port1") {
+ port = message.data.data;
+ port.postMessage(new SharedArrayBuffer(10));
+ message.source.postMessage("send port2", "*");
+ } else if (message.data.state === "port2") {
+ // Note that onmessage calls start()
+ message.data.data.onmessage = t.step_func(message => {
+ assert_true(message.data instanceof SharedArrayBuffer);
+ assert_equals(message.data.byteLength, 10);
+ resolve();
+ });
+ message.data.data.onmessageerror = t.unreached_func();
+ }
+ });
+ iframe.src = get_host_info().HTTPS_NOTSAMESITE_ORIGIN + new URL("resources/iframe-messagechannel-complex.html", window.location).pathname;
+ document.body.append(iframe);
+ });
+}, "postMessaging with a MessageChannel that's been cross-site should succeed");
+</script>
diff --git a/testing/web-platform/tests/html/infrastructure/safe-passing-of-structured-data/shared-array-buffers/window-iframe-messagechannel.https.html.headers b/testing/web-platform/tests/html/infrastructure/safe-passing-of-structured-data/shared-array-buffers/window-iframe-messagechannel.https.html.headers
new file mode 100644
index 0000000000..63b60e490f
--- /dev/null
+++ b/testing/web-platform/tests/html/infrastructure/safe-passing-of-structured-data/shared-array-buffers/window-iframe-messagechannel.https.html.headers
@@ -0,0 +1,2 @@
+Cross-Origin-Opener-Policy: same-origin
+Cross-Origin-Embedder-Policy: require-corp
diff --git a/testing/web-platform/tests/html/infrastructure/safe-passing-of-structured-data/shared-array-buffers/window-messagechannel-success.https.html b/testing/web-platform/tests/html/infrastructure/safe-passing-of-structured-data/shared-array-buffers/window-messagechannel-success.https.html
new file mode 100644
index 0000000000..cd67e5b2c9
--- /dev/null
+++ b/testing/web-platform/tests/html/infrastructure/safe-passing-of-structured-data/shared-array-buffers/window-messagechannel-success.https.html
@@ -0,0 +1,22 @@
+<!DOCTYPE html>
+<meta charset="utf-8">
+<title>Structured cloning of SharedArrayBuffers using MessageChannel</title>
+<link rel="help" href="https://html.spec.whatwg.org/multipage/#structuredserialize">
+<link rel="author" title="Domenic Denicola" href="mailto:d@domenic.me">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="resources/test-incrementer.js"></script>
+
+<div id="log"></div>
+
+<script>
+"use strict";
+
+promise_test(t => {
+ const worker = new Worker("resources/incrementer-worker-with-channel.js");
+ const channel = new MessageChannel();
+ worker.postMessage(channel.port2, [channel.port2]);
+
+ return testSharingViaIncrementerScript(t, channel.port1, "window", channel.port1, "worker");
+}, "postMessaging to a dedicated worker via MessageChannel allows them to see each others' modifications");
+</script>
diff --git a/testing/web-platform/tests/html/infrastructure/safe-passing-of-structured-data/shared-array-buffers/window-messagechannel-success.https.html.headers b/testing/web-platform/tests/html/infrastructure/safe-passing-of-structured-data/shared-array-buffers/window-messagechannel-success.https.html.headers
new file mode 100644
index 0000000000..63b60e490f
--- /dev/null
+++ b/testing/web-platform/tests/html/infrastructure/safe-passing-of-structured-data/shared-array-buffers/window-messagechannel-success.https.html.headers
@@ -0,0 +1,2 @@
+Cross-Origin-Opener-Policy: same-origin
+Cross-Origin-Embedder-Policy: require-corp
diff --git a/testing/web-platform/tests/html/infrastructure/safe-passing-of-structured-data/shared-array-buffers/window-serviceworker-failure.https.html b/testing/web-platform/tests/html/infrastructure/safe-passing-of-structured-data/shared-array-buffers/window-serviceworker-failure.https.html
new file mode 100644
index 0000000000..373359de85
--- /dev/null
+++ b/testing/web-platform/tests/html/infrastructure/safe-passing-of-structured-data/shared-array-buffers/window-serviceworker-failure.https.html
@@ -0,0 +1,56 @@
+<!DOCTYPE html>
+<meta charset="utf-8">
+<title>SharedArrayBuffer cannot cross agent clusters, service worker edition</title>
+<link rel="help" href="https://html.spec.whatwg.org/multipage/#structuredserialize">
+<link rel="author" title="Domenic Denicola" href="mailto:d@domenic.me">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="/service-workers/service-worker/resources/test-helpers.sub.js"></script>
+
+<script>
+"use strict";
+promise_test(t => {
+ const scope = "resources/blank.html";
+ return service_worker_unregister_and_register(t, "resources/serviceworker-failure.js", scope)
+ .then(reg => {
+ t.add_cleanup(() => service_worker_unregister(t, scope));
+ return wait_for_state(t, reg.installing, "activated");
+ })
+ .then(() => with_iframe(scope))
+ .then(iframe => {
+ t.add_cleanup(() => iframe.remove());
+ const sw = iframe.contentWindow.navigator.serviceWorker;
+ let state = "start in window";
+
+ return new Promise(resolve => {
+ sw.onmessage = t.step_func(e => {
+ if (e.data === "start in worker") {
+ assert_equals(state, "start in window");
+ sw.controller.postMessage(new SharedArrayBuffer());
+ state = "we are expecting confirmation of an onmessageerror in the worker";
+ } else if (e.data === "onmessageerror was received in worker") {
+ assert_equals(state, "we are expecting confirmation of an onmessageerror in the worker");
+ state = "we are expecting a messageerror due to the worker sending us a SAB";
+ sw.controller.postMessage(state);
+ } else {
+ assert_unreached("Got an unexpected message from the service worker: " + e.data);
+ }
+ });
+
+ sw.onmessageerror = t.step_func(e => {
+ assert_equals(state, "we are expecting a messageerror due to the worker sending us a SAB");
+
+ assert_equals(e.data, null, "data");
+ assert_equals(e.origin, self.origin, "origin");
+ assert_not_equals(e.source, null, "source");
+ assert_equals(e.ports.length, 0, "ports length");
+
+ state = "done in window";
+ resolve();
+ });
+
+ sw.controller.postMessage(state);
+ });
+ });
+});
+</script>
diff --git a/testing/web-platform/tests/html/infrastructure/safe-passing-of-structured-data/shared-array-buffers/window-serviceworker-failure.https.html.headers b/testing/web-platform/tests/html/infrastructure/safe-passing-of-structured-data/shared-array-buffers/window-serviceworker-failure.https.html.headers
new file mode 100644
index 0000000000..63b60e490f
--- /dev/null
+++ b/testing/web-platform/tests/html/infrastructure/safe-passing-of-structured-data/shared-array-buffers/window-serviceworker-failure.https.html.headers
@@ -0,0 +1,2 @@
+Cross-Origin-Opener-Policy: same-origin
+Cross-Origin-Embedder-Policy: require-corp
diff --git a/testing/web-platform/tests/html/infrastructure/safe-passing-of-structured-data/shared-array-buffers/window-sharedworker-failure.https.html b/testing/web-platform/tests/html/infrastructure/safe-passing-of-structured-data/shared-array-buffers/window-sharedworker-failure.https.html
new file mode 100644
index 0000000000..023cb5acde
--- /dev/null
+++ b/testing/web-platform/tests/html/infrastructure/safe-passing-of-structured-data/shared-array-buffers/window-sharedworker-failure.https.html
@@ -0,0 +1,31 @@
+<!doctype html>
+<title>SharedArrayBuffer cannot cross agent clusters, shared worker edition</title>
+<script src=/resources/testharness.js></script>
+<script src=/resources/testharnessreport.js></script>
+<script>
+async_test(t => {
+ const sw = new SharedWorker("resources/sharedworker-failure.js")
+ let state = ""
+ sw.port.onmessage = t.step_func(e => {
+ if(e.data === "send-sw-failure") {
+ sw.port.postMessage(new SharedArrayBuffer())
+ } else if(e.data === "send-sw-failure-success") {
+ state = "send-window-failure"
+ sw.port.postMessage(state)
+ } else {
+ assert_unreached()
+ }
+ })
+ sw.port.onmessageerror = t.step_func(e => {
+ if(state === "send-window-failure") {
+ assert_equals(e.data, null, "data")
+ assert_equals(e.origin, "", "origin")
+ assert_equals(e.source, null, "source")
+ assert_equals(e.ports.length, 0, "ports length")
+ t.done()
+ } else {
+ assert_unreached()
+ }
+ })
+})
+</script>
diff --git a/testing/web-platform/tests/html/infrastructure/safe-passing-of-structured-data/shared-array-buffers/window-sharedworker-failure.https.html.headers b/testing/web-platform/tests/html/infrastructure/safe-passing-of-structured-data/shared-array-buffers/window-sharedworker-failure.https.html.headers
new file mode 100644
index 0000000000..63b60e490f
--- /dev/null
+++ b/testing/web-platform/tests/html/infrastructure/safe-passing-of-structured-data/shared-array-buffers/window-sharedworker-failure.https.html.headers
@@ -0,0 +1,2 @@
+Cross-Origin-Opener-Policy: same-origin
+Cross-Origin-Embedder-Policy: require-corp
diff --git a/testing/web-platform/tests/html/infrastructure/safe-passing-of-structured-data/shared-array-buffers/window-simple-success.https.html b/testing/web-platform/tests/html/infrastructure/safe-passing-of-structured-data/shared-array-buffers/window-simple-success.https.html
new file mode 100644
index 0000000000..c9b41d0a0d
--- /dev/null
+++ b/testing/web-platform/tests/html/infrastructure/safe-passing-of-structured-data/shared-array-buffers/window-simple-success.https.html
@@ -0,0 +1,72 @@
+<!DOCTYPE html>
+<meta charset="utf-8">
+<title>Structured cloning of SharedArrayBuffers: simple success cases that don't need dedicated files</title>
+<link rel="help" href="https://html.spec.whatwg.org/multipage/#structuredserialize">
+<link rel="author" title="Domenic Denicola" href="mailto:d@domenic.me">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="resources/test-incrementer.js"></script>
+
+<div id="log"></div>
+
+<script>
+"use strict";
+
+[
+ "DataView",
+ "Int8Array",
+ "Uint8Array",
+ "Uint8ClampedArray",
+ "Int16Array",
+ "Uint16Array",
+ "Int32Array",
+ "Uint32Array",
+ "BigInt64Array",
+ "BigUint64Array",
+ "Float32Array",
+ "Float64Array"
+].forEach(type => {
+ promise_test(t => {
+ const worker = new Worker("resources/incrementer-worker.js");
+
+ return testSharingViaIncrementerScript(t, worker, "window", worker, "worker", undefined, type);
+ }, "postMessaging to a dedicated worker allows them to see each others' modifications with " + type);
+});
+
+promise_test(t => {
+ return new Promise(resolve => {
+ const iframe = document.createElement("iframe");
+ iframe.onload = t.step_func(() => {
+ resolve(testSharingViaIncrementerScript(t, window, "window", iframe.contentWindow, "iframe", "*"));
+ });
+ iframe.src = "resources/incrementer-iframe.html";
+ document.body.appendChild(iframe);
+ });
+}, "postMessaging to a same-origin iframe allows them to see each others' modifications");
+
+promise_test(t => {
+ return new Promise(resolve => {
+ const iframe = document.createElement("iframe");
+ iframe.onload = t.step_func(() => {
+ const level1 = iframe.contentWindow;
+ const level2 = level1.frames[0];
+ const level3 = level2.frames[0];
+ const targetWindow = level3.frames[0];
+ resolve(testSharingViaIncrementerScript(t, window, "window", targetWindow, "nested iframe", "*"));
+ });
+ iframe.src = "resources/nested-iframe-1.html";
+ document.body.appendChild(iframe);
+ });
+}, "postMessaging to a same-origin deeply-nested iframe allows them to see each others' modifications");
+
+promise_test(t => {
+ return new Promise(resolve => {
+ const w = window.open("resources/incrementer-popup.html");
+ w.onload = t.step_func(() => {
+ resolve(testSharingViaIncrementerScript(t, window, "window", w, "popup window", "*").then(() => {
+ w.close();
+ }));
+ });
+ });
+}, "postMessaging to a same-origin opened window allows them to see each others' modifications");
+</script>
diff --git a/testing/web-platform/tests/html/infrastructure/safe-passing-of-structured-data/shared-array-buffers/window-simple-success.https.html.headers b/testing/web-platform/tests/html/infrastructure/safe-passing-of-structured-data/shared-array-buffers/window-simple-success.https.html.headers
new file mode 100644
index 0000000000..63b60e490f
--- /dev/null
+++ b/testing/web-platform/tests/html/infrastructure/safe-passing-of-structured-data/shared-array-buffers/window-simple-success.https.html.headers
@@ -0,0 +1,2 @@
+Cross-Origin-Opener-Policy: same-origin
+Cross-Origin-Embedder-Policy: require-corp
diff --git a/testing/web-platform/tests/html/infrastructure/safe-passing-of-structured-data/structured-cloning-error-extra.html b/testing/web-platform/tests/html/infrastructure/safe-passing-of-structured-data/structured-cloning-error-extra.html
new file mode 100644
index 0000000000..5ff10cbc10
--- /dev/null
+++ b/testing/web-platform/tests/html/infrastructure/safe-passing-of-structured-data/structured-cloning-error-extra.html
@@ -0,0 +1,46 @@
+<!DOCTYPE html>
+<meta charset="utf-8">
+<title>Structured cloning of Error objects: extra tests</title>
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+
+<!-- Most tests are in the general framework in structuredclone_0.html.
+ This contains specialty tests that don't fit into that framework. -->
+
+<body>
+
+<script>
+"use strict";
+test(t => {
+ const exceptionToThrow = new Error("throw me!");
+
+ const badError = new Error();
+ Object.defineProperty(badError, "name", { get() { throw exceptionToThrow; } });
+
+ const worker = new Worker("./resources/echo-worker.js");
+ t.add_cleanup(() => worker.terminate());
+
+ assert_throws_exactly(exceptionToThrow, () => {
+ worker.postMessage(badError);
+ });
+}, "Throwing name getter fails serialization");
+
+// https://bugs.chromium.org/p/chromium/issues/detail?id=1030086
+// https://github.com/whatwg/html/pull/5150
+async_test(t => {
+ window.onmessage = t.step_func_done(e => {
+ assert_equals(e.data.name, "TypeError");
+ });
+
+ const iframe = document.createElement("iframe");
+ iframe.onload = () => {
+ if (iframe.contentWindow.location === "about:blank") {
+ return;
+ }
+
+ iframe.contentWindow.doIt();
+ };
+ iframe.src = "resources/post-parent-type-error.html";
+ document.body.append(iframe);
+}, "Errors sent across realms should preserve their type");
+</script>
diff --git a/testing/web-platform/tests/html/infrastructure/safe-passing-of-structured-data/structured-cloning-error-stack-optional.sub.window.js b/testing/web-platform/tests/html/infrastructure/safe-passing-of-structured-data/structured-cloning-error-stack-optional.sub.window.js
new file mode 100644
index 0000000000..cbc6a73d51
--- /dev/null
+++ b/testing/web-platform/tests/html/infrastructure/safe-passing-of-structured-data/structured-cloning-error-stack-optional.sub.window.js
@@ -0,0 +1,106 @@
+// META: script=/common/utils.js
+
+// .stack properties on errors are unspecified, but are present in most
+// browsers, most of the time. https://github.com/tc39/proposal-error-stacks/ tracks standardizing them.
+// Tests will pass automatically if the .stack property isn't present.
+
+stackTests(() => {
+ return new Error('some message');
+}, 'page-created Error');
+
+stackTests(() => {
+ return new DOMException('InvalidStateError', 'some message');
+}, 'page-created DOMException');
+
+stackTests(() => {
+ try {
+ Object.defineProperty();
+ } catch (e) {
+ return e;
+ }
+}, 'JS-engine-created TypeError');
+
+stackTests(() => {
+ try {
+ HTMLParagraphElement.prototype.align;
+ } catch (e) {
+ return e;
+ }
+}, 'web API-created TypeError');
+
+stackTests(() => {
+ try {
+ document.createElement('');
+ } catch (e) {
+ return e;
+ }
+}, 'web API-created DOMException');
+
+function stackTests(errorFactory, description) {
+ test(t => {
+ const error = errorFactory();
+ const originalStack = error.stack;
+
+ if (!originalStack) {
+ return;
+ }
+
+ const clonedError = structuredClone(error);
+ assert_equals(clonedError.stack, originalStack);
+ }, description + ' (structuredClone())');
+
+ async_test(t => {
+ const error = errorFactory();
+ const originalStack = error.stack;
+
+ if (!originalStack) {
+ t.done();
+ return;
+ }
+
+ const worker = new Worker('resources/echo-worker.js');
+ worker.onmessage = t.step_func_done(e => {
+ assert_equals(e.data.stack, originalStack);
+ });
+
+ worker.postMessage(error);
+ }, description + ' (worker)');
+
+ let iframeTest = (t, url) => {
+ const thisTestId = token();
+
+ const error = errorFactory();
+ const originalStack = error.stack;
+
+ if (!originalStack) {
+ t.done();
+ return;
+ }
+
+ const iframe = document.createElement('iframe');
+ window.addEventListener('message', t.step_func(e => {
+ if (e.data.testId === thisTestId) {
+ assert_equals(e.data.error.stack, originalStack);
+ t.done();
+ }
+ }));
+
+ iframe.onload = t.step_func(() => {
+ iframe.contentWindow.postMessage({ error, testId: thisTestId }, "*");
+ });
+
+ iframe.src = url;
+ document.body.append(iframe);
+ }
+
+ async_test(t => {
+ const crossSiteURL = new URL('resources/echo-iframe.html', location.href);
+ crossSiteURL.hostname = '{{hosts[alt][www1]}}';
+ iframeTest(t, crossSiteURL);
+ }, description + ' (cross-site iframe)');
+
+ async_test(t => {
+ const sameOriginURL = new URL('resources/echo-iframe.html', location.href);
+ iframeTest(t, sameOriginURL);
+ }, description + ' (same-origin iframe)')
+}
diff --git a/testing/web-platform/tests/html/infrastructure/safe-passing-of-structured-data/structuredclone_0.html b/testing/web-platform/tests/html/infrastructure/safe-passing-of-structured-data/structuredclone_0.html
new file mode 100644
index 0000000000..c8a6d38393
--- /dev/null
+++ b/testing/web-platform/tests/html/infrastructure/safe-passing-of-structured-data/structuredclone_0.html
@@ -0,0 +1,637 @@
+<!doctype html>
+<html>
+ <head>
+ <meta content="text/html; charset=utf-8" http-equiv="content-type" />
+ <title>2.8 Common DOM interfaces - Structured Clone Algorithm </title>
+ <link rel="help" href="http://www.w3.org/TR/html5/common-dom-interfaces.html#safe-passing-of-structured-data" />
+ <script src="/resources/testharness.js"></script>
+ <script src="/resources/testharnessreport.js"></script>
+</head>
+<body>
+ <div id="log"></div>
+ <iframe></iframe> <!-- used for grabbing an URIError from another realm -->
+
+<script type="text/javascript">
+ var worker;
+ var testCollection;
+ setup(function()
+ {
+ //the worker is used for each test in sequence
+ //worker's callback will be set for each test
+ //worker's internal onmessage echoes the data back to this thread through postMessage
+ worker = new Worker("./resources/echo-worker.js");
+ testCollection = [
+ function() {
+ var t = async_test("Primitive string is cloned");
+ t.id = 0;
+ worker.onmessage = t.step_func(function(e) {assert_equals("primitive string", e.data, "\"primitive string\" === event.data"); t.done(); });
+ t.step(function() { worker.postMessage("primitive string");});
+ },
+ function() {
+ var t = async_test("Primitive integer is cloned");
+ t.id = 1;
+ worker.onmessage = t.step_func(function(e) {assert_equals(2000, e.data, "2000 === event.data"); t.done(); });
+ t.step(function() { worker.postMessage(2000);});
+ },
+ function() {
+ var t = async_test("Primitive floating point is cloned");
+ t.id = 2;
+ worker.onmessage = t.step_func(function(e) {assert_equals(111.456, e.data, "111.456 === event.data"); t.done(); });
+ t.step(function() { worker.postMessage(111.456);});
+ },
+ function() {
+ var t = async_test("Primitive floating point (negative) is cloned");
+ t.id = 3;
+ worker.onmessage = t.step_func(function(e) {assert_equals(-111.456, e.data, "-111.456 === event.data"); t.done(); });
+ t.step(function() { worker.postMessage(-111.456);});
+ },
+ function() {
+ var t = async_test("Primitive number (hex) is cloned");
+ t.id = 4;
+ worker.onmessage = t.step_func(function(e) {assert_equals(0xAB25, e.data, "0xAB25 === event.data"); t.done(); });
+ t.step(function() { worker.postMessage(0xAB25);});
+ },
+ function() {
+ var t = async_test("Primitive number (scientific) is cloned");
+ t.id = 5;
+ worker.onmessage = t.step_func(function(e) {assert_equals(15e2, e.data, "15e2 === event.data"); t.done(); });
+ t.step(function() { worker.postMessage(15e2);});
+ },
+ function() {
+ var t = async_test("Primitive boolean is cloned");
+ t.id = 6;
+ worker.onmessage = t.step_func(function(e) {assert_equals(false, e.data, "false === event.data"); t.done(); });
+ t.step(function() { worker.postMessage(false);});
+ },
+ function() {
+ var t = async_test("Instance of Boolean is cloned");
+ t.id = 7;
+ var obj;
+ t.step(function() {obj = new Boolean(false);});
+ worker.onmessage = t.step_func(function(e) {
+ assert_equals(obj.constructor, e.data.constructor, "Boolean === event.data.constructor");
+ assert_equals(obj.valueOf(), e.data.valueOf(), "(new Boolean(false)).valueof() === event.data.valueOf()");
+ t.done();
+ });
+ t.step(function() { worker.postMessage(obj);});
+ },function() {
+ var t = async_test("Instance of Number is cloned");
+ t.id = 8;
+ var obj;
+ t.step(function() {obj = new Number(2000);});
+ worker.onmessage = t.step_func(function(e) {
+ assert_equals(obj.constructor, e.data.constructor, "Number === event.data.constructor");
+ assert_equals(obj.valueOf(), e.data.valueOf(), "(new Number(2000)).valueof() === event.data.valueOf()");
+ t.done();
+ });
+ t.step(function() { worker.postMessage(obj);});
+ },
+ function() {
+ var t = async_test("Instance of String is cloned");
+ t.id = 9;
+ var obj;
+ t.step(function() { obj = new String("String Object");});
+ worker.onmessage = t.step_func(function(e) {
+ assert_equals(obj.constructor, e.data.constructor, "String === event.data.constructor");
+ assert_equals(obj.valueOf(), e.data.valueOf(), "(new String(\"String Object\")).valueof() === event.data.valueOf()");
+ t.done();
+ });
+ t.step(function() { worker.postMessage(obj);});
+ },
+ function() {
+ var t = async_test("Instance of Date is cloned");
+ t.id = 10;
+ var obj;
+ t.step(function() { obj= new Date(2011,1,1);});
+ worker.onmessage = t.step_func(function(e) {
+ assert_equals(obj.constructor, e.data.constructor, "Date === event.data.constructor");
+ assert_equals(obj.valueOf(), e.data.valueOf(), "(new Date(2011,1,1)).valueof() === event.data.valueOf()");
+ t.done();
+ });
+ t.step(function() { worker.postMessage(obj);});
+ },
+ function() {
+ var t = async_test("Instance of RegExp is cloned");
+ t.id = 11;
+ var obj;
+ t.step(function() {obj = new RegExp("w3+c","g","i");});
+ worker.onmessage = t.step_func(function(e) {
+ assert_equals(obj.constructor, e.data.constructor, "RegExp === event.data.constructor");
+ assert_equals(obj.source, e.data.source, "canon.source === event.data.source");
+ assert_equals(obj.multiline, e.data.multiline, "canon.multiline === event.data.multiline");
+ assert_equals(obj.global, e.data.global, "canon.global === event.data.global");
+ assert_equals(obj.ignoreCase, e.data.ignoreCase, "canon.ignoreCase === event.data.ignoreCase");
+ t.done();
+ });
+ t.step(function() { worker.postMessage(obj);});
+ },
+ function() {
+ var t = async_test("Value 'null' is cloned");
+ t.id = 12;
+ worker.onmessage = t.step_func(function(e) {assert_equals(null, e.data, "null === event.data"); t.done(); });
+ t.step(function() { worker.postMessage(null);});
+ },
+ function() {
+ var t = async_test("Value 'undefined' is cloned");
+ t.id = 13;
+ worker.onmessage = t.step_func(function(e) {assert_equals(undefined, e.data, "undefined === event.data"); t.done(); });
+ t.step(function() { worker.postMessage(undefined);});
+ },
+ function() {
+ var t = async_test("Object properties are cloned");
+ t.id = 14;
+ var obj;
+ t.step(function() {
+ obj= {};
+ obj.a = "test";
+ obj.b = 2;
+ obj["child"] = 3;
+ });
+ worker.onmessage = t.step_func(function(e) {
+ assert_equals(obj.constructor, e.data.constructor, "canon.constructor === event.data.constructor");
+ assert_equals(obj.a, e.data.a, "canon.a === event.data.a");
+ assert_equals(obj.b, e.data.b, "canon.b === event.data.b");
+ assert_equals(obj.child, e.data.child, "canon.child === e.data.child");
+ t.done();
+ });
+ t.step(function() { worker.postMessage(obj);});
+ },
+ function() {
+ var t = async_test("Prototype chains are not walked.");
+ t.id = 15;
+ function Custom() {
+ this.a = "hello";
+ }
+
+ var obj;
+ t.step(function() {
+ Object.defineProperty(Custom.prototype, "b", { enumerable: true, value: 100 });
+ obj = new Custom();
+ });
+ worker.onmessage = t.step_func(function(e) {
+ assert_not_equals(obj.constructor, e.data.constructor, "canon.constructor !== event.data.constructor");
+ assert_equals(Object, e.data.constructor, "Object === e.data.constructor");
+ assert_equals(obj.a, e.data.a, "canon.a === e.data.a");
+ assert_equals(undefined, e.data.b, "undefined === e.data.b");
+ t.done();
+ });
+ t.step(function() { worker.postMessage(obj);});
+ },
+ function() {
+ var t = async_test("Property descriptors of Objects are not cloned");
+ t.id = 16;
+ var obj;
+ t.step(function() {
+ obj = {};
+ Object.defineProperty(obj, "a", { enumerable: true, writable: false, value: 100 });
+ });
+ worker.onmessage = t.step_func(function(e) {
+ var des = Object.getOwnPropertyDescriptor(e.data, "a");
+ assert_equals(obj.constructor, e.data.constructor, "canon.constructor === event.data.constructor");
+ assert_true(des.writable, "Descriptor is writable");
+ t.done();
+ });
+ t.step(function() { worker.postMessage(obj);});
+ },
+ function() {
+ var t = async_test("Cycles are preserved in Objects");
+ t.id = 17;
+ var obj;
+ t.step(function() {
+ obj = {};
+ obj.a = obj;
+ });
+ worker.onmessage = t.step_func(function(e) {
+ assert_equals(obj.constructor, e.data.constructor, "canon.constructor === event.data.constructor");
+ assert_equals(e.data, e.data.a, "cycle is preserved");
+ t.done();
+ });
+ t.step(function() { worker.postMessage(obj);});
+ },
+ function() {
+ var t = async_test("Identity of duplicates is preserved");
+ t.id = 18;
+ var ref;
+ var obj;
+ t.step(function() {
+ ref = {};
+ ref.called = 0;
+ Object.defineProperty(ref, "child", {get: function(){this.called++;}, enumerable: true});
+
+ obj = {a:ref, b:ref};
+ });
+ worker.onmessage = t.step_func(function(e) {
+ assert_equals(obj.constructor, e.data.constructor, "canon.constructor === event.data.constructor");
+ assert_equals(e.data.b.called, 0, "e.data.b.called === 0");
+ t.done();
+ });
+ t.step(function() { worker.postMessage(obj);});
+ },
+ function() {
+ var t = async_test("Property order is preserved");
+ t.id = 19;
+ var obj;
+ t.step(function() {
+ obj = { "a": "hello", "b": "w3c", "c": "and world" };
+ obj["a"] = "named1";
+ });
+ worker.onmessage = t.step_func(function(e) {
+ assert_equals(obj.constructor, e.data.constructor, "canon.constructor === event.data.constructor");
+ var canonNames = Object.getOwnPropertyNames(obj);
+ var testNames = Object.getOwnPropertyNames(e.data);
+ for (var i in canonNames) {
+ assert_equals(canonNames[i], testNames[i], "canonProperty["+i+"] === dataProperty["+i+"]");
+ }
+ t.done();
+ });
+ t.step(function() { worker.postMessage(obj);});
+ },
+ function() {
+ var t = async_test("Enumerable properties of Arrays are cloned");
+ t.id = 20;
+ var obj;
+ t.step(function() {
+ obj = [0,1];
+ obj["a"] = "named1";
+ });
+ worker.onmessage = t.step_func(function(e) {
+ assert_equals(obj.constructor, e.data.constructor, "canon.constructor === event.data.constructor");
+ assert_equals(e.data["a"], "named1", "e.data[\"a\"] === \"named1\"");
+ assert_equals(e.data[0], 0, "e.data[0] === 0");
+ assert_equals(e.data[1], 1, "e.data[1] === 1");
+ t.done();
+ });
+ t.step(function() { worker.postMessage(obj);});
+ },
+ function() {
+ var t = async_test("Property descriptors of Arrays are not cloned");
+ t.id = 21;
+ var obj;
+ t.step(function() {
+ obj = [0, 1];
+ Object.defineProperty(obj, "2", { enumerable: true, writable: false, value: 100 });
+ });
+ worker.onmessage = t.step_func(function(e) {
+ assert_equals(obj.constructor, e.data.constructor, "canon.constructor === event.data.constructor");
+ assert_equals(e.data[0], 0, "e.data[0] === 0");
+ assert_equals(e.data[1], 1, "e.data[1] === 1");
+ var des = Object.getOwnPropertyDescriptor(e.data, "2");
+ assert_true(des.writable, "Descriptor is writable");
+ t.done();
+ });
+ t.step(function() { worker.postMessage(obj);});
+ },
+ function() {
+ var t = async_test("Cycles are preserved in Arrays");
+ t.id = 22;
+ var obj;
+ t.step(function() {
+ obj = [0,1];
+ obj[2] = obj;
+ });
+ worker.onmessage = t.step_func(function(e) {
+ assert_equals(obj.constructor, e.data.constructor, "canon.constructor === event.data.constructor");
+ assert_equals(e.data[0], 0, "e.data[0] === 0");
+ assert_equals(e.data[1], 1, "e.data[1] === 1");
+ assert_equals(e.data[2], e.data, "e.data[2] === e.data");
+ t.done();
+ });
+ t.step(function() { worker.postMessage(obj);});
+ },
+
+ function() {
+ var t = async_test("ImageData object can be cloned");
+ t.id = 23;
+ var obj;
+ t.step(function() {
+ var canvas = document.createElement("canvas");
+ canvas.width = 40;
+ canvas.height = 40;
+ var context = canvas.getContext('2d');
+ obj = context.createImageData(40, 40);
+ assert_true(window.hasOwnProperty("ImageData"), "ImageData constructor must be present");
+ assert_true(obj instanceof ImageData, "ImageData must be returned by .createImageData");
+ });
+ worker.onmessage = t.step_func(function(e) {
+ assert_equals(obj.constructor, e.data.constructor, "canon.constructor === event.data.constructor");
+ assert_not_equals(obj, e.data, "cloned object should be a new instance of ImageData");
+ assert_equals(obj.width, e.data.width, "canon.width === e.data.width");
+ assert_equals(obj.height, e.data.height, "canon.height === e.data.height");
+ assert_array_equals(obj.data, e.data.data, "data arrays are the same");
+ t.done();
+ });
+ t.step(function() { worker.postMessage(obj);});
+ },
+ function() {
+ var t = async_test("ImageData expandos are not cloned");
+ t.id = 24;
+ var obj;
+ t.step(function() {
+ var canvas = document.createElement("canvas");
+ canvas.width = 40;
+ canvas.height = 40;
+ var context = canvas.getContext('2d');
+ obj = context.createImageData(40, 40);
+ assert_true(window.hasOwnProperty("ImageData"), "ImageData constructor must be present");
+ assert_true(obj instanceof ImageData, "ImageData must be returned by .createImageData");
+ obj.foo = "bar";
+ });
+ worker.onmessage = t.step_func(function(e) {
+ assert_equals(obj.constructor, e.data.constructor, "canon.constructor === event.data.constructor");
+ assert_not_equals(obj, e.data, "cloned object should be a new instance of ImageData");
+ assert_equals(obj.width, e.data.width, "canon.width === e.data.width");
+ assert_equals(obj.height, e.data.height, "canon.height === e.data.height");
+ assert_array_equals(obj.data, e.data.data, "data arrays are the same");
+ assert_equals(undefined, e.data.foo, "Expando is lost (undefined === e.data.foo)");
+ t.done();
+ });
+ t.step(function() { worker.postMessage(obj);});
+ },
+ function() {
+ var t = async_test("Window objects cannot be cloned");
+ t.id = 25;
+ worker.onmessage = function() {}; //no op because exception should be thrown.
+ t.step(function() {
+ assert_true(DOMException.hasOwnProperty('DATA_CLONE_ERR'), "DOMException.DATA_CLONE_ERR is present");
+ assert_equals(DOMException.DATA_CLONE_ERR, 25, "DOMException.DATA_CLONE_ERR === 25");
+ assert_throws_dom('DATA_CLONE_ERR', function() {worker.postMessage(window)});
+ });
+ t.done();
+ },
+ function() {
+ var t = async_test("Document objects cannot be cloned");
+ t.id = 26;
+ worker.onmessage = function() {}; //no op because exception should be thrown.
+ t.step(function() {
+ assert_true(DOMException.hasOwnProperty('DATA_CLONE_ERR'), "DOMException.DATA_CLONE_ERR is present");
+ assert_equals(DOMException.DATA_CLONE_ERR, 25, "DOMException.DATA_CLONE_ERR === 25");
+ assert_throws_dom('DATA_CLONE_ERR', function() {worker.postMessage(document)});
+ });
+ t.done();
+ },
+ function() {
+ var t = async_test("Empty Error objects can be cloned");
+ t.id = 27;
+ worker.onmessage = t.step_func_done(function(e) {
+ assert_equals(Object.getPrototypeOf(e.data), Error.prototype, "Checking prototype");
+ assert_equals(e.data.constructor, Error, "Checking constructor");
+ assert_equals(e.data.name, "Error", "Checking name");
+ assert_false(e.data.hasOwnProperty("message"), "Checking message");
+ assert_equals(e.data.foo, undefined, "Checking custom property");
+ });
+ t.step(function() {
+ const error = Error();
+ assert_false(error.hasOwnProperty("message"), "Checking message on the source realm");
+ worker.postMessage(error);
+ });
+ },
+ function() {
+ var t = async_test("Error objects can be cloned");
+ t.id = 28;
+ worker.onmessage = t.step_func_done(function(e) {
+ assert_equals(Object.getPrototypeOf(e.data), Error.prototype, "Checking prototype");
+ assert_equals(e.data.constructor, Error, "Checking constructor");
+ assert_equals(e.data.name, "Error", "Checking name");
+ assert_equals(e.data.message, "some message", "Checking message");
+ assert_equals(e.data.foo, undefined, "Checking custom property");
+ });
+ t.step(function() {
+ const error = Error("some message");
+ error.foo = "bar";
+ worker.postMessage(error);
+ });
+ },
+ function() {
+ var t = async_test("EvalError objects can be cloned");
+ t.id = 29;
+ worker.onmessage = t.step_func_done(function(e) {
+ assert_equals(Object.getPrototypeOf(e.data), EvalError.prototype, "Checking prototype");
+ assert_equals(e.data.constructor, EvalError, "Checking constructor");
+ assert_equals(e.data.name, "EvalError", "Checking name");
+ assert_equals(e.data.message, "some message", "Checking message");
+ assert_equals(e.data.foo, undefined, "Checking custom property");
+ });
+ t.step(function() {
+ const error = EvalError("some message");
+ error.foo = "bar";
+ worker.postMessage(error);
+ });
+ },
+ function() {
+ var t = async_test("RangeError objects can be cloned");
+ t.id = 30;
+ worker.onmessage = t.step_func_done(function(e) {
+ assert_equals(Object.getPrototypeOf(e.data), RangeError.prototype, "Checking prototype");
+ assert_equals(e.data.constructor, RangeError, "Checking constructor");
+ assert_equals(e.data.name, "RangeError", "Checking name");
+ assert_equals(e.data.message, "some message", "Checking message");
+ assert_equals(e.data.foo, undefined, "Checking custom property");
+ });
+ t.step(function() {
+ const error = RangeError("some message");
+ error.foo = "bar";
+ worker.postMessage(error);
+ });
+ },
+ function() {
+ var t = async_test("ReferenceError objects can be cloned");
+ t.id = 31;
+ worker.onmessage = t.step_func_done(function(e) {
+ assert_equals(Object.getPrototypeOf(e.data), ReferenceError.prototype, "Checking prototype");
+ assert_equals(e.data.constructor, ReferenceError, "Checking constructor");
+ assert_equals(e.data.name, "ReferenceError", "Checking name");
+ assert_equals(e.data.message, "some message", "Checking message");
+ assert_equals(e.data.foo, undefined, "Checking custom property");
+ });
+ t.step(function() {
+ const error = ReferenceError("some message");
+ error.foo = "bar";
+ worker.postMessage(error);
+ });
+ },
+ function() {
+ var t = async_test("SyntaxError objects can be cloned");
+ t.id = 32;
+ worker.onmessage = t.step_func_done(function(e) {
+ assert_equals(Object.getPrototypeOf(e.data), SyntaxError.prototype, "Checking prototype");
+ assert_equals(e.data.constructor, SyntaxError, "Checking constructor");
+ assert_equals(e.data.name, "SyntaxError", "Checking name");
+ assert_equals(e.data.message, "some message", "Checking message");
+ assert_equals(e.data.foo, undefined, "Checking custom property");
+ });
+ t.step(function() {
+ const error = SyntaxError("some message");
+ error.foo = "bar";
+ worker.postMessage(error);
+ });
+ },
+ function() {
+ var t = async_test("TypeError objects can be cloned");
+ t.id = 33;
+ worker.onmessage = t.step_func_done(function(e) {
+ assert_equals(Object.getPrototypeOf(e.data), TypeError.prototype, "Checking prototype");
+ assert_equals(e.data.constructor, TypeError, "Checking constructor");
+ assert_equals(e.data.name, "TypeError", "Checking name");
+ assert_equals(e.data.message, "some message", "Checking message");
+ assert_equals(e.data.foo, undefined, "Checking custom property");
+ });
+ t.step(function() {
+ const error = TypeError("some message");
+ error.foo = "bar";
+ worker.postMessage(error);
+ });
+ },
+ function() {
+ var t = async_test("URIError objects can be cloned");
+ t.id = 34;
+ worker.onmessage = t.step_func_done(function(e) {
+ assert_equals(Object.getPrototypeOf(e.data), URIError.prototype, "Checking prototype");
+ assert_equals(e.data.constructor, URIError, "Checking constructor");
+ assert_equals(e.data.name, "URIError", "Checking name");
+ assert_equals(e.data.message, "some message", "Checking message");
+ assert_equals(e.data.foo, undefined, "Checking custom property");
+ });
+ t.step(function() {
+ const error = URIError("some message");
+ error.foo = "bar";
+ worker.postMessage(error);
+ });
+ },
+ function() {
+ var t = async_test("URIError objects from other realms are treated as URIError");
+ t.id = 35;
+ worker.onmessage = t.step_func_done(function(e) {
+ assert_equals(Object.getPrototypeOf(e.data), URIError.prototype, "Checking prototype");
+ assert_equals(e.data.constructor, URIError, "Checking constructor");
+ assert_equals(e.data.name, "URIError", "Checking name");
+ assert_equals(e.data.message, "some message", "Checking message");
+ assert_equals(e.data.foo, undefined, "Checking custom property");
+ });
+ t.step(function() {
+ const error = frames[0].URIError("some message");
+ assert_equals(Object.getPrototypeOf(error), frames[0].URIError.prototype, "Checking prototype before cloning");
+ assert_equals(error.constructor, frames[0].URIError, "Checking constructor before cloning");
+ assert_equals(error.name, "URIError", "Checking name before cloning");
+ error.foo = "bar";
+ worker.postMessage(error);
+ });
+ },
+ function() {
+ var t = async_test("Cloning a modified Error");
+ t.id = 36;
+ worker.onmessage = t.step_func_done(function(e) {
+ assert_equals(Object.getPrototypeOf(e.data), TypeError.prototype, "Checking prototype");
+ assert_equals(e.data.constructor, TypeError, "Checking constructor");
+ assert_equals(e.data.name, "TypeError", "Checking name");
+ assert_equals(e.data.message, "another message", "Checking message");
+ assert_equals(e.data.foo, undefined, "Checking custom property");
+ });
+ t.step(function() {
+ const error = URIError("some message");
+ Object.setPrototypeOf(error, SyntaxError.prototype);
+ error.message = {toString: () => "another message" }
+ error.constructor = RangeError;
+ error.name = "TypeError";
+ error.foo = "bar";
+ worker.postMessage(error);
+ });
+ },
+ function() {
+ var t = async_test("Error.message: getter is ignored when cloning");
+ t.id = 37;
+ worker.onmessage = t.step_func_done(function(e) {
+ assert_equals(Object.getPrototypeOf(e.data), Error.prototype, "Checking prototype");
+ assert_equals(e.data.constructor, Error, "Checking constructor");
+ assert_equals(e.data.name, "Error", "Checking name");
+ assert_false(e.data.hasOwnProperty("message"), "Checking message");
+ assert_equals(e.data.foo, undefined, "Checking custom property");
+ });
+ t.step(function() {
+ const error = Error();
+ Object.defineProperty(error, "message", { get: () => "hello" });
+ assert_equals(error.message, "hello", "Checking message on the source realm");
+ worker.postMessage(error);
+ });
+ },
+ function() {
+ var t = async_test("Error.message: undefined property is stringified");
+ t.id = 38;
+ worker.onmessage = t.step_func_done(function(e) {
+ assert_equals(Object.getPrototypeOf(e.data), Error.prototype, "Checking prototype");
+ assert_equals(e.data.constructor, Error, "Checking constructor");
+ assert_equals(e.data.name, "Error", "Checking name");
+ assert_equals(e.data.message, "undefined", "Checking message");
+ assert_equals(e.data.foo, undefined, "Checking custom property");
+ });
+ t.step(function() {
+ const error = Error();
+ error.message = undefined;
+ assert_equals(error.message, undefined, "Checking message on the source realm");
+ worker.postMessage(error);
+ });
+ },
+ function() {
+ var t = async_test("DOMException objects can be cloned");
+ t.id = 39;
+ worker.onmessage = t.step_func_done(function(e) {
+ assert_equals(Object.getPrototypeOf(e.data), DOMException.prototype, "Checking prototype");
+ assert_equals(e.data.constructor, DOMException, "Checking constructor");
+ assert_equals(e.data.name, "IndexSizeError", "Checking name");
+ assert_equals(e.data.message, "some message", "Checking message");
+ assert_equals(e.data.code, DOMException.INDEX_SIZE_ERR, "Checking code");
+ assert_equals(e.data.foo, undefined, "Checking custom property");
+ });
+ t.step(function() {
+ const error = new DOMException("some message", "IndexSizeError");
+ worker.postMessage(error);
+ });
+ },
+ function() {
+ var t = async_test("DOMException objects created by the UA can be cloned");
+ t.id = 40;
+ worker.onmessage = t.step_func_done(function(e) {
+ assert_equals(Object.getPrototypeOf(e.data), DOMException.prototype, "Checking prototype");
+ assert_equals(e.data.constructor, DOMException, "Checking constructor");
+ assert_equals(e.data.code, DOMException.DATA_CLONE_ERR, "Checking code");
+ assert_equals(e.data.name, "DataCloneError", "Checking name");
+ });
+ t.step(function() {
+ try {
+ worker.postMessage(window);
+ } catch (error) {
+ worker.postMessage(error);
+ return;
+ }
+ assert_unreached("Window must not be clonable");
+ });
+ },
+ ];
+ }, {explicit_done:true});
+
+ //Callback for result_callback
+ //queues the next test in the array testCollection
+ //serves to make test execution sequential from the async worker callbacks
+ //alternatively, we would have to create a worker for each test
+ function testFinished(test) {
+ if(test.id < testCollection.length - 1) {
+ //queue the function so that stack remains shallow
+ queue(testCollection[test.id+1]);
+ } else {
+ //when the last test has run, explicitly end test suite
+ done();
+ }
+ }
+ function queue(func) {
+ step_timeout(func, 10);
+ }
+
+ add_result_callback(testFinished);
+ //start the first test manually
+ queue(testCollection[0]);
+
+
+
+
+ </script>
+</body>
+</html>
diff --git a/testing/web-platform/tests/html/infrastructure/safe-passing-of-structured-data/transfer-errors.window.js b/testing/web-platform/tests/html/infrastructure/safe-passing-of-structured-data/transfer-errors.window.js
new file mode 100644
index 0000000000..b3ecd86b40
--- /dev/null
+++ b/testing/web-platform/tests/html/infrastructure/safe-passing-of-structured-data/transfer-errors.window.js
@@ -0,0 +1,47 @@
+function assert_transfer_error(transferList) {
+ assert_throws_dom("DataCloneError", () => self.postMessage({ get whatever() { throw new Error("You should not have gotten to this point") } }, "*", transferList));
+}
+
+test(() => {
+ [self, self.document, new Image()].forEach(val => {
+ assert_transfer_error([val]);
+ });
+}, "Cannot transfer all objects");
+
+function transfer_tests(name, create) {
+ promise_test(async () => {
+ const transferable = await create();
+ assert_transfer_error([transferable, transferable]);
+ }, `Cannot transfer the same ${name} twice`);
+
+ promise_test(async () => {
+ const transferable = await create();
+ self.postMessage(null, "*", [transferable]);
+ assert_throws_dom("DataCloneError", () => self.postMessage(null, "*", [transferable]));
+ }, `Serialize should make the ${name} detached, so it cannot be transferred again`);
+
+ promise_test(async () => {
+ const transferable = await create(),
+ customError = new Error("hi");
+ self.postMessage(null, "*", [transferable]);
+ assert_throws_exactly(customError, () => self.postMessage({ get whatever() { throw customError } }, "*", [transferable]));
+ }, `Serialize should throw before a detached ${name} is found`);
+
+ promise_test(async () => {
+ const transferable = await create();
+ let seen = false;
+ const message = {
+ get a() {
+ self.postMessage(null, '*', [transferable]);
+ seen = true;
+ }
+ };
+ assert_throws_dom("DataCloneError", () => self.postMessage(message, "*", [transferable]));
+ assert_true(seen);
+ }, `Cannot transfer ${name} detached while the message was serialized`);
+}
+
+transfer_tests("ArrayBuffer", () => new ArrayBuffer(1));
+transfer_tests("MessagePort", () => new MessageChannel().port1);
+transfer_tests("ImageBitmap", () => self.createImageBitmap(document.createElement("canvas")));
+transfer_tests("OffscreenCanvas", () => new OffscreenCanvas(1, 1));
diff --git a/testing/web-platform/tests/html/infrastructure/safe-passing-of-structured-data/window-postmessage.window.js b/testing/web-platform/tests/html/infrastructure/safe-passing-of-structured-data/window-postmessage.window.js
new file mode 100644
index 0000000000..2a46d790b8
--- /dev/null
+++ b/testing/web-platform/tests/html/infrastructure/safe-passing-of-structured-data/window-postmessage.window.js
@@ -0,0 +1,16 @@
+// META: script=/common/sab.js
+// META: script=/html/webappapis/structured-clone/structured-clone-battery-of-tests.js
+// META: script=/html/webappapis/structured-clone/structured-clone-battery-of-tests-with-transferables.js
+// META: script=/html/webappapis/structured-clone/structured-clone-battery-of-tests-harness.js
+
+runStructuredCloneBatteryOfTests({
+ structuredClone(data, transfer) {
+ return new Promise(resolve => {
+ window.addEventListener('message', function f(ev) {
+ window.removeEventListener('message', f);
+ resolve(ev.data.data);
+ });
+ window.postMessage({data, transfer}, "/", transfer);
+ });
+ }
+});