Skip to content

Commit 15b87f1

Browse files
mikewestchromium-wpt-export-bot
authored andcommitted
CSP: Implement 'prefetch-src' behind a flag.
As discussed in w3c/webappsec-csp#107, 'prefetch-src' gives developers the ability to control the endpoints from which resources may be prefetched. Bug: 801561 Change-Id: Ifedd78e3101ea66d242c6f3c7a2f49385a681bd1
1 parent 6cc8fc5 commit 15b87f1

8 files changed

+172
-0
lines changed
Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
<!DOCTYPE html>
2+
<html>
3+
<head>
4+
<meta http-equiv="Content-Security-Policy" content="prefetch-src 'self'">
5+
<script src='/resources/testharness.js'></script>
6+
<script src='/resources/testharnessreport.js'></script>
7+
<script src='/content-security-policy/support/testharness-helper.js'></script>
8+
<script src='/content-security-policy/support/prefetch-helper.js'></script>
9+
<script>
10+
async_test(t => {
11+
let url = window.origin + '/content-security-policy/support/pass.png';
12+
13+
let link = document.createElement('link');
14+
link.rel = 'prefetch';
15+
link.href = url;
16+
17+
assert_link_prefetches(t, link);
18+
}, 'Prefetch succeeds when allowed by prefetch-src');
19+
</script>
20+
</head>
21+
<body>
22+
</body>
23+
</html>
Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
<!DOCTYPE html>
2+
<html>
3+
<head>
4+
<meta http-equiv="Content-Security-Policy" content="prefetch-src 'none';">
5+
<script src='/resources/testharness.js'></script>
6+
<script src='/resources/testharnessreport.js'></script>
7+
<script src='/content-security-policy/support/testharness-helper.js'></script>
8+
<script src='/content-security-policy/support/prefetch-helper.js'></script>
9+
<script>
10+
async_test(t => {
11+
let url = window.origin + '/content-security-policy/support/fail.png';
12+
13+
let link = document.createElement('link');
14+
link.rel = 'prefetch';
15+
link.href = url;
16+
17+
assert_link_does_not_prefetch(t, link);
18+
}, "Blocked prefetch generates report.");
19+
</script>
20+
</head>
21+
<body>
22+
</body>
23+
</html>
Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
<!DOCTYPE html>
2+
<html>
3+
<head>
4+
<!-- Headers:
5+
Content-Security-Policy: prefetch-src 'self'
6+
Link: </content-security-policy/support/pass.png>;rel=prefetch
7+
-->
8+
<script src='/resources/testharness.js'></script>
9+
<script src='/resources/testharnessreport.js'></script>
10+
<script src='/content-security-policy/support/testharness-helper.js'></script>
11+
<script src='/content-security-policy/support/prefetch-helper.js'></script>
12+
<script>
13+
async_test(t => {
14+
let url = window.origin + '/content-security-policy/support/pass.png';
15+
assert_no_csp_event_for_url(t, url);
16+
17+
waitUntilResourceDownloaded(url)
18+
.then(t.step_func_done());
19+
}, 'Prefetch via `Link` header succeeds when allowed by prefetch-src');
20+
</script>
21+
</head>
22+
<body>
23+
</body>
24+
</html>
25+
Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
Content-Security-Policy: prefetch-src 'self'
2+
Link: </content-security-policy/support/pass.png>;rel=prefetch
Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
<!DOCTYPE html>
2+
<html>
3+
<head>
4+
<meta http-equiv="Content-Security-Policy" content="prefetch-src 'none'">
5+
<script src='/resources/testharness.js'></script>
6+
<script src='/resources/testharnessreport.js'></script>
7+
<script src='/content-security-policy/support/testharness-helper.js'></script>
8+
<script src='/content-security-policy/support/prefetch-helper.js'></script>
9+
<script>
10+
async_test(t => {
11+
let url = window.origin + '/content-security-policy/support/fail.png';
12+
waitUntilCSPEventForURL(t, url)
13+
.then(t.step_func_done(e => {
14+
assert_equals(e.violatedDirective, 'prefetch-src');
15+
assert_resource_not_downloaded(t, url);
16+
}));
17+
18+
// Load a stylesheet that tries to trigger a prefetch:
19+
let link = document.createElement('link');
20+
link.rel = 'stylesheet';
21+
link.href = '/content-security-policy/support/prefetch-subresource.css';
22+
document.head.appendChild(link);
23+
}, 'Prefetch via `Link` header succeeds when allowed by prefetch-src');
24+
</script>
25+
</head>
26+
<body>
27+
</body>
28+
</html>
29+
30+
Lines changed: 65 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,65 @@
1+
test(t => {
2+
assert_true(document.createElement('link').relList.supports('prefetch'));
3+
}, "Browser supports prefetch.");
4+
5+
test(t => {
6+
assert_true(!!window.PerformanceResourceTiming);
7+
}, "Browser supports performance APIs.");
8+
9+
async function waitUntilResourceDownloaded(url) {
10+
await new Promise((resolve, reject) => {
11+
if (performance.getEntriesByName(url).length >= 1)
12+
resolve();
13+
14+
let observer = new PerformanceObserver(list => {
15+
list.getEntries().forEach(entry => {
16+
if (entry.name == url) {
17+
resolve();
18+
}
19+
});
20+
});
21+
});
22+
}
23+
24+
async function assert_resource_not_downloaded(test, url) {
25+
if (performance.getEntriesByName(url).length >= 1) {
26+
(test.unreached_func(`'${url}' should not have downloaded.`))();
27+
}
28+
}
29+
30+
function assert_link_prefetches(test, link) {
31+
assert_no_csp_event_for_url(test, link.href);
32+
33+
link.onerror = test.unreached_func('onerror should not fire.');
34+
35+
// Test is finished when either the `load` event fires, or we get a performance
36+
// entry showing that the resource loaded successfully.
37+
link.onload = test.step_func(test.step_func_done());
38+
waitUntilResourceDownloaded(link.href).then(test.step_func_done());
39+
40+
document.head.appendChild(link);
41+
}
42+
43+
function assert_link_does_not_prefetch(test, link) {
44+
let cspEvent = false;
45+
let errorEvent = false;
46+
47+
waitUntilCSPEventForURL(test, link.href)
48+
.then(test.step_func(e => {
49+
cspEvent = true;
50+
assert_equals(e.violatedDirective, "prefetch-src");
51+
assert_equals(e.effectiveDirective, "prefetch-src");
52+
53+
if (errorEvent)
54+
test.done();
55+
}));
56+
57+
link.onerror = test.step_func(e => {
58+
errorEvent = true;
59+
if (cspEvent)
60+
test.done();
61+
});
62+
link.onload = test.unreached_func('onload should not fire.');
63+
64+
document.head.appendChild(link);
65+
}
Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
/* This CSS file sends some headers:
2+
* Link: </content-security-policy/support/fail.png>;rel=prefetch
3+
*/
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
Link: </content-security-policy/support/fail.png>;rel=prefetch

0 commit comments

Comments
 (0)