// By default, this worker responds to fetch events with // respondWith(fetch(request)). Additionally, if the request has a &url // parameter, it fetches the provided URL instead. Because it forwards fetch // events to this other URL, it is called the "fetch rewrite" worker. // // The worker also looks for other params on the request to do more custom // behavior, like falling back to network or throwing an error. function get_query_params(url) { var search = (new URL(url)).search; if (!search) { return {}; } var ret = {}; var params = search.substring(1).split('&'); params.forEach(function(param) { var element = param.split('='); ret[decodeURIComponent(element[0])] = decodeURIComponent(element[1]); }); return ret; } function get_request_init(base, params) { var init = {}; init['method'] = params['method'] || base['method']; init['mode'] = params['mode'] || base['mode']; if (init['mode'] == 'navigate') { init['mode'] = 'same-origin'; } init['credentials'] = params['credentials'] || base['credentials']; init['redirect'] = params['redirect-mode'] || base['redirect']; return init; } self.addEventListener('fetch', function(event) { var params = get_query_params(event.request.url); var init = get_request_init(event.request, params); var url = params['url']; if (params['ignore']) { return; } if (params['throw']) { throw new Error('boom'); } if (params['reject']) { event.respondWith(new Promise(function(resolve, reject) { reject(); })); return; } if (params['resolve-null']) { event.respondWith(new Promise(function(resolve) { resolve(null); })); return; } if (params['generate-png']) { var binary = atob( 'iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAAAXNSR0IArs4c6QAAAA' + 'RnQU1BAACxjwv8YQUAAAAJcEhZcwAADsQAAA7EAZUrDhsAAAAhSURBVDhPY3wro/Kf' + 'gQLABKXJBqMGjBoAAqMGDLwBDAwAEsoCTFWunmQAAAAASUVORK5CYII='); var array = new Uint8Array(binary.length); for(var i = 0; i < binary.length; i++) { array[i] = binary.charCodeAt(i); }; event.respondWith(new Response(new Blob([array], {type: 'image/png'}))); return; } if (params['check-ua-header']) { var ua = event.request.headers.get('User-Agent'); if (ua) { // We have a user agent! event.respondWith(new Response(new Blob([ua]))); } else { // We don't have a user-agent! event.respondWith(new Response(new Blob(["NO_UA"]))); } return; } if (params['check-accept-header']) { var accept = event.request.headers.get('Accept'); if (accept) { event.respondWith(new Response(accept)); } else { event.respondWith(new Response('NO_ACCEPT')); } return; } event.respondWith(new Promise(function(resolve, reject) { var request = event.request; if (url) { request = new Request(url, init); } else if (params['change-request']) { request = new Request(request, init); } const response_promise = params['navpreload'] ? event.preloadResponse : fetch(request); response_promise.then(function(response) { var expectedType = params['expected_type']; if (expectedType && response.type !== expectedType) { // Resolve a JSON object with a failure instead of rejecting // in order to distinguish this from a NetworkError, which // may be expected even if the type is correct. resolve(new Response(JSON.stringify({ result: 'failure', detail: 'got ' + response.type + ' Response.type instead of ' + expectedType }))); } var expectedRedirected = params['expected_redirected']; if (typeof expectedRedirected !== 'undefined') { var expected_redirected = (expectedRedirected === 'true'); if(response.redirected !== expected_redirected) { // This is simply determining how to pass an error to the outer // test case(fetch-request-redirect.https.html). var execptedResolves = params['expected_resolves']; if (execptedResolves === 'true') { // Reject a JSON object with a failure since promise is expected // to be resolved. reject(new Response(JSON.stringify({ result: 'failure', detail: 'got '+ response.redirected + ' Response.redirected instead of ' + expectedRedirected }))); } else { // Resolve a JSON object with a failure since promise is // expected to be rejected. resolve(new Response(JSON.stringify({ result: 'failure', detail: 'got '+ response.redirected + ' Response.redirected instead of ' + expectedRedirected }))); } } } if (params['clone']) { response = response.clone(); } // |cache| means to bounce responses through Cache Storage and back. if (params['cache']) { var cacheName = "cached-fetches-" + performance.now() + "-" + event.request.url; var cache; var cachedResponse; return self.caches.open(cacheName).then(function(opened) { cache = opened; return cache.put(request, response); }).then(function() { return cache.match(request); }).then(function(cached) { cachedResponse = cached; return self.caches.delete(cacheName); }).then(function() { resolve(cachedResponse); }); } else { resolve(response); } }, reject) })); });