<!--
  Any copyright is dedicated to the Public Domain.
  http://creativecommons.org/publicdomain/zero/1.0/
-->
<!DOCTYPE HTML>
<html>
<!--
https://bugzilla.mozilla.org/show_bug.cgi?id=965727
-->
<head>
  <meta charset="utf-8">
  <title>Test for Content Security Policy referrer Directive (Bug 965727)</title>
  <script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
  <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
</head>
<body>
<div id="content" style="display: none">

</div>
<pre id="test">
<script class="testbody" type="application/javascript">
/*
 * This tests various referrer policies and the referrer-sending behavior when
 * requesting scripts in different ways:
 *  - cross-origin (https://example.com -> https://test2.example.com)
 *  - same-origin (https://example.com -> https://example.com)
 *  - downgrade (https://example.com -> http://example.com)
 *
 * Each test creates an iframe that loads scripts for each of the checks.  If
 * the scripts are blocked, the test fails (they should run).  When loaded,
 * each script updates a results object in the test page, and then when the
 * test page has finished loading all the scripts, it postMessages back to this
 * page.  Once all tests are done, the results are checked.
 */

var testData = {
  'default': { 'csp': "script-src * 'unsafe-inline'; referrer default",
          'expected': {  'sameorigin': 'full',
                        'crossorigin': 'full',
                          'downgrade': 'none' }},

  'origin':  { 'csp': "script-src * 'unsafe-inline'; referrer origin",
          'expected': {  'sameorigin': 'origin',
                        'crossorigin': 'origin',
                          'downgrade': 'origin' }},

  'origin-when-cross-origin':  { 'csp': "script-src * 'unsafe-inline'; referrer origin-when-cross-origin",
          'expected': {  'sameorigin': 'full',
                        'crossorigin': 'origin',
                          'downgrade': 'origin' }},

  'unsafe-url':  { 'csp': "script-src * 'unsafe-inline'; referrer unsafe-url",
          'expected': {  'sameorigin': 'full',
                        'crossorigin': 'full',
                          'downgrade': 'full' }},

  'none':   { 'csp': "script-src * 'unsafe-inline'; referrer no-referrer",
          'expected': {  'sameorigin': 'none',
                        'crossorigin': 'none',
                          'downgrade': 'none' }},

  // referrer delivered through CSPRO should be ignored
  'ignore-cspro':  { 'cspro': "script-src * 'unsafe-inline'; referrer origin",
          'expected': {  'sameorigin': 'full',
                        'crossorigin': 'full',
                          'downgrade': 'none' }},

  // referrer delivered through CSPRO should be ignored
  'ignore-cspro2':   { 'csp'  : "script-src * 'unsafe-inline'; referrer no-referrer",
                       'cspro': "script-src * 'unsafe-inline'; referrer origin",
         'expected': {  'sameorigin': 'none',
                        'crossorigin': 'none',
                          'downgrade': 'none' }},
  };

var referrerDirectiveTests = {
  // called via postMessage when one of the iframes is done running.
  onIframeComplete: function(event) {
    try {
      var results = JSON.parse(event.data);
      ok(results.hasOwnProperty('id'), "'id' property required in posted message " + event.data);

      ok(testData.hasOwnProperty(results['id']), "Test " + results['id'] + " must be expected.");

      // check all the various load types' referrers.
      var expected = testData[results['id']].expected;
      for (var t in expected) {
        is(results.results[t], expected[t],
          " referrer must match expected for " + t + " in " + results['id']);
      }
      testData[results['id']]['complete'] = true;

    } catch(e) {
      // fail -- should always be JSON
      ok(false, "failed to parse posted message + " + event.data);
      // have to end as well since not all messages were valid.
      SimpleTest.finish();
    }

    referrerDirectiveTests.checkForCompletion();
  },

  // checks to see if all the parallel tests are done and validates results.
  checkForCompletion: function() {
    for (var id in testData) {
      if (!testData[id].hasOwnProperty('complete')) {
        return;
      }
    }
    SimpleTest.finish();
  }
};

SimpleTest.waitForExplicitFinish();
// have to disable mixed content blocking to test https->http referrers.
SpecialPowers.pushPrefEnv({
    'set': [['security.mixed_content.block_active_content',   false],
            ['security.mixed_content.block_display_content',  false],
            ['security.mixed_content.send_hsts_priming',  false],
            ['security.mixed_content.use_hsts',  false],
    ]
    },
    function() {
      // each of the iframes we create will call us back when its contents are loaded.
      window.addEventListener("message", referrerDirectiveTests.onIframeComplete.bind(window), false);

      // one iframe created for each test case
      for (var id in testData) {
        var elt = document.createElement("iframe");
        var src = "https://example.com/tests/dom/security/test/csp/file_testserver.sjs?id=" + id;
        if (testData[id]['csp']) {
          src += "&csp=" + escape(testData[id]['csp']);
        }
        if (testData[id]['cspro']) {
          src += "&cspro=" + escape(testData[id]['cspro']);
        }
        src += "&file=tests/dom/security/test/csp/file_referrerdirective.html";
        elt.src = src;
        document.getElementById("content").appendChild(elt);
      }
    });
</script>
</pre>
</body>
</html>