diff options
author | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-19 00:47:55 +0000 |
---|---|---|
committer | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-19 00:47:55 +0000 |
commit | 26a029d407be480d791972afb5975cf62c9360a6 (patch) | |
tree | f435a8308119effd964b339f76abb83a57c29483 /testing/web-platform/tests/service-workers/service-worker/navigation-redirect.https.html | |
parent | Initial commit. (diff) | |
download | firefox-26a029d407be480d791972afb5975cf62c9360a6.tar.xz firefox-26a029d407be480d791972afb5975cf62c9360a6.zip |
Adding upstream version 124.0.1.upstream/124.0.1
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'testing/web-platform/tests/service-workers/service-worker/navigation-redirect.https.html')
-rw-r--r-- | testing/web-platform/tests/service-workers/service-worker/navigation-redirect.https.html | 846 |
1 files changed, 846 insertions, 0 deletions
diff --git a/testing/web-platform/tests/service-workers/service-worker/navigation-redirect.https.html b/testing/web-platform/tests/service-workers/service-worker/navigation-redirect.https.html new file mode 100644 index 0000000000..a87de56931 --- /dev/null +++ b/testing/web-platform/tests/service-workers/service-worker/navigation-redirect.https.html @@ -0,0 +1,846 @@ +<!DOCTYPE html> +<title>Service Worker: Navigation redirection</title> +<meta name="timeout" content="long"> +<!-- default variant tests document.location and intercepted URLs --> +<meta name="variant" content="?default"> +<!-- client variant tests the Clients API (resultingClientId and Client.url) --> +<meta name="variant" content="?client"> + +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> +<script src="/common/get-host-info.sub.js"></script> +<script src="resources/test-helpers.sub.js"></script> +<body> +<script> +const host_info = get_host_info(); + +// This test registers three Service Workers at SCOPE1, SCOPE2 and +// OTHER_ORIGIN_SCOPE. And checks the redirected page's URL and the requests +// which are intercepted by Service Worker while loading redirect page. +const BASE_URL = host_info['HTTPS_ORIGIN'] + base_path(); +const OTHER_BASE_URL = host_info['HTTPS_REMOTE_ORIGIN'] + base_path(); + +const SCOPE1 = BASE_URL + 'resources/navigation-redirect-scope1.py?'; +const SCOPE2 = BASE_URL + 'resources/navigation-redirect-scope2.py?'; +const OUT_SCOPE = BASE_URL + 'resources/navigation-redirect-out-scope.py?'; +const SCRIPT = 'resources/redirect-worker.js'; + +const OTHER_ORIGIN_IFRAME_URL = + OTHER_BASE_URL + 'resources/navigation-redirect-other-origin.html'; +const OTHER_ORIGIN_SCOPE = + OTHER_BASE_URL + 'resources/navigation-redirect-scope1.py?'; +const OTHER_ORIGIN_OUT_SCOPE = + OTHER_BASE_URL + 'resources/navigation-redirect-out-scope.py?'; + +let registrations; +let workers; +let other_origin_frame; +let message_resolvers = {}; +let next_message_id = 0; + +promise_test(async t => { + // In this frame we register a service worker at OTHER_ORIGIN_SCOPE. + // And will use this frame to communicate with the worker. + other_origin_frame = await with_iframe(OTHER_ORIGIN_IFRAME_URL); + + // Register same-origin service workers. + registrations = await Promise.all([ + service_worker_unregister_and_register(t, SCRIPT, SCOPE1), + service_worker_unregister_and_register(t, SCRIPT, SCOPE2)]); + + // Wait for all workers to activate. + workers = registrations.map(get_effective_worker); + return Promise.all([ + wait_for_state(t, workers[0], 'activated'), + wait_for_state(t, workers[1], 'activated'), + // This promise will resolve when |wait_for_worker_promise| + // in OTHER_ORIGIN_IFRAME_URL resolves. + send_to_iframe(other_origin_frame, {command: 'wait_for_worker'})]); +}, 'initialize global state'); + +function get_effective_worker(registration) { + if (registration.active) + return registration.active; + if (registration.waiting) + return registration.waiting; + if (registration.installing) + return registration.installing; +} + +async function check_all_intercepted_urls(expected_urls) { + const urls = []; + urls.push(await get_intercepted_urls(workers[0])); + urls.push(await get_intercepted_urls(workers[1])); + // Gets the request URLs which are intercepted by OTHER_ORIGIN_SCOPE's + // SW. This promise will resolve when get_request_infos() in + // OTHER_ORIGIN_IFRAME_URL resolves. + const request_infos = await send_to_iframe(other_origin_frame, + {command: 'get_request_infos'}); + urls.push(request_infos.map(info => { return info.url; })); + + assert_object_equals(urls, expected_urls, 'Intercepted URLs should match.'); +} + +// Checks |clients| returned from a worker. Only the client matching +// |expected_final_client_tag| should be found. Returns true if a client was +// found. Note that the final client is not necessarily found by this worker, +// if the client is cross-origin. +// +// |clients| is an object like: +// {x: {found: true, id: id1, url: url1}, b: {found: false}} +function check_clients(clients, + expected_id, + expected_url, + expected_final_client_tag, + worker_name) { + let found = false; + Object.keys(clients).forEach(key => { + const info = clients[key]; + if (info.found) { + assert_true(!!expected_final_client_tag, + `${worker_name} client tag exists`); + assert_equals(key, expected_final_client_tag, + `${worker_name} client tag matches`); + assert_equals(info.id, expected_id, `${worker_name} client id`); + assert_equals(info.url, expected_url, `${worker_name} client url`); + found = true; + } + }); + return found; +} + +function check_resulting_client_ids(infos, expected_infos, actual_ids, worker) { + assert_equals(infos.length, expected_infos.length, + `request length for ${worker}`); + for (var i = 0; i < infos.length; i++) { + const tag = expected_infos[i].resultingClientIdTag; + const url = expected_infos[i].url; + const actual_id = infos[i].resultingClientId; + const expected_id = actual_ids[tag]; + assert_equals(typeof(actual_id), 'string', + `resultingClientId for ${url} request to ${worker}`); + if (expected_id) { + assert_equals(actual_id, expected_id, + `resultingClientId for ${url} request to ${worker}`); + } else { + actual_ids[tag] = actual_id; + } + } +} + +// Creates an iframe and navigates to |url|, which is expected to start a chain +// of redirects. +// - |expected_last_url| is the expected window.location after the +// navigation. +// +// - |expected_request_infos| is the expected requests that the service workers +// were dispatched fetch events for. The format is: +// [ +// [ +// // Requests received by workers[0]. +// {url: url1, resultingClientIdTag: 'a'}, +// {url: url2, resultingClientIdTag: 'a'} +// ], +// [ +// // Requests received by workers[1]. +// {url: url3, resultingClientIdTag: 'a'} +// ], +// [ +// // Requests received by the cross-origin worker. +// {url: url4, resultingClientIdTag: 'x'} +// {url: url5, resultingClientIdTag: 'x'} +// ] +// ] +// Here, |url| is |event.request.url| and |resultingClientIdTag| represents +// |event.resultingClientId|. Since the actual client ids are not known +// beforehand, the expectation isn't the literal expected value, but all equal +// tags must map to the same actual id. +// +// - |expected_final_client_tag| is the resultingClientIdTag that is +// expected to map to the created client's id. This is null if there +// is no such tag, which can happen when the final request was a cross-origin +// redirect to out-scope, so no worker received a fetch event whose +// resultingClientId is the id of the resulting client. +// +// In the example above: +// - workers[0] receives two requests with the same resultingClientId. +// - workers[1] receives one request also with that resultingClientId. +// - The cross-origin worker receives two requests with the same +// resultingClientId which differs from the previous one. +// - Assuming |expected_final_client_tag| is 'x', then the created +// client has the id seen by the cross-origin worker above. +function redirect_test(url, + expected_last_url, + expected_request_infos, + expected_final_client_tag, + test_name) { + promise_test(async t => { + const frame = await with_iframe(url); + t.add_cleanup(() => { frame.remove(); }); + + // Switch on variant. + if (document.location.search == '?client') { + return client_variant_test(url, expected_last_url, expected_request_infos, + expected_final_client_tag, test_name); + } + + return default_variant_test(url, expected_last_url, expected_request_infos, + frame, test_name); + }, test_name); +} + +// The default variant tests the request interception chain and +// resulting document.location. +async function default_variant_test(url, + expected_last_url, + expected_request_infos, + frame, + test_name) { + const expected_intercepted_urls = expected_request_infos.map( + requests_for_worker => { + return requests_for_worker.map(info => { + return info.url; + }); + }); + await check_all_intercepted_urls(expected_intercepted_urls); + const last_url = await send_to_iframe(frame, 'getLocation'); + assert_equals(last_url, expected_last_url, 'Last URL should match.'); +} + +// The "client" variant tests the Clients API using resultingClientId. +async function client_variant_test(url, + expected_last_url, + expected_request_infos, + expected_final_client_tag, + test_name) { + // Request infos is an array like: + // [ + // [{url: url1, resultingClientIdTag: tag1}], + // [{url: url2, resultingClientIdTag: tag2}], + // [{url: url3: resultingClientIdTag: tag3}] + // ] + const requestInfos = await get_all_request_infos(); + + // We check the actual infos against the expected ones, and learn the + // actual ids as we go. + const actual_ids = {}; + check_resulting_client_ids(requestInfos[0], + expected_request_infos[0], + actual_ids, + 'worker0'); + check_resulting_client_ids(requestInfos[1], + expected_request_infos[1], + actual_ids, + 'worker1'); + check_resulting_client_ids(requestInfos[2], + expected_request_infos[2], + actual_ids, + 'crossOriginWorker'); + + // Now |actual_ids| maps tag to actual id: + // {x: id1, b: id2, c: id3} + // Ask each worker to try to resolve the actual ids to clients. + // Only |expected_final_client_tag| should resolve to a client. + const client_infos = await get_all_clients(actual_ids); + + // Client infos is an object like: + // { + // worker0: {x: {found: true, id: id1, url: url1}, b: {found: false}}, + // worker1: {x: {found: true, id: id1, url: url1}}, + // crossOriginWorker: {x: {found: false}}, {b: {found: false}} + // } + // + // Now check each client info. check_clients() verifies each info: only + // |expected_final_client_tag| should ever be found and the found client + // should have the expected url and id. A wrinkle is that not all workers + // will find the client, if they are cross-origin to the client. This + // means check_clients() trivially passes if no clients are found. So + // additionally check that at least one worker found the client (|found|), + // if that was expected (|expect_found|). + let found = false; + const expect_found = !!expected_final_client_tag; + const expected_id = actual_ids[expected_final_client_tag]; + found = check_clients(client_infos.worker0, + expected_id, + expected_last_url, + expected_final_client_tag, + 'worker0'); + found = check_clients(client_infos.worker1, + expected_id, + expected_last_url, + expected_final_client_tag, + 'worker1') || found; + found = check_clients(client_infos.crossOriginWorker, + expected_id, + expected_last_url, + expected_final_client_tag, + 'crossOriginWorker') || found; + assert_equals(found, expect_found, 'client found'); + + if (!expect_found) { + // TODO(falken): Ask the other origin frame if it has a client of the + // expected URL. + } +} + +window.addEventListener('message', on_message, false); + +function on_message(e) { + if (e.origin != host_info['HTTPS_REMOTE_ORIGIN'] && + e.origin != host_info['HTTPS_ORIGIN'] ) { + console.error('invalid origin: ' + e.origin); + return; + } + var resolve = message_resolvers[e.data.id]; + delete message_resolvers[e.data.id]; + resolve(e.data.result); +} + +function send_to_iframe(frame, message) { + var message_id = next_message_id++; + return new Promise(resolve => { + message_resolvers[message_id] = resolve; + frame.contentWindow.postMessage( + {id: message_id, message}, + '*'); + }); +} + +async function get_all_clients(actual_ids) { + const client_infos = {}; + client_infos['worker0'] = await get_clients(workers[0], actual_ids); + client_infos['worker1'] = await get_clients(workers[1], actual_ids); + client_infos['crossOriginWorker'] = + await send_to_iframe(other_origin_frame, + {command: 'get_clients', actual_ids}); + return client_infos; +} + +function get_clients(worker, actual_ids) { + return new Promise(resolve => { + var channel = new MessageChannel(); + channel.port1.onmessage = (msg) => { + resolve(msg.data.clients); + }; + worker.postMessage({command: 'getClients', actual_ids, port: channel.port2}, + [channel.port2]); + }); +} + +// Returns an array of the URLs that |worker| received fetch events for: +// [url1, url2] +async function get_intercepted_urls(worker) { + const infos = await get_request_infos(worker); + return infos.map(info => { return info.url; }); +} + +// Returns the requests that |worker| received fetch events for. The return +// value is an array of format: +// [ +// {url: url1, resultingClientId: id}, +// {url: url2, resultingClientId: id} +// ] +function get_request_infos(worker) { + return new Promise(resolve => { + var channel = new MessageChannel(); + channel.port1.onmessage = (msg) => { + resolve(msg.data.requestInfos); + }; + worker.postMessage({command: 'getRequestInfos', port: channel.port2}, + [channel.port2]); + }); +} + +// Returns an array of the requests the workers received fetch events for: +// [ +// // Requests from workers[0]. +// [ +// {url: url1, resultingClientIdTag: tag1}, +// {url: url2, resultingClientIdTag: tag1} +// ], +// +// // Requests from workers[1]. +// [{url: url3, resultingClientIdTag: tag2}], +// +// // Requests from the cross-origin worker. +// [] +// ] +async function get_all_request_infos() { + const request_infos = []; + request_infos.push(await get_request_infos(workers[0])); + request_infos.push(await get_request_infos(workers[1])); + request_infos.push(await send_to_iframe(other_origin_frame, + {command: 'get_request_infos'})); + return request_infos; +} + +let url; +let url1; +let url2; + +// Normal redirect (from out-scope to in-scope). +url = SCOPE1; +redirect_test( + OUT_SCOPE + 'url=' + encodeURIComponent(url), + url, + [[{url, resultingClientIdTag: 'x'}], [], []], + 'x', + 'Normal redirect to same-origin scope.'); + + +url = SCOPE1 + '#ref'; +redirect_test( + OUT_SCOPE + 'url=' + encodeURIComponent(SCOPE1) + '#ref', + url, + [[{url, resultingClientIdTag: 'x'}], [], []], + 'x', + 'Normal redirect to same-origin scope with a hash fragment.'); + +url = SCOPE1 + '#ref2'; +redirect_test( + OUT_SCOPE + 'url=' + encodeURIComponent(url) + '#ref', + url, + [[{url, resultingClientIdTag: 'x'}], [], []], + 'x', + 'Normal redirect to same-origin scope with different hash fragments.'); + +url = OTHER_ORIGIN_SCOPE; +redirect_test( + OUT_SCOPE + 'url=' + encodeURIComponent(url), + url, + [[], [], [{url, resultingClientIdTag: 'x'}]], + 'x', + 'Normal redirect to other-origin scope.'); + +// SW fallbacked redirect. SW doesn't handle the fetch request. +url = SCOPE1 + 'url=' + encodeURIComponent(OUT_SCOPE); +redirect_test( + url, + OUT_SCOPE, + [[{url, resultingClientIdTag: 'x'}], [], []], + 'x', + 'SW-fallbacked redirect to same-origin out-scope.'); + +url1 = SCOPE1 + 'url=' + encodeURIComponent(SCOPE1); +url2 = SCOPE1; +redirect_test( + url1, + url2, + [ + [ + {url: url1, resultingClientIdTag: 'x'}, + {url: url2, resultingClientIdTag: 'x'} + ], + [], + [] + ], + 'x', + 'SW-fallbacked redirect to same-origin same-scope.'); + +url1 = SCOPE1 + 'url=' + encodeURIComponent(SCOPE1) + '#ref'; +url2 = SCOPE1 + '#ref'; +redirect_test( + url1, + url2, + [ + [ + {url: url1, resultingClientIdTag: 'x'}, + {url: url2, resultingClientIdTag: 'x'} + ], + [], + [] + ], + 'x', + 'SW-fallbacked redirect to same-origin same-scope with a hash fragment.'); + +url1 = SCOPE1 + 'url=' + encodeURIComponent(SCOPE1 + '#ref2') + '#ref'; +url2 = SCOPE1 + '#ref2'; +redirect_test( + url1, + url2, + [ + [ + {url: url1, resultingClientIdTag: 'x'}, + {url: url2, resultingClientIdTag: 'x'} + ], + [], + [] + ], + 'x', + 'SW-fallbacked redirect to same-origin same-scope with different hash ' + + 'fragments.'); + +url1 = SCOPE1 + 'url=' + encodeURIComponent(SCOPE2); +url2 = SCOPE2; +redirect_test( + url1, + url2, + [ + [{url: url1, resultingClientIdTag: 'x'}], + [{url: url2, resultingClientIdTag: 'x'}], + [] + ], + 'x', + 'SW-fallbacked redirect to same-origin other-scope.'); + +url1 = SCOPE1 + 'url=' + encodeURIComponent(OTHER_ORIGIN_OUT_SCOPE); +url2 = OTHER_ORIGIN_OUT_SCOPE; +redirect_test( + url1, + url2, + [[{url: url1, resultingClientIdTag: 'a'}], [], []], + null, + 'SW-fallbacked redirect to other-origin out-scope.'); + +url1 = SCOPE1 + 'url=' + encodeURIComponent(OTHER_ORIGIN_SCOPE); +url2 = OTHER_ORIGIN_SCOPE; +redirect_test( + url1, + url2, + [ + [{url: url1, resultingClientIdTag: 'a'}], + [], + [{url: url2, resultingClientIdTag: 'x'}] + ], + 'x', + 'SW-fallbacked redirect to other-origin in-scope.'); + + +url3 = SCOPE1; +url2 = OTHER_ORIGIN_SCOPE + 'url=' + encodeURIComponent(url3); +url1 = SCOPE1 + 'url=' + encodeURIComponent(url2); +redirect_test( + url1, + url3, + [ + [ + {url: url1, resultingClientIdTag: 'a'}, + {url: url3, resultingClientIdTag: 'x'} + ], + [], + [{url: url2, resultingClientIdTag: 'b'}] + ], + 'x', + 'SW-fallbacked redirect to other-origin and back to same-origin.'); + +// SW generated redirect. +// SW: event.respondWith(Response.redirect(params['url'])); +url1 = SCOPE1 + 'sw=gen&url=' + encodeURIComponent(OUT_SCOPE); +url2 = OUT_SCOPE; +redirect_test( + url1, + url2, + [[{url: url1, resultingClientIdTag: 'x'}], [], []], + 'x', + 'SW-generated redirect to same-origin out-scope.'); + +url1 = SCOPE1 + 'sw=gen&url=' + encodeURIComponent(OUT_SCOPE) + '#ref'; +url2 = OUT_SCOPE + '#ref'; +redirect_test( + url1, + url2, + [[{url: url1, resultingClientIdTag: 'x'}], [], []], + 'x', + 'SW-generated redirect to same-origin out-scope with a hash fragment.'); + +url1 = SCOPE1 + 'sw=gen&url=' + encodeURIComponent(OUT_SCOPE + '#ref2') + '#ref'; +url2 = OUT_SCOPE + '#ref2'; +redirect_test( + url1, + url2, + [[{url: url1, resultingClientIdTag: 'x'}], [], []], + 'x', + 'SW-generated redirect to same-origin out-scope with different hash ' + + 'fragments.'); + +url1 = SCOPE1 + 'sw=gen&url=' + encodeURIComponent(SCOPE1); +url2 = SCOPE1; +redirect_test( + url1, + url2, + [ + [ + {url: url1, resultingClientIdTag: 'x'}, + {url: url2, resultingClientIdTag: 'x'} + ], + [], + [] + ], + 'x', + 'SW-generated redirect to same-origin same-scope.'); + +url1 = SCOPE1 + 'sw=gen&url=' + encodeURIComponent(SCOPE2); +url2 = SCOPE2; +redirect_test( + url1, + url2, + [ + [{url: url1, resultingClientIdTag: 'x'}], + [{url: url2, resultingClientIdTag: 'x'}], + [] + ], + 'x', + 'SW-generated redirect to same-origin other-scope.'); + +url1 = SCOPE1 + 'sw=gen&url=' + encodeURIComponent(OTHER_ORIGIN_OUT_SCOPE); +url2 = OTHER_ORIGIN_OUT_SCOPE; +redirect_test( + url1, + url2, + [[{url: url1, resultingClientIdTag: 'a'}], [], []], + null, + 'SW-generated redirect to other-origin out-scope.'); + +url1 = SCOPE1 + 'sw=gen&url=' + encodeURIComponent(OTHER_ORIGIN_SCOPE); +url2 = OTHER_ORIGIN_SCOPE; +redirect_test( + url1, + url2, + [ + [{url: url1, resultingClientIdTag: 'a'}], + [], + [{url: url2, resultingClientIdTag: 'x'}] + ], + 'x', + 'SW-generated redirect to other-origin in-scope.'); + + +// SW fetched redirect. +// SW: event.respondWith(fetch(event.request)); +url1 = SCOPE1 + 'sw=fetch&url=' + encodeURIComponent(OUT_SCOPE) +url2 = OUT_SCOPE; +redirect_test( + url1, + url2, + [[{url: url1, resultingClientIdTag: 'x'}], [], []], + 'x', + 'SW-fetched redirect to same-origin out-scope.'); + +url1 = SCOPE1 + 'sw=fetch&url=' + encodeURIComponent(SCOPE1); +url2 = SCOPE1; +redirect_test( + url1, + url2, + [ + [ + {url: url1, resultingClientIdTag: 'x'}, + {url: url2, resultingClientIdTag: 'x'} + ], + [], + [] + ], + 'x', + 'SW-fetched redirect to same-origin same-scope.'); + +url1 = SCOPE1 + 'sw=fetch&url=' + encodeURIComponent(SCOPE2); +url2 = SCOPE2; +redirect_test( + url1, + url2, + [ + [{url: url1, resultingClientIdTag: 'x'}], + [{url: url2, resultingClientIdTag: 'x'}], + [] + ], + 'x', + 'SW-fetched redirect to same-origin other-scope.'); + +url1 = SCOPE1 + 'sw=fetch&url=' + encodeURIComponent(OTHER_ORIGIN_OUT_SCOPE); +url2 = OTHER_ORIGIN_OUT_SCOPE; +redirect_test( + url1, + url2, + [[{url: url1, resultingClientIdTag: 'a'}], [], []], + null, + 'SW-fetched redirect to other-origin out-scope.'); + +url1 = SCOPE1 + 'sw=fetch&url=' + encodeURIComponent(OTHER_ORIGIN_SCOPE); +url2 = OTHER_ORIGIN_SCOPE; +redirect_test( + url1, + url2, + [ + [{url: url1, resultingClientIdTag: 'a'}], + [], + [{url: url2, resultingClientIdTag: 'x'}] + ], + 'x', + 'SW-fetched redirect to other-origin in-scope.'); + + +// SW responds with a fetch from a different url. +// SW: event.respondWith(fetch(params['url'])); +url2 = SCOPE1; +url1 = SCOPE1 + 'sw=fetch-url&url=' + encodeURIComponent(url2); +redirect_test( + url1, + url1, + [ + [ + {url: url1, resultingClientIdTag: 'x'} + ], + [], + [] + ], + 'x', + 'SW-fetched response from different URL, same-origin same-scope.'); + + +// Opaque redirect. +// SW: event.respondWith(fetch( +// new Request(event.request.url, {redirect: 'manual'}))); +url1 = SCOPE1 + 'sw=manual&url=' + encodeURIComponent(OUT_SCOPE); +url2 = OUT_SCOPE; +redirect_test( + url1, + url2, + [[{url: url1, resultingClientIdTag: 'x'}], [], []], + 'x', + 'Redirect to same-origin out-scope with opaque redirect response.'); + +url1 = SCOPE1 + 'sw=manual&url=' + encodeURIComponent(SCOPE1); +url2 = SCOPE1; +redirect_test( + url1, + url2, + [ + [ + {url: url1, resultingClientIdTag: 'x'}, + {url: url2, resultingClientIdTag: 'x'} + ], + [], + [] + ], + 'x', + 'Redirect to same-origin same-scope with opaque redirect response.'); + +url1 = SCOPE1 + 'sw=manual&url=' + encodeURIComponent(SCOPE2); +url2 = SCOPE2; +redirect_test( + url1, + url2, + [ + [{url: url1, resultingClientIdTag: 'x'}], + [{url: url2, resultingClientIdTag: 'x'}], + [] + ], + 'x', + 'Redirect to same-origin other-scope with opaque redirect response.'); + +url1 = SCOPE1 + 'sw=manual&url=' + encodeURIComponent(OTHER_ORIGIN_OUT_SCOPE); +url2 = OTHER_ORIGIN_OUT_SCOPE; +redirect_test( + url1, + url2, + [[{url: url1, resultingClientIdTag: 'a'}], [], []], + null, + 'Redirect to other-origin out-scope with opaque redirect response.'); + +url1 = SCOPE1 + 'sw=manual&url=' + encodeURIComponent(OTHER_ORIGIN_SCOPE); +url2 = OTHER_ORIGIN_SCOPE; +redirect_test( + url1, + url2, + [ + [{url: url1, resultingClientIdTag: 'a'}], + [], + [{url: url2, resultingClientIdTag: 'x'}] + ], + 'x', + 'Redirect to other-origin in-scope with opaque redirect response.'); + +url= SCOPE1 + 'sw=manual&noLocationRedirect'; +redirect_test( + url, url, [[{url, resultingClientIdTag: 'x'}], [], []], + 'x', + 'No location redirect response.'); + + +// Opaque redirect passed through Cache. +// SW responds with an opaque redirectresponse from the Cache API. +url1 = SCOPE1 + 'sw=manualThroughCache&url=' + encodeURIComponent(OUT_SCOPE); +url2 = OUT_SCOPE; +redirect_test( + url1, + url2, + [[{url: url1, resultingClientIdTag: 'x'}], [], []], + 'x', + 'Redirect to same-origin out-scope with opaque redirect response which ' + + 'is passed through Cache.'); + +url1 = SCOPE1 + 'sw=manualThroughCache&url=' + encodeURIComponent(SCOPE1); +url2 = SCOPE1; +redirect_test( + url1, + url2, + [ + [ + {url: url1, resultingClientIdTag: 'x'}, + {url: url2, resultingClientIdTag: 'x'} + ], + [], + [] + ], + 'x', + 'Redirect to same-origin same-scope with opaque redirect response which ' + + 'is passed through Cache.'); + +url1 = SCOPE1 + 'sw=manualThroughCache&url=' + encodeURIComponent(SCOPE2); +url2 = SCOPE2; +redirect_test( + url1, + url2, + [ + [{url: url1, resultingClientIdTag: 'x'}], + [{url: url2, resultingClientIdTag: 'x'}], + [] + ], + 'x', + 'Redirect to same-origin other-scope with opaque redirect response which ' + + 'is passed through Cache.'); + +url1 = SCOPE1 + 'sw=manualThroughCache&url=' + + encodeURIComponent(OTHER_ORIGIN_OUT_SCOPE); +url2 = OTHER_ORIGIN_OUT_SCOPE; +redirect_test( + url1, + url2, + [[{url: url1, resultingClientIdTag: 'a'}], [], []], + null, + 'Redirect to other-origin out-scope with opaque redirect response which ' + + 'is passed through Cache.'); + +url1 = SCOPE1 + 'sw=manualThroughCache&url=' + + encodeURIComponent(OTHER_ORIGIN_SCOPE); +url2 = OTHER_ORIGIN_SCOPE; +redirect_test( + url1, + url2, + [ + [{url: url1, resultingClientIdTag: 'a'}], + [], + [{url: url2, resultingClientIdTag: 'x'}], + ], + 'x', + 'Redirect to other-origin in-scope with opaque redirect response which ' + + 'is passed through Cache.'); + +url = SCOPE1 + 'sw=manualThroughCache&noLocationRedirect'; +redirect_test( + url, + url, + [[{url, resultingClientIdTag: 'x'}], [], []], + 'x', + 'No location redirect response via Cache.'); + +// Clean up the test environment. This promise_test() needs to be the last one. +promise_test(async t => { + registrations.forEach(async registration => { + if (registration) + await registration.unregister(); + }); + await send_to_iframe(other_origin_frame, {command: 'unregister'}); + other_origin_frame.remove(); +}, 'clean up global state'); +</script> +</body> |