Skip to content

Commit

Permalink
CSP: Implement 'prefetch-src' behind a flag.
Browse files Browse the repository at this point in the history
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
  • Loading branch information
mikewest authored and chromium-wpt-export-bot committed Jan 16, 2018
1 parent 6cc8fc5 commit 15b87f1
Show file tree
Hide file tree
Showing 8 changed files with 172 additions and 0 deletions.
23 changes: 23 additions & 0 deletions content-security-policy/prefetch-src/prefetch-allowed.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
<!DOCTYPE html>
<html>
<head>
<meta http-equiv="Content-Security-Policy" content="prefetch-src 'self'">
<script src='/resources/testharness.js'></script>
<script src='/resources/testharnessreport.js'></script>
<script src='/content-security-policy/support/testharness-helper.js'></script>
<script src='/content-security-policy/support/prefetch-helper.js'></script>
<script>
async_test(t => {
let url = window.origin + '/content-security-policy/support/pass.png';

let link = document.createElement('link');
link.rel = 'prefetch';
link.href = url;

assert_link_prefetches(t, link);
}, 'Prefetch succeeds when allowed by prefetch-src');
</script>
</head>
<body>
</body>
</html>
23 changes: 23 additions & 0 deletions content-security-policy/prefetch-src/prefetch-blocked.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
<!DOCTYPE html>
<html>
<head>
<meta http-equiv="Content-Security-Policy" content="prefetch-src 'none';">
<script src='/resources/testharness.js'></script>
<script src='/resources/testharnessreport.js'></script>
<script src='/content-security-policy/support/testharness-helper.js'></script>
<script src='/content-security-policy/support/prefetch-helper.js'></script>
<script>
async_test(t => {
let url = window.origin + '/content-security-policy/support/fail.png';

let link = document.createElement('link');
link.rel = 'prefetch';
link.href = url;

assert_link_does_not_prefetch(t, link);
}, "Blocked prefetch generates report.");
</script>
</head>
<body>
</body>
</html>
25 changes: 25 additions & 0 deletions content-security-policy/prefetch-src/prefetch-header-allowed.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
<!DOCTYPE html>
<html>
<head>
<!-- Headers:
Content-Security-Policy: prefetch-src 'self'
Link: </content-security-policy/support/pass.png>;rel=prefetch
-->
<script src='/resources/testharness.js'></script>
<script src='/resources/testharnessreport.js'></script>
<script src='/content-security-policy/support/testharness-helper.js'></script>
<script src='/content-security-policy/support/prefetch-helper.js'></script>
<script>
async_test(t => {
let url = window.origin + '/content-security-policy/support/pass.png';
assert_no_csp_event_for_url(t, url);

waitUntilResourceDownloaded(url)
.then(t.step_func_done());
}, 'Prefetch via `Link` header succeeds when allowed by prefetch-src');
</script>
</head>
<body>
</body>
</html>

Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
Content-Security-Policy: prefetch-src 'self'
Link: </content-security-policy/support/pass.png>;rel=prefetch
30 changes: 30 additions & 0 deletions content-security-policy/prefetch-src/prefetch-header-blocked.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
<!DOCTYPE html>
<html>
<head>
<meta http-equiv="Content-Security-Policy" content="prefetch-src 'none'">
<script src='/resources/testharness.js'></script>
<script src='/resources/testharnessreport.js'></script>
<script src='/content-security-policy/support/testharness-helper.js'></script>
<script src='/content-security-policy/support/prefetch-helper.js'></script>
<script>
async_test(t => {
let url = window.origin + '/content-security-policy/support/fail.png';
waitUntilCSPEventForURL(t, url)
.then(t.step_func_done(e => {
assert_equals(e.violatedDirective, 'prefetch-src');
assert_resource_not_downloaded(t, url);
}));

// Load a stylesheet that tries to trigger a prefetch:
let link = document.createElement('link');
link.rel = 'stylesheet';
link.href = '/content-security-policy/support/prefetch-subresource.css';
document.head.appendChild(link);
}, 'Prefetch via `Link` header succeeds when allowed by prefetch-src');
</script>
</head>
<body>
</body>
</html>


65 changes: 65 additions & 0 deletions content-security-policy/support/prefetch-helper.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
test(t => {
assert_true(document.createElement('link').relList.supports('prefetch'));
}, "Browser supports prefetch.");

test(t => {
assert_true(!!window.PerformanceResourceTiming);
}, "Browser supports performance APIs.");

async function waitUntilResourceDownloaded(url) {
await new Promise((resolve, reject) => {
if (performance.getEntriesByName(url).length >= 1)
resolve();

let observer = new PerformanceObserver(list => {
list.getEntries().forEach(entry => {
if (entry.name == url) {
resolve();
}
});
});
});
}

async function assert_resource_not_downloaded(test, url) {
if (performance.getEntriesByName(url).length >= 1) {
(test.unreached_func(`'${url}' should not have downloaded.`))();
}
}

function assert_link_prefetches(test, link) {
assert_no_csp_event_for_url(test, link.href);

link.onerror = test.unreached_func('onerror should not fire.');

// Test is finished when either the `load` event fires, or we get a performance
// entry showing that the resource loaded successfully.
link.onload = test.step_func(test.step_func_done());
waitUntilResourceDownloaded(link.href).then(test.step_func_done());

document.head.appendChild(link);
}

function assert_link_does_not_prefetch(test, link) {
let cspEvent = false;
let errorEvent = false;

waitUntilCSPEventForURL(test, link.href)
.then(test.step_func(e => {
cspEvent = true;
assert_equals(e.violatedDirective, "prefetch-src");
assert_equals(e.effectiveDirective, "prefetch-src");

if (errorEvent)
test.done();
}));

link.onerror = test.step_func(e => {
errorEvent = true;
if (cspEvent)
test.done();
});
link.onload = test.unreached_func('onload should not fire.');

document.head.appendChild(link);
}
3 changes: 3 additions & 0 deletions content-security-policy/support/prefetch-subresource.css
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
/* This CSS file sends some headers:
* Link: </content-security-policy/support/fail.png>;rel=prefetch
*/
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
Link: </content-security-policy/support/fail.png>;rel=prefetch

0 comments on commit 15b87f1

Please sign in to comment.