[tor-commits] [tor-browser/tor-browser-31.4.0esr-4.5-1] Bug #13749.2: Regression tests for first-party isolation of cache

mikeperry at torproject.org mikeperry at torproject.org
Wed Jan 14 16:40:50 UTC 2015


commit c102a828cc194fa7a7eb4ffd5d01d7c5810033f3
Author: Arthur Edelstein <arthuredelstein at gmail.com>
Date:   Mon Dec 15 02:35:03 2014 -0800

    Bug #13749.2: Regression tests for first-party isolation of cache
    
    This test ensures that if first-party isolation is enabled
    ("privacy.thirdparty.isolate" pref is set to 2) then when a loaded file is cached,
    it is indexed by the URL-bar domain.
    
    In this test, a number of files are loaded (via IFRAME, LINK, SCRIPT, IMG, OBJECT,
    EMBED, AUDIO, VIDEO, TRACK and XMLHttpRequest) by parent pages with different URL bar
    domains. When isolation is active, we test to confirm that a separate copy of each file
    is cached for each different parent domain. We also test to make sure that when
    isolation is inactive, a single copy of the child page is cached and reused for all
    parent domains.
---
 netwerk/test/browser/browser.ini                 |   14 ++
 netwerk/test/browser/browser_cacheFirstParty.js  |  157 ++++++++++++++++++++++
 netwerk/test/browser/firstPartyGrandParent.html  |   10 ++
 netwerk/test/browser/firstPartyParent.html       |   38 ++++++
 netwerk/test/browser/thirdPartyChild.audio.ogg   |  Bin 0 -> 2603 bytes
 netwerk/test/browser/thirdPartyChild.embed.png   |  Bin 0 -> 95 bytes
 netwerk/test/browser/thirdPartyChild.iframe.html |   13 ++
 netwerk/test/browser/thirdPartyChild.img.png     |  Bin 0 -> 95 bytes
 netwerk/test/browser/thirdPartyChild.link.css    |    1 +
 netwerk/test/browser/thirdPartyChild.object.png  |  Bin 0 -> 95 bytes
 netwerk/test/browser/thirdPartyChild.script.js   |    1 +
 netwerk/test/browser/thirdPartyChild.track.vtt   |   13 ++
 netwerk/test/browser/thirdPartyChild.video.ogv   |  Bin 0 -> 16049 bytes
 netwerk/test/browser/thirdPartyChild.xhr.html    |    8 ++
 14 files changed, 255 insertions(+)

diff --git a/netwerk/test/browser/browser.ini b/netwerk/test/browser/browser.ini
index a5f31f9..cae28f7 100644
--- a/netwerk/test/browser/browser.ini
+++ b/netwerk/test/browser/browser.ini
@@ -1,3 +1,17 @@
 [DEFAULT]
+support-files =
+  firstPartyGrandParent.html
+  firstPartyParent.html
+  thirdPartyChild.link.css
+  thirdPartyChild.iframe.html
+  thirdPartyChild.script.js
+  thirdPartyChild.audio.ogg
+  thirdPartyChild.video.ogv
+  thirdPartyChild.embed.png
+  thirdPartyChild.img.png
+  thirdPartyChild.object.png
+  thirdPartyChild.xhr.html
+  thirdPartyChild.track.vtt
 
+[browser_cacheFirstParty.js]
 [browser_NetUtil.js]
diff --git a/netwerk/test/browser/browser_cacheFirstParty.js b/netwerk/test/browser/browser_cacheFirstParty.js
new file mode 100644
index 0000000..673b8c9
--- /dev/null
+++ b/netwerk/test/browser/browser_cacheFirstParty.js
@@ -0,0 +1,157 @@
+// # URL-bar domain (first party) isolation test
+
+// This test ensures that if first-party isolation is enabled
+// ("privacy.thirdparty.isolate" pref is set to 2) then when a loaded file is cached,
+// it is indexed by the URL-bar domain.
+
+// In this test, a number of files are loaded (via IFRAME, LINK, SCRIPT, IMG, OBJECT,
+// EMBED, AUDIO, VIDEO, TRACK and XMLHttpRequest) by parent pages with different URL bar
+// domains. When isolation is active, we test to confirm that a separate copy of each file
+// is cached for each different parent domain. We also test to make sure that when
+// isolation is inactive, a single copy of the child page is cached and reused for all
+// parent domains.
+
+// In this file, functions are defined in call stack order (later functions call earlier
+// functions). Comments are formatted for docco.
+
+/* jshint esnext:true */
+
+// __Mozilla utilities__.
+const Cu = Components.utils;
+const Ci = Components.interfaces;
+Cu.import("resource://gre/modules/Services.jsm");
+Cu.import("resource://gre/modules/Task.jsm");
+
+// __listen(target, eventType, timeoutMs, useCapture)__.
+// Calls addEventListener on target, with the given eventType.
+// Returns a Promise that resolves to an Event object, if the event fires.
+// If a timeout occurs, then Promise is rejected with a "Timed out" error.
+// For use with Task.jsm.
+let listen = function (target, eventType, timeoutMs, useCapture) {
+  return new Promise(function (resolve, reject) {
+    let listenFunction = function (event) {
+      target.removeEventListener(eventType, listenFunction, useCapture);
+      resolve(event);
+    };
+    target.addEventListener(eventType, listenFunction, useCapture);
+    window.setTimeout(() => reject(new Error("Timed out")), timeoutMs);
+  });
+};
+
+// __copyObject(obj)__.
+// Returns a shallow copy of an object. Works with JS native objects.
+let copyObject = function (obj) {
+  let result = {};
+  for (let k of Object.keys(obj)) {
+    result[k] = obj[k];
+  }
+  return result;
+};
+
+// __cacheData()__.
+// Returns the current state of the cache.
+let cacheData = function () {
+  let devices = [],
+      cacheEntries = [],
+      cacheVisitor = { visitDevice : function (deviceID, deviceInfo) {
+                                       devices.push(copyObject(deviceInfo));
+                                       return true;
+                                     },
+                       visitEntry : function (deviceID, entryInfo) {
+                                      cacheEntries.push(copyObject(entryInfo));
+                                      return true;
+                                    },
+                       QueryInterface : function(iid) {
+                             if (iid.equals(Ci.nsICacheVisitor)) return this;
+                       } };
+  Services.cache.visitEntries(cacheVisitor);
+  return { devices : devices, cacheEntries : cacheEntries };
+};
+
+// __loadURLinNewTab(URL)__.
+// Opens a new tab at a given URL, and waits for it to load. Times out after 5 sec.
+// Returns a promise that resolves to the tab. (Task.jsm coroutine.)
+let loadURLinNewTab = function* (URL) {
+  let tab = gBrowser.addTab(URL),
+      browser = gBrowser.getBrowserForTab(tab),
+      result = yield listen(browser, "load", 5000, true);
+  return tab;
+};
+
+// __countMatchingCacheEntries(cacheEntries, domain, fileSuffix)__.
+// Reports how many cache entries contain a given domain name and file suffix.
+let countMatchingCacheEntries = function (cacheEntries, domain, fileSuffix) {
+  return cacheEntries.map(entry => entry.key)
+           .filter(key => key.contains(domain))
+           .filter(key => key.contains("thirdPartyChild." + fileSuffix))
+           .length;
+};
+
+// __Constants__.
+let privacyPref = "privacy.thirdparty.isolate",
+    parentPage = "/browser/netwerk/test/browser/firstPartyParent.html",
+    grandParentPage = "/browser/netwerk/test/browser/firstPartyGrandParent.html",
+    // Parent domains (the iframe "child" domain is example.net):
+    domains = ["test1", "test2"],
+    // We duplicate domains, to check that two pages with the same first party domain
+    // share cached embedded objects.
+    duplicatedDomains = [].concat(domains, domains),
+    // We will check cache for example.net content from
+    // iframe, link, script, img, object, embed, xhr, audio, video, track
+    suffixes = ["iframe.html", "link.css", "script.js", "img.png", "object.png",
+                "embed.png", "xhr.html", "audio.ogg", "video.ogv", "track.vtt" ];
+
+// __checkCachePopulation(pref, numberOfDomains)__.
+// Check if the number of entries found in the cache for each
+// embedded file type matches the number we expect, given the 
+// number of domains and the isolation state.
+let checkCachePopulation = function (pref, numberOfDomains) {
+  let expectedEntryCount = (pref === 2) ? (2 * numberOfDomains) : 1;
+  // Collect cache data.
+  let data = cacheData();
+  for (let suffix of suffixes) {
+    let foundEntryCount = countMatchingCacheEntries(data.cacheEntries, "example.net", suffix),
+        result = (suffix.startsWith("video") || suffix.startsWith("audio")) ?
+          // Video and audio elements aren't always cached, so
+          // tolerate fewer cached copies.
+          (expectedEntryCount === 1 ? (foundEntryCount <= 1) : (foundEntryCount > 1)) :
+          (expectedEntryCount === foundEntryCount);
+    // Report results to mochitest
+    ok(result, "Cache entries expected for " + suffix +
+                           ": " + expectedEntryCount);
+  }
+};
+
+// __test()__.
+// The main testing function.
+let test = function () {
+  waitForExplicitFinish();
+  // Launch a Task.jsm coroutine so we can open tabs and wait for each of them to open,
+  // one by one.
+  Task.spawn(function* () {
+    // Keep original pref value for restoring after the tests.
+    let originalPrefValue = Services.prefs.getIntPref(privacyPref);
+    // Test the pref with both values: 2 (isolating by first party) or 0 (not isolating)
+    for (let pref of [2, 0]) {
+      // Clear the cache.
+      Services.cache2.clear();
+      // Set the pref to desired value
+      Services.prefs.setIntPref(privacyPref, pref);
+      // Open test tabs
+      let tabs = [];
+      for (let domain of duplicatedDomains) {
+        tabs.push(yield loadURLinNewTab("http://" + domain + ".example.com" + parentPage));
+        tabs.push(yield loadURLinNewTab("http://" + domain + ".example.org" + grandParentPage));
+      }
+      // Run checks to make sure cache has expected number of entries for
+      // the chosen pref state.
+      checkCachePopulation(pref, domains.length);
+      // Clean up by removing tabs.
+      tabs.forEach(tab => gBrowser.removeTab(tab));
+    }
+    // Restore the pref to its original value.
+    Services.prefs.setIntPref(privacyPref, originalPrefValue);
+    // All tests have now been run.
+    finish();
+  });
+};
diff --git a/netwerk/test/browser/firstPartyGrandParent.html b/netwerk/test/browser/firstPartyGrandParent.html
new file mode 100644
index 0000000..c990831
--- /dev/null
+++ b/netwerk/test/browser/firstPartyGrandParent.html
@@ -0,0 +1,10 @@
+<!DOCTYPE html>
+<html>
+<head>
+<meta content="text/html;charset=utf-8" http-equiv="Content-Type">
+</head>
+<frameset cols="50%,50%">
+  <frame src="http://example.net/browser/netwerk/test/browser/firstPartyParent.html">
+  <frame src="">
+</frameset>
+</html>
diff --git a/netwerk/test/browser/firstPartyParent.html b/netwerk/test/browser/firstPartyParent.html
new file mode 100644
index 0000000..7f2f5c8
--- /dev/null
+++ b/netwerk/test/browser/firstPartyParent.html
@@ -0,0 +1,38 @@
+<!DOCTYPE html>
+<html>
+<!-- The parent page, used by browser_cacheFirstParty.js -->
+<meta content="text/html;charset=utf-8" http-equiv="Content-Type">
+<head>
+  <link rel="stylesheet" type="text/css"
+        href="http://example.net/browser/netwerk/test/browser/thirdPartyChild.link.css">
+</head>
+<body>
+<div>firstPartyParent.html</div>
+
+<iframe src="http://example.net/browser/netwerk/test/browser/thirdPartyChild.iframe.html">
+</iframe>
+
+<script src="http://example.net/browser/netwerk/test/browser/thirdPartyChild.script.js">
+</script>
+
+<img src="http://example.net/browser/netwerk/test/browser/thirdPartyChild.img.png">
+
+<embed src="http://example.net/browser/netwerk/test/browser/thirdPartyChild.embed.png">
+
+<object data="http://example.net/browser/netwerk/test/browser/thirdPartyChild.object.png"
+        type="image/png"></object>
+
+<audio id="audio" autoplay>
+  <source src="http://example.net/browser/netwerk/test/browser/thirdPartyChild.audio.ogg"
+          type="audio/ogg">
+  <track src="http://example.net/browser/netwerk/test/browser/thirdPartyChild.track.vtt"
+         kind="subtitles"> 
+</audio>
+
+<video id="video"
+       src="http://example.net/browser/netwerk/test/browser/thirdPartyChild.video.ogv"
+       type="video/ogg">
+</video>
+
+</body>
+</html>
diff --git a/netwerk/test/browser/thirdPartyChild.audio.ogg b/netwerk/test/browser/thirdPartyChild.audio.ogg
new file mode 100644
index 0000000..edda4e9
Binary files /dev/null and b/netwerk/test/browser/thirdPartyChild.audio.ogg differ
diff --git a/netwerk/test/browser/thirdPartyChild.embed.png b/netwerk/test/browser/thirdPartyChild.embed.png
new file mode 100644
index 0000000..c5916f2
Binary files /dev/null and b/netwerk/test/browser/thirdPartyChild.embed.png differ
diff --git a/netwerk/test/browser/thirdPartyChild.iframe.html b/netwerk/test/browser/thirdPartyChild.iframe.html
new file mode 100644
index 0000000..f7b7531
--- /dev/null
+++ b/netwerk/test/browser/thirdPartyChild.iframe.html
@@ -0,0 +1,13 @@
+<!DOCTYPE html>
+<html>
+<meta content="text/html;charset=utf-8" http-equiv="Content-Type">
+<!-- The child page, used by browser_cacheFirstParty.js -->
+<body>
+<div>thirdPartyChild.html</div>
+<script>
+  var xhr = new XMLHttpRequest();
+  xhr.open("GET", "http://example.net/browser/netwerk/test/browser/thirdPartyChild.xhr.html", true);
+  xhr.send();
+</script>
+</body>
+</html>
diff --git a/netwerk/test/browser/thirdPartyChild.img.png b/netwerk/test/browser/thirdPartyChild.img.png
new file mode 100644
index 0000000..c5916f2
Binary files /dev/null and b/netwerk/test/browser/thirdPartyChild.img.png differ
diff --git a/netwerk/test/browser/thirdPartyChild.link.css b/netwerk/test/browser/thirdPartyChild.link.css
new file mode 100644
index 0000000..cf8a82e
--- /dev/null
+++ b/netwerk/test/browser/thirdPartyChild.link.css
@@ -0,0 +1 @@
+/* Dummy CSS file, used by browser_cacheFirstParty.js. */
\ No newline at end of file
diff --git a/netwerk/test/browser/thirdPartyChild.object.png b/netwerk/test/browser/thirdPartyChild.object.png
new file mode 100644
index 0000000..c5916f2
Binary files /dev/null and b/netwerk/test/browser/thirdPartyChild.object.png differ
diff --git a/netwerk/test/browser/thirdPartyChild.script.js b/netwerk/test/browser/thirdPartyChild.script.js
new file mode 100644
index 0000000..1cf2937
--- /dev/null
+++ b/netwerk/test/browser/thirdPartyChild.script.js
@@ -0,0 +1 @@
+// Dummy child script, used by browser_cacheFirstParty.js
diff --git a/netwerk/test/browser/thirdPartyChild.track.vtt b/netwerk/test/browser/thirdPartyChild.track.vtt
new file mode 100644
index 0000000..b37cb40
--- /dev/null
+++ b/netwerk/test/browser/thirdPartyChild.track.vtt
@@ -0,0 +1,13 @@
+WEBVTT FILE
+
+1
+00:00:00.500 --> 00:00:02.000 D:vertical A:start
+blah blah blah
+
+2
+00:00:02.500 --> 00:00:04.300
+this is a test
+
+3
+00:00:05.000 --> 00:00:07.000
+one more line
diff --git a/netwerk/test/browser/thirdPartyChild.video.ogv b/netwerk/test/browser/thirdPartyChild.video.ogv
new file mode 100644
index 0000000..68dee3c
Binary files /dev/null and b/netwerk/test/browser/thirdPartyChild.video.ogv differ
diff --git a/netwerk/test/browser/thirdPartyChild.xhr.html b/netwerk/test/browser/thirdPartyChild.xhr.html
new file mode 100644
index 0000000..b750364
--- /dev/null
+++ b/netwerk/test/browser/thirdPartyChild.xhr.html
@@ -0,0 +1,8 @@
+<!DOCTYPE html>
+<html>
+<meta content="text/html;charset=utf-8" http-equiv="Content-Type">
+<!-- The child page, used by browser_cacheFirstParty.js -->
+<body>
+<div>thirdPartyChild.html</div>
+</body>
+</html>



More information about the tor-commits mailing list