Bug 1045891 - Tests for child-src r=ckerschb
authorKate McKinley <kmckinley@mozilla.com>
Mon, 09 Nov 2015 16:42:26 +0900
changeset 306080 459d282e48abec62d6fdbc23dbe48e98abe12eff
parent 306079 4ca475a0254a7b2b50800bdf65a0729b45d0e071
child 306081 a735ff65e2397783697ff1eee31f85e069840e6d
push idunknown
push userunknown
push dateunknown
reviewersckerschb
bugs1045891
milestone45.0a1
Bug 1045891 - Tests for child-src r=ckerschb
dom/security/test/csp/file_child-src_iframe.html
dom/security/test/csp/file_child-src_inner_frame.html
dom/security/test/csp/file_child-src_service_worker.html
dom/security/test/csp/file_child-src_service_worker.js
dom/security/test/csp/file_child-src_shared_worker-redirect.html
dom/security/test/csp/file_child-src_shared_worker.html
dom/security/test/csp/file_child-src_shared_worker.js
dom/security/test/csp/file_child-src_shared_worker_data.html
dom/security/test/csp/file_child-src_worker-redirect.html
dom/security/test/csp/file_child-src_worker.html
dom/security/test/csp/file_child-src_worker.js
dom/security/test/csp/file_child-src_worker_data.html
dom/security/test/csp/file_redirect_worker.sjs
dom/security/test/csp/file_redirects_page.sjs
dom/security/test/csp/file_redirects_resource.sjs
dom/security/test/csp/mochitest.ini
dom/security/test/csp/test_child-src_iframe.html
dom/security/test/csp/test_child-src_worker-redirect.html
dom/security/test/csp/test_child-src_worker.html
dom/security/test/csp/test_child-src_worker_data.html
dom/security/test/csp/test_service_worker.html
dom/security/test/csp/test_worker_redirect.html
new file mode 100644
--- /dev/null
+++ b/dom/security/test/csp/file_child-src_iframe.html
@@ -0,0 +1,61 @@
+<!DOCTYPE HTML>
+<html>
+  <head>
+    <title>Bug 1045891</title>
+  </head>
+  <body>
+    <iframe id="testframe"> </iframe>
+  <script type="text/javascript">
+    page_id = window.location.hash.substring(1);
+
+    function executeTest(ev) {
+      testframe = document.getElementById('testframe');
+      testframe.contentWindow.postMessage({id:page_id, message:"execute"}, 'http://mochi.test:8888');
+    }
+
+    function reportError(ev) {
+      window.parent.postMessage({id:page_id, message:"blocked"}, 'http://mochi.test:8888');
+      cleanup();
+    }
+
+    function recvMessage(ev) {
+      if (ev.data.id == page_id) {
+        window.parent.postMessage({id:ev.data.id, message:ev.data.message}, 'http://mochi.test:8888');
+        cleanup();
+      }
+    }
+
+    function cleanup() {
+      testframe = document.getElementById('testframe');
+      window.removeEventListener('message', recvMessage);
+      testframe.removeEventListener('load', executeTest);
+      testframe.removeEventListener('error', reportError);
+    }
+
+
+    window.addEventListener('message', recvMessage, false);
+
+    try {
+      // Please note that file_testserver.sjs?foo does not return a response.
+      // For testing purposes this is not necessary because we only want to check
+      // whether CSP allows or blocks the load.
+      src = "file_testserver.sjs";
+      src += "?file=" + escape("tests/dom/security/test/csp/file_child-src_inner_frame.html");
+      src += "#" + escape(page_id);
+      testframe = document.getElementById('testframe');
+
+      testframe.addEventListener('load', executeTest, false);
+      testframe.addEventListener('error', reportError, false);
+
+      testframe.src = src;
+    }
+    catch (e) {
+      if (e.message.match(/Failed to load script/)) {
+        window.parent.postMessage({id:page_id, message:"blocked"}, 'http://mochi.test:8888');
+      } else {
+        window.parent.postMessage({id:page_id, message:"exception"}, 'http://mochi.test:8888');
+      }
+    }
+  </script>
+  </body>
+</html>
new file mode 100644
--- /dev/null
+++ b/dom/security/test/csp/file_child-src_inner_frame.html
@@ -0,0 +1,21 @@
+<!DOCTYPE HTML>
+<html>
+  <head>
+    <title>Bug 1045891</title>
+  </head>
+  <body>
+    <iframe id="innermosttestframe"> </iframe>
+  <script type="text/javascript">
+    page_id = window.location.hash.substring(1);
+
+    function recvMessage(ev) {
+      if (ev.data.id == page_id) {
+        window.parent.postMessage({id:ev.data.id, message:'allowed'}, 'http://mochi.test:8888');
+        window.removeEventListener('message', recvMessage);
+      }
+    }
+
+    window.addEventListener('message', recvMessage, false);
+  </script>
+  </body>
+</html>
new file mode 100644
--- /dev/null
+++ b/dom/security/test/csp/file_child-src_service_worker.html
@@ -0,0 +1,29 @@
+<!DOCTYPE HTML>
+<html>
+  <head>
+    <title>Bug 1045891</title>
+  </head>
+  <body>
+  <script type="text/javascript">
+    page_id = window.location.hash.substring(1);
+    try {
+      if ('serviceWorker' in navigator) {
+        navigator.serviceWorker.register(
+            'file_child-src_service_worker.js'
+            + "#"
+            + page_id
+            ).then(function(reg)
+              {
+                // registration worked
+                window.parent.postMessage({id:page_id, message:"allowed"}, 'http://mochi.test:8888');
+              }).catch(function(error) {
+              // registration failed
+              window.parent.postMessage({id:page_id, message:"blocked"}, 'http://mochi.test:8888');
+            });
+      };
+    } catch(ex) {
+      window.parent.postMessage({id:page_id, message:"exception"}, 'http://mochi.test:8888');
+    }
+  </script>
+  </body>
+</html>
new file mode 100644
--- /dev/null
+++ b/dom/security/test/csp/file_child-src_service_worker.js
@@ -0,0 +1,3 @@
+this.addEventListener('install', function(event) {
+  close();
+});
new file mode 100644
--- /dev/null
+++ b/dom/security/test/csp/file_child-src_shared_worker-redirect.html
@@ -0,0 +1,41 @@
+<!DOCTYPE HTML>
+<html>
+  <head>
+    <title>Bug 1045891</title>
+  </head>
+  <body>
+  <script type="text/javascript">
+    page_id = window.location.hash.substring(1);
+    var redir = 'none';
+
+    page_id.split('_').forEach(function (val) {
+      var [name, value] = val.split('-');
+      if (name  == 'redir') {
+        redir = unescape(value);
+      }
+    });
+
+    try {
+      worker = new SharedWorker('file_redirect_worker.sjs?path='
+          + escape("/tests/dom/security/test/csp/file_child-src_shared_worker.js")
+          + "&redir=" + redir
+          + "&page_id=" + page_id,
+          page_id);
+      worker.port.start();
+
+      worker.port.onmessage = function(ev) {
+        window.parent.postMessage({id:page_id, message:"allowed"}, 'http://mochi.test:8888');
+      };
+
+      worker.onerror = function() {
+        window.parent.postMessage({id:page_id, message:"blocked"}, 'http://mochi.test:8888');
+      };
+
+      worker.port.postMessage('foo');
+    }
+    catch (e) {
+      window.parent.postMessage({id:page_id, message:"blocked"}, 'http://mochi.test:8888');
+    }
+  </script>
+  </body>
+</html>
new file mode 100644
--- /dev/null
+++ b/dom/security/test/csp/file_child-src_shared_worker.html
@@ -0,0 +1,28 @@
+<!DOCTYPE HTML>
+<html>
+  <head>
+    <title>Bug 1045891</title>
+  </head>
+  <body>
+  <script type="text/javascript">
+    page_id = window.location.hash.substring(1);
+    try {
+      worker = new SharedWorker(
+          'file_testserver.sjs?file='+
+                escape("tests/dom/security/test/csp/file_child-src_shared_worker.js"),
+          page_id);
+      worker.port.start();
+
+      worker.port.onmessage = function(ev) {
+        window.parent.postMessage({id:page_id, message:"allowed"},
+            'http://mochi.test:8888');
+      };
+      worker.port.postMessage('foo');
+    }
+    catch (e) {
+      window.parent.postMessage({id:page_id, message:"blocked"},
+          'http://mochi.test:8888');
+    }
+  </script>
+  </body>
+</html>
new file mode 100644
--- /dev/null
+++ b/dom/security/test/csp/file_child-src_shared_worker.js
@@ -0,0 +1,8 @@
+onconnect = function(e) {
+  var port = e.ports[0];
+  port.addEventListener('message', function(e) {
+    port.postMessage('success');
+  });
+
+  port.start();
+}
new file mode 100644
--- /dev/null
+++ b/dom/security/test/csp/file_child-src_shared_worker_data.html
@@ -0,0 +1,32 @@
+
+<!DOCTYPE HTML>
+<html>
+  <head>
+    <title>Bug 1045891</title>
+  </head>
+  <body>
+  <script type="text/javascript">
+    var page_id = window.location.hash.substring(1);
+    var shared_worker = "onconnect = function(e) { " +
+                        "var port = e.ports[0];" +
+                        "port.addEventListener('message'," +
+                        "function(e) { port.postMessage('success'); });" +
+                        "port.start(); }";
+    
+    try {
+      var worker = new SharedWorker('data:application/javascript;charset=UTF-8,'+
+          escape(shared_worker), page_id);
+      worker.port.start();
+
+      worker.port.onmessage = function(ev) {
+        window.parent.postMessage({id:page_id, message:"allowed"}, 'http://mochi.test:8888');
+      };
+      
+      worker.port.postMessage('foo');
+    }
+    catch (e) {
+      window.parent.postMessage({id:page_id, message:"blocked"}, 'http://mochi.test:8888');
+    }
+  </script>
+  </body>
+</html>
new file mode 100644
--- /dev/null
+++ b/dom/security/test/csp/file_child-src_worker-redirect.html
@@ -0,0 +1,49 @@
+<!DOCTYPE HTML>
+<html>
+  <head>
+    <title>Bug 1045891</title>
+  </head>
+  <body>
+  <script type="text/javascript">
+    var page_id = window.location.hash.substring(1);
+    var redir = 'none';
+
+    page_id.split('_').forEach(function (val) {
+      var [name, value] = val.split('-');
+      if (name  == 'redir') {
+        redir = unescape(value);
+      }
+    });
+
+    try {
+      worker = new Worker('file_redirect_worker.sjs?path='
+          + escape("/tests/dom/security/test/csp/file_child-src_worker.js")
+          + "&redir=" + redir
+          + "&page_id=" + page_id
+          );
+
+      worker.onerror = function(error) {
+        var msg = error.message;
+        if (msg.match(/^: NetworkError/)) {
+          // this means CSP blocked it
+          msg = "blocked";
+        }
+        window.parent.postMessage({id:page_id, message:msg}, 'http://mochi.test:8888');
+      };
+
+      worker.onmessage = function(ev) {
+        window.parent.postMessage({id:page_id, message:"allowed"}, 'http://mochi.test:8888');
+
+      };
+      worker.postMessage('foo');
+    }
+    catch (e) {
+      if (e.message.match(/Failed to load script/)) {
+        window.parent.postMessage({id:page_id, message:"blocked"}, 'http://mochi.test:8888');
+      } else {
+        window.parent.postMessage({id:page_id, message:"exception"}, 'http://mochi.test:8888');
+      }
+    }
+  </script>
+  </body>
+</html>
new file mode 100644
--- /dev/null
+++ b/dom/security/test/csp/file_child-src_worker.html
@@ -0,0 +1,25 @@
+<!DOCTYPE HTML>
+<html>
+  <head>
+    <title>Bug 1045891</title>
+  </head>
+  <body>
+  <script type="text/javascript">
+    page_id = window.location.hash.substring(1);
+    try {
+      worker = new Worker('file_testserver.sjs?file='+escape("tests/dom/security/test/csp/file_child-src_worker.js"));
+      worker.onmessage = function(ev) {
+        window.parent.postMessage({id:page_id, message:"allowed"}, 'http://mochi.test:8888');
+      };
+      worker.postMessage('foo');
+    }
+    catch (e) {
+      if (e.message.match(/Failed to load script/)) {
+        window.parent.postMessage({id:page_id, message:"blocked"}, 'http://mochi.test:8888');
+      } else {
+        window.parent.postMessage({id:page_id, message:"exception"}, 'http://mochi.test:8888');
+      }
+    }
+  </script>
+  </body>
+</html>
new file mode 100644
--- /dev/null
+++ b/dom/security/test/csp/file_child-src_worker.js
@@ -0,0 +1,4 @@
+onmessage = function(e) {
+  postMessage('worker');
+};
+
new file mode 100644
--- /dev/null
+++ b/dom/security/test/csp/file_child-src_worker_data.html
@@ -0,0 +1,26 @@
+<!DOCTYPE HTML>
+<html>
+  <head>
+    <title>Bug 1045891</title>
+  </head>
+  <body>
+  <script type="text/javascript">
+    page_id = window.location.hash.substring(1);
+    try {
+      worker = new Worker('data:application/javascript;charset=UTF-8,'+escape('onmessage = function(e) { postMessage("worker"); };'));
+      worker.onmessage = function(ev) {
+        window.parent.postMessage({id:page_id, message:"allowed"}, 'http://mochi.test:8888');
+      };
+      worker.postMessage('foo');
+    }
+    catch (e) {
+      if (e.message.match(/Failed to load script/)) {
+        window.parent.postMessage({id:page_id, message:"blocked"}, 'http://mochi.test:8888');
+      } else {
+        console.log(e);
+        window.parent.postMessage({id:page_id, message:"exception"}, 'http://mochi.test:8888');
+      }
+    }
+  </script>
+  </body>
+</html>
new file mode 100644
--- /dev/null
+++ b/dom/security/test/csp/file_redirect_worker.sjs
@@ -0,0 +1,34 @@
+// SJS file to serve resources for CSP redirect tests
+// This file redirects to a specified resource.
+const THIS_SITE = "http://mochi.test:8888";
+const OTHER_SITE = "http://example.com";
+
+function handleRequest(request, response)
+{
+  var query = {};
+  request.queryString.split('&').forEach(function (val) {
+    var [name, value] = val.split('=');
+    query[name] = unescape(value);
+  });
+
+  var resource = query['path'];
+
+  response.setHeader("Cache-Control", "no-cache", false);
+  var loc = '';
+
+  // redirect to a resource on this site
+  if (query["redir"] == "same") {
+    loc = THIS_SITE+resource+"#"+query['page_id']
+  }
+
+  // redirect to a resource on a different site
+  else if (query["redir"] == "other") {
+    loc = OTHER_SITE+resource+"#"+query['page_id']
+  }
+
+  response.setStatusLine("1.1", 302, "Found");
+  response.setHeader("Location", loc, false);
+
+  response.write('<html><head><meta http-equiv="refresh" content="0; url='+loc+'">');
+  return;
+}
--- a/dom/security/test/csp/file_redirects_page.sjs
+++ b/dom/security/test/csp/file_redirects_page.sjs
@@ -10,17 +10,23 @@ function handleRequest(request, response
 
   response.setHeader("Cache-Control", "no-cache", false);
   response.setHeader("Content-Type", "text/html", false);
 
   var resource = "/tests/dom/security/test/csp/file_redirects_resource.sjs";
 
   // CSP header value
   if (query["csp"] == 1) {
-    response.setHeader("Content-Security-Policy", "default-src 'self' ; style-src 'self' 'unsafe-inline'", false);
+    var additional = ""
+    if (query['testid'] == "worker") {
+      additional = "; script-src 'self' 'unsafe-inline'";
+    }
+    response.setHeader("Content-Security-Policy",
+        "default-src 'self' ; style-src 'self' 'unsafe-inline'" + additional,
+        false);
   }
 
   // downloadable font that redirects to another site
   if (query["testid"] == "font-src") {
     var resp = '<style type="text/css"> @font-face { font-family:' +
                '"Redirecting Font"; src: url("' + resource +
                '?res=font&redir=other&id=font-src-redir")} #test{font-family:' +
                '"Redirecting Font"}</style></head><body>' +
@@ -56,23 +62,23 @@ function handleRequest(request, response
   // external script that redirects to another site
   if (query["testid"] == "script-src") {
     response.write('<script src="'+resource+'?res=script&redir=other&id=script-src-redir"></script>');
     return;
   }
 
   // external stylesheet that redirects to another site
   if (query["testid"] == "style-src") {
-    response.write('<link rel="stylesheet" type="text/css" href="'+resource+'?res=style&redir=other&id=style-src-redir"></script>');
+    response.write('<link rel="stylesheet" type="text/css" href="'+resource+'?res=style&redir=other&id=style-src-redir"></link>');
     return;
   }
 
   // worker script resource that redirects to another site
   if (query["testid"] == "worker") {
-    response.write('<script src="'+resource+'?res=worker&redir=other&id=worker-redir"></script>');
+    response.write('<script>var worker = new Worker("'+resource+'?res=worker&redir=other&id=worker-redir");</script>');
     return;
   }
 
   // script that XHR's to a resource that redirects to another site
   if (query["testid"] == "xhr-src") {
     response.write('<script src="'+resource+'?res=xhr"></script>');
     return;
   }
--- a/dom/security/test/csp/file_redirects_resource.sjs
+++ b/dom/security/test/csp/file_redirects_resource.sjs
@@ -117,28 +117,19 @@ function handleRequest(request, response
     let scriptURL = thisSite + resource + "?redir=other&res=script&id=" + query["id"];
     response.setHeader("Content-Type", "application/javascript", false);
     response.write("importScripts('" + scriptURL + "');");
     return;
   }
 
   // script that invokes XHR
   if (query["res"] == "xhr") {
-    response.setHeader("Content-Type", "text/html", false);
-    var resp = 'var x = new XMLHttpRequest(); x.open("GET", "' + otherSite +
-               resource+'?res=xhr-resp&testid=xhr-src-redir", false); ' +
-               'x.send(null);';
-    response.write(resp);
-    return;
-  }
-
-  if (query["res"] == "xhr") {
-    response.setHeader("Content-Type", "text/html", false);
-    var resp = 'var x = new XMLHttpRequest(); x.open("GET", "' + otherSite +
-               resource+'?res=xhr-resp&testid=xhr-src-redir", false); ' +
+    response.setHeader("Content-Type", "application/javascript", false);
+    var resp = 'var x = new XMLHttpRequest();x.open("GET", "' + otherSite +
+               resource+'?res=xhr-resp&testid=xhr-src-redir", false);\n' +
                'x.send(null);';
     response.write(resp);
     return;
   }
 
   // response to XHR
   if (query["res"] == "xhr-resp") {
     response.setHeader("Access-Control-Allow-Origin", "*", false);
--- a/dom/security/test/csp/mochitest.ini
+++ b/dom/security/test/csp/mochitest.ini
@@ -128,16 +128,29 @@ support-files =
   file_upgrade_insecure_referrer_server.sjs
   file_upgrade_insecure_cors.html
   file_upgrade_insecure_cors_server.sjs
   file_report_for_import.css
   file_report_for_import.html
   file_report_for_import_server.sjs
   file_service_worker.html
   file_service_worker.js
+  file_child-src_iframe.html
+  file_child-src_inner_frame.html
+  file_child-src_worker.html
+  file_child-src_worker_data.html
+  file_child-src_worker-redirect.html
+  file_child-src_worker.js
+  file_child-src_service_worker.html
+  file_child-src_service_worker.js
+  file_child-src_shared_worker.html
+  file_child-src_shared_worker_data.html
+  file_child-src_shared_worker-redirect.html
+  file_child-src_shared_worker.js
+  file_redirect_worker.sjs
 
 [test_base-uri.html]
 [test_blob_data_schemes.html]
 [test_connect-src.html]
 [test_CSP.html]
 [test_allow_https_schemes.html]
 skip-if = buildapp == 'b2g' #no ssl support
 [test_bug663567.html]
@@ -195,8 +208,13 @@ skip-if = buildapp == 'b2g' || toolkit =
 [test_upgrade_insecure_referrer.html]
 skip-if = buildapp == 'b2g' || toolkit == 'gonk' || toolkit == 'android'
 [test_upgrade_insecure_cors.html]
 skip-if = buildapp == 'b2g' || toolkit == 'gonk' || toolkit == 'android'
 [test_report_for_import.html]
 [test_blocked_uri_in_reports.html]
 [test_service_worker.html]
 skip-if = buildapp == 'b2g' #no ssl support
+[test_child-src_worker.html]
+skip-if = buildapp == 'b2g' #investigate in bug 1222904
+[test_child-src_worker_data.html]
+[test_child-src_worker-redirect.html]
+[test_child-src_iframe.html]
new file mode 100644
--- /dev/null
+++ b/dom/security/test/csp/test_child-src_iframe.html
@@ -0,0 +1,114 @@
+<!DOCTYPE HTML>
+<html>
+<head>
+  <title>Bug 1045891</title>
+  <!-- Including SimpleTest.js so we can use waitForExplicitFinish !-->
+  <script type="text/javascript" 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="visibility: hidden">
+  </div>
+
+<script class="testbody" type="text/javascript">
+
+/*
+ * Description of the test:
+ *   We load a page with a given CSP and verify that child frames and workers are correctly
+ *   evaluated through the "child-src" directive.
+ */
+
+SimpleTest.waitForExplicitFinish();
+
+var IFRAME_SRC="file_child-src_iframe.html"
+
+var tests = {
+  'same-src': {
+    id: "same-src",
+    file: IFRAME_SRC,
+    result : "allowed",
+    policy : "default-src 'none'; script-src 'unsafe-inline'; child-src http://mochi.test:8888"
+  },
+  'star-src': {
+    id: "star-src",
+    file: IFRAME_SRC,
+    result : "allowed",
+    policy : "default-src 'none'; script-src 'unsafe-inline'; child-src *"
+  },
+  'other-src': {
+    id: "other-src",
+    file: IFRAME_SRC,
+    result : "blocked",
+    policy : "default-src http://mochi.test:8888; script-src 'unsafe-inline'; child-src http://www.example.com"
+  },
+  'same-src-by-frame-src': {
+    id: "same-src-by-frame-src",
+    file: IFRAME_SRC,
+    result : "allowed",
+    policy : "default-src 'none'; script-src 'unsafe-inline'; child-src 'none'; frame-src http://mochi.test:8888"
+  },
+  'star-src-by-frame-src': {
+    id: "star-src-by-frame-src",
+    file: IFRAME_SRC,
+    result : "allowed",
+    policy : "default-src 'none'; script-src 'unsafe-inline'; child-src 'none'; frame-src *"
+  },
+  'other-src-by-frame-src': {
+    id: "other-src-by-frame-src",
+    file: IFRAME_SRC,
+    result : "blocked",
+    policy : "default-src 'none'; script-src 'unsafe-inline'; child-src http://mochi.test:8888; frame-src http://www.example.com"
+  },
+  'none-src-by-frame-src': {
+    id: "none-src-by-frame-src",
+    file: "file_child-src_iframe.html",
+    file: IFRAME_SRC,
+    result : "blocked",
+    policy : "default-src 'none'; script-src 'unsafe-inline'; child-src http://mochi.test:8888; frame-src 'none'"
+  }
+};
+
+finished = {};
+
+function checkFinished() {
+  if (Object.keys(finished).length == Object.keys(tests).length) {
+    window.removeEventListener('message', recvMessage);
+    SimpleTest.finish();
+  }
+}
+
+function recvMessage(ev) {
+  is(ev.data.message, tests[ev.data.id].result, "CSP child-src test " + ev.data.id);
+  finished[ev.data.id] = ev.data.message;
+
+  checkFinished();
+}
+
+window.addEventListener('message', recvMessage, false);
+
+function loadNextTest() {
+  for (item in tests) {
+    test = tests[item];
+    var src = "file_testserver.sjs";
+    // append the file that should be served
+    src += "?file=" + escape("tests/dom/security/test/csp/" + test.file);
+    // append the CSP that should be used to serve the file
+    src += "&csp=" + escape(test.policy);
+    // add our identifier
+    src += "#" + escape(test.id);
+
+    content = document.getElementById('content');
+    testframe = document.createElement("iframe");
+    testframe.setAttribute('id', test.id);
+    content.appendChild(testframe);
+    testframe.src = src;
+  }
+}
+
+// start running the tests
+loadNextTest();
+
+</script>
+</body>
+</html>
new file mode 100644
--- /dev/null
+++ b/dom/security/test/csp/test_child-src_worker-redirect.html
@@ -0,0 +1,125 @@
+<!DOCTYPE HTML>
+<html>
+  <head>
+    <title>Bug 1045891</title>
+    <!-- Including SimpleTest.js so we can use waitForExplicitFinish !-->
+    <script type="text/javascript" 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="visibility: hidden">
+    </div>
+
+    <script class="testbody" type="text/javascript">
+      /*
+       * Description of the test:
+       *   We load a page with a given CSP and verify that child frames and workers are correctly
+       *   evaluated through the "child-src" directive.
+       */
+
+      SimpleTest.waitForExplicitFinish();
+
+      var WORKER_REDIRECT_TEST_FILE = "file_child-src_worker-redirect.html";
+      var SHARED_WORKER_REDIRECT_TEST_FILE = "file_child-src_shared_worker-redirect.html";
+
+      var tests = {
+        'same-src-worker_redir-same': {
+          id: "same-src-worker_redir-same",
+          file: WORKER_REDIRECT_TEST_FILE,
+          result : "allowed",
+          redir: "same",
+          policy : "default-src 'none'; script-src 'self' 'unsafe-inline'; child-src http://mochi.test:8888"
+        },
+        'same-src-worker_redir-other': {
+          id: "same-src-worker_redir-other",
+          file: WORKER_REDIRECT_TEST_FILE,
+          result : "blocked",
+          redir: "other",
+          policy : "default-src 'none'; script-src 'self' 'unsafe-inline'; child-src http://mochi.test:8888"
+        },
+        'star-src-worker_redir-same': {
+          id: "star-src-worker_redir-same",
+          file: WORKER_REDIRECT_TEST_FILE,
+          redir: "same",
+          result : "allowed",
+          policy : "default-src 'none'; script-src 'self' 'unsafe-inline'; child-src *"
+        },
+        'other-src-worker_redir-same': {
+          id: "other-src-worker_redir-same",
+          file: WORKER_REDIRECT_TEST_FILE,
+          redir: "same",
+          result : "blocked",
+          policy : "default-src 'none'; script-src 'self' 'unsafe-inline'; child-src https://www.example.org"
+        },
+        /* shared workers */
+        'same-src-shared_worker_redir-same': {
+          id: "same-src-shared_worker_redir-same",
+          file: SHARED_WORKER_REDIRECT_TEST_FILE,
+          result : "allowed",
+          redir: "same",
+          policy : "default-src 'none'; script-src 'self' 'unsafe-inline'; child-src http://mochi.test:8888"
+        },
+        'same-src-shared_worker_redir-other': {
+          id: "same-src-shared_worker_redir-other",
+          file: SHARED_WORKER_REDIRECT_TEST_FILE,
+          result : "blocked",
+          redir: "other",
+          policy : "default-src 'none'; script-src 'self' 'unsafe-inline'; child-src http://mochi.test:8888"
+        },
+        'star-src-shared_worker_redir-same': {
+          id: "star-src-shared_worker_redir-same",
+          file: SHARED_WORKER_REDIRECT_TEST_FILE,
+          redir: "same",
+          result : "allowed",
+          policy : "default-src 'none'; script-src 'self' 'unsafe-inline'; child-src *"
+        },
+        'other-src-shared_worker_redir-same': {
+          id: "other-src-shared_worker_redir-same",
+          file: SHARED_WORKER_REDIRECT_TEST_FILE,
+          redir: "same",
+          result : "blocked",
+          policy : "default-src 'none'; script-src 'self' 'unsafe-inline'; child-src https://www.example.org"
+        },
+      };
+
+      finished = {};
+
+      function recvMessage(ev) {
+        is(ev.data.message, tests[ev.data.id].result, "CSP child-src worker test " + ev.data.id);
+        finished[ev.data.id] = ev.data.message;
+
+        if (Object.keys(finished).length == Object.keys(tests).length) {
+          window.removeEventListener('message', recvMessage);
+          SimpleTest.finish();
+        }
+      }
+
+      window.addEventListener('message', recvMessage, false);
+
+      function loadNextTest() {
+        for (item in tests) {
+          test = tests[item];
+          var src = "file_testserver.sjs";
+          // append the file that should be served
+          src += "?file=" + escape("tests/dom/security/test/csp/" + test.file);
+          // append the CSP that should be used to serve the file
+          src += "&csp=" + escape(test.policy);
+          // add whether redirect is to same or different
+          src += "&redir=" + escape(test.policy);
+          // add our identifier
+          src += "#" + escape(test.id);
+
+          content = document.getElementById('content');
+          testframe = document.createElement("iframe");
+          testframe.setAttribute('id', test.id);
+          content.appendChild(testframe);
+          testframe.src = src;
+        }
+      }
+
+      // start running the tests
+      loadNextTest();
+    </script>
+  </body>
+</html>
new file mode 100644
--- /dev/null
+++ b/dom/security/test/csp/test_child-src_worker.html
@@ -0,0 +1,131 @@
+<!DOCTYPE HTML>
+<html>
+  <head>
+    <title>Bug 1045891</title>
+    <!-- Including SimpleTest.js so we can use waitForExplicitFinish !-->
+    <script type="text/javascript" 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="visibility: hidden">
+    </div>
+
+    <script class="testbody" type="text/javascript">
+      /*
+       * Description of the test:
+       *   We load a page with a given CSP and verify that child frames and workers are correctly
+       *   evaluated through the "child-src" directive.
+       */
+
+      SimpleTest.waitForExplicitFinish();
+
+      var WORKER_TEST_FILE = "file_child-src_worker.html";
+      var SERVICE_WORKER_TEST_FILE = "file_child-src_service_worker.html";
+      var SHARED_WORKER_TEST_FILE = "file_child-src_shared_worker.html";
+
+      var tests = {
+        'same-src-worker': {
+          id: "same-src-worker",
+          file: WORKER_TEST_FILE,
+          result : "allowed",
+          policy : "default-src 'none'; script-src 'unsafe-inline'; child-src http://mochi.test:8888"
+        },
+        'same-src-service_worker': {
+          id: "same-src-service_worker",
+          file: SERVICE_WORKER_TEST_FILE,
+          result : "allowed",
+          policy : "default-src 'none'; script-src 'unsafe-inline'; child-src http://mochi.test:8888"
+        },
+        'same-src-shared_worker': {
+          id: "same-src-shared_worker",
+          file: SHARED_WORKER_TEST_FILE,
+          result : "allowed",
+          policy : "default-src 'none'; script-src 'unsafe-inline'; child-src http://mochi.test:8888"
+        },
+        'star-src-worker': {
+          id: "star-src-worker",
+          file: WORKER_TEST_FILE,
+          result : "allowed",
+          policy : "default-src 'none'; script-src 'unsafe-inline'; child-src *"
+        },
+        'star-src-service_worker': {
+          id: "star-src-service_worker",
+          file: SERVICE_WORKER_TEST_FILE,
+          result : "allowed",
+          policy : "default-src 'none'; script-src 'unsafe-inline'; child-src *"
+        },
+        'star-src-shared_worker': {
+          id: "star-src-shared_worker",
+          file: SHARED_WORKER_TEST_FILE,
+          result : "allowed",
+          policy : "default-src 'none'; script-src 'unsafe-inline'; child-src *"
+        },
+        'other-src-worker': {
+          id: "other-src-worker",
+          file: WORKER_TEST_FILE,
+          result : "blocked",
+          policy : "default-src 'none'; script-src 'unsafe-inline'; child-src https://www.example.org"
+        },
+        'other-src-service_worker': {
+          id: "other-src-service_worker",
+          file: SERVICE_WORKER_TEST_FILE,
+          result : "blocked",
+          policy : "default-src 'none'; script-src 'unsafe-inline'; child-src https://www.example.org"
+        },
+        'other-src-shared_worker': {
+          id: "other-src-shared_worker",
+          file: SHARED_WORKER_TEST_FILE,
+          result : "blocked",
+          policy : "default-src 'none'; script-src 'unsafe-inline'; child-src https://www.example.org"
+        },
+      };
+
+      finished = {};
+
+      function recvMessage(ev) {
+        is(ev.data.message, tests[ev.data.id].result, "CSP child-src worker test " + ev.data.id);
+        finished[ev.data.id] = ev.data.message;
+
+        if (Object.keys(finished).length == Object.keys(tests).length) {
+          window.removeEventListener('message', recvMessage);
+          SimpleTest.finish();
+        }
+      }
+
+      window.addEventListener('message', recvMessage, false);
+
+      function loadNextTest() {
+        for (item in tests) {
+          test = tests[item];
+          var src = "file_testserver.sjs";
+          // append the file that should be served
+          src += "?file=" + escape("tests/dom/security/test/csp/" + test.file);
+          // append the CSP that should be used to serve the file
+          src += "&csp=" + escape(test.policy);
+          // add our identifier
+          src += "#" + escape(test.id);
+
+          content = document.getElementById('content');
+          testframe = document.createElement("iframe");
+          testframe.setAttribute('id', test.id);
+          content.appendChild(testframe);
+          testframe.src = src;
+        }
+      }
+
+      onload = function() {
+        SpecialPowers.pushPrefEnv({"set": [
+          ["dom.serviceWorkers.exemptFromPerDomainMax", true],
+          ["dom.serviceWorkers.interception.enabled", true],
+          ["dom.serviceWorkers.enabled", true],
+          ["dom.serviceWorkers.testing.enabled", true],
+          ["dom.caches.enabled", true]
+        ]}, loadNextTest);
+      };
+
+      // start running the tests
+      //loadNextTest();
+    </script>
+  </body>
+</html>
new file mode 100644
--- /dev/null
+++ b/dom/security/test/csp/test_child-src_worker_data.html
@@ -0,0 +1,126 @@
+<!DOCTYPE HTML>
+<html>
+  <head>
+    <title>Bug 1045891</title>
+    <!-- Including SimpleTest.js so we can use waitForExplicitFinish !-->
+    <script type="text/javascript" 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="visibility: hidden">
+    </div>
+
+    <script class="testbody" type="text/javascript">
+      /*
+       * Description of the test:
+       *   We load a page with a given CSP and verify that child frames and workers are correctly
+       *   evaluated through the "child-src" directive.
+       */
+
+      SimpleTest.waitForExplicitFinish();
+
+      var WORKER_TEST_FILE = "file_child-src_worker_data.html";
+      var SHARED_WORKER_TEST_FILE = "file_child-src_shared_worker_data.html";
+
+      var tests = {
+        'same-src-worker-no-data': {
+          id: "same-src-worker-no-data",
+          file: WORKER_TEST_FILE,
+          result : "blocked",
+          policy : "default-src 'none'; script-src 'unsafe-inline'; child-src 'self'"
+        },
+        'same-src-worker': {
+          id: "same-src-worker",
+          file: WORKER_TEST_FILE,
+          result : "allowed",
+          policy : "default-src 'none'; script-src 'unsafe-inline'; child-src 'self' data:"
+        },
+        'same-src-shared_worker-no-data': {
+          id: "same-src-shared_worker-no-data",
+          file: SHARED_WORKER_TEST_FILE,
+          result : "blocked",
+          policy : "default-src 'none'; script-src 'unsafe-inline'; child-src 'self'"
+        },
+        'same-src-shared_worker': {
+          id: "same-src-shared_worker",
+          file: SHARED_WORKER_TEST_FILE,
+          result : "allowed",
+          policy : "default-src 'none'; script-src 'unsafe-inline'; child-src 'self' data:"
+        },
+        'star-src-worker': {
+          id: "star-src-worker",
+          file: WORKER_TEST_FILE,
+          result : "allowed",
+          policy : "default-src 'none'; script-src 'unsafe-inline'; child-src * data:"
+        },
+        'star-src-worker-no-data': {
+          id: "star-src-worker-no-data",
+          file: WORKER_TEST_FILE,
+          result : "blocked",
+          policy : "default-src 'none'; script-src 'unsafe-inline'; child-src *"
+        },
+        'star-src-shared_worker-no-data': {
+          id: "star-src-shared_worker-no-data",
+          file: SHARED_WORKER_TEST_FILE,
+          result : "blocked",
+          policy : "default-src 'none'; script-src 'unsafe-inline'; child-src *"
+        },
+        'star-src-shared_worker': {
+          id: "star-src-shared_worker",
+          file: SHARED_WORKER_TEST_FILE,
+          result : "allowed",
+          policy : "default-src 'none'; script-src 'unsafe-inline'; child-src * data:"
+        },
+        'other-src-worker-no-data': {
+          id: "other-src-worker-no-data",
+          file: WORKER_TEST_FILE,
+          result : "blocked",
+          policy : "default-src 'none'; script-src 'unsafe-inline'; child-src https://www.example.org"
+        },
+        'other-src-shared_worker-no-data': {
+          id: "other-src-shared_worker-no-data",
+          file: SHARED_WORKER_TEST_FILE,
+          result : "blocked",
+          policy : "default-src 'none'; script-src 'unsafe-inline'; child-src https://www.example.org"
+        },
+      };
+
+      finished = {};
+
+      function recvMessage(ev) {
+        is(ev.data.message, tests[ev.data.id].result, "CSP child-src worker test " + ev.data.id);
+        finished[ev.data.id] = ev.data.message;
+
+        if (Object.keys(finished).length == Object.keys(tests).length) {
+          window.removeEventListener('message', recvMessage);
+          SimpleTest.finish();
+        }
+      }
+
+      window.addEventListener('message', recvMessage, false);
+
+      function loadNextTest() {
+        for (item in tests) {
+          test = tests[item];
+          var src = "file_testserver.sjs";
+          // append the file that should be served
+          src += "?file=" + escape("tests/dom/security/test/csp/" + test.file);
+          // append the CSP that should be used to serve the file
+          src += "&csp=" + escape(test.policy);
+          // add our identifier
+          src += "#" + escape(test.id);
+
+          content = document.getElementById('content');
+          testframe = document.createElement("iframe");
+          testframe.setAttribute('id', test.id);
+          content.appendChild(testframe);
+          testframe.src = src;
+        }
+      }
+
+      // start running the tests
+      loadNextTest();
+    </script>
+  </body>
+</html>
--- a/dom/security/test/csp/test_service_worker.html
+++ b/dom/security/test/csp/test_service_worker.html
@@ -14,17 +14,17 @@
 /* Description of the test:
  * Spawning a worker from https://example.com but script-src is 'test1.example.com'
  * CSP is not consulted
  */
 SimpleTest.waitForExplicitFinish();
 
 var tests = [
   {
-    policy: "default-src 'self'; script-src test1.example.com 'unsafe-inline'",
+    policy: "default-src 'self'; script-src 'unsafe-inline'; child-src test1.example.com;",
     expected: "blocked"
   },
 ];
 
 var counter = 0;
 var curTest;
 
 window.addEventListener("message", receiveMessage, false);
--- a/dom/security/test/csp/test_worker_redirect.html
+++ b/dom/security/test/csp/test_worker_redirect.html
@@ -32,21 +32,21 @@
  * The main test is loaded using:
  *   http://mochi.test:8888
  * where the imported script gets redirected to:
  *   http://test1.example.com
  */
 
 var tests = [
   {
-    policy: "default-src 'self'; script-src 'self' 'unsafe-eval' http://test1.example.com;",
+    policy: "default-src 'self'; script-src 'self' 'unsafe-eval'; child-src 'self' http://test1.example.com;",
     expected: "allowed"
   },
   {
-    policy: "default-src 'self'; script-src 'self' 'unsafe-eval';",
+    policy: "default-src 'self'; script-src 'self' 'unsafe-eval'; child-src 'self';",
     expected: "blocked",
   },
 ];
 
 var counter = 0;
 var curTest;
 
 function checkResult(aResult) {