stalling-service-worker.js (1693B)
1 async function post_message_to_client(role, message, ports) { 2 (await clients.matchAll()).forEach(client => { 3 if (new URL(client.url).searchParams.get('role') === role) { 4 client.postMessage(message, ports); 5 } 6 }); 7 } 8 9 async function post_message_to_child(message, ports) { 10 await post_message_to_client('child', message, ports); 11 } 12 13 function ping_message(data) { 14 return { type: 'ping', data }; 15 } 16 17 self.onmessage = event => { 18 const message = ping_message(event.data); 19 post_message_to_child(message); 20 post_message_to_parent(message); 21 } 22 23 async function post_message_to_parent(message, ports) { 24 await post_message_to_client('parent', message, ports); 25 } 26 27 function fetch_message(key) { 28 return { type: 'fetch', key }; 29 } 30 31 // Send a message to the parent along with a MessagePort to respond 32 // with. 33 function report_fetch_request(key) { 34 const channel = new MessageChannel(); 35 const reply = new Promise(resolve => { 36 channel.port1.onmessage = resolve; 37 }).then(event => event.data); 38 return post_message_to_parent(fetch_message(key), [channel.port2]).then(() => reply); 39 } 40 41 function respond_with_script(script) { 42 return new Response(new Blob(script, { type: 'text/javascript' })); 43 } 44 45 // Whenever a controlled document requests a URL with a 'key' search 46 // parameter we report the request to the parent frame and wait for 47 // a response. The content of the response is then used to respond to 48 // the fetch request. 49 addEventListener('fetch', event => { 50 let key = new URL(event.request.url).searchParams.get('key'); 51 if (key) { 52 event.respondWith(report_fetch_request(key).then(respond_with_script)); 53 } 54 });