diff options
Diffstat (limited to 'testing/web-platform/tests/fetch/range/resources/range-sw.js')
-rw-r--r-- | testing/web-platform/tests/fetch/range/resources/range-sw.js | 218 |
1 files changed, 218 insertions, 0 deletions
diff --git a/testing/web-platform/tests/fetch/range/resources/range-sw.js b/testing/web-platform/tests/fetch/range/resources/range-sw.js new file mode 100644 index 0000000000..b47823f03b --- /dev/null +++ b/testing/web-platform/tests/fetch/range/resources/range-sw.js @@ -0,0 +1,218 @@ +importScripts('/resources/testharness.js'); + +setup({ explicit_done: true }); + +function assert_range_request(request, expectedRangeHeader, name) { + assert_equals(request.headers.get('Range'), expectedRangeHeader, name); +} + +async function broadcast(msg) { + for (const client of await clients.matchAll()) { + client.postMessage(msg); + } +} + +addEventListener('fetch', async event => { + /** @type Request */ + const request = event.request; + const url = new URL(request.url); + const action = url.searchParams.get('action'); + + switch (action) { + case 'range-header-filter-test': + rangeHeaderFilterTest(request); + return; + case 'range-header-passthrough-test': + rangeHeaderPassthroughTest(event); + return; + case 'store-ranged-response': + storeRangedResponse(event); + return; + case 'use-stored-ranged-response': + useStoredRangeResponse(event); + return; + case 'broadcast-accept-encoding': + broadcastAcceptEncoding(event); + return; + case 'record-media-range-request': + return recordMediaRangeRequest(event); + case 'use-media-range-request': + useMediaRangeRequest(event); + return; + } +}); + +/** + * @param {Request} request + */ +function rangeHeaderFilterTest(request) { + const rangeValue = request.headers.get('Range'); + + test(() => { + assert_range_request(new Request(request), rangeValue, `Untampered`); + assert_range_request(new Request(request, {}), rangeValue, `Untampered (no init props set)`); + assert_range_request(new Request(request, { __foo: 'bar' }), rangeValue, `Untampered (only invalid props set)`); + assert_range_request(new Request(request, { mode: 'cors' }), rangeValue, `More permissive mode`); + assert_range_request(request.clone(), rangeValue, `Clone`); + }, "Range headers correctly preserved"); + + test(() => { + assert_range_request(new Request(request, { headers: { Range: 'foo' } }), null, `Tampered - range header set`); + assert_range_request(new Request(request, { headers: {} }), null, `Tampered - empty headers set`); + assert_range_request(new Request(request, { mode: 'no-cors' }), null, `Tampered – mode set`); + assert_range_request(new Request(request, { cache: 'no-cache' }), null, `Tampered – cache mode set`); + }, "Range headers correctly removed"); + + test(() => { + let headers; + + headers = new Request(request).headers; + headers.delete('does-not-exist'); + assert_equals(headers.get('Range'), rangeValue, `Preserved if no header actually removed`); + + headers = new Request(request).headers; + headers.append('foo', 'bar'); + assert_equals(headers.get('Range'), rangeValue, `Preserved if silent-failure on append (due to request-no-cors guard)`); + + headers = new Request(request).headers; + headers.set('foo', 'bar'); + assert_equals(headers.get('Range'), rangeValue, `Preserved if silent-failure on set (due to request-no-cors guard)`); + + headers = new Request(request).headers; + headers.append('Range', 'foo'); + assert_equals(headers.get('Range'), rangeValue, `Preserved if silent-failure on append (due to request-no-cors guard)`); + + headers = new Request(request).headers; + headers.set('Range', 'foo'); + assert_equals(headers.get('Range'), rangeValue, `Preserved if silent-failure on set (due to request-no-cors guard)`); + + headers = new Request(request).headers; + headers.append('Accept', 'whatever'); + assert_equals(headers.get('Range'), null, `Stripped if header successfully appended`); + + headers = new Request(request).headers; + headers.set('Accept', 'whatever'); + assert_equals(headers.get('Range'), null, `Stripped if header successfully set`); + + headers = new Request(request).headers; + headers.delete('Accept'); + assert_equals(headers.get('Range'), null, `Stripped if header successfully deleted`); + + headers = new Request(request).headers; + headers.delete('Range'); + assert_equals(headers.get('Range'), null, `Stripped if range header successfully deleted`); + }, "Headers correctly filtered"); + + done(); +} + +function rangeHeaderPassthroughTest(event) { + /** @type Request */ + const request = event.request; + const url = new URL(request.url); + const key = url.searchParams.get('range-received-key'); + + event.waitUntil(new Promise(resolve => { + promise_test(async () => { + await fetch(event.request); + const response = await fetch('stash-take.py?key=' + key); + assert_equals(await response.json(), 'range-header-received'); + resolve(); + }, `Include range header in network request`); + + done(); + })); + + // Just send back any response, it isn't important for the test. + event.respondWith(new Response('')); +} + +let storedRangeResponseP; + +function storeRangedResponse(event) { + /** @type Request */ + const request = event.request; + const id = new URL(request.url).searchParams.get('id'); + + storedRangeResponseP = fetch(event.request); + broadcast({ id }); + + // Just send back any response, it isn't important for the test. + event.respondWith(new Response('')); +} + +function useStoredRangeResponse(event) { + event.respondWith(async function() { + const response = await storedRangeResponseP; + if (!response) throw Error("Expected stored range response"); + return response.clone(); + }()); +} + +function broadcastAcceptEncoding(event) { + /** @type Request */ + const request = event.request; + const id = new URL(request.url).searchParams.get('id'); + + broadcast({ + id, + acceptEncoding: request.headers.get('Accept-Encoding') + }); + + // Just send back any response, it isn't important for the test. + event.respondWith(new Response('')); +} + +let rangeResponse = {}; + +async function recordMediaRangeRequest(event) { + /** @type Request */ + const request = event.request; + const url = new URL(request.url); + const urlParams = new URLSearchParams(url.search); + const size = urlParams.get("size"); + const id = urlParams.get('id'); + const key = 'size' + size; + + if (key in rangeResponse) { + // Don't re-fetch ranges we already have. + const clonedResponse = rangeResponse[key].clone(); + event.respondWith(clonedResponse); + } else if (event.request.headers.get("range") === "bytes=0-") { + // Generate a bogus 206 response to trigger subsequent range requests + // of the desired size. + const length = urlParams.get("length") + 100; + const body = "A".repeat(Number(size)); + event.respondWith(new Response(body, {status: 206, headers: { + "Content-Type": "audio/mp4", + "Content-Range": `bytes 0-1/${length}` + }})); + } else if (event.request.headers.get("range") === `bytes=${Number(size)}-`) { + // Pass through actual range requests which will attempt to fetch up to the + // length in the original response which is bigger than the actual resource + // to make sure 206 and 416 responses are treated the same. + rangeResponse[key] = await fetch(event.request); + + // Let the client know we have the range response for the given ID + broadcast({id}); + } else { + event.respondWith(Promise.reject(Error("Invalid Request"))); + } +} + +function useMediaRangeRequest(event) { + /** @type Request */ + const request = event.request; + const url = new URL(request.url); + const urlParams = new URLSearchParams(url.search); + const size = urlParams.get("size"); + const key = 'size' + size; + + // Send a clone of the range response to preload. + if (key in rangeResponse) { + const clonedResponse = rangeResponse[key].clone(); + event.respondWith(clonedResponse); + } else { + event.respondWith(Promise.reject(Error("Invalid Request"))); + } +} |