1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244
|
<!DOCTYPE html>
<title>Service Worker: intercepting Worker script loads</title>
<meta name="timeout" content="long">
<script src="/resources/testharness.js"></script>
<script src="/resources/testharnessreport.js"></script>
<script src="resources/test-helpers.sub.js"></script>
<body>
<script>
// ========== Worker main resource interception tests ==========
async function setup_service_worker(t, service_worker_url, scope) {
const r = await service_worker_unregister_and_register(
t, service_worker_url, scope);
t.add_cleanup(() => service_worker_unregister(t, scope));
await wait_for_state(t, r.installing, 'activated');
return r.active;
}
promise_test(async t => {
const worker_url = 'resources/sample-synthesized-worker.js?dedicated';
const service_worker_url = 'resources/sample-worker-interceptor.js';
const scope = worker_url;
const serviceWorker = await setup_service_worker(t, service_worker_url, scope);
const channels = new MessageChannel();
serviceWorker.postMessage({port: channels.port1}, [channels.port1]);
const clientId = await new Promise(resolve => channels.port2.onmessage = (e) => resolve(e.data.id));
const resultPromise = new Promise(resolve => channels.port2.onmessage = (e) => resolve(e.data));
const w = new Worker(worker_url);
const data = await new Promise((resolve, reject) => {
w.onmessage = e => resolve(e.data);
w.onerror = e => reject(e.message);
});
assert_equals(data, 'worker loading intercepted by service worker');
const results = await resultPromise;
assert_equals(results.clientId, clientId);
assert_true(!!results.resultingClientId.length);
channels.port2.postMessage("done");
}, `Verify a dedicated worker script request gets correct client Ids`);
promise_test(async t => {
const worker_url = 'resources/sample-synthesized-worker.js?dedicated';
const service_worker_url = 'resources/sample-worker-interceptor.js';
const scope = worker_url;
await setup_service_worker(t, service_worker_url, scope);
const w = new Worker(worker_url);
const data = await new Promise((resolve, reject) => {
w.onmessage = e => resolve(e.data);
w.onerror = e => reject(e.message);
});
assert_equals(data, 'worker loading intercepted by service worker');
}, `Verify a dedicated worker script request issued from a uncontrolled ` +
`document is intercepted by worker's own service worker.`);
promise_test(async t => {
const frame_url = 'resources/create-out-of-scope-worker.html';
const service_worker_url = 'resources/sample-worker-interceptor.js';
const scope = frame_url;
const registration = await service_worker_unregister_and_register(
t, service_worker_url, scope);
t.add_cleanup(() => service_worker_unregister(t, scope));
await wait_for_state(t, registration.installing, 'activated');
const frame = await with_iframe(frame_url);
t.add_cleanup(_ => frame.remove());
assert_equals(
frame.contentWindow.navigator.serviceWorker.controller.scriptURL,
get_newest_worker(registration).scriptURL,
'the frame should be controlled by a service worker'
);
const result = await frame.contentWindow.getWorkerPromise();
assert_equals(result,
'worker loading was not intercepted by service worker');
}, `Verify an out-of-scope dedicated worker script request issued from a ` +
`controlled document should not be intercepted by document's service ` +
`worker.`);
promise_test(async t => {
const worker_url = 'resources/sample-synthesized-worker.js?shared';
const service_worker_url = 'resources/sample-worker-interceptor.js';
const scope = worker_url;
await setup_service_worker(t, service_worker_url, scope);
const w = new SharedWorker(worker_url);
const data = await new Promise((resolve, reject) => {
w.port.onmessage = e => resolve(e.data);
w.onerror = e => reject(e.message);
});
assert_equals(data, 'worker loading intercepted by service worker');
}, `Verify a shared worker script request issued from a uncontrolled ` +
`document is intercepted by worker's own service worker.`);
promise_test(async t => {
const worker_url = 'resources/sample-same-origin-worker.js?dedicated';
const service_worker_url = 'resources/sample-worker-interceptor.js';
const scope = worker_url;
await setup_service_worker(t, service_worker_url, scope);
const w = new Worker(worker_url);
const data = await new Promise((resolve, reject) => {
w.onmessage = e => resolve(e.data);
w.onerror = e => reject(e.message);
});
assert_equals(data, 'dedicated worker script loaded');
}, 'Verify a same-origin worker script served by a service worker succeeds ' +
'in starting a dedicated worker.');
promise_test(async t => {
const worker_url = 'resources/sample-same-origin-worker.js?shared';
const service_worker_url = 'resources/sample-worker-interceptor.js';
const scope = worker_url;
await setup_service_worker(t, service_worker_url, scope);
const w = new SharedWorker(worker_url);
const data = await new Promise((resolve, reject) => {
w.port.onmessage = e => resolve(e.data);
w.onerror = e => reject(e.message);
});
assert_equals(data, 'shared worker script loaded');
}, 'Verify a same-origin worker script served by a service worker succeeds ' +
'in starting a shared worker.');
promise_test(async t => {
const worker_url = 'resources/sample-cors-worker.js?dedicated';
const service_worker_url = 'resources/sample-worker-interceptor.js';
const scope = worker_url;
await setup_service_worker(t, service_worker_url, scope);
const w = new Worker(worker_url);
const watcher = new EventWatcher(t, w, ['message', 'error']);
await watcher.wait_for('error');
}, 'Verify a cors worker script served by a service worker fails dedicated ' +
'worker start.');
promise_test(async t => {
const worker_url = 'resources/sample-cors-worker.js?shared';
const service_worker_url = 'resources/sample-worker-interceptor.js';
const scope = worker_url;
await setup_service_worker(t, service_worker_url, scope);
const w = new SharedWorker(worker_url);
const watcher = new EventWatcher(t, w, ['message', 'error']);
await watcher.wait_for('error');
}, 'Verify a cors worker script served by a service worker fails shared ' +
'worker start.');
promise_test(async t => {
const worker_url = 'resources/sample-no-cors-worker.js?dedicated';
const service_worker_url = 'resources/sample-worker-interceptor.js';
const scope = worker_url;
await setup_service_worker(t, service_worker_url, scope);
const w = new Worker(worker_url);
const watcher = new EventWatcher(t, w, ['message', 'error']);
await watcher.wait_for('error');
}, 'Verify a no-cors cross-origin worker script served by a service worker ' +
'fails dedicated worker start.');
promise_test(async t => {
const worker_url = 'resources/sample-no-cors-worker.js?shared';
const service_worker_url = 'resources/sample-worker-interceptor.js';
const scope = worker_url;
await setup_service_worker(t, service_worker_url, scope);
const w = new SharedWorker(worker_url);
const watcher = new EventWatcher(t, w, ['message', 'error']);
await watcher.wait_for('error');
}, 'Verify a no-cors cross-origin worker script served by a service worker ' +
'fails shared worker start.');
// ========== Worker subresource interception tests ==========
const scope_for_subresource_interception = 'resources/load_worker.js';
promise_test(async t => {
const service_worker_url = 'resources/worker-load-interceptor.js';
const r = await service_worker_unregister_and_register(
t, service_worker_url, scope_for_subresource_interception);
await wait_for_state(t, r.installing, 'activated');
}, 'Register a service worker for worker subresource interception tests.');
// Do not call this function multiple times without waiting for the promise
// resolution because this sets new event handlers on |worker|.
// TODO(nhiroki): To isolate multiple function calls, use MessagePort instead of
// worker's onmessage event handler.
async function request_on_worker(worker, resource_type) {
const data = await new Promise((resolve, reject) => {
if (worker instanceof Worker) {
worker.onmessage = e => resolve(e.data);
worker.onerror = e => reject(e);
worker.postMessage(resource_type);
} else if (worker instanceof SharedWorker) {
worker.port.onmessage = e => resolve(e.data);
worker.onerror = e => reject(e);
worker.port.postMessage(resource_type);
} else {
reject('Unexpected worker type!');
}
});
assert_equals(data, 'This load was successfully intercepted.');
}
async function subresource_test(worker) {
await request_on_worker(worker, 'xhr');
await request_on_worker(worker, 'fetch');
await request_on_worker(worker, 'importScripts');
}
promise_test(async t => {
await subresource_test(new Worker('resources/load_worker.js'));
}, 'Requests on a dedicated worker controlled by a service worker.');
promise_test(async t => {
await subresource_test(new SharedWorker('resources/load_worker.js'));
}, 'Requests on a shared worker controlled by a service worker.');
promise_test(async t => {
await subresource_test(new Worker('resources/nested_load_worker.js'));
}, 'Requests on a dedicated worker nested in a dedicated worker and ' +
'controlled by a service worker');
promise_test(async t => {
await subresource_test(new SharedWorker('resources/nested_load_worker.js'));
}, 'Requests on a dedicated worker nested in a shared worker and controlled ' +
'by a service worker');
promise_test(async t => {
await service_worker_unregister(t, scope_for_subresource_interception);
}, 'Unregister a service worker for subresource interception tests.');
</script>
</body>
|