fetch-rewrite-worker.js (6193B)
1 // By default, this worker responds to fetch events with 2 // respondWith(fetch(request)). Additionally, if the request has a &url 3 // parameter, it fetches the provided URL instead. Because it forwards fetch 4 // events to this other URL, it is called the "fetch rewrite" worker. 5 // 6 // The worker also looks for other params on the request to do more custom 7 // behavior, like falling back to network or throwing an error. 8 9 function get_query_params(url) { 10 var search = (new URL(url)).search; 11 if (!search) { 12 return {}; 13 } 14 var ret = {}; 15 var params = search.substring(1).split('&'); 16 params.forEach(function(param) { 17 var element = param.split('='); 18 ret[decodeURIComponent(element[0])] = decodeURIComponent(element[1]); 19 }); 20 return ret; 21 } 22 23 function get_request_init(base, params) { 24 var init = {}; 25 init['method'] = params['method'] || base['method']; 26 init['mode'] = params['mode'] || base['mode']; 27 if (init['mode'] == 'navigate') { 28 init['mode'] = 'same-origin'; 29 } 30 init['credentials'] = params['credentials'] || base['credentials']; 31 init['redirect'] = params['redirect-mode'] || base['redirect']; 32 return init; 33 } 34 35 self.addEventListener('fetch', function(event) { 36 var params = get_query_params(event.request.url); 37 var init = get_request_init(event.request, params); 38 var url = params['url']; 39 if (params['ignore']) { 40 return; 41 } 42 if (params['throw']) { 43 throw new Error('boom'); 44 } 45 if (params['reject']) { 46 event.respondWith(new Promise(function(resolve, reject) { 47 reject(); 48 })); 49 return; 50 } 51 if (params['resolve-null']) { 52 event.respondWith(new Promise(function(resolve) { 53 resolve(null); 54 })); 55 return; 56 } 57 if (params['generate-png']) { 58 var binary = atob( 59 'iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAAAXNSR0IArs4c6QAAAA' + 60 'RnQU1BAACxjwv8YQUAAAAJcEhZcwAADsQAAA7EAZUrDhsAAAAhSURBVDhPY3wro/Kf' + 61 'gQLABKXJBqMGjBoAAqMGDLwBDAwAEsoCTFWunmQAAAAASUVORK5CYII='); 62 var array = new Uint8Array(binary.length); 63 for(var i = 0; i < binary.length; i++) { 64 array[i] = binary.charCodeAt(i); 65 }; 66 event.respondWith(new Response(new Blob([array], {type: 'image/png'}))); 67 return; 68 } 69 if (params['check-ua-header']) { 70 var ua = event.request.headers.get('User-Agent'); 71 if (ua) { 72 // We have a user agent! 73 event.respondWith(new Response(new Blob([ua]))); 74 } else { 75 // We don't have a user-agent! 76 event.respondWith(new Response(new Blob(["NO_UA"]))); 77 } 78 return; 79 } 80 if (params['check-accept-header']) { 81 var accept = event.request.headers.get('Accept'); 82 if (accept) { 83 event.respondWith(new Response(accept)); 84 } else { 85 event.respondWith(new Response('NO_ACCEPT')); 86 } 87 return; 88 } 89 event.respondWith(new Promise(function(resolve, reject) { 90 var request = event.request; 91 if (url) { 92 request = new Request(url, init); 93 } else if (params['change-request']) { 94 request = new Request(request, init); 95 } 96 const response_promise = params['navpreload'] ? event.preloadResponse 97 : fetch(request); 98 response_promise.then(function(response) { 99 var expectedType = params['expected_type']; 100 if (expectedType && response.type !== expectedType) { 101 // Resolve a JSON object with a failure instead of rejecting 102 // in order to distinguish this from a NetworkError, which 103 // may be expected even if the type is correct. 104 resolve(new Response(JSON.stringify({ 105 result: 'failure', 106 detail: 'got ' + response.type + ' Response.type instead of ' + 107 expectedType 108 }))); 109 } 110 111 var expectedRedirected = params['expected_redirected']; 112 if (typeof expectedRedirected !== 'undefined') { 113 var expected_redirected = (expectedRedirected === 'true'); 114 if(response.redirected !== expected_redirected) { 115 // This is simply determining how to pass an error to the outer 116 // test case(fetch-request-redirect.https.html). 117 var execptedResolves = params['expected_resolves']; 118 if (execptedResolves === 'true') { 119 // Reject a JSON object with a failure since promise is expected 120 // to be resolved. 121 reject(new Response(JSON.stringify({ 122 result: 'failure', 123 detail: 'got '+ response.redirected + 124 ' Response.redirected instead of ' + 125 expectedRedirected 126 }))); 127 } else { 128 // Resolve a JSON object with a failure since promise is 129 // expected to be rejected. 130 resolve(new Response(JSON.stringify({ 131 result: 'failure', 132 detail: 'got '+ response.redirected + 133 ' Response.redirected instead of ' + 134 expectedRedirected 135 }))); 136 } 137 } 138 } 139 140 if (params['clone']) { 141 response = response.clone(); 142 } 143 144 // |cache| means to bounce responses through Cache Storage and back. 145 if (params['cache']) { 146 var cacheName = "cached-fetches-" + performance.now() + "-" + 147 event.request.url; 148 var cache; 149 var cachedResponse; 150 return self.caches.open(cacheName).then(function(opened) { 151 cache = opened; 152 return cache.put(request, response); 153 }).then(function() { 154 return cache.match(request); 155 }).then(function(cached) { 156 cachedResponse = cached; 157 return self.caches.delete(cacheName); 158 }).then(function() { 159 resolve(cachedResponse); 160 }); 161 } else { 162 resolve(response); 163 } 164 }, reject) 165 })); 166 });