fetch-canvas-tainting-video-with-range-request.https.html (5286B)
1 <!DOCTYPE html> 2 <meta charset="utf-8"> 3 <title>Canvas tainting due to video whose responses are fetched via a service worker including range requests</title> 4 <script src="/resources/testharness.js"></script> 5 <script src="/resources/testharnessreport.js"></script> 6 <script src="resources/test-helpers.sub.js?pipe=sub"></script> 7 <script src="/common/get-host-info.sub.js"></script> 8 <body> 9 <script> 10 // These tests try to test canvas tainting due to a <video> element. The video 11 // src URL is same-origin as the page, but the response is fetched via a service 12 // worker that does tricky things like returning opaque responses from another 13 // origin. Furthermore, this tests range requests so there are multiple 14 // responses. 15 // 16 // We test range requests by having the server return 206 Partial Content to the 17 // first request (which doesn't necessarily have a "Range" header or one with a 18 // byte range). Then the <video> element automatically makes ranged requests 19 // (the "Range" HTTP request header specifies a byte range). The server responds 20 // to these with 206 Partial Content for the given range. 21 let unique = 0; // See https://bugzilla.mozilla.org/show_bug.cgi?id=1129121 22 function range_request_test(script, expected, description, 23 {remote_origin_src} = {}) { 24 promise_test(t => { 25 let frame; 26 let registration; 27 add_result_callback(() => { 28 if (frame) frame.remove(); 29 if (registration) registration.unregister(); 30 }); 31 32 const scope = 'resources/fetch-canvas-tainting-iframe.html'; 33 return service_worker_unregister_and_register(t, script, scope) 34 .then(r => { 35 registration = r; 36 return wait_for_state(t, registration.installing, 'activated'); 37 }) 38 .then(() => { 39 return with_iframe(scope); 40 }) 41 .then(f => { 42 frame = f; 43 // Add "?PartialContent&VIDEO" to get a video resource from the 44 // server using range requests. 45 let video_url = 46 'fetch-access-control.py?PartialContent&VIDEO=' + unique++; 47 if (remote_origin_src) { 48 video_url = get_host_info().HTTPS_REMOTE_ORIGIN + 49 base_path() + 'resources/' + video_url; 50 } 51 return frame.contentWindow.create_test_case_promise(video_url); 52 }) 53 .then(result => { 54 assert_equals(result, expected); 55 }); 56 }, description); 57 } 58 59 // We want to consider a number of scenarios: 60 // (1) Range responses come from a single origin, the same-origin as the page. 61 // The canvas should not be tainted. 62 range_request_test( 63 'resources/fetch-event-network-fallback-worker.js', 64 'NOT_TAINTED', 65 'range responses from single origin (same-origin)'); 66 67 // (2) Range responses come from a single origin, cross-origin from the page 68 // (and without CORS sharing). This is not possible to test, since service 69 // worker can't make a request with a "Range" HTTP header in no-cors mode. 70 71 // (3) Range responses come from multiple origins. The first response comes from 72 // cross-origin (and without CORS sharing, so is opaque). Subsequent 73 // responses come from same-origin. This should result in a load error, as regardless of canvas 74 // loading range requests from multiple opaque origins can reveal information across those origins. 75 range_request_test( 76 'resources/range-request-to-different-origins-worker.js', 77 'LOAD_ERROR', 78 'range responses from multiple origins (cross-origin first)'); 79 80 // (4) Range responses come from multiple origins. The first response comes from 81 // same-origin. Subsequent responses come from cross-origin (and without 82 // CORS sharing). Like (2) this is not possible since the service worker 83 // cannot make range requests cross-origin. 84 85 // (5) Range responses come from a single origin, with a mix of opaque and 86 // non-opaque responses. The first request uses 'no-cors' mode to 87 // receive an opaque response, and subsequent range requests use 'cors' 88 // to receive non-opaque responses. The canvas should be tainted. 89 range_request_test( 90 'resources/range-request-with-different-cors-modes-worker.js', 91 'TAINTED', 92 'range responses from single origin with both opaque and non-opaque responses'); 93 94 // (6) Range responses come from a single origin, with a mix of opaque and 95 // non-opaque responses. The first request uses 'cors' mode to 96 // receive an non-opaque response, and subsequent range requests use 97 // 'no-cors' to receive non-opaque responses. Like (2) this is not possible. 98 99 // (7) The first Range response is synthesized using the Response constructor. 100 // Subsequent responses are same-origin, not handled by the service worker. 101 range_request_test( 102 'resources/range-request-with-synth-head-worker.js', 103 'NOT_TAINTED', 104 'synth and same-origin fallback range responses'); 105 106 // (8) The first Range response is synthesized using the Response constructor. 107 // Subsequent responses are cross-origin, not handled by the service worker, 108 // no-cors and opaque. 109 range_request_test( 110 'resources/range-request-with-synth-head-worker.js', 111 'LOAD_ERROR', 112 'synth and cross-origin fallback range responses', 113 {remote_origin_src: true}); 114 </script> 115 </body>