summaryrefslogtreecommitdiffstats
path: root/testing/web-platform/tests/fetch
diff options
context:
space:
mode:
authorDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-19 01:14:29 +0000
committerDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-19 01:14:29 +0000
commitfbaf0bb26397aa498eb9156f06d5a6fe34dd7dd8 (patch)
tree4c1ccaf5486d4f2009f9a338a98a83e886e29c97 /testing/web-platform/tests/fetch
parentReleasing progress-linux version 124.0.1-1~progress7.99u1. (diff)
downloadfirefox-fbaf0bb26397aa498eb9156f06d5a6fe34dd7dd8.tar.xz
firefox-fbaf0bb26397aa498eb9156f06d5a6fe34dd7dd8.zip
Merging upstream version 125.0.1.
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'testing/web-platform/tests/fetch')
-rw-r--r--testing/web-platform/tests/fetch/api/basic/request-upload.h2.any.js23
-rw-r--r--testing/web-platform/tests/fetch/api/body/formdata.any.js11
-rw-r--r--testing/web-platform/tests/fetch/api/request/request-consume-empty.any.js22
-rw-r--r--testing/web-platform/tests/fetch/api/request/request-consume.any.js29
-rw-r--r--testing/web-platform/tests/fetch/api/response/response-consume-empty.any.js23
-rw-r--r--testing/web-platform/tests/fetch/private-network-access/anchor.tentative.https.window.js38
-rw-r--r--testing/web-platform/tests/fetch/private-network-access/resources/service-worker-fetch-all.js20
-rw-r--r--testing/web-platform/tests/fetch/private-network-access/resources/support.sub.js84
-rw-r--r--testing/web-platform/tests/fetch/private-network-access/service-worker-fetch-document-treat-as-public.tentative.https.window.js101
-rw-r--r--testing/web-platform/tests/fetch/private-network-access/service-worker-fetch-document.tentative.https.window.js114
-rw-r--r--testing/web-platform/tests/fetch/private-network-access/service-worker-fetch.tentative.https.window.js117
-rw-r--r--testing/web-platform/tests/fetch/private-network-access/window-open-existing.tentative.https.window.js38
-rw-r--r--testing/web-platform/tests/fetch/private-network-access/window-open.tentative.https.window.js38
-rw-r--r--testing/web-platform/tests/fetch/security/dangling-markup/dangling-markup-mitigation-allowed-apis.html26
-rw-r--r--testing/web-platform/tests/fetch/security/dangling-markup/dangling-markup-mitigation-data-url.sub.html (renamed from testing/web-platform/tests/fetch/security/dangling-markup/dangling-markup-mitigation-data-url.tentative.sub.html)0
-rw-r--r--testing/web-platform/tests/fetch/security/dangling-markup/dangling-markup-mitigation.html (renamed from testing/web-platform/tests/fetch/security/dangling-markup/dangling-markup-mitigation.tentative.html)0
-rw-r--r--testing/web-platform/tests/fetch/security/dangling-markup/dangling-markup-mitigation.https.html61
-rw-r--r--testing/web-platform/tests/fetch/security/dangling-markup/resources/empty.html1
-rw-r--r--testing/web-platform/tests/fetch/security/dangling-markup/service-worker.js35
19 files changed, 645 insertions, 136 deletions
diff --git a/testing/web-platform/tests/fetch/api/basic/request-upload.h2.any.js b/testing/web-platform/tests/fetch/api/basic/request-upload.h2.any.js
index eedc2bf6a7..68122278cc 100644
--- a/testing/web-platform/tests/fetch/api/basic/request-upload.h2.any.js
+++ b/testing/web-platform/tests/fetch/api/basic/request-upload.h2.any.js
@@ -184,3 +184,26 @@ promise_test(async (t) => {
await promise_rejects_js(t, TypeError, fetch(url, { method, body, duplex }));
}, "Streaming upload should fail on a 401 response");
+promise_test(async (t) => {
+ const abortMessage = 'foo abort';
+ let streamCancelPromise = new Promise(async res => {
+ var stream = new ReadableStream({
+ cancel: function(reason) {
+ res(reason);
+ }
+ });
+ let abortController = new AbortController();
+ let fetchPromise = promise_rejects_exactly(t, abortMessage, fetch('', {
+ method: 'POST',
+ body: stream,
+ duplex: 'half',
+ signal: abortController.signal
+ }));
+ abortController.abort(abortMessage);
+ await fetchPromise;
+ });
+
+ let cancelReason = await streamCancelPromise;
+ assert_equals(
+ cancelReason, abortMessage, 'ReadableStream.cancel should be called.');
+}, 'ReadbleStream should be closed on signal.abort');
diff --git a/testing/web-platform/tests/fetch/api/body/formdata.any.js b/testing/web-platform/tests/fetch/api/body/formdata.any.js
index e25035923c..6733fa0ed7 100644
--- a/testing/web-platform/tests/fetch/api/body/formdata.any.js
+++ b/testing/web-platform/tests/fetch/api/body/formdata.any.js
@@ -12,3 +12,14 @@ promise_test(async t => {
const fd = await req.formData();
assert_true(fd instanceof FormData);
}, 'Consume empty request.formData() as FormData');
+
+promise_test(async t => {
+ let formdata = new FormData();
+ formdata.append('foo', new Blob([JSON.stringify({ bar: "baz", })], { type: "application/json" }));
+ let blob = await new Response(formdata).blob();
+ let body = await blob.text();
+ blob = new Blob([body.toLowerCase()], { type: blob.type.toLowerCase() });
+ let formdataWithLowercaseBody = await new Response(blob).formData();
+ assert_true(formdataWithLowercaseBody.has("foo"));
+ assert_equals(formdataWithLowercaseBody.get("foo").type, "application/json");
+}, 'Consume multipart/form-data headers case-insensitively');
diff --git a/testing/web-platform/tests/fetch/api/request/request-consume-empty.any.js b/testing/web-platform/tests/fetch/api/request/request-consume-empty.any.js
index 034a86041a..0bf9672a79 100644
--- a/testing/web-platform/tests/fetch/api/request/request-consume-empty.any.js
+++ b/testing/web-platform/tests/fetch/api/request/request-consume-empty.any.js
@@ -8,23 +8,11 @@ function checkBodyText(test, request) {
});
}
-function checkBodyBlob(test, request) {
- return request.blob().then(function(bodyAsBlob) {
- var promise = new Promise(function(resolve, reject) {
- var reader = new FileReader();
- reader.onload = function(evt) {
- resolve(reader.result)
- };
- reader.onerror = function() {
- reject("Blob's reader failed");
- };
- reader.readAsText(bodyAsBlob);
- });
- return promise.then(function(body) {
- assert_equals(body, "", "Resolved value should be empty");
- assert_false(request.bodyUsed);
- });
- });
+async function checkBodyBlob(test, request) {
+ const bodyAsBlob = await request.blob();
+ const body = await bodyAsBlob.text();
+ assert_equals(body, "", "Resolved value should be empty");
+ assert_false(request.bodyUsed);
}
function checkBodyArrayBuffer(test, request) {
diff --git a/testing/web-platform/tests/fetch/api/request/request-consume.any.js b/testing/web-platform/tests/fetch/api/request/request-consume.any.js
index aff5d65244..3db9e8f265 100644
--- a/testing/web-platform/tests/fetch/api/request/request-consume.any.js
+++ b/testing/web-platform/tests/fetch/api/request/request-consume.any.js
@@ -9,26 +9,15 @@ function checkBodyText(request, expectedBody) {
});
}
-function checkBodyBlob(request, expectedBody, checkContentType) {
- return request.blob().then(function(bodyAsBlob) {
- if (checkContentType)
- assert_equals(bodyAsBlob.type, "text/plain", "Blob body type should be computed from the request Content-Type");
-
- var promise = new Promise(function (resolve, reject) {
- var reader = new FileReader();
- reader.onload = function(evt) {
- resolve(reader.result)
- };
- reader.onerror = function() {
- reject("Blob's reader failed");
- };
- reader.readAsText(bodyAsBlob);
- });
- return promise.then(function(body) {
- assert_equals(body, expectedBody, "Retrieve and verify request's body");
- assert_true(request.bodyUsed, "body as blob: bodyUsed turned true");
- });
- });
+async function checkBodyBlob(request, expectedBody, checkContentType) {
+ const bodyAsBlob = await request.blob();
+
+ if (checkContentType)
+ assert_equals(bodyAsBlob.type, "text/plain", "Blob body type should be computed from the request Content-Type");
+
+ const body = await bodyAsBlob.text();
+ assert_equals(body, expectedBody, "Retrieve and verify request's body");
+ assert_true(request.bodyUsed, "body as blob: bodyUsed turned true");
}
function checkBodyArrayBuffer(request, expectedBody) {
diff --git a/testing/web-platform/tests/fetch/api/response/response-consume-empty.any.js b/testing/web-platform/tests/fetch/api/response/response-consume-empty.any.js
index 0fa85ecbcb..a5df356258 100644
--- a/testing/web-platform/tests/fetch/api/response/response-consume-empty.any.js
+++ b/testing/web-platform/tests/fetch/api/response/response-consume-empty.any.js
@@ -8,23 +8,12 @@ function checkBodyText(test, response) {
});
}
-function checkBodyBlob(test, response) {
- return response.blob().then(function(bodyAsBlob) {
- var promise = new Promise(function(resolve, reject) {
- var reader = new FileReader();
- reader.onload = function(evt) {
- resolve(reader.result)
- };
- reader.onerror = function() {
- reject("Blob's reader failed");
- };
- reader.readAsText(bodyAsBlob);
- });
- return promise.then(function(body) {
- assert_equals(body, "", "Resolved value should be empty");
- assert_false(response.bodyUsed);
- });
- });
+async function checkBodyBlob(test, response) {
+ const bodyAsBlob = await response.blob();
+ const body = await bodyAsBlob.text();
+
+ assert_equals(body, "", "Resolved value should be empty");
+ assert_false(response.bodyUsed);
}
function checkBodyArrayBuffer(test, response) {
diff --git a/testing/web-platform/tests/fetch/private-network-access/anchor.tentative.https.window.js b/testing/web-platform/tests/fetch/private-network-access/anchor.tentative.https.window.js
index 4e860ad381..f5473868b7 100644
--- a/testing/web-platform/tests/fetch/private-network-access/anchor.tentative.https.window.js
+++ b/testing/web-platform/tests/fetch/private-network-access/anchor.tentative.https.window.js
@@ -149,6 +149,44 @@ subsetTestByKey("from-public", promise_test_parallel, t => anchorTest(t, {
expected: NavigationTestResult.SUCCESS,
}), "public to public: no preflight required.");
+subsetTestByKey(
+ 'from-public', promise_test_parallel,
+ t => anchorTest(t, {
+ source: {server: Server.HTTPS_PUBLIC},
+ target: {
+ server: Server.HTTPS_PUBLIC,
+ behavior: {
+ redirect: preflightUrl({
+ server: Server.HTTPS_PRIVATE,
+ behavior: {
+ preflight: PreflightBehavior.noCorsHeader(token()),
+ }
+ }),
+ }
+ },
+ expected: NavigationTestResult.FAILURE,
+ }),
+ 'public to public redirected to private: missing CORS headers.');
+
+subsetTestByKey(
+ 'from-public', promise_test_parallel,
+ t => anchorTest(t, {
+ source: {server: Server.HTTPS_PUBLIC},
+ target: {
+ server: Server.HTTPS_PUBLIC,
+ behavior: {
+ redirect: preflightUrl({
+ server: Server.HTTPS_PRIVATE,
+ behavior: {
+ preflight: PreflightBehavior.navigation(token()),
+ }
+ }),
+ }
+ },
+ expected: NavigationTestResult.SUCCESS,
+ }),
+ 'public to public to private: success.');
+
// The following tests verify that `CSP: treat-as-public-address` makes
// documents behave as if they had been served from a public IP address.
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 0000000000..78ac8d1576
--- /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 46a9d9e076..1cb432b787 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
@@ -480,6 +480,13 @@ const NavigationTestResult = {
};
async function windowOpenTest(t, { source, target, expected }) {
+ if (target.behavior && target.behavior.redirect) {
+ target.behavior.redirect.searchParams.set('file', 'openee.html');
+ target.behavior.redirect.searchParams.set(
+ 'file-if-no-preflight-received',
+ 'no-preflight-received.html',
+ );
+ }
const targetUrl = preflightUrl(target);
targetUrl.searchParams.set("file", "openee.html");
targetUrl.searchParams.set(
@@ -507,6 +514,13 @@ async function windowOpenTest(t, { source, target, expected }) {
}
async function windowOpenExistingTest(t, { source, target, expected }) {
+ if (target.behavior && target.behavior.redirect) {
+ target.behavior.redirect.searchParams.set('file', 'openee.html');
+ target.behavior.redirect.searchParams.set(
+ 'file-if-no-preflight-received',
+ 'no-preflight-received.html',
+ );
+ }
const targetUrl = preflightUrl(target);
targetUrl.searchParams.set("file", "openee.html");
targetUrl.searchParams.set(
@@ -535,6 +549,13 @@ async function windowOpenExistingTest(t, { source, target, expected }) {
}
async function anchorTest(t, { source, target, expected }) {
+ if (target.behavior && target.behavior.redirect) {
+ target.behavior.redirect.searchParams.set('file', 'openee.html');
+ target.behavior.redirect.searchParams.set(
+ 'file-if-no-preflight-received',
+ 'no-preflight-received.html',
+ );
+ }
const targetUrl = preflightUrl(target);
targetUrl.searchParams.set("file", "openee.html");
targetUrl.searchParams.set(
@@ -855,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 0000000000..6fc29ce472
--- /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 0000000000..ec380555a8
--- /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 cb6d1f79b0..5fc5800ba0 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,
diff --git a/testing/web-platform/tests/fetch/private-network-access/window-open-existing.tentative.https.window.js b/testing/web-platform/tests/fetch/private-network-access/window-open-existing.tentative.https.window.js
index 6a2a624fc8..565a2117a8 100644
--- a/testing/web-platform/tests/fetch/private-network-access/window-open-existing.tentative.https.window.js
+++ b/testing/web-platform/tests/fetch/private-network-access/window-open-existing.tentative.https.window.js
@@ -167,6 +167,44 @@ subsetTestByKey(
}),
'public to public: no preflight required.');
+subsetTestByKey(
+ 'from-public', promise_test_parallel,
+ t => windowOpenExistingTest(t, {
+ source: {server: Server.HTTPS_PUBLIC},
+ target: {
+ server: Server.HTTPS_PUBLIC,
+ behavior: {
+ redirect: preflightUrl({
+ server: Server.HTTPS_PRIVATE,
+ behavior: {
+ preflight: PreflightBehavior.noCorsHeader(token()),
+ }
+ }),
+ }
+ },
+ expected: NavigationTestResult.FAILURE,
+ }),
+ 'public to public redirected to private: missing CORS headers.');
+
+subsetTestByKey(
+ 'from-public', promise_test_parallel,
+ t => windowOpenExistingTest(t, {
+ source: {server: Server.HTTPS_PUBLIC},
+ target: {
+ server: Server.HTTPS_PUBLIC,
+ behavior: {
+ redirect: preflightUrl({
+ server: Server.HTTPS_PRIVATE,
+ behavior: {
+ preflight: PreflightBehavior.navigation(token()),
+ }
+ }),
+ }
+ },
+ expected: NavigationTestResult.SUCCESS,
+ }),
+ 'public to public to private: success.');
+
// The following tests verify that `CSP: treat-as-public-address` makes
// documents behave as if they had been served from a public IP address.
diff --git a/testing/web-platform/tests/fetch/private-network-access/window-open.tentative.https.window.js b/testing/web-platform/tests/fetch/private-network-access/window-open.tentative.https.window.js
index 6793d1f3b4..42d70af4e4 100644
--- a/testing/web-platform/tests/fetch/private-network-access/window-open.tentative.https.window.js
+++ b/testing/web-platform/tests/fetch/private-network-access/window-open.tentative.https.window.js
@@ -149,6 +149,44 @@ subsetTestByKey("from-public", promise_test_parallel, t => windowOpenTest(t, {
expected: NavigationTestResult.SUCCESS,
}), "public to public: no preflight required.");
+subsetTestByKey(
+ 'from-public', promise_test_parallel,
+ t => windowOpenTest(t, {
+ source: {server: Server.HTTPS_PUBLIC},
+ target: {
+ server: Server.HTTPS_PUBLIC,
+ behavior: {
+ redirect: preflightUrl({
+ server: Server.HTTPS_PRIVATE,
+ behavior: {
+ preflight: PreflightBehavior.noCorsHeader(token()),
+ }
+ }),
+ }
+ },
+ expected: NavigationTestResult.FAILURE,
+ }),
+ 'public to public redirected to private: missing CORS headers.');
+
+subsetTestByKey(
+ 'from-public', promise_test_parallel,
+ t => windowOpenTest(t, {
+ source: {server: Server.HTTPS_PUBLIC},
+ target: {
+ server: Server.HTTPS_PUBLIC,
+ behavior: {
+ redirect: preflightUrl({
+ server: Server.HTTPS_PRIVATE,
+ behavior: {
+ preflight: PreflightBehavior.navigation(token()),
+ }
+ }),
+ }
+ },
+ expected: NavigationTestResult.SUCCESS,
+ }),
+ 'public to public to private: success.');
+
// The following tests verify that `CSP: treat-as-public-address` makes
// documents behave as if they had been served from a public IP address.
diff --git a/testing/web-platform/tests/fetch/security/dangling-markup/dangling-markup-mitigation-allowed-apis.html b/testing/web-platform/tests/fetch/security/dangling-markup/dangling-markup-mitigation-allowed-apis.html
new file mode 100644
index 0000000000..66456a8876
--- /dev/null
+++ b/testing/web-platform/tests/fetch/security/dangling-markup/dangling-markup-mitigation-allowed-apis.html
@@ -0,0 +1,26 @@
+<!DOCTYPE html>
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<body>
+<script>
+ const blank = 'about:blank';
+ const dangling_url = 'resources/empty.html?\n<';
+ const api_calls = [
+ `window.open(\`${dangling_url}\`,'_self')`,
+ `location.replace(\`${dangling_url}\`)`,
+ ];
+
+ api_calls.forEach(call => {
+ async_test(t => {
+ const iframe =
+ document.body.appendChild(document.createElement('iframe'));
+ t.step(() => {
+ iframe.contentWindow.eval(call)
+ t.step_timeout(()=>{
+ assert_false(iframe.contentWindow.location.href.endsWith(blank));
+ t.done();
+ }, 500);
+ });
+ }, `Does not block ${call}`);
+ });
+</script>
diff --git a/testing/web-platform/tests/fetch/security/dangling-markup/dangling-markup-mitigation-data-url.tentative.sub.html b/testing/web-platform/tests/fetch/security/dangling-markup/dangling-markup-mitigation-data-url.sub.html
index f27735daa1..f27735daa1 100644
--- a/testing/web-platform/tests/fetch/security/dangling-markup/dangling-markup-mitigation-data-url.tentative.sub.html
+++ b/testing/web-platform/tests/fetch/security/dangling-markup/dangling-markup-mitigation-data-url.sub.html
diff --git a/testing/web-platform/tests/fetch/security/dangling-markup/dangling-markup-mitigation.tentative.html b/testing/web-platform/tests/fetch/security/dangling-markup/dangling-markup-mitigation.html
index 61a931608b..61a931608b 100644
--- a/testing/web-platform/tests/fetch/security/dangling-markup/dangling-markup-mitigation.tentative.html
+++ b/testing/web-platform/tests/fetch/security/dangling-markup/dangling-markup-mitigation.html
diff --git a/testing/web-platform/tests/fetch/security/dangling-markup/dangling-markup-mitigation.https.html b/testing/web-platform/tests/fetch/security/dangling-markup/dangling-markup-mitigation.https.html
new file mode 100644
index 0000000000..3f038cbb7b
--- /dev/null
+++ b/testing/web-platform/tests/fetch/security/dangling-markup/dangling-markup-mitigation.https.html
@@ -0,0 +1,61 @@
+<!DOCTYPE html>
+<meta name="timeout" content="long">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<body>
+<script>
+ function get_requests(worker, expected) {
+ return new Promise(resolve => {
+ navigator.serviceWorker.addEventListener('message', function onMsg(evt) {
+ if (evt.data.size >= expected) {
+ navigator.serviceWorker.removeEventListener('message', onMsg);
+ resolve(evt.data);
+ } else {
+ worker.postMessage("");
+ }
+ });
+ worker.postMessage("");
+ });
+ }
+
+ const resources = [
+ x=>`<link rel="stylesheet" href="404/style?${x}">`,
+ x=>`<link rel="prefetch" as="style" href="404/prefetch?${x}">`,
+ x=>`<script src="404/script?${x}"><\/script>`,
+ x=>`<iframe src="404/iframe?${x}"></iframe>`,
+ x=>`<meta http-equiv="refresh" content="0;url=404/meta?${x}">`,
+ x=>`<a href="404/a?${x}">click</a><script>document.querySelector('a').click()<\/script>`,
+ x=>`<base href="404/base?${x}"><a href>me</a><script>document.querySelector('a').click()<\/script>`,
+ x=>`<video controls poster="404/poster?${x}"></video>`,
+ x=>`<input type="image" src="404/input?${x}">`,
+ x=>`<form method="GET" action="404/form?${x}"></form><script>document.querySelector('form').submit()<\/script>`,
+ x=>`<body background="404/body?${x}"></body>`,
+ ];
+
+ async_test(t => {
+ const script = 'service-worker.js';
+ const paths = [];
+ navigator.serviceWorker.register(script);
+ t.step(async () => {
+ const registration = await navigator.serviceWorker.ready;
+ for (const html of resources) {
+ const iframe1 =
+ document.body.appendChild(document.createElement('iframe'));
+ iframe1.src = 'resources.html?html=' + html`%0A<`;
+ const iframe2 =
+ document.body.appendChild(document.createElement('iframe'));
+ iframe2.src = 'resources.html?html=' + html``;
+ const path = html`EOP`;
+ paths.push(path.substring(path.search('404\\/')+4, path.search('EOP')));
+ }
+
+ const requests = await get_requests(registration.active, resources.length);
+ paths.forEach(path => {
+ assert_true(requests.has(path),
+ `${path} should appear in requests sent`);
+ });
+ await registration.unregister();
+ t.done();
+ });
+ }, 'Only blocks dangling markup requests');
+</script>
diff --git a/testing/web-platform/tests/fetch/security/dangling-markup/resources/empty.html b/testing/web-platform/tests/fetch/security/dangling-markup/resources/empty.html
new file mode 100644
index 0000000000..0e76edd65b
--- /dev/null
+++ b/testing/web-platform/tests/fetch/security/dangling-markup/resources/empty.html
@@ -0,0 +1 @@
+<!DOCTYPE html>
diff --git a/testing/web-platform/tests/fetch/security/dangling-markup/service-worker.js b/testing/web-platform/tests/fetch/security/dangling-markup/service-worker.js
new file mode 100644
index 0000000000..837e216a01
--- /dev/null
+++ b/testing/web-platform/tests/fetch/security/dangling-markup/service-worker.js
@@ -0,0 +1,35 @@
+const requests = new Set();
+
+addEventListener('install', evt => {
+ evt.waitUntil(self.skipWaiting());
+});
+
+addEventListener('activate', evt => {
+ evt.waitUntil(self.clients.claim());
+});
+
+addEventListener('message', evt => {
+ evt.source.postMessage(requests);
+});
+
+addEventListener('fetch', evt => {
+ const url = new URL(evt.request.url);
+ const path = url.pathname;
+ const search = url.search || "?";
+ if (path.includes('404')) {
+ const dir = path.split('/');
+ const request = dir[dir.length-1] + search;
+ if (!requests.has(request)) {
+ requests.add(request);
+ }
+ evt.respondWith(new Response(""));
+ } else if (path.endsWith('resources.html')) {
+ const html = (new URLSearchParams(search)).get('html');
+ evt.respondWith(new Response(html, {
+ headers: {
+ "Content-Type": "text/html"
+ }
+ }));
+ }
+ return;
+});