fetch-event-respond-with-readable-stream-worker.js (1939B)
1 'use strict'; 2 importScripts("/resources/testharness.js"); 3 4 const map = new Map(); 5 6 self.addEventListener('fetch', event => { 7 const url = new URL(event.request.url); 8 if (!url.searchParams.has('stream')) return; 9 10 if (url.searchParams.has('observe-cancel')) { 11 const id = url.searchParams.get('id'); 12 if (id === undefined) { 13 event.respondWith(new Error('error')); 14 return; 15 } 16 event.waitUntil(new Promise(resolve => { 17 map.set(id, {label: 'pending', resolve}); 18 })); 19 20 const stream = new ReadableStream({ 21 pull(c) { 22 if (url.searchParams.get('enqueue') === 'true') { 23 url.searchParams.delete('enqueue'); 24 c.enqueue(new Uint8Array([65])); 25 } 26 }, 27 cancel() { 28 map.get(id).label = 'cancelled'; 29 } 30 }); 31 event.respondWith(new Response(stream)); 32 return; 33 } 34 35 if (url.searchParams.has('query-cancel')) { 36 const id = url.searchParams.get('id'); 37 if (id === undefined) { 38 event.respondWith(new Error('error')); 39 return; 40 } 41 const entry = map.get(id); 42 if (entry === undefined) { 43 event.respondWith(new Error('not found')); 44 return; 45 } 46 map.delete(id); 47 entry.resolve(); 48 event.respondWith(new Response(entry.label)); 49 return; 50 } 51 52 if (url.searchParams.has('use-fetch-stream')) { 53 event.respondWith(async function() { 54 const response = await fetch('pass.txt'); 55 return new Response(response.body); 56 }()); 57 return; 58 } 59 60 const delayEnqueue = url.searchParams.has('delay'); 61 62 const stream = new ReadableStream({ 63 start(controller) { 64 const encoder = new TextEncoder(); 65 66 const populate = () => { 67 controller.enqueue(encoder.encode('PASS')); 68 controller.close(); 69 } 70 71 if (delayEnqueue) { 72 step_timeout(populate, 16); 73 } 74 else { 75 populate(); 76 } 77 } 78 }); 79 80 event.respondWith(new Response(stream)); 81 });