local-url-inherit-controller-frame.html (4224B)
1 <!DOCTYPE html> 2 <html> 3 <script> 4 5 const fetchURL = new URL('sample.js', window.location).href; 6 7 const frameControllerText = 8 `<script> 9 let t = null; 10 try { 11 if (navigator.serviceWorker.controller) { 12 t = navigator.serviceWorker.controller.scriptURL; 13 } 14 } catch (e) { 15 t = e.message; 16 } finally { 17 parent.postMessage({ data: t }, '*'); 18 } 19 </` + `script>`; 20 21 const frameFetchText = 22 `<script> 23 fetch('${fetchURL}', { mode: 'no-cors' }).then(response => { 24 return response.text(); 25 }).then(text => { 26 parent.postMessage({ data: text }, '*'); 27 }).catch(e => { 28 parent.postMessage({ data: e.message }, '*'); 29 }); 30 </` + `script>`; 31 32 const workerControllerText = 33 `let t = navigator.serviceWorker.controller 34 ? navigator.serviceWorker.controller.scriptURL 35 : null; 36 self.postMessage(t);`; 37 38 const workerFetchText = 39 `fetch('${fetchURL}', { mode: 'no-cors' }).then(response => { 40 return response.text(); 41 }).then(text => { 42 self.postMessage(text); 43 }).catch(e => { 44 self.postMessage(e.message); 45 });`; 46 47 const sharedWorkerControllerText = 48 `const ports = []; 49 self.onconnect = evt => { 50 const port = evt.ports[0]; 51 ports.push(port); 52 const t = navigator.serviceWorker.controller 53 ? navigator.serviceWorker.controller.scriptURL 54 : null; 55 port.postMessage(t); 56 }; 57 self.onerror = msg => { 58 ports.forEach(port => {port.postMessage(msg);}); 59 };`; 60 61 const sharedWorkerFetchText = 62 `self.onconnect = evt => { 63 const port = evt.ports[0]; 64 fetch('${fetchURL}', { mode: 'no-cors' }).then(response => { 65 return response.text(); 66 }).then(text => { 67 port.postMessage(text); 68 }).catch(e => { 69 port.postMessage(e.message); 70 }); 71 };`; 72 73 function getChildText(opts) { 74 if (opts.child === 'iframe') { 75 if (opts.check === 'controller') { 76 return frameControllerText; 77 } 78 79 if (opts.check === 'fetch') { 80 return frameFetchText; 81 } 82 83 throw('unexpected feature to check: ' + opts.check); 84 } 85 86 if (opts.child === 'worker') { 87 if (opts.check === 'controller') { 88 return workerControllerText; 89 } 90 91 if (opts.check === 'fetch') { 92 return workerFetchText; 93 } 94 95 throw('unexpected feature to check: ' + opts.check); 96 } 97 98 if (opts.child === 'sharedworker') { 99 if (opts.check === 'controller') { 100 return sharedWorkerControllerText; 101 } 102 103 if (opts.check === 'fetch') { 104 return sharedWorkerFetchText; 105 } 106 107 throw('unexpected feature to check: ' + opts.check); 108 } 109 110 throw('unexpected child type ' + opts.child); 111 } 112 113 function makeURL(opts) { 114 let mimetype = opts.child === 'iframe' ? 'text/html' 115 : 'text/javascript'; 116 117 if (opts.scheme === 'blob') { 118 let blob = new Blob([getChildText(opts)], { type: mimetype }); 119 return URL.createObjectURL(blob); 120 } 121 122 if (opts.scheme === 'data') { 123 return `data:${mimetype},${getChildText(opts)}`; 124 } 125 126 throw(`unexpected URL scheme ${opts.scheme}`); 127 } 128 129 function testWorkerChild(url) { 130 let w = new Worker(url); 131 return new Promise((resolve, reject) => { 132 w.onmessage = resolve; 133 w.onerror = evt => { 134 reject(evt.message); 135 } 136 }); 137 } 138 139 function testSharedWorkerChild(url) { 140 let w = new SharedWorker(url); 141 return new Promise((resolve, reject) => { 142 w.port.onmessage = m => { 143 // (null is a valid value when the SharedWorker is not controlled) 144 if (m.data?.includes("Error")) { 145 reject(m.data); 146 return; 147 } 148 resolve(m); 149 } 150 w.onerror = evt => { 151 reject(evt.message); 152 } 153 }); 154 } 155 156 function testIframeChild(url) { 157 let frame = document.createElement('iframe'); 158 frame.src = url; 159 document.body.appendChild(frame); 160 161 return new Promise(resolve => { 162 addEventListener('message', evt => { 163 resolve(evt.data); 164 }, { once: true }); 165 }); 166 } 167 168 function testURL(opts, url) { 169 if (opts.child === 'worker') { 170 return testWorkerChild(url); 171 } 172 173 if (opts.child === 'sharedworker') { 174 return testSharedWorkerChild(url); 175 } 176 177 if (opts.child === 'iframe') { 178 return testIframeChild(url); 179 } 180 181 throw(`unexpected child type ${opts.child}`); 182 } 183 184 function checkChildController(opts) { 185 let url = makeURL(opts); 186 return testURL(opts, url); 187 } 188 </script> 189 </html>