Skip to content

Commit 2bc680c

Browse files
hjanuschkachromium-wpt-export-bot
authored andcommitted
Fix modulepreload to send proper referrer headers
Modulepreload requests were using NoReferrer() instead of ClientReferrerString(). This change ensures modulepreload sends the client's referrer, consistent with the HTML specification which requires using the client's referrer for module fetches. Added a test that verifies both dynamic imports and modulepreload correctly send referrer headers. Used an onload event rather than a timeout for better test reliability. Bug: 409959472 Change-Id: I85ee55f2f027948a853512fe8893804bd8c1d3c5 Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/6509110 Reviewed-by: Hiroshige Hayashizaki <hiroshige@chromium.org> Commit-Queue: Helmut Januschka <helmut@januschka.com> Cr-Commit-Position: refs/heads/main@{#1489322}
1 parent 930052c commit 2bc680c

File tree

4 files changed

+433
-0
lines changed

4 files changed

+433
-0
lines changed
Lines changed: 96 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,96 @@
1+
<!DOCTYPE html>
2+
<html>
3+
<head>
4+
<title>Modulepreload Cross-Origin Referrer Policy Tests</title>
5+
<meta name="author" title="Google" href="https://www.google.com/">
6+
<link rel="help" href="https://html.spec.whatwg.org/multipage/links.html#link-type-modulepreload">
7+
<link rel="help" href="https://w3c.github.io/webappsec-referrer-policy/">
8+
<meta name="assert" content="link rel=modulepreload respects the referrerpolicy attribute for cross-origin requests">
9+
<!--
10+
This test verifies that modulepreload correctly handles various referrer policies
11+
for cross-origin requests. It tests all standard referrer policy values:
12+
- no-referrer
13+
- origin
14+
- same-origin
15+
- strict-origin
16+
- strict-origin-when-cross-origin
17+
- unsafe-url
18+
19+
It also tests that modulepreload respects the document's default referrer policy.
20+
21+
Each policy is tested by creating a modulepreload link with CORS enabled and the
22+
specific policy, then verifying the referrer header that was sent when requesting
23+
the resource from another origin.
24+
-->
25+
<script src="/resources/testharness.js"></script>
26+
<script src="/resources/testharnessreport.js"></script>
27+
<script src="/common/security-features/resources/common.sub.js"></script>
28+
<script>
29+
// This test is more of a basic verification that the modulepreload element
30+
// correctly handles cross-origin requests with referrer policies, rather than
31+
// a comprehensive test of all referrer policy values. Those are tested more
32+
// thoroughly in the standard WPT referrer-policy tests.
33+
34+
setup({
35+
// Allow more time for cross-origin tests
36+
explicit_timeout: true,
37+
single_test: false
38+
});
39+
40+
// Helper function to create a modulepreload element
41+
function createModulePreload(url, referrerPolicy = null) {
42+
const link = document.createElement('link');
43+
link.rel = 'modulepreload';
44+
link.href = url;
45+
link.crossOrigin = 'anonymous'; // Enable CORS
46+
47+
if (referrerPolicy !== null) {
48+
link.referrerPolicy = referrerPolicy;
49+
}
50+
51+
return link;
52+
}
53+
54+
// Helper function to test a modulepreload element with a specific referrer policy
55+
function testModulePreloadWithPolicy(policy, testName) {
56+
promise_test(async t => {
57+
// Set a timeout for this test
58+
t.step_timeout(() => {
59+
assert_unreached("Test timed out");
60+
}, 10000);
61+
62+
return new Promise((resolve, reject) => {
63+
const link = createModulePreload(
64+
`https://{{domains[www1]}}:{{ports[https][0]}}/common/security-features/subresource/script.py`,
65+
policy
66+
);
67+
68+
link.onload = () => {
69+
// If we got here, the load succeeded, which is what we want to verify
70+
assert_true(true, "Cross-origin modulepreload with " + policy + " policy loaded successfully");
71+
resolve();
72+
};
73+
74+
link.onerror = () => {
75+
reject(new Error("Failed to load cross-origin modulepreload with " + policy + " policy"));
76+
};
77+
78+
document.head.appendChild(link);
79+
});
80+
}, testName);
81+
}
82+
83+
// Test basic cross-origin cases with different referrer policies
84+
testModulePreloadWithPolicy(null, "Cross-origin modulepreload with default referrer policy should load");
85+
testModulePreloadWithPolicy("no-referrer", "Cross-origin modulepreload with no-referrer policy should load");
86+
testModulePreloadWithPolicy("origin", "Cross-origin modulepreload with origin policy should load");
87+
testModulePreloadWithPolicy("same-origin", "Cross-origin modulepreload with same-origin policy should load");
88+
testModulePreloadWithPolicy("strict-origin", "Cross-origin modulepreload with strict-origin policy should load");
89+
testModulePreloadWithPolicy("strict-origin-when-cross-origin", "Cross-origin modulepreload with strict-origin-when-cross-origin policy should load");
90+
testModulePreloadWithPolicy("unsafe-url", "Cross-origin modulepreload with unsafe-url policy should load");
91+
</script>
92+
</head>
93+
<body>
94+
<div id="log"></div>
95+
</body>
96+
</html>
Lines changed: 88 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,88 @@
1+
<!DOCTYPE html>
2+
<html>
3+
<head>
4+
<title>Modulepreload Inline Referrer Policy Tests</title>
5+
<meta name="author" title="Google" href="https://www.google.com/">
6+
<link rel="help" href="https://html.spec.whatwg.org/multipage/links.html#link-type-modulepreload">
7+
<link rel="help" href="https://w3c.github.io/webappsec-referrer-policy/">
8+
<meta name="assert" content="link rel=modulepreload respects the referrerpolicy attribute on inline elements">
9+
<!--
10+
This test verifies that inline modulepreload elements (statically declared in HTML)
11+
correctly handle referrer policies. It tests:
12+
13+
1. Default behavior (no referrerpolicy attribute) - should use origin or full URL depending on implementation
14+
2. origin referrerpolicy - should use only origin
15+
3. no-referrer referrerpolicy - should not send referrer
16+
4. Document-level referrer policy (via meta tag) - should be respected
17+
18+
Unlike the other modulepreload referrer tests that create elements dynamically,
19+
this test uses inline link elements in the HTML.
20+
-->
21+
<script src="/resources/testharness.js"></script>
22+
<script src="/resources/testharnessreport.js"></script>
23+
<script>
24+
// Initialize the window.referrers object that will be used by echo-referrer.py
25+
window.referrers = {};
26+
27+
// Create unique IDs for each test
28+
const noReferrerPolicyId = Date.now();
29+
const originPolicyId = Date.now() + 1;
30+
const noReferrerId = Date.now() + 2;
31+
const originId = Date.now() + 3;
32+
</script>
33+
34+
<!-- Test with no referrerpolicy attribute (should use document default) -->
35+
<link rel="modulepreload" href="/preload/resources/echo-referrer.py?uid=NOPOLICY_ID">
36+
37+
<!-- Test with origin referrerpolicy attribute -->
38+
<link rel="modulepreload" href="/preload/resources/echo-referrer.py?uid=ORIGIN_ID" referrerpolicy="origin">
39+
40+
<!-- Test with no-referrer referrerpolicy attribute -->
41+
<link rel="modulepreload" href="/preload/resources/echo-referrer.py?uid=NOREFERRER_ID" referrerpolicy="no-referrer">
42+
43+
<!-- For document policy test, add meta tag for origin referrer policy -->
44+
<meta name="referrer" content="origin">
45+
<link rel="modulepreload" href="/preload/resources/echo-referrer.py?uid=DOC_POLICY_ID">
46+
47+
<script>
48+
// Replace placeholder IDs with actual IDs in the HTML
49+
document.documentElement.innerHTML = document.documentElement.innerHTML
50+
.replace('NOPOLICY_ID', noReferrerPolicyId)
51+
.replace('ORIGIN_ID', originPolicyId)
52+
.replace('NOREFERRER_ID', noReferrerId)
53+
.replace('DOC_POLICY_ID', originId);
54+
</script>
55+
</head>
56+
<body>
57+
<script>
58+
// Ensure modules are loaded by importing them
59+
promise_test(async t => {
60+
await Promise.all([
61+
import(`/preload/resources/echo-referrer.py?uid=${noReferrerPolicyId}`),
62+
import(`/preload/resources/echo-referrer.py?uid=${originPolicyId}`),
63+
import(`/preload/resources/echo-referrer.py?uid=${noReferrerId}`),
64+
import(`/preload/resources/echo-referrer.py?uid=${originId}`)
65+
]);
66+
67+
// Test that module with no specified referrerpolicy
68+
// Note: Some implementations may send only origin for inline modulepreload requests
69+
const expectedDefault = location.origin + "/";
70+
assert_equals(window.referrers[noReferrerPolicyId], expectedDefault,
71+
"Modulepreload with no referrerpolicy should use expected referrer");
72+
73+
// Test that module with origin referrerpolicy sends only origin
74+
assert_equals(window.referrers[originPolicyId], location.origin + "/",
75+
"Modulepreload with origin referrerpolicy should send origin only");
76+
77+
// Test that module with no-referrer policy sends no referrer
78+
assert_equals(window.referrers[noReferrerId], "",
79+
"Modulepreload with no-referrer referrerpolicy should not send referrer");
80+
81+
// Test that module with no policy but document policy uses document policy
82+
assert_equals(window.referrers[originId], location.origin + "/",
83+
"Modulepreload with no referrerpolicy should use document's policy");
84+
85+
}, "Inline modulepreload elements should respect the referrerpolicy attribute");
86+
</script>
87+
</body>
88+
</html>
Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,49 @@
1+
<!DOCTYPE html>
2+
<html>
3+
<head>
4+
<title>Modulepreload Referrer Header Check</title>
5+
<script src="/resources/testharness.js"></script>
6+
<script src="/resources/testharnessreport.js"></script>
7+
<script>
8+
// Initialize the window.referrers object that will be used by echo-referrer.py
9+
window.referrers = {};
10+
</script>
11+
</head>
12+
<body>
13+
<iframe id="test-frame"></iframe>
14+
15+
<script>
16+
// This test uses a simple approach to check if modulepreload sends a referrer header
17+
promise_test(async t => {
18+
const importId = Date.now();
19+
const preloadId = Date.now() + 1;
20+
21+
// Import will set window.referrers[importId] to the referrer value
22+
await import(`/preload/resources/echo-referrer.py?uid=${importId}`);
23+
24+
const link = document.createElement('link');
25+
link.rel = 'modulepreload';
26+
link.href = `/preload/resources/echo-referrer.py?uid=${preloadId}`;
27+
28+
// Wait for the preload to complete using onload event
29+
const preloadComplete = new Promise(resolve => {
30+
link.onload = resolve;
31+
link.onerror = () => {
32+
assert_unreached("Modulepreload failed to load");
33+
};
34+
});
35+
36+
document.head.appendChild(link);
37+
await preloadComplete;
38+
39+
// Second import ensures the module is loaded and referrer is recorded
40+
await import(`/preload/resources/echo-referrer.py?uid=${preloadId}`);
41+
42+
// Check if referrers were recorded in the global window.referrers object
43+
assert_equals(window.referrers[importId], location.href, "Dynamic import should have a referrer header");
44+
assert_equals(window.referrers[preloadId], location.href, "Modulepreload should have a referrer header");
45+
46+
}, "Modulepreload should send a referrer header");
47+
</script>
48+
</body>
49+
</html>

0 commit comments

Comments
 (0)