Bug 704320 - Add tests for whether preloaded resources can be reused after script-added meta referrer policy is added to a document. (r=bz)
authorSid Stamm <sstamm@mozilla.com>
Tue, 18 Nov 2014 08:47:26 -0500
changeset 216291 a0c582c952756433e9ab27a11c6948791af1ba83
parent 216290 52dfc1a43464bc0bd150b8ef50a2620e4c75bace
child 216292 f268d422e9fba24da11ed15eb1b6083e7fe2e7fc
push id27845
push userkwierso@gmail.com
push dateWed, 19 Nov 2014 02:08:01 +0000
treeherdermozilla-central@64e7a6391916 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersbz
bugs704320
milestone36.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Bug 704320 - Add tests for whether preloaded resources can be reused after script-added meta referrer policy is added to a document. (r=bz)
dom/base/test/bug704320_counter.sjs
dom/base/test/file_bug704320_preload_common.js
dom/base/test/file_bug704320_preload_noreuse.html
dom/base/test/file_bug704320_preload_reuse.html
dom/base/test/mochitest.ini
dom/base/test/test_bug704320_preload.html
new file mode 100644
--- /dev/null
+++ b/dom/base/test/bug704320_counter.sjs
@@ -0,0 +1,94 @@
+// Handle counting loads for bug 704320.
+
+const SHARED_KEY="bug704320_counter";
+const DEFAULT_STATE = {'css': {'count': 0, 'referrers': []},
+                       'img': {'count': 0, 'referrers': []},
+                       'js':  {'count': 0, 'referrers': []}};
+const TYPE_MAP = {'css': 'text/css',
+                  'js':  'application/javascript',
+                  'img': 'image/png',
+                  'html': 'text/html'};
+
+// Writes an image to the response
+function WriteOutImage(response)
+{
+  var file = Components.classes["@mozilla.org/file/directory_service;1"]
+             .getService(Components.interfaces.nsIProperties)
+             .get("CurWorkD", Components.interfaces.nsIFile);
+
+  file.append("tests");
+  file.append("image");
+  file.append("test");
+  file.append("mochitest");
+  file.append('blue.png');
+
+  var fileStream = Components.classes['@mozilla.org/network/file-input-stream;1']
+                   .createInstance(Components.interfaces.nsIFileInputStream);
+  fileStream.init(file, 1, 0, false);
+  response.bodyOutputStream.writeFrom(fileStream, fileStream.available());
+}
+
+function handleRequest(request, response)
+{
+  var query = {};
+  request.queryString.split('&').forEach(function (val) {
+    var [name, value] = val.split('=');
+    query[name] = unescape(value);
+  });
+
+  var referrerLevel = "none";
+  if (request.hasHeader('Referer')) {
+    let referrer = request.getHeader('Referer');
+    if (referrer.indexOf("bug704320_preload") > 0) {
+      referrerLevel = "full";
+    } else if (referrer == "http://mochi.test:8888") {
+      referrerLevel = "origin";
+    }
+  }
+
+  var state = getSharedState(SHARED_KEY);
+  if (state === '') {
+    state = DEFAULT_STATE;
+  } else {
+    state = JSON.parse(state);
+  }
+
+  response.setStatusLine(request.httpVersion, 200, "OK");
+
+
+  //avoid confusing cache behaviors
+  response.setHeader("Cache-Control", "no-cache", false);
+
+  if ("reset" in query) {
+    //reset server state
+    setSharedState(SHARED_KEY, JSON.stringify(DEFAULT_STATE));
+    //serve any CSS that we want to use.
+    response.write("");
+    return;
+  }
+
+  if ("results" in query) {
+    response.setHeader("Content-Type", "text/javascript", false);
+    response.write(JSON.stringify(state));
+    return;
+  }
+
+  if ('type' in query) {
+    state[query.type].count++;
+    response.setHeader("Content-Type", TYPE_MAP[query.type], false);
+    if (state[query.type].referrers.indexOf(referrerLevel) < 0) {
+      state[query.type].referrers.push(referrerLevel);
+    }
+
+    if (query.type == 'img') {
+      WriteOutImage(response);
+    }
+  }
+
+  if ('content' in query) {
+    response.write(unescape(query['content']));
+  }
+
+  setSharedState(SHARED_KEY, JSON.stringify(state));
+  return;
+}
new file mode 100644
--- /dev/null
+++ b/dom/base/test/file_bug704320_preload_common.js
@@ -0,0 +1,23 @@
+// Common code for the iframes used by bug704320_preload.
+
+var loadCount = 0;
+
+// Called by the various onload handlers to indicate that a resource has
+// been fully loaded.  We require three loads to complete (img, script,
+// link) for this test.
+function incrementLoad(tag) {
+  loadCount++;
+  if (loadCount == 3) {
+    window.parent.postMessage("childLoadComplete", window.location.origin);
+  } else if (loadCount > 3) {
+    document.write("<h1>Too Many Load Events!</h1>");
+    window.parent.postMessage("childOverload", window.location.origin);
+  }
+}
+
+// in case something fails to load, cause the test to fail.
+function postfail(msg) {
+  window.parent.postMessage("fail-" + msg, window.location.origin);
+}
+
+
new file mode 100644
--- /dev/null
+++ b/dom/base/test/file_bug704320_preload_noreuse.html
@@ -0,0 +1,33 @@
+<!DOCTYPE HTML>
+<html>
+<!--
+This is a spot check for whether the speculative parser reuses style, script or image loads after the referrer policy has changed.
+https://bugzilla.mozilla.org/show_bug.cgi?id=704320
+-->
+<head>
+  <meta charset="utf-8">
+  <script type="text/javascript" src="file_bug704320_preload_common.js"></script>
+
+  <script type="text/javascript">
+    // mess with parser speculation's choice of referrer policy
+    document.write("<meta name='referrer' content='origin'>");
+  </script>
+
+  <!-- preload happens with full referrer, but real load should happen with origin -->
+  <script src="/tests/dom/base/test/bug704320_counter.sjs?type=js"
+          onload="incrementLoad('script');"></script>
+
+  <!-- preload happens with full referrer, but real load should happen with origin -->
+  <link rel="stylesheet"
+        href="/tests/dom/base/test/bug704320_counter.sjs?type=css"
+        onload="incrementLoad('link');"/>
+
+</head>
+<body>
+
+  <!-- preload happens with full referrer, but real load should happen with origin -->
+<img src="/tests/dom/base/test/bug704320_counter.sjs?type=img"
+     onload="incrementLoad('img');"
+     onerror="postfail('image load caused an error in noreuse test');"/>
+</body>
+</html>
new file mode 100644
--- /dev/null
+++ b/dom/base/test/file_bug704320_preload_reuse.html
@@ -0,0 +1,31 @@
+<!DOCTYPE HTML>
+<html>
+<!--
+This is a spot check for whether the speculative parser reuses style, script or image loads after the referrer policy has changed.
+https://bugzilla.mozilla.org/show_bug.cgi?id=704320
+-->
+<head>
+  <meta charset="utf-8">
+  <meta name="referrer" content="origin">
+  <script type="text/javascript" src="file_bug704320_preload_common.js"></script>
+  <script language="javascript" type="text/javascript">
+    // mess with parser speculation -- the loads here MAY be reused because the
+    // referrer policy did not change.
+    document.write("<meta name='referrer' content='origin'>");
+  </script>
+
+  <script src="http://example.com/tests/dom/base/test/bug704320_counter.sjs?type=js"
+          onload="incrementLoad('script');"></script>
+
+  <link rel="stylesheet"
+        href="http://example.com/tests/dom/base/test/bug704320_counter.sjs?type=css"
+        onload="incrementLoad('link');"/>
+
+</head>
+<body>
+
+<img src="http://example.com/tests/dom/base/test/bug704320_counter.sjs?type=img"
+     onload="incrementLoad('img');"
+     onerror="postfail('image load caused an error in reuse test');"/>
+</body>
+</html>
--- a/dom/base/test/mochitest.ini
+++ b/dom/base/test/mochitest.ini
@@ -48,16 +48,17 @@ support-files =
   bug638112-response.txt
   bug638112.sjs
   bug682592-subframe-ref.html
   bug682592-subframe.html
   bug696301-script-1.js
   bug696301-script-1.js^headers^
   bug696301-script-2.js
   bug704320.sjs
+  bug704320_counter.sjs
   bug819051.sjs
   copypaste.js
   delayedServerEvents.sjs
   echo.sjs
   eventsource.resource
   eventsource.resource^headers^
   eventsource_redirect.resource
   eventsource_redirect.resource^headers^
@@ -134,16 +135,19 @@ support-files =
   file_bug687859-16.js^headers^
   file_bug687859-bom.js
   file_bug687859-bom.js^headers^
   file_bug687859-charset.js
   file_bug687859-http.js
   file_bug687859-http.js^headers^
   file_bug687859-inherit.js
   file_bug692434.xml
+  file_bug704320_preload_common.js
+  file_bug704320_preload_reuse.html
+  file_bug704320_preload_noreuse.html
   file_bug704320_redirect.html
   file_bug707142_baseline.json
   file_bug707142_bom.json
   file_bug707142_utf-16.json
   file_bug708620-2.html
   file_bug708620.html
   file_bug782342.txt
   file_bug787778.sjs
@@ -592,16 +596,17 @@ skip-if = buildapp == 'b2g'
 [test_bug694754.xhtml]
 [test_bug696301-1.html]
 [test_bug696301-2.html]
 [test_bug698381.html]
 [test_bug698384.html]
 [test_bug704063.html]
 [test_bug704320.html]
 skip-if = buildapp == 'b2g' || toolkit == 'android' || e10s # b2g (Needs multiple window.open support) android(times out, bug 1100609) e10s(randomly fails, bug 1100362)
+[test_bug704320_preload.html]
 [test_bug707142.html]
 [test_bug708620.html]
 [test_bug711047.html]
 [test_bug711180.html]
 [test_bug719533.html]
 [test_bug726364.html]
 [test_bug737087.html]
 [test_bug737565.html]
new file mode 100644
--- /dev/null
+++ b/dom/base/test/test_bug704320_preload.html
@@ -0,0 +1,189 @@
+<!DOCTYPE HTML>
+<html>
+<!--
+This is a spot check for whether the speculative parser reuses style, script or image loads after the referrer policy has changed.
+https://bugzilla.mozilla.org/show_bug.cgi?id=704320
+-->
+
+<head>
+  <meta charset="utf-8">
+  <title>Test preloads for Bug 704320</title>
+  <script type="application/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
+  <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
+
+<script type="application/javascript;version=1.7">
+
+SimpleTest.waitForExplicitFinish();
+var advance = function() { tests.next(); };
+
+/**
+ * Listen for notifications from the child.
+ * These are sent in case of error, or when the loads we await have completed.
+ */
+window.addEventListener("message", function(event) {
+    if (event.data == "childLoadComplete") {
+      // all three loads happen, continue the test.
+      advance();
+    } else if (event.data == "childOverload") {
+      // too many loads happened in a test frame, abort.
+      ok(false, "Too many load handlers called in test.");
+      SimpleTest.finish();
+    } else if (event.data.indexOf("fail-") == 0) {
+      // something else failed in the test frame, abort.
+      ok(false, "Child failed the test with error " + event.data.substr(5));
+      SimpleTest.finish();
+    }});
+
+/**
+ * This is the main test routine -- serialized by use of a generator.
+ * It resets the counter, then performs two tests in sequence using
+ * the same iframe.
+ */
+var tests = (function() {
+  var iframe = document.getElementById("testframe");
+
+  // reset the counter
+  yield resetCounter();
+
+  // load the first test frame
+  // it will call back into this function via postMessage when it finishes loading.
+  // and continue beyond the yield.
+  yield iframe.src = 'file_bug704320_preload_noreuse.html';
+
+  // check the first test
+  yield checkResults(finalizePreloadNoreuse);
+
+  // reset the counter
+  yield resetCounter();
+
+  // load the second test frame
+  // it will call back into this function via postMessage when it finishes loading.
+  // and continue beyond the yield.
+  yield iframe.src = 'file_bug704320_preload_reuse.html';
+
+  // check the second test
+  yield checkResults(finalizePreloadReuse);
+
+  // complete.  Be sure to yield so we don't call this twice.
+  yield SimpleTest.finish();
+})();
+
+// Helper functions below.
+
+/**
+ * This checks the first test: a test where the preloads should not
+ * be reused.  * we expect two requests for each image, script, js request
+ * since the referrer policy changed after speculative loads were started.
+ * Problem is that the "origin"/revised loads won't necessarily happen,
+ * so we test for one or two loads (both are OK) and make the 'origin'
+ * referrer optional.
+ */
+function finalizePreloadNoreuse(results) {
+  console.log("<br/><pre>" + JSON.stringify(results) + "</pre>");
+  var expected = {'css': {'count': 2, 'referrers': ['full', 'origin']},
+                  'img': {'count': 2, 'referrers': ['full', 'origin']},
+                  'js':  {'count': 2, 'referrers': ['full', 'origin']}};
+
+  for (var x in expected) {
+    ok(x in results, "some " + x + " loads required in results object.");
+
+    ok(results[x].count == 1 || results[x].count == 2,
+       "Expected 1-2  loads for " + x + " requests.");
+
+    // the 'full' preload is optional, but required if count > 1
+    if (results[x].count > 1) {
+      ok(results[x].referrers.indexOf('full') >= 0,
+         "More than one load for " + x + ", so expected an 'full' referrer preload.")
+    }
+
+    // 'origin' (final load) is required
+    ok(results[x].referrers.indexOf('origin') >= 0,
+       "One load for " + x + " should have had 'origin' referrer.");
+
+    // no other values should be in the referrers.
+    is(results[x].referrers.indexOf('none'), -1,
+       "No loads for " + x + " should have a missing referrer.");
+  }
+
+  advance();
+}
+
+/**
+ * This checks the second test: a test where preloads SHOULD be reused.
+ * We expect one request for each image, script, js request since
+ * the referrer policy does not change after speculative loads.
+ */
+function finalizePreloadReuse(results) {
+  var expected = {'css': {'count': 1, 'referrers': ['origin']},
+                  'img': {'count': 1, 'referrers': ['origin']},
+                  'js':  {'count': 1, 'referrers': ['origin']}};
+
+  for (var x in expected) {
+    ok(x in results, "some " + x + " loads required in results object.");
+
+    is(results[x].count, expected[x].count,
+       "Expected " + expected[x].count + " loads for " + x + " requests.");
+
+    // 'origin' is required
+    ok(results[x].referrers.indexOf('origin') >= 0,
+       "One load for " + x + " should have had 'origin' referrer.");
+
+    // no other values should be in the referrers.
+    is(results[x].referrers.indexOf('none'), -1,
+       "No loads for " + x + " should have a missing referrer.");
+    is(results[x].referrers.indexOf('full'), -1,
+       "No loads for " + x + " should have an 'full' referrer.")
+  }
+
+  advance();
+}
+
+/**
+ * helper to perform an XHR.
+ * Used by resetCounter() and checkResults().
+ */
+function doXHR(url, onSuccess, onFail) {
+  var xhr = new XMLHttpRequest();
+  xhr.onload = function () {
+    if (xhr.status == 200) {
+      onSuccess(xhr);
+    } else {
+      onFail(xhr);
+    }
+  };
+  xhr.open('GET', url, true);
+  xhr.send(null);
+}
+
+/**
+ * This triggers state-resetting on the counter server.
+ */
+function resetCounter() {
+  doXHR('/tests/dom/base/test/bug704320_counter.sjs?reset',
+        advance,
+        function(xhr) {
+          ok(false, "Need to be able to reset the request counter");
+        });
+}
+
+/**
+ * Grabs the results via XHR and passes to checker.
+ */
+function checkResults(checker) {
+  doXHR('/tests/dom/base/test/bug704320_counter.sjs?results',
+        function(xhr) {
+          checker(JSON.parse(xhr.responseText));
+        },
+        function(xhr) {
+          ok(false, "Can't get results from the counter server.");
+        });
+}
+
+</script>
+</head>
+
+<body onload="tests.next();">
+  <iframe id="testframe"></iframe>
+
+</body>
+</html>