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