reporting-navigation.https.window.js (4916B)
1 // META: timeout=long 2 // META: script=/common/get-host-info.sub.js 3 // META: script=./resources/common.js 4 const {ORIGIN, REMOTE_ORIGIN} = get_host_info(); 5 const COEP = '|header(cross-origin-embedder-policy,credentialless)'; 6 const COEP_RO = 7 '|header(cross-origin-embedder-policy-report-only,credentialless)'; 8 const CORP_CROSS_ORIGIN = 9 '|header(cross-origin-resource-policy,cross-origin)'; 10 const FRAME_URL = `${ORIGIN}/common/blank.html?pipe=`; 11 const REMOTE_FRAME_URL = `${REMOTE_ORIGIN}/common/blank.html?pipe=`; 12 13 function checkCorpReport(report, contextUrl, blockedUrl, disposition) { 14 assert_equals(report.type, 'coep'); 15 assert_equals(report.url, contextUrl); 16 assert_equals(report.body.type, 'corp'); 17 assert_equals(report.body.blockedURL, blockedUrl); 18 assert_equals(report.body.disposition, disposition); 19 assert_equals(report.body.destination, 'iframe'); 20 } 21 22 function checkCoepMismatchReport(report, contextUrl, blockedUrl, disposition) { 23 assert_equals(report.type, 'coep'); 24 assert_equals(report.url, contextUrl); 25 assert_equals(report.body.type, 'navigation'); 26 assert_equals(report.body.blockedURL, blockedUrl); 27 assert_equals(report.body.disposition, disposition); 28 } 29 30 function loadFrame(document, url) { 31 return new Promise((resolve, reject) => { 32 const frame = document.createElement('iframe'); 33 frame.src = url; 34 frame.onload = () => resolve(frame); 35 frame.onerror = reject; 36 document.body.appendChild(frame); 37 }); 38 } 39 40 // |parentSuffix| is a suffix for the parent frame URL. 41 // |targetUrl| is a URL for the target frame. 42 async function loadFrames(test, parentSuffix, targetUrl) { 43 const frame = await loadFrame(document, FRAME_URL + parentSuffix); 44 test.add_cleanup(() => frame.remove()); 45 // Here we don't need "await". This loading may or may not succeed, and 46 // we're not interested in the result. 47 loadFrame(frame.contentDocument, targetUrl); 48 49 return frame; 50 } 51 52 async function observeReports(global, expected_count) { 53 const reports = []; 54 const receivedEveryReports = new Promise(resolve => { 55 if (expected_count == 0) 56 resolve(); 57 58 const observer = new global.ReportingObserver((rs) => { 59 for (const r of rs) { 60 reports.push(r.toJSON()); 61 } 62 if (expected_count <= reports.length) 63 resolve(); 64 }); 65 observer.observe(); 66 67 }); 68 69 // Wait 500ms more to catch additionnal unexpected reports. 70 await receivedEveryReports; 71 await new Promise(r => step_timeout(r, 500)); 72 return reports; 73 } 74 75 function desc(headers) { 76 return headers === '' ? '(none)' : headers; 77 } 78 79 // CASES is a list of test case. Each test case consists of: 80 // parent_headers: the suffix of the URL of the parent frame. 81 // target_headers: the suffix of the URL of the target frame. 82 // expected_reports: one of: 83 // 'CORP': CORP violation 84 // 'CORP-RO': CORP violation (report only) 85 // 'NAV': COEP mismatch between the frames. 86 // 'NAV-RO': COEP mismatch between the frames (report only). 87 const reportingTest = function( 88 parent_headers, target_headers, expected_reports) { 89 // These tests are very slow, so they must be run in parallel using 90 // async_test. 91 promise_test_parallel(async t => { 92 const targetUrl = REMOTE_FRAME_URL + target_headers; 93 const parent = await loadFrames(t, parent_headers, targetUrl); 94 const contextUrl = parent.src ? parent.src : 'about:blank'; 95 const reports = await observeReports( 96 parent.contentWindow, 97 expected_reports.length 98 ); 99 assert_equals(reports.length, expected_reports.length); 100 for (let i = 0; i < reports.length; i += 1) { 101 const report = reports[i]; 102 switch (expected_reports[i]) { 103 case 'CORP': 104 checkCorpReport(report, contextUrl, targetUrl, 'enforce'); 105 break; 106 case 'CORP-RO': 107 checkCorpReport(report, contextUrl, targetUrl, 'reporting'); 108 break; 109 case 'NAV': 110 checkCoepMismatchReport(report, contextUrl, targetUrl, 'enforce'); 111 break; 112 case 'NAV-RO': 113 checkCoepMismatchReport(report, contextUrl, targetUrl, 'reporting'); 114 break; 115 default: 116 assert_unreached( 117 'Unexpected report exception: ' + expected_reports[i]); 118 } 119 } 120 }, `parent: ${desc(parent_headers)}, target: ${desc(target_headers)}, `); 121 } 122 123 reportingTest('', '', []); 124 reportingTest('', COEP, []); 125 reportingTest(COEP, COEP, ['CORP']); 126 reportingTest(COEP, '', ['CORP']); 127 128 reportingTest('', CORP_CROSS_ORIGIN, []); 129 reportingTest(COEP, CORP_CROSS_ORIGIN, ['NAV']); 130 131 reportingTest('', COEP + CORP_CROSS_ORIGIN, []); 132 reportingTest(COEP, COEP + CORP_CROSS_ORIGIN, []); 133 134 reportingTest(COEP_RO, COEP, ['CORP-RO']); 135 reportingTest(COEP_RO, '', ['CORP-RO', 'NAV-RO']); 136 reportingTest(COEP_RO, CORP_CROSS_ORIGIN, ['NAV-RO']); 137 reportingTest(COEP_RO, COEP + CORP_CROSS_ORIGIN, []); 138 139 reportingTest(COEP, COEP_RO + CORP_CROSS_ORIGIN, ['NAV']);