diff options
Diffstat (limited to 'dom/security/test/csp/test_bug836922_npolicies.html')
-rw-r--r-- | dom/security/test/csp/test_bug836922_npolicies.html | 235 |
1 files changed, 235 insertions, 0 deletions
diff --git a/dom/security/test/csp/test_bug836922_npolicies.html b/dom/security/test/csp/test_bug836922_npolicies.html new file mode 100644 index 0000000000..e418969e3d --- /dev/null +++ b/dom/security/test/csp/test_bug836922_npolicies.html @@ -0,0 +1,235 @@ +<!DOCTYPE HTML> +<html> +<head> + <title>Test for Content Security Policy multiple policy support (regular and Report-Only mode)</title> + <script src="/tests/SimpleTest/SimpleTest.js"></script> + <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" /> +</head> +<body> +<p id="display"></p> +<div id="content" style="display: none"> +</div> + +<iframe style="width:200px;height:200px;" id='cspframe'></iframe> +<script class="testbody" type="text/javascript"> + +var path = "/tests/dom/security/test/csp/"; + +// These are test results: verified indicates whether or not the test has run. +// true/false is the pass/fail result. +window.loads = { + css_self: {expected: true, verified: false}, + img_self: {expected: false, verified: false}, + script_self: {expected: true, verified: false}, +}; + +window.violation_reports = { + css_self: + {expected: 0, expected_ro: 0}, /* totally fine */ + img_self: + {expected: 1, expected_ro: 0}, /* violates enforced CSP */ + script_self: + {expected: 0, expected_ro: 1}, /* violates report-only */ +}; + +// This is used to watch the blocked data bounce off CSP and allowed data +// get sent out to the wire. This also watches for violation reports to go out. +function examiner() { + SpecialPowers.addObserver(this, "csp-on-violate-policy"); + SpecialPowers.addObserver(this, "specialpowers-http-notify-request"); +} +examiner.prototype = { + observe(subject, topic, data) { + var testpat = new RegExp("testid=([a-z0-9_]+)"); + + if (topic === "specialpowers-http-notify-request") { + var uri = data; + if (!testpat.test(uri)) return; + var testid = testpat.exec(uri)[1]; + + // violation reports don't come through here, but the requested resources do + // if the test has already finished, move on. Some things throw multiple + // requests (preloads and such) + try { + if (window.loads[testid].verified) return; + } catch(e) { return; } + + // these are requests that were allowed by CSP + var testid = testpat.exec(uri)[1]; + window.testResult(testid, 'allowed', uri + " allowed by csp"); + } + + if(topic === "csp-on-violate-policy") { + // if the violated policy was report-only, the resource will still be + // loaded even if this topic is notified. + var asciiSpec = SpecialPowers.getPrivilegedProps( + SpecialPowers.do_QueryInterface(subject, "nsIURI"), + "asciiSpec"); + if (!testpat.test(asciiSpec)) return; + var testid = testpat.exec(asciiSpec)[1]; + + // if the test has already finished, move on. + try { + if (window.loads[testid].verified) return; + } catch(e) { return; } + + // record the ones that were supposed to be blocked, but don't use this + // as an indicator for tests that are not blocked but do generate reports. + // We skip recording the result if the load is expected since a + // report-only policy will generate a request *and* a violation note. + if (!window.loads[testid].expected) { + window.testResult(testid, + 'blocked', + asciiSpec + " blocked by \"" + data + "\""); + } + } + + // if any test is unverified, keep waiting + for (var v in window.loads) { + if(!window.loads[v].verified) { + return; + } + } + + window.bug836922examiner.remove(); + window.resultPoller.pollForFinish(); + }, + + // must eventually call this to remove the listener, + // or mochitests might get borked. + remove() { + SpecialPowers.removeObserver(this, "csp-on-violate-policy"); + SpecialPowers.removeObserver(this, "specialpowers-http-notify-request"); + } +} +window.bug836922examiner = new examiner(); + + +// Poll for results and see if enough reports came in. Keep trying +// for a few seconds before failing with lack of reports. +// Have to do this because there's a race between the async reporting +// and this test finishing, and we don't want to win the race. +window.resultPoller = { + + POLL_ATTEMPTS_LEFT: 14, + + pollForFinish() { + var vr = resultPoller.tallyReceivedReports(); + if (resultPoller.verifyReports(vr, resultPoller.POLL_ATTEMPTS_LEFT < 1)) { + // report success condition. + resultPoller.resetReportServer(); + SimpleTest.finish(); + } else { + resultPoller.POLL_ATTEMPTS_LEFT--; + // try again unless we reached the threshold. + setTimeout(resultPoller.pollForFinish, 100); + } + }, + + resetReportServer() { + var xhr = new XMLHttpRequest(); + var xhr_ro = new XMLHttpRequest(); + xhr.open("GET", "file_bug836922_npolicies_violation.sjs?reset", false); + xhr_ro.open("GET", "file_bug836922_npolicies_ro_violation.sjs?reset", false); + xhr.send(null); + xhr_ro.send(null); + }, + + tallyReceivedReports() { + var xhr = new XMLHttpRequest(); + var xhr_ro = new XMLHttpRequest(); + xhr.open("GET", "file_bug836922_npolicies_violation.sjs?results", false); + xhr_ro.open("GET", "file_bug836922_npolicies_ro_violation.sjs?results", false); + xhr.send(null); + xhr_ro.send(null); + + var received = JSON.parse(xhr.responseText); + var received_ro = JSON.parse(xhr_ro.responseText); + + var results = {enforced: {}, reportonly: {}}; + for (var r in window.violation_reports) { + results.enforced[r] = 0; + results.reportonly[r] = 0; + } + + for (var r in received) { + results.enforced[r] += received[r]; + } + for (var r in received_ro) { + results.reportonly[r] += received_ro[r]; + } + + return results; + }, + + verifyReports(receivedCounts, lastAttempt) { + for (var r in window.violation_reports) { + var exp = window.violation_reports[r].expected; + var exp_ro = window.violation_reports[r].expected_ro; + var rec = receivedCounts.enforced[r]; + var rec_ro = receivedCounts.reportonly[r]; + + // if this test breaks, these are helpful dumps: + //dump(">>> Verifying " + r + "\n"); + //dump(" > Expected: " + exp + " / " + exp_ro + " (ro)\n"); + //dump(" > Received: " + rec + " / " + rec_ro + " (ro) \n"); + + // in all cases, we're looking for *at least* the expected number of + // reports of each type (there could be more in some edge cases). + // If there are not enough, we keep waiting and poll the server again + // later. If there are enough, we can successfully finish. + + if (exp == 0) + is(rec, 0, + "Expected zero enforced-policy violation " + + "reports for " + r + ", got " + rec); + else if (lastAttempt) + ok(rec >= exp, + "Received (" + rec + "/" + exp + ") " + + "enforced-policy reports for " + r); + else if (rec < exp) + return false; // continue waiting for more + + if(exp_ro == 0) + is(rec_ro, 0, + "Expected zero report-only-policy violation " + + "reports for " + r + ", got " + rec_ro); + else if (lastAttempt) + ok(rec_ro >= exp_ro, + "Received (" + rec_ro + "/" + exp_ro + ") " + + "report-only-policy reports for " + r); + else if (rec_ro < exp_ro) + return false; // continue waiting for more + } + + // if we complete the loop, we've found all of the violation + // reports we expect. + if (lastAttempt) return true; + + // Repeat successful tests once more to record successes via ok() + return resultPoller.verifyReports(receivedCounts, true); + } +}; + +window.testResult = function(testname, result, msg) { + // otherwise, make sure the allowed ones are expected and blocked ones are not. + if (window.loads[testname].expected) { + is(result, 'allowed', ">> " + msg); + } else { + is(result, 'blocked', ">> " + msg); + } + window.loads[testname].verified = true; +} + + +SimpleTest.waitForExplicitFinish(); +SimpleTest.requestFlakyTimeout("untriaged"); + +// save this for last so that our listeners are registered. +// ... this loads the testbed of good and bad requests. +document.getElementById('cspframe').src = 'http://mochi.test:8888' + path + 'file_bug836922_npolicies.html'; + +</script> +</pre> +</body> +</html> |