diff options
author | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-07 09:22:09 +0000 |
---|---|---|
committer | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-07 09:22:09 +0000 |
commit | 43a97878ce14b72f0981164f87f2e35e14151312 (patch) | |
tree | 620249daf56c0258faa40cbdcf9cfba06de2a846 /testing/web-platform/tests/client-hints | |
parent | Initial commit. (diff) | |
download | firefox-43a97878ce14b72f0981164f87f2e35e14151312.tar.xz firefox-43a97878ce14b72f0981164f87f2e35e14151312.zip |
Adding upstream version 110.0.1.upstream/110.0.1upstream
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'testing/web-platform/tests/client-hints')
202 files changed, 3525 insertions, 0 deletions
diff --git a/testing/web-platform/tests/client-hints/META.yml b/testing/web-platform/tests/client-hints/META.yml new file mode 100644 index 0000000000..68cbc4d4fa --- /dev/null +++ b/testing/web-platform/tests/client-hints/META.yml @@ -0,0 +1,5 @@ +spec: https://wicg.github.io/client-hints-infrastructure/ +suggested_reviewers: + - igrigorik + - yoavweiss + - tarunban diff --git a/testing/web-platform/tests/client-hints/accept-ch-change.https.html b/testing/web-platform/tests/client-hints/accept-ch-change.https.html new file mode 100644 index 0000000000..b0a4da61dd --- /dev/null +++ b/testing/web-platform/tests/client-hints/accept-ch-change.https.html @@ -0,0 +1,67 @@ +<!DOCTYPE html> +<html> +<title>Accept-CH test</title> +<body> +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> +<script src="resources/open-and-add-load-event.js"></script> + +<!-- +Apart from this webpage, the test opens two more html web page. One test is run +in this web page, and two in the other web pages. +--> + +<script> + +// This test fetches resources/accept_ch.html. The response headers to +// that webpage contains only the Accept-CH header. These preferences should be +// stored so that the next request to the same origin is sent with the +// requested client hint headers. + +// Next, to verify that the origin preferences were persisted by the user +// agent, this test fetches resources/expect_client_hints_headers.html in a new +// window. Fetching of resources/expect_client_hints_headers.html verifies that +// the user agent does send the client hints in the request headers. + +// After this, the same is done but with a differet Accept-CH header, to test +// that the preferences change after receiving a different header. + +promise_test(async () => { + r = await fetch("resources/echo-client-hints-received.py"); + + assert_equals(r.status, 200); + // Verify that the browser did not include client hints in the request + // headers when fetching echo_client_hints_received.py. + assert_false(r.headers.has("device-memory-received"), "device-memory-received"); + assert_false(r.headers.has("device-memory-deprecated-received"), "device-memory-deprecated-received"); + assert_false(r.headers.has("viewport-width-received"), "viewport-width-received"); + assert_false(r.headers.has("viewport-width-deprecated-received"), "viewport-width-deprecated-received"); + + // Fetching this webpage should cause user-agent to persist client hint + // preferences for the origin. + await open_and_add_load_event("resources/accept-ch.html"); + + // Open a new window. Verify that the user agent does attach the client hints. + await open_and_expect_headers("resources/expect-client-hints-headers.html"); + + // Use new window to overwrite client hint preferences, then verify new + // settings have been saved + await open_and_add_load_event("resources/accept-ch-different.html"); + + // Use new window to overwrite client hint preferences, then verify new + // settings have been saved + await open_and_expect_headers("resources/expect-different-client-hints-headers.html"); + + // Use new window to overwrite client hint preferences, then verify new + // settings have been saved + await open_and_add_load_event("resources/accept-ch-empty.html"); + + // Use new window to overwrite client hint preferences, then verify new + // settings have been saved + await open_and_expect_headers("resources/expect-no-client-hints-headers.html"); + +}, "Accept-CH changes based on header"); + +</script> +</body> +</html> diff --git a/testing/web-platform/tests/client-hints/accept-ch-malformed-header.https.html b/testing/web-platform/tests/client-hints/accept-ch-malformed-header.https.html new file mode 100644 index 0000000000..649ecf9590 --- /dev/null +++ b/testing/web-platform/tests/client-hints/accept-ch-malformed-header.https.html @@ -0,0 +1,24 @@ +<!DOCTYPE html> +<body> +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> +<script src="resources/open-and-add-load-event.js"></script> + +<script> + +promise_test(async t => { + t.add_cleanup(() => { + return open_and_add_load_event("resources/accept-ch-empty.html"); + }); + + await open_and_add_load_event("resources/accept-ch-malformed.html"); + // Verify that the browser does not include client hints in the headers + // since Accept-CH is malformed (includes whitespace between attributes + // instead of comma). + await open_and_expect_headers("resources/expect-no-client-hints-headers.html"); +}, "Accept-CH malformed header test"); + +</script> + +</body> +</html> diff --git a/testing/web-platform/tests/client-hints/accept-ch-malformed-header.https.html.headers b/testing/web-platform/tests/client-hints/accept-ch-malformed-header.https.html.headers new file mode 100644 index 0000000000..81396b1e41 --- /dev/null +++ b/testing/web-platform/tests/client-hints/accept-ch-malformed-header.https.html.headers @@ -0,0 +1 @@ +Accept-CH: sec-ch-device-memory device-memory sec-ch-dpr dpr
\ No newline at end of file diff --git a/testing/web-platform/tests/client-hints/accept-ch-stickiness/README.md b/testing/web-platform/tests/client-hints/accept-ch-stickiness/README.md new file mode 100644 index 0000000000..7dd1c6ddaf --- /dev/null +++ b/testing/web-platform/tests/client-hints/accept-ch-stickiness/README.md @@ -0,0 +1,14 @@ +These tests all follow the same format, calling the `run_test` function from +`resources/accept_ch_test.js`. This function does the following: + + * checks to make sure no client-hint preferences are saved for a particular origin + * loading a page with the response header `Accept-CH: device-memory` via a + particular method: + * Navigation (via window.open) + * Subresource (via fetch) + * iframe (added via js) + * Navigates to another page to check if the device-memory client hint was sent + with the next request + +Each test is in a separate file to ensure that the browser and it's state is +properly reset between each test. diff --git a/testing/web-platform/tests/client-hints/accept-ch-stickiness/cross-origin-iframe-not-setting-other-origins.https.html b/testing/web-platform/tests/client-hints/accept-ch-stickiness/cross-origin-iframe-not-setting-other-origins.https.html new file mode 100644 index 0000000000..5316c2874c --- /dev/null +++ b/testing/web-platform/tests/client-hints/accept-ch-stickiness/cross-origin-iframe-not-setting-other-origins.https.html @@ -0,0 +1,19 @@ +<!doctype html> +<meta name="timeout" content="long"> +<title>Accept-CH Persistence test</title> +<body> +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> +<script src="/common/get-host-info.sub.js"></script> +<script src="resources/accept-ch-test.js"></script> + +<script> +run_test({ name: "cross origin iframe not setting other origins", + initial_url: echo, + accept_url: host_info.HTTPS_REMOTE_ORIGIN + accept, + expect_url: do_not_expect, + type: "iframe" }); +</script> +</body> +</html> + diff --git a/testing/web-platform/tests/client-hints/accept-ch-stickiness/cross-origin-iframe-not-setting-own-origin.https.html b/testing/web-platform/tests/client-hints/accept-ch-stickiness/cross-origin-iframe-not-setting-own-origin.https.html new file mode 100644 index 0000000000..f83aa6173e --- /dev/null +++ b/testing/web-platform/tests/client-hints/accept-ch-stickiness/cross-origin-iframe-not-setting-own-origin.https.html @@ -0,0 +1,19 @@ +<!doctype html> +<meta name="timeout" content="long"> +<title>Accept-CH Persistence test</title> +<body> +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> +<script src="/common/get-host-info.sub.js"></script> +<script src="resources/accept-ch-test.js"></script> + +<script> +run_test({ name: "cross origin iframe not setting own origin", + initial_url: host_info.HTTPS_REMOTE_ORIGIN + echo, + accept_url: host_info.HTTPS_REMOTE_ORIGIN + accept, + expect_url: host_info.HTTPS_REMOTE_ORIGIN + do_not_expect, + type: "iframe" }); +</script> +</body> +</html> + diff --git a/testing/web-platform/tests/client-hints/accept-ch-stickiness/cross-origin-iframe-redirect-with-fp-delegation.https.html b/testing/web-platform/tests/client-hints/accept-ch-stickiness/cross-origin-iframe-redirect-with-fp-delegation.https.html new file mode 100644 index 0000000000..a2bc66fca1 --- /dev/null +++ b/testing/web-platform/tests/client-hints/accept-ch-stickiness/cross-origin-iframe-redirect-with-fp-delegation.https.html @@ -0,0 +1,18 @@ +<!doctype html> +<meta name="timeout" content="long"> +<title>Accept-CH Persistence test</title> +<body> +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> +<script src="/common/get-host-info.sub.js"></script> +<script src="resources/accept-ch-test.js"></script> + +<script> +// Make sure that cross origin iframes that gets redirected, and has Feature Policy delegation maintain their Client Hints. +const test_name = "Iframe redirect with Feature Policy delegation"; +verify_iframe_state("resources/accept-ch-and-redir.py?url=" + get_host_info()["HTTPS_REMOTE_ORIGIN"] + "/client-hints/accept-ch-stickiness/resources/expect-received.py", test_name); + +</script> +</body> +</html> + diff --git a/testing/web-platform/tests/client-hints/accept-ch-stickiness/cross-origin-iframe-redirect-with-fp-delegation.https.html.headers b/testing/web-platform/tests/client-hints/accept-ch-stickiness/cross-origin-iframe-redirect-with-fp-delegation.https.html.headers new file mode 100644 index 0000000000..f3f85f9eba --- /dev/null +++ b/testing/web-platform/tests/client-hints/accept-ch-stickiness/cross-origin-iframe-redirect-with-fp-delegation.https.html.headers @@ -0,0 +1,2 @@ +Accept-CH: Sec-CH-DPR, DPR, Sec-CH-Device-Memory, Device-Memory +Feature-Policy: ch-dpr *; ch-device-memory * diff --git a/testing/web-platform/tests/client-hints/accept-ch-stickiness/cross-origin-navigation-redirect.https.html b/testing/web-platform/tests/client-hints/accept-ch-stickiness/cross-origin-navigation-redirect.https.html new file mode 100644 index 0000000000..14ba51ab5d --- /dev/null +++ b/testing/web-platform/tests/client-hints/accept-ch-stickiness/cross-origin-navigation-redirect.https.html @@ -0,0 +1,18 @@ +<!doctype html> +<meta name="timeout" content="long"> +<title>Accept-CH Persistence test</title> +<body> +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> +<script src="/common/get-host-info.sub.js"></script> +<script src="resources/accept-ch-test.js"></script> + +<script> +// Make sure a cross origin navigation that gets redirected doesn't keep the initial request's Client Hints. +const test_name = "cross-origin redirect on navigation"; +verify_navigation_state("resources/accept-ch-and-redir.py?url=" + get_host_info()["HTTPS_REMOTE_ORIGIN"] + "/client-hints/accept-ch-stickiness/resources/do-not-expect-received.py", test_name); + +</script> +</body> +</html> + diff --git a/testing/web-platform/tests/client-hints/accept-ch-stickiness/cross-origin-navigation-redirect.https.html.headers b/testing/web-platform/tests/client-hints/accept-ch-stickiness/cross-origin-navigation-redirect.https.html.headers new file mode 100644 index 0000000000..af6945319d --- /dev/null +++ b/testing/web-platform/tests/client-hints/accept-ch-stickiness/cross-origin-navigation-redirect.https.html.headers @@ -0,0 +1 @@ +Accept-CH: Sec-CH-DPR, DPR, Sec-CH-Device-Memory, Device-Memory diff --git a/testing/web-platform/tests/client-hints/accept-ch-stickiness/cross-origin-navigation.https.html b/testing/web-platform/tests/client-hints/accept-ch-stickiness/cross-origin-navigation.https.html new file mode 100644 index 0000000000..e05c8e3ef5 --- /dev/null +++ b/testing/web-platform/tests/client-hints/accept-ch-stickiness/cross-origin-navigation.https.html @@ -0,0 +1,19 @@ +<!doctype html> +<meta name="timeout" content="long"> +<title>Accept-CH Persistence test</title> +<body> +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> +<script src="/common/get-host-info.sub.js"></script> +<script src="resources/accept-ch-test.js"></script> + +<script> +run_test({ name: "cross origin navigation", + initial_url: echo, + accept_url: host_info.HTTPS_REMOTE_ORIGIN + accept, + expect_url: host_info.HTTPS_REMOTE_ORIGIN + expect, + type: "navigation" }); +</script> +</body> +</html> + diff --git a/testing/web-platform/tests/client-hints/accept-ch-stickiness/cross-origin-subresource-redirect-with-fp-delegation.https.html b/testing/web-platform/tests/client-hints/accept-ch-stickiness/cross-origin-subresource-redirect-with-fp-delegation.https.html new file mode 100644 index 0000000000..dd7b9fab97 --- /dev/null +++ b/testing/web-platform/tests/client-hints/accept-ch-stickiness/cross-origin-subresource-redirect-with-fp-delegation.https.html @@ -0,0 +1,17 @@ +<!doctype html> +<meta name="timeout" content="long"> +<title>Accept-CH Persistence test</title> +<body> +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> +<script src="/common/get-host-info.sub.js"></script> +<script src="resources/accept-ch-test.js"></script> + +<script> +// Make sure a cross origin subresource that gets redirected with Feature Policy delegation keeps the initial request's Client Hints. +const test_name = "cross-origin subresource redirect with Feature Policy delegation"; +verify_subresource_state("resources/accept-ch-and-redir.py?url=" + get_host_info()["HTTPS_REMOTE_ORIGIN"] + "/client-hints/accept-ch-stickiness/resources/expect-received.py", test_name); +</script> +</body> +</html> + diff --git a/testing/web-platform/tests/client-hints/accept-ch-stickiness/cross-origin-subresource-redirect-with-fp-delegation.https.html.headers b/testing/web-platform/tests/client-hints/accept-ch-stickiness/cross-origin-subresource-redirect-with-fp-delegation.https.html.headers new file mode 100644 index 0000000000..ed41009784 --- /dev/null +++ b/testing/web-platform/tests/client-hints/accept-ch-stickiness/cross-origin-subresource-redirect-with-fp-delegation.https.html.headers @@ -0,0 +1,2 @@ +Accept-CH: Sec-CH-DPR, DPR, Sec-CH-Device-Memory, Device-Memory +Feature-Policy: ch-dpr *;ch-device-memory * diff --git a/testing/web-platform/tests/client-hints/accept-ch-stickiness/cross-origin-subresource-redirect.https.html b/testing/web-platform/tests/client-hints/accept-ch-stickiness/cross-origin-subresource-redirect.https.html new file mode 100644 index 0000000000..31334543cf --- /dev/null +++ b/testing/web-platform/tests/client-hints/accept-ch-stickiness/cross-origin-subresource-redirect.https.html @@ -0,0 +1,17 @@ +<!doctype html> +<meta name="timeout" content="long"> +<title>Accept-CH Persistence test</title> +<body> +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> +<script src="/common/get-host-info.sub.js"></script> +<script src="resources/accept-ch-test.js"></script> + +<script> +// Make sure a cross origin subresource that gets redirected doesn't keep the initial request's Client Hints. +const test_name = "cross-origin subresource redirect"; +verify_subresource_state("resources/accept-ch-and-redir.py?url=" + get_host_info()["HTTPS_REMOTE_ORIGIN"] + "/client-hints/accept-ch-stickiness/resources/do-not-expect-received.py", test_name); +</script> +</body> +</html> + diff --git a/testing/web-platform/tests/client-hints/accept-ch-stickiness/cross-origin-subresource-redirect.https.html.headers b/testing/web-platform/tests/client-hints/accept-ch-stickiness/cross-origin-subresource-redirect.https.html.headers new file mode 100644 index 0000000000..af6945319d --- /dev/null +++ b/testing/web-platform/tests/client-hints/accept-ch-stickiness/cross-origin-subresource-redirect.https.html.headers @@ -0,0 +1 @@ +Accept-CH: Sec-CH-DPR, DPR, Sec-CH-Device-Memory, Device-Memory diff --git a/testing/web-platform/tests/client-hints/accept-ch-stickiness/cross-origin-subresource-with-feature-policy.https.html b/testing/web-platform/tests/client-hints/accept-ch-stickiness/cross-origin-subresource-with-feature-policy.https.html new file mode 100644 index 0000000000..3108c23faa --- /dev/null +++ b/testing/web-platform/tests/client-hints/accept-ch-stickiness/cross-origin-subresource-with-feature-policy.https.html @@ -0,0 +1,19 @@ +<!doctype html> +<meta name="timeout" content="long"> +<title>Accept-CH Persistence test</title> +<body> +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> +<script src="/common/get-host-info.sub.js"></script> +<script src="resources/accept-ch-test.js"></script> + +<script> +run_test({ name: "cross origin subresources authorized by FP gets it own resources", + initial_url: echo, + accept_url: accept, + expect_url: "resources/feature-policy-with-cross-origin-subresource.html", + type: "navigation" }); +</script> +</body> +</html> + diff --git a/testing/web-platform/tests/client-hints/accept-ch-stickiness/cross-origin-subresource.https.html b/testing/web-platform/tests/client-hints/accept-ch-stickiness/cross-origin-subresource.https.html new file mode 100644 index 0000000000..249ccb4a60 --- /dev/null +++ b/testing/web-platform/tests/client-hints/accept-ch-stickiness/cross-origin-subresource.https.html @@ -0,0 +1,19 @@ +<!doctype html> +<meta name="timeout" content="long"> +<title>Accept-CH Persistence test</title> +<body> +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> +<script src="/common/get-host-info.sub.js"></script> +<script src="resources/accept-ch-test.js"></script> + +<script> +run_test({ name: "cross origin subresource", + initial_url: host_info.HTTPS_REMOTE_ORIGIN + echo, + accept_url: host_info.HTTPS_REMOTE_ORIGIN + accept, + expect_url: host_info.HTTPS_REMOTE_ORIGIN + do_not_expect, + type: "subresource" }); +</script> +</body> +</html> + diff --git a/testing/web-platform/tests/client-hints/accept-ch-stickiness/cross-origin-syncxhr-redirect.https.html b/testing/web-platform/tests/client-hints/accept-ch-stickiness/cross-origin-syncxhr-redirect.https.html new file mode 100644 index 0000000000..1cce664d2c --- /dev/null +++ b/testing/web-platform/tests/client-hints/accept-ch-stickiness/cross-origin-syncxhr-redirect.https.html @@ -0,0 +1,17 @@ +<!doctype html> +<meta name="timeout" content="long"> +<title>Accept-CH Persistence test</title> +<body> +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> +<script src="/common/get-host-info.sub.js"></script> +<script src="resources/accept-ch-test.js"></script> + +<script> +// Make sure a cross origin syn XHR that gets redirected doesn't keep the initial request's Client Hints. +const test_name = "cross-origin sync XHR redirect"; +verify_syncxhr_state("resources/accept-ch-and-redir.py?url=" + get_host_info()["HTTPS_REMOTE_ORIGIN"] + "/client-hints/accept-ch-stickiness/resources/do-not-expect-received.py", test_name); +</script> +</body> +</html> + diff --git a/testing/web-platform/tests/client-hints/accept-ch-stickiness/cross-origin-syncxhr-redirect.https.html.headers b/testing/web-platform/tests/client-hints/accept-ch-stickiness/cross-origin-syncxhr-redirect.https.html.headers new file mode 100644 index 0000000000..af6945319d --- /dev/null +++ b/testing/web-platform/tests/client-hints/accept-ch-stickiness/cross-origin-syncxhr-redirect.https.html.headers @@ -0,0 +1 @@ +Accept-CH: Sec-CH-DPR, DPR, Sec-CH-Device-Memory, Device-Memory diff --git a/testing/web-platform/tests/client-hints/accept-ch-stickiness/http-equiv-cross-origin-iframe-not-setting-other-origins.https.html b/testing/web-platform/tests/client-hints/accept-ch-stickiness/http-equiv-cross-origin-iframe-not-setting-other-origins.https.html new file mode 100644 index 0000000000..226b3116fc --- /dev/null +++ b/testing/web-platform/tests/client-hints/accept-ch-stickiness/http-equiv-cross-origin-iframe-not-setting-other-origins.https.html @@ -0,0 +1,19 @@ +<!doctype html> +<meta name="timeout" content="long"> +<title>Accept-CH Persistence test</title> +<body> +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> +<script src="/common/get-host-info.sub.js"></script> +<script src="resources/accept-ch-test.js"></script> + +<script> +run_test({ name: "http-equiv cross origin iframe not setting other origins", + initial_url: echo, + accept_url: host_info.HTTPS_REMOTE_ORIGIN + httpequiv_accept, + expect_url: do_not_expect, + type: "iframe" }); +</script> +</body> +</html> + diff --git a/testing/web-platform/tests/client-hints/accept-ch-stickiness/http-equiv-cross-origin-iframe-not-setting-own-origin.https.html b/testing/web-platform/tests/client-hints/accept-ch-stickiness/http-equiv-cross-origin-iframe-not-setting-own-origin.https.html new file mode 100644 index 0000000000..705b65a7bf --- /dev/null +++ b/testing/web-platform/tests/client-hints/accept-ch-stickiness/http-equiv-cross-origin-iframe-not-setting-own-origin.https.html @@ -0,0 +1,19 @@ +<!doctype html> +<meta name="timeout" content="long"> +<title>Accept-CH Persistence test</title> +<body> +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> +<script src="/common/get-host-info.sub.js"></script> +<script src="resources/accept-ch-test.js"></script> + +<script> +run_test({ name: "http-equiv cross origin iframe not setting own origin", + initial_url: host_info.HTTPS_REMOTE_ORIGIN + echo, + accept_url: host_info.HTTPS_REMOTE_ORIGIN + httpequiv_accept, + expect_url: host_info.HTTPS_REMOTE_ORIGIN + do_not_expect, + type: "iframe" }); +</script> +</body> +</html> + diff --git a/testing/web-platform/tests/client-hints/accept-ch-stickiness/http-equiv-cross-origin-navigation.https.html b/testing/web-platform/tests/client-hints/accept-ch-stickiness/http-equiv-cross-origin-navigation.https.html new file mode 100644 index 0000000000..d2fa472015 --- /dev/null +++ b/testing/web-platform/tests/client-hints/accept-ch-stickiness/http-equiv-cross-origin-navigation.https.html @@ -0,0 +1,19 @@ +<!doctype html> +<meta name="timeout" content="long"> +<title>Accept-CH Persistence test</title> +<body> +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> +<script src="/common/get-host-info.sub.js"></script> +<script src="resources/accept-ch-test.js"></script> + +<script> +run_test({ name: "http-equiv cross origin navigation", + initial_url: echo, + accept_url: host_info.HTTPS_REMOTE_ORIGIN + httpequiv_accept, + expect_url: host_info.HTTPS_REMOTE_ORIGIN + do_not_expect, + type: "navigation" }); +</script> +</body> +</html> + diff --git a/testing/web-platform/tests/client-hints/accept-ch-stickiness/http-equiv-cross-origin-subresource.https.html b/testing/web-platform/tests/client-hints/accept-ch-stickiness/http-equiv-cross-origin-subresource.https.html new file mode 100644 index 0000000000..7bb5d1520c --- /dev/null +++ b/testing/web-platform/tests/client-hints/accept-ch-stickiness/http-equiv-cross-origin-subresource.https.html @@ -0,0 +1,19 @@ +<!doctype html> +<meta name="timeout" content="long"> +<title>Accept-CH Persistence test</title> +<body> +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> +<script src="/common/get-host-info.sub.js"></script> +<script src="resources/accept-ch-test.js"></script> + +<script> +run_test({ name: "http-equiv cross origin subresource", + initial_url: host_info.HTTPS_REMOTE_ORIGIN + echo, + accept_url: host_info.HTTPS_REMOTE_ORIGIN + httpequiv_accept, + expect_url: host_info.HTTPS_REMOTE_ORIGIN + do_not_expect, + type: "subresource" }); +</script> +</body> +</html> + diff --git a/testing/web-platform/tests/client-hints/accept-ch-stickiness/http-equiv-same-origin-iframe.https.html b/testing/web-platform/tests/client-hints/accept-ch-stickiness/http-equiv-same-origin-iframe.https.html new file mode 100644 index 0000000000..93380ad23c --- /dev/null +++ b/testing/web-platform/tests/client-hints/accept-ch-stickiness/http-equiv-same-origin-iframe.https.html @@ -0,0 +1,19 @@ +<!doctype html> +<!-- <meta name="timeout" content="long"> --> +<title>Accept-CH Persistence test</title> +<body> +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> +<script src="/common/get-host-info.sub.js"></script> +<script src="resources/accept-ch-test.js"></script> + +<script> +run_test({ name: "http-equiv same origin iframe", + initial_url: echo, + accept_url: httpequiv_accept, + expect_url: do_not_expect, + type: "iframe" }); +</script> +</body> +</html> + diff --git a/testing/web-platform/tests/client-hints/accept-ch-stickiness/http-equiv-same-origin-navigation.https.html b/testing/web-platform/tests/client-hints/accept-ch-stickiness/http-equiv-same-origin-navigation.https.html new file mode 100644 index 0000000000..6efd7ccdf5 --- /dev/null +++ b/testing/web-platform/tests/client-hints/accept-ch-stickiness/http-equiv-same-origin-navigation.https.html @@ -0,0 +1,19 @@ +<!doctype html> +<meta name="timeout" content="long"> +<title>Accept-CH Persistence test</title> +<body> +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> +<script src="/common/get-host-info.sub.js"></script> +<script src="resources/accept-ch-test.js"></script> + +<script> +run_test({ name: "http-equiv same origin navigation", + initial_url: echo, + accept_url: httpequiv_accept, + expect_url: do_not_expect, + type: "navigation" }); +</script> +</body> +</html> + diff --git a/testing/web-platform/tests/client-hints/accept-ch-stickiness/http-equiv-same-origin-subresource.https.html b/testing/web-platform/tests/client-hints/accept-ch-stickiness/http-equiv-same-origin-subresource.https.html new file mode 100644 index 0000000000..793bf5e079 --- /dev/null +++ b/testing/web-platform/tests/client-hints/accept-ch-stickiness/http-equiv-same-origin-subresource.https.html @@ -0,0 +1,19 @@ +<!doctype html> +<meta name="timeout" content="long"> +<title>Accept-CH Persistence test</title> +<body> +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> +<script src="/common/get-host-info.sub.js"></script> +<script src="resources/accept-ch-test.js"></script> + +<script> +run_test({ name: "http-equiv same origin subresource", + initial_url: echo, + accept_url: httpequiv_accept, + expect_url: do_not_expect, + type: "subresource" }); +</script> +</body> +</html> + diff --git a/testing/web-platform/tests/client-hints/accept-ch-stickiness/meta-equiv-cross-origin-iframe-not-setting-other-origins.https.html b/testing/web-platform/tests/client-hints/accept-ch-stickiness/meta-equiv-cross-origin-iframe-not-setting-other-origins.https.html new file mode 100644 index 0000000000..9c4e9cf506 --- /dev/null +++ b/testing/web-platform/tests/client-hints/accept-ch-stickiness/meta-equiv-cross-origin-iframe-not-setting-other-origins.https.html @@ -0,0 +1,19 @@ +<!doctype html> +<meta name="timeout" content="long"> +<title>Meta cross origin iframe not setting other origins</title> +<body> +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> +<script src="/common/get-host-info.sub.js"></script> +<script src="resources/accept-ch-test.js"></script> + +<script> +run_test({ name: "meta-equiv delegate-ch cross origin iframe not setting other origins", + initial_url: echo, + accept_url: host_info.HTTPS_REMOTE_ORIGIN + metaequiv_delegate, + expect_url: do_not_expect, + type: "iframe" }); +</script> +</body> +</html> + diff --git a/testing/web-platform/tests/client-hints/accept-ch-stickiness/meta-equiv-cross-origin-iframe-not-setting-own-origin.https.html b/testing/web-platform/tests/client-hints/accept-ch-stickiness/meta-equiv-cross-origin-iframe-not-setting-own-origin.https.html new file mode 100644 index 0000000000..26e30a40e7 --- /dev/null +++ b/testing/web-platform/tests/client-hints/accept-ch-stickiness/meta-equiv-cross-origin-iframe-not-setting-own-origin.https.html @@ -0,0 +1,19 @@ +<!doctype html> +<meta name="timeout" content="long"> +<title>Meta cross origin iframe not setting own origin</title> +<body> +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> +<script src="/common/get-host-info.sub.js"></script> +<script src="resources/accept-ch-test.js"></script> + +<script> +run_test({ name: "meta-equiv delegate-ch cross origin iframe not setting own origin", + initial_url: host_info.HTTPS_REMOTE_ORIGIN + echo, + accept_url: host_info.HTTPS_REMOTE_ORIGIN + metaequiv_delegate, + expect_url: host_info.HTTPS_REMOTE_ORIGIN + do_not_expect, + type: "iframe" }); +</script> +</body> +</html> + diff --git a/testing/web-platform/tests/client-hints/accept-ch-stickiness/meta-equiv-cross-origin-navigation.https.html b/testing/web-platform/tests/client-hints/accept-ch-stickiness/meta-equiv-cross-origin-navigation.https.html new file mode 100644 index 0000000000..eb2292b22f --- /dev/null +++ b/testing/web-platform/tests/client-hints/accept-ch-stickiness/meta-equiv-cross-origin-navigation.https.html @@ -0,0 +1,19 @@ +<!doctype html> +<meta name="timeout" content="long"> +<title>Meta cross origin navigation</title> +<body> +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> +<script src="/common/get-host-info.sub.js"></script> +<script src="resources/accept-ch-test.js"></script> + +<script> +run_test({ name: "meta-equiv delegate-ch cross origin navigation", + initial_url: echo, + accept_url: host_info.HTTPS_REMOTE_ORIGIN + metaequiv_delegate, + expect_url: host_info.HTTPS_REMOTE_ORIGIN + do_not_expect, + type: "navigation" }); +</script> +</body> +</html> + diff --git a/testing/web-platform/tests/client-hints/accept-ch-stickiness/meta-equiv-cross-origin-subresource.https.html b/testing/web-platform/tests/client-hints/accept-ch-stickiness/meta-equiv-cross-origin-subresource.https.html new file mode 100644 index 0000000000..31775cbea2 --- /dev/null +++ b/testing/web-platform/tests/client-hints/accept-ch-stickiness/meta-equiv-cross-origin-subresource.https.html @@ -0,0 +1,19 @@ +<!doctype html> +<meta name="timeout" content="long"> +<title>Meta cross origin subresource</title> +<body> +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> +<script src="/common/get-host-info.sub.js"></script> +<script src="resources/accept-ch-test.js"></script> + +<script> +run_test({ name: "meta-equiv delegate-ch cross origin subresource", + initial_url: host_info.HTTPS_REMOTE_ORIGIN + echo, + accept_url: host_info.HTTPS_REMOTE_ORIGIN + metaequiv_delegate, + expect_url: host_info.HTTPS_REMOTE_ORIGIN + do_not_expect, + type: "subresource" }); +</script> +</body> +</html> + diff --git a/testing/web-platform/tests/client-hints/accept-ch-stickiness/meta-equiv-delegate-ch-cross-origin-iframe-with-hints.https.sub.html b/testing/web-platform/tests/client-hints/accept-ch-stickiness/meta-equiv-delegate-ch-cross-origin-iframe-with-hints.https.sub.html new file mode 100644 index 0000000000..0a2c4897bc --- /dev/null +++ b/testing/web-platform/tests/client-hints/accept-ch-stickiness/meta-equiv-delegate-ch-cross-origin-iframe-with-hints.https.sub.html @@ -0,0 +1,18 @@ +<!doctype html> +<meta name="timeout" content="long"> +<meta http-equiv="Delegate-CH" content="sec-ch-device-memory https://www1.{{host}}:{{ports[https][0]}}/; device-memory https://www1.{{host}}:{{ports[https][0]}}/"> +<title>Meta-equiv Delegate-CH cross origin iframe with hints</title> +<body> +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> +<script src="/common/get-host-info.sub.js"></script> +<script src="resources/accept-ch-test.js"></script> + +<script> +verify_iframe_state( + host_info.HTTPS_REMOTE_ORIGIN + "/client-hints/accept-ch-stickiness/resources/do-expect-received.py", + "meta-equiv cross origin iframe with hints"); +</script> +</body> +</html> + diff --git a/testing/web-platform/tests/client-hints/accept-ch-stickiness/meta-equiv-delegate-ch-cross-origin-iframe-without-hints.https.sub.html b/testing/web-platform/tests/client-hints/accept-ch-stickiness/meta-equiv-delegate-ch-cross-origin-iframe-without-hints.https.sub.html new file mode 100644 index 0000000000..b79a941237 --- /dev/null +++ b/testing/web-platform/tests/client-hints/accept-ch-stickiness/meta-equiv-delegate-ch-cross-origin-iframe-without-hints.https.sub.html @@ -0,0 +1,18 @@ +<!doctype html> +<meta name="timeout" content="long"> +<meta http-equiv="Delegate-CH" content="sec-ch-device-memory https://{{host}}:{{ports[https][0]}}/; device-memory https://{{host}}:{{ports[https][0]}}/"> +<title>Meta-equiv Delegate-CH cross origin iframe without hints</title> +<body> +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> +<script src="/common/get-host-info.sub.js"></script> +<script src="resources/accept-ch-test.js"></script> + +<script> +verify_iframe_state( + host_info.HTTPS_REMOTE_ORIGIN + "/client-hints/accept-ch-stickiness/resources/do-not-expect-received.py", + "meta-equiv cross origin iframe without hints"); +</script> +</body> +</html> + diff --git a/testing/web-platform/tests/client-hints/accept-ch-stickiness/meta-equiv-delegate-ch-cross-origin-subresource-with-hints.https.sub.html b/testing/web-platform/tests/client-hints/accept-ch-stickiness/meta-equiv-delegate-ch-cross-origin-subresource-with-hints.https.sub.html new file mode 100644 index 0000000000..bd39cbaff4 --- /dev/null +++ b/testing/web-platform/tests/client-hints/accept-ch-stickiness/meta-equiv-delegate-ch-cross-origin-subresource-with-hints.https.sub.html @@ -0,0 +1,18 @@ +<!doctype html> +<meta name="timeout" content="long"> +<meta http-equiv="Delegate-CH" content="sec-ch-device-memory https://www1.{{host}}:{{ports[https][0]}}/; device-memory https://www1.{{host}}:{{ports[https][0]}}/"> +<title>Meta-equiv Delegate-CH cross origin subresource with hints</title> +<body> +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> +<script src="/common/get-host-info.sub.js"></script> +<script src="resources/accept-ch-test.js"></script> + +<script> +verify_subresource_state( + host_info.HTTPS_REMOTE_ORIGIN + "/client-hints/accept-ch-stickiness/resources/do-expect-received.py", + "meta-equiv cross origin subresource with hints"); +</script> +</body> +</html> + diff --git a/testing/web-platform/tests/client-hints/accept-ch-stickiness/meta-equiv-delegate-ch-cross-origin-subresource-without-hints.https.sub.html b/testing/web-platform/tests/client-hints/accept-ch-stickiness/meta-equiv-delegate-ch-cross-origin-subresource-without-hints.https.sub.html new file mode 100644 index 0000000000..20a3357fb6 --- /dev/null +++ b/testing/web-platform/tests/client-hints/accept-ch-stickiness/meta-equiv-delegate-ch-cross-origin-subresource-without-hints.https.sub.html @@ -0,0 +1,18 @@ +<!doctype html> +<meta name="timeout" content="long"> +<meta http-equiv="Delegate-CH" content="sec-ch-device-memory https://{{host}}:{{ports[https][0]}}/; device-memory https://{{host}}:{{ports[https][0]}}/"> +<title>Meta-equiv Delegate-CH cross origin subresource without hints</title> +<body> +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> +<script src="/common/get-host-info.sub.js"></script> +<script src="resources/accept-ch-test.js"></script> + +<script> +verify_subresource_state( + host_info.HTTPS_REMOTE_ORIGIN + "/client-hints/accept-ch-stickiness/resources/do-not-expect-received.py", + "meta-equiv cross origin subresource without hints"); +</script> +</body> +</html> + diff --git a/testing/web-platform/tests/client-hints/accept-ch-stickiness/meta-equiv-same-origin-iframe.https.html b/testing/web-platform/tests/client-hints/accept-ch-stickiness/meta-equiv-same-origin-iframe.https.html new file mode 100644 index 0000000000..06a68ce3bc --- /dev/null +++ b/testing/web-platform/tests/client-hints/accept-ch-stickiness/meta-equiv-same-origin-iframe.https.html @@ -0,0 +1,19 @@ +<!doctype html> +<!-- <meta name="timeout" content="long"> --> +<title>Meta same origin iframe</title> +<body> +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> +<script src="/common/get-host-info.sub.js"></script> +<script src="resources/accept-ch-test.js"></script> + +<script> +run_test({ name: "meta-equiv delegate-ch same origin iframe", + initial_url: echo, + accept_url: metaequiv_delegate, + expect_url: do_not_expect, + type: "iframe" }); +</script> +</body> +</html> + diff --git a/testing/web-platform/tests/client-hints/accept-ch-stickiness/meta-equiv-same-origin-navigation.https.html b/testing/web-platform/tests/client-hints/accept-ch-stickiness/meta-equiv-same-origin-navigation.https.html new file mode 100644 index 0000000000..10fb120fc2 --- /dev/null +++ b/testing/web-platform/tests/client-hints/accept-ch-stickiness/meta-equiv-same-origin-navigation.https.html @@ -0,0 +1,19 @@ +<!doctype html> +<meta name="timeout" content="long"> +<title>Meta same origin navigation</title> +<body> +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> +<script src="/common/get-host-info.sub.js"></script> +<script src="resources/accept-ch-test.js"></script> + +<script> +run_test({ name: "meta-equiv delegate-ch same origin navigation", + initial_url: echo, + accept_url: metaequiv_delegate, + expect_url: do_not_expect, + type: "navigation" }); +</script> +</body> +</html> + diff --git a/testing/web-platform/tests/client-hints/accept-ch-stickiness/meta-equiv-same-origin-subresource.https.html b/testing/web-platform/tests/client-hints/accept-ch-stickiness/meta-equiv-same-origin-subresource.https.html new file mode 100644 index 0000000000..b4374476c6 --- /dev/null +++ b/testing/web-platform/tests/client-hints/accept-ch-stickiness/meta-equiv-same-origin-subresource.https.html @@ -0,0 +1,19 @@ +<!doctype html> +<meta name="timeout" content="long"> +<title>Meta same origin subresource</title> +<body> +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> +<script src="/common/get-host-info.sub.js"></script> +<script src="resources/accept-ch-test.js"></script> + +<script> +run_test({ name: "meta-equiv delegate-ch same origin subresource", + initial_url: echo, + accept_url: metaequiv_delegate, + expect_url: do_not_expect, + type: "subresource" }); +</script> +</body> +</html> + diff --git a/testing/web-platform/tests/client-hints/accept-ch-stickiness/resources/accept-ch-and-redir.py b/testing/web-platform/tests/client-hints/accept-ch-stickiness/resources/accept-ch-and-redir.py new file mode 100644 index 0000000000..16ab11faa7 --- /dev/null +++ b/testing/web-platform/tests/client-hints/accept-ch-stickiness/resources/accept-ch-and-redir.py @@ -0,0 +1,5 @@ +def main(request, response): + url = b'' + if b'url' in request.GET: + url = request.GET[b'url'] + return 301, [(b'Location', url),(b'Accept-CH', b'sec-ch-device-memory, device-memory, Sec-CH-DPR, DPR')], u'' diff --git a/testing/web-platform/tests/client-hints/accept-ch-stickiness/resources/accept-ch-blank.html b/testing/web-platform/tests/client-hints/accept-ch-stickiness/resources/accept-ch-blank.html new file mode 100644 index 0000000000..8a2e40ad90 --- /dev/null +++ b/testing/web-platform/tests/client-hints/accept-ch-stickiness/resources/accept-ch-blank.html @@ -0,0 +1,11 @@ +<html> +<body> + +<!-- Page with an empty accept-ch header, which disables client hints --> +<script> + window.top.opener.postMessage('Loaded', '*'); +</script> + + +</body> +</html> diff --git a/testing/web-platform/tests/client-hints/accept-ch-stickiness/resources/accept-ch-blank.html.headers b/testing/web-platform/tests/client-hints/accept-ch-stickiness/resources/accept-ch-blank.html.headers new file mode 100644 index 0000000000..25215abdf7 --- /dev/null +++ b/testing/web-platform/tests/client-hints/accept-ch-stickiness/resources/accept-ch-blank.html.headers @@ -0,0 +1,2 @@ +Accept-CH: +Access-Control-Allow-Origin: * diff --git a/testing/web-platform/tests/client-hints/accept-ch-stickiness/resources/accept-ch-test.js b/testing/web-platform/tests/client-hints/accept-ch-stickiness/resources/accept-ch-test.js new file mode 100644 index 0000000000..b0bf39250c --- /dev/null +++ b/testing/web-platform/tests/client-hints/accept-ch-stickiness/resources/accept-ch-test.js @@ -0,0 +1,133 @@ +const echo = "/client-hints/accept-ch-stickiness/resources/echo-client-hints-received.py"; +const accept = "/client-hints/accept-ch-stickiness/resources/accept-ch.html"; +const accept_blank = "/client-hints/accept-ch-stickiness/resources/accept-ch-blank.html"; +const no_accept = "/client-hints/accept-ch-stickiness/resources/no-accept-ch.html"; +const httpequiv_accept = "/client-hints/accept-ch-stickiness/resources/http-equiv-accept-ch.html"; +const metaequiv_delegate = "/client-hints/accept-ch-stickiness/resources/meta-equiv-delegate-ch.html"; +const expect = "/client-hints/accept-ch-stickiness/resources/expect-client-hints-headers.html" +const do_not_expect = "/client-hints/accept-ch-stickiness/resources/do-not-expect-client-hints-headers.html" + +const host_info = get_host_info(); + +function verify_initial_state(initial_url, test_name) { + promise_test(t => { + return fetch(initial_url).then(r => { + assert_equals(r.status, 200) + // Verify that the browser did not include client hints in the request + // headers when fetching echo-client-hints-received.py. + assert_false(r.headers.has("device-memory-received"), + "device-memory-received"); + assert_false(r.headers.has("device-memory-deprecated-received"), + "device-memory-deprecated-received"); + }); + }, test_name + " precondition: Test that the browser does not have client " + + "hints preferences cached"); +} + +function verify_iframe_state(expect_url, test_name) { + promise_test(t => { + return new Promise(resolve => { + window.addEventListener('message', t.step_func(function(e) { + assert_equals(e.data, "PASS", "message from opened frame"); + fetch("/client-hints/accept-ch-stickiness/resources/clear-site-data.html").then(resolve); + })); + const iframe = document.createElement("iframe"); + iframe.src = expect_url; + document.body.appendChild(iframe); + }); + }, test_name + " got client hints according to expectations."); +} + +function verify_navigation_state(expect_url, test_name) { + promise_test(t => { + return new Promise(resolve => { + let win; + window.addEventListener('message', t.step_func(function(e) { + win.close(); + assert_equals(e.data, "PASS", "message from opened page"); + fetch("/client-hints/accept-ch-stickiness/resources/clear-site-data.html").then(resolve); + })); + // Open a new window. Verify that the user agent attaches client hints. + win = window.open(expect_url); + assert_not_equals(win, null, "Popup windows not allowed?"); + }); + }, test_name + " got client hints according to expectations."); +} + +function verify_subresource_state(expect_url, test_name) { + promise_test(t => { + return new Promise(resolve => { + fetch(expect_url).then(response => response.text()).then(t.step_func(text => { + assert_true(text.includes("PASS")); + fetch("/client-hints/accept-ch-stickiness/resources/clear-site-data.html").then(resolve); + })); + }); + }, test_name + " got client hints according to expectations."); +} + +function verify_syncxhr_state(expect_url, test_name) { + promise_test(t => { + return new Promise(resolve => { + const xhr = new XMLHttpRequest(); + xhr.onreadystatechange = t.step_func(() => { + if (xhr.readyState != XMLHttpRequest.DONE) { + return; + } + assert_true(xhr.responseText.includes("PASS")); + fetch("/client-hints/accept-ch-stickiness/resources/clear-site-data.html").then(resolve); + }); + xhr.open("GET", expect_url, false /* async */); + xhr.send(); + }); + }, test_name + " got client hints according to expectations."); +} + +function attempt_set(test_type, accept_url, test_name, test_name_suffix) { + promise_test(t => { + return new Promise(resolve => { + if (test_type == "navigation") { + const win = window.open(accept_url); + assert_not_equals(win, null, "Popup windows not allowed?"); + addEventListener('message', t.step_func(() => { + win.close(); + resolve(); + }), false); + } else if (test_type == "iframe") { + const iframe = document.createElement("iframe"); + iframe.addEventListener('load', t.step_func(() => { + resolve(); + }), false); + iframe.src = accept_url; + document.body.appendChild(iframe); + } else if (test_type == "subresource") { + fetch(accept_url).then(r => { + assert_equals(r.status, 200, "subresource response status") + // Verify that the browser did not include client hints in the request + // headers, just because we can.. + assert_false(r.headers.has("device-memory-received"), + "device-memory-received", + "subresource request had no client hints"); + assert_false(r.headers.has("device-memory-deprecated-received"), + "device-memory-deprecated-received", + "subresource request had no client hints"); + resolve(); + }); + } else { + assert_unreached("unknown test type"); + } + }); + }, test_name + " set Accept-CH" + test_name_suffix); +} + +const run_test = test => { + // First, verify the initial state to make sure that the browser does not have + // client hints preferences cached from a previous run of the test. + verify_initial_state(test.initial_url, test.name); + + // Then, attempt to set Accept-CH + attempt_set(test.type, test.accept_url, test.name, ""); + + // Finally, verify that CH are actually sent (or not) on requests + verify_navigation_state(test.expect_url, test.name); +}; + diff --git a/testing/web-platform/tests/client-hints/accept-ch-stickiness/resources/accept-ch.html b/testing/web-platform/tests/client-hints/accept-ch-stickiness/resources/accept-ch.html new file mode 100644 index 0000000000..694c5b03bc --- /dev/null +++ b/testing/web-platform/tests/client-hints/accept-ch-stickiness/resources/accept-ch.html @@ -0,0 +1,16 @@ +<html> +<body> + +<!-- An empty webpage whose response headers include Accept-CH +header. Fetching this webpage should cause +user-agent to persist origin preferences for the client hints +specified in the Accept-CH header until a Clear-Site-Data header +is sent or user action is take to clear the session or data about +the origin.--> +<script> + window.top.opener.postMessage('Loaded', '*'); +</script> + + +</body> +</html> diff --git a/testing/web-platform/tests/client-hints/accept-ch-stickiness/resources/accept-ch.html.headers b/testing/web-platform/tests/client-hints/accept-ch-stickiness/resources/accept-ch.html.headers new file mode 100644 index 0000000000..e3ee616f2b --- /dev/null +++ b/testing/web-platform/tests/client-hints/accept-ch-stickiness/resources/accept-ch.html.headers @@ -0,0 +1,2 @@ +Accept-CH: sec-ch-device-memory, device-memory, Sec-CH-DPR, DPR +Access-Control-Allow-Origin: * diff --git a/testing/web-platform/tests/client-hints/accept-ch-stickiness/resources/clear-site-data.html b/testing/web-platform/tests/client-hints/accept-ch-stickiness/resources/clear-site-data.html new file mode 100644 index 0000000000..e69de29bb2 --- /dev/null +++ b/testing/web-platform/tests/client-hints/accept-ch-stickiness/resources/clear-site-data.html diff --git a/testing/web-platform/tests/client-hints/accept-ch-stickiness/resources/clear-site-data.html.headers b/testing/web-platform/tests/client-hints/accept-ch-stickiness/resources/clear-site-data.html.headers new file mode 100644 index 0000000000..955424f246 --- /dev/null +++ b/testing/web-platform/tests/client-hints/accept-ch-stickiness/resources/clear-site-data.html.headers @@ -0,0 +1,2 @@ +Clear-Site-Data: "*" +Access-Control-Allow-Origin: *
\ No newline at end of file diff --git a/testing/web-platform/tests/client-hints/accept-ch-stickiness/resources/do-expect-received.py b/testing/web-platform/tests/client-hints/accept-ch-stickiness/resources/do-expect-received.py new file mode 100644 index 0000000000..d2a544e46a --- /dev/null +++ b/testing/web-platform/tests/client-hints/accept-ch-stickiness/resources/do-expect-received.py @@ -0,0 +1,20 @@ +def main(request, response): + """ + Check that headers sent to navigate here *do* contain the device-memory client + hint, and report success/failure in a way compatible with + verify_{subresource|iframe}_state() in accept-ch-test.js + """ + + if b"device-memory" in request.headers and b"sec-ch-device-memory" in request.headers: + result = u"PASS" + else: + result = u"FAIL" + + content = u''' +<script> + let messagee = window.opener || window.parent; + messagee.postMessage("%s" , "*"); +</script> +''' % (result) + headers = [(b"Content-Type", b"text/html"), (b"Access-Control-Allow-Origin", b"*")] + return 200, headers, content diff --git a/testing/web-platform/tests/client-hints/accept-ch-stickiness/resources/do-not-expect-client-hints-headers.html b/testing/web-platform/tests/client-hints/accept-ch-stickiness/resources/do-not-expect-client-hints-headers.html new file mode 100644 index 0000000000..2421eea18e --- /dev/null +++ b/testing/web-platform/tests/client-hints/accept-ch-stickiness/resources/do-not-expect-client-hints-headers.html @@ -0,0 +1,22 @@ +<html> +<body> +<script> + +// This test checks if browser attaches the device-memory client hint in the +// HTTP request headers. + +// echo-client-hints-received.py sets the response headers depending on the set +// of client hints it receives in the request headers. + +fetch("/client-hints/accept-ch-stickiness/resources/echo-client-hints-received.py").then(r => { + if(r.status == 200 && !r.headers.has("device-memory-received") && !r.headers.has("device-memory-deprecated-received")) { + window.top.opener.postMessage('PASS', '*'); + } + else { + window.top.opener.postMessage('FAIL', '*'); + } +}); + +</script> +</body> +</html> diff --git a/testing/web-platform/tests/client-hints/accept-ch-stickiness/resources/do-not-expect-received.py b/testing/web-platform/tests/client-hints/accept-ch-stickiness/resources/do-not-expect-received.py new file mode 100644 index 0000000000..48ebc21d14 --- /dev/null +++ b/testing/web-platform/tests/client-hints/accept-ch-stickiness/resources/do-not-expect-received.py @@ -0,0 +1,20 @@ +def main(request, response): + """ + Check that headers sent to navigate here *do not* contain the device-memory client + hint, and report success/failure in a way compatible with + verify_{subresource|iframe}_state() in accept-ch-test.js + """ + + if b"device-memory" in request.headers or b"sec-ch-device-memory" in request.headers: + result = u"FAIL" + else: + result = u"PASS" + + content = u''' +<script> + let messagee = window.opener || window.parent; + messagee.postMessage("%s" , "*"); +</script> +''' % (result) + headers = [(b"Content-Type", b"text/html"), (b"Access-Control-Allow-Origin", b"*")] + return 200, headers, content diff --git a/testing/web-platform/tests/client-hints/accept-ch-stickiness/resources/echo-client-hints-received.py b/testing/web-platform/tests/client-hints/accept-ch-stickiness/resources/echo-client-hints-received.py new file mode 100644 index 0000000000..3c61330671 --- /dev/null +++ b/testing/web-platform/tests/client-hints/accept-ch-stickiness/resources/echo-client-hints-received.py @@ -0,0 +1,14 @@ +def main(request, response): + """ + Simple handler that sets a response header based on which client hint + request headers were received. + """ + + response.headers.append(b"Access-Control-Allow-Origin", b"*") + response.headers.append(b"Access-Control-Allow-Headers", b"*") + response.headers.append(b"Access-Control-Expose-Headers", b"*") + + if b"sec-ch-device-memory" in request.headers: + response.headers.set(b"device-memory-received", request.headers.get(b"sec-ch-device-memory")) + if b"device-memory" in request.headers: + response.headers.set(b"device-memory-deprecated-received", request.headers.get(b"device-memory")) diff --git a/testing/web-platform/tests/client-hints/accept-ch-stickiness/resources/expect-client-hints-headers.html b/testing/web-platform/tests/client-hints/accept-ch-stickiness/resources/expect-client-hints-headers.html new file mode 100644 index 0000000000..1cde2ffd05 --- /dev/null +++ b/testing/web-platform/tests/client-hints/accept-ch-stickiness/resources/expect-client-hints-headers.html @@ -0,0 +1,22 @@ +<html> +<body> +<script> + +// This test checks if browser attaches the device-memory client hint in the +// HTTP request headers. + +// echo-client-hints-received.py sets the response headers depending on the set +// of client hints it receives in the request headers. + +fetch("/client-hints/accept-ch-stickiness/resources/echo-client-hints-received.py").then(r => { + if(r.status == 200 && r.headers.has("device-memory-received") && r.headers.has("device-memory-deprecated-received")) { + window.top.opener.postMessage('PASS', '*'); + } + else { + window.top.opener.postMessage('FAIL', '*'); + } +}); + +</script> +</body> +</html> diff --git a/testing/web-platform/tests/client-hints/accept-ch-stickiness/resources/expect-received.py b/testing/web-platform/tests/client-hints/accept-ch-stickiness/resources/expect-received.py new file mode 100644 index 0000000000..876f025f3e --- /dev/null +++ b/testing/web-platform/tests/client-hints/accept-ch-stickiness/resources/expect-received.py @@ -0,0 +1,28 @@ +def main(request, response): + """ + Check that headers sent to navigate here contain the device-memory client + hint, and report success/failure in a way compatible with + verify_navigation_state() in accept-ch-test.js + """ + + if b"sec-ch-device-memory" not in request.headers: + result = u"DEVICE-MEMORY" + elif b"device-memory" not in request.headers: + result = u"DEVICE-MEMORY-DEPRECATED" + elif b"sec-ch-ua" not in request.headers: + result = u"UA" + elif b"sec-ch-ua-mobile" not in request.headers: + result = u"MOBILE" + elif b"sec-ch-ua-platform" not in request.headers: + result = u"PLATFORM" + else: + result = u"PASS" + + content = u''' +<script> + let messagee = window.opener || window.parent; + messagee.postMessage("%s" , "*"); +</script> +''' % (result) + headers = [(b"Content-Type", b"text/html"), (b"Access-Control-Allow-Origin", b"*")] + return 200, headers, content diff --git a/testing/web-platform/tests/client-hints/accept-ch-stickiness/resources/feature-policy-with-cross-origin-subresource.html b/testing/web-platform/tests/client-hints/accept-ch-stickiness/resources/feature-policy-with-cross-origin-subresource.html new file mode 100644 index 0000000000..f7e1a767b4 --- /dev/null +++ b/testing/web-platform/tests/client-hints/accept-ch-stickiness/resources/feature-policy-with-cross-origin-subresource.html @@ -0,0 +1,25 @@ +<html> +<body> +<script src="/common/get-host-info.sub.js"></script> +<script> + +// This test checks if browser attaches the device-memory client hint in the +// HTTP request headers --- while requesting it from 3P context after +// settings feature policy to allow it; with Accept-CH coming from a sticky +// source. + +// echo-client-hints-received.py sets the response headers depending on the set +// of client hints it receives in the request headers. + +fetch(get_host_info()["HTTPS_REMOTE_ORIGIN"] + "/client-hints/accept-ch-stickiness/resources/echo-client-hints-received.py").then(r => { + if(r.status == 200 && r.headers.has("device-memory-received") && r.headers.has("device-memory-deprecated-received")) { + window.top.opener.postMessage('PASS', '*'); + } + else { + window.top.opener.postMessage('FAIL', '*'); + } +}); + +</script> +</body> +</html> diff --git a/testing/web-platform/tests/client-hints/accept-ch-stickiness/resources/feature-policy-with-cross-origin-subresource.html.headers b/testing/web-platform/tests/client-hints/accept-ch-stickiness/resources/feature-policy-with-cross-origin-subresource.html.headers new file mode 100644 index 0000000000..cb6b0cfd13 --- /dev/null +++ b/testing/web-platform/tests/client-hints/accept-ch-stickiness/resources/feature-policy-with-cross-origin-subresource.html.headers @@ -0,0 +1 @@ +Feature-Policy: ch-device-memory *; diff --git a/testing/web-platform/tests/client-hints/accept-ch-stickiness/resources/http-equiv-accept-ch.html b/testing/web-platform/tests/client-hints/accept-ch-stickiness/resources/http-equiv-accept-ch.html new file mode 100644 index 0000000000..561cae49ca --- /dev/null +++ b/testing/web-platform/tests/client-hints/accept-ch-stickiness/resources/http-equiv-accept-ch.html @@ -0,0 +1,8 @@ +<html> +<meta http-equiv="Accept-CH" content="sec-ch-device-memory,device-memory"> +<body> +<script> + window.top.opener.postMessage('Loaded', '*'); +</script> +</body> +</html> diff --git a/testing/web-platform/tests/client-hints/accept-ch-stickiness/resources/http-equiv-accept-ch.html.headers b/testing/web-platform/tests/client-hints/accept-ch-stickiness/resources/http-equiv-accept-ch.html.headers new file mode 100644 index 0000000000..27140bf36e --- /dev/null +++ b/testing/web-platform/tests/client-hints/accept-ch-stickiness/resources/http-equiv-accept-ch.html.headers @@ -0,0 +1,2 @@ +Access-Control-Allow-Origin: * + diff --git a/testing/web-platform/tests/client-hints/accept-ch-stickiness/resources/meta-equiv-delegate-ch.html b/testing/web-platform/tests/client-hints/accept-ch-stickiness/resources/meta-equiv-delegate-ch.html new file mode 100644 index 0000000000..7d7c4ccdf7 --- /dev/null +++ b/testing/web-platform/tests/client-hints/accept-ch-stickiness/resources/meta-equiv-delegate-ch.html @@ -0,0 +1,9 @@ +<!DOCTYPE html> +<html> +<meta http-equiv="Delegate-CH" content="sec-ch-device-memory;device-memory"> +<body> +<script> + window.top.opener.postMessage('Loaded', '*'); +</script> +</body> +</html> diff --git a/testing/web-platform/tests/client-hints/accept-ch-stickiness/resources/meta-equiv-delegate-ch.html.headers b/testing/web-platform/tests/client-hints/accept-ch-stickiness/resources/meta-equiv-delegate-ch.html.headers new file mode 100644 index 0000000000..27140bf36e --- /dev/null +++ b/testing/web-platform/tests/client-hints/accept-ch-stickiness/resources/meta-equiv-delegate-ch.html.headers @@ -0,0 +1,2 @@ +Access-Control-Allow-Origin: * + diff --git a/testing/web-platform/tests/client-hints/accept-ch-stickiness/resources/no-accept-ch.html b/testing/web-platform/tests/client-hints/accept-ch-stickiness/resources/no-accept-ch.html new file mode 100644 index 0000000000..16ed6c1a7c --- /dev/null +++ b/testing/web-platform/tests/client-hints/accept-ch-stickiness/resources/no-accept-ch.html @@ -0,0 +1,11 @@ +<html> +<body> + +<!-- Page with out an accept-ch header; client hints are unaffected --> +<script> + window.top.opener.postMessage('Loaded', '*'); +</script> + + +</body> +</html> diff --git a/testing/web-platform/tests/client-hints/accept-ch-stickiness/resources/no-accept-ch.html.headers b/testing/web-platform/tests/client-hints/accept-ch-stickiness/resources/no-accept-ch.html.headers new file mode 100644 index 0000000000..cb762eff80 --- /dev/null +++ b/testing/web-platform/tests/client-hints/accept-ch-stickiness/resources/no-accept-ch.html.headers @@ -0,0 +1 @@ +Access-Control-Allow-Origin: * diff --git a/testing/web-platform/tests/client-hints/accept-ch-stickiness/same-origin-iframe.https.html b/testing/web-platform/tests/client-hints/accept-ch-stickiness/same-origin-iframe.https.html new file mode 100644 index 0000000000..c768094544 --- /dev/null +++ b/testing/web-platform/tests/client-hints/accept-ch-stickiness/same-origin-iframe.https.html @@ -0,0 +1,19 @@ +<!doctype html> +<meta name="timeout" content="long"> +<title>Accept-CH Persistence test</title> +<body> +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> +<script src="/common/get-host-info.sub.js"></script> +<script src="resources/accept-ch-test.js"></script> + +<script> +run_test({ name: "same origin iframe can't set accept-ch", + initial_url: echo, + accept_url: accept, + expect_url: do_not_expect, + type: "iframe" }); +</script> +</body> +</html> + diff --git a/testing/web-platform/tests/client-hints/accept-ch-stickiness/same-origin-navigation-empty-accept-ch.https.html b/testing/web-platform/tests/client-hints/accept-ch-stickiness/same-origin-navigation-empty-accept-ch.https.html new file mode 100644 index 0000000000..e57f1c3dc6 --- /dev/null +++ b/testing/web-platform/tests/client-hints/accept-ch-stickiness/same-origin-navigation-empty-accept-ch.https.html @@ -0,0 +1,20 @@ +<!doctype html> +<meta name="timeout" content="long"> +<title>Accept-CH Persistence test</title> +<body> +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> +<script src="/common/get-host-info.sub.js"></script> +<script src="resources/accept-ch-test.js"></script> + +<script> +// Tests that an empty accept-ch header disables client hints. +const test_name = "empty-ch on navigation"; +verify_initial_state(echo, test_name); +attempt_set("navigation", accept, test_name, " to non-empty first"); +attempt_set("navigation", accept_blank, test_name, " to empty second"); +verify_navigation_state(do_not_expect, test_name); +</script> +</body> +</html> + diff --git a/testing/web-platform/tests/client-hints/accept-ch-stickiness/same-origin-navigation-no-accept-ch.https.html b/testing/web-platform/tests/client-hints/accept-ch-stickiness/same-origin-navigation-no-accept-ch.https.html new file mode 100644 index 0000000000..ab59770176 --- /dev/null +++ b/testing/web-platform/tests/client-hints/accept-ch-stickiness/same-origin-navigation-no-accept-ch.https.html @@ -0,0 +1,20 @@ +<!doctype html> +<meta name="timeout" content="long"> +<title>Accept-CH Persistence test</title> +<body> +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> +<script src="/common/get-host-info.sub.js"></script> +<script src="resources/accept-ch-test.js"></script> + +<script> +// Tests that a non-existing accept-ch header doesn't affect client hints. +const test_name = "empty-ch on navigation"; +verify_initial_state(echo, test_name); +attempt_set("navigation", accept, test_name, " to non-empty first"); +attempt_set("navigation", no_accept, test_name, " w/o header second"); +verify_navigation_state(expect, test_name); +</script> +</body> +</html> + diff --git a/testing/web-platform/tests/client-hints/accept-ch-stickiness/same-origin-navigation-redirect.https.html b/testing/web-platform/tests/client-hints/accept-ch-stickiness/same-origin-navigation-redirect.https.html new file mode 100644 index 0000000000..69fc55e8f3 --- /dev/null +++ b/testing/web-platform/tests/client-hints/accept-ch-stickiness/same-origin-navigation-redirect.https.html @@ -0,0 +1,19 @@ +<!doctype html> +<meta name="timeout" content="long"> +<title>Accept-CH Persistence test</title> +<body> +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> +<script src="/common/get-host-info.sub.js"></script> +<script src="resources/accept-ch-test.js"></script> + +<script> +// This is similar to accept-ch-test.js tests, except setting and checking +// header here are a single step, connected via redirect. +const test_name = "redirect on navigation"; +verify_initial_state(echo, test_name); +verify_navigation_state("resources/accept-ch-and-redir.py?url=expect-received.py", test_name); +</script> +</body> +</html> + diff --git a/testing/web-platform/tests/client-hints/accept-ch-stickiness/same-origin-navigation.https.html b/testing/web-platform/tests/client-hints/accept-ch-stickiness/same-origin-navigation.https.html new file mode 100644 index 0000000000..e35cbdcedd --- /dev/null +++ b/testing/web-platform/tests/client-hints/accept-ch-stickiness/same-origin-navigation.https.html @@ -0,0 +1,19 @@ +<!doctype html> +<meta name="timeout" content="long"> +<title>Accept-CH Persistence test</title> +<body> +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> +<script src="/common/get-host-info.sub.js"></script> +<script src="resources/accept-ch-test.js"></script> + +<script> +run_test({ name: "same origin navigation", + initial_url: echo, + accept_url: accept, + expect_url: expect, + type: "navigation" }); +</script> +</body> +</html> + diff --git a/testing/web-platform/tests/client-hints/accept-ch-stickiness/same-origin-subresource-redirect-opted-in.https.html b/testing/web-platform/tests/client-hints/accept-ch-stickiness/same-origin-subresource-redirect-opted-in.https.html new file mode 100644 index 0000000000..66c0e57497 --- /dev/null +++ b/testing/web-platform/tests/client-hints/accept-ch-stickiness/same-origin-subresource-redirect-opted-in.https.html @@ -0,0 +1,17 @@ +<!doctype html> +<meta name="timeout" content="long"> +<title>Accept-CH Persistence test</title> +<body> +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> +<script src="/common/get-host-info.sub.js"></script> +<script src="resources/accept-ch-test.js"></script> + +<script> +// Make sure a same origin subresource that gets redirected keeps the initial request's Client Hints. +const test_name = "same-origin subresource redirect with opt-in"; +verify_subresource_state("resources/accept-ch-and-redir.py?url=expect-received.py", test_name); +</script> +</body> +</html> + diff --git a/testing/web-platform/tests/client-hints/accept-ch-stickiness/same-origin-subresource-redirect-opted-in.https.html.headers b/testing/web-platform/tests/client-hints/accept-ch-stickiness/same-origin-subresource-redirect-opted-in.https.html.headers new file mode 100644 index 0000000000..af6945319d --- /dev/null +++ b/testing/web-platform/tests/client-hints/accept-ch-stickiness/same-origin-subresource-redirect-opted-in.https.html.headers @@ -0,0 +1 @@ +Accept-CH: Sec-CH-DPR, DPR, Sec-CH-Device-Memory, Device-Memory diff --git a/testing/web-platform/tests/client-hints/accept-ch-stickiness/same-origin-subresource-redirect.https.html b/testing/web-platform/tests/client-hints/accept-ch-stickiness/same-origin-subresource-redirect.https.html new file mode 100644 index 0000000000..8e687b58b1 --- /dev/null +++ b/testing/web-platform/tests/client-hints/accept-ch-stickiness/same-origin-subresource-redirect.https.html @@ -0,0 +1,18 @@ +<!doctype html> +<meta name="timeout" content="long"> +<title>Accept-CH Persistence test</title> +<body> +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> +<script src="/common/get-host-info.sub.js"></script> +<script src="resources/accept-ch-test.js"></script> + +<script> +// Make sure a same origin subresource without an opt-in that gets redirected doesn't contain Client Hints. +const test_name = "same-origin subresource redirect with no opt-in"; +verify_initial_state(echo, test_name); +verify_subresource_state("resources/accept-ch-and-redir.py?url=do-not-expect-received.py", test_name); +</script> +</body> +</html> + diff --git a/testing/web-platform/tests/client-hints/accept-ch-stickiness/same-origin-subresource.https.html b/testing/web-platform/tests/client-hints/accept-ch-stickiness/same-origin-subresource.https.html new file mode 100644 index 0000000000..0b7151a2cc --- /dev/null +++ b/testing/web-platform/tests/client-hints/accept-ch-stickiness/same-origin-subresource.https.html @@ -0,0 +1,19 @@ +<!doctype html> +<meta name="timeout" content="long"> +<title>Accept-CH Persistence test</title> +<body> +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> +<script src="/common/get-host-info.sub.js"></script> +<script src="resources/accept-ch-test.js"></script> + +<script> +run_test({ name: "same origin subresource", + initial_url: echo, + accept_url: accept, + expect_url: do_not_expect, + type: "subresource" }); +</script> +</body> +</html> + diff --git a/testing/web-platform/tests/client-hints/accept-ch/__dir__.headers b/testing/web-platform/tests/client-hints/accept-ch/__dir__.headers new file mode 100644 index 0000000000..f233c2e9d6 --- /dev/null +++ b/testing/web-platform/tests/client-hints/accept-ch/__dir__.headers @@ -0,0 +1 @@ +Accept-CH: device-memory, dpr, width, viewport-width, rtt, downlink, ect, sec-ch-ua, sec-ch-ua-arch, sec-ch-ua-platform, sec-ch-ua-model, sec-ch-ua-mobile, sec-ch-ua-full-version, sec-ch-ua-platform-version, sec-ch-prefers-color-scheme, sec-ch-prefers-reduced-motion, sec-ch-ua-bitness, sec-ch-viewport-height, sec-ch-device-memory, sec-ch-dpr, sec-ch-width, sec-ch-viewport-width, sec-ch-ua-full-version-list, sec-ch-ua-wow64 diff --git a/testing/web-platform/tests/client-hints/accept-ch/answers.sub.https.html b/testing/web-platform/tests/client-hints/accept-ch/answers.sub.https.html new file mode 100644 index 0000000000..e49a515bf4 --- /dev/null +++ b/testing/web-platform/tests/client-hints/accept-ch/answers.sub.https.html @@ -0,0 +1,68 @@ +<html> +<body> +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> + +<script> + +// If the response for the HTML file contains "Accept-CH" in the response +// headers, then the browser should attach the specified client hints in the +// HTTP request headers depending on whether the resource is being fetched from +// the same origin or a different origin. Test this functionality by fetching +// same-origin and cross-origin resources from this page. The response headers +// for this page include "Accept-CH: device-memory, dpr, viewport-width, rtt, downlink, ect". +// +// resources/echo-client-hints-received.py sets the response headers depending on the set +// of client hints it receives in the request headers. + +promise_test(t => { + return fetch("https://{{domains[]}}:{{ports[https][0]}}/client-hints/resources/echo-client-hints-received.py").then(r => { + assert_equals(r.status, 200) + // Verify that the browser includes client hints in the headers for a + // same-origin fetch. + assert_true(r.headers.has("device-memory-received"), "device-memory-received"); + assert_true(r.headers.has("device-memory-deprecated-received"), "device-memory-deprecated-received"); + assert_true(r.headers.has("dpr-received"), "dpr-received"); + assert_true(r.headers.has("dpr-deprecated-received"), "dpr-deprecated-received"); + assert_true(r.headers.has("viewport-width-received"), "viewport-width-received"); + assert_true(r.headers.has("viewport-width-deprecated-received"), "viewport-width-deprecated-received"); + + assert_true(r.headers.has("rtt-received"), "rtt-received"); + var rtt = parseInt(r.headers.get("rtt-received")); + assert_greater_than_equal(rtt, 0); + assert_less_than_equal(rtt, 3000); + assert_equals(rtt % 50, 0, 'rtt must be a multiple of 50 msec'); + + assert_true(r.headers.has("downlink-received"), "downlink-received"); + var downlinkKbps = r.headers.get("downlink-received") * 1000; + assert_greater_than_equal(downlinkKbps, 0); + assert_less_than_equal(downlinkKbps, 10000); + + assert_in_array(r.headers.get("ect-received"), ["slow-2g", "2g", + "3g", "4g"], 'ect-received is unexpected'); + }); +}, "Accept-CH header test"); + +promise_test(t => { + return fetch("https://{{domains[www]}}:{{ports[https][0]}}/client-hints/resources/echo-client-hints-received.py").then(r => { + assert_equals(r.status, 200) + // Verify that the browser does not include client hints in the headers + // for a cross-origin fetch. + assert_false(r.headers.has("device-memory-received"), "device-memory-received"); + assert_false(r.headers.has("device-memory-deprecated-received"), "device-memory-deprecated-received"); + assert_false(r.headers.has("dpr-received"), "dpr-received"); + assert_false(r.headers.has("dpr-deprecated-received"), "dpr-deprecated-received"); + assert_false(r.headers.has("viewport-width-received"), "viewport-width-received"); + assert_false(r.headers.has("viewport-width-deprecated-received"), "viewport-width-deprecated-received"); + assert_false(r.headers.has("rtt-received"), "rtt-received"); + assert_false(r.headers.has("downlink-received"), "downlink-received"); + assert_false(r.headers.has("ect-received"), "ect-received"); + }); +}, "Cross-Origin Accept-CH header test"); + + + +</script> + +</body> +</html> diff --git a/testing/web-platform/tests/client-hints/accept-ch/cache-revalidation.https.html b/testing/web-platform/tests/client-hints/accept-ch/cache-revalidation.https.html new file mode 100644 index 0000000000..5ed6f074a7 --- /dev/null +++ b/testing/web-platform/tests/client-hints/accept-ch/cache-revalidation.https.html @@ -0,0 +1,36 @@ +<!DOCTYPE html> +<meta charset="utf-8"> +<title>Tests Stale While Revalidate is not executed for fetch API</title> +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> +<script src="/client-hints/resources/export.js"></script> +<script src="/common/utils.js"></script> +<script> +function wait25ms(test) { + return new Promise(resolve => { + test.step_timeout(() => { + resolve(); + }, 25); + }); +} + +promise_test(async (test) => { + var request_token = token(); + + const response = await fetch(`/client-hints/resources/stale-echo-client-hints.py?token=` + request_token); + const response2 = await fetch(`/client-hints/resources/stale-echo-client-hints.py?token=` + request_token); + + assert_equals(response.headers.get('Unique-Id'), response2.headers.get('Unique-Id')); + + while(true) { + const revalidation_check = await fetch(`/client-hints/resources/stale-echo-client-hints.py?query&token=` + request_token); + if (revalidation_check.headers.get('Count') == '2') { + client_hints_full_list.forEach(header => { + assert_equals(revalidation_check.headers.get(header+"-recieved"), revalidation_check.headers.get(header+"-previous")); + }); + break; + } + await wait25ms(test); + } +}, 'Same headers sent for revalidation request'); +</script> diff --git a/testing/web-platform/tests/client-hints/accept-ch/feature-policy-navigation/__dir__.headers b/testing/web-platform/tests/client-hints/accept-ch/feature-policy-navigation/__dir__.headers new file mode 100644 index 0000000000..f233c2e9d6 --- /dev/null +++ b/testing/web-platform/tests/client-hints/accept-ch/feature-policy-navigation/__dir__.headers @@ -0,0 +1 @@ +Accept-CH: device-memory, dpr, width, viewport-width, rtt, downlink, ect, sec-ch-ua, sec-ch-ua-arch, sec-ch-ua-platform, sec-ch-ua-model, sec-ch-ua-mobile, sec-ch-ua-full-version, sec-ch-ua-platform-version, sec-ch-prefers-color-scheme, sec-ch-prefers-reduced-motion, sec-ch-ua-bitness, sec-ch-viewport-height, sec-ch-device-memory, sec-ch-dpr, sec-ch-width, sec-ch-viewport-width, sec-ch-ua-full-version-list, sec-ch-ua-wow64 diff --git a/testing/web-platform/tests/client-hints/accept-ch/feature-policy-navigation/feature-policy.https.html b/testing/web-platform/tests/client-hints/accept-ch/feature-policy-navigation/feature-policy.https.html new file mode 100644 index 0000000000..90a27280c1 --- /dev/null +++ b/testing/web-platform/tests/client-hints/accept-ch/feature-policy-navigation/feature-policy.https.html @@ -0,0 +1,29 @@ +<html> +<body> +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> +<script src="/common/get-host-info.sub.js"></script> +<script src="/client-hints/resources/export.js"></script> +<script src="/client-hints/resources/feature-policy-navigation.js"></script> +<script> +(async () => { + await test_frame( + "HTTPS_REMOTE_ORIGIN", + cross_origin_client_hints, + "", + "Client hints loaded on cross-origin iframe request with feature policy."); + await test_frame( + "HTTPS_ORIGIN", + same_origin_client_hints, + "", + "Client hints loaded on same-origin iframe request with feature policy."); + await test_frame( + "HTTPS_REMOTE_ORIGIN", + cross_origin_client_hints, + "", + "Client hints loaded on cross-origin iframe request with feature policy after attempting to set independently."); +})(); + +</script> +</body> +</html> diff --git a/testing/web-platform/tests/client-hints/accept-ch/feature-policy-navigation/feature-policy.https.html.headers b/testing/web-platform/tests/client-hints/accept-ch/feature-policy-navigation/feature-policy.https.html.headers new file mode 100644 index 0000000000..8e976388ec --- /dev/null +++ b/testing/web-platform/tests/client-hints/accept-ch/feature-policy-navigation/feature-policy.https.html.headers @@ -0,0 +1 @@ +Feature-Policy: ch-device-memory *; ch-dpr 'none'; ch-viewport-width 'self'; ch-ua 'self'; ch-ua-mobile 'none' diff --git a/testing/web-platform/tests/client-hints/accept-ch/feature-policy-navigation/no-feature-policy.https.html b/testing/web-platform/tests/client-hints/accept-ch/feature-policy-navigation/no-feature-policy.https.html new file mode 100644 index 0000000000..02458f3116 --- /dev/null +++ b/testing/web-platform/tests/client-hints/accept-ch/feature-policy-navigation/no-feature-policy.https.html @@ -0,0 +1,36 @@ +<html> +<body> +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> +<script src="/common/get-host-info.sub.js"></script> +<script src="/client-hints/resources/export.js"></script> +<script src="/client-hints/resources/feature-policy-navigation.js"></script> +<script> +(async () => { + await test_frame( + "HTTPS_REMOTE_ORIGIN", + expect_iframe_no_hints, + "", + "Client hints not loaded on cross-origin iframe request with no feature policy."); + await test_frame( + "HTTPS_ORIGIN", + expect_iframe_hints, + "", + "Client hints loaded on same-origin iframe request with no feature policy."); + + let allow = "ch-device-memory *; ch-dpr 'none'; ch-viewport-width 'self'; ch-ua 'self'; ch-ua-mobile 'none';"; await test_frame( + "HTTPS_REMOTE_ORIGIN", + cross_origin_client_hints, + allow, + "Client hints loaded on cross-origin iframe request with allow list."); + await test_frame( + "HTTPS_ORIGIN", + same_origin_client_hints, + allow, + "Client hints loaded on same-origin iframe request with allow list."); +})(); + +</script> +</body> +</html> + diff --git a/testing/web-platform/tests/client-hints/accept-ch/feature-policy.sub.https.html b/testing/web-platform/tests/client-hints/accept-ch/feature-policy.sub.https.html new file mode 100644 index 0000000000..e1aa3ad68f --- /dev/null +++ b/testing/web-platform/tests/client-hints/accept-ch/feature-policy.sub.https.html @@ -0,0 +1,77 @@ +<html> +<body> +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> +<script src="/common/get-host-info.sub.js"></script> +<script> + +// If the response for the HTML file contains "Accept-CH" in the response +// headers, then the browser should attach the specified client hints in the +// HTTP request headers depending on whether the resource is being fetched from +// the same origin or a different origin. Test this functionality by fetching +// same-origin and cross-origin resources from this page. The response headers +// for this page include "Accept-CH: device-memory, dpr, viewport-width, rtt, downlink, ect". +// +// resources/echo-client-hints-received.py sets the response headers depending on the set +// of client hints it receives in the request headers. + +promise_test(t => { + return fetch(get_host_info()["HTTPS_ORIGIN"] + "/client-hints/resources/echo-client-hints-received.py").then(r => { + assert_equals(r.status, 200) + // Verify that the browser includes client hints in the headers for a + // same-origin fetch which not specifically excluded via Feature-Policy. + assert_true(r.headers.has("device-memory-received"), "device-memory-received"); + assert_true(r.headers.has("device-memory-deprecated-received"), "device-memory-deprecated-received"); + assert_false(r.headers.has("dpr-received"), "dpr-received"); + assert_false(r.headers.has("dpr-deprecated-received"), "dpr-deprecated-received"); + assert_true(r.headers.has("viewport-width-received"), "viewport-width-received"); + assert_true(r.headers.has("viewport-width-deprecated-received"), "viewport-width-deprecated-received"); + + assert_true(r.headers.has("rtt-received"), "rtt-received"); + var rtt = parseInt(r.headers.get("rtt-received")); + assert_greater_than_equal(rtt, 0); + assert_less_than_equal(rtt, 3000); + assert_equals(rtt % 50, 0, 'rtt must be a multiple of 50 msec'); + + assert_true(r.headers.has("downlink-received"), "downlink-received"); + var downlinkKbps = r.headers.get("downlink-received") * 1000; + assert_greater_than_equal(downlinkKbps, 0); + assert_less_than_equal(downlinkKbps, 10000); + + assert_in_array(r.headers.get("ect-received"), ["slow-2g", "2g", + "3g", "4g"], 'ect-received is unexpected'); + + assert_true(r.headers.has("mobile-received")); + assert_in_array(r.headers.get("mobile-received"), ["?0", "?1"], 'mobile is unexpected'); + assert_false(r.headers.has("prefers-color-scheme-received"), "prefers-color-scheme-received"); + assert_false(r.headers.has("prefers-reduced-motion-received"), "prefers-reduced-motion-received"); + assert_false(r.headers.has("viewport-height-received"), "viewport-height-received"); + }); +}, "Accept-CH header test"); + +promise_test(t => { + return fetch(get_host_info()["HTTPS_REMOTE_ORIGIN"] + "/client-hints/resources/echo-client-hints-received.py").then(r => { + assert_equals(r.status, 200) + // Verify that the browser includes client hints in the headers for a + // cross-origin fetch which are specifically requested via Feature-Policy. + assert_true(r.headers.has("device-memory-received"), "device-memory-received"); + assert_true(r.headers.has("device-memory-deprecated-received"), "device-memory-deprecated-received"); + assert_false(r.headers.has("dpr-received"), "dpr-received"); + assert_false(r.headers.has("dpr-deprecated-received"), "dpr-deprecated-received"); + assert_false(r.headers.has("viewport-width-received"), "viewport-width-received"); + assert_false(r.headers.has("viewport-width-deprecated-received"), "viewport-width-deprecated-received"); + assert_false(r.headers.has("rtt-received"), "rtt-received"); + assert_false(r.headers.has("downlink-received"), "downlink-received"); + assert_false(r.headers.has("ect-received"), "ect-received"); + assert_false(r.headers.has("prefers-color-scheme-received"), "prefers-color-scheme-received"); + assert_false(r.headers.has("prefers-reduced-motion-received"), "prefers-reduced-motion-received"); + assert_false(r.headers.has("viewport-height-received"), "viewport-height-received"); + }); +}, "Cross-Origin Accept-CH header test"); + + + +</script> + +</body> +</html> diff --git a/testing/web-platform/tests/client-hints/accept-ch/feature-policy.sub.https.html.headers b/testing/web-platform/tests/client-hints/accept-ch/feature-policy.sub.https.html.headers new file mode 100644 index 0000000000..78bbb8c872 --- /dev/null +++ b/testing/web-platform/tests/client-hints/accept-ch/feature-policy.sub.https.html.headers @@ -0,0 +1 @@ +Feature-Policy: ch-device-memory *; ch-dpr 'none'; ch-viewport-width 'self'; ch-mobile; ch-prefers-color-scheme 'none'; ch-prefers-reduced-motion 'none'; ch-viewport-height 'none' diff --git a/testing/web-platform/tests/client-hints/accept-ch/meta/resource-in-markup-accept-ch.https.html b/testing/web-platform/tests/client-hints/accept-ch/meta/resource-in-markup-accept-ch.https.html new file mode 100644 index 0000000000..c9b98daccf --- /dev/null +++ b/testing/web-platform/tests/client-hints/accept-ch/meta/resource-in-markup-accept-ch.https.html @@ -0,0 +1,14 @@ +<!DOCTYPE html> +<script src=/resources/testharness.js></script> +<script src=/resources/testharnessreport.js></script> + +<meta http-equiv="Accept-CH" content="sec-ch-dpr"> + +<script src="../../resources/script-set-dpr-header.py"></script> + +<script> +test(() => { + assert_greater_than(dprHeader.length, 0, + "sec-ch-dpr header should have been received"); +}, "DPR is received in page with Accept-CH http-equiv meta tag"); +</script> diff --git a/testing/web-platform/tests/client-hints/accept-ch/meta/resource-in-markup-delegate-ch.https.html b/testing/web-platform/tests/client-hints/accept-ch/meta/resource-in-markup-delegate-ch.https.html new file mode 100644 index 0000000000..751f07f278 --- /dev/null +++ b/testing/web-platform/tests/client-hints/accept-ch/meta/resource-in-markup-delegate-ch.https.html @@ -0,0 +1,14 @@ +<!DOCTYPE html> +<script src=/resources/testharness.js></script> +<script src=/resources/testharnessreport.js></script> + +<meta http-equiv="Delegate-CH" content="sec-ch-dpr"> + +<script src="../../resources/script-set-dpr-header.py"></script> + +<script> +test(() => { + assert_greater_than(dprHeader.length, 0, + "sec-ch-dpr header should have been received"); +}, "DPR is received in page with Accept-CH meta tag"); +</script> diff --git a/testing/web-platform/tests/client-hints/accept-ch/no-feature-policy.sub.https.html b/testing/web-platform/tests/client-hints/accept-ch/no-feature-policy.sub.https.html new file mode 100644 index 0000000000..8458bbed7b --- /dev/null +++ b/testing/web-platform/tests/client-hints/accept-ch/no-feature-policy.sub.https.html @@ -0,0 +1,65 @@ +<html> +<body> +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> +<script src="/common/get-host-info.sub.js"></script> +<script> + +// If the response for the HTML file contains "Accept-CH" in the response +// headers, then the browser should attach the specified client hints in the +// HTTP request headers depending on whether the resource is being fetched from +// the same origin or a different origin. Test this functionality by fetching +// same-origin and cross-origin resources from this page. The response headers +// for this page include "Accept-CH: device-memory, dpr, viewport-width, rtt, downlink, ect". +// +// resources/echo-client-hints-received.py sets the response headers depending on the set +// of client hints it receives in the request headers. + +promise_test(t => { + return fetch(get_host_info()["HTTPS_ORIGIN"] + "/client-hints/resources/echo-client-hints-received.py").then(r => { + assert_equals(r.status, 200) + // Verify that the browser includes client hints in the headers for a + // same-origin fetch with the default feature policy in place. + assert_true(r.headers.has("device-memory-received"), "device-memory-received"); + assert_true(r.headers.has("device-memory-deprecated-received"), "device-memory-deprecated-received"); + assert_true(r.headers.has("dpr-received"), "dpr-received"); + assert_true(r.headers.has("dpr-deprecated-received"), "dpr-deprecated-received"); + assert_true(r.headers.has("viewport-width-received"), "viewport-width-received"); + assert_true(r.headers.has("viewport-width-deprecated-received"), "viewport-width-deprecated-received"); + + assert_true(r.headers.has("rtt-received"), "rtt-received"); + var rtt = parseInt(r.headers.get("rtt-received")); + assert_greater_than_equal(rtt, 0); + assert_less_than_equal(rtt, 3000); + assert_equals(rtt % 50, 0, 'rtt must be a multiple of 50 msec'); + + assert_true(r.headers.has("downlink-received"), "downlink-received"); + var downlinkKbps = r.headers.get("downlink-received") * 1000; + assert_greater_than_equal(downlinkKbps, 0); + assert_less_than_equal(downlinkKbps, 10000); + + assert_in_array(r.headers.get("ect-received"), ["slow-2g", "2g", + "3g", "4g"], 'ect-received is unexpected'); + }); +}, "Accept-CH header test"); + +promise_test(t => { + return fetch(get_host_info()["HTTPS_REMOTE_ORIGIN"] + "/client-hints/resources/echo-client-hints-received.py").then(r => { + assert_equals(r.status, 200) + // Verify that the browser includes no client hints in the headers for a + // cross-origin fetch with the default feature policy in place. + assert_false(r.headers.has("device-memory-received"), "device-memory-received"); + assert_false(r.headers.has("dpr-received"), "dpr-received"); + assert_false(r.headers.has("viewport-width-received"), "viewport-width-received"); + assert_false(r.headers.has("rtt-received"), "rtt-received"); + assert_false(r.headers.has("downlink-received"), "downlink-received"); + assert_false(r.headers.has("ect-received"), "ect-received"); + }); +}, "Cross-Origin Accept-CH header test"); + + + +</script> + +</body> +</html> diff --git a/testing/web-platform/tests/client-hints/accept-ch/non-secure.http.html b/testing/web-platform/tests/client-hints/accept-ch/non-secure.http.html new file mode 100644 index 0000000000..9115578b57 --- /dev/null +++ b/testing/web-platform/tests/client-hints/accept-ch/non-secure.http.html @@ -0,0 +1,38 @@ +<html> +<body> +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> + +<script> + +// When the response for the HTML file contains "Accept-CH" in the response +// headers, then the browser should not attach the specified client hints in +// the HTTP request headers if the response was delivered by an insecure HTTP +// server. Test this functionality by fetching an XHR from this page hosted on +// an insecure HTTP server. The response headers for this page include +// "Accept-CH: device-memory, dpr, viewport-width, rtt, downlink, ect". +// +// resources/echo-client-hints-received.py sets the response headers depending on the set +// of client hints it receives in the request headers. + + promise_test(t => { + return fetch("/client-hints/resources/echo-client-hints-received.py").then(r => { + assert_equals(r.status, 200) + // Verify that the browser does not include client hints in the headers + // when fetching the XHR from an insecure HTTP server. + assert_false(r.headers.has("device-memory-received"), "device-memory-received"); + assert_false(r.headers.has("device-memory-deprecated-received"), "device-memory-deprecated-received"); + assert_false(r.headers.has("dpr-received"), "dpr-received"); + assert_false(r.headers.has("dpr-deprecated-received"), "dpr-deprecated-received"); + assert_false(r.headers.has("viewport-width-received"), "viewport-width-received"); + assert_false(r.headers.has("viewport-width-deprecated-received"), "viewport-width-deprecated-received"); + assert_false(r.headers.has("rtt-received"), "rtt-received"); + assert_false(r.headers.has("downlink-received"), "downlink-received"); + assert_false(r.headers.has("ect-received"), "ect-received"); + }); +}, "Accept-CH header test"); + +</script> + +</body> +</html> diff --git a/testing/web-platform/tests/client-hints/critical-ch/iframe.https.window.js b/testing/web-platform/tests/client-hints/critical-ch/iframe.https.window.js new file mode 100644 index 0000000000..f4dd295208 --- /dev/null +++ b/testing/web-platform/tests/client-hints/critical-ch/iframe.https.window.js @@ -0,0 +1,8 @@ +// META: script=resources/util.js + +async_test((t) => { + var iframe = document.createElement("iframe"); + iframe.src = ECHO_URL; + document.body.appendChild(iframe); + iframe.contentWindow.addEventListener('message', message_listener(t, "FAIL")); +}, "Critical-CH iframe"); diff --git a/testing/web-platform/tests/client-hints/critical-ch/mis-matched-count.https.window.js b/testing/web-platform/tests/client-hints/critical-ch/mis-matched-count.https.window.js new file mode 100644 index 0000000000..54bd667897 --- /dev/null +++ b/testing/web-platform/tests/client-hints/critical-ch/mis-matched-count.https.window.js @@ -0,0 +1,4 @@ +// META: script=resources/util.js +// META: script=/common/utils.js + +async_test(make_message_test(ECHO_URL+"?mismatch=true&token="+token(), "1"), "Critical-CH no restart on mismatched hints") diff --git a/testing/web-platform/tests/client-hints/critical-ch/mis-matched.https.window.js b/testing/web-platform/tests/client-hints/critical-ch/mis-matched.https.window.js new file mode 100644 index 0000000000..9476640b35 --- /dev/null +++ b/testing/web-platform/tests/client-hints/critical-ch/mis-matched.https.window.js @@ -0,0 +1,3 @@ +// META: script=resources/util.js + +async_test(make_message_test(ECHO_URL+"?mismatch=true", "FAIL"), "Critical-CH Mis-matched hints") diff --git a/testing/web-platform/tests/client-hints/critical-ch/navigation.https.window.js b/testing/web-platform/tests/client-hints/critical-ch/navigation.https.window.js new file mode 100644 index 0000000000..549b321443 --- /dev/null +++ b/testing/web-platform/tests/client-hints/critical-ch/navigation.https.window.js @@ -0,0 +1,3 @@ +// META: script=resources/util.js + +async_test(make_message_test(ECHO_URL, "PASS"), "Critical-CH navigation") diff --git a/testing/web-platform/tests/client-hints/critical-ch/non-secure.http.window.js b/testing/web-platform/tests/client-hints/critical-ch/non-secure.http.window.js new file mode 100644 index 0000000000..cdd7924398 --- /dev/null +++ b/testing/web-platform/tests/client-hints/critical-ch/non-secure.http.window.js @@ -0,0 +1,3 @@ +// META: script=resources/util.js + +async_test(make_message_test(ECHO_URL, "FAIL"), "Critical-CH navigation non-secure") diff --git a/testing/web-platform/tests/client-hints/critical-ch/request-count.https.window.js b/testing/web-platform/tests/client-hints/critical-ch/request-count.https.window.js new file mode 100644 index 0000000000..b337340509 --- /dev/null +++ b/testing/web-platform/tests/client-hints/critical-ch/request-count.https.window.js @@ -0,0 +1,4 @@ +// META: script=resources/util.js +// META: script=/common/utils.js + +async_test(make_message_test(ECHO_URL+"?token="+token(), "2"), "Critical-CH navigation restart") diff --git a/testing/web-platform/tests/client-hints/critical-ch/resources/echo-critical-hint.py b/testing/web-platform/tests/client-hints/critical-ch/resources/echo-critical-hint.py new file mode 100644 index 0000000000..e4e77ad2a9 --- /dev/null +++ b/testing/web-platform/tests/client-hints/critical-ch/resources/echo-critical-hint.py @@ -0,0 +1,43 @@ +import sys + +def main(request, response): + """ + Simple handler that sets a response header based on which client hint + request headers were received. + """ + + response.headers.append(b"Content-Type", b"text/html; charset=UTF-8") + response.headers.append(b"Access-Control-Allow-Origin", b"*") + response.headers.append(b"Access-Control-Allow-Headers", b"*") + response.headers.append(b"Access-Control-Expose-Headers", b"*") + + response.headers.append(b"Accept-CH", b"sec-ch-device-memory,device-memory") + + critical = b"sec-ch-device-memory,device-memory" + if(request.GET.first(b"mismatch", None) is not None): + critical = b"sec-ch-viewport-width,viewport-width" + + response.headers.append(b"Critical-CH", critical) + + response.headers.append(b"Cache-Control", b"no-store") + + result = "FAIL" + + if b"sec-ch-device-memory" in request.headers and b"device-memory" in request.headers: + result = "PASS" + + token = request.GET.first(b"token", None) + if(token is not None): + with request.server.stash.lock: + count = request.server.stash.take(token) + if(count == None): + count = 1 + else: + count += 1 + request.server.stash.put(token, count) + result = str(count) + + if b"sec-ch-viewport-width" in request.headers and b"viewport-width" in request.headers: + result = "MISMATCH" + + response.content = "<script>window.postMessage('{0}', '*')</script>".format(result) diff --git a/testing/web-platform/tests/client-hints/critical-ch/resources/util.js b/testing/web-platform/tests/client-hints/critical-ch/resources/util.js new file mode 100644 index 0000000000..7471d9022e --- /dev/null +++ b/testing/web-platform/tests/client-hints/critical-ch/resources/util.js @@ -0,0 +1,15 @@ +ECHO_URL = "resources/echo-critical-hint.py" + +message_listener = (t, message) => + (e) => { + t.step(()=>{assert_equals(e.data, message)}); + t.done(); + } + +make_message_test = (url, message) => + (t) => { + popup_window = window.open("/common/blank.html"); + assert_not_equals(popup_window, null, "Popup windows not allowed?"); + popup_window.addEventListener('message', message_listener(t, message)); + popup_window.location = url; + } diff --git a/testing/web-platform/tests/client-hints/critical-ch/subresource.https.window.js b/testing/web-platform/tests/client-hints/critical-ch/subresource.https.window.js new file mode 100644 index 0000000000..f8112b628d --- /dev/null +++ b/testing/web-platform/tests/client-hints/critical-ch/subresource.https.window.js @@ -0,0 +1,10 @@ +// META: script=resources/util.js +// META: script=/common/utils.js + +promise_test(() => + fetch("resources/echo-critical-hint.py") + .then((r) => r.text()) + .then((r) => { + assert_true(r.includes("FAIL")); + }) +, "Critical-CH subresource fetch"); diff --git a/testing/web-platform/tests/client-hints/critical-ch/unsafe-method.https.window.js b/testing/web-platform/tests/client-hints/critical-ch/unsafe-method.https.window.js new file mode 100644 index 0000000000..0eca0eb8e9 --- /dev/null +++ b/testing/web-platform/tests/client-hints/critical-ch/unsafe-method.https.window.js @@ -0,0 +1,23 @@ +async_test((t) => { + // This test requires a navigation with a non-safe (i.e. non-GET) HTTP + // response, which the Critical-CH spec says to ignore. The most + // "straight-forward" way to do this in JS is by making a form with an + // unsafe method (e.g. POST) method and submit it. + + // Build the form DOM element + var form = document.createElement("form"); + form.setAttribute("method", "post"); + form.setAttribute("action", "resources/echo-critical-hint.py"); + form.setAttribute("target", "popup"); //don't navigate away from the page running the test... + document.body.appendChild(form); + + var popup_window = window.open("/common/blank.html", "popup"); + assert_not_equals(popup_window, null, "Popup windows not allowed?"); + + popup_window.addEventListener('message', (e) => { + t.step(()=>{assert_equals(e.data, "FAIL")}); + t.done(); + }); + + form.submit(); +}, "Critical-CH unsafe method") diff --git a/testing/web-platform/tests/client-hints/http-equiv-accept-ch-iframe.https.html b/testing/web-platform/tests/client-hints/http-equiv-accept-ch-iframe.https.html new file mode 100644 index 0000000000..4bde8ebc2d --- /dev/null +++ b/testing/web-platform/tests/client-hints/http-equiv-accept-ch-iframe.https.html @@ -0,0 +1,26 @@ +<html> +<meta http-equiv="Accept-CH" content="Sec-CH-Device-Memory, Device-Memory, Sec-CH-DPR, DPR, Sec-CH-Viewport-Width, Viewport-Width"> +<title>Accept-CH http-equiv iframe test</title> +<body> +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> +<script src="/common/get-host-info.sub.js"></script> +<script src="/client-hints/resources/export.js"></script> +<script src="resources/feature-policy-navigation.js"></script> +<script> +(async () => { + await test_frame( + "HTTPS_ORIGIN", + expect_iframe_no_hints, + "", + "Client hints loaded on same-origin iframe should include hints with a default permissions policy of" + + "self and *, but the http-equiv meta tag has a bug and it doesn't impact iframes."); + await test_frame( + "HTTPS_REMOTE_ORIGIN", + expect_iframe_no_hints, + "", + "Client hints loaded on cross-origin iframe only include hints with a default permissions policy of *."); +})(); +</script> +</body> +</html> diff --git a/testing/web-platform/tests/client-hints/http-equiv-accept-ch-malformed-header.https.html b/testing/web-platform/tests/client-hints/http-equiv-accept-ch-malformed-header.https.html new file mode 100644 index 0000000000..3576dc9920 --- /dev/null +++ b/testing/web-platform/tests/client-hints/http-equiv-accept-ch-malformed-header.https.html @@ -0,0 +1,31 @@ +<html> +<meta http-equiv="Accept-CH" content="Sec-CH-DPR Sec-CH-Width"> +<title>Accept-CH malformed http-equiv test</title> +<body> +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> + +<script> + +promise_test(t => { + return fetch("/client-hints/resources/echo-client-hints-received.py").then(r => { + assert_equals(r.status, 200) + // Verify that the browser does not include client hints in the headers + // since Accept-CH value in http-equiv is malformed (includes whitespace + // between attributes instead of comma). + assert_false(r.headers.has("device-memory-received"), "device-memory-received"); + assert_false(r.headers.has("device-memory-deprecated-received"), "device-memory-deprecated-received"); + assert_false(r.headers.has("dpr-received"), "dpr-received"); + assert_false(r.headers.has("dpr-deprecated-received"), "dpr-deprecated-received"); + assert_false(r.headers.has("viewport-width-received"), "viewport-width-received"); + assert_false(r.headers.has("viewport-width-deprecated-received"), "viewport-width-deprecated-received"); + assert_false(r.headers.has("rtt-received"), "rtt-received"); + assert_false(r.headers.has("downlink-received"), "downlink-received"); + assert_false(r.headers.has("ect-received"), "ect-received"); + }); +}, "Accept-CH malformed http-equiv test"); + +</script> + +</body> +</html> diff --git a/testing/web-platform/tests/client-hints/http-equiv-accept-ch-merge.https.html b/testing/web-platform/tests/client-hints/http-equiv-accept-ch-merge.https.html new file mode 100644 index 0000000000..832c057887 --- /dev/null +++ b/testing/web-platform/tests/client-hints/http-equiv-accept-ch-merge.https.html @@ -0,0 +1,49 @@ +<html> +<head> +<meta http-equiv="Accept-CH" content="sec-ch-viewport-width, viewport-width, rtt"> +<meta http-equiv="Accept-CH" content="downlink, ect, sec-ch-prefers-color-scheme"> +<meta http-equiv="Accept-CH" content="sec-ch-prefers-reduced-motion"> +<body> +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> +<script src="/common/get-host-info.sub.js"></script> +<script> + +// Test of merge of http-equiv headers on top of accept-ch provided ones. +// +// resources/echo-client-hints-received.py sets the response headers depending on the set +// of client hints it receives in the request headers. + +promise_test(t => { + return fetch(get_host_info()["HTTPS_ORIGIN"] + "/client-hints/resources/echo-client-hints-received.py").then(r => { + assert_equals(r.status, 200) + // Verify that the browser includes client hints in the headers. + assert_true(r.headers.has("device-memory-received"), "device-memory-received"); + assert_true(r.headers.has("device-memory-deprecated-received"), "device-memory-deprecated-received"); + assert_true(r.headers.has("dpr-received"), "dpr-received"); + assert_true(r.headers.has("dpr-deprecated-received"), "dpr-deprecated-received"); + assert_true(r.headers.has("viewport-width-received"), "viewport-width-received"); + assert_true(r.headers.has("viewport-width-deprecated-received"), "viewport-width-deprecated-received"); + + assert_true(r.headers.has("rtt-received"), "rtt-received"); + var rtt = parseInt(r.headers.get("rtt-received")); + assert_greater_than_equal(rtt, 0); + assert_less_than_equal(rtt, 3000); + assert_equals(rtt % 50, 0, 'rtt must be a multiple of 50 msec'); + + assert_true(r.headers.has("downlink-received"), "downlink-received"); + var downlinkKbps = r.headers.get("downlink-received") * 1000; + assert_greater_than_equal(downlinkKbps, 0); + assert_less_than_equal(downlinkKbps, 10000); + + assert_in_array(r.headers.get("ect-received"), ["slow-2g", "2g", + "3g", "4g"], 'ect-received is unexpected'); + assert_true(r.headers.has("prefers-color-scheme-received"), "prefers-color-scheme-received"); + assert_true(r.headers.has("prefers-reduced-motion-received"), "prefers-reduced-motion-received"); + }); +}, "Accept-CH header test"); + +</script> + +</body> +</html> diff --git a/testing/web-platform/tests/client-hints/http-equiv-accept-ch-merge.https.html.headers b/testing/web-platform/tests/client-hints/http-equiv-accept-ch-merge.https.html.headers new file mode 100644 index 0000000000..34edb7b82b --- /dev/null +++ b/testing/web-platform/tests/client-hints/http-equiv-accept-ch-merge.https.html.headers @@ -0,0 +1,2 @@ +Accept-CH: sec-ch-device-memory, device-memory, sec-ch-dpr, dpr + diff --git a/testing/web-platform/tests/client-hints/http-equiv-accept-ch-non-secure.http.html b/testing/web-platform/tests/client-hints/http-equiv-accept-ch-non-secure.http.html new file mode 100644 index 0000000000..58a55d44c3 --- /dev/null +++ b/testing/web-platform/tests/client-hints/http-equiv-accept-ch-non-secure.http.html @@ -0,0 +1,39 @@ +<html> +<meta http-equiv="Accept-CH" content="Sec-CH-DPR, DPR, Sec-CH-Width, Width, Sec-CH-Viewport-Width, Viewport-Width, Sec-CH-Device-Memory, Device-Memory, rtt, downlink, ect"> +<title>Accept-CH http-equiv insecure transport test</title> +<body> +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> + +<script> + +// Even though this HTML file contains "Accept-CH" http-equiv headers, the +// browser should NOT attach the specified client hints in the HTTP request +// headers since the page is being fetched over an insecure transport. +// Test this functionality by fetching an XHR from this page hosted on +// an insecure HTTP server. + +// resources/echo-client-hints-received.py sets the response headers depending on the set +// of client hints it receives in the request headers. + +promise_test(t => { + return fetch("/client-hints/resources/echo-client-hints-received.py").then(r => { + assert_equals(r.status, 200) + // Verify that the browser does not include client hints in the headers + // when fetching the XHR from an insecure HTTP server. + assert_false(r.headers.has("device-memory-received"), "device-memory-received"); + assert_false(r.headers.has("device-memory-deprecated-received"), "device-memory-deprecated-received"); + assert_false(r.headers.has("dpr-received"), "dpr-received"); + assert_false(r.headers.has("dpr-deprecated-received"), "dpr-deprecated-received"); + assert_false(r.headers.has("viewport-width-received"), "viewport-width-received"); + assert_false(r.headers.has("viewport-width-deprecated-received"), "viewport-width-deprecated-received"); + assert_false(r.headers.has("rtt-received"), "rtt-received"); + assert_false(r.headers.has("downlink-received"), "downlink-received"); + assert_false(r.headers.has("ect-received"), "ect-received"); + assert_false(r.headers.has("prefers-color-scheme-received"), "prefers-color-scheme-received"); + }); +}, "Accept-CH http-equiv test over insecure transport"); + +</script> +</body> +</html> diff --git a/testing/web-platform/tests/client-hints/inner-delegation/accept_ch_delegation_to_all.sub.https.html b/testing/web-platform/tests/client-hints/inner-delegation/accept_ch_delegation_to_all.sub.https.html new file mode 100644 index 0000000000..27ce76302d --- /dev/null +++ b/testing/web-platform/tests/client-hints/inner-delegation/accept_ch_delegation_to_all.sub.https.html @@ -0,0 +1,37 @@ +<!doctype html> +<meta charset=utf-8> +<title>Client Hints: Delegation of hints to cross-origin frames and resources for *</title> +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> +<body> +<script> +// Here's the set-up for this test: +// Step 1. (Site 1 Window) verify ch-device-memory availability. +// Step 2. (Site 1 Window) set up listener and embed Site 2 Frame. +// Step 3. (Site 2 Frame) verify ch-device-memory availability. +// Step 4. (Site 2 Frame) embeds Site 1 Frame. +// Step 5. (Site 3 Frame) verify ch-device-memory availability. +// Step 6. (Site 1 Window) exit. + +promise_test(async (t) => { + // Step 1 + let r = await fetch("/client-hints/inner-delegation/resources/was-sec-ch-device-memory-received.py"); + assert_equals(r.status, 200, "Site 1 fetching Site 1 didn't recieve sec-ch-device-memory"); + r = await fetch("https://{{hosts[alt][]}}:{{ports[https][0]}}/client-hints/inner-delegation/resources/was-sec-ch-device-memory-received.py"); + assert_equals(r.status, 200, "Site 1 fetching Site 2 didn't recieve sec-ch-device-memory"); + r = await fetch("https://{{domains[www2]}}:{{ports[https][0]}}/client-hints/inner-delegation/resources/was-sec-ch-device-memory-received.py"); + assert_equals(r.status, 200, "Site 1 fetching Site 3 didn't recieve sec-ch-device-memory"); + // Step 2 + const site2Frame = document.createElement("iframe"); + site2Frame.src = "https://{{hosts[alt][]}}:{{ports[https][0]}}/client-hints/inner-delegation/resources/accept_ch_delegation_to_all_iframe.sub.https.html"; + site2Frame.allow = "ch-device-memory *" + document.body.appendChild(site2Frame); + // Step 6 + return new Promise(resolve => { + window.addEventListener("message", resolve); + }).then(e => { + assert_equals(e.data, "ch-device-memory is available as expected for all"); + }); +}, "postMessage: First-Party to Third-Party, Cross-Partition, Same-Origin"); +</script> +</body> diff --git a/testing/web-platform/tests/client-hints/inner-delegation/accept_ch_delegation_to_all.sub.https.html.headers b/testing/web-platform/tests/client-hints/inner-delegation/accept_ch_delegation_to_all.sub.https.html.headers new file mode 100644 index 0000000000..a8b1708b9d --- /dev/null +++ b/testing/web-platform/tests/client-hints/inner-delegation/accept_ch_delegation_to_all.sub.https.html.headers @@ -0,0 +1,2 @@ +Permissions-Policy: ch-device-memory=(*) +Accept-CH: Sec-CH-Device-Memory diff --git a/testing/web-platform/tests/client-hints/inner-delegation/accept_ch_delegation_to_none.sub.https.html b/testing/web-platform/tests/client-hints/inner-delegation/accept_ch_delegation_to_none.sub.https.html new file mode 100644 index 0000000000..1d4bfffe0a --- /dev/null +++ b/testing/web-platform/tests/client-hints/inner-delegation/accept_ch_delegation_to_none.sub.https.html @@ -0,0 +1,36 @@ +<!doctype html> +<meta charset=utf-8> +<title>Client Hints: Delegation of hints to cross-origin frames and resources for none</title> +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> +<body> +<script> +// Here's the set-up for this test: +// Step 1. (Site 1 Window) verify ch-device-memory availability. +// Step 2. (Site 1 Window) set up listener and embed Site 2 Frame. +// Step 3. (Site 2 Frame) verify ch-device-memory availability. +// Step 4. (Site 2 Frame) embeds Site 1 Frame. +// Step 5. (Site 3 Frame) verify ch-device-memory availability. +// Step 6. (Site 1 Window) exit. + +promise_test(async (t) => { + // Step 1 + let r = await fetch("/client-hints/inner-delegation/resources/was-sec-ch-device-memory-received.py"); + assert_equals(r.status, 400, "Site 1 fetching Site 1 did recieve sec-ch-device-memory"); + r = await fetch("https://{{hosts[alt][]}}:{{ports[https][0]}}/client-hints/inner-delegation/resources/was-sec-ch-device-memory-received.py"); + assert_equals(r.status, 400, "Site 1 fetching Site 2 did recieve sec-ch-device-memory"); + r = await fetch("https://{{domains[www2]}}:{{ports[https][0]}}/client-hints/inner-delegation/resources/was-sec-ch-device-memory-received.py"); + assert_equals(r.status, 400, "Site 1 fetching Site 3 did recieve sec-ch-device-memory"); + // Step 2 + const site2Frame = document.createElement("iframe"); + site2Frame.src = "https://{{hosts[alt][]}}:{{ports[https][0]}}/client-hints/inner-delegation/resources/accept_ch_delegation_to_none_iframe.sub.https.html"; + document.body.appendChild(site2Frame); + // Step 6 + return new Promise(resolve => { + window.addEventListener("message", resolve); + }).then(e => { + assert_equals(e.data, "ch-device-memory is available as expected for none"); + }); +}, "postMessage: First-Party to Third-Party, Cross-Partition, Same-Origin"); +</script> +</body> diff --git a/testing/web-platform/tests/client-hints/inner-delegation/accept_ch_delegation_to_none.sub.https.html.headers b/testing/web-platform/tests/client-hints/inner-delegation/accept_ch_delegation_to_none.sub.https.html.headers new file mode 100644 index 0000000000..0b260a43f0 --- /dev/null +++ b/testing/web-platform/tests/client-hints/inner-delegation/accept_ch_delegation_to_none.sub.https.html.headers @@ -0,0 +1,2 @@ +Permissions-Policy: ch-device-memory=() +Accept-CH: Sec-CH-Device-Memory diff --git a/testing/web-platform/tests/client-hints/inner-delegation/accept_ch_delegation_to_self.sub.https.html b/testing/web-platform/tests/client-hints/inner-delegation/accept_ch_delegation_to_self.sub.https.html new file mode 100644 index 0000000000..9647a8741a --- /dev/null +++ b/testing/web-platform/tests/client-hints/inner-delegation/accept_ch_delegation_to_self.sub.https.html @@ -0,0 +1,37 @@ +<!doctype html> +<meta charset=utf-8> +<title>Client Hints: Delegation of hints to cross-origin frames and resources for self</title> +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> +<body> +<script> +// Here's the set-up for this test: +// Step 1. (Site 1 Window) verify ch-device-memory availability. +// Step 2. (Site 1 Window) set up listener and embed Site 2 Frame. +// Step 3. (Site 2 Frame) verify ch-device-memory availability. +// Step 4. (Site 2 Frame) embeds Site 1 Frame. +// Step 5. (Site 3 Frame) verify ch-device-memory availability. +// Step 6. (Site 1 Window) exit. + +promise_test(async (t) => { + // Step 1 + let r = await fetch("/client-hints/inner-delegation/resources/was-sec-ch-device-memory-received.py"); + assert_equals(r.status, 200, "Site 1 fetching Site 1 didn't recieve sec-ch-device-memory"); + r = await fetch("https://{{hosts[alt][]}}:{{ports[https][0]}}/client-hints/inner-delegation/resources/was-sec-ch-device-memory-received.py"); + assert_equals(r.status, 400, "Site 1 fetching Site 2 did recieve sec-ch-device-memory"); + r = await fetch("https://{{domains[www2]}}:{{ports[https][0]}}/client-hints/inner-delegation/resources/was-sec-ch-device-memory-received.py"); + assert_equals(r.status, 400, "Site 1 fetching Site 3 did recieve sec-ch-device-memory"); + // Step 2 + const site2Frame = document.createElement("iframe"); + site2Frame.src = "https://{{hosts[alt][]}}:{{ports[https][0]}}/client-hints/inner-delegation/resources/accept_ch_delegation_to_self_iframe.sub.https.html"; + site2Frame.allow = "ch-device-memory self" + document.body.appendChild(site2Frame); + // Step 6 + return new Promise(resolve => { + window.addEventListener("message", resolve); + }).then(e => { + assert_equals(e.data, "ch-device-memory is available as expected for self"); + }); +}, "postMessage: First-Party to Third-Party, Cross-Partition, Same-Origin"); +</script> +</body> diff --git a/testing/web-platform/tests/client-hints/inner-delegation/accept_ch_delegation_to_self.sub.https.html.headers b/testing/web-platform/tests/client-hints/inner-delegation/accept_ch_delegation_to_self.sub.https.html.headers new file mode 100644 index 0000000000..3b9de86bbd --- /dev/null +++ b/testing/web-platform/tests/client-hints/inner-delegation/accept_ch_delegation_to_self.sub.https.html.headers @@ -0,0 +1,2 @@ +Permissions-Policy: ch-device-memory=(self) +Accept-CH: Sec-CH-Device-Memory diff --git a/testing/web-platform/tests/client-hints/inner-delegation/accept_ch_delegation_to_some.sub.https.html b/testing/web-platform/tests/client-hints/inner-delegation/accept_ch_delegation_to_some.sub.https.html new file mode 100644 index 0000000000..9ea0049c39 --- /dev/null +++ b/testing/web-platform/tests/client-hints/inner-delegation/accept_ch_delegation_to_some.sub.https.html @@ -0,0 +1,37 @@ +<!doctype html> +<meta charset=utf-8> +<title>Client Hints: Delegation of hints to cross-origin frames and resources for some</title> +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> +<body> +<script> +// Here's the set-up for this test: +// Step 1. (Site 1 Window) verify ch-device-memory availability. +// Step 2. (Site 1 Window) set up listener and embed Site 2 Frame. +// Step 3. (Site 2 Frame) verify ch-device-memory availability. +// Step 4. (Site 2 Frame) embeds Site 1 Frame. +// Step 5. (Site 3 Frame) verify ch-device-memory availability. +// Step 6. (Site 1 Window) exit. + +promise_test(async (t) => { + // Step 1 + let r = await fetch("/client-hints/inner-delegation/resources/was-sec-ch-device-memory-received.py"); + assert_equals(r.status, 200, "Site 1 fetching Site 1 didn't recieve sec-ch-device-memory"); + r = await fetch("https://{{hosts[alt][]}}:{{ports[https][0]}}/client-hints/inner-delegation/resources/was-sec-ch-device-memory-received.py"); + assert_equals(r.status, 200, "Site 1 fetching Site 2 didn't recieve sec-ch-device-memory"); + r = await fetch("https://{{domains[www2]}}:{{ports[https][0]}}/client-hints/inner-delegation/resources/was-sec-ch-device-memory-received.py"); + assert_equals(r.status, 400, "Site 1 fetching Site 3 did recieve sec-ch-device-memory"); + // Step 2 + const site2Frame = document.createElement("iframe"); + site2Frame.src = "https://{{hosts[alt][]}}:{{ports[https][0]}}/client-hints/inner-delegation/resources/accept_ch_delegation_to_some_iframe.sub.https.html"; + site2Frame.allow = "ch-device-memory https://{{hosts[alt][]}}:{{ports[https][0]}}" + document.body.appendChild(site2Frame); + // Step 6 + return new Promise(resolve => { + window.addEventListener("message", resolve); + }).then(e => { + assert_equals(e.data, "ch-device-memory is available as expected for some"); + }); +}, "postMessage: First-Party to Third-Party, Cross-Partition, Same-Origin"); +</script> +</body> diff --git a/testing/web-platform/tests/client-hints/inner-delegation/accept_ch_delegation_to_some.sub.https.html.sub.headers b/testing/web-platform/tests/client-hints/inner-delegation/accept_ch_delegation_to_some.sub.https.html.sub.headers new file mode 100644 index 0000000000..24fe4e84c8 --- /dev/null +++ b/testing/web-platform/tests/client-hints/inner-delegation/accept_ch_delegation_to_some.sub.https.html.sub.headers @@ -0,0 +1,2 @@ +Permissions-Policy: ch-device-memory=("https://{{host}}:{{ports[https][0]}}" "https://{{hosts[alt][]}}:{{ports[https][0]}}") +Accept-CH: Sec-CH-Device-Memory diff --git a/testing/web-platform/tests/client-hints/inner-delegation/accept_ch_delegation_to_src.sub.https.html b/testing/web-platform/tests/client-hints/inner-delegation/accept_ch_delegation_to_src.sub.https.html new file mode 100644 index 0000000000..e01853e5e9 --- /dev/null +++ b/testing/web-platform/tests/client-hints/inner-delegation/accept_ch_delegation_to_src.sub.https.html @@ -0,0 +1,37 @@ +<!doctype html> +<meta charset=utf-8> +<title>Client Hints: Delegation of hints to cross-origin frames and resources for src</title> +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> +<body> +<script> +// Here's the set-up for this test: +// Step 1. (Site 1 Window) verify ch-device-memory availability. +// Step 2. (Site 1 Window) set up listener and embed Site 2 Frame. +// Step 3. (Site 2 Frame) verify ch-device-memory availability. +// Step 4. (Site 2 Frame) embeds Site 1 Frame. +// Step 5. (Site 3 Frame) verify ch-device-memory availability. +// Step 6. (Site 1 Window) exit. + +promise_test(async (t) => { + // Step 1 + let r = await fetch("/client-hints/inner-delegation/resources/was-sec-ch-device-memory-received.py"); + assert_equals(r.status, 200, "Site 1 fetching Site 1 didn't recieve sec-ch-device-memory"); + r = await fetch("https://{{hosts[alt][]}}:{{ports[https][0]}}/client-hints/inner-delegation/resources/was-sec-ch-device-memory-received.py"); + assert_equals(r.status, 400, "Site 1 fetching Site 2 did recieve sec-ch-device-memory"); + r = await fetch("https://{{domains[www2]}}:{{ports[https][0]}}/client-hints/inner-delegation/resources/was-sec-ch-device-memory-received.py"); + assert_equals(r.status, 400, "Site 1 fetching Site 3 did recieve sec-ch-device-memory"); + // Step 2 + const site2Frame = document.createElement("iframe"); + site2Frame.src = "https://{{hosts[alt][]}}:{{ports[https][0]}}/client-hints/inner-delegation/resources/accept_ch_delegation_to_src_iframe.sub.https.html"; + site2Frame.allow = "ch-device-memory src" + document.body.appendChild(site2Frame); + // Step 6 + return new Promise(resolve => { + window.addEventListener("message", resolve); + }).then(e => { + assert_equals(e.data, "ch-device-memory is available as expected for src"); + }); +}, "postMessage: First-Party to Third-Party, Cross-Partition, Same-Origin"); +</script> +</body> diff --git a/testing/web-platform/tests/client-hints/inner-delegation/accept_ch_delegation_to_src.sub.https.html.headers b/testing/web-platform/tests/client-hints/inner-delegation/accept_ch_delegation_to_src.sub.https.html.headers new file mode 100644 index 0000000000..3b9de86bbd --- /dev/null +++ b/testing/web-platform/tests/client-hints/inner-delegation/accept_ch_delegation_to_src.sub.https.html.headers @@ -0,0 +1,2 @@ +Permissions-Policy: ch-device-memory=(self) +Accept-CH: Sec-CH-Device-Memory diff --git a/testing/web-platform/tests/client-hints/inner-delegation/resources/accept_ch_delegation_to_all_iframe.sub.https.html b/testing/web-platform/tests/client-hints/inner-delegation/resources/accept_ch_delegation_to_all_iframe.sub.https.html new file mode 100644 index 0000000000..09df9ec46f --- /dev/null +++ b/testing/web-platform/tests/client-hints/inner-delegation/resources/accept_ch_delegation_to_all_iframe.sub.https.html @@ -0,0 +1,32 @@ +<!doctype html> +<meta charset=utf-8> +<body> +<script> +async function test() { + // Step 3 (client-hints/inner-delegation/accept_ch_delegation_to_all.sub.https.html) + let r = await fetch("https://{{host}}:{{ports[https][0]}}/client-hints/inner-delegation/resources/was-sec-ch-device-memory-received.py"); + if (r.status == 200) { + return "Site 2 fetching Site 1 did recieve sec-ch-device-memory"; + } + r = await fetch("/client-hints/inner-delegation/resources/was-sec-ch-device-memory-received.py"); + if (r.status != 200) { + return "Site 2 fetching Site 2 didn't recieve sec-ch-device-memory"; + } + r = await fetch("https://{{domains[www2]}}:{{ports[https][0]}}/client-hints/inner-delegation/resources/was-sec-ch-device-memory-received.py"); + if (r.status == 200) { + return "Site 2 fetching Site 3 did recieve sec-ch-device-memory"; + } + // Step 4 (client-hints/inner-delegation/accept_ch_delegation_to_all.sub.https.html) + const site3Frame = document.createElement("iframe"); + site3Frame.src = "https://{{domains[www2]}}:{{ports[https][0]}}/client-hints/inner-delegation/resources/accept_ch_delegation_to_all_iframe_iframe.sub.https.html"; + site3Frame.allow = "ch-device-memory *" + document.body.appendChild(site3Frame); + return "" +} +test().then((message) => { + if (message) { + window.top.postMessage(message, "*"); + } +}); +</script> +</body> diff --git a/testing/web-platform/tests/client-hints/inner-delegation/resources/accept_ch_delegation_to_all_iframe_iframe.sub.https.html b/testing/web-platform/tests/client-hints/inner-delegation/resources/accept_ch_delegation_to_all_iframe_iframe.sub.https.html new file mode 100644 index 0000000000..4291ae954c --- /dev/null +++ b/testing/web-platform/tests/client-hints/inner-delegation/resources/accept_ch_delegation_to_all_iframe_iframe.sub.https.html @@ -0,0 +1,23 @@ +<!doctype html> +<meta charset=utf-8> +<body> +<script> +async function test() { + // Step 5 (client-hints/inner-delegation/accept_ch_delegation_to_all.sub.https.html) + let r = await fetch("https://{{host}}:{{ports[https][0]}}/client-hints/inner-delegation/resources/was-sec-ch-device-memory-received.py"); + if (r.status == 200) { + return "Site 3 fetching Site 1 did recieve sec-ch-device-memory"; + } + r = await fetch("https://{{hosts[alt][]}}:{{ports[https][0]}}/client-hints/inner-delegation/resources/was-sec-ch-device-memory-received.py"); + if (r.status == 200) { + return "Site 3 fetching Site 2 did recieve sec-ch-device-memory"; + } + r = await fetch("/client-hints/inner-delegation/resources/was-sec-ch-device-memory-received.py"); + if (r.status != 200) { + return "Site 3 fetching Site 3 didn't recieve sec-ch-device-memory"; + } + return "ch-device-memory is available as expected for all" +} +test().then((message) => window.top.postMessage(message, "*")); +</script> +</body> diff --git a/testing/web-platform/tests/client-hints/inner-delegation/resources/accept_ch_delegation_to_none_iframe.sub.https.html b/testing/web-platform/tests/client-hints/inner-delegation/resources/accept_ch_delegation_to_none_iframe.sub.https.html new file mode 100644 index 0000000000..cd88fa54fc --- /dev/null +++ b/testing/web-platform/tests/client-hints/inner-delegation/resources/accept_ch_delegation_to_none_iframe.sub.https.html @@ -0,0 +1,32 @@ +<!doctype html> +<meta charset=utf-8> +<body> +<script> +async function test() { + // Step 3 (client-hints/inner-delegation/accept_ch_delegation_to_none.sub.https.html) + let r = await fetch("https://{{host}}:{{ports[https][0]}}/client-hints/inner-delegation/resources/was-sec-ch-device-memory-received.py"); + if (r.status == 200) { + return "Site 2 fetching Site 1 did recieve sec-ch-device-memory"; + } + r = await fetch("/client-hints/inner-delegation/resources/was-sec-ch-device-memory-received.py"); + if (r.status == 200) { + return "Site 2 fetching Site 2 did recieve sec-ch-device-memory"; + } + r = await fetch("https://{{domains[www2]}}:{{ports[https][0]}}/client-hints/inner-delegation/resources/was-sec-ch-device-memory-received.py"); + if (r.status == 200) { + return "Site 2 fetching Site 3 did recieve sec-ch-device-memory"; + } + // Step 4 (client-hints/inner-delegation/accept_ch_delegation_to_none.sub.https.html) + const site3Frame = document.createElement("iframe"); + site3Frame.src = "https://{{domains[www2]}}:{{ports[https][0]}}/client-hints/inner-delegation/resources/accept_ch_delegation_to_none_iframe_iframe.sub.https.html"; + site3Frame.allow = "ch-device-memory none" + document.body.appendChild(site3Frame); + return "" +} +test().then((message) => { + if (message) { + window.top.postMessage(message, "*"); + } +}); +</script> +</body> diff --git a/testing/web-platform/tests/client-hints/inner-delegation/resources/accept_ch_delegation_to_none_iframe_iframe.sub.https.html b/testing/web-platform/tests/client-hints/inner-delegation/resources/accept_ch_delegation_to_none_iframe_iframe.sub.https.html new file mode 100644 index 0000000000..5d661f4b15 --- /dev/null +++ b/testing/web-platform/tests/client-hints/inner-delegation/resources/accept_ch_delegation_to_none_iframe_iframe.sub.https.html @@ -0,0 +1,23 @@ +<!doctype html> +<meta charset=utf-8> +<body> +<script> +async function test() { + // Step 5 (client-hints/inner-delegation/accept_ch_delegation_to_none.sub.https.html) + let r = await fetch("https://{{host}}:{{ports[https][0]}}/client-hints/inner-delegation/resources/was-sec-ch-device-memory-received.py"); + if (r.status == 200) { + return "Site 3 fetching Site 1 did recieve sec-ch-device-memory"; + } + r = await fetch("https://{{hosts[alt][]}}:{{ports[https][0]}}/client-hints/inner-delegation/resources/was-sec-ch-device-memory-received.py"); + if (r.status == 200) { + return "Site 3 fetching Site 2 did recieve sec-ch-device-memory"; + } + r = await fetch("/client-hints/inner-delegation/resources/was-sec-ch-device-memory-received.py"); + if (r.status == 200) { + return "Site 3 fetching Site 3 did recieve sec-ch-device-memory"; + } + return "ch-device-memory is available as expected for none" +} +test().then((message) => window.top.postMessage(message, "*")); +</script> +</body> diff --git a/testing/web-platform/tests/client-hints/inner-delegation/resources/accept_ch_delegation_to_self_iframe.sub.https.html b/testing/web-platform/tests/client-hints/inner-delegation/resources/accept_ch_delegation_to_self_iframe.sub.https.html new file mode 100644 index 0000000000..92157f4989 --- /dev/null +++ b/testing/web-platform/tests/client-hints/inner-delegation/resources/accept_ch_delegation_to_self_iframe.sub.https.html @@ -0,0 +1,32 @@ +<!doctype html> +<meta charset=utf-8> +<body> +<script> +async function test() { + // Step 3 (client-hints/inner-delegation/accept_ch_delegation_to_self.sub.https.html) + let r = await fetch("https://{{host}}:{{ports[https][0]}}/client-hints/inner-delegation/resources/was-sec-ch-device-memory-received.py"); + if (r.status == 200) { + return "Site 2 fetching Site 1 did recieve sec-ch-device-memory"; + } + r = await fetch("/client-hints/inner-delegation/resources/was-sec-ch-device-memory-received.py"); + if (r.status == 200) { + return "Site 2 fetching Site 2 did recieve sec-ch-device-memory"; + } + r = await fetch("https://{{domains[www2]}}:{{ports[https][0]}}/client-hints/inner-delegation/resources/was-sec-ch-device-memory-received.py"); + if (r.status == 200) { + return "Site 2 fetching Site 3 did recieve sec-ch-device-memory"; + } + // Step 4 (client-hints/inner-delegation/accept_ch_delegation_to_self.sub.https.html) + const site3Frame = document.createElement("iframe"); + site3Frame.src = "https://{{domains[www2]}}:{{ports[https][0]}}/client-hints/inner-delegation/resources/accept_ch_delegation_to_self_iframe_iframe.sub.https.html"; + site3Frame.allow = "ch-device-memory self" + document.body.appendChild(site3Frame); + return "" +} +test().then((message) => { + if (message) { + window.top.postMessage(message, "*"); + } +}); +</script> +</body> diff --git a/testing/web-platform/tests/client-hints/inner-delegation/resources/accept_ch_delegation_to_self_iframe_iframe.sub.https.html b/testing/web-platform/tests/client-hints/inner-delegation/resources/accept_ch_delegation_to_self_iframe_iframe.sub.https.html new file mode 100644 index 0000000000..e12759e076 --- /dev/null +++ b/testing/web-platform/tests/client-hints/inner-delegation/resources/accept_ch_delegation_to_self_iframe_iframe.sub.https.html @@ -0,0 +1,23 @@ +<!doctype html> +<meta charset=utf-8> +<body> +<script> +async function test() { + // Step 5 (client-hints/inner-delegation/accept_ch_delegation_to_self.sub.https.html) + let r = await fetch("https://{{host}}:{{ports[https][0]}}/client-hints/inner-delegation/resources/was-sec-ch-device-memory-received.py"); + if (r.status == 200) { + return "Site 3 fetching Site 1 did recieve sec-ch-device-memory"; + } + r = await fetch("https://{{hosts[alt][]}}:{{ports[https][0]}}/client-hints/inner-delegation/resources/was-sec-ch-device-memory-received.py"); + if (r.status == 200) { + return "Site 3 fetching Site 2 did recieve sec-ch-device-memory"; + } + r = await fetch("/client-hints/inner-delegation/resources/was-sec-ch-device-memory-received.py"); + if (r.status == 200) { + return "Site 3 fetching Site 3 did recieve sec-ch-device-memory"; + } + return "ch-device-memory is available as expected for self" +} +test().then((message) => window.top.postMessage(message, "*")); +</script> +</body> diff --git a/testing/web-platform/tests/client-hints/inner-delegation/resources/accept_ch_delegation_to_some_iframe.sub.https.html b/testing/web-platform/tests/client-hints/inner-delegation/resources/accept_ch_delegation_to_some_iframe.sub.https.html new file mode 100644 index 0000000000..39a4307230 --- /dev/null +++ b/testing/web-platform/tests/client-hints/inner-delegation/resources/accept_ch_delegation_to_some_iframe.sub.https.html @@ -0,0 +1,32 @@ +<!doctype html> +<meta charset=utf-8> +<body> +<script> +async function test() { + // Step 3 (client-hints/inner-delegation/accept_ch_delegation_to_some.sub.https.html) + let r = await fetch("https://{{host}}:{{ports[https][0]}}/client-hints/inner-delegation/resources/was-sec-ch-device-memory-received.py"); + if (r.status != 200) { + return "Site 2 fetching Site 1 didn't recieve sec-ch-device-memory"; + } + r = await fetch("/client-hints/inner-delegation/resources/was-sec-ch-device-memory-received.py"); + if (r.status != 200) { + return "Site 2 fetching Site 2 didn't recieve sec-ch-device-memory"; + } + r = await fetch("https://{{domains[www2]}}:{{ports[https][0]}}/client-hints/inner-delegation/resources/was-sec-ch-device-memory-received.py"); + if (r.status != 200) { + return "Site 2 fetching Site 3 didn't recieve sec-ch-device-memory"; + } + // Step 4 (client-hints/inner-delegation/accept_ch_delegation_to_some.sub.https.html) + const site3Frame = document.createElement("iframe"); + site3Frame.src = "https://{{domains[www2]}}:{{ports[https][0]}}/client-hints/inner-delegation/resources/accept_ch_delegation_to_some_iframe_iframe.sub.https.html"; + site3Frame.allow = "ch-device-memory https://{{domains[www2]}}:{{ports[https][0]}}" + document.body.appendChild(site3Frame); + return "" +} +test().then((message) => { + if (message) { + window.top.postMessage(message, "*"); + } +}); +</script> +</body> diff --git a/testing/web-platform/tests/client-hints/inner-delegation/resources/accept_ch_delegation_to_some_iframe.sub.https.html.headers b/testing/web-platform/tests/client-hints/inner-delegation/resources/accept_ch_delegation_to_some_iframe.sub.https.html.headers new file mode 100644 index 0000000000..3e53702c6e --- /dev/null +++ b/testing/web-platform/tests/client-hints/inner-delegation/resources/accept_ch_delegation_to_some_iframe.sub.https.html.headers @@ -0,0 +1 @@ +Permissions-Policy: ch-device-memory=(*) diff --git a/testing/web-platform/tests/client-hints/inner-delegation/resources/accept_ch_delegation_to_some_iframe_iframe.sub.https.html b/testing/web-platform/tests/client-hints/inner-delegation/resources/accept_ch_delegation_to_some_iframe_iframe.sub.https.html new file mode 100644 index 0000000000..999e3b6c99 --- /dev/null +++ b/testing/web-platform/tests/client-hints/inner-delegation/resources/accept_ch_delegation_to_some_iframe_iframe.sub.https.html @@ -0,0 +1,23 @@ +<!doctype html> +<meta charset=utf-8> +<body> +<script> +async function test() { + // Step 5 (client-hints/inner-delegation/accept_ch_delegation_to_some.sub.https.html) + let r = await fetch("https://{{host}}:{{ports[https][0]}}/client-hints/inner-delegation/resources/was-sec-ch-device-memory-received.py"); + if (r.status != 200) { + return "Site 3 fetching Site 1 didn't recieve sec-ch-device-memory"; + } + r = await fetch("https://{{hosts[alt][]}}:{{ports[https][0]}}/client-hints/inner-delegation/resources/was-sec-ch-device-memory-received.py"); + if (r.status == 200) { + return "Site 3 fetching Site 2 did recieve sec-ch-device-memory"; + } + r = await fetch("/client-hints/inner-delegation/resources/was-sec-ch-device-memory-received.py"); + if (r.status == 200) { + return "Site 3 fetching Site 3 did recieve sec-ch-device-memory"; + } + return "ch-device-memory is available as expected for some" +} +test().then((message) => window.top.postMessage(message, "*")); +</script> +</body> diff --git a/testing/web-platform/tests/client-hints/inner-delegation/resources/accept_ch_delegation_to_some_iframe_iframe.sub.https.html.sub.headers b/testing/web-platform/tests/client-hints/inner-delegation/resources/accept_ch_delegation_to_some_iframe_iframe.sub.https.html.sub.headers new file mode 100644 index 0000000000..e8ccc92f51 --- /dev/null +++ b/testing/web-platform/tests/client-hints/inner-delegation/resources/accept_ch_delegation_to_some_iframe_iframe.sub.https.html.sub.headers @@ -0,0 +1 @@ +Permissions-Policy: ch-device-memory=("https://{{host}}:{{ports[https][0]}}") diff --git a/testing/web-platform/tests/client-hints/inner-delegation/resources/accept_ch_delegation_to_src_iframe.sub.https.html b/testing/web-platform/tests/client-hints/inner-delegation/resources/accept_ch_delegation_to_src_iframe.sub.https.html new file mode 100644 index 0000000000..05d1db9fc9 --- /dev/null +++ b/testing/web-platform/tests/client-hints/inner-delegation/resources/accept_ch_delegation_to_src_iframe.sub.https.html @@ -0,0 +1,33 @@ +<!doctype html> +<meta charset=utf-8> +<body> +<script> +async function test() { + // Step 3 (client-hints/inner-delegation/accept_ch_delegation_to_src.sub.https.html) + const policy = JSON.stringify(document.featurePolicy.getAllowlistForFeature("ch-device-memory")); + let r = await fetch("https://{{host}}:{{ports[https][0]}}/client-hints/inner-delegation/resources/was-sec-ch-device-memory-received.py"); + if (r.status == 200) { + return "Site 2 fetching Site 1 did recieve sec-ch-device-memory"; + } + r = await fetch("/client-hints/inner-delegation/resources/was-sec-ch-device-memory-received.py"); + if (r.status == 200) { + return "Site 2 fetching Site 2 did recieve sec-ch-device-memory"; + } + r = await fetch("https://{{domains[www2]}}:{{ports[https][0]}}/client-hints/inner-delegation/resources/was-sec-ch-device-memory-received.py"); + if (r.status == 200) { + return "Site 2 fetching Site 3 did recieve sec-ch-device-memory"; + } + // Step 4 (client-hints/inner-delegation/accept_ch_delegation_to_src.sub.https.html) + const site3Frame = document.createElement("iframe"); + site3Frame.src = "https://{{domains[www2]}}:{{ports[https][0]}}/client-hints/inner-delegation/resources/accept_ch_delegation_to_src_iframe_iframe.sub.https.html"; + site3Frame.allow = "ch-device-memory src" + document.body.appendChild(site3Frame); + return "" +} +test().then((message) => { + if (message) { + window.top.postMessage(message, "*"); + } +}); +</script> +</body> diff --git a/testing/web-platform/tests/client-hints/inner-delegation/resources/accept_ch_delegation_to_src_iframe_iframe.sub.https.html b/testing/web-platform/tests/client-hints/inner-delegation/resources/accept_ch_delegation_to_src_iframe_iframe.sub.https.html new file mode 100644 index 0000000000..497a19161f --- /dev/null +++ b/testing/web-platform/tests/client-hints/inner-delegation/resources/accept_ch_delegation_to_src_iframe_iframe.sub.https.html @@ -0,0 +1,23 @@ +<!doctype html> +<meta charset=utf-8> +<body> +<script> +async function test() { + // Step 5 (client-hints/inner-delegation/accept_ch_delegation_to_src.sub.https.html) + let r = await fetch("https://{{host}}:{{ports[https][0]}}/client-hints/inner-delegation/resources/was-sec-ch-device-memory-received.py"); + if (r.status == 200) { + return "Site 3 fetching Site 1 did recieve sec-ch-device-memory"; + } + r = await fetch("https://{{hosts[alt][]}}:{{ports[https][0]}}/client-hints/inner-delegation/resources/was-sec-ch-device-memory-received.py"); + if (r.status == 200) { + return "Site 3 fetching Site 2 did recieve sec-ch-device-memory"; + } + r = await fetch("/client-hints/inner-delegation/resources/was-sec-ch-device-memory-received.py"); + if (r.status == 200) { + return "Site 3 fetching Site 3 did recieve sec-ch-device-memory"; + } + return "ch-device-memory is available as expected for src" +} +test().then((message) => window.top.postMessage(message, "*")); +</script> +</body> diff --git a/testing/web-platform/tests/client-hints/inner-delegation/resources/was-sec-ch-device-memory-received.py b/testing/web-platform/tests/client-hints/inner-delegation/resources/was-sec-ch-device-memory-received.py new file mode 100644 index 0000000000..f57e121252 --- /dev/null +++ b/testing/web-platform/tests/client-hints/inner-delegation/resources/was-sec-ch-device-memory-received.py @@ -0,0 +1,11 @@ +def main(request, response): + """ + Simple handler that sets the status based on whether sec-ch-device-memory was received. + """ + response.headers.append(b"Access-Control-Allow-Origin", b"*") + response.headers.append(b"Access-Control-Allow-Headers", b"*") + response.headers.append(b"Access-Control-Expose-Headers", b"*") + if b"sec-ch-device-memory" in request.headers: + response.status = 200 + else: + response.status = 400
\ No newline at end of file diff --git a/testing/web-platform/tests/client-hints/meta-equiv-delegate-ch-iframe.https.html b/testing/web-platform/tests/client-hints/meta-equiv-delegate-ch-iframe.https.html new file mode 100644 index 0000000000..2ce9c63c18 --- /dev/null +++ b/testing/web-platform/tests/client-hints/meta-equiv-delegate-ch-iframe.https.html @@ -0,0 +1,26 @@ +<!DOCTYPE html> +<html> +<meta http-equiv="Delegate-CH" content="Sec-CH-Device-Memory; Device-Memory; Sec-CH-DPR; DPR; Sec-CH-Viewport-Width; Viewport-Width"> +<title>Delegate-CH meta-equiv iframe test</title> +<body> +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> +<script src="/common/get-host-info.sub.js"></script> +<script src="/client-hints/resources/export.js"></script> +<script src="resources/feature-policy-navigation.js"></script> +<script> +(async () => { + await test_frame( + "HTTPS_ORIGIN", + meta_name_client_hints, + "", + "Client hints loaded on same-origin iframe include hints with a default permissions policy of self and *."); + await test_frame( + "HTTPS_REMOTE_ORIGIN", + expect_iframe_no_hints, + "", + "Client hints loaded on cross-origin iframe only include hints with a default permissions policy of *."); +})(); +</script> +</body> +</html> diff --git a/testing/web-platform/tests/client-hints/meta-equiv-delegate-ch-injection.https.html b/testing/web-platform/tests/client-hints/meta-equiv-delegate-ch-injection.https.html new file mode 100644 index 0000000000..b9e4a334fc --- /dev/null +++ b/testing/web-platform/tests/client-hints/meta-equiv-delegate-ch-injection.https.html @@ -0,0 +1,42 @@ +<!DOCTYPE html> +<html> +<head> + <title>Delegate-CH meta-equiv injection test</title> + <meta http-equiv="Delegate-CH" content=""> +</head> +<body> +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> + +<script> +// Even though the next line injects an "Delegate-CH" meta-equiv header, the +// browser should NOT attach the specified client hints in the request headers +// because javascript injected delegate-ch meta-equiv headers are not trusted. +document.getElementsByTagName('meta')[0].setAttribute("content", "dpr;sec-ch-dpr;device-memory;sec-ch-device-memory;viewport-width;sec-ch-viewport-width;rtt;downlink;ect"); +document.head.outerHTML += '<meta http-equiv="Delegate-CH" content="sec-ch-ua-arch;sec-ch-ua-platform;sec-ch-ua-model">'; +document.head.innerHTML += '<meta http-equiv="Delegate-CH" content="sec-ch-ua-full-version;sec-ch-ua-bitness;sec-ch-ua-full-version-list">'; +document.write('<meta http-equiv="Delegate-CH" content="sec-ch-ua-platform-version;sec-ch-prefers-color-scheme;sec-ch-prefers-reduced-motion;sec-ch-viewport-height">'); + +// resources/echo-client-hints-received.py sets the response headers depending on the set +// of client hints it receives in the request headers. +promise_test(t => { + return fetch("/client-hints/resources/echo-client-hints-received.py").then(r => { + assert_equals(r.status, 200) + // Verify that the browser does not include client hints for javascript + // injected headers on the XHR. + assert_false(r.headers.has("device-memory-received"), "device-memory-received"); + assert_false(r.headers.has("device-memory-deprecated-received"), "device-memory-deprecated-received"); + assert_false(r.headers.has("dpr-received"), "dpr-received"); + assert_false(r.headers.has("dpr-deprecated-received"), "dpr-deprecated-received"); + assert_false(r.headers.has("viewport-width-received"), "viewport-width-received"); + assert_false(r.headers.has("viewport-width-deprecated-received"), "viewport-width-deprecated-received"); + assert_false(r.headers.has("rtt-received"), "rtt-received"); + assert_false(r.headers.has("downlink-received"), "downlink-received"); + assert_false(r.headers.has("ect-received"), "ect-received"); + assert_false(r.headers.has("prefers-color-scheme-received"), "prefers-color-scheme-received"); + }); +}, "Delegate-CH meta-equiv injection test"); + +</script> +</body> +</html> diff --git a/testing/web-platform/tests/client-hints/meta-equiv-delegate-ch-malformed-header.https.html b/testing/web-platform/tests/client-hints/meta-equiv-delegate-ch-malformed-header.https.html new file mode 100644 index 0000000000..a4b91fd99b --- /dev/null +++ b/testing/web-platform/tests/client-hints/meta-equiv-delegate-ch-malformed-header.https.html @@ -0,0 +1,32 @@ +<!DOCTYPE html> +<html> +<meta http-equiv="Delegate-CH" content="Sec-CH-DPR= Sec-CH-Width"> +<title>Delegate-CH malformed meta-equiv test</title> +<body> +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> + +<script> + +promise_test(t => { + return fetch("/client-hints/resources/echo-client-hints-received.py").then(r => { + assert_equals(r.status, 200) + // Verify that the browser does not include client hints in the headers + // since Delegate-CH value in meta-equiv is malformed (includes whitespace + // between attributes instead of comma). + assert_false(r.headers.has("device-memory-received"), "device-memory-received"); + assert_false(r.headers.has("device-memory-deprecated-received"), "device-memory-deprecated-received"); + assert_false(r.headers.has("dpr-received"), "dpr-received"); + assert_false(r.headers.has("dpr-deprecated-received"), "dpr-deprecated-received"); + assert_false(r.headers.has("viewport-width-received"), "viewport-width-received"); + assert_false(r.headers.has("viewport-width-deprecated-received"), "viewport-width-deprecated-received"); + assert_false(r.headers.has("rtt-received"), "rtt-received"); + assert_false(r.headers.has("downlink-received"), "downlink-received"); + assert_false(r.headers.has("ect-received"), "ect-received"); + }); +}, "Delegate-CH malformed meta-equiv test"); + +</script> + +</body> +</html> diff --git a/testing/web-platform/tests/client-hints/meta-equiv-delegate-ch-merge.https.html b/testing/web-platform/tests/client-hints/meta-equiv-delegate-ch-merge.https.html new file mode 100644 index 0000000000..d8dbc9f96c --- /dev/null +++ b/testing/web-platform/tests/client-hints/meta-equiv-delegate-ch-merge.https.html @@ -0,0 +1,50 @@ +<!DOCTYPE html> +<html> +<head> +<meta http-equiv="Delegate-CH" content="sec-ch-viewport-width; viewport-width; rtt"> +<meta http-equiv="Delegate-CH" content="downlink; ect; sec-ch-prefers-color-scheme"> +<meta http-equiv="Delegate-CH" content="sec-ch-prefers-reduced-motion"> +<body> +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> +<script src="/common/get-host-info.sub.js"></script> +<script> + +// Test of merge of meta-equiv headers on top of delegate-ch provided ones. +// +// resources/echo-client-hints-received.py sets the response headers depending on the set +// of client hints it receives in the request headers. + +promise_test(t => { + return fetch(get_host_info()["HTTPS_ORIGIN"] + "/client-hints/resources/echo-client-hints-received.py").then(r => { + assert_equals(r.status, 200) + // Verify that the browser includes client hints in the headers. + assert_true(r.headers.has("device-memory-received"), "device-memory-received"); + assert_true(r.headers.has("device-memory-deprecated-received"), "device-memory-deprecated-received"); + assert_true(r.headers.has("dpr-received"), "dpr-received"); + assert_true(r.headers.has("dpr-deprecated-received"), "dpr-deprecated-received"); + assert_true(r.headers.has("viewport-width-received"), "viewport-width-received"); + assert_true(r.headers.has("viewport-width-deprecated-received"), "viewport-width-deprecated-received"); + + assert_true(r.headers.has("rtt-received"), "rtt-received"); + var rtt = parseInt(r.headers.get("rtt-received")); + assert_greater_than_equal(rtt, 0); + assert_less_than_equal(rtt, 3000); + assert_equals(rtt % 50, 0, 'rtt must be a multiple of 50 msec'); + + assert_true(r.headers.has("downlink-received"), "downlink-received"); + var downlinkKbps = r.headers.get("downlink-received") * 1000; + assert_greater_than_equal(downlinkKbps, 0); + assert_less_than_equal(downlinkKbps, 10000); + + assert_in_array(r.headers.get("ect-received"), ["slow-2g", "2g", + "3g", "4g"], 'ect-received is unexpected'); + assert_true(r.headers.has("prefers-color-scheme-received"), "prefers-color-scheme-received"); + assert_true(r.headers.has("prefers-reduced-motion-received"), "prefers-reduced-motion-received"); + }); +}, "Delegate-CH header test"); + +</script> + +</body> +</html> diff --git a/testing/web-platform/tests/client-hints/meta-equiv-delegate-ch-merge.https.html.headers b/testing/web-platform/tests/client-hints/meta-equiv-delegate-ch-merge.https.html.headers new file mode 100644 index 0000000000..34edb7b82b --- /dev/null +++ b/testing/web-platform/tests/client-hints/meta-equiv-delegate-ch-merge.https.html.headers @@ -0,0 +1,2 @@ +Accept-CH: sec-ch-device-memory, device-memory, sec-ch-dpr, dpr + diff --git a/testing/web-platform/tests/client-hints/meta-equiv-delegate-ch-non-secure.http.html b/testing/web-platform/tests/client-hints/meta-equiv-delegate-ch-non-secure.http.html new file mode 100644 index 0000000000..1fbe62c281 --- /dev/null +++ b/testing/web-platform/tests/client-hints/meta-equiv-delegate-ch-non-secure.http.html @@ -0,0 +1,40 @@ +<!DOCTYPE html> +<html> +<meta http-equiv="Delegate-CH" content="Sec-CH-DPR; DPR; Sec-CH-Width; Width; Sec-CH-Viewport-Width; Viewport-Width; Sec-CH-Device-Memory; Device-Memory; rtt; downlink; ect"> +<title>Delegate-CH meta-equiv insecure transport test</title> +<body> +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> + +<script> + +// Even though this HTML file contains "Delegate-CH" meta-equiv headers, the +// browser should NOT attach the specified client hints in the HTTP request +// headers since the page is being fetched over an insecure transport. +// Test this functionality by fetching an XHR from this page hosted on +// an insecure HTTP server. + +// resources/echo-client-hints-received.py sets the response headers depending on the set +// of client hints it receives in the request headers. + +promise_test(t => { + return fetch("/client-hints/resources/echo-client-hints-received.py").then(r => { + assert_equals(r.status, 200) + // Verify that the browser does not include client hints in the headers + // when fetching the XHR from an insecure HTTP server. + assert_false(r.headers.has("device-memory-received"), "device-memory-received"); + assert_false(r.headers.has("device-memory-deprecated-received"), "device-memory-deprecated-received"); + assert_false(r.headers.has("dpr-received"), "dpr-received"); + assert_false(r.headers.has("dpr-deprecated-received"), "dpr-deprecated-received"); + assert_false(r.headers.has("viewport-width-received"), "viewport-width-received"); + assert_false(r.headers.has("viewport-width-deprecated-received"), "viewport-width-deprecated-received"); + assert_false(r.headers.has("rtt-received"), "rtt-received"); + assert_false(r.headers.has("downlink-received"), "downlink-received"); + assert_false(r.headers.has("ect-received"), "ect-received"); + assert_false(r.headers.has("prefers-color-scheme-received"), "prefers-color-scheme-received"); + }); +}, "Delegate-CH meta-equiv test over insecure transport"); + +</script> +</body> +</html> diff --git a/testing/web-platform/tests/client-hints/resources/accept-ch-different.html b/testing/web-platform/tests/client-hints/resources/accept-ch-different.html new file mode 100644 index 0000000000..05cc0b61b0 --- /dev/null +++ b/testing/web-platform/tests/client-hints/resources/accept-ch-different.html @@ -0,0 +1,11 @@ +<html> +<body> + +<!-- An empty webpage whose response headers include only the +Accept-CH header. Fetching this webpage not cause +user-agent to persist origin preferences for the client hints +specified in the Accept-CH header. (This test sends a viewport-width +preference instead of the device-memory preference)--> + +</body> +</html> diff --git a/testing/web-platform/tests/client-hints/resources/accept-ch-different.html.headers b/testing/web-platform/tests/client-hints/resources/accept-ch-different.html.headers new file mode 100644 index 0000000000..b428fda331 --- /dev/null +++ b/testing/web-platform/tests/client-hints/resources/accept-ch-different.html.headers @@ -0,0 +1,2 @@ +Accept-CH: sec-ch-viewport-width,viewport-width +Access-Control-Allow-Origin: * diff --git a/testing/web-platform/tests/client-hints/resources/accept-ch-empty.html b/testing/web-platform/tests/client-hints/resources/accept-ch-empty.html new file mode 100644 index 0000000000..27393e5a1a --- /dev/null +++ b/testing/web-platform/tests/client-hints/resources/accept-ch-empty.html @@ -0,0 +1,11 @@ +<html> +<body> + +<!-- An empty webpage whose response headers include only the +Accept-CH header. Fetching this webpage should cause +user-agent to persist origin preferences for the client hints +specified in the Accept-CH header until the origin data is +cleared.--> + +</body> +</html> diff --git a/testing/web-platform/tests/client-hints/resources/accept-ch-empty.html.headers b/testing/web-platform/tests/client-hints/resources/accept-ch-empty.html.headers new file mode 100644 index 0000000000..25215abdf7 --- /dev/null +++ b/testing/web-platform/tests/client-hints/resources/accept-ch-empty.html.headers @@ -0,0 +1,2 @@ +Accept-CH: +Access-Control-Allow-Origin: * diff --git a/testing/web-platform/tests/client-hints/resources/accept-ch-malformed.html b/testing/web-platform/tests/client-hints/resources/accept-ch-malformed.html new file mode 100644 index 0000000000..70c1c75713 --- /dev/null +++ b/testing/web-platform/tests/client-hints/resources/accept-ch-malformed.html @@ -0,0 +1,11 @@ +<!DOCTYPE html> +<html> +<body> + +<!-- An empty webpage whose response headers include only the +Accept-CH header. Fetching this webpage should cause +user-agent to persist origin preferences for the client hints +specified in the Accept-CH header.--> + +</body> +</html> diff --git a/testing/web-platform/tests/client-hints/resources/accept-ch-malformed.html.headers b/testing/web-platform/tests/client-hints/resources/accept-ch-malformed.html.headers new file mode 100644 index 0000000000..83a6a05e54 --- /dev/null +++ b/testing/web-platform/tests/client-hints/resources/accept-ch-malformed.html.headers @@ -0,0 +1,2 @@ +Accept-CH: device memory +Access-Control-Allow-Origin: * diff --git a/testing/web-platform/tests/client-hints/resources/accept-ch.html b/testing/web-platform/tests/client-hints/resources/accept-ch.html new file mode 100644 index 0000000000..1f1da26ceb --- /dev/null +++ b/testing/web-platform/tests/client-hints/resources/accept-ch.html @@ -0,0 +1,10 @@ +<html> +<body> + +<!-- An empty webpage whose response headers include only the +Accept-CH header. Fetching this webpage should cause +user-agent to persist origin preferences for the client hints +specified in the Accept-CH header.--> + +</body> +</html> diff --git a/testing/web-platform/tests/client-hints/resources/accept-ch.html.headers b/testing/web-platform/tests/client-hints/resources/accept-ch.html.headers new file mode 100644 index 0000000000..f5beb4c365 --- /dev/null +++ b/testing/web-platform/tests/client-hints/resources/accept-ch.html.headers @@ -0,0 +1,2 @@ +Accept-CH: sec-ch-device-memory,device-memory +Access-Control-Allow-Origin: * diff --git a/testing/web-platform/tests/client-hints/resources/clienthintslist.py b/testing/web-platform/tests/client-hints/resources/clienthintslist.py new file mode 100644 index 0000000000..3d1f7caf46 --- /dev/null +++ b/testing/web-platform/tests/client-hints/resources/clienthintslist.py @@ -0,0 +1,40 @@ +def client_hints_list(): + return [b"device-memory", + b"dpr", + # b"width", (Only available for images) + b"viewport-width", + b"rtt", + b"downlink", + b"ect", + b"sec-ch-ua", + b"sec-ch-ua-arch", + b"sec-ch-ua-platform", + b"sec-ch-ua-model", + b"sec-ch-ua-mobile", + b"sec-ch-ua-full-version", + b"sec-ch-ua-platform-version", + b"sec-ch-prefers-color-scheme", + b"sec-ch-prefers-reduced-motion", + b"sec-ch-ua-bitness", + b"sec-ch-viewport-height", + b"sec-ch-device-memory", + b"sec-ch-dpr", + # b"sec-ch-width", (Only available for images) + b"sec-ch-viewport-width", + b"sec-ch-ua-full-version-list", + b"sec-ch-ua-wow64", + ] + +def client_hints_full_list(): + return client_hints_list() + [b"width", b"sec-ch-width"] + +def client_hints_ua_list(): + return [b"sec-ch-ua", + b"sec-ch-ua-arch", + b"sec-ch-ua-platform", + b"sec-ch-ua-platform-version", + b"sec-ch-ua-model", + b"sec-ch-ua-full-version", + b"sec-ch-ua-full-version-list", + b"sec-ch-ua-wow64", + ]
\ No newline at end of file diff --git a/testing/web-platform/tests/client-hints/resources/echo-client-hints-received.py b/testing/web-platform/tests/client-hints/resources/echo-client-hints-received.py new file mode 100644 index 0000000000..190cd86289 --- /dev/null +++ b/testing/web-platform/tests/client-hints/resources/echo-client-hints-received.py @@ -0,0 +1,36 @@ +def main(request, response): + """ + Simple handler that sets a response header based on which client hint + request headers were received. + """ + + response.headers.append(b"Access-Control-Allow-Origin", b"*") + response.headers.append(b"Access-Control-Allow-Headers", b"*") + response.headers.append(b"Access-Control-Expose-Headers", b"*") + + if b"sec-ch-device-memory" in request.headers: + response.headers.set(b"device-memory-received", request.headers.get(b"sec-ch-device-memory")) + if b"device-memory" in request.headers: + response.headers.set(b"device-memory-deprecated-received", request.headers.get(b"device-memory")) + if b"sec-ch-dpr" in request.headers: + response.headers.set(b"dpr-received", request.headers.get(b"sec-ch-dpr")) + if b"dpr" in request.headers: + response.headers.set(b"dpr-deprecated-received", request.headers.get(b"dpr")) + if b"sec-ch-viewport-width" in request.headers: + response.headers.set(b"viewport-width-received", request.headers.get(b"sec-ch-viewport-width")) + if b"viewport-width" in request.headers: + response.headers.set(b"viewport-width-deprecated-received", request.headers.get(b"viewport-width")) + if b"sec-ch-viewport-height" in request.headers: + response.headers.set(b"viewport-height-received", request.headers.get(b"sec-ch-viewport-height")) + if b"rtt" in request.headers: + response.headers.set(b"rtt-received", request.headers.get(b"rtt")) + if b"downlink" in request.headers: + response.headers.set(b"downlink-received", request.headers.get(b"downlink")) + if b"ect" in request.headers: + response.headers.set(b"ect-received", request.headers.get(b"ect")) + if b"sec-ch-ua-mobile" in request.headers: + response.headers.set(b"mobile-received", request.headers.get(b"sec-ch-ua-mobile")) + if b"sec-ch-prefers-color-scheme" in request.headers: + response.headers.set(b"prefers-color-scheme-received", request.headers.get(b"sec-ch-prefers-color-scheme")) + if b"sec-ch-prefers-reduced-motion" in request.headers: + response.headers.set(b"prefers-reduced-motion-received", request.headers.get(b"sec-ch-prefers-reduced-motion")) diff --git a/testing/web-platform/tests/client-hints/resources/echo-ua-client-hints-received.py b/testing/web-platform/tests/client-hints/resources/echo-ua-client-hints-received.py new file mode 100644 index 0000000000..7982421d07 --- /dev/null +++ b/testing/web-platform/tests/client-hints/resources/echo-ua-client-hints-received.py @@ -0,0 +1,23 @@ +import importlib +client_hints_ua_list = importlib.import_module("client-hints.resources.clienthintslist").client_hints_ua_list + +def main(request, response): + """ + Simple handler that sets a response header based on which client hint + request headers were received. + """ + + response.headers.append(b"Access-Control-Allow-Origin", b"*") + response.headers.append(b"Access-Control-Allow-Headers", b"*") + response.headers.append(b"Access-Control-Expose-Headers", b"*") + + client_hint_headers = client_hints_ua_list() + request_client_hints = {i: request.headers.get(i) for i in client_hint_headers} + + for header in client_hint_headers: + if request_client_hints[header] is not None: + response.headers.set(header + b"-received", request_client_hints[header]) + + headers = [] + content = u"" + return 200, headers, content diff --git a/testing/web-platform/tests/client-hints/resources/expect-client-hints-headers-iframe.py b/testing/web-platform/tests/client-hints/resources/expect-client-hints-headers-iframe.py new file mode 100644 index 0000000000..6a1218264e --- /dev/null +++ b/testing/web-platform/tests/client-hints/resources/expect-client-hints-headers-iframe.py @@ -0,0 +1,31 @@ +from wptserve.utils import isomorphic_decode + +import importlib +client_hints_list = importlib.import_module("client-hints.resources.clienthintslist").client_hints_list + +def main(request, response): + """ + Simple handler that returns an HTML response that passes when the required + Client Hints are received as request headers. + """ + + result = u"PASS" + log = u"" + for value in client_hints_list(): + should = (request.GET[value.lower()] == b"true") + present = request.headers.get(value.lower()) or request.headers.get(value) + if present: + log += isomorphic_decode(value) + u" " + str(should) + u" " + isomorphic_decode(present) + u", " + else: + log += isomorphic_decode(value) + u" " + str(should) + u" " + str(present) + u", " + if (should and not present) or (not should and present): + if present: + result = u"FAIL " + isomorphic_decode(value) + u" " + str(should) + u" " + isomorphic_decode(present) + else: + result = u"FAIL " + isomorphic_decode(value) + u" " + str(should) + u" " + str(present) + break + + response.headers.append(b"Access-Control-Allow-Origin", b"*") + body = u"<script>console.log('" + log + u"'); window.parent.postMessage('" + result + u"', '*');</script>" + + response.content = body diff --git a/testing/web-platform/tests/client-hints/resources/expect-client-hints-headers.html b/testing/web-platform/tests/client-hints/resources/expect-client-hints-headers.html new file mode 100644 index 0000000000..928a82db45 --- /dev/null +++ b/testing/web-platform/tests/client-hints/resources/expect-client-hints-headers.html @@ -0,0 +1,22 @@ +<html> +<body> +<script> + +// This test checks if browser attaches the device-memory client hint in the +// HTTP request headers. + +// resources/echo-client-hints-received.py sets the response headers depending on the set +// of client hints it receives in the request headers. + +fetch("../resources/echo-client-hints-received.py").then(r => { + if(r.status == 200 && r.headers.has("device-memory-received") && r.headers.has("device-memory-deprecated-received")) { + window.top.opener.postMessage('PASS', '*'); + } + else { + window.top.opener.postMessage('FAIL', '*'); + } +}); + +</script> +</body> +</html> diff --git a/testing/web-platform/tests/client-hints/resources/expect-different-client-hints-headers.html b/testing/web-platform/tests/client-hints/resources/expect-different-client-hints-headers.html new file mode 100644 index 0000000000..19ee394f46 --- /dev/null +++ b/testing/web-platform/tests/client-hints/resources/expect-different-client-hints-headers.html @@ -0,0 +1,22 @@ +<html> +<body> +<script> + +// This test checks if browser attaches the viewport-width client hint in the +// HTTP request headers. + +// resources/echo-client-hints-received.py sets the response headers depending on the set +// of client hints it receives in the request headers. + +fetch("../resources/echo-client-hints-received.py").then(r => { + if(r.status == 200 && r.headers.has("viewport-width-received") && r.headers.has("viewport-width-deprecated-received")) { + window.top.opener.postMessage('PASS', '*'); + } + else { + window.top.opener.postMessage('FAIL', '*'); + } +}); + +</script> +</body> +</html> diff --git a/testing/web-platform/tests/client-hints/resources/expect-no-client-hints-headers.html b/testing/web-platform/tests/client-hints/resources/expect-no-client-hints-headers.html new file mode 100644 index 0000000000..07eb0568d4 --- /dev/null +++ b/testing/web-platform/tests/client-hints/resources/expect-no-client-hints-headers.html @@ -0,0 +1,24 @@ +<!DOCTYPE html> +<html> +<body> +<script> + +// This test checks if browser attaches the viewport-width client hint in the +// HTTP request headers. + +// resources/echo-client-hints-received.py sets the response headers depending on the set +// of client hints it receives in the request headers. + +fetch("../resources/echo-client-hints-received.py").then(r => { + if(r.status == 200 && + !r.headers.has("viewport-width-received") && + !r.headers.has("viewport-width-received")) { + window.top.opener.postMessage('PASS', '*'); + } else { + window.top.opener.postMessage('FAIL', '*'); + } +}); + +</script> +</body> +</html> diff --git a/testing/web-platform/tests/client-hints/resources/export.js b/testing/web-platform/tests/client-hints/resources/export.js new file mode 100644 index 0000000000..68cea03ce4 --- /dev/null +++ b/testing/web-platform/tests/client-hints/resources/export.js @@ -0,0 +1,49 @@ +const client_hints_list = [ + "device-memory", + "dpr", + // "width", (only available for images) + "viewport-width", + "rtt", + "downlink", + "ect", + "sec-ch-ua", + "sec-ch-ua-arch", + "sec-ch-ua-platform", + "sec-ch-ua-model", + "sec-ch-ua-mobile", + "sec-ch-ua-full-version", + "sec-ch-ua-platform-version", + "sec-ch-prefers-color-scheme", + "sec-ch-prefers-reduced-motion", + "sec-ch-ua-bitness", + "sec-ch-viewport-height", + "sec-ch-device-memory", + "sec-ch-dpr", + // "sec-ch-width", (Only available for images) + "sec-ch-viewport-width", + "sec-ch-ua-full-version-list", + "sec-ch-ua-wow64", +]; + +const client_hints_full_list = client_hints_list.concat(["width", "sec-ch-width"]) + +const default_on_client_hints = [ + "sec-ch-ua", + "sec-ch-ua-mobile", + "sec-ch-ua-platform", +]; + +const iframe_src = + "/client-hints/resources/expect-client-hints-headers-iframe.py?"; + +const expect_iframe_no_hints = iframe_src + + client_hints_list.map((e) => { + if(default_on_client_hints.includes(e)) { + return e+"=true"; + } else { + return e+"=false"; + } + }).join("&"); + +const expect_iframe_hints = iframe_src + + client_hints_list.map(e => e+"=true").join("&");
\ No newline at end of file diff --git a/testing/web-platform/tests/client-hints/resources/feature-policy-navigation.js b/testing/web-platform/tests/client-hints/resources/feature-policy-navigation.js new file mode 100644 index 0000000000..23782fdfdb --- /dev/null +++ b/testing/web-platform/tests/client-hints/resources/feature-policy-navigation.js @@ -0,0 +1,72 @@ +const meta_name_enabled = [ + "sec-ch-device-memory", + "device-memory", + "sec-ch-dpr", + "dpr", + "sec-ch-viewport-width", + "viewport-width", + "sec-ch-ua", + "sec-ch-ua-mobile", + "sec-ch-ua-platform", +]; + +const meta_name_client_hints = iframe_src + + client_hints_list.map((e) => { + if(meta_name_enabled.includes(e)) { + return e+"=true"; + } else { + return e+"=false"; + } + }).join("&"); + +const cross_origin_enabled = [ + "device-memory", + "sec-ch-device-memory", + "sec-ch-ua-platform", +]; + +const cross_origin_client_hints = iframe_src + + client_hints_list.map((e) => { + if(cross_origin_enabled.includes(e)) { + return e+"=true"; + } else { + return e+"=false"; + } + }).join("&"); + +const same_origin_disabled = [ + "dpr", + "sec-ch-dpr", + "sec-ch-ua-mobile", +]; + +const same_origin_client_hints = iframe_src + + client_hints_list.map((e) => { + if(same_origin_disabled.includes(e)) { + return e+"=false"; + } else { + return e+"=true"; + } + }).join("&"); + +const test_frame = (origin, url, allow, message) => { + promise_test(() => { + return new Promise((resolve, reject) => { + let frame = document.createElement('iframe'); + frame.allow = allow; + window.addEventListener('message', function(e) { + try { + assert_equals(typeof e.data, "string"); + assert_equals(e.data, "PASS"); + } catch { + reject(e.data); + } + resolve(); + }); + document.body.appendChild(frame); + // Writing to |frame.src| triggers the navigation, so + // everything else need to happen first. + frame.src = get_host_info()[origin] + url; + }); + }, message); +} diff --git a/testing/web-platform/tests/client-hints/resources/open-and-add-load-event.js b/testing/web-platform/tests/client-hints/resources/open-and-add-load-event.js new file mode 100644 index 0000000000..bd88fcc28e --- /dev/null +++ b/testing/web-platform/tests/client-hints/resources/open-and-add-load-event.js @@ -0,0 +1,23 @@ +function open_and_add_load_event(href) { + return new Promise((resolve) => { + // While not practically possible, opening "blank" first and setting the + // href after allows for the theoretical possibility of registering the event + // after the window is loaded. + let popup_window = window.open("/resources/blank.html"); + assert_not_equals(popup_window, null, "Popup windows not allowed?"); + popup_window.addEventListener('load', resolve, {once: true}); + popup_window.location.href = href; + }); +} + +async function open_and_expect_headers(href) { + let e = await new Promise(resolve => { + let popup_window = window.open("/resources/blank.html"); + assert_not_equals(popup_window, null, "Popup windows not allowed?"); + window.addEventListener('message', resolve, false); + popup_window.location.href = href; + }); + + assert_equals(e.data, "PASS"); + return e; +}
\ No newline at end of file diff --git a/testing/web-platform/tests/client-hints/resources/script-set-dpr-header.py b/testing/web-platform/tests/client-hints/resources/script-set-dpr-header.py new file mode 100644 index 0000000000..9a65886ed8 --- /dev/null +++ b/testing/web-platform/tests/client-hints/resources/script-set-dpr-header.py @@ -0,0 +1,4 @@ +def main(request, response): + headers = [(b"Content-Type", b"text/javascript")] + body = u'dprHeader = "%s";' % request.headers.get(b'sec-ch-dpr', '') + return 200, headers, body diff --git a/testing/web-platform/tests/client-hints/resources/sec-ch-ua.py b/testing/web-platform/tests/client-hints/resources/sec-ch-ua.py new file mode 100644 index 0000000000..ddeb582a19 --- /dev/null +++ b/testing/web-platform/tests/client-hints/resources/sec-ch-ua.py @@ -0,0 +1,9 @@ +def main(request, response): + ua = request.headers.get(b'Sec-CH-UA', b'') + response.headers.set(b"Content-Type", b"text/html") + response.content = b''' +<script> + window.opener.postMessage({ header: '%s' }, "*"); +</script> +Sec-CH-UA: %s +''' % (ua, ua) diff --git a/testing/web-platform/tests/client-hints/resources/stale-echo-client-hints.py b/testing/web-platform/tests/client-hints/resources/stale-echo-client-hints.py new file mode 100644 index 0000000000..e9832273b8 --- /dev/null +++ b/testing/web-platform/tests/client-hints/resources/stale-echo-client-hints.py @@ -0,0 +1,50 @@ +import random +import string + +from wptserve.utils import isomorphic_encode +import importlib +client_hints_full_list = importlib.import_module("client-hints.resources.clienthintslist").client_hints_full_list + +def id_token(): + letters = string.ascii_lowercase + return u''.join(random.choice(letters) for i in range(20)) + +def main(request, response): + client_hint_headers = client_hints_full_list() + client_hints_curr = {i:request.headers.get(i) for i in client_hint_headers} + + token = request.GET.first(b"token", None) + is_query = request.GET.first(b"query", None) is not None + with request.server.stash.lock: + stash = request.server.stash.take(token) + if stash != None: + (value, client_hints_prev) = stash + count = int(value) + else: + count = 0 + client_hints_prev = {} + + if is_query: + if count < 2: + request.server.stash.put(token, (count, client_hints_curr)) + else: + count = count + 1 + request.server.stash.put(token, (count, client_hints_curr)) + + for header in client_hint_headers: + if client_hints_curr[header] is not None: + response.headers.set(header+b"-recieved", client_hints_curr[header]) + if (header in client_hints_prev) and (client_hints_prev[header] is not None): + response.headers.set(header+b"-previous", client_hints_prev[header]) + + if is_query: + headers = [(b"Count", count)] + content = u"" + return 200, headers, content + else: + unique_id = id_token() + headers = [(b"Content-Type", b"text/html"), + (b"Cache-Control", b"private, max-age=0, stale-while-revalidate=60"), + (b"Unique-Id", isomorphic_encode(unique_id))] + content = u"report('{}')".format(unique_id) + return 200, headers, content diff --git a/testing/web-platform/tests/client-hints/resources/viewport-frame.py b/testing/web-platform/tests/client-hints/resources/viewport-frame.py new file mode 100644 index 0000000000..67b592c71a --- /dev/null +++ b/testing/web-platform/tests/client-hints/resources/viewport-frame.py @@ -0,0 +1,25 @@ +def main(request, response): + """ + postMessage with Viewport-Width and Sec-Ch-Viewport-Height headers + """ + + if b"sec-ch-viewport-width" in request.headers: + width = request.headers["sec-ch-viewport-width"] + else: + width = b"FAIL" + + if b"sec-ch-viewport-height" in request.headers: + height = request.headers["sec-ch-viewport-height"] + else: + height = b"FAIL" + + headers = [(b"Content-Type", b"text/html"), + (b"Access-Control-Allow-Origin", b"*")] + content = b''' +<script> + let parentOrOpener = window.opener || window.parent; + parentOrOpener.postMessage({ viewportWidth: '%s', viewportHeight: '%s' }, "*"); +</script> +''' % (width, height) + + return 200, headers, content diff --git a/testing/web-platform/tests/client-hints/resources/viewport-measurement.html b/testing/web-platform/tests/client-hints/resources/viewport-measurement.html new file mode 100644 index 0000000000..2ac9043af7 --- /dev/null +++ b/testing/web-platform/tests/client-hints/resources/viewport-measurement.html @@ -0,0 +1,8 @@ +<!DOCTYPE html> +<script> +(async () => { + const response = await fetch("viewport.py"); + const body = await response.text(); + parent.postMessage(body, "*"); +})(); +</script> diff --git a/testing/web-platform/tests/client-hints/resources/viewport.py b/testing/web-platform/tests/client-hints/resources/viewport.py new file mode 100644 index 0000000000..d5ab6d4eee --- /dev/null +++ b/testing/web-platform/tests/client-hints/resources/viewport.py @@ -0,0 +1,13 @@ +def main(request, response): + """ + Reflect Sec-Ch-Viewport-Width and Sec-Ch-Viewport-Height headers + """ + + if b"sec-ch-viewport-width" in request.headers and b"sec-ch-viewport-height" in request.headers: + result = request.headers["sec-ch-viewport-width"] + b"," + request.headers["sec-ch-viewport-height"] + else: + result = u"FAIL" + + headers = [(b"Content-Type", b"text/html"), + (b"Access-Control-Allow-Origin", b"*")] + return 200, headers, result diff --git a/testing/web-platform/tests/client-hints/sandbox/__dir__.headers b/testing/web-platform/tests/client-hints/sandbox/__dir__.headers new file mode 100644 index 0000000000..f233c2e9d6 --- /dev/null +++ b/testing/web-platform/tests/client-hints/sandbox/__dir__.headers @@ -0,0 +1 @@ +Accept-CH: device-memory, dpr, width, viewport-width, rtt, downlink, ect, sec-ch-ua, sec-ch-ua-arch, sec-ch-ua-platform, sec-ch-ua-model, sec-ch-ua-mobile, sec-ch-ua-full-version, sec-ch-ua-platform-version, sec-ch-prefers-color-scheme, sec-ch-prefers-reduced-motion, sec-ch-ua-bitness, sec-ch-viewport-height, sec-ch-device-memory, sec-ch-dpr, sec-ch-width, sec-ch-viewport-width, sec-ch-ua-full-version-list, sec-ch-ua-wow64 diff --git a/testing/web-platform/tests/client-hints/sandbox/iframe-csp-same-origin.https.html b/testing/web-platform/tests/client-hints/sandbox/iframe-csp-same-origin.https.html new file mode 100644 index 0000000000..a5f094af9d --- /dev/null +++ b/testing/web-platform/tests/client-hints/sandbox/iframe-csp-same-origin.https.html @@ -0,0 +1,19 @@ +<!DOCTYPE html> +<html> + +<body> +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> +<script src="/client-hints/resources/export.js"></script> +<script src="resources/util.js"></script> + +<script> + +sandbox_iframe_test("", + expect_iframe_hints, + "CSP sandboxed iframe with same-origin flag does send client hint headers"); + +</script> + +</body> +</html>
\ No newline at end of file diff --git a/testing/web-platform/tests/client-hints/sandbox/iframe-csp-same-origin.https.html.headers b/testing/web-platform/tests/client-hints/sandbox/iframe-csp-same-origin.https.html.headers new file mode 100644 index 0000000000..895eb51993 --- /dev/null +++ b/testing/web-platform/tests/client-hints/sandbox/iframe-csp-same-origin.https.html.headers @@ -0,0 +1 @@ +Content-Security-Policy: sandbox allow-scripts allow-same-origin
\ No newline at end of file diff --git a/testing/web-platform/tests/client-hints/sandbox/iframe-csp.https.html b/testing/web-platform/tests/client-hints/sandbox/iframe-csp.https.html new file mode 100644 index 0000000000..fb63c393fd --- /dev/null +++ b/testing/web-platform/tests/client-hints/sandbox/iframe-csp.https.html @@ -0,0 +1,19 @@ +<!DOCTYPE html> +<html> + +<body> +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> +<script src="/client-hints/resources/export.js"></script> +<script src="resources/util.js"></script> + +<script> + +sandbox_iframe_test("", + expect_iframe_no_hints, + "CSP sandboxed iframe does not send client hint headers"); + +</script> + +</body> +</html>
\ No newline at end of file diff --git a/testing/web-platform/tests/client-hints/sandbox/iframe-csp.https.html.headers b/testing/web-platform/tests/client-hints/sandbox/iframe-csp.https.html.headers new file mode 100644 index 0000000000..c7e4e7cc5b --- /dev/null +++ b/testing/web-platform/tests/client-hints/sandbox/iframe-csp.https.html.headers @@ -0,0 +1 @@ +Content-Security-Policy: sandbox allow-scripts
\ No newline at end of file diff --git a/testing/web-platform/tests/client-hints/sandbox/iframe-iframe-popups.https.html b/testing/web-platform/tests/client-hints/sandbox/iframe-iframe-popups.https.html new file mode 100644 index 0000000000..9cbf6006c8 --- /dev/null +++ b/testing/web-platform/tests/client-hints/sandbox/iframe-iframe-popups.https.html @@ -0,0 +1,19 @@ +<!DOCTYPE html> +<html> + +<body> +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> +<script src="/client-hints/resources/export.js"></script> +<script src="resources/util.js"></script> + +<script> + +sandbox_iframe_test("allow-scripts allow-popups", + "resources/iframe-with-embedded-popup-expect-no-hints.html", + "Popup from an iframe within a sandboxed iframe does not send hints"); + +</script> + +</body> +</html>
\ No newline at end of file diff --git a/testing/web-platform/tests/client-hints/sandbox/iframe-popups-escape-sandbox.https.html b/testing/web-platform/tests/client-hints/sandbox/iframe-popups-escape-sandbox.https.html new file mode 100644 index 0000000000..35a94b537d --- /dev/null +++ b/testing/web-platform/tests/client-hints/sandbox/iframe-popups-escape-sandbox.https.html @@ -0,0 +1,19 @@ +<!DOCTYPE html> +<html> + +<body> +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> +<script src="/client-hints/resources/export.js"></script> +<script src="resources/util.js"></script> + +<script> + +sandbox_iframe_test("allow-scripts allow-popups allow-popups-to-escape-sandbox", + "resources/embedded-popup-expect-hints.html", + "popup from sandboxed iframe with allow-popups-to-escape-sandbox flag does send client hint headers"); + +</script> + +</body> +</html>
\ No newline at end of file diff --git a/testing/web-platform/tests/client-hints/sandbox/iframe-popups.https.html b/testing/web-platform/tests/client-hints/sandbox/iframe-popups.https.html new file mode 100644 index 0000000000..3d7bc6eb80 --- /dev/null +++ b/testing/web-platform/tests/client-hints/sandbox/iframe-popups.https.html @@ -0,0 +1,19 @@ +<!DOCTYPE html> +<html> + +<body> +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> +<script src="/client-hints/resources/export.js"></script> +<script src="resources/util.js"></script> + +<script> + +sandbox_iframe_test("allow-scripts allow-popups", + "resources/embedded-popup-expect-no-hints.html", + "popup from sandboxed iframe does not send client hint headers"); + +</script> + +</body> +</html>
\ No newline at end of file diff --git a/testing/web-platform/tests/client-hints/sandbox/iframe-same-origin.https.html b/testing/web-platform/tests/client-hints/sandbox/iframe-same-origin.https.html new file mode 100644 index 0000000000..0ea6a8ed53 --- /dev/null +++ b/testing/web-platform/tests/client-hints/sandbox/iframe-same-origin.https.html @@ -0,0 +1,17 @@ +<!DOCTYPE html> +<html> + +<body> +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> +<script src="/client-hints/resources/export.js"></script> +<script src="resources/util.js"></script> + +<script> +sandbox_iframe_test("allow-scripts allow-same-origin", + expect_iframe_hints, + "Same origin sandboxed iframe with allow-same-origin flag does send client hint headers"); +</script> + +</body> +</html>
\ No newline at end of file diff --git a/testing/web-platform/tests/client-hints/sandbox/iframe.https.html b/testing/web-platform/tests/client-hints/sandbox/iframe.https.html new file mode 100644 index 0000000000..f37b91011b --- /dev/null +++ b/testing/web-platform/tests/client-hints/sandbox/iframe.https.html @@ -0,0 +1,19 @@ +<!DOCTYPE html> +<html> + +<body> +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> +<script src="/client-hints/resources/export.js"></script> +<script src="resources/util.js"></script> + +<script> + +sandbox_iframe_test("allow-scripts", + expect_iframe_no_hints, + "sandboxed iframe does not send client hint headers"); + +</script> + +</body> +</html>
\ No newline at end of file diff --git a/testing/web-platform/tests/client-hints/sandbox/resources/embedded-popup-expect-hints.html b/testing/web-platform/tests/client-hints/sandbox/resources/embedded-popup-expect-hints.html new file mode 100644 index 0000000000..6cd5f0a29e --- /dev/null +++ b/testing/web-platform/tests/client-hints/sandbox/resources/embedded-popup-expect-hints.html @@ -0,0 +1,11 @@ +<!DOCTYPE html> +<html> +<body> +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> +<script src="util.js"></script> +<script> +sandbox_popup_listener("/client-hints/resources/expect-client-hints-headers.html"); +</script> +</body> +</html>
\ No newline at end of file diff --git a/testing/web-platform/tests/client-hints/sandbox/resources/embedded-popup-expect-no-hints.html b/testing/web-platform/tests/client-hints/sandbox/resources/embedded-popup-expect-no-hints.html new file mode 100644 index 0000000000..46dbb7f236 --- /dev/null +++ b/testing/web-platform/tests/client-hints/sandbox/resources/embedded-popup-expect-no-hints.html @@ -0,0 +1,11 @@ +<!DOCTYPE html> +<html> +<body> +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> +<script src="util.js"></script> +<script> +sandbox_popup_listener("/client-hints/resources/expect-no-client-hints-headers.html"); +</script> +</body> +</html>
\ No newline at end of file diff --git a/testing/web-platform/tests/client-hints/sandbox/resources/iframe-with-embedded-popup-expect-no-hints.html b/testing/web-platform/tests/client-hints/sandbox/resources/iframe-with-embedded-popup-expect-no-hints.html new file mode 100644 index 0000000000..21efd76180 --- /dev/null +++ b/testing/web-platform/tests/client-hints/sandbox/resources/iframe-with-embedded-popup-expect-no-hints.html @@ -0,0 +1,12 @@ +<!DOCTYPE html> +<html> +<body> +<script> + window.addEventListener('message', e => { + window.parent.postMessage(e.data, '*'); + }); + +</script> +<iframe src="embedded-popup-expect-no-hints.html" /> +</body> +</html>
\ No newline at end of file diff --git a/testing/web-platform/tests/client-hints/sandbox/resources/util.js b/testing/web-platform/tests/client-hints/sandbox/resources/util.js new file mode 100644 index 0000000000..8c25e5ad8b --- /dev/null +++ b/testing/web-platform/tests/client-hints/sandbox/resources/util.js @@ -0,0 +1,25 @@ +function sandbox_iframe_test(sandbox, src, title) { + return promise_test(async t => { + const iframe = document.createElement("iframe"); + if (sandbox !== "") + iframe.sandbox = sandbox; + iframe.src = src; + + let msg = await new Promise(resolve => { + window.addEventListener('message', resolve); + document.body.appendChild(iframe); + }); + + assert_equals(msg.data, "PASS", "message from opened frame"); + await fetch("/client-hints/accept-ch-stickiness/resources/clear-site-data.html"); + }, title); +} + +function sandbox_popup_listener(src) { + window.addEventListener('message', e => { + window.parent.postMessage(e.data, '*'); + }); + + let popup_window = window.open("/resources/blank.html"); + popup_window.location.href = src; +}
\ No newline at end of file diff --git a/testing/web-platform/tests/client-hints/sec-ch-quotes.https.html b/testing/web-platform/tests/client-hints/sec-ch-quotes.https.html new file mode 100644 index 0000000000..31dc945510 --- /dev/null +++ b/testing/web-platform/tests/client-hints/sec-ch-quotes.https.html @@ -0,0 +1,63 @@ +<!DOCTYPE html> +<meta charset="utf-8"> +<title>Tests Stale While Revalidate is not executed for fetch API</title> +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> +<script src="/common/utils.js"></script> +<script> +const verify_headers = (header_list, response, verification_func) => { + header_list.forEach(header => { + const value = response.headers.get(header+"-received"); + if(value) { + verification_func(value); + } + }); +}; + +promise_test(async (test) => { + const request_token = token(); + const string_list_client_hint_headers = [ + "sec-ch-ua", + ]; + const string_client_hint_headers = [ + "sec-ch-ua-arch", + "sec-ch-ua-platform", + "sec-ch-ua-platform-version", + "sec-ch-ua-model", + "sec-ch-ua-full-version", + "sec-ch-prefers-color-scheme", + "sec-ch-prefers-reduced-motion", + "sec-ch-ua-full-version-list", + "sec-ch-ua-wow64", + ]; + const boolean_client_hint_headers = [ + "sec-ch-mobile", + ]; + + const response = await fetch("resources/echo-ua-client-hints-received.py"); + verify_headers(string_client_hint_headers, response, value => { + if(value) { + // Check that the hints have quotes + // TODO(yoav): this doesn't account for parameters. Need an SH parser, that verifies no parameters are present. + assert_equals(value.slice(0,1), "\""); + assert_equals(value.slice(-1), "\""); + } + }); + verify_headers(string_list_client_hint_headers, response, value => { + // Check that the hints have quotes + // TODO(yoav): this doesn't account for list parsing or parameters. Need an SH parser, that verifies this is a list of strings with a "v" parameter present in at least one value. + assert_false((typeof value) == "undefined"); + assert_equals(value.slice(0,1), "\""); + assert_equals(value.slice(-1), "\""); + }); + verify_headers(boolean_client_hint_headers, response, value => { + if(value) { + // Check that the value is a valid boolean + assert_false((typeof value) == "undefined"); + assert_equals(value.slice(0,1), "?"); + const num = value.slice(-1); + assert_true(num == "0" || num == "1"); + } + }); +}, 'User agent client hint header values are surrounded by quotes'); +</script> diff --git a/testing/web-platform/tests/client-hints/sec-ch-quotes.https.html.headers b/testing/web-platform/tests/client-hints/sec-ch-quotes.https.html.headers new file mode 100644 index 0000000000..60ab0f2024 --- /dev/null +++ b/testing/web-platform/tests/client-hints/sec-ch-quotes.https.html.headers @@ -0,0 +1 @@ +Accept-CH: sec-ch-ua,sec-ch-ua-arch,sec-ch-ua-platform,sec-ch-ua-platform-version,sec-ch-ua-model,sec-ch-prefers-color-scheme,sec-ch-prefers-reduced-motion diff --git a/testing/web-platform/tests/client-hints/sec-ch-ua.http.html b/testing/web-platform/tests/client-hints/sec-ch-ua.http.html new file mode 100644 index 0000000000..e333c60530 --- /dev/null +++ b/testing/web-platform/tests/client-hints/sec-ch-ua.http.html @@ -0,0 +1,16 @@ +<!DOCTYPE html> +<script src=/resources/testharness.js></script> +<script src=/resources/testharnessreport.js></script> +<script> + promise_test(t => { + return new Promise((resolve, reject) => { + var w; + window.onmessage = e => { + assert_equals(e.data.header, "", "The `Sec-CH-UA` header is not delivered."); + w.close(); + resolve(); + }; + w = window.open("./resources/sec-ch-ua.py"); + }); + }, "Open HTTP window: no `Sec-CH-UA` header.") +</script> diff --git a/testing/web-platform/tests/client-hints/sec-ch-ua.https.html b/testing/web-platform/tests/client-hints/sec-ch-ua.https.html new file mode 100644 index 0000000000..deb8169216 --- /dev/null +++ b/testing/web-platform/tests/client-hints/sec-ch-ua.https.html @@ -0,0 +1,50 @@ +<!DOCTYPE html> +<head> +<script src=/resources/testharness.js></script> +<script src=/resources/testharnessreport.js></script> +<script> + var sec_ch_ua_header = ""; + + function grabSECCHUAHeader(t) { + return new Promise((resolve, reject) => { + var w; + window.onmessage = e => { + try { + resolve(e.data.header) + } catch (ex) { + reject(ex); + } + }; + w = window.open("./resources/sec-ch-ua.py"); + t.add_cleanup(w.close); + }); + } + promise_test(t => { + return grabSECCHUAHeader(t).then(header => { + sec_ch_ua_header = header; + assert_not_equals(sec_ch_ua_header, "", "`Sec-CH-UA` is sent."); + }); + }, "Open HTTPS window: `Sec-CH-UA` header returned by default."); + + promise_test(t => { + return grabSECCHUAHeader(t).then(header => { + assert_not_equals(header, "", "The `Sec-CH-UA` header is delivered."); + assert_equals(header, sec_ch_ua_header, + "The `Sec-CH-UA` header did not change between requests."); + }); + }, "Open HTTPS window: `Sec-CH-UA` header is consistent across versions."); + + promise_test(t => { + return grabSECCHUAHeader(t).then(header => { + assert_true(header.split(", ").every((brand) => { + let brandEnd = brand.indexOf(";v="); + assert_true(brandEnd !== -1, + "A well-formed Sec-CH-UA header must have version (v=) params"); + /* 32 + 2, becuase of the extra quotes padding the brand, + e.g. '"lol";v=22"' */ + return brandEnd < 34; + })); + }); + }, "Open HTTPS window: No brand in `Sec-CH-UA` header is > than 32 chars."); +</script> +</head> diff --git a/testing/web-platform/tests/client-hints/service-workers/critical-ch/echo-hint-in-html.py b/testing/web-platform/tests/client-hints/service-workers/critical-ch/echo-hint-in-html.py new file mode 100644 index 0000000000..87a1afed7c --- /dev/null +++ b/testing/web-platform/tests/client-hints/service-workers/critical-ch/echo-hint-in-html.py @@ -0,0 +1,24 @@ +import sys + +def main(request, response): + """ + Simple handler that sets a response header based on which client hint + request headers were received. + """ + + response.headers.append(b"Content-Type", b"text/html; charset=UTF-8") + response.headers.append(b"Access-Control-Allow-Origin", b"*") + response.headers.append(b"Access-Control-Allow-Headers", b"*") + response.headers.append(b"Access-Control-Expose-Headers", b"*") + + response.headers.append(b"Cache-Control", b"no-store") + + response.headers.append(b"Accept-CH", b"sec-ch-device-memory,device-memory"); + response.headers.append(b"Critical-CH", b"sec-ch-device-memory,device-memory"); + + result = "FAIL" + + if b"sec-ch-device-memory" in request.headers and b"device-memory" in request.headers: + result = "PASS" + + response.content = result diff --git a/testing/web-platform/tests/client-hints/service-workers/critical-ch/foo.html b/testing/web-platform/tests/client-hints/service-workers/critical-ch/foo.html new file mode 100644 index 0000000000..ba578e48b1 --- /dev/null +++ b/testing/web-platform/tests/client-hints/service-workers/critical-ch/foo.html @@ -0,0 +1 @@ +BAR diff --git a/testing/web-platform/tests/client-hints/service-workers/critical-ch/foo.html.headers b/testing/web-platform/tests/client-hints/service-workers/critical-ch/foo.html.headers new file mode 100644 index 0000000000..56b489178e --- /dev/null +++ b/testing/web-platform/tests/client-hints/service-workers/critical-ch/foo.html.headers @@ -0,0 +1,2 @@ +Accept-CH: sec-ch-device-memory, device-memory +Critical-CH: sec-ch-device-memory, device-memory diff --git a/testing/web-platform/tests/client-hints/service-workers/critical-ch/intercept-request.js b/testing/web-platform/tests/client-hints/service-workers/critical-ch/intercept-request.js new file mode 100644 index 0000000000..4d27ceadcc --- /dev/null +++ b/testing/web-platform/tests/client-hints/service-workers/critical-ch/intercept-request.js @@ -0,0 +1,6 @@ +self.addEventListener('fetch', (event) => { + result="FAIL"; + if(event.request.headers.has("sec-ch-device-memory") && event.request.headers.has("device-memory")) + result="PASS"; + event.respondWith(new Response(result)); +}); diff --git a/testing/web-platform/tests/client-hints/service-workers/critical-ch/navigation-preload.js b/testing/web-platform/tests/client-hints/service-workers/critical-ch/navigation-preload.js new file mode 100644 index 0000000000..d8a38ee7de --- /dev/null +++ b/testing/web-platform/tests/client-hints/service-workers/critical-ch/navigation-preload.js @@ -0,0 +1,2 @@ +self.addEventListener('activate', () => self.registration.navigationPreload.enable()); +self.addEventListener('fetch', (event) => event.respondWith(event.preloadResponse)); diff --git a/testing/web-platform/tests/client-hints/service-workers/critical-ch/new-request.js b/testing/web-platform/tests/client-hints/service-workers/critical-ch/new-request.js new file mode 100644 index 0000000000..395c77183e --- /dev/null +++ b/testing/web-platform/tests/client-hints/service-workers/critical-ch/new-request.js @@ -0,0 +1,3 @@ +self.addEventListener('fetch', (event) => { + event.respondWith(fetch("/client-hints/service-workers/resources/echo-hint-in-html.py")) +}); diff --git a/testing/web-platform/tests/client-hints/service-workers/critical-ch/passthrough-request.js b/testing/web-platform/tests/client-hints/service-workers/critical-ch/passthrough-request.js new file mode 100644 index 0000000000..5541c5eb55 --- /dev/null +++ b/testing/web-platform/tests/client-hints/service-workers/critical-ch/passthrough-request.js @@ -0,0 +1 @@ +self.addEventListener('fetch', (event) => fetch(event.request)); diff --git a/testing/web-platform/tests/client-hints/service-workers/intercept-request-critical.https.window.js b/testing/web-platform/tests/client-hints/service-workers/intercept-request-critical.https.window.js new file mode 100644 index 0000000000..079b9fd9ba --- /dev/null +++ b/testing/web-platform/tests/client-hints/service-workers/intercept-request-critical.https.window.js @@ -0,0 +1,5 @@ +// META: script=/service-workers/service-worker/resources/test-helpers.sub.js +// META: script=resources/util.js +promise_test((t) => + ch_sw_test(t, 'critical-ch/intercept-request.js', 'critical-ch/foo.html', 'FAIL'), + "Service workers succsefully receives hints from request"); diff --git a/testing/web-platform/tests/client-hints/service-workers/intercept-request.https.html b/testing/web-platform/tests/client-hints/service-workers/intercept-request.https.html new file mode 100644 index 0000000000..00e024b7b6 --- /dev/null +++ b/testing/web-platform/tests/client-hints/service-workers/intercept-request.https.html @@ -0,0 +1,11 @@ +<!DOCTYPE html> +<title>Client Hint/Service Worker interaction</title> +<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/util.js"></script> +<script> +promise_test((t) => + ch_sw_test(t, 'resources/intercept-request.js', 'resources/foo.html', 'PASS'), + "Service workers succsefully receives hints from request"); +</script> diff --git a/testing/web-platform/tests/client-hints/service-workers/intercept-request.https.html.headers b/testing/web-platform/tests/client-hints/service-workers/intercept-request.https.html.headers new file mode 100644 index 0000000000..546ac83d4b --- /dev/null +++ b/testing/web-platform/tests/client-hints/service-workers/intercept-request.https.html.headers @@ -0,0 +1 @@ +Accept-CH: sec-ch-device-memory, device-memory diff --git a/testing/web-platform/tests/client-hints/service-workers/navigation-preload-critical.https.window.js b/testing/web-platform/tests/client-hints/service-workers/navigation-preload-critical.https.window.js new file mode 100644 index 0000000000..5d05ab3c53 --- /dev/null +++ b/testing/web-platform/tests/client-hints/service-workers/navigation-preload-critical.https.window.js @@ -0,0 +1,5 @@ +//META: script=/service-workers/service-worker/resources/test-helpers.sub.js +//META: script=resources/util.js +promise_test((t) => + ch_sw_test(t, 'critical-ch/navigation-preload.js', 'critical-ch/echo-hint-in-html.py', 'PASS'), + "Service worker successfully passes hints through to new fetch"); diff --git a/testing/web-platform/tests/client-hints/service-workers/navigation-preload.https.html b/testing/web-platform/tests/client-hints/service-workers/navigation-preload.https.html new file mode 100644 index 0000000000..a952e1e406 --- /dev/null +++ b/testing/web-platform/tests/client-hints/service-workers/navigation-preload.https.html @@ -0,0 +1,11 @@ +<!DOCTYPE html> +<title>Client Hint/Service Worker interaction</title> +<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/util.js"></script> +<script> +promise_test((t) => + ch_sw_test(t, 'resources/navigation-preload.js', 'resources/echo-hint-in-html.py', 'PASS'), + "Service worker successfully passes hints through to new fetch"); +</script> diff --git a/testing/web-platform/tests/client-hints/service-workers/navigation-preload.https.html.headers b/testing/web-platform/tests/client-hints/service-workers/navigation-preload.https.html.headers new file mode 100644 index 0000000000..546ac83d4b --- /dev/null +++ b/testing/web-platform/tests/client-hints/service-workers/navigation-preload.https.html.headers @@ -0,0 +1 @@ +Accept-CH: sec-ch-device-memory, device-memory diff --git a/testing/web-platform/tests/client-hints/service-workers/new-request-critical.https.window.js b/testing/web-platform/tests/client-hints/service-workers/new-request-critical.https.window.js new file mode 100644 index 0000000000..9dee11a934 --- /dev/null +++ b/testing/web-platform/tests/client-hints/service-workers/new-request-critical.https.window.js @@ -0,0 +1,5 @@ +//META: script=/service-workers/service-worker/resources/test-helpers.sub.js +//META: script=resources/util.js +promise_test((t) => + ch_sw_test(t, 'critical-ch/new-request.js', 'critical-ch/foo.html', 'FAIL'), + "Service worker does NOT generate client hints in a new request"); diff --git a/testing/web-platform/tests/client-hints/service-workers/new-request.https.html b/testing/web-platform/tests/client-hints/service-workers/new-request.https.html new file mode 100644 index 0000000000..006ec24e8b --- /dev/null +++ b/testing/web-platform/tests/client-hints/service-workers/new-request.https.html @@ -0,0 +1,11 @@ +<!DOCTYPE html> +<title>Client Hint/Service Worker interaction</title> +<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/util.js"></script> +<script> +promise_test((t) => + ch_sw_test(t, 'resources/new-request.js', 'resources/foo.html', 'FAIL'), + "Service worker does NOT generate client hints in a new request"); +</script> diff --git a/testing/web-platform/tests/client-hints/service-workers/new-request.https.html.headers b/testing/web-platform/tests/client-hints/service-workers/new-request.https.html.headers new file mode 100644 index 0000000000..546ac83d4b --- /dev/null +++ b/testing/web-platform/tests/client-hints/service-workers/new-request.https.html.headers @@ -0,0 +1 @@ +Accept-CH: sec-ch-device-memory, device-memory diff --git a/testing/web-platform/tests/client-hints/service-workers/passthrough-request-critical.https.window.js b/testing/web-platform/tests/client-hints/service-workers/passthrough-request-critical.https.window.js new file mode 100644 index 0000000000..4d59f5f478 --- /dev/null +++ b/testing/web-platform/tests/client-hints/service-workers/passthrough-request-critical.https.window.js @@ -0,0 +1,5 @@ +//META: script=/service-workers/service-worker/resources/test-helpers.sub.js +//META: script=resources/util.js +promise_test((t) => + ch_sw_test(t, 'critical-ch/passthrough-request.js', 'critical-ch/echo-hint-in-html.py', 'PASS'), + "Service worker successfully passes hints through to new fetch"); diff --git a/testing/web-platform/tests/client-hints/service-workers/passthrough-request.https.html b/testing/web-platform/tests/client-hints/service-workers/passthrough-request.https.html new file mode 100644 index 0000000000..8dca424098 --- /dev/null +++ b/testing/web-platform/tests/client-hints/service-workers/passthrough-request.https.html @@ -0,0 +1,11 @@ +<!DOCTYPE html> +<title>Client Hint/Service Worker interaction</title> +<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/util.js"></script> +<script> +promise_test((t) => + ch_sw_test(t, 'resources/passthrough-request.js', 'resources/echo-hint-in-html.py', 'PASS'), + "Service worker successfully passes hints through to new fetch"); +</script> diff --git a/testing/web-platform/tests/client-hints/service-workers/passthrough-request.https.html.headers b/testing/web-platform/tests/client-hints/service-workers/passthrough-request.https.html.headers new file mode 100644 index 0000000000..546ac83d4b --- /dev/null +++ b/testing/web-platform/tests/client-hints/service-workers/passthrough-request.https.html.headers @@ -0,0 +1 @@ +Accept-CH: sec-ch-device-memory, device-memory diff --git a/testing/web-platform/tests/client-hints/service-workers/resources/echo-hint-in-html.py b/testing/web-platform/tests/client-hints/service-workers/resources/echo-hint-in-html.py new file mode 100644 index 0000000000..e029b5433b --- /dev/null +++ b/testing/web-platform/tests/client-hints/service-workers/resources/echo-hint-in-html.py @@ -0,0 +1,21 @@ +import sys + +def main(request, response): + """ + Simple handler that sets a response header based on which client hint + request headers were received. + """ + + response.headers.append(b"Content-Type", b"text/html; charset=UTF-8") + response.headers.append(b"Access-Control-Allow-Origin", b"*") + response.headers.append(b"Access-Control-Allow-Headers", b"*") + response.headers.append(b"Access-Control-Expose-Headers", b"*") + + response.headers.append(b"Cache-Control", b"no-store") + + result = "FAIL" + + if b"sec-ch-device-memory" in request.headers and b"device-memory" in request.headers: + result = "PASS" + + response.content = result diff --git a/testing/web-platform/tests/client-hints/service-workers/resources/foo.html b/testing/web-platform/tests/client-hints/service-workers/resources/foo.html new file mode 100644 index 0000000000..ba578e48b1 --- /dev/null +++ b/testing/web-platform/tests/client-hints/service-workers/resources/foo.html @@ -0,0 +1 @@ +BAR diff --git a/testing/web-platform/tests/client-hints/service-workers/resources/intercept-request.js b/testing/web-platform/tests/client-hints/service-workers/resources/intercept-request.js new file mode 100644 index 0000000000..4d27ceadcc --- /dev/null +++ b/testing/web-platform/tests/client-hints/service-workers/resources/intercept-request.js @@ -0,0 +1,6 @@ +self.addEventListener('fetch', (event) => { + result="FAIL"; + if(event.request.headers.has("sec-ch-device-memory") && event.request.headers.has("device-memory")) + result="PASS"; + event.respondWith(new Response(result)); +}); diff --git a/testing/web-platform/tests/client-hints/service-workers/resources/navigation-preload.js b/testing/web-platform/tests/client-hints/service-workers/resources/navigation-preload.js new file mode 100644 index 0000000000..d8a38ee7de --- /dev/null +++ b/testing/web-platform/tests/client-hints/service-workers/resources/navigation-preload.js @@ -0,0 +1,2 @@ +self.addEventListener('activate', () => self.registration.navigationPreload.enable()); +self.addEventListener('fetch', (event) => event.respondWith(event.preloadResponse)); diff --git a/testing/web-platform/tests/client-hints/service-workers/resources/new-request.js b/testing/web-platform/tests/client-hints/service-workers/resources/new-request.js new file mode 100644 index 0000000000..395c77183e --- /dev/null +++ b/testing/web-platform/tests/client-hints/service-workers/resources/new-request.js @@ -0,0 +1,3 @@ +self.addEventListener('fetch', (event) => { + event.respondWith(fetch("/client-hints/service-workers/resources/echo-hint-in-html.py")) +}); diff --git a/testing/web-platform/tests/client-hints/service-workers/resources/passthrough-request.js b/testing/web-platform/tests/client-hints/service-workers/resources/passthrough-request.js new file mode 100644 index 0000000000..5541c5eb55 --- /dev/null +++ b/testing/web-platform/tests/client-hints/service-workers/resources/passthrough-request.js @@ -0,0 +1 @@ +self.addEventListener('fetch', (event) => fetch(event.request)); diff --git a/testing/web-platform/tests/client-hints/service-workers/resources/util.js b/testing/web-platform/tests/client-hints/service-workers/resources/util.js new file mode 100644 index 0000000000..d9b8f3f4d9 --- /dev/null +++ b/testing/web-platform/tests/client-hints/service-workers/resources/util.js @@ -0,0 +1,23 @@ +async function ch_sw_test(t, worker, url, response) { + r = await service_worker_unregister_and_register(t, worker, url); + await wait_for_state(t, r.installing, 'activated') + var popup_window = window.open("/common/blank.html"); + assert_not_equals(popup_window, null, "Popup windows not allowed?"); + + t.add_cleanup(async _=>{ + popup_window.close(); + await r.unregister(); + }); + + popup_load = new Promise((resolve, reject) => { + popup_window.addEventListener('load', t.step_func((e) => { + if(popup_window.location.pathname != "/blank.html") { + assert_equals(popup_window.document.body.textContent, response); + resolve(); + } + })) + }); + + popup_window.location = url; + await popup_load; +} diff --git a/testing/web-platform/tests/client-hints/viewport-size/viewport-size-iframe.https.html b/testing/web-platform/tests/client-hints/viewport-size/viewport-size-iframe.https.html new file mode 100644 index 0000000000..6cb549d8f1 --- /dev/null +++ b/testing/web-platform/tests/client-hints/viewport-size/viewport-size-iframe.https.html @@ -0,0 +1,17 @@ +<!DOCTYPE html> +<html> +<body> +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> +<script> +promise_test(t => { + return new Promise(resolve => { + window.addEventListener("message", t.step_func(e => { + assert_equals(e.data.viewportWidth, window.innerWidth.toString()); + assert_equals(e.data.viewportHeight, window.innerHeight.toString()); + resolve(); + })); + }); +}); +</script> +<iframe src="../resources/viewport-frame.py" width=503 height=614></iframe> diff --git a/testing/web-platform/tests/client-hints/viewport-size/viewport-size-iframe.https.html.headers b/testing/web-platform/tests/client-hints/viewport-size/viewport-size-iframe.https.html.headers new file mode 100644 index 0000000000..76c3cb886c --- /dev/null +++ b/testing/web-platform/tests/client-hints/viewport-size/viewport-size-iframe.https.html.headers @@ -0,0 +1 @@ +Accept-CH: Sec-Ch-Viewport-Width,Sec-Ch-Viewport-Height diff --git a/testing/web-platform/tests/client-hints/viewport-size/viewport-size-subresource.https.html b/testing/web-platform/tests/client-hints/viewport-size/viewport-size-subresource.https.html new file mode 100644 index 0000000000..ec22a4bdf3 --- /dev/null +++ b/testing/web-platform/tests/client-hints/viewport-size/viewport-size-subresource.https.html @@ -0,0 +1,16 @@ +<!DOCTYPE html> +<html> +<body> +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> +<script> +promise_test(t => { + return new Promise(resolve => { + window.addEventListener("message", t.step_func(e => { + assert_equals(e.data, "503,614"); + resolve(); + })); + }); +}); +</script> +<iframe src="../resources/viewport-measurement.html" width=503 height=614> diff --git a/testing/web-platform/tests/client-hints/viewport-size/viewport-size-subresource.https.html.headers b/testing/web-platform/tests/client-hints/viewport-size/viewport-size-subresource.https.html.headers new file mode 100644 index 0000000000..76c3cb886c --- /dev/null +++ b/testing/web-platform/tests/client-hints/viewport-size/viewport-size-subresource.https.html.headers @@ -0,0 +1 @@ +Accept-CH: Sec-Ch-Viewport-Width,Sec-Ch-Viewport-Height diff --git a/testing/web-platform/tests/client-hints/viewport-size/viewport-size-window-different-dimensions.https.html b/testing/web-platform/tests/client-hints/viewport-size/viewport-size-window-different-dimensions.https.html new file mode 100644 index 0000000000..242f68e3fa --- /dev/null +++ b/testing/web-platform/tests/client-hints/viewport-size/viewport-size-window-different-dimensions.https.html @@ -0,0 +1,17 @@ +<!DOCTYPE html> +<html> +<body> +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> +<script> +promise_test(t => { + return new Promise(resolve => { + window.addEventListener("message", t.step_func(e => { + assert_equals(e.data.viewportWidth, "503"); + assert_equals(e.data.viewportHeight, "614"); + resolve(); + })); + }); +}); +window.open("../resources/viewport-frame.py", "", "width=503,height=614"); +</script> diff --git a/testing/web-platform/tests/client-hints/viewport-size/viewport-size-window-different-dimensions.https.html.headers b/testing/web-platform/tests/client-hints/viewport-size/viewport-size-window-different-dimensions.https.html.headers new file mode 100644 index 0000000000..76c3cb886c --- /dev/null +++ b/testing/web-platform/tests/client-hints/viewport-size/viewport-size-window-different-dimensions.https.html.headers @@ -0,0 +1 @@ +Accept-CH: Sec-Ch-Viewport-Width,Sec-Ch-Viewport-Height diff --git a/testing/web-platform/tests/client-hints/viewport-size/viewport-size-window.https.html b/testing/web-platform/tests/client-hints/viewport-size/viewport-size-window.https.html new file mode 100644 index 0000000000..0de61362b3 --- /dev/null +++ b/testing/web-platform/tests/client-hints/viewport-size/viewport-size-window.https.html @@ -0,0 +1,17 @@ +<!DOCTYPE html> +<html> +<body> +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> +<script> +promise_test(t => { + return new Promise(resolve => { + window.addEventListener("message", t.step_func(e => { + assert_equals(e.data.viewportWidth, window.innerWidth.toString()); + assert_equals(e.data.viewportHeight, window.innerHeight.toString()); + resolve(); + })); + }); +}); +window.open("../resources/viewport-frame.py", ""); +</script> diff --git a/testing/web-platform/tests/client-hints/viewport-size/viewport-size-window.https.html.headers b/testing/web-platform/tests/client-hints/viewport-size/viewport-size-window.https.html.headers new file mode 100644 index 0000000000..76c3cb886c --- /dev/null +++ b/testing/web-platform/tests/client-hints/viewport-size/viewport-size-window.https.html.headers @@ -0,0 +1 @@ +Accept-CH: Sec-Ch-Viewport-Width,Sec-Ch-Viewport-Height |