From 0c6bf0bef9117ac7fdd9afef6783971f8863adf5 Mon Sep 17 00:00:00 2001 From: Yifan Luo Date: Sat, 2 Mar 2024 22:42:52 +0000 Subject: [PATCH] Bug 1881006 [wpt PR 44670] - [Private Network Access] Add test for service worker fetching document, a=testonly Automatic update from web-platform-tests [Private Network Access] Add test for service worker fetching document Bug: b/323583084 Change-Id: I031d4ebd81d105e01a66eea10bf2bfefa781cd19 Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/5307002 Reviewed-by: Mike West Commit-Queue: Yifan Luo Cr-Commit-Position: refs/heads/main@{#1266949} -- wpt-commits: ce648a01bf0b63f75eecc1705cacd2e87241ac4e wpt-pr: 44670 --- .../resources/service-worker-fetch-all.js | 20 ++++ .../resources/support.sub.js | 63 +++++++++++ ...ument-treat-as-public.tentative.https.window.js | 101 ++++++++++++++++++ ...worker-fetch-document.tentative.https.window.js | 114 ++++++++++++++++++++ .../service-worker-fetch.tentative.https.window.js | 117 ++++++--------------- 5 files changed, 333 insertions(+), 82 deletions(-) create mode 100644 testing/web-platform/tests/fetch/private-network-access/resources/service-worker-fetch-all.js create mode 100644 testing/web-platform/tests/fetch/private-network-access/service-worker-fetch-document-treat-as-public.tentative.https.window.js create mode 100644 testing/web-platform/tests/fetch/private-network-access/service-worker-fetch-document.tentative.https.window.js diff --git a/testing/web-platform/tests/fetch/private-network-access/resources/service-worker-fetch-all.js b/testing/web-platform/tests/fetch/private-network-access/resources/service-worker-fetch-all.js new file mode 100644 index 000000000000..78ac8d1576b4 --- /dev/null +++ b/testing/web-platform/tests/fetch/private-network-access/resources/service-worker-fetch-all.js @@ -0,0 +1,20 @@ +self.addEventListener("install", () => { + // Skip waiting before replacing the previously-active service worker, if any. + // This allows the bridge script to notice the controller change and query + // the install time via fetch. + self.skipWaiting(); +}); + +self.addEventListener("activate", (event) => { + // Claim all clients so that the bridge script notices the activation. + event.waitUntil(self.clients.claim()); +}); + +self.addEventListener("fetch", (event) => { + const url = new URL(event.request.url).searchParams.get("proxied-url"); + if (url) { + event.respondWith(fetch(url)); + } else { + event.respondWith(fetch(event.request)); + } +}); diff --git a/testing/web-platform/tests/fetch/private-network-access/resources/support.sub.js b/testing/web-platform/tests/fetch/private-network-access/resources/support.sub.js index 35f39b11c032..1cb432b7874a 100644 --- a/testing/web-platform/tests/fetch/private-network-access/resources/support.sub.js +++ b/testing/web-platform/tests/fetch/private-network-access/resources/support.sub.js @@ -876,3 +876,66 @@ async function sharedWorkerBlobFetchTest(t, { source, target, expected }) { assert_equals(status, expected.status, "response status"); assert_equals(body, expected.body, "response body"); } + +async function makeServiceWorkerTest(t, { source, target, expected, fetch_document=false }) { + const bridgeUrl = resolveUrl( + "resources/service-worker-bridge.html", + sourceResolveOptions({ server: source.server })); + + const scriptUrl = fetch_document? + resolveUrl("resources/service-worker-fetch-all.js", sourceResolveOptions(source)): + resolveUrl("resources/service-worker.js", sourceResolveOptions(source)); + + const realTargetUrl = preflightUrl(target); + + // Fetch a URL within the service worker's scope, but tell it which URL to + // really fetch. + const targetUrl = new URL("service-worker-proxy", scriptUrl); + targetUrl.searchParams.append("proxied-url", realTargetUrl.href); + + const iframe = await appendIframe(t, document, bridgeUrl); + + const request = (message) => { + const reply = futureMessage(); + iframe.contentWindow.postMessage(message, "*"); + return reply; + }; + + { + const { error, loaded } = await request({ + action: "register", + url: scriptUrl.href, + }); + + assert_equals(error, undefined, "register error"); + assert_true(loaded, "response loaded"); + } + + try { + const { controlled, numControllerChanges } = await request({ + action: "wait", + numControllerChanges: 1, + }); + + assert_equals(numControllerChanges, 1, "controller change"); + assert_true(controlled, "bridge script is controlled"); + + const { error, ok, body } = await request({ + action: "fetch", + url: targetUrl.href, + }); + + assert_equals(error, expected.error, "fetch error"); + assert_equals(ok, expected.ok, "response ok"); + assert_equals(body, expected.body, "response body"); + } finally { + // Always unregister the service worker. + const { error, unregistered } = await request({ + action: "unregister", + scope: new URL("./", scriptUrl).href, + }); + + assert_equals(error, undefined, "unregister error"); + assert_true(unregistered, "unregistered"); + } +} diff --git a/testing/web-platform/tests/fetch/private-network-access/service-worker-fetch-document-treat-as-public.tentative.https.window.js b/testing/web-platform/tests/fetch/private-network-access/service-worker-fetch-document-treat-as-public.tentative.https.window.js new file mode 100644 index 000000000000..6fc29ce4725b --- /dev/null +++ b/testing/web-platform/tests/fetch/private-network-access/service-worker-fetch-document-treat-as-public.tentative.https.window.js @@ -0,0 +1,101 @@ +// META: script=/common/utils.js +// META: script=resources/support.sub.js +// +// Spec: https://wicg.github.io/private-network-access/#integration-fetch +// +// These tests check that fetches from within `ServiceWorker` scripts are +// subject to Private Network Access checks, just like fetches from within +// documents. + +// Results that may be expected in tests. +const TestResult = { + SUCCESS: { ok: true, body: "success" }, + FAILURE: { error: "TypeError" }, +}; + +promise_test(t => makeServiceWorkerTest(t, { + source: { + server: Server.HTTPS_LOCAL, + treatAsPublic: true, + }, + target: { + server: Server.OTHER_HTTPS_LOCAL, + behavior: { + preflight: PreflightBehavior.failure(), + response: ResponseBehavior.allowCrossOrigin() + }, + }, + expected: TestResult.FAILURE, + fetch_document: true, +}), "treat-as-public to local: failed preflight."); + +promise_test(t => makeServiceWorkerTest(t, { + source: { + server: Server.HTTPS_LOCAL, + treatAsPublic: true, + }, + target: { + server: Server.OTHER_HTTPS_LOCAL, + behavior: { + preflight: PreflightBehavior.success(token()), + response: ResponseBehavior.allowCrossOrigin(), + }, + }, + expected: TestResult.SUCCESS, + fetch_document: true, +}), "treat-as-public to local: success."); + +promise_test(t => makeServiceWorkerTest(t, { + source: { + server: Server.HTTPS_LOCAL, + treatAsPublic: true, + }, + target: { server: Server.HTTPS_LOCAL }, + expected: TestResult.SUCCESS, + fetch_document: true, +}), "treat-as-public to local (same-origin): no preflight required."); + +promise_test(t => makeServiceWorkerTest(t, { + source: { + server: Server.HTTPS_LOCAL, + treatAsPublic: true, + }, + target: { + server: Server.HTTPS_PRIVATE, + behavior: { + preflight: PreflightBehavior.failure(), + response: ResponseBehavior.allowCrossOrigin() + }, + }, + expected: TestResult.FAILURE, + fetch_document: true, +}), "treat-as-public to private: failed preflight."); + +promise_test(t => makeServiceWorkerTest(t, { + source: { + server: Server.HTTPS_LOCAL, + treatAsPublic: true, + }, + target: { + server: Server.HTTPS_PRIVATE, + behavior: { + preflight: PreflightBehavior.success(token()), + response: ResponseBehavior.allowCrossOrigin(), + }, + }, + expected: TestResult.SUCCESS, + fetch_document: true, +}), "treat-as-public to private: success."); + +promise_test(t => makeServiceWorkerTest(t, { + source: { + server: Server.HTTPS_LOCAL, + treatAsPublic: true, + }, + target: { + server: Server.HTTPS_PUBLIC, + behavior: { response: ResponseBehavior.allowCrossOrigin() }, + }, + expected: TestResult.SUCCESS, + fetch_document: true, +}), "treat-as-public to public: success."); diff --git a/testing/web-platform/tests/fetch/private-network-access/service-worker-fetch-document.tentative.https.window.js b/testing/web-platform/tests/fetch/private-network-access/service-worker-fetch-document.tentative.https.window.js new file mode 100644 index 000000000000..ec380555a809 --- /dev/null +++ b/testing/web-platform/tests/fetch/private-network-access/service-worker-fetch-document.tentative.https.window.js @@ -0,0 +1,114 @@ +// META: script=/common/utils.js +// META: script=resources/support.sub.js +// +// Spec: https://wicg.github.io/private-network-access/#integration-fetch +// +// These tests check that fetches from within `ServiceWorker` scripts are +// subject to Private Network Access checks, just like fetches from within +// documents. + +// Results that may be expected in tests. +const TestResult = { + SUCCESS: { ok: true, body: "success" }, + FAILURE: { error: "TypeError" }, +}; + +promise_test(t => makeServiceWorkerTest(t, { + source: { server: Server.HTTPS_LOCAL }, + target: { server: Server.HTTPS_LOCAL }, + expected: TestResult.SUCCESS, + fetch_document: true, +}), "local to local: success."); + +promise_test(t => makeServiceWorkerTest(t, { + source: { server: Server.HTTPS_PRIVATE }, + target: { + server: Server.HTTPS_LOCAL, + behavior: { + preflight: PreflightBehavior.failure(), + response: ResponseBehavior.allowCrossOrigin() + }, + }, + expected: TestResult.FAILURE, + fetch_document: true, +}), "private to local: failed preflight."); + +promise_test(t => makeServiceWorkerTest(t, { + source: { server: Server.HTTPS_PRIVATE }, + target: { + server: Server.HTTPS_LOCAL, + behavior: { + preflight: PreflightBehavior.success(token()), + response: ResponseBehavior.allowCrossOrigin(), + }, + }, + expected: TestResult.SUCCESS, + fetch_document: true, +}), "private to local: success."); + +promise_test(t => makeServiceWorkerTest(t, { + source: { server: Server.HTTPS_PRIVATE }, + target: { server: Server.HTTPS_PRIVATE }, + expected: TestResult.SUCCESS, + fetch_document: true, +}), "private to private: success."); + +promise_test(t => makeServiceWorkerTest(t, { + source: { server: Server.HTTPS_PUBLIC }, + target: { + server: Server.HTTPS_LOCAL, + behavior: { + preflight: PreflightBehavior.failure(), + response: ResponseBehavior.allowCrossOrigin() + }, + }, + expected: TestResult.FAILURE, + fetch_document: true, +}), "public to local: failed preflight."); + +promise_test(t => makeServiceWorkerTest(t, { + source: { server: Server.HTTPS_PUBLIC }, + target: { + server: Server.HTTPS_LOCAL, + behavior: { + preflight: PreflightBehavior.success(token()), + response: ResponseBehavior.allowCrossOrigin(), + }, + }, + expected: TestResult.SUCCESS, + fetch_document: true, +}), "public to local: success."); + +promise_test(t => makeServiceWorkerTest(t, { + source: { server: Server.HTTPS_PUBLIC }, + target: { + server: Server.HTTPS_PRIVATE, + behavior: { + preflight: PreflightBehavior.failure(), + response: ResponseBehavior.allowCrossOrigin() + }, + }, + expected: TestResult.FAILURE, + fetch_document: true, +}), "public to private: failed preflight."); + +promise_test(t => makeServiceWorkerTest(t, { + source: { server: Server.HTTPS_PUBLIC }, + target: { + server: Server.HTTPS_PRIVATE, + behavior: { + preflight: PreflightBehavior.success(token()), + response: ResponseBehavior.allowCrossOrigin(), + }, + }, + expected: TestResult.SUCCESS, + fetch_document: true, +}), "public to private: success."); + +promise_test(t => makeServiceWorkerTest(t, { + source: { server: Server.HTTPS_PUBLIC }, + target: { server: Server.HTTPS_PUBLIC }, + expected: TestResult.SUCCESS, + fetch_document: true, +}), "public to public: success."); + diff --git a/testing/web-platform/tests/fetch/private-network-access/service-worker-fetch.tentative.https.window.js b/testing/web-platform/tests/fetch/private-network-access/service-worker-fetch.tentative.https.window.js index cb6d1f79b01f..5fc5800ba042 100644 --- a/testing/web-platform/tests/fetch/private-network-access/service-worker-fetch.tentative.https.window.js +++ b/testing/web-platform/tests/fetch/private-network-access/service-worker-fetch.tentative.https.window.js @@ -16,84 +16,25 @@ const TestResult = { FAILURE: { error: "TypeError" }, }; -async function makeTest(t, { source, target, expected }) { - const bridgeUrl = resolveUrl( - "resources/service-worker-bridge.html", - sourceResolveOptions({ server: source.server })); - - const scriptUrl = - resolveUrl("resources/service-worker.js", sourceResolveOptions(source)); - - const realTargetUrl = preflightUrl(target); - - // Fetch a URL within the service worker's scope, but tell it which URL to - // really fetch. - const targetUrl = new URL("service-worker-proxy", scriptUrl); - targetUrl.searchParams.append("proxied-url", realTargetUrl.href); - - const iframe = await appendIframe(t, document, bridgeUrl); - - const request = (message) => { - const reply = futureMessage(); - iframe.contentWindow.postMessage(message, "*"); - return reply; - }; - - { - const { error, loaded } = await request({ - action: "register", - url: scriptUrl.href, - }); - - assert_equals(error, undefined, "register error"); - assert_true(loaded, "response loaded"); - } - - try { - const { controlled, numControllerChanges } = await request({ - action: "wait", - numControllerChanges: 1, - }); - - assert_equals(numControllerChanges, 1, "controller change"); - assert_true(controlled, "bridge script is controlled"); - - const { error, ok, body } = await request({ - action: "fetch", - url: targetUrl.href, - }); - - assert_equals(error, expected.error, "fetch error"); - assert_equals(ok, expected.ok, "response ok"); - assert_equals(body, expected.body, "response body"); - } finally { - // Always unregister the service worker. - const { error, unregistered } = await request({ - action: "unregister", - scope: new URL("./", scriptUrl).href, - }); - - assert_equals(error, undefined, "unregister error"); - assert_true(unregistered, "unregistered"); - } -} - -subsetTest(promise_test, t => makeTest(t, { +subsetTest(promise_test, t => makeServiceWorkerTest(t, { source: { server: Server.HTTPS_LOCAL }, target: { server: Server.HTTPS_LOCAL }, expected: TestResult.SUCCESS, }), "local to local: success."); -subsetTest(promise_test, t => makeTest(t, { +subsetTest(promise_test, t => makeServiceWorkerTest(t, { source: { server: Server.HTTPS_PRIVATE }, target: { server: Server.HTTPS_LOCAL, - behavior: { response: ResponseBehavior.allowCrossOrigin() }, + behavior: { + preflight: PreflightBehavior.failure(), + response: ResponseBehavior.allowCrossOrigin() + }, }, expected: TestResult.FAILURE, }), "private to local: failed preflight."); -subsetTest(promise_test, t => makeTest(t, { +subsetTest(promise_test, t => makeServiceWorkerTest(t, { source: { server: Server.HTTPS_PRIVATE }, target: { server: Server.HTTPS_LOCAL, @@ -105,22 +46,25 @@ subsetTest(promise_test, t => makeTest(t, { expected: TestResult.SUCCESS, }), "private to local: success."); -subsetTest(promise_test, t => makeTest(t, { +subsetTest(promise_test, t => makeServiceWorkerTest(t, { source: { server: Server.HTTPS_PRIVATE }, target: { server: Server.HTTPS_PRIVATE }, expected: TestResult.SUCCESS, }), "private to private: success."); -subsetTest(promise_test, t => makeTest(t, { +subsetTest(promise_test, t => makeServiceWorkerTest(t, { source: { server: Server.HTTPS_PUBLIC }, target: { server: Server.HTTPS_LOCAL, - behavior: { response: ResponseBehavior.allowCrossOrigin() }, + behavior: { + preflight: PreflightBehavior.failure(), + response: ResponseBehavior.allowCrossOrigin() + }, }, expected: TestResult.FAILURE, }), "public to local: failed preflight."); -subsetTest(promise_test, t => makeTest(t, { +subsetTest(promise_test, t => makeServiceWorkerTest(t, { source: { server: Server.HTTPS_PUBLIC }, target: { server: Server.HTTPS_LOCAL, @@ -132,16 +76,19 @@ subsetTest(promise_test, t => makeTest(t, { expected: TestResult.SUCCESS, }), "public to local: success."); -subsetTest(promise_test, t => makeTest(t, { +subsetTest(promise_test, t => makeServiceWorkerTest(t, { source: { server: Server.HTTPS_PUBLIC }, target: { server: Server.HTTPS_PRIVATE, - behavior: { response: ResponseBehavior.allowCrossOrigin() }, + behavior: { + preflight: PreflightBehavior.failure(), + response: ResponseBehavior.allowCrossOrigin() + }, }, expected: TestResult.FAILURE, }), "public to private: failed preflight."); -subsetTest(promise_test, t => makeTest(t, { +subsetTest(promise_test, t => makeServiceWorkerTest(t, { source: { server: Server.HTTPS_PUBLIC }, target: { server: Server.HTTPS_PRIVATE, @@ -153,25 +100,28 @@ subsetTest(promise_test, t => makeTest(t, { expected: TestResult.SUCCESS, }), "public to private: success."); -subsetTest(promise_test, t => makeTest(t, { +subsetTest(promise_test, t => makeServiceWorkerTest(t, { source: { server: Server.HTTPS_PUBLIC }, target: { server: Server.HTTPS_PUBLIC }, expected: TestResult.SUCCESS, }), "public to public: success."); -subsetTest(promise_test, t => makeTest(t, { +subsetTest(promise_test, t => makeServiceWorkerTest(t, { source: { server: Server.HTTPS_LOCAL, treatAsPublic: true, }, target: { server: Server.OTHER_HTTPS_LOCAL, - behavior: { response: ResponseBehavior.allowCrossOrigin() }, + behavior: { + preflight: PreflightBehavior.failure(), + response: ResponseBehavior.allowCrossOrigin() + }, }, expected: TestResult.FAILURE, }), "treat-as-public to local: failed preflight."); -subsetTest(promise_test, t => makeTest(t, { +subsetTest(promise_test, t => makeServiceWorkerTest(t, { source: { server: Server.HTTPS_LOCAL, treatAsPublic: true, @@ -186,7 +136,7 @@ subsetTest(promise_test, t => makeTest(t, { expected: TestResult.SUCCESS, }), "treat-as-public to local: success."); -subsetTest(promise_test, t => makeTest(t, { +subsetTest(promise_test, t => makeServiceWorkerTest(t, { source: { server: Server.HTTPS_LOCAL, treatAsPublic: true, @@ -195,19 +145,22 @@ subsetTest(promise_test, t => makeTest(t, { expected: TestResult.SUCCESS, }), "treat-as-public to local (same-origin): no preflight required."); -subsetTest(promise_test, t => makeTest(t, { +subsetTest(promise_test, t => makeServiceWorkerTest(t, { source: { server: Server.HTTPS_LOCAL, treatAsPublic: true, }, target: { server: Server.HTTPS_PRIVATE, - behavior: { response: ResponseBehavior.allowCrossOrigin() }, + behavior: { + preflight: PreflightBehavior.failure(), + response: ResponseBehavior.allowCrossOrigin() + }, }, expected: TestResult.FAILURE, }), "treat-as-public to private: failed preflight."); -subsetTest(promise_test, t => makeTest(t, { +subsetTest(promise_test, t => makeServiceWorkerTest(t, { source: { server: Server.HTTPS_LOCAL, treatAsPublic: true, @@ -222,7 +175,7 @@ subsetTest(promise_test, t => makeTest(t, { expected: TestResult.SUCCESS, }), "treat-as-public to private: success."); -subsetTest(promise_test, t => makeTest(t, { +subsetTest(promise_test, t => makeServiceWorkerTest(t, { source: { server: Server.HTTPS_LOCAL, treatAsPublic: true, -- 2.11.4.GIT