Relax same-site prefetch referrer policy check

Applying the sufficiently-strict referrer policy restriction to all
prefetches was found to break legitimate same-site use cases. We now
only enforce this for cross-site prefetches. This also makes the logic
consistent between prefetch and prerender.

Bug: 1379846, 1355146
Change-Id: I945cc4f584af83e42cf80f146ee96823f2ada27a
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/4077268
Auto-Submit: Kevin McNee <mcnee@chromium.org>
Reviewed-by: Jeremy Roman <jbroman@chromium.org>
Commit-Queue: Jeremy Roman <jbroman@chromium.org>
Cr-Commit-Position: refs/heads/main@{#1079453}
diff --git a/speculation-rules/prefetch/referrer-policy-from-rules.https.html b/speculation-rules/prefetch/referrer-policy-from-rules.https.html
index ce3db0f..4120bf6 100644
--- a/speculation-rules/prefetch/referrer-policy-from-rules.https.html
+++ b/speculation-rules/prefetch/referrer-policy-from-rules.https.html
@@ -60,19 +60,18 @@
   const agent = await spawnWindow(t);
   await agent.setReferrerPolicy("unsafe-url");
 
-  const nextURL = agent.getExecutorURL({ page: 2 });
-  await agent.forceSinglePrefetch(nextURL, { referrer_policy: "no-referrer" });
+  const nextURL = agent.getExecutorURL({ hostname: PREFETCH_PROXY_BYPASS_HOST, page: 2 });
+  await agent.forceSinglePrefetch(
+      nextURL, { referrer_policy: "no-referrer", requires: ["anonymous-client-ip-when-cross-origin"] });
   await agent.navigate(nextURL);
 
   // This referring page's referrer policy would not be eligible for
-  // prefetching, but setting a sufficiently strict policy in the rule allows
-  // for prefetching.
-  // TODO(crbug.com/1379846): This test will be trivialized once the prefetch
-  // referrer policy requirements are relaxed for same-site.
+  // cross-site prefetching, but setting a sufficiently strict policy in the
+  // rule allows for prefetching.
   const headers = await agent.getRequestHeaders();
   assert_prefetched(headers, "must be prefetched");
   assert_equals(headers.referer, '', "must send no referrer");
-}, 'with "no-referrer" referrer policy in rule set overriding "unsafe-url" of referring page');
+}, 'with "no-referrer" referrer policy in rule set overriding "unsafe-url" of cross-site referring page');
 
 subsetTest(promise_test, async t => {
   assert_implements(HTMLScriptElement.supports('speculationrules'), "Speculation Rules not supported");
@@ -109,17 +108,17 @@
   await agent.setReferrerPolicy("strict-origin");
   const expectedReferrer = agent.getExecutorURL().origin + "/";
 
-  const nextURL = agent.getExecutorURL({ page: 2 });
-  await agent.forceSinglePrefetch(nextURL, { referrer_policy: "unsafe-url" });
+  const nextURL = agent.getExecutorURL({ hostname: PREFETCH_PROXY_BYPASS_HOST, page: 2 });
+  await agent.forceSinglePrefetch(
+      nextURL, { referrer_policy: "unsafe-url", requires: ["anonymous-client-ip-when-cross-origin"] });
   await agent.navigate(nextURL);
 
   // This referring page's referrer policy would normally make it eligible for
-  // prefetching, but setting an unacceptable policy in the rule makes it ineligible.
-  // TODO(crbug.com/1379846): This test will be invalidated once the prefetch
-  // referrer policy requirements are relaxed for same-site.
+  // cross-site prefetching, but setting an unacceptable policy in the rule
+  // makes it ineligible.
   const headers = await agent.getRequestHeaders();
   assert_not_prefetched(headers, "must not be prefetched");
   assert_equals(headers.referer, expectedReferrer, "must send the origin as the referrer");
-}, 'with "unsafe-url" referrer policy in rule set overriding "strict-origin" of referring page');
+}, 'with "unsafe-url" referrer policy in rule set overriding "strict-origin" of cross-site referring page');
 
 </script>
diff --git a/speculation-rules/prefetch/referrer-policy-not-accepted.https.html b/speculation-rules/prefetch/referrer-policy-not-accepted.https.html
index 25b1128..d7c003b 100644
--- a/speculation-rules/prefetch/referrer-policy-not-accepted.https.html
+++ b/speculation-rules/prefetch/referrer-policy-not-accepted.https.html
@@ -1,15 +1,21 @@
 <!DOCTYPE html>
 <title>Prefetch attempts with an unacceptable referrer policy</title>
+
+<!--Split test cases due to the use of timeouts in speculation rules test utilities.-->
+<meta name="variant" content="?1-1">
+<meta name="variant" content="?2-last">
+
 <script src="/resources/testharness.js"></script>
 <script src="/resources/testharnessreport.js"></script>
 <script src="/common/dispatcher/dispatcher.js"></script>
+<script src="/common/subset-tests.js"></script>
 <script src="/common/utils.js"></script>
 <script src="resources/utils.sub.js"></script>
 
 <script>
 "use strict";
 
-promise_test(async t => {
+subsetTest(promise_test, async t => {
   assert_implements(HTMLScriptElement.supports('speculationrules'), "Speculation Rules not supported");
 
   const agent = await spawnWindow(t);
@@ -17,13 +23,31 @@
   const expectedReferrer = agent.getExecutorURL().href;
 
   const nextURL = agent.getExecutorURL({ page: 2 });
-  // This prefetch attempt should be ignored.
   await agent.forceSinglePrefetch(nextURL);
   await agent.navigate(nextURL);
 
   const headers = await agent.getRequestHeaders();
+  // The referrer policy restriction does not apply to same-site prefetch.
+  assert_prefetched(headers, "must be prefetched");
+  assert_equals(headers.referer, expectedReferrer, "must send the full URL as the referrer");
+}, 'with "unsafe-url" referrer policy on same-site referring page');
+
+subsetTest(promise_test, async t => {
+  assert_implements(HTMLScriptElement.supports('speculationrules'), "Speculation Rules not supported");
+
+  const agent = await spawnWindow(t);
+  await agent.setReferrerPolicy("unsafe-url");
+  const expectedReferrer = agent.getExecutorURL().href;
+
+  const nextURL = agent.getExecutorURL({ hostname: PREFETCH_PROXY_BYPASS_HOST, page: 2 });
+  // This prefetch attempt should be ignored.
+  await agent.forceSinglePrefetch(
+      nextURL, { requires: ["anonymous-client-ip-when-cross-origin"] });
+  await agent.navigate(nextURL);
+
+  const headers = await agent.getRequestHeaders();
   assert_not_prefetched(headers, "must not be prefetched");
   assert_equals(headers.referer, expectedReferrer, "must send the full URL as the referrer");
-}, 'with "unsafe-url" referrer policy');
+}, 'with "unsafe-url" referrer policy on cross-site referring page');
 
 </script>
diff --git a/speculation-rules/prefetch/resources/utils.sub.js b/speculation-rules/prefetch/resources/utils.sub.js
index b29dd6b..a306b8c 100644
--- a/speculation-rules/prefetch/resources/utils.sub.js
+++ b/speculation-rules/prefetch/resources/utils.sub.js
@@ -159,7 +159,8 @@
 
 function assert_prefetched (requestHeaders, description) {
   assert_in_array(requestHeaders.purpose, ["", "prefetch"], "The vendor-specific header Purpose, if present, must be 'prefetch'.");
-  assert_equals(requestHeaders.sec_purpose, "prefetch", description);
+  assert_in_array(requestHeaders.sec_purpose,
+                  ["prefetch", "prefetch;anonymous-client-ip"], description);
 }
 
 function assert_not_prefetched (requestHeaders, description){