From b0f8874718b3d59fd60f10fe14a1c267cf6d442c Mon Sep 17 00:00:00 2001 From: Matt Falkenhagen Date: Mon, 9 Apr 2018 00:44:34 -0700 Subject: [PATCH] service worker: Add tests for inteception of workers after redirects. This tests behavior discussed here: https://github.com/w3c/ServiceWorker/issues/1289 Namely it tests when a request for a worker goes through a redirect chain: 1) On redirect from A -> B, whether the service worker at B sees the request. 2) After the final redirect, which service worker controls the resulting client. The tests are written as specified today. Therefore, Firefox passes this test (verified in Nightly) and Chrome does not. (Actually a small change is required to the test to make Firefox pass it, see: https://bugzilla.mozilla.org/show_bug.cgi?id=1452528) Currently it only tests shared worker but dedicated worker can be added in a follow-up patch. Bug: 829720 Change-Id: Id3b1ea8b952760be0ef9917f2c6a3afe60ca1fb5 --- .../resources/scope1/redirect.py | 5 + .../worker_interception_redirect_webworker.py | 5 + ...ker-interception-redirect-serviceworker.js | 39 ++++ .../worker-interception-redirect-webworker.js | 30 ++++ .../worker_interception_redirect_webworker.py | 19 ++ .../worker-interception-redirect.https.html | 170 ++++++++++++++++++ 6 files changed, 268 insertions(+) create mode 100644 service-workers/service-worker/resources/scope1/redirect.py create mode 100644 service-workers/service-worker/resources/scope2/worker_interception_redirect_webworker.py create mode 100644 service-workers/service-worker/resources/worker-interception-redirect-serviceworker.js create mode 100644 service-workers/service-worker/resources/worker-interception-redirect-webworker.js create mode 100644 service-workers/service-worker/resources/worker_interception_redirect_webworker.py create mode 100644 service-workers/service-worker/worker-interception-redirect.https.html diff --git a/service-workers/service-worker/resources/scope1/redirect.py b/service-workers/service-worker/resources/scope1/redirect.py new file mode 100644 index 000000000000000..0663ca0ed04d907 --- /dev/null +++ b/service-workers/service-worker/resources/scope1/redirect.py @@ -0,0 +1,5 @@ +import os +import sys +# Use the file from the parent directory. +sys.path.append(os.path.dirname(os.path.dirname(__file__))) +from redirect import main diff --git a/service-workers/service-worker/resources/scope2/worker_interception_redirect_webworker.py b/service-workers/service-worker/resources/scope2/worker_interception_redirect_webworker.py new file mode 100644 index 000000000000000..99db1343bad2a86 --- /dev/null +++ b/service-workers/service-worker/resources/scope2/worker_interception_redirect_webworker.py @@ -0,0 +1,5 @@ +import os +import sys +# Use the file from the parent directory. +sys.path.append(os.path.dirname(os.path.dirname(__file__))) +from worker_interception_redirect_webworker import main diff --git a/service-workers/service-worker/resources/worker-interception-redirect-serviceworker.js b/service-workers/service-worker/resources/worker-interception-redirect-serviceworker.js new file mode 100644 index 000000000000000..b815442fd3c5b9c --- /dev/null +++ b/service-workers/service-worker/resources/worker-interception-redirect-serviceworker.js @@ -0,0 +1,39 @@ +let name; +if (self.registration.scope.indexOf('scope1') != -1) + name = 'sw1'; +if (self.registration.scope.indexOf('scope2') != -1) + name = 'sw2'; + + +self.addEventListener('fetch', evt => { + // There are three types of requests this service worker handles. + + // (1) The first request for the worker, which will redirect elsewhere. + // "redirect.py" means to test network redirect, so let network handle it. + if (evt.request.url.indexOf('redirect.py') != -1) { + return; + } + // "sw-redirect" means to test service worker redirect, so respond with a + // redirect. + if (evt.request.url.indexOf('sw-redirect') != -1) { + const url = new URL(evt.request.url); + const redirect_to = url.searchParams.get('Redirect'); + evt.respondWith(Response.redirect(redirect_to)); + return; + } + + // (2) After redirect, the request is for a "webworker.py" URL. + // Add a search parameter to indicate this service worker handled the + // final request for the worker. + if (evt.request.url.indexOf('webworker.py') != -1) { + const greeting = encodeURIComponent(`${name} saw the request for the worker script`); + evt.respondWith(fetch(`worker_interception_redirect_webworker.py?greeting=${greeting}`)); + return; + } + + // (3) The worker does a fetch() to simple.txt. Indicate that this service + // worker handled the request. + if (evt.request.url.indexOf('simple.txt') != -1) { + evt.respondWith(new Response(`${name} saw the fetch from the worker`)); + } +}); diff --git a/service-workers/service-worker/resources/worker-interception-redirect-webworker.js b/service-workers/service-worker/resources/worker-interception-redirect-webworker.js new file mode 100644 index 000000000000000..7863af70d7835e5 --- /dev/null +++ b/service-workers/service-worker/resources/worker-interception-redirect-webworker.js @@ -0,0 +1,30 @@ +// This is the (shared or dedicated) worker file for the +// worker-interception-redirect test. It should be served by the corresponding +// .py file instead of being served directly. +// +// This file is served from both resources/*webworker.py and +// resources/scope2/*webworker.py, hence some of the complexity +// below about paths. +const resources_url = new URL("/service-workers/service-worker/resources/", + self.location); + +// This greeting text is meant to be injected by the Python script that serves +// this file, to indicate how the script was served (from network or from +// service worker). +// +// We can't just use a sub pipe and name this file .sub.js since we want +// to serve the file from multiple URLs (see above). +let greeting = '%GREETING_TEXT%'; +if (!greeting) + greeting = 'the shared worker script was served from network'; + +self.onconnect = async function(e) { + const port = e.ports[0]; + port.start(); + port.postMessage(greeting); + + const fetch_url = new URL('simple.txt', resources_url); + const response = await fetch(fetch_url); + const text = await response.text(); + port.postMessage('fetch(): ' + text); +}; diff --git a/service-workers/service-worker/resources/worker_interception_redirect_webworker.py b/service-workers/service-worker/resources/worker_interception_redirect_webworker.py new file mode 100644 index 000000000000000..e388e461448f64d --- /dev/null +++ b/service-workers/service-worker/resources/worker_interception_redirect_webworker.py @@ -0,0 +1,19 @@ +# This serves the worker JavaScript file. It takes a |greeting| request +# parameter to inject into the JavaScript to indicate how the request +# reached the server. +import os +import sys + +def main(request, response): + path = os.path.join(os.path.dirname(__file__), + "worker-interception-redirect-webworker.js") + body = open(path, "rb").read() + if "greeting" in request.GET: + body = body.replace("%GREETING_TEXT%", request.GET["greeting"]) + else: + body = body.replace("%GREETING_TEXT%", "") + + headers = [] + headers.append(("Content-Type", "text/javascript")) + + return headers, body diff --git a/service-workers/service-worker/worker-interception-redirect.https.html b/service-workers/service-worker/worker-interception-redirect.https.html new file mode 100644 index 000000000000000..9c1eec06b968130 --- /dev/null +++ b/service-workers/service-worker/worker-interception-redirect.https.html @@ -0,0 +1,170 @@ + +Service Worker: controlling a SharedWorker + + + + + +