summaryrefslogtreecommitdiffstats
path: root/testing/web-platform/tests/client-hints/accept-ch-stickiness
diff options
context:
space:
mode:
authorDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-07 09:22:09 +0000
committerDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-07 09:22:09 +0000
commit43a97878ce14b72f0981164f87f2e35e14151312 (patch)
tree620249daf56c0258faa40cbdcf9cfba06de2a846 /testing/web-platform/tests/client-hints/accept-ch-stickiness
parentInitial commit. (diff)
downloadfirefox-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/accept-ch-stickiness')
-rw-r--r--testing/web-platform/tests/client-hints/accept-ch-stickiness/README.md14
-rw-r--r--testing/web-platform/tests/client-hints/accept-ch-stickiness/cross-origin-iframe-not-setting-other-origins.https.html19
-rw-r--r--testing/web-platform/tests/client-hints/accept-ch-stickiness/cross-origin-iframe-not-setting-own-origin.https.html19
-rw-r--r--testing/web-platform/tests/client-hints/accept-ch-stickiness/cross-origin-iframe-redirect-with-fp-delegation.https.html18
-rw-r--r--testing/web-platform/tests/client-hints/accept-ch-stickiness/cross-origin-iframe-redirect-with-fp-delegation.https.html.headers2
-rw-r--r--testing/web-platform/tests/client-hints/accept-ch-stickiness/cross-origin-navigation-redirect.https.html18
-rw-r--r--testing/web-platform/tests/client-hints/accept-ch-stickiness/cross-origin-navigation-redirect.https.html.headers1
-rw-r--r--testing/web-platform/tests/client-hints/accept-ch-stickiness/cross-origin-navigation.https.html19
-rw-r--r--testing/web-platform/tests/client-hints/accept-ch-stickiness/cross-origin-subresource-redirect-with-fp-delegation.https.html17
-rw-r--r--testing/web-platform/tests/client-hints/accept-ch-stickiness/cross-origin-subresource-redirect-with-fp-delegation.https.html.headers2
-rw-r--r--testing/web-platform/tests/client-hints/accept-ch-stickiness/cross-origin-subresource-redirect.https.html17
-rw-r--r--testing/web-platform/tests/client-hints/accept-ch-stickiness/cross-origin-subresource-redirect.https.html.headers1
-rw-r--r--testing/web-platform/tests/client-hints/accept-ch-stickiness/cross-origin-subresource-with-feature-policy.https.html19
-rw-r--r--testing/web-platform/tests/client-hints/accept-ch-stickiness/cross-origin-subresource.https.html19
-rw-r--r--testing/web-platform/tests/client-hints/accept-ch-stickiness/cross-origin-syncxhr-redirect.https.html17
-rw-r--r--testing/web-platform/tests/client-hints/accept-ch-stickiness/cross-origin-syncxhr-redirect.https.html.headers1
-rw-r--r--testing/web-platform/tests/client-hints/accept-ch-stickiness/http-equiv-cross-origin-iframe-not-setting-other-origins.https.html19
-rw-r--r--testing/web-platform/tests/client-hints/accept-ch-stickiness/http-equiv-cross-origin-iframe-not-setting-own-origin.https.html19
-rw-r--r--testing/web-platform/tests/client-hints/accept-ch-stickiness/http-equiv-cross-origin-navigation.https.html19
-rw-r--r--testing/web-platform/tests/client-hints/accept-ch-stickiness/http-equiv-cross-origin-subresource.https.html19
-rw-r--r--testing/web-platform/tests/client-hints/accept-ch-stickiness/http-equiv-same-origin-iframe.https.html19
-rw-r--r--testing/web-platform/tests/client-hints/accept-ch-stickiness/http-equiv-same-origin-navigation.https.html19
-rw-r--r--testing/web-platform/tests/client-hints/accept-ch-stickiness/http-equiv-same-origin-subresource.https.html19
-rw-r--r--testing/web-platform/tests/client-hints/accept-ch-stickiness/meta-equiv-cross-origin-iframe-not-setting-other-origins.https.html19
-rw-r--r--testing/web-platform/tests/client-hints/accept-ch-stickiness/meta-equiv-cross-origin-iframe-not-setting-own-origin.https.html19
-rw-r--r--testing/web-platform/tests/client-hints/accept-ch-stickiness/meta-equiv-cross-origin-navigation.https.html19
-rw-r--r--testing/web-platform/tests/client-hints/accept-ch-stickiness/meta-equiv-cross-origin-subresource.https.html19
-rw-r--r--testing/web-platform/tests/client-hints/accept-ch-stickiness/meta-equiv-delegate-ch-cross-origin-iframe-with-hints.https.sub.html18
-rw-r--r--testing/web-platform/tests/client-hints/accept-ch-stickiness/meta-equiv-delegate-ch-cross-origin-iframe-without-hints.https.sub.html18
-rw-r--r--testing/web-platform/tests/client-hints/accept-ch-stickiness/meta-equiv-delegate-ch-cross-origin-subresource-with-hints.https.sub.html18
-rw-r--r--testing/web-platform/tests/client-hints/accept-ch-stickiness/meta-equiv-delegate-ch-cross-origin-subresource-without-hints.https.sub.html18
-rw-r--r--testing/web-platform/tests/client-hints/accept-ch-stickiness/meta-equiv-same-origin-iframe.https.html19
-rw-r--r--testing/web-platform/tests/client-hints/accept-ch-stickiness/meta-equiv-same-origin-navigation.https.html19
-rw-r--r--testing/web-platform/tests/client-hints/accept-ch-stickiness/meta-equiv-same-origin-subresource.https.html19
-rw-r--r--testing/web-platform/tests/client-hints/accept-ch-stickiness/resources/accept-ch-and-redir.py5
-rw-r--r--testing/web-platform/tests/client-hints/accept-ch-stickiness/resources/accept-ch-blank.html11
-rw-r--r--testing/web-platform/tests/client-hints/accept-ch-stickiness/resources/accept-ch-blank.html.headers2
-rw-r--r--testing/web-platform/tests/client-hints/accept-ch-stickiness/resources/accept-ch-test.js133
-rw-r--r--testing/web-platform/tests/client-hints/accept-ch-stickiness/resources/accept-ch.html16
-rw-r--r--testing/web-platform/tests/client-hints/accept-ch-stickiness/resources/accept-ch.html.headers2
-rw-r--r--testing/web-platform/tests/client-hints/accept-ch-stickiness/resources/clear-site-data.html0
-rw-r--r--testing/web-platform/tests/client-hints/accept-ch-stickiness/resources/clear-site-data.html.headers2
-rw-r--r--testing/web-platform/tests/client-hints/accept-ch-stickiness/resources/do-expect-received.py20
-rw-r--r--testing/web-platform/tests/client-hints/accept-ch-stickiness/resources/do-not-expect-client-hints-headers.html22
-rw-r--r--testing/web-platform/tests/client-hints/accept-ch-stickiness/resources/do-not-expect-received.py20
-rw-r--r--testing/web-platform/tests/client-hints/accept-ch-stickiness/resources/echo-client-hints-received.py14
-rw-r--r--testing/web-platform/tests/client-hints/accept-ch-stickiness/resources/expect-client-hints-headers.html22
-rw-r--r--testing/web-platform/tests/client-hints/accept-ch-stickiness/resources/expect-received.py28
-rw-r--r--testing/web-platform/tests/client-hints/accept-ch-stickiness/resources/feature-policy-with-cross-origin-subresource.html25
-rw-r--r--testing/web-platform/tests/client-hints/accept-ch-stickiness/resources/feature-policy-with-cross-origin-subresource.html.headers1
-rw-r--r--testing/web-platform/tests/client-hints/accept-ch-stickiness/resources/http-equiv-accept-ch.html8
-rw-r--r--testing/web-platform/tests/client-hints/accept-ch-stickiness/resources/http-equiv-accept-ch.html.headers2
-rw-r--r--testing/web-platform/tests/client-hints/accept-ch-stickiness/resources/meta-equiv-delegate-ch.html9
-rw-r--r--testing/web-platform/tests/client-hints/accept-ch-stickiness/resources/meta-equiv-delegate-ch.html.headers2
-rw-r--r--testing/web-platform/tests/client-hints/accept-ch-stickiness/resources/no-accept-ch.html11
-rw-r--r--testing/web-platform/tests/client-hints/accept-ch-stickiness/resources/no-accept-ch.html.headers1
-rw-r--r--testing/web-platform/tests/client-hints/accept-ch-stickiness/same-origin-iframe.https.html19
-rw-r--r--testing/web-platform/tests/client-hints/accept-ch-stickiness/same-origin-navigation-empty-accept-ch.https.html20
-rw-r--r--testing/web-platform/tests/client-hints/accept-ch-stickiness/same-origin-navigation-no-accept-ch.https.html20
-rw-r--r--testing/web-platform/tests/client-hints/accept-ch-stickiness/same-origin-navigation-redirect.https.html19
-rw-r--r--testing/web-platform/tests/client-hints/accept-ch-stickiness/same-origin-navigation.https.html19
-rw-r--r--testing/web-platform/tests/client-hints/accept-ch-stickiness/same-origin-subresource-redirect-opted-in.https.html17
-rw-r--r--testing/web-platform/tests/client-hints/accept-ch-stickiness/same-origin-subresource-redirect-opted-in.https.html.headers1
-rw-r--r--testing/web-platform/tests/client-hints/accept-ch-stickiness/same-origin-subresource-redirect.https.html18
-rw-r--r--testing/web-platform/tests/client-hints/accept-ch-stickiness/same-origin-subresource.https.html19
65 files changed, 1049 insertions, 0 deletions
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>
+