Skip to content

Commit

Permalink
Refine crossOriginIsolated implementation for workers (#25748)
Browse files Browse the repository at this point in the history
- Fix WindowOrWorketGlobalScope.crossOriginIsolated behavior for
   workers.
   - For SharedWorkers and ServiceWorkers it always return false. See
     https://crbug.com/1131403 and https://crbug.com/1131404.
 - Rename ExecutionContext::IsCrossOriginIsolated to
   CrossOriginCapability. This is aligned with
   https://html.spec.whatwg.org/C/#concept-settings-object-cross-origin-isolated-capability.
 - Fix wpt/html/infrastructure/safe-passing-of-structured-data/shared-array-buffers/blob-data.https.html.
   I originally planned to do that in
   #24600 but I couldn't
   do that due to some flakiness.
 - Add more tests for workers in
   wpt/html/cross-origin-embedder-policy/cross-origin-isolated-permission.https.html.

Bug: 1115379, 1018680, 1131403, 1131404
Change-Id: I2afcb01403f67a11fd06aefde1238aba16b68f36
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/2416428
Commit-Queue: Yutaka Hirano <yhirano@chromium.org>
Reviewed-by: Domenic Denicola <domenic@chromium.org>
Reviewed-by: Robert Flack <flackr@chromium.org>
Reviewed-by: Hiroki Nakagawa <nhiroki@chromium.org>
Cr-Commit-Position: refs/heads/master@{#810130}

Co-authored-by: Yutaka Hirano <yhirano@chromium.org>
  • Loading branch information
chromium-wpt-export-bot and yutakahirano authored Sep 24, 2020
1 parent a3921bb commit ce281cc
Show file tree
Hide file tree
Showing 3 changed files with 154 additions and 25 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -3,32 +3,36 @@
<script src=/resources/testharness.js></script>
<script src=/resources/testharnessreport.js></script>
<script src="/common/get-host-info.sub.js"></script>
<script src="/common/utils.js"></script>
<script src="/service-workers/service-worker/resources/test-helpers.sub.js"></script>
<body>
<script>
const {ORIGIN, HTTPS_REMOTE_ORIGIN} = get_host_info();
const PATH =
const FRAME_PATH =
new URL('resources/cross-origin-isolated-frame.html', location).pathname;
const WORKER_URL =
new URL('resources/cross-origin-isolated-worker.js', location).href;
const PIPE =
'?pipe=' +
'|header(cross-origin-embedder-policy,require-corp)' +
'|header(cross-origin-resource-policy,cross-origin)';

async function getCrossOriginIsolatedFor(t, origin, value) {
async function getCrossOriginIsolatedForFrame(t, origin, value) {
const parentFrame = document.createElement('iframe');
t.add_cleanup(() => parentFrame.remove());
let pipe = PIPE;
if (value !== undefined) {
pipe += `|header(permissions-policy,cross-origin-isolated=${value})`;
}
parentFrame.src = `${PATH}${pipe}`;
parentFrame.src = `${FRAME_PATH}${pipe}`;
document.body.append(parentFrame);

await new Promise((resolve) => {
parentFrame.addEventListener('load', resolve);
});

const frame = parentFrame.contentDocument.createElement('iframe');
frame.src = `${origin}${PATH}${PIPE}`;
frame.src = `${origin}${FRAME_PATH}${PIPE}`;
parentFrame.contentDocument.body.append(frame);
frame.addEventListener('error', t.unreached_func('frame.error'));
await new Promise((resolve) => {
Expand All @@ -37,35 +41,149 @@

const mc = new MessageChannel();
frame.contentWindow.postMessage({port: mc.port2}, '*', [mc.port2]);
return (await new Promise(r => mc.port1.onmessage = r)).data;
}

async function getCrossOriginIsolatedForDedicatedWorker(t, scheme, value) {
const frame = document.createElement('iframe');
t.add_cleanup(() => frame.remove());
let pipe = PIPE;
if (value !== undefined) {
pipe += `|header(permissions-policy,cross-origin-isolated=${value})`
}
frame.src = `${FRAME_PATH}${pipe}`;
document.body.append(frame);

const e = await new Promise((resolve) => {
mc.port1.onmessage = resolve;
frame.addEventListener('error', t.unreached_func('frame.error'));
await new Promise((resolve) => {
frame.addEventListener('load', resolve);
});
assert_equals(typeof(e.data), 'boolean');
return e.data;

let workerURL;
if (scheme === 'https') {
workerURL = `${WORKER_URL}${PIPE}`;
} else if (scheme === 'data') {
const res = await fetch(WORKER_URL);
const text = await res.text();

workerURL = `data:application/javascript;base64,${btoa(text)}`;
} else if (scheme === 'blob') {
const res = await fetch(WORKER_URL);
const blob = await res.blob();

workerURL = URL.createObjectURL(blob);
} else {
assert_unreached('scheme should be one of "https", "data" and "blob".');
}

const worker = new frame.contentWindow.Worker(workerURL);
const mc = new MessageChannel();
worker.postMessage({port: mc.port2}, [mc.port2]);
return (await new Promise(r => mc.port1.onmessage = r)).data;
}

async function getCrossOriginIsolatedForSharedWorker(t, withCoopCoep) {
const workerURL = `${WORKER_URL}${withCoopCoep ? PIPE : ''}`;
const worker = new SharedWorker(workerURL);
worker.addEventListener('error', t.unreached_func('worker.error'));

const mc = new MessageChannel();
worker.port.postMessage({port: mc.port2}, [mc.port2]);
return (await new Promise(r => mc.port1.onmessage = r)).data;
}

async function getCrossOriginIsolatedForServiceWorker(t, withCoopCoep) {
// As we don't want the service worker to control any page, generate a
// one-time scope.
const SCOPE = new URL(`resources/${token()}.html`, location).pathname;
const workerURL = `${WORKER_URL}${withCoopCoep ? PIPE : ''}`;
const reg =
await service_worker_unregister_and_register(t, workerURL, SCOPE);
t.add_cleanup(() => reg.unregister());
const worker = reg.installing;

const mc = new MessageChannel();
worker.postMessage({port: mc.port2}, [mc.port2]);
return (await new Promise(r => mc.port1.onmessage = r)).data;
}

function generateFrameTest(origin, value, expectation) {
async function run(t) {
assert_equals(
await getCrossOriginIsolatedForFrame(t, origin, value), expectation);
}
// We use async_test, not promise_test here to run tests in parallel.
async_test((t) => {
run(t).then(() => t.done(), (e) => t.step(() => {throw e;}));
}, `frame: origin = ${origin}, value = ${value}`);
}

function generateTest(origin, value, expectation) {
function generateDedicatedWorkerTest(scheme, value, expectation) {
async function run(t) {
assert_equals(
await getCrossOriginIsolatedFor(t, origin, value), expectation);
await getCrossOriginIsolatedForDedicatedWorker(t, scheme, value),
expectation);
}
// We use async_test, not promise_test here to run tests in parallel.
async_test((t) => {
run(t).then(() => t.done(), (e) => t.step(() => {throw e;}));
}, `origin = ${origin}, value = ${value}`);
}, `dedicated worker: scheme = ${scheme}, value = ${value}`);
}

generateTest(ORIGIN, undefined, true);
generateTest(ORIGIN, '*', true);
generateTest(ORIGIN, "self", true);
function generateSharedWorkerTest(withCoopCoep) {
async function run(t) {
assert_equals(
await getCrossOriginIsolatedForSharedWorker(t, withCoopCoep),
withCoopCoep);
}
// We use async_test, not promise_test here to run tests in parallel.
async_test((t) => {
run(t).then(() => t.done(), (e) => t.step(() => {throw e;}));
}, `shared worker: withCoopCoep = ${withCoopCoep}`);
}

function generateServiceWorkerTest(withCoopCoep) {
// Here we use promise_test as we want to use a cleanup callback that returns
// a promise.
promise_test(async (t) => {
assert_equals(
await getCrossOriginIsolatedForServiceWorker(t, withCoopCoep),
withCoopCoep);
}, `service worker: withCoopCoep = ${withCoopCoep}`);
}

generateFrameTest(ORIGIN, undefined, true);
generateFrameTest(ORIGIN, '*', true);
generateFrameTest(ORIGIN, 'self', true);
// We need the backslash to escape the close parenthesis in a wpt pipe.
generateTest(ORIGIN, "(\\)", false);
generateTest(HTTPS_REMOTE_ORIGIN, undefined, false);
generateTest(HTTPS_REMOTE_ORIGIN, '*', true);
generateTest(HTTPS_REMOTE_ORIGIN, "self", false);
generateFrameTest(ORIGIN, '(\\)', false);
generateFrameTest(HTTPS_REMOTE_ORIGIN, undefined, false);
generateFrameTest(HTTPS_REMOTE_ORIGIN, '*', true);
generateFrameTest(HTTPS_REMOTE_ORIGIN, 'self', false);
// We need the backslash to escape the close parenthesis in a wpt pipe.
generateFrameTest(HTTPS_REMOTE_ORIGIN, '(\\)', false);

generateDedicatedWorkerTest('https', undefined, true);
generateDedicatedWorkerTest('https', '*', true);
generateDedicatedWorkerTest('https', 'self', true);
// We need the backslash to escape the close parenthesis in a wpt pipe.
generateDedicatedWorkerTest('https', '(\\)', false);
generateDedicatedWorkerTest('data', undefined, false);
generateDedicatedWorkerTest('data', '*', false);
generateDedicatedWorkerTest('data', 'self', false);
// We need the backslash to escape the close parenthesis in a wpt pipe.
generateDedicatedWorkerTest('data', '(\\)', false);
generateDedicatedWorkerTest('blob', undefined, true);
generateDedicatedWorkerTest('blob', '*', true);
generateDedicatedWorkerTest('blob', 'self', true);
// We need the backslash to escape the close parenthesis in a wpt pipe.
generateTest(HTTPS_REMOTE_ORIGIN, "(\\)", false);
generateDedicatedWorkerTest('blob', '(\\)', false);

generateSharedWorkerTest(false);
generateSharedWorkerTest(true);

generateServiceWorkerTest(false);
generateServiceWorkerTest(true);
</script>
</body>
</html>
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
// For DedicatedWorker and ServiceWorker
self.addEventListener('message', (e) => {
e.data.port.postMessage(self.crossOriginIsolated);
});

// For SharedWorker
self.addEventListener('connect', (e) => {
e.ports[0].onmessage = (ev) => {
ev.data.port.postMessage(self.crossOriginIsolated);
};
});
Original file line number Diff line number Diff line change
Expand Up @@ -50,14 +50,14 @@
`;
}

function propertyTests(name) {
function propertyTests(name, crossOriginIsolated) {
return `
test(() => {
assert_equals(self.origin, self.location.origin);
}, "${name}: self.origin");
test(() => {
assert_true(self.crossOriginIsolated);
assert_equals(self.crossOriginIsolated, ${crossOriginIsolated});
}, "${name}: self.crossOriginIsolated");
test(() => {
Expand All @@ -74,7 +74,7 @@
${blobWorkerIncrementerTest("blob worker", self.location.origin)}
${propertyTests("blob worker")}
${propertyTests("blob worker", true)}
done();
`;
Expand All @@ -90,7 +90,7 @@
${blobWorkerIncrementerTest("blob frame", self.location.origin)}
${propertyTests("blob frame")}
${propertyTests("blob frame", true)}
<\/script>
`;

Expand All @@ -106,7 +106,7 @@
${blobWorkerIncrementerTest("data worker")}
${propertyTests("data worker")}
${propertyTests("data worker", false)}
done();
`;
Expand All @@ -121,7 +121,7 @@
${blobWorkerIncrementerTest("data frame")}
${propertyTests("data frame")}
${propertyTests("data frame", true)}
<\/script>
`;

Expand Down

0 comments on commit ce281cc

Please sign in to comment.