blob: 28c3071804767b10a1bfe08ee6bc57855c274bcc [file] [log] [blame]
<!DOCTYPE html>
<meta charset="utf-8">
<title>Canvas tainting due to video whose responses are fetched via a service worker including range requests</title>
<script src="/resources/testharness.js"></script>
<script src="/resources/testharnessreport.js"></script>
<script src="resources/test-helpers.sub.js?pipe=sub"></script>
<script src="/common/get-host-info.sub.js"></script>
<body>
<script>
// These tests try to test canvas tainting due to a <video> element. The video
// src URL is same-origin as the page, but the response is fetched via a service
// worker that does tricky things like returning opaque responses from another
// origin. Furthermore, this tests range requests so there are multiple
// responses.
//
// We test range requests by having the server return 206 Partial Content to the
// first request (which doesn't necessarily have a "Range" header or one with a
// byte range). Then the <video> element automatically makes ranged requests
// (the "Range" HTTP request header specifies a byte range). The server responds
// to these with 206 Partial Content for the given range.
function range_request_test(script, expected, description) {
promise_test(t => {
let frame;
let registration;
add_result_callback(() => {
if (frame) frame.remove();
if (registration) registration.unregister();
});
const scope = 'resources/fetch-canvas-tainting-iframe.html';
return service_worker_unregister_and_register(t, script, scope)
.then(r => {
registration = r;
return wait_for_state(t, registration.installing, 'activated');
})
.then(() => {
return with_iframe(scope);
})
.then(f => {
frame = f;
// Add "?VIDEO&PartialContent" to get a video resource from the
// server using range requests.
const video_url = 'fetch-access-control.py?VIDEO&PartialContent';
return frame.contentWindow.create_test_case_promise(video_url);
})
.then(result => {
assert_equals(result, expected);
});
}, description);
}
// We want to consider a number of scenarios:
// (1) Range responses come from a single origin, the same-origin as the page.
// The canvas should not be tainted.
range_request_test(
'resources/fetch-event-network-fallback-worker.js',
'NOT_TAINTED',
'range responses from single origin (same-origin)');
// (2) Range responses come from a single origin, cross-origin from the page
// (and without CORS sharing). This is not possible to test, since service
// worker can't make a request with a "Range" HTTP header in no-cors mode.
// (3) Range responses come from multiple origins. The first response comes from
// cross-origin (and without CORS sharing, so is opaque). Subsequent
// responses come from same-origin. This should result in a load error, as regardless of canvas
// loading range requests from multiple opaque origins can reveal information across those origins.
range_request_test(
'resources/range-request-to-different-origins-worker.js',
'LOAD_ERROR',
'range responses from multiple origins (cross-origin first)');
// (4) Range responses come from multiple origins. The first response comes from
// same-origin. Subsequent responses come from cross-origin (and without
// CORS sharing). Like (2) this is not possible since the service worker
// cannot make range requests cross-origin.
// (5) Range responses come from a single origin, with a mix of opaque and
// non-opaque responses. The first request uses 'no-cors' mode to
// receive an opaque response, and subsequent range requests use 'cors'
// to receive non-opaque responses. The canvas should be tainted.
range_request_test(
'resources/range-request-with-different-cors-modes-worker.js',
'TAINTED',
'range responses from single origin with both opaque and non-opaque responses');
// (6) Range responses come from a single origin, with a mix of opaque and
// non-opaque responses. The first request uses 'cors' mode to
// receive an non-opaque response, and subsequent range requests use
// 'no-cors' to receive non-opaque responses. Like (2) this is not possible.
</script>
</body>