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/tentative | |
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/tentative')
30 files changed, 1293 insertions, 0 deletions
diff --git a/testing/web-platform/tests/service-workers/service-worker/tentative/static-router/README.md b/testing/web-platform/tests/service-workers/service-worker/tentative/static-router/README.md new file mode 100644 index 0000000000..5429b61d40 --- /dev/null +++ b/testing/web-platform/tests/service-workers/service-worker/tentative/static-router/README.md @@ -0,0 +1,4 @@ +A test suite for the ServiceWorker Static Routing API. + +WICG proposal: https://github.com/WICG/proposals/issues/102 +Specification PR: https://github.com/w3c/ServiceWorker/pull/1686 diff --git a/testing/web-platform/tests/service-workers/service-worker/tentative/static-router/resources/direct.css b/testing/web-platform/tests/service-workers/service-worker/tentative/static-router/resources/direct.css new file mode 100644 index 0000000000..c812213f53 --- /dev/null +++ b/testing/web-platform/tests/service-workers/service-worker/tentative/static-router/resources/direct.css @@ -0,0 +1,3 @@ +body { + width: 100%; +} diff --git a/testing/web-platform/tests/service-workers/service-worker/tentative/static-router/resources/direct.html b/testing/web-platform/tests/service-workers/service-worker/tentative/static-router/resources/direct.html new file mode 100644 index 0000000000..e98d70207a --- /dev/null +++ b/testing/web-platform/tests/service-workers/service-worker/tentative/static-router/resources/direct.html @@ -0,0 +1,5 @@ +<!DOCTYPE html> +<title>Direct</title> +<body> + Here's a direct html from network. +</body> diff --git a/testing/web-platform/tests/service-workers/service-worker/tentative/static-router/resources/direct.js b/testing/web-platform/tests/service-workers/service-worker/tentative/static-router/resources/direct.js new file mode 100644 index 0000000000..ed6f0e5f98 --- /dev/null +++ b/testing/web-platform/tests/service-workers/service-worker/tentative/static-router/resources/direct.js @@ -0,0 +1 @@ +window.router_condition_request_destination_script = true; diff --git a/testing/web-platform/tests/service-workers/service-worker/tentative/static-router/resources/direct.py b/testing/web-platform/tests/service-workers/service-worker/tentative/static-router/resources/direct.py new file mode 100644 index 0000000000..d30d41b44e --- /dev/null +++ b/testing/web-platform/tests/service-workers/service-worker/tentative/static-router/resources/direct.py @@ -0,0 +1,11 @@ +import os +import time + +def main(request, response): + if 'server_slow' in request.url_parts.query: + time.sleep(0.2) + if 'server_no_content' in request.url_parts.query: + return 204, [(b'Content-Type', b'text/plain')], u'Network with %s request' % request.method + if 'server_not_found' in request.url_parts.query: + return 404, [(b'Content-Type', b'text/plain')], u'Not Found' + return 200, [(b'Content-Type', b'text/plain')], u'Network with %s request' % request.method diff --git a/testing/web-platform/tests/service-workers/service-worker/tentative/static-router/resources/direct.txt b/testing/web-platform/tests/service-workers/service-worker/tentative/static-router/resources/direct.txt new file mode 100644 index 0000000000..f3d9861c13 --- /dev/null +++ b/testing/web-platform/tests/service-workers/service-worker/tentative/static-router/resources/direct.txt @@ -0,0 +1 @@ +Network diff --git a/testing/web-platform/tests/service-workers/service-worker/tentative/static-router/resources/imported-sw.js b/testing/web-platform/tests/service-workers/service-worker/tentative/static-router/resources/imported-sw.js new file mode 100644 index 0000000000..04a894d77f --- /dev/null +++ b/testing/web-platform/tests/service-workers/service-worker/tentative/static-router/resources/imported-sw.js @@ -0,0 +1,13 @@ +'use strict'; + +import {routerRules} from './router-rules.js'; + +const params = new URLSearchParams(location.search); +const key = params.get('imported-sw-router-key'); + +if (key) { + self.addEventListener('install', async e => { + await e.addRoutes(routerRules[key]); + self.skipWaiting(); + }); +} diff --git a/testing/web-platform/tests/service-workers/service-worker/tentative/static-router/resources/or-test/direct1.text b/testing/web-platform/tests/service-workers/service-worker/tentative/static-router/resources/or-test/direct1.text new file mode 100644 index 0000000000..f3d9861c13 --- /dev/null +++ b/testing/web-platform/tests/service-workers/service-worker/tentative/static-router/resources/or-test/direct1.text @@ -0,0 +1 @@ +Network diff --git a/testing/web-platform/tests/service-workers/service-worker/tentative/static-router/resources/or-test/direct1.text.headers b/testing/web-platform/tests/service-workers/service-worker/tentative/static-router/resources/or-test/direct1.text.headers new file mode 100644 index 0000000000..156209f9c8 --- /dev/null +++ b/testing/web-platform/tests/service-workers/service-worker/tentative/static-router/resources/or-test/direct1.text.headers @@ -0,0 +1 @@ +Content-Type: text/html diff --git a/testing/web-platform/tests/service-workers/service-worker/tentative/static-router/resources/or-test/direct2.text b/testing/web-platform/tests/service-workers/service-worker/tentative/static-router/resources/or-test/direct2.text new file mode 100644 index 0000000000..f3d9861c13 --- /dev/null +++ b/testing/web-platform/tests/service-workers/service-worker/tentative/static-router/resources/or-test/direct2.text @@ -0,0 +1 @@ +Network diff --git a/testing/web-platform/tests/service-workers/service-worker/tentative/static-router/resources/or-test/direct2.text.headers b/testing/web-platform/tests/service-workers/service-worker/tentative/static-router/resources/or-test/direct2.text.headers new file mode 100644 index 0000000000..156209f9c8 --- /dev/null +++ b/testing/web-platform/tests/service-workers/service-worker/tentative/static-router/resources/or-test/direct2.text.headers @@ -0,0 +1 @@ +Content-Type: text/html diff --git a/testing/web-platform/tests/service-workers/service-worker/tentative/static-router/resources/router-rules.js b/testing/web-platform/tests/service-workers/service-worker/tentative/static-router/resources/router-rules.js new file mode 100644 index 0000000000..4e6f8bb955 --- /dev/null +++ b/testing/web-platform/tests/service-workers/service-worker/tentative/static-router/resources/router-rules.js @@ -0,0 +1,76 @@ +const routerRules = { + 'condition-urlpattern-constructed-source-network': [{ + condition: {urlPattern: new URLPattern({pathname: '/**/direct.txt'})}, + source: 'network' + }], + 'condition-urlpattern-urlpatterninit-source-network': [ + {condition: {urlPattern: {pathname: '/**/direct.txt'}}, source: 'network'}, + ], + 'condition-urlpattern-string-source-network': [ + {condition: {urlPattern: '/**/direct.txt'}, source: 'network'}, + ], + 'condition-urlpattern-string-source-cache': [ + {condition: {urlPattern: '/**/cache.txt'}, source: 'cache'}, + ], + 'condition-urlpattern-constructed-ignore-case-source-network': [{ + condition: { + urlPattern: + new URLPattern({pathname: '/**/DiReCT.TxT'}, {ignoreCase: true}) + }, + source: 'network' + }], + 'condition-urlpattern-constructed-respect-case-source-network': [{ + condition: {urlPattern: new URLPattern({pathname: '/**/DiReCT.TxT'})}, + source: 'network' + }], + 'condition-request-source-network': + [{condition: {requestMode: 'no-cors'}, source: 'network'}], + 'condition-request-navigate-source-cache': + [{condition: {requestMode: 'navigate'}, source: 'cache'}], + 'condition-request-method-get-network': + [{condition: {requestMethod: 'GET'}, source: 'network'}], + 'condition-request-method-post-network': + [{condition: {requestMethod: 'POST'}, source: 'network'}], + 'condition-request-method-put-network': + [{condition: {requestMethod: 'PUT'}, source: 'network'}], + 'condition-request-method-delete-network': + [{condition: {requestMethod: 'DELETE'}, source: 'network'}], + 'condition-invalid-request-method': [{ + condition: {requestMethod: String.fromCodePoint(0x3042)}, + source: 'network' + }], + 'condition-request-destination-script-network': + [{condition: {requestDestination: 'script'}, source: 'network'}], + 'condition-or-source-network': [{ + condition: { + or: [ + { + or: [{urlPattern: '/**/or-test/direct1.*??*'}], + }, + {urlPattern: '/**/or-test/direct2.*??*'} + ] + }, + source: 'network' + }], + 'condition-request-source-fetch-event': + [{condition: {requestMode: 'no-cors'}, source: 'fetch-event'}], + 'condition-urlpattern-string-source-fetch-event': + [{condition: {urlPattern: '/**/*'}, source: 'fetch-event'}], + 'multiple-router-rules': [ + { + condition: { + urlPattern: '/**/direct.txt', + }, + source: 'network' + }, + {condition: {urlPattern: '/**/direct.html'}, source: 'network'} + ], + 'condition-urlpattern-string-source-race-network-and-fetch-handler': [ + { + condition: {urlPattern: '/**/direct.py'}, + source: 'race-network-and-fetch-handler' + }, + ], +}; + +export {routerRules}; diff --git a/testing/web-platform/tests/service-workers/service-worker/tentative/static-router/resources/simple-test-for-condition-main-resource.html b/testing/web-platform/tests/service-workers/service-worker/tentative/static-router/resources/simple-test-for-condition-main-resource.html new file mode 100644 index 0000000000..0c3e3e7870 --- /dev/null +++ b/testing/web-platform/tests/service-workers/service-worker/tentative/static-router/resources/simple-test-for-condition-main-resource.html @@ -0,0 +1,3 @@ +<!DOCTYPE html> +<title>Simple</title> +Here's a simple html file. diff --git a/testing/web-platform/tests/service-workers/service-worker/tentative/static-router/resources/simple.csv b/testing/web-platform/tests/service-workers/service-worker/tentative/static-router/resources/simple.csv new file mode 100644 index 0000000000..ecbef786e7 --- /dev/null +++ b/testing/web-platform/tests/service-workers/service-worker/tentative/static-router/resources/simple.csv @@ -0,0 +1 @@ +matched,with,non-url,conditions diff --git a/testing/web-platform/tests/service-workers/service-worker/tentative/static-router/resources/simple.html b/testing/web-platform/tests/service-workers/service-worker/tentative/static-router/resources/simple.html new file mode 100644 index 0000000000..0c3e3e7870 --- /dev/null +++ b/testing/web-platform/tests/service-workers/service-worker/tentative/static-router/resources/simple.html @@ -0,0 +1,3 @@ +<!DOCTYPE html> +<title>Simple</title> +Here's a simple html file. diff --git a/testing/web-platform/tests/service-workers/service-worker/tentative/static-router/resources/static-router-helpers.sub.js b/testing/web-platform/tests/service-workers/service-worker/tentative/static-router/resources/static-router-helpers.sub.js new file mode 100644 index 0000000000..cf34e98635 --- /dev/null +++ b/testing/web-platform/tests/service-workers/service-worker/tentative/static-router/resources/static-router-helpers.sub.js @@ -0,0 +1,76 @@ +// Helper functions for ServiceWorker static routing API. +// +// test-helpers.sub.js must be loaded before using this. + +// Get a dictionary of information recorded inside ServiceWorker. +// It includes: +// - request URL and mode. +// - errors. +// +// See: static-router-sw.js for details. +const get_info_from_worker = + async worker => { + const promise = new Promise(function(resolve) { + var channel = new MessageChannel(); + channel.port1.onmessage = function(msg) { resolve(msg); }; + worker.postMessage({port: channel.port2}, [channel.port2]); + }); + const message = await promise; + + return message.data; +} + +// Reset information stored inside ServiceWorker. +const reset_info_in_worker = + async worker => { + const promise = new Promise(function(resolve) { + var channel = new MessageChannel(); + channel.port1.onmessage = function(msg) { resolve(msg); }; + worker.postMessage({port: channel.port2, reset: true}, [channel.port2]); + }); + await promise; +} + +// Register the ServiceWorker and wait until activated. +// {ruleKey} represents the key of routerRules defined in router-rules.js. +// {swScript} represents the service worker source URL. +const registerAndActivate = async (test, ruleKey, swScript) => { + if (!swScript) { + swScript = 'resources/static-router-sw.js' + } + const swURL = `${swScript}?key=${ruleKey}`; + const swScope = 'resources/'; + const reg = await service_worker_unregister_and_register( + test, swURL, swScope, { type: 'module' }); + add_completion_callback(() => reg.unregister()); + const worker = reg.installing; + await wait_for_state(test, worker, 'activated'); + + return worker; +}; + +// Create iframe with the given url. This automatically removes the iframe in a +// cleanup. +const createIframe = async (t, url) => { + const iframe = await with_iframe(url); + t.add_cleanup(() => iframe.remove()); + + return iframe; +}; + +// Register a service worker, then create an iframe at url. +function iframeTest(url, ruleKey, callback, name) { + return promise_test(async t => { + const worker = await registerAndActivate(t, ruleKey); + const iframe = await createIframe(t, url); + await callback(t, iframe.contentWindow, worker); + }, name); +}; + +function randomString() { + let result = ""; + for (let i = 0; i < 5; i++) { + result += String.fromCharCode(97 + Math.floor(Math.random() * 26)); + } + return result; +} diff --git a/testing/web-platform/tests/service-workers/service-worker/tentative/static-router/resources/static-router-no-fetch-handler-sw.js b/testing/web-platform/tests/service-workers/service-worker/tentative/static-router/resources/static-router-no-fetch-handler-sw.js new file mode 100644 index 0000000000..1ba5fd7d46 --- /dev/null +++ b/testing/web-platform/tests/service-workers/service-worker/tentative/static-router/resources/static-router-no-fetch-handler-sw.js @@ -0,0 +1,35 @@ +'use strict'; + +import {routerRules} from './router-rules.js'; +import { + recordError, + getRecords, + resetRecords } from './static-router-sw.sub.js'; + +self.addEventListener('install', async e => { + e.waitUntil(caches.open('v1').then( + cache => {cache.put('cache.txt', new Response('From cache'))})); + + const params = new URLSearchParams(location.search); + const key = params.get('key'); + try { + await e.addRoutes(routerRules[key]); + } catch (e) { + recordError(e); + } + self.skipWaiting(); +}); + +self.addEventListener('activate', e => { + e.waitUntil(clients.claim()); +}); + +self.addEventListener('message', function(event) { + if (event.data.reset) { + resetRecords(); + } + if (event.data.port) { + const {requests, errors} = getRecords(); + event.data.port.postMessage({requests, errors}); + } +}); diff --git a/testing/web-platform/tests/service-workers/service-worker/tentative/static-router/resources/static-router-race-network-and-fetch-handler-sw.js b/testing/web-platform/tests/service-workers/service-worker/tentative/static-router/resources/static-router-race-network-and-fetch-handler-sw.js new file mode 100644 index 0000000000..468116eea8 --- /dev/null +++ b/testing/web-platform/tests/service-workers/service-worker/tentative/static-router/resources/static-router-race-network-and-fetch-handler-sw.js @@ -0,0 +1,57 @@ +'use strict'; + +import {routerRules} from './router-rules.js'; +import { + recordRequest, + recordError, + getRecords, + resetRecords } from './static-router-sw.sub.js'; + +import './imported-sw.js'; + +self.addEventListener('install', async e => { + e.waitUntil(caches.open('v1').then( + cache => {cache.put('cache.txt', new Response('From cache'))})); + + const params = new URLSearchParams(location.search); + const key = params.get('key'); + try { + await e.addRoutes(routerRules[key]); + } catch (e) { + recordError(e); + } + self.skipWaiting(); +}); + +self.addEventListener('activate', e => { + e.waitUntil(clients.claim()); +}); + +self.addEventListener('fetch', function(event) { + recordRequest(event.request); + const url = new URL(event.request.url); + + + // Force slow response + if (url.searchParams.has('sw_slow')) { + const start = Date.now(); + while (true) { + if (Date.now() - start > 200) { + break; + } + } + } + + const nonce = url.searchParams.get('nonce'); + event.respondWith(new Response(nonce)); +}); + +self.addEventListener('message', function(event) { + if (event.data.reset) { + resetRecords(); + } + if (event.data.port) { + const {requests, errors} = getRecords(); + event.data.port.postMessage({requests, errors}); + } +}); diff --git a/testing/web-platform/tests/service-workers/service-worker/tentative/static-router/resources/static-router-sw.js b/testing/web-platform/tests/service-workers/service-worker/tentative/static-router/resources/static-router-sw.js new file mode 100644 index 0000000000..07409ec42c --- /dev/null +++ b/testing/web-platform/tests/service-workers/service-worker/tentative/static-router/resources/static-router-sw.js @@ -0,0 +1,45 @@ +'use strict'; + +import {routerRules} from './router-rules.js'; +import { + recordRequest, + recordError, + getRecords, + resetRecords } from './static-router-sw.sub.js'; + +import './imported-sw.js'; + +self.addEventListener('install', async e => { + e.waitUntil(caches.open('v1').then( + cache => {cache.put('cache.txt', new Response('From cache'))})); + + const params = new URLSearchParams(location.search); + const key = params.get('key'); + try { + await e.addRoutes(routerRules[key]); + } catch (e) { + recordError(e); + } + self.skipWaiting(); +}); + +self.addEventListener('activate', e => { + e.waitUntil(clients.claim()); +}); + +self.addEventListener('fetch', function(event) { + recordRequest(event.request); + const url = new URL(event.request.url); + const nonce = url.searchParams.get('nonce'); + event.respondWith(new Response(nonce)); +}); + +self.addEventListener('message', function(event) { + if (event.data.reset) { + resetRecords(); + } + if (event.data.port) { + const {requests, errors} = getRecords(); + event.data.port.postMessage({requests, errors}); + } +}); diff --git a/testing/web-platform/tests/service-workers/service-worker/tentative/static-router/resources/static-router-sw.sub.js b/testing/web-platform/tests/service-workers/service-worker/tentative/static-router/resources/static-router-sw.sub.js new file mode 100644 index 0000000000..04f9c5533a --- /dev/null +++ b/testing/web-platform/tests/service-workers/service-worker/tentative/static-router/resources/static-router-sw.sub.js @@ -0,0 +1,29 @@ +let requests = []; +let errors = []; + +const recordRequest = req => { + requests.push({url: req.url, mode: req.mode, destination: req.destination}); +}; + +const recordError = (error) => { + errors.push(error); +}; + +const getRecords = () => { + return { + requests, + errors + }; +} + +const resetRecords = () => { + requests = []; + errors = []; +} + +export { + recordRequest, + recordError, + getRecords, + resetRecords +}; diff --git a/testing/web-platform/tests/service-workers/service-worker/tentative/static-router/resources/test-helpers.sub.js b/testing/web-platform/tests/service-workers/service-worker/tentative/static-router/resources/test-helpers.sub.js new file mode 100644 index 0000000000..64a7f7d24f --- /dev/null +++ b/testing/web-platform/tests/service-workers/service-worker/tentative/static-router/resources/test-helpers.sub.js @@ -0,0 +1,303 @@ +// Copied from +// service-workers/service-worker/resources/testharness-helpers.js to be used under tentative. + +// Adapter for testharness.js-style tests with Service Workers + +/** + * @param options an object that represents RegistrationOptions except for scope. + * @param options.type a WorkerType. + * @param options.updateViaCache a ServiceWorkerUpdateViaCache. + * @see https://w3c.github.io/ServiceWorker/#dictdef-registrationoptions + */ +function service_worker_unregister_and_register(test, url, scope, options) { + if (!scope || scope.length == 0) + return Promise.reject(new Error('tests must define a scope')); + + if (options && options.scope) + return Promise.reject(new Error('scope must not be passed in options')); + + options = Object.assign({ scope: scope }, options); + return service_worker_unregister(test, scope) + .then(function() { + return navigator.serviceWorker.register(url, options); + }) + .catch(unreached_rejection(test, + 'unregister and register should not fail')); +} + +// This unregisters the registration that precisely matches scope. Use this +// when unregistering by scope. If no registration is found, it just resolves. +function service_worker_unregister(test, scope) { + var absoluteScope = (new URL(scope, window.location).href); + return navigator.serviceWorker.getRegistration(scope) + .then(function(registration) { + if (registration && registration.scope === absoluteScope) + return registration.unregister(); + }) + .catch(unreached_rejection(test, 'unregister should not fail')); +} + +function service_worker_unregister_and_done(test, scope) { + return service_worker_unregister(test, scope) + .then(test.done.bind(test)); +} + +function unreached_fulfillment(test, prefix) { + return test.step_func(function(result) { + var error_prefix = prefix || 'unexpected fulfillment'; + assert_unreached(error_prefix + ': ' + result); + }); +} + +// Rejection-specific helper that provides more details +function unreached_rejection(test, prefix) { + return test.step_func(function(error) { + var reason = error.message || error.name || error; + var error_prefix = prefix || 'unexpected rejection'; + assert_unreached(error_prefix + ': ' + reason); + }); +} + +/** + * Adds an iframe to the document and returns a promise that resolves to the + * iframe when it finishes loading. The caller is responsible for removing the + * iframe later if needed. + * + * @param {string} url + * @returns {HTMLIFrameElement} + */ +function with_iframe(url) { + return new Promise(function(resolve) { + var frame = document.createElement('iframe'); + frame.className = 'test-iframe'; + frame.src = url; + frame.onload = function() { resolve(frame); }; + document.body.appendChild(frame); + }); +} + +function normalizeURL(url) { + return new URL(url, self.location).toString().replace(/#.*$/, ''); +} + +function wait_for_update(test, registration) { + if (!registration || registration.unregister == undefined) { + return Promise.reject(new Error( + 'wait_for_update must be passed a ServiceWorkerRegistration')); + } + + return new Promise(test.step_func(function(resolve) { + var handler = test.step_func(function() { + registration.removeEventListener('updatefound', handler); + resolve(registration.installing); + }); + registration.addEventListener('updatefound', handler); + })); +} + +// Return true if |state_a| is more advanced than |state_b|. +function is_state_advanced(state_a, state_b) { + if (state_b === 'installing') { + switch (state_a) { + case 'installed': + case 'activating': + case 'activated': + case 'redundant': + return true; + } + } + + if (state_b === 'installed') { + switch (state_a) { + case 'activating': + case 'activated': + case 'redundant': + return true; + } + } + + if (state_b === 'activating') { + switch (state_a) { + case 'activated': + case 'redundant': + return true; + } + } + + if (state_b === 'activated') { + switch (state_a) { + case 'redundant': + return true; + } + } + return false; +} + +function wait_for_state(test, worker, state) { + if (!worker || worker.state == undefined) { + return Promise.reject(new Error( + 'wait_for_state needs a ServiceWorker object to be passed.')); + } + if (worker.state === state) + return Promise.resolve(state); + + if (is_state_advanced(worker.state, state)) { + return Promise.reject(new Error( + `Waiting for ${state} but the worker is already ${worker.state}.`)); + } + return new Promise(test.step_func(function(resolve, reject) { + worker.addEventListener('statechange', test.step_func(function() { + if (worker.state === state) + resolve(state); + + if (is_state_advanced(worker.state, state)) { + reject(new Error( + `The state of the worker becomes ${worker.state} while waiting` + + `for ${state}.`)); + } + })); + })); +} + +// Declare a test that runs entirely in the ServiceWorkerGlobalScope. The |url| +// is the service worker script URL. This function: +// - Instantiates a new test with the description specified in |description|. +// The test will succeed if the specified service worker can be successfully +// registered and installed. +// - Creates a new ServiceWorker registration with a scope unique to the current +// document URL. Note that this doesn't allow more than one +// service_worker_test() to be run from the same document. +// - Waits for the new worker to begin installing. +// - Imports tests results from tests running inside the ServiceWorker. +function service_worker_test(url, description) { + // If the document URL is https://example.com/document and the script URL is + // https://example.com/script/worker.js, then the scope would be + // https://example.com/script/scope/document. + var scope = new URL('scope' + window.location.pathname, + new URL(url, window.location)).toString(); + promise_test(function(test) { + return service_worker_unregister_and_register(test, url, scope) + .then(function(registration) { + add_completion_callback(function() { + registration.unregister(); + }); + return wait_for_update(test, registration) + .then(function(worker) { + return fetch_tests_from_worker(worker); + }); + }); + }, description); +} + +function base_path() { + return location.pathname.replace(/\/[^\/]*$/, '/'); +} + +function test_login(test, origin, username, password, cookie) { + return new Promise(function(resolve, reject) { + with_iframe( + origin + base_path() + + 'resources/fetch-access-control-login.html') + .then(test.step_func(function(frame) { + var channel = new MessageChannel(); + channel.port1.onmessage = test.step_func(function() { + frame.remove(); + resolve(); + }); + frame.contentWindow.postMessage( + {username: username, password: password, cookie: cookie}, + origin, [channel.port2]); + })); + }); +} + +function test_websocket(test, frame, url) { + return new Promise(function(resolve, reject) { + var ws = new frame.contentWindow.WebSocket(url, ['echo', 'chat']); + var openCalled = false; + ws.addEventListener('open', test.step_func(function(e) { + assert_equals(ws.readyState, 1, "The WebSocket should be open"); + openCalled = true; + ws.close(); + }), true); + + ws.addEventListener('close', test.step_func(function(e) { + assert_true(openCalled, "The WebSocket should be closed after being opened"); + resolve(); + }), true); + + ws.addEventListener('error', reject); + }); +} + +function login_https(test) { + var host_info = get_host_info(); + return test_login(test, host_info.HTTPS_REMOTE_ORIGIN, + 'username1s', 'password1s', 'cookie1') + .then(function() { + return test_login(test, host_info.HTTPS_ORIGIN, + 'username2s', 'password2s', 'cookie2'); + }); +} + +function websocket(test, frame) { + return test_websocket(test, frame, get_websocket_url()); +} + +function get_websocket_url() { + return 'wss://{{host}}:{{ports[wss][0]}}/echo'; +} + +// The navigator.serviceWorker.register() method guarantees that the newly +// installing worker is available as registration.installing when its promise +// resolves. However some tests test installation using a <link> element where +// it is possible for the installing worker to have already become the waiting +// or active worker. So this method is used to get the newest worker when these +// tests need access to the ServiceWorker itself. +function get_newest_worker(registration) { + if (registration.installing) + return registration.installing; + if (registration.waiting) + return registration.waiting; + if (registration.active) + return registration.active; +} + +function register_using_link(script, options) { + var scope = options.scope; + var link = document.createElement('link'); + link.setAttribute('rel', 'serviceworker'); + link.setAttribute('href', script); + link.setAttribute('scope', scope); + document.getElementsByTagName('head')[0].appendChild(link); + return new Promise(function(resolve, reject) { + link.onload = resolve; + link.onerror = reject; + }) + .then(() => navigator.serviceWorker.getRegistration(scope)); +} + +function with_sandboxed_iframe(url, sandbox) { + return new Promise(function(resolve) { + var frame = document.createElement('iframe'); + frame.sandbox = sandbox; + frame.src = url; + frame.onload = function() { resolve(frame); }; + document.body.appendChild(frame); + }); +} + +// Registers, waits for activation, then unregisters on a sample scope. +// +// This can be used to wait for a period of time needed to register, +// activate, and then unregister a service worker. When checking that +// certain behavior does *NOT* happen, this is preferable to using an +// arbitrary delay. +async function wait_for_activation_on_sample_scope(t, window_or_workerglobalscope) { + const script = '/service-workers/service-worker/resources/empty-worker.js'; + const scope = 'resources/there/is/no/there/there?' + Date.now(); + let registration = await window_or_workerglobalscope.navigator.serviceWorker.register(script, { scope }); + await wait_for_state(t, registration.installing, 'activated'); + await registration.unregister(); +} + diff --git a/testing/web-platform/tests/service-workers/service-worker/tentative/static-router/static-router-fetch-event.https.html b/testing/web-platform/tests/service-workers/service-worker/tentative/static-router/static-router-fetch-event.https.html new file mode 100644 index 0000000000..167e3af009 --- /dev/null +++ b/testing/web-platform/tests/service-workers/service-worker/tentative/static-router/static-router-fetch-event.https.html @@ -0,0 +1,39 @@ +<!DOCTYPE html> +<meta charset="utf-8"> +<title> + Static Router: routers are evaluated with the fetch-event source. +</title> +<script src="/common/get-host-info.sub.js"></script> +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> +<script src="/service-workers/service-worker/resources/test-helpers.sub.js"> +</script> +<script src="resources/static-router-helpers.sub.js"> +</script> +<body> +<script> +const ROUTER_KEY = 'condition-urlpattern-string-source-fetch-event'; +const REGISTERED_ROUTE = 'resources/simple.html'; + +promise_test(async t => { + const worker = await registerAndActivate(t, ROUTER_KEY); + const rnd = randomString(); + const iframe = await createIframe(t, `${REGISTERED_ROUTE}?nonce=${rnd}`); + const {errors, requests} = await get_info_from_worker(worker); + + assert_equals(errors.length, 0); + assert_equals(requests.length, 1); + assert_equals(iframe.contentWindow.document.body.innerText, rnd); +}, 'Main resource matched the rule with fetch-event source'); + +iframeTest(REGISTERED_ROUTE, ROUTER_KEY, async (t, iwin, worker) => { + const rnd = randomString(); + const response = await iwin.fetch(`?nonce=${rnd}`); + assert_equals(response.status, 200); + assert_equals(await response.text(), rnd); + const {requests} = await get_info_from_worker(worker); + // Main resource request + subreosurce request = 2. + assert_equals(requests.length, 2); +}, 'Subresource load matched the rule fetch-event source'); +</script> +</body> diff --git a/testing/web-platform/tests/service-workers/service-worker/tentative/static-router/static-router-invalid-rules.https.html b/testing/web-platform/tests/service-workers/service-worker/tentative/static-router/static-router-invalid-rules.https.html new file mode 100644 index 0000000000..4ed4ad4b3c --- /dev/null +++ b/testing/web-platform/tests/service-workers/service-worker/tentative/static-router/static-router-invalid-rules.https.html @@ -0,0 +1,29 @@ +<!DOCTYPE html> +<meta charset="utf-8"> +<title> + Static Router: registration of invalid rules should raise. +</title> +<script src="/common/get-host-info.sub.js"></script> +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> +<script src="/service-workers/service-worker/resources/test-helpers.sub.js"> +</script> +<script src="resources/static-router-helpers.sub.js"> +</script> +<body> +<script> + +const ROUTER_RULE_KEY_INVALID_REQUEST_METHOD = + 'condition-invalid-request-method'; +const ROUTER_RULE_KEY_SOURCE_FETCH_EVENT = + 'condition-request-source-fetch-event'; + +promise_test(async t => { + const worker = await registerAndActivate(t, ROUTER_RULE_KEY_INVALID_REQUEST_METHOD); + t.add_cleanup(() => {reset_info_in_worker(worker)}); + const {errors} = await get_info_from_worker(worker); + assert_equals(errors.length, 1); +}, 'addRoutes should raise for invalid request method.'); + +</script> +</body> diff --git a/testing/web-platform/tests/service-workers/service-worker/tentative/static-router/static-router-main-resource.https.html b/testing/web-platform/tests/service-workers/service-worker/tentative/static-router/static-router-main-resource.https.html new file mode 100644 index 0000000000..fc93a4f7c9 --- /dev/null +++ b/testing/web-platform/tests/service-workers/service-worker/tentative/static-router/static-router-main-resource.https.html @@ -0,0 +1,69 @@ +<!DOCTYPE html> +<meta charset="utf-8"> +<title> + Static Router: simply skip fetch handler for main resource if pattern matches +</title> +<script src="/common/get-host-info.sub.js"></script> +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> +<script src="resources/test-helpers.sub.js"></script> +<script src="resources/static-router-helpers.sub.js"></script> +<body> +<script> +const ROUTER_RULE_KEY = 'condition-urlpattern-constructed-source-network'; +const ROUTER_RULE_KEY_IGNORE_CASE = + 'condition-urlpattern-constructed-ignore-case-source-network'; +const ROUTER_RULE_KEY_RESPECT_CASE = + 'condition-urlpattern-constructed-respect-case-source-network'; +const ROUTER_RULE_KEY_URLPATTERN_CACHE = + 'condition-urlpattern-string-source-cache'; +const ROUTER_RULE_KEY_REQUEST_CACHE = 'condition-request-navigate-source-cache'; +const REGISTERED_ROUTE = 'resources/direct.txt'; +const CACHED_ROUTE = 'resources/cache.txt'; +const NON_REGISTERED_ROUTE = 'resources/simple.html'; +const host_info = get_host_info(); +const path = new URL(".", window.location).pathname; + +iframeTest(REGISTERED_ROUTE, ROUTER_RULE_KEY, async (t, iwin, worker) => { + const {requests} = await get_info_from_worker(worker); + assert_equals(requests.length, 0); + assert_equals(iwin.document.body.innerText, "Network\n"); +}, 'Main resource load matched with the condition'); + +iframeTest(REGISTERED_ROUTE, ROUTER_RULE_KEY_IGNORE_CASE, async (t, iwin, worker) => { + const {requests} = await get_info_from_worker(worker); + assert_equals(requests.length, 0); + assert_equals(iwin.document.body.innerText, "Network\n"); +}, 'Main resource load matched with the ignore case condition'); + +iframeTest(REGISTERED_ROUTE, ROUTER_RULE_KEY_RESPECT_CASE, async (t, iwin, worker) => { + const {requests} = await get_info_from_worker(worker); + assert_equals(requests.length, 1); +}, 'Main resource load matched without the ignore case condition'); + +iframeTest(NON_REGISTERED_ROUTE, ROUTER_RULE_KEY, async (t, iwin, worker) => { + const {requests} = await get_info_from_worker(worker); + assert_equals(requests.length, 1); + assert_equals( + requests[0].url, + `${host_info['HTTPS_ORIGIN']}${path}${NON_REGISTERED_ROUTE}`); + assert_equals(requests[0].mode, 'navigate'); +}, 'Main resource load not matched with the condition'); + +iframeTest(CACHED_ROUTE, ROUTER_RULE_KEY_URLPATTERN_CACHE, async (t, iwin, worker) => { + const {requests} = await get_info_from_worker(worker); + assert_equals(requests.length, 0); + assert_equals(iwin.document.body.innerText, "From cache"); +}, 'Main resource load matched with the cache source'); + +iframeTest(NON_REGISTERED_ROUTE, ROUTER_RULE_KEY_REQUEST_CACHE, async (t, iwin, worker) => { + const {requests} = await get_info_from_worker(worker); + // When the request matched to the rule with the "cache" source but failed to + // get the cache entry, the fetch handler is not involved and the network + // fallback is triggered instead. + assert_equals(requests.length, 0); + assert_equals(iwin.document.body.innerText, "Here's a simple html file."); +}, 'Main resource fallback to the network when there is no cache entry'); + +</script> +</body> diff --git a/testing/web-platform/tests/service-workers/service-worker/tentative/static-router/static-router-multiple-router-registrations.https.html b/testing/web-platform/tests/service-workers/service-worker/tentative/static-router/static-router-multiple-router-registrations.https.html new file mode 100644 index 0000000000..dd7ff1e4e9 --- /dev/null +++ b/testing/web-platform/tests/service-workers/service-worker/tentative/static-router/static-router-multiple-router-registrations.https.html @@ -0,0 +1,57 @@ +<!DOCTYPE html> +<meta charset="utf-8"> +<title> + Static Router: routers are registered multiple times. +</title> +<script src="/common/get-host-info.sub.js"></script> +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> +<script src="/service-workers/service-worker/resources/test-helpers.sub.js"> +</script> +<script src="resources/static-router-helpers.sub.js"> +</script> +<body> +<script> +const ROUTER_KEY_MULTIPLE_RULES = 'multiple-router-rules'; +const ROUTER_KEY_1 = 'condition-urlpattern-string-source-network'; +const ROUTER_KEY_2 = 'condition-request-method-post-network'; + +const REGISTERED_ROUTE_1 = 'resources/direct.txt'; +const REGISTERED_ROUTE_2 = 'resources/direct.html'; +const REGISTERED_ROUTE_3 = 'direct.py'; + +promise_test(async t => { + const worker = await registerAndActivate(t, ROUTER_KEY_MULTIPLE_RULES); + + // Matched with the first rule. + const iframe = await createIframe(t, REGISTERED_ROUTE_1); + assert_equals(iframe.contentWindow.document.body.innerText, "Network\n"); + + // Matched with the second rule. + const second_iframe = await createIframe(t, REGISTERED_ROUTE_2); + assert_equals(second_iframe.contentWindow.document.body.innerText, "Here's a direct html from network."); + + const {requests} = await get_info_from_worker(worker); + assert_equals(requests.length, 0); +}, 'Main reosurce load matched with the service worker having multiple rules'); + +promise_test(async t => { + const worker = await registerAndActivate(t, + `${ROUTER_KEY_1}&imported-sw-router-key=${ROUTER_KEY_2}`); + + // Matched with the first rule. + const iframe = await createIframe(t, REGISTERED_ROUTE_1); + assert_equals(iframe.contentWindow.document.body.innerText, "Network\n"); + let info = await get_info_from_worker(worker); + assert_equals(info.requests.length, 0); + + // Matched with the second rule, which is registered in the service worker + // loaded via `import` by the main script. + const response = await iframe.contentWindow.fetch(REGISTERED_ROUTE_3, {method: 'POST'}); + assert_equals(response.status, 200); + assert_equals(await response.text(), "Network with POST request"); + info = await get_info_from_worker(worker); + assert_equals(info.requests.length, 0); +}, 'Resource load matched with the rule registered in the imported service worker'); +</script> +</body> diff --git a/testing/web-platform/tests/service-workers/service-worker/tentative/static-router/static-router-no-fetch-handler.https.html b/testing/web-platform/tests/service-workers/service-worker/tentative/static-router/static-router-no-fetch-handler.https.html new file mode 100644 index 0000000000..e98dd08a90 --- /dev/null +++ b/testing/web-platform/tests/service-workers/service-worker/tentative/static-router/static-router-no-fetch-handler.https.html @@ -0,0 +1,48 @@ +<!DOCTYPE html> +<meta charset="utf-8"> +<title> + Static Router: routers are evaluated when there is no fetch handler. +</title> +<script src="/common/get-host-info.sub.js"></script> +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> +<script src="/service-workers/service-worker/resources/test-helpers.sub.js"> +</script> +<script src="resources/static-router-helpers.sub.js"> +</script> +<body> +<script> +const RULE_KEY_SOURCE_CACHE = 'condition-urlpattern-string-source-cache'; +const RULE_KEY_SOURCE_FETCH_EVENT = + 'condition-request-source-fetch-event'; +const SW_SRC = 'resources/static-router-no-fetch-handler-sw.js'; +const CACHED_FILE = 'cache.txt'; + +promise_test(async t => { + const worker = await registerAndActivate(t, RULE_KEY_SOURCE_CACHE, SW_SRC); + + // Matched with the main reosurce load. + const {contentWindow} = await createIframe(t, `resources/${CACHED_FILE}`); + assert_equals(contentWindow.document.body.innerText, "From cache"); + + // Matched with the subreosurce load. + const response = await contentWindow.fetch(CACHED_FILE); + assert_equals(response.status, 200); + assert_equals(await response.text(), "From cache"); + + // Both requests are served from cache. + const {requests} = await get_info_from_worker(worker); + assert_equals(requests.length, 0); +}, 'The router rule is evaluated without fetch handlers in service worker'); + +promise_test(async t => { + const worker = + await registerAndActivate(t, RULE_KEY_SOURCE_FETCH_EVENT, SW_SRC); + t.add_cleanup(() => {reset_info_in_worker(worker)}); + + const {errors} = await get_info_from_worker(worker); + assert_equals(errors.length, 1); +}, 'addRoutes should raise if the fetch-event source is used without onfetch') + +</script> +</body> diff --git a/testing/web-platform/tests/service-workers/service-worker/tentative/static-router/static-router-race-network-and-fetch-handler.https.html b/testing/web-platform/tests/service-workers/service-worker/tentative/static-router/static-router-race-network-and-fetch-handler.https.html new file mode 100644 index 0000000000..0dad64ad99 --- /dev/null +++ b/testing/web-platform/tests/service-workers/service-worker/tentative/static-router/static-router-race-network-and-fetch-handler.https.html @@ -0,0 +1,91 @@ +<!DOCTYPE html> +<meta charset="utf-8"> +<title> + Static Router: routers are evaluated with the request desitnation condition. +</title> +<script src="/common/get-host-info.sub.js"></script> +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> +<script src="/service-workers/service-worker/resources/test-helpers.sub.js"> +</script> +<script src="resources/static-router-helpers.sub.js"> +</script> +<body> +<script> +const ROUTER_KEY = 'condition-urlpattern-string-source-race-network-and-fetch-handler'; +const SW_SRC = 'resources/static-router-race-network-and-fetch-handler-sw.js'; +const FRAME_SRC = 'resources/direct.py'; + +promise_test(async t => { + const rnd = randomString(); + const worker = await registerAndActivate(t, ROUTER_KEY, SW_SRC); + const iframe = await createIframe(t, `${FRAME_SRC}?nonce=${rnd}&server_slow`); + // Expect the response from the fetch handler. + assert_equals(iframe.contentWindow.document.body.innerText, rnd); + const {requests} = await get_info_from_worker(worker); + assert_equals(requests.length, 1); +}, 'Main resource load matched the rule with race-network-and-fetch-handler source, and the fetch handler response is faster than the server response'); + +promise_test(async t => { + const rnd = randomString(); + const worker = await registerAndActivate(t, ROUTER_KEY, SW_SRC); + const iframe = await createIframe(t, `${FRAME_SRC}?nonce=${rnd}&sw_slow`); + // Expect the response from the netowrk request. + assert_equals(iframe.contentWindow.document.body.innerText, "Network with GET request"); + // Ensure the fetch handler is also executed. + const {requests} = await get_info_from_worker(worker); + assert_equals(requests.length, 1); +}, 'Main resource load matched the rule with race-network-and-fetch-handler source, and the server reseponse is faster than the fetch handler'); + +promise_test(async t => { + const rnd = randomString(); + const worker = await registerAndActivate(t, ROUTER_KEY, SW_SRC); + const iframe = await createIframe(t, FRAME_SRC); + // Expect the response from the fetch handler. + const response = await iframe.contentWindow.fetch(`?nonce=${rnd}&server_slow`); + assert_equals(response.status, 200); + assert_equals(await response.text(), rnd); + const {requests} = await get_info_from_worker(worker); + assert_equals(requests.length, 2); +}, 'Subresource load matched the rule with race-network-and-fetch-handler source, and the fetch handler response is faster than the server response'); + +promise_test(async t => { + const rnd = randomString(); + const worker = await registerAndActivate(t, ROUTER_KEY, SW_SRC); + const iframe = await createIframe(t, FRAME_SRC); + // Expect the response from the network request. + const response = await iframe.contentWindow.fetch(`?nonce=${rnd}&sw_slow`); + assert_equals(response.status, 200); + assert_equals(await response.text(), "Network with GET request"); + // Ensure the fetch handler is also executed. + const {requests} = await get_info_from_worker(worker); + assert_equals(requests.length, 2); +}, 'Subresource load matched the rule with race-network-and-fetch-handler source, and the server reseponse is faster than the fetch handler'); + +promise_test(async t => { + const rnd = randomString(); + const worker = await registerAndActivate(t, ROUTER_KEY, SW_SRC); + const iframe = await createIframe(t, FRAME_SRC); + // Expect the response from the network request. + const response = await iframe.contentWindow.fetch(`?nonce=${rnd}&sw_slow&server_no_content`); + assert_equals(response.status, 204); + // Ensure the fetch handler is also executed. + const {requests} = await get_info_from_worker(worker); + assert_equals(requests.length, 2); +}, 'Subresource load matched the rule with race-network-and-fetch-handler source, and the server reseponse with 204 response is faster than the fetch handler'); + + +promise_test(async t => { + const rnd = randomString(); + const worker = await registerAndActivate(t, ROUTER_KEY, SW_SRC); + const iframe = await createIframe(t, FRAME_SRC); + const response = await iframe.contentWindow.fetch(`?nonce=${rnd}&sw_slow&server_not_found`); + // Expect the response from the network request was faster, but the result was 404. + // So, the fetch handler result will be used instead. + assert_equals(response.status, 200); + assert_equals(await response.text(), rnd); + const {requests} = await get_info_from_worker(worker); + assert_equals(requests.length, 2); +}, 'Subresource load matched the rule with race-network-and-fetch-handler source, and the server reseponse is faster than the fetch handler, but not found'); +</script> +</body> diff --git a/testing/web-platform/tests/service-workers/service-worker/tentative/static-router/static-router-request-destination.https.html b/testing/web-platform/tests/service-workers/service-worker/tentative/static-router/static-router-request-destination.https.html new file mode 100644 index 0000000000..55ad6da31a --- /dev/null +++ b/testing/web-platform/tests/service-workers/service-worker/tentative/static-router/static-router-request-destination.https.html @@ -0,0 +1,77 @@ +<!DOCTYPE html> +<meta charset="utf-8"> +<title> + Static Router: routers are evaluated with the request desitnation condition. +</title> +<script src="/common/get-host-info.sub.js"></script> +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> +<script src="/service-workers/service-worker/resources/test-helpers.sub.js"> +</script> +<script src="resources/static-router-helpers.sub.js"> +</script> +<body> +<script> +const ROUTER_KEY_DESTINATION_SCRIPT = 'condition-request-destination-script-network'; +const FRAME_SRC = 'resources/direct.html'; +const SCRIPT_SRC = 'direct.js'; +const STYLE_SRC = 'direct.txt'; + +const appendScript = async (iwin, src) => { + const promise = new Promise(resolve => { + const script = iwin.document.createElement('script'); + script.src = src; + iwin.document.body.appendChild(script); + script.onload = () => { + resolve(script); + }; + }); + + return promise; +}; + +const appendCSS = async (iwin, src) => { + const promise = new Promise(resolve => { + const link = iwin.document.createElement('link'); + link.rel = 'stylesheet'; + link.href = src; + iwin.document.head.appendChild(link); + link.onload = () => { + resolve(link); + }; + }); + + return promise; +}; + +promise_test(async t => { + const worker = await registerAndActivate(t, ROUTER_KEY_DESTINATION_SCRIPT); + const iframe = await createIframe(t, FRAME_SRC); + + let info = await get_info_from_worker(worker); + assert_equals(info.requests.length, 1); + assert_equals(info.requests[0].destination, 'iframe'); + + // JavaScript is not handled by fetch handler. + await appendScript(iframe.contentWindow, SCRIPT_SRC); + assert_equals(iframe.contentWindow.router_condition_request_destination_script, true); + info = await get_info_from_worker(worker); + assert_equals(info.requests.length, 1); +}, 'Subreosurce load matched with the requestMethod script condition'); + +promise_test(async t => { + const worker = await registerAndActivate(t, ROUTER_KEY_DESTINATION_SCRIPT); + const iframe = await createIframe(t, FRAME_SRC); + + let info = await get_info_from_worker(worker); + assert_equals(info.requests.length, 1); + assert_equals(info.requests[0].destination, 'iframe'); + + // Stylesheet is not handled by fetch handler. + await appendCSS(iframe.contentWindow, STYLE_SRC); + info = await get_info_from_worker(worker); + assert_equals(info.requests.length, 2); + assert_equals(info.requests[1].destination, 'style'); +}, 'Subreosurce load not matched with the requestMethod script condition'); +</script> +</body> diff --git a/testing/web-platform/tests/service-workers/service-worker/tentative/static-router/static-router-request-method.https.html b/testing/web-platform/tests/service-workers/service-worker/tentative/static-router/static-router-request-method.https.html new file mode 100644 index 0000000000..8e219532a3 --- /dev/null +++ b/testing/web-platform/tests/service-workers/service-worker/tentative/static-router/static-router-request-method.https.html @@ -0,0 +1,59 @@ +<!DOCTYPE html> +<meta charset="utf-8"> +<title> + Static Router: routers are evaluated with the request method condition. +</title> +<script src="/common/get-host-info.sub.js"></script> +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> +<script src="/service-workers/service-worker/resources/test-helpers.sub.js"> +</script> +<script src="resources/static-router-helpers.sub.js"> +</script> +<body> +<script> +const ROUTER_KEY_MEHOD_GET = 'condition-request-method-get-network'; +const ROUTER_KEY_MEHOD_POST = 'condition-request-method-post-network'; +const ROUTER_KEY_MEHOD_PUT = 'condition-request-method-put-network'; +const ROUTER_KEY_MEHOD_DELETE = 'condition-request-method-delete-network'; +const REQUET_SRC = 'resources/direct.py'; + +iframeTest(REQUET_SRC, ROUTER_KEY_MEHOD_GET, async (t, iwin, worker) => { + const rnd = randomString(); + const response = await iwin.fetch('?nonce=' + rnd); + assert_equals(await response.text(), "Network with GET request"); + const {requests} = await get_info_from_worker(worker); + assert_equals(requests.length, 0); +}, 'Subresource load matched with the requestMethod GET condition'); + +iframeTest(REQUET_SRC, ROUTER_KEY_MEHOD_POST, async (t, iwin, worker) => { + const rnd = randomString(); + const response = await iwin.fetch('?nonce=' + rnd, {method: 'POST'}); + assert_equals(await response.text(), "Network with POST request"); + const {requests} = await get_info_from_worker(worker); + // The navigation request is the only request handled by fetch handler. + assert_equals(requests.length, 1); + assert_equals(requests[0].mode, 'navigate'); +}, 'Subresource load matched with the requestMethod POST condition'); + +iframeTest(REQUET_SRC, ROUTER_KEY_MEHOD_PUT, async (t, iwin, worker) => { + const rnd = randomString(); + const response = await iwin.fetch('?nonce=' + rnd, {method: 'PUT'}); + assert_equals(await response.text(), "Network with PUT request"); + const {requests} = await get_info_from_worker(worker); + // The navigation request is the only request handled by fetch handler. + assert_equals(requests.length, 1); + assert_equals(requests[0].mode, 'navigate'); +}, 'Subresource load matched with the requestMethod PUT condition'); + +iframeTest(REQUET_SRC, ROUTER_KEY_MEHOD_DELETE, async (t, iwin, worker) => { + const rnd = randomString(); + const response = await iwin.fetch('?nonce=' + rnd, {method: 'DELETE'}); + assert_equals(await response.text(), "Network with DELETE request"); + const {requests} = await get_info_from_worker(worker); + // The navigation request is the only request handled by fetch handler. + assert_equals(requests.length, 1); + assert_equals(requests[0].mode, 'navigate'); +}, 'Subresource load matched with the requestMethod DELETE condition'); +</script> +</body> diff --git a/testing/web-platform/tests/service-workers/service-worker/tentative/static-router/static-router-subresource.https.html b/testing/web-platform/tests/service-workers/service-worker/tentative/static-router/static-router-subresource.https.html new file mode 100644 index 0000000000..3f7902a872 --- /dev/null +++ b/testing/web-platform/tests/service-workers/service-worker/tentative/static-router/static-router-subresource.https.html @@ -0,0 +1,154 @@ +<!DOCTYPE html> +<meta charset="utf-8"> +<title>Static Router: simply skip fetch handler if pattern matches</title> +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> +<script src="resources/test-helpers.sub.js"></script> +<script src="/common/get-host-info.sub.js"></script> +<script src="resources/static-router-helpers.sub.js"></script> +<body> +<script> +const SCRIPT = 'resources/static-router-sw.js'; +const ROUTER_RULE_KEY_URL_PATTERN_CONSTRUCTED = + 'condition-urlpattern-constructed-source-network'; +const ROUTER_RULE_KEY_URL_PATTERN_CONSTRUCTED_IGNORE_CASE = + 'condition-urlpattern-constructed-ignore-case-source-network'; +const ROUTER_RULE_KEY_URL_PATTERN_CONSTRUCTED_RESPECT_CASE = + 'condition-urlpattern-constructed-respect-case-source-network'; +const ROUTER_RULE_KEY_URL_PATTERN_URLPATTERNINIT = + 'condition-urlpattern-urlpatterninit-source-network'; +const ROUTER_RULE_KEY_URL_PATTERN_STRING = + 'condition-urlpattern-string-source-network'; +const ROUTER_RULE_KEY_REQUEST = 'condition-request-source-network' +const ROUTER_RULE_KEY_URL_PATTERN_STRING_CACHE = + 'condition-urlpattern-string-source-cache'; +const ROUTER_RULE_KEY_OR = 'condition-or-source-network' +const SCOPE = 'resources/'; +const HTML_FILE = 'resources/simple.html'; +const TXT_FILE = 'resources/direct.txt'; +const CSV_FILE = 'resources/simple.csv'; +// Warning: please prepare the corresponding `*.text.headers` files, otherwise +// iframeTest() fails to load the following files due to MIME mismatches. +const OR_TEST_FILES = [ + 'resources/or-test/direct1.text', + 'resources/or-test/direct2.text', + 'resources/or-test/does-not-exist.text', +]; + +iframeTest(HTML_FILE, ROUTER_RULE_KEY_URL_PATTERN_CONSTRUCTED, async (t, iwin) => { + const rnd = randomString(); + const response = await iwin.fetch('?nonce=' + rnd); + assert_equals(await response.text(), rnd); +}, 'Subresource load not matched with URLPattern condition'); + +iframeTest(TXT_FILE, ROUTER_RULE_KEY_URL_PATTERN_CONSTRUCTED, async (t, iwin) => { + const rnd = randomString(); + const response = await iwin.fetch('?nonce=' + rnd); + assert_equals(await response.text(), "Network\n"); +}, 'Subresource load matched with URLPattern condition'); + +iframeTest(TXT_FILE, ROUTER_RULE_KEY_URL_PATTERN_CONSTRUCTED, async (t, iwin, worker) => { + const rnd = randomString(); + // Confirm that the given URLPatternInit has a wildcard pattern for the + // hostname. Also, if |urlPattern| is a consutructed URLPattern object, + // baseURL won't be set while adding router rules, thus it matches the cross + // origin request as far as other components matches. So expecting the direct + // network request and the fetch handler doesn't capture the response. + // The response is going to be a opaque. + const origin = get_host_info().HTTPS_REMOTE_ORIGIN; + const response = await iwin.fetch( + `${origin}/${TXT_FILE}?nonce=${rnd}`, {mode: 'no-cors'}); + const {requests} = await get_info_from_worker(worker); + assert_equals(requests.length, 0); + assert_equals(response.type, 'opaque'); +}, 'Subresource cross origin load matched with URLPattern condition via constructed object'); + +iframeTest(TXT_FILE, ROUTER_RULE_KEY_URL_PATTERN_CONSTRUCTED_IGNORE_CASE, async (t, iwin) => { + const rnd = randomString(); + const response = await iwin.fetch('?nonce=' + rnd); + assert_equals(await response.text(), "Network\n"); +}, 'Subresource load matched with ignoreCase URLPattern condition'); + +iframeTest(TXT_FILE, ROUTER_RULE_KEY_URL_PATTERN_CONSTRUCTED_RESPECT_CASE, async (t, iwin) => { + const rnd = randomString(); + const response = await iwin.fetch('?nonce=' + rnd); + assert_equals(await response.text(), rnd); +}, 'Subresource load matched without ignoreCase URLPattern condition'); + +iframeTest(TXT_FILE, ROUTER_RULE_KEY_URL_PATTERN_URLPATTERNINIT, async (t, iwin) => { + const rnd = randomString(); + const response = await iwin.fetch('?nonce=' + rnd); + assert_equals(await response.text(), "Network\n"); +}, 'Subresource load matched with URLPattern condition via URLPatternInit'); + +iframeTest(TXT_FILE, ROUTER_RULE_KEY_URL_PATTERN_URLPATTERNINIT, async (t, iwin, worker) => { + // The SW script URL is added as a baseURL when |urlPattern| is passed via + // URLPatternInit, and there is not |baseURL| in it. Cross origin request will + // go through the fetch handler because |baseURL| info complements hostname + // with the hostname of the SW script. + const rnd = randomString(); + const origin = get_host_info().HTTPS_REMOTE_ORIGIN; + const response = await iwin.fetch(`${origin}/${TXT_FILE}?nonce=${rnd}`); + const {requests} = await get_info_from_worker(worker); + assert_equals(requests.length, 1); + assert_equals(await response.text(), rnd); +}, 'Subresource cross origin load not matched with URLPattern condition via URLPatternInit'); + +iframeTest(TXT_FILE, ROUTER_RULE_KEY_URL_PATTERN_STRING, async (t, iwin) => { + const rnd = randomString(); + const response = await iwin.fetch('?nonce=' + rnd); + assert_equals(await response.text(), "Network\n"); +}, 'Subresource load matched with URLPattern condition via string'); + +iframeTest(TXT_FILE, ROUTER_RULE_KEY_URL_PATTERN_STRING, async (t, iwin, worker) => { + // The SW script URL is added as a baseURL when |urlPattern| is passed via + // string, and there is not |baseURL| in it. Cross origin request will go + // through the fetch handler because |baseURL| info complements hostname with + // the hostname of the SW script. + const rnd = randomString(); + const origin = get_host_info().HTTPS_REMOTE_ORIGIN; + const response = await iwin.fetch(`${origin}/${TXT_FILE}?nonce=${rnd}`); + const {requests} = await get_info_from_worker(worker); + assert_equals(requests.length, 1); + assert_equals(await response.text(), rnd); +}, 'Subresource cross origin load not matched with URLPattern condition via string'); + +iframeTest(CSV_FILE, ROUTER_RULE_KEY_REQUEST, async (t, iwin) => { + const rnd = randomString(); + const response = await iwin.fetch('?nonce=' + rnd, { mode: 'no-cors' }); + assert_equals(await response.text(), "matched,with,non-url,conditions\n"); +}, 'Subresource load matched with RequestMode condition'); + +iframeTest(OR_TEST_FILES[0], ROUTER_RULE_KEY_OR, async (t, iwin) => { + const rnd = randomString(); + const response = await iwin.fetch('?nonce=' + rnd); + assert_equals(await response.text(), "Network\n"); +}, 'Subresource load matched with the nested `or` condition'); + +iframeTest(OR_TEST_FILES[1], ROUTER_RULE_KEY_OR, async (t, iwin) => { + const rnd = randomString(); + const response = await iwin.fetch('?nonce=' + rnd); + assert_equals(await response.text(), "Network\n"); +}, 'Subresource load matched with the next `or` condition'); + +iframeTest(OR_TEST_FILES[2], ROUTER_RULE_KEY_OR, async (t, iwin) => { + const rnd = randomString(); + const response = await iwin.fetch('?nonce=' + rnd); + assert_equals(await response.text(), rnd); +}, 'Subresource load not matched with `or` condition'); + +iframeTest(HTML_FILE, ROUTER_RULE_KEY_URL_PATTERN_STRING_CACHE, async (t, iwin) => { + // No need to set `resources/` because the request is dispatched from iframe. + const CACHED_FILE = 'cache.txt'; + const response = await iwin.fetch(CACHED_FILE); + assert_equals(response.status, 200); + assert_equals(await response.text(), "From cache"); + + // This doesn't match because the cache key is wrong. + const rnd = randomString(); + const response_with_param = await iwin.fetch(`${CACHED_FILE}?nonce=${rnd}`); + assert_equals(response_with_param.status, 404); +}, 'Subresource load matched with the cache source rule'); + +</script> +</body> |