1 // https://w3c.github.io/webappsec-referrer-policy/#strip-url
2 function stripUrlForUseAsReferrer(url, originOnly) {
3 // Step 2. If url’s scheme is a local scheme, then return no referrer.
4 const parsedUrl = new URL(url);
6 if (["about:", "blob:", "data:"].includes(parsedUrl.protocol))
9 // Step 3. Set url’s username to the empty string.
10 parsedUrl.username = '';
12 // Step 4. Set url’s password to null.
13 parsedUrl.password = '';
15 // Step 5. Set url’s fragment to null.
18 // Step 6. If the origin-only flag is true, then:
20 // Step 6.1. Set url’s path to null.
21 parsedUrl.pathname = '';
22 // Step 6.2. Set url’s query to null.
23 parsedUrl.search = '';
25 return parsedUrl.href;
28 function invokeScenario(scenario) {
29 const urls = getRequestURLs(
32 scenario.redirection);
33 /** @type {Subresource} */
35 subresourceType: scenario.subresource,
37 policyDeliveries: scenario.subresource_policy_deliveries,
40 return invokeRequest(subresource, scenario.source_context_list);
43 const referrerUrlResolver = {
44 // The spec allows UAs to "enforce arbitrary policy considerations in the
45 // interests of minimizing data leakage"; to start to vaguely approximate
46 // this, we allow stronger policies to be used instead of what's specificed.
47 "omitted": function(sourceUrl) {
50 "origin": function(sourceUrl) {
51 return [stripUrlForUseAsReferrer(sourceUrl, true),
54 "stripped-referrer": function(sourceUrl) {
55 return [stripUrlForUseAsReferrer(sourceUrl, false),
56 stripUrlForUseAsReferrer(sourceUrl, true),
61 function checkResult(scenario, expectation, result) {
62 // https://w3c.github.io/webappsec-referrer-policy/#determine-requests-referrer
63 let referrerSource = result.sourceContextUrl;
64 const sentFromSrcdoc = scenario.source_context_list.length > 0 &&
65 scenario.source_context_list[scenario.source_context_list.length - 1]
66 .sourceContextType === 'srcdoc';
68 // Step 3. While document is an iframe srcdoc document, let document be
69 // document's browsing context's browsing context container's node
70 // document. [spec text]
72 // Workaround for srcdoc cases. Currently we only test <iframe srcdoc>
73 // inside the top-level Document, so |document| in the spec here is
74 // the top-level Document.
75 // This doesn't work if e.g. we test <iframe srcdoc> inside another
77 referrerSource = location.toString();
79 const possibleReferrerUrls =
80 referrerUrlResolver[expectation](referrerSource);
82 // Check the reported URL.
83 assert_in_array(result.referrer,
86 assert_in_array(result.headers.referer,
88 "HTTP Referer header");
91 function runLengthTest(scenario, urlLength, expectation, testDescription) {
92 // `Referer` headers with length over 4k are culled down to an origin, so,
93 // let's test around that boundary for tests that would otherwise return
95 history.pushState(null, null, "/");
96 history.replaceState(null, null,
97 "A".repeat(urlLength - location.href.length));
100 assert_equals(scenario.expectation, "stripped-referrer");
101 // Only on top-level Window, due to navigations using `history`.
102 assert_equals(scenario.source_context_list.length, 0);
104 return invokeScenario(scenario)
105 .then(result => checkResult(scenario, expectation, result));
109 function TestCase(scenarios, sanityChecker) {
110 function runTest(scenario) {
111 // This check is A NOOP in release.
112 sanityChecker.checkScenario(scenario);
115 return invokeScenario(scenario)
116 .then(result => checkResult(scenario, scenario.expectation, result));
117 }, scenario.test_description);
120 function runTests() {
121 for (const scenario of scenarios) {
126 return {start: runTests};