<!DOCTYPE HTML>
<html>
<head>
  <title>Bug 1529068 Implement CSP 'navigate-to' directive</title>
  <!-- Including SimpleTest.js so we can use waitForExplicitFinish !-->
  <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">
    <iframe style="width:100%;" id="testframe"></iframe>
  </div>

<script class="testbody" type="text/javascript">

/*
 * Description of the test:
 *   We load a page with a given CSP and verify that navigations are correctly
 *   evaluated through the "navigate-to" directive.
 */
SpecialPowers.pushPrefEnv({"set": [["security.csp.enableNavigateTo", true]]});
SimpleTest.waitForExplicitFinish();

// Note: The final website for the navigation chain must always be: www.example.com
var tests = [
  {
    result : "blocked",
    policy : "navigate-to www.mozilla.com",
    target : "http://www.example.com/"
  },
  {
    result : "allowed",
    policy : "navigate-to www.example.com",
    target : "http://www.example.com/"
  },
  {
    // Test path-sensitivity 
    result : "blocked",
    policy : "navigate-to http://www.example.com/full/path/to/file",
    target : "http://www.example.com/"
  },
  {
    // Test scheme
    result : "blocked",
    policy : "navigate-to https://www.example.com/",
    target : "http://www.example.com/"
  },
  {
    // Redirect from tracking.example.com to www.example.com
    result : "blocked",
    policy : "navigate-to www.example.com",
    target : "http://tracking.example.com/tests/dom/security/test/csp/file_navigate_to.sjs?redir=http://www.example.com/"
  },
  {
  // Redirect from tracking.example.com to www.example.com (Explicitly allowed)
    result : "allowed",
    policy : "navigate-to tracking.example.com www.example.com",
    target : "http://tracking.example.com/tests/dom/security/test/csp/file_navigate_to.sjs?redir=http://www.example.com/"
  },
  {
  // Redirect from tracking.example.com to www.example.com ('unsafe-allow-redirects')
    result : "allowed",
    policy : "navigate-to 'unsafe-allow-redirects' www.example.com",
    target : "http://tracking.example.com/tests/dom/security/test/csp/file_navigate_to.sjs?redir=http://www.example.com/"
  },
  // No path-sensitivity after redirect
  {
    result : "allowed",
    policy : "navigate-to tracking.example.com http://www.example.com/full/path/to/file",
    target : "http://tracking.example.com/tests/dom/security/test/csp/file_navigate_to.sjs?redir=http://www.example.com/"
  },
  // Multiple CSP directives, first block (origin) second allow
  {
    result : "allowed",
    policy : "img-src 'none'; navigate-to www.example.com",
    target : "http://www.example.com/"
  },
  // Multiple CSP directives, first allow (origin) second block
  {
    result : "blocked",
    policy : "img-src www.example.com mochi.test:8888; navigate-to www.mozilla.com",
    target : "http://www.example.com/"
  },
  // Multiple CSPs, first allow second block
  {
    result  : "blocked",
    policy  : "navigate-to www.example.com",
    policy2 : "navigate-to www.mozilla.com",
    target  : "http://www.example.com/"
  },
  // Multiple CSPs, first block second allow
  {
    result  : "blocked",
    policy  : "navigate-to www.mozilla.com",
    policy2 : "navigate-to www.example.com",
    target  : "http://www.example.com/"
  },
];

// initializing to -1 so we start at index 0 when we start the test
var counter = -1;

function checkResult(aResult) {
  is(aResult, tests[counter].result, "should be " + tests[counter].result + " in test " + counter + 
    "(" + tests[counter].policy + ", " + tests[counter].target + ")!");
  loadNextTest();
}

// We use the examiner to identify requests that hit the wire and requests
// that are blocked by CSP and bubble up the result to the including iframe
// document (parent).
function examiner() {
  SpecialPowers.addObserver(this, "csp-on-violate-policy");
}
examiner.prototype  = {
  observe(subject, topic, data) {
    if (topic === "csp-on-violate-policy" && data === "navigate-to") {
      checkResult("blocked");
    }

  },
  remove() {
    SpecialPowers.removeObserver(this, "csp-on-violate-policy");
  }
}
window.NavigationActionExaminer = new examiner();
// We use iframe onload to check if requests are not blocked by CSP
var iframe = document.getElementById("testframe");
iframe.onload = function() {
  checkResult("allowed");
}

function loadNextTest() {
  counter++;
  if (counter == tests.length) {
    window.NavigationActionExaminer.remove();
    SimpleTest.finish();
    return;
  }

  var src = "file_navigate_to.sjs";
  // append the CSP that should be used to serve the file
  src += "?csp=" + escape(tests[counter].policy);
  if( tests[counter].policy2 ) {
     src += "&csp2=" + escape(tests[counter].policy2);
  }
  src += "&target=" + escape(tests[counter].target);

  iframe.src = src;
}

// start running the tests
loadNextTest();

</script>
</body>
</html>
