diff options
Diffstat (limited to 'test/wpt/tests/fetch/range/sw.https.window.js')
-rw-r--r-- | test/wpt/tests/fetch/range/sw.https.window.js | 228 |
1 files changed, 228 insertions, 0 deletions
diff --git a/test/wpt/tests/fetch/range/sw.https.window.js b/test/wpt/tests/fetch/range/sw.https.window.js new file mode 100644 index 0000000..62ad894 --- /dev/null +++ b/test/wpt/tests/fetch/range/sw.https.window.js @@ -0,0 +1,228 @@ +// META: script=../../../service-workers/service-worker/resources/test-helpers.sub.js +// META: script=/common/utils.js +// META: script=/common/get-host-info.sub.js +// META: script=resources/utils.js + +const { REMOTE_HOST } = get_host_info(); +const BASE_SCOPE = 'resources/basic.html?'; + +async function cleanup() { + for (const iframe of document.querySelectorAll('.test-iframe')) { + iframe.parentNode.removeChild(iframe); + } + + for (const reg of await navigator.serviceWorker.getRegistrations()) { + await reg.unregister(); + } +} + +async function setupRegistration(t, scope) { + await cleanup(); + const reg = await navigator.serviceWorker.register('resources/range-sw.js', { scope }); + await wait_for_state(t, reg.installing, 'activated'); + return reg; +} + +function awaitMessage(obj, id) { + return new Promise(resolve => { + obj.addEventListener('message', function listener(event) { + if (event.data.id !== id) return; + obj.removeEventListener('message', listener); + resolve(event.data); + }); + }); +} + +promise_test(async t => { + const scope = BASE_SCOPE + Math.random(); + const reg = await setupRegistration(t, scope); + const iframe = await with_iframe(scope); + const w = iframe.contentWindow; + + // Trigger a cross-origin range request using media + const url = new URL('long-wav.py?action=range-header-filter-test', w.location); + url.hostname = REMOTE_HOST; + appendAudio(w.document, url); + + // See rangeHeaderFilterTest in resources/range-sw.js + await fetch_tests_from_worker(reg.active); +}, `Defer range header filter tests to service worker`); + +promise_test(async t => { + const scope = BASE_SCOPE + Math.random(); + const reg = await setupRegistration(t, scope); + const iframe = await with_iframe(scope); + const w = iframe.contentWindow; + + // Trigger a cross-origin range request using media + const url = new URL('long-wav.py', w.location); + url.searchParams.set('action', 'range-header-passthrough-test'); + url.searchParams.set('range-received-key', token()); + url.hostname = REMOTE_HOST; + appendAudio(w.document, url); + + // See rangeHeaderPassthroughTest in resources/range-sw.js + await fetch_tests_from_worker(reg.active); +}, `Defer range header passthrough tests to service worker`); + +promise_test(async t => { + const scope = BASE_SCOPE + Math.random(); + await setupRegistration(t, scope); + const iframe = await with_iframe(scope); + const w = iframe.contentWindow; + const id = Math.random() + ''; + const storedRangeResponse = awaitMessage(w.navigator.serviceWorker, id); + + // Trigger a cross-origin range request using media + const url = new URL('partial-script.py', w.location); + url.searchParams.set('require-range', '1'); + url.searchParams.set('action', 'store-ranged-response'); + url.searchParams.set('id', id); + url.hostname = REMOTE_HOST; + + appendAudio(w.document, url); + + await storedRangeResponse; + + // Fetching should reject + const fetchPromise = w.fetch('?action=use-stored-ranged-response', { mode: 'no-cors' }); + await promise_rejects_js(t, w.TypeError, fetchPromise); + + // Script loading should error too + const loadScriptPromise = loadScript('?action=use-stored-ranged-response', { doc: w.document }); + await promise_rejects_js(t, Error, loadScriptPromise); + + await loadScriptPromise.catch(() => {}); + + assert_false(!!w.scriptExecuted, `Partial response shouldn't be executed`); +}, `Ranged response not allowed following no-cors ranged request`); + +promise_test(async t => { + const scope = BASE_SCOPE + Math.random(); + await setupRegistration(t, scope); + const iframe = await with_iframe(scope); + const w = iframe.contentWindow; + const id = Math.random() + ''; + const storedRangeResponse = awaitMessage(w.navigator.serviceWorker, id); + + // Trigger a range request using media + const url = new URL('partial-script.py', w.location); + url.searchParams.set('require-range', '1'); + url.searchParams.set('action', 'store-ranged-response'); + url.searchParams.set('id', id); + + appendAudio(w.document, url); + + await storedRangeResponse; + + // This should not throw + await w.fetch('?action=use-stored-ranged-response'); + + // This shouldn't throw either + await loadScript('?action=use-stored-ranged-response', { doc: w.document }); + + assert_true(w.scriptExecuted, `Partial response should be executed`); +}, `Non-opaque ranged response executed`); + +promise_test(async t => { + const scope = BASE_SCOPE + Math.random(); + await setupRegistration(t, scope); + const iframe = await with_iframe(scope); + const w = iframe.contentWindow; + const fetchId = Math.random() + ''; + const fetchBroadcast = awaitMessage(w.navigator.serviceWorker, fetchId); + const audioId = Math.random() + ''; + const audioBroadcast = awaitMessage(w.navigator.serviceWorker, audioId); + + const url = new URL('long-wav.py', w.location); + url.searchParams.set('action', 'broadcast-accept-encoding'); + url.searchParams.set('id', fetchId); + + await w.fetch(url, { + headers: { Range: 'bytes=0-10' } + }); + + assert_equals((await fetchBroadcast).acceptEncoding, null, "Accept-Encoding should not be set for fetch"); + + url.searchParams.set('id', audioId); + appendAudio(w.document, url); + + assert_equals((await audioBroadcast).acceptEncoding, null, "Accept-Encoding should not be set for media"); +}, `Accept-Encoding should not appear in a service worker`); + +promise_test(async t => { + const scope = BASE_SCOPE + Math.random(); + await setupRegistration(t, scope); + const iframe = await with_iframe(scope); + const w = iframe.contentWindow; + const length = 100; + const count = 3; + const counts = {}; + + // test a single range request size + async function testSizedRange(size, partialResponseCode) { + const rangeId = Math.random() + ''; + const rangeBroadcast = awaitMessage(w.navigator.serviceWorker, rangeId); + + // Create a bogus audio element to trick the browser into sending + // cross-origin range requests that can be manipulated by the service worker. + const sound_url = new URL('partial-text.py', w.location); + sound_url.hostname = REMOTE_HOST; + sound_url.searchParams.set('action', 'record-media-range-request'); + sound_url.searchParams.set('length', length); + sound_url.searchParams.set('size', size); + sound_url.searchParams.set('partial', partialResponseCode); + sound_url.searchParams.set('id', rangeId); + sound_url.searchParams.set('type', 'audio/mp4'); + appendAudio(w.document, sound_url); + + // wait for the range requests to happen + await rangeBroadcast; + + // Create multiple preload requests and count the number of resource timing + // entries that get created to make sure 206 and 416 range responses are treated + // the same. + const url = new URL('partial-text.py', w.location); + url.searchParams.set('action', 'use-media-range-request'); + url.searchParams.set('size', size); + url.searchParams.set('type', 'audio/mp4'); + counts['size' + size] = 0; + for (let i = 0; i < count; i++) { + await preloadImage(url, { doc: w.document }); + } + } + + // Test range requests from 1 smaller than the correct size to 1 larger than + // the correct size to exercise the various permutations using the default 206 + // response code for successful range requests. + for (let size = length - 1; size <= length + 1; size++) { + await testSizedRange(size, '206'); + } + + // Test a successful range request using a 200 response. + await testSizedRange(length - 2, '200'); + + // Check the resource timing entries and count the reported number of fetches of each type + const resources = w.performance.getEntriesByType("resource"); + for (const entry of resources) { + const url = new URL(entry.name); + if (url.searchParams.has('action') && + url.searchParams.get('action') == 'use-media-range-request' && + url.searchParams.has('size')) { + counts['size' + url.searchParams.get('size')]++; + } + } + + // Make sure there are a non-zero number of preload requests and they are all the same + let counts_valid = true; + const first = 'size' + (length - 2); + for (let size = length - 2; size <= length + 1; size++) { + let key = 'size' + size; + if (!(key in counts) || counts[key] <= 0 || counts[key] != counts[first]) { + counts_valid = false; + break; + } + } + + assert_true(counts_valid, `Opaque range request preloads were different for error and success`); +}, `Opaque range preload successes and failures should be indistinguishable`); |