Bug 1138979 - Pref to turn TP on when in Private Browsing mode. r=mmc, r=ehsan
authorFrancois Marier <francois@mozilla.com>
Tue, 24 Mar 2015 14:10:00 -0400
changeset 264719 6f3151d4ff03c0bb1924e121fbef87d3696d5724
parent 264718 5c0cc88b465e5ef03598514fd1a0f7c1ab180649
child 264720 b53d8a0d5645af2f740487d11ce3b2e25141bb0f
push id4718
push userraliiev@mozilla.com
push dateMon, 11 May 2015 18:39:53 +0000
treeherdermozilla-beta@c20c4ef55f08 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersmmc, ehsan
bugs1138979
milestone39.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 1138979 - Pref to turn TP on when in Private Browsing mode. r=mmc, r=ehsan
modules/libpref/init/all.js
netwerk/base/nsChannelClassifier.cpp
toolkit/components/url-classifier/SafeBrowsing.jsm
toolkit/components/url-classifier/nsUrlClassifierDBService.cpp
toolkit/components/url-classifier/tests/mochitest/chrome.ini
toolkit/components/url-classifier/tests/mochitest/classifiedAnnotatedPBFrame.html
toolkit/components/url-classifier/tests/mochitest/test_privatebrowsing_trackingprotection.html
--- a/modules/libpref/init/all.js
+++ b/modules/libpref/init/all.js
@@ -1024,18 +1024,20 @@ pref("content.sink.pending_event_mode", 
 // Disable popups from plugins by default
 //   0 = openAllowed
 //   1 = openControlled
 //   2 = openAbused
 pref("privacy.popups.disable_from_plugins", 2);
 
 // send "do not track" HTTP header, disabled by default
 pref("privacy.donottrackheader.enabled",    false);
-// Enforce tracking protection
+// Enforce tracking protection in all modes
 pref("privacy.trackingprotection.enabled",  false);
+// Enforce tracking protection in Private Browsing mode
+pref("privacy.trackingprotection.pbmode.enabled",  false);
 
 pref("dom.event.contextmenu.enabled",       true);
 pref("dom.event.clipboardevents.enabled",   true);
 #if defined(XP_WIN) && !defined(RELEASE_BUILD)
 pref("dom.event.highrestimestamp.enabled",  true);
 #else
 pref("dom.event.highrestimestamp.enabled",  false);
 #endif
--- a/netwerk/base/nsChannelClassifier.cpp
+++ b/netwerk/base/nsChannelClassifier.cpp
@@ -63,17 +63,19 @@ nsChannelClassifier::ShouldEnableTrackin
                                                     bool *result)
 {
     // Should only be called in the parent process.
     MOZ_ASSERT(XRE_GetProcessType() == GeckoProcessType_Default);
 
     NS_ENSURE_ARG(result);
     *result = false;
 
-    if (!Preferences::GetBool("privacy.trackingprotection.enabled", false)) {
+    if (!Preferences::GetBool("privacy.trackingprotection.enabled", false) &&
+        (!Preferences::GetBool("privacy.trackingprotection.pbmode.enabled",
+                               false) || !NS_UsePrivateBrowsing(aChannel))) {
       return NS_OK;
     }
 
     nsresult rv;
     nsCOMPtr<mozIThirdPartyUtil> thirdPartyUtil =
         do_GetService(THIRDPARTYUTIL_CONTRACTID, &rv);
     NS_ENSURE_SUCCESS(rv, rv);
     // Third party checks don't work for chrome:// URIs in mochitests, so just
--- a/toolkit/components/url-classifier/SafeBrowsing.jsm
+++ b/toolkit/components/url-classifier/SafeBrowsing.jsm
@@ -103,17 +103,17 @@ this.SafeBrowsing = {
 
 
   readPrefs: function() {
     log("reading prefs");
 
     debug = Services.prefs.getBoolPref("browser.safebrowsing.debug");
     this.phishingEnabled = Services.prefs.getBoolPref("browser.safebrowsing.enabled");
     this.malwareEnabled = Services.prefs.getBoolPref("browser.safebrowsing.malware.enabled");
-    this.trackingEnabled = Services.prefs.getBoolPref("privacy.trackingprotection.enabled");
+    this.trackingEnabled = Services.prefs.getBoolPref("privacy.trackingprotection.enabled") || Services.prefs.getBoolPref("privacy.trackingprotection.pbmode.enabled");
     this.updateProviderURLs();
 
     // XXX The listManager backend gets confused if this is called before the
     // lists are registered. So only call it here when a pref changes, and not
     // when doing initialization. I expect to refactor this later, so pardon the hack.
     if (this.initialized) {
       this.controlUpdateChecking();
     }
--- a/toolkit/components/url-classifier/nsUrlClassifierDBService.cpp
+++ b/toolkit/components/url-classifier/nsUrlClassifierDBService.cpp
@@ -69,16 +69,19 @@ PRLogModuleInfo *gUrlClassifierDbService
 #define CHECK_MALWARE_DEFAULT   false
 
 #define CHECK_PHISHING_PREF     "browser.safebrowsing.enabled"
 #define CHECK_PHISHING_DEFAULT  false
 
 #define CHECK_TRACKING_PREF     "privacy.trackingprotection.enabled"
 #define CHECK_TRACKING_DEFAULT  false
 
+#define CHECK_TRACKING_PB_PREF    "privacy.trackingprotection.pbmode.enabled"
+#define CHECK_TRACKING_PB_DEFAULT false
+
 #define GETHASH_NOISE_PREF      "urlclassifier.gethashnoise"
 #define GETHASH_NOISE_DEFAULT   4
 
 // Comma-separated lists
 #define MALWARE_TABLE_PREF      "urlclassifier.malwareTable"
 #define PHISH_TABLE_PREF        "urlclassifier.phishTable"
 #define TRACKING_TABLE_PREF     "urlclassifier.trackingTable"
 #define DOWNLOAD_BLOCK_TABLE_PREF "urlclassifier.downloadBlockTable"
@@ -1111,28 +1114,30 @@ nsUrlClassifierDBService::Init()
     }
   }
 
   // Retrieve all the preferences.
   mCheckMalware = Preferences::GetBool(CHECK_MALWARE_PREF,
     CHECK_MALWARE_DEFAULT);
   mCheckPhishing = Preferences::GetBool(CHECK_PHISHING_PREF,
     CHECK_PHISHING_DEFAULT);
-  mCheckTracking = Preferences::GetBool(CHECK_TRACKING_PREF,
-    CHECK_TRACKING_DEFAULT);
+  mCheckTracking =
+    Preferences::GetBool(CHECK_TRACKING_PREF, CHECK_TRACKING_DEFAULT) ||
+    Preferences::GetBool(CHECK_TRACKING_PB_PREF, CHECK_TRACKING_PB_DEFAULT);
   uint32_t gethashNoise = Preferences::GetUint(GETHASH_NOISE_PREF,
     GETHASH_NOISE_DEFAULT);
   gFreshnessGuarantee = Preferences::GetInt(CONFIRM_AGE_PREF,
     CONFIRM_AGE_DEFAULT_SEC);
   ReadTablesFromPrefs();
 
   // Do we *really* need to be able to change all of these at runtime?
   Preferences::AddStrongObserver(this, CHECK_MALWARE_PREF);
   Preferences::AddStrongObserver(this, CHECK_PHISHING_PREF);
   Preferences::AddStrongObserver(this, CHECK_TRACKING_PREF);
+  Preferences::AddStrongObserver(this, CHECK_TRACKING_PB_PREF);
   Preferences::AddStrongObserver(this, GETHASH_NOISE_PREF);
   Preferences::AddStrongObserver(this, CONFIRM_AGE_PREF);
   Preferences::AddStrongObserver(this, PHISH_TABLE_PREF);
   Preferences::AddStrongObserver(this, MALWARE_TABLE_PREF);
   Preferences::AddStrongObserver(this, TRACKING_TABLE_PREF);
   Preferences::AddStrongObserver(this, DOWNLOAD_BLOCK_TABLE_PREF);
   Preferences::AddStrongObserver(this, DOWNLOAD_ALLOW_TABLE_PREF);
   Preferences::AddStrongObserver(this, DISALLOW_COMPLETION_TABLE_PREF);
@@ -1522,19 +1527,21 @@ nsUrlClassifierDBService::Observe(nsISup
     nsCOMPtr<nsIPrefBranch> prefs(do_QueryInterface(aSubject, &rv));
     NS_ENSURE_SUCCESS(rv, rv);
     if (NS_LITERAL_STRING(CHECK_MALWARE_PREF).Equals(aData)) {
       mCheckMalware = Preferences::GetBool(CHECK_MALWARE_PREF,
         CHECK_MALWARE_DEFAULT);
     } else if (NS_LITERAL_STRING(CHECK_PHISHING_PREF).Equals(aData)) {
       mCheckPhishing = Preferences::GetBool(CHECK_PHISHING_PREF,
         CHECK_PHISHING_DEFAULT);
-    } else if (NS_LITERAL_STRING(CHECK_TRACKING_PREF).Equals(aData)) {
-      mCheckTracking = Preferences::GetBool(CHECK_TRACKING_PREF,
-        CHECK_TRACKING_DEFAULT);
+    } else if (NS_LITERAL_STRING(CHECK_TRACKING_PREF).Equals(aData) ||
+               NS_LITERAL_STRING(CHECK_TRACKING_PB_PREF).Equals(aData)) {
+      mCheckTracking =
+        Preferences::GetBool(CHECK_TRACKING_PREF, CHECK_TRACKING_DEFAULT) ||
+        Preferences::GetBool(CHECK_TRACKING_PB_PREF, CHECK_TRACKING_PB_DEFAULT);
     } else if (
       NS_LITERAL_STRING(PHISH_TABLE_PREF).Equals(aData) ||
       NS_LITERAL_STRING(MALWARE_TABLE_PREF).Equals(aData) ||
       NS_LITERAL_STRING(TRACKING_TABLE_PREF).Equals(aData) ||
       NS_LITERAL_STRING(DOWNLOAD_BLOCK_TABLE_PREF).Equals(aData) ||
       NS_LITERAL_STRING(DOWNLOAD_ALLOW_TABLE_PREF).Equals(aData) ||
       NS_LITERAL_STRING(DISALLOW_COMPLETION_TABLE_PREF).Equals(aData)) {
       // Just read everything again.
@@ -1564,16 +1571,17 @@ nsUrlClassifierDBService::Shutdown()
 
   mCompleters.Clear();
 
   nsCOMPtr<nsIPrefBranch> prefs = do_GetService(NS_PREFSERVICE_CONTRACTID);
   if (prefs) {
     prefs->RemoveObserver(CHECK_MALWARE_PREF, this);
     prefs->RemoveObserver(CHECK_PHISHING_PREF, this);
     prefs->RemoveObserver(CHECK_TRACKING_PREF, this);
+    prefs->RemoveObserver(CHECK_TRACKING_PB_PREF, this);
     prefs->RemoveObserver(PHISH_TABLE_PREF, this);
     prefs->RemoveObserver(MALWARE_TABLE_PREF, this);
     prefs->RemoveObserver(TRACKING_TABLE_PREF, this);
     prefs->RemoveObserver(DOWNLOAD_BLOCK_TABLE_PREF, this);
     prefs->RemoveObserver(DOWNLOAD_ALLOW_TABLE_PREF, this);
     prefs->RemoveObserver(DISALLOW_COMPLETION_TABLE_PREF, this);
     prefs->RemoveObserver(CONFIRM_AGE_PREF, this);
   }
--- a/toolkit/components/url-classifier/tests/mochitest/chrome.ini
+++ b/toolkit/components/url-classifier/tests/mochitest/chrome.ini
@@ -1,9 +1,11 @@
 [DEFAULT]
 skip-if = buildapp == 'b2g'
 support-files =
   allowlistAnnotatedFrame.html
   classifiedAnnotatedFrame.html
+  classifiedAnnotatedPBFrame.html
 
 [test_lookup_system_principal.html]
 [test_classified_annotations.html]
 [test_allowlisted_annotations.html]
+[test_privatebrowsing_trackingprotection.html]
new file mode 100644
--- /dev/null
+++ b/toolkit/components/url-classifier/tests/mochitest/classifiedAnnotatedPBFrame.html
@@ -0,0 +1,22 @@
+<!DOCTYPE HTML>
+<!-- Any copyright is dedicated to the Public Domain.
+     http://creativecommons.org/publicdomain/zero/1.0/ -->
+<html>
+<head>
+<title></title>
+
+<link id="badcss" rel="stylesheet" type="text/css" href="http://tracking.example.com/tests/toolkit/components/url-classifier/tests/mochitest/evil.css"></link>
+
+</head>
+<body>
+
+<script id="badscript" data-touched="not sure" src="http://tracking.example.com/tests/toolkit/components/url-classifier/tests/mochitest/evil.js" onload="this.dataset.touched = 'yes';" onerror="this.dataset.touched = 'no';"></script>
+
+<!-- The image cache can cache JS handlers, so make sure we use a different URL for raptor.jpg each time -->
+<img id="badimage" data-touched="not sure" src="http://tracking.example.com/tests/toolkit/components/url-classifier/tests/mochitest/raptor.jpg?pbmode=test" onload="this.dataset.touched = 'yes';" onerror="this.dataset.touched = 'no';"/>
+
+The following should not be hidden:
+<div id="styleCheck">STYLE TEST</div>
+
+</body>
+</html>
new file mode 100644
--- /dev/null
+++ b/toolkit/components/url-classifier/tests/mochitest/test_privatebrowsing_trackingprotection.html
@@ -0,0 +1,184 @@
+<!DOCTYPE HTML>
+<!-- Any copyright is dedicated to the Public Domain.
+     http://creativecommons.org/publicdomain/zero/1.0/ -->
+<html>
+<head>
+  <title>Test Tracking Protection in Private Browsing mode</title>
+  <script type="text/javascript" src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"></script>
+  <link rel="stylesheet" type="text/css" href="chrome://mochikit/content/tests/SimpleTest/test.css">
+</head>
+
+<body>
+<p id="display"></p>
+<div id="content" style="display: none">
+</div>
+<pre id="test">
+
+<script class="testbody" type="text/javascript">
+
+var Cc = SpecialPowers.Cc;
+var Ci = SpecialPowers.Ci;
+
+var mainWindow = window.QueryInterface(Ci.nsIInterfaceRequestor)
+                    .getInterface(Ci.nsIWebNavigation)
+                    .QueryInterface(Ci.nsIDocShellTreeItem)
+                    .rootTreeItem
+                    .QueryInterface(Ci.nsIInterfaceRequestor)
+                    .getInterface(Ci.nsIDOMWindow);
+var contentPage = "chrome://mochitests/content/chrome/toolkit/components/url-classifier/tests/mochitest/classifiedAnnotatedPBFrame.html"
+
+Components.utils.import("resource://gre/modules/Services.jsm");
+
+function whenDelayedStartupFinished(aWindow, aCallback) {
+  Services.obs.addObserver(function observer(aSubject, aTopic) {
+    if (aWindow == aSubject) {
+      Services.obs.removeObserver(observer, aTopic);
+      setTimeout(aCallback, 0);
+    }
+  }, "browser-delayed-startup-finished", false);
+}
+
+function testOnWindow(aPrivate, aCallback) {
+  var win = mainWindow.OpenBrowserWindow({private: aPrivate});
+  win.addEventListener("load", function onLoad() {
+    win.removeEventListener("load", onLoad, false);
+    whenDelayedStartupFinished(win, function() {
+      win.addEventListener("DOMContentLoaded", function onInnerLoad() {
+        if (win.content.location.href != contentPage) {
+          win.gBrowser.loadURI(contentPage);
+          return;
+        }
+        win.removeEventListener("DOMContentLoaded", onInnerLoad, true);
+
+        win.content.addEventListener('load', function innerLoad2() {
+          win.content.removeEventListener('load', innerLoad2, false);
+          SimpleTest.executeSoon(function() { aCallback(win); });
+        }, false, true);
+      }, true);
+      SimpleTest.executeSoon(function() { win.gBrowser.loadURI(contentPage); });
+    });
+  }, true);
+}
+
+// Add some URLs to the tracking database
+var testData = "tracking.example.com/";
+var testUpdate =
+  "n:1000\ni:test-track-simple\nad:1\n" +
+  "a:524:32:" + testData.length + "\n" +
+  testData;
+
+var badids = [
+  "badscript",
+  "badimage",
+  "badcss"
+];
+
+function checkLoads(aWindow, aBlocked) {
+  var win = aWindow.content;
+  is(win.document.getElementById("badscript").dataset.touched, aBlocked ? "no" : "yes", "Should not load tracking javascript");
+  is(win.document.getElementById("badimage").dataset.touched, aBlocked ? "no" : "yes", "Should not load tracking images");
+
+  var elt = win.document.getElementById("styleCheck");
+  var style = win.document.defaultView.getComputedStyle(elt, "");
+  isnot(style.visibility, aBlocked ? "hidden" : "", "Should not load tracking css");
+
+  is(win.document.blockedTrackingNodeCount, aBlocked ? badids.length : 0, "Should identify all tracking elements");
+
+  var blockedTrackingNodes = win.document.blockedTrackingNodes;
+
+  // Make sure that every node in blockedTrackingNodes exists in the tree
+  // (that may not always be the case but do not expect any nodes to disappear
+  // from the tree here)
+  var allNodeMatch = true;
+  for (var i = 0; i < blockedTrackingNodes.length; i++) {
+    var nodeMatch = false;
+    for (var j = 0; j < badids.length && !nodeMatch; j++) {
+      nodeMatch |=
+        (blockedTrackingNodes[i] == win.document.getElementById(badids[j]));
+    }
+
+    allNodeMatch &= nodeMatch;
+  }
+  is(allNodeMatch, true, "All annotated nodes are expected in the tree");
+
+  // Make sure that every node with a badid (see badids) is found in the
+  // blockedTrackingNodes. This tells us if we are neglecting to annotate
+  // some nodes
+  allNodeMatch = true;
+  for (var j = 0; j < badids.length; j++) {
+    var nodeMatch = false;
+    for (var i = 0; i < blockedTrackingNodes.length && !nodeMatch; i++) {
+      nodeMatch |=
+        (blockedTrackingNodes[i] == win.document.getElementById(badids[j]));
+    }
+
+    allNodeMatch &= nodeMatch;
+  }
+  is(allNodeMatch, aBlocked, "All tracking nodes are expected to be annotated as such");
+}
+
+var dbService = Cc["@mozilla.org/url-classifier/dbservice;1"]
+                .getService(Ci.nsIUrlClassifierDBService);
+
+function doUpdate(update) {
+  var listener = {
+    QueryInterface: function(iid)
+    {
+      if (iid.equals(Ci.nsISupports) ||
+          iid.equals(Ci.nsIUrlClassifierUpdateObserver))
+        return this;
+
+      throw Cr.NS_ERROR_NO_INTERFACE;
+    },
+    updateUrlRequested: function(url) { },
+    streamFinished: function(status) { },
+    updateError: function(errorCode) {
+      ok(false, "Couldn't update classifier.");
+      // Abort test.
+      SimpleTest.finish();
+    },
+    updateSuccess: function(requestedTimeout) {
+      // Normal mode, with the pref (trackers should be loaded)
+      testOnWindow(false, function(aWindow) {
+        checkLoads(aWindow, false);
+        aWindow.close();
+
+        // Private Browsing, with the pref (trackers should be blocked)
+        testOnWindow(true, function(aWindow) {
+          checkLoads(aWindow, true);
+          aWindow.close();
+
+          // Private Browsing, without the pref (trackers should be loaded)
+          SpecialPowers.setBoolPref("privacy.trackingprotection.pbmode.enabled", false);
+          testOnWindow(true, function(aWindow) {
+             checkLoads(aWindow, false);
+             aWindow.close();
+             SimpleTest.finish();
+          });
+        });
+      });
+    }
+  };
+
+  dbService.beginUpdate(listener, "test-track-simple", "");
+  dbService.beginStream("", "");
+  dbService.updateStream(update);
+  dbService.finishStream();
+  dbService.finishUpdate();
+}
+
+SpecialPowers.pushPrefEnv(
+  {"set" : [["urlclassifier.trackingTable", "test-track-simple"],
+            ["privacy.trackingprotection.enabled", false],
+            ["privacy.trackingprotection.pbmode.enabled", true],
+            ["channelclassifier.allowlist_example", true]]},
+  function() { doUpdate(testUpdate); });
+
+SimpleTest.waitForExplicitFinish();
+
+</script>
+
+</pre>
+<iframe id="testFrame" width="100%" height="100%" onload=""></iframe>
+</body>
+</html>