Bug 1269195 - Display non domain permissions and preferences under global data domain in Data Manager r=Ratty a=Ratty
authorFrank-Rainer Grahl <frgrahl@gmx.net>
Mon, 09 May 2016 17:07:11 +0200
changeset 24871 814f87ba88b5b8ae366eb33c3c86b3c273a856b0
parent 24870 b8752b0337f931f16444666cebb7e3a66980b4a8
child 24872 239ff6070e8ef005c88cb4fd57cf79bac5493afa
push id1657
push userclokep@gmail.com
push dateMon, 06 Jun 2016 19:50:21 +0000
treeherdercomm-beta@9fac989284b5 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersRatty, Ratty
bugs1269195
Bug 1269195 - Display non domain permissions and preferences under global data domain in Data Manager r=Ratty a=Ratty
suite/common/dataman/dataman.js
--- a/suite/common/dataman/dataman.js
+++ b/suite/common/dataman/dataman.js
@@ -101,32 +101,16 @@ var gDataman = {
     // Empty domain with a pane specified will only list this data type
     // Permissions allow specifying "add" and type to prefill the adding field
     this.viewToLoad = aView.split('|');
     if (gDomains.listLoadCompleted)
       gDomains.loadView();
     // Else will call this at the end of loading the list.
   },
 
-  checkValidPermission: function dataman_checkValidPermission(aPermission) {
-    // It is currently possible to add a permission for about:xxx and other internal pages.
-    // These are probably invalid and will be ignored for now.
-    // Test if the permission has a host. If not consider it invalid for now.
-    try {
-       aPermission.principal.URI.host;
-     }
-     catch (e) {
-       gDataman.debugError("Invalid permission found: " +
-                           aPermission.principal.origin + " " +
-                           aPermission.type);
-       return false;
-     }
-     return true;
-  },
-
   handleKeyPress: function dataman_handleKeyPress(aEvent) {
     if (aEvent.keyCode == KeyEvent.DOM_VK_ESCAPE &&
         gTabs.tabbox.selectedPanel &&
         gTabs.tabbox.selectedPanel.id == "forgetPanel") {
       gForget.handleKeyPress(aEvent);
     }
   },
 
@@ -306,18 +290,22 @@ var gDomains = {
 
       // Add domains for permissions.
       gDataman.debugMsg("Add permissions to domain list: " + Date.now()/1000);
       gDomains.ignoreUpdate = true;
       let enumerator = Services.perms.enumerator;
       while (enumerator.hasMoreElements()) {
         let nextPermission = enumerator.getNext().QueryInterface(Components.interfaces.nsIPermission);
 
-        if (gDataman.checkValidPermission(nextPermission))
+        if (!gDomains.commonScheme(nextPermission.principal.URI.scheme)) {
+          gDomains.addDomainOrFlag("*", "hasPermissions");
+        }
+        else {
           gDomains.addDomainOrFlag(nextPermission.principal.URI.host.replace(/^\./, ""), "hasPermissions");
+        }
       }
       gDomains.ignoreUpdate = false;
       gDomains.search(gDomains.searchfield.value);
       yield setTimeout(nextStep, 0);
 
       // Add domains for password rejects to permissions.
       gDataman.debugMsg("Add pwd reject permissions to domain list: " + Date.now()/1000);
       gDomains.ignoreUpdate = true;
@@ -328,18 +316,21 @@ var gDomains = {
       gDomains.search(gDomains.searchfield.value);
       yield setTimeout(nextStep, 0);
 
       // Add domains for content prefs.
       gDataman.debugMsg("Add content prefs to domain list: " + Date.now()/1000);
       gDomains.ignoreUpdate = true;
       try {
         var statement = Services.contentPrefs.DBConnection.createStatement("SELECT groups.name AS host FROM groups");
-        while (statement.executeStep())
-          gDomains.addDomainOrFlag(statement.row["host"], "hasPreferences");
+        while (statement.executeStep()) {
+          gDataman.debugMsg("Found pref: " + statement.row["host"]);
+          let prefHost = gDomains.getDomainFromHostWithCheck(statement.row["host"]);
+          gDomains.addDomainOrFlag(prefHost, "hasPreferences");
+        }
       }
       finally {
         statement.reset();
       }
       gDomains.ignoreUpdate = false;
       gDomains.search(gDomains.searchfield.value);
       yield setTimeout(nextStep, 0);
 
@@ -498,16 +489,27 @@ var gDomains = {
     loaderInstance = loader();
     setTimeout(nextStep, 0);
   },
 
   _getObjID: function domain__getObjID(aIdx) {
     return gDomains.displayedDomains[aIdx].title;
   },
 
+  getDomainFromHostWithCheck: function domain_getDomainFromHostWithCheck(aHost)  {
+    let host = gDomains.getDomainFromHost(aHost).trim();
+    // Host couldn't be found and 2 static references for internal pages and data.
+    if (host.trim().length == 0 ||
+        aHost.startsWith("about:") ||
+        aHost.startsWith("jar:"))
+      return '*';
+
+    return host;
+  },
+
   getDomainFromHost: function domain_getDomainFromHost(aHostname) {
     // Find the base domain name for the given host name.
     if (!this.xlcache[aHostname]) {
       // aHostname is not always an actual host name, but potentially something
       // URI-like, e.g. gopher://example.com and newURI doesn't work there as we
       // need to display entries for schemes that are not supported (any more).
       // nsIURLParser is a fast way to generically ensure a pure host name.
       var hostName;
@@ -539,33 +541,64 @@ var gDomains = {
         }
       }
 
       var domain;
       try {
         domain = Services.eTLD.getBaseDomainFromHost(hostName);
       }
       catch (e) {
-        gDataman.debugError("Error while trying to get domain from host name: " + hostName);
-        gDataman.debugError(e);
+        gDataman.debugMsg("Unable to get domain from host name: " + hostName);
         domain = hostName;
       }
       this.xlcache[aHostname] = domain;
       gDataman.debugMsg("cached: " + aHostname + " -> " + this.xlcache[aHostname]);
-    }
+    } // end hostname not cached
     return this.xlcache[aHostname];
   },
 
+  // Used for checking if * global data domain should be used.
+  commonScheme: function domain_commonScheme(aScheme) {
+    // case intensitive search for domain schemes
+    return /^(https?|ftp|gopher)/i.test(aScheme);
+  },
+
   hostMatchesSelected: function domain_hostMatchesSelected(aHostname) {
     return this.getDomainFromHost(aHostname) == this.selectedDomain.title;
   },
 
+  hostMatchesSelectedURI: function domain_hostMatchesSelectedURI(aURI) {
+    // default to * global data domain.
+    let mScheme = "*";
+
+    // First, try to get the scheme.
+    try {
+      mScheme = aURI.scheme;
+    }
+    catch (e) {
+      gDataman.debugError("Invalid permission found: " + aUri);
+    }
+
+    // See if his is a scheme which does not go into the global data domain.
+    if (!this.commonScheme(mScheme)) {
+      return ("*") == this.selectedDomain.title;
+    }
+
+    rawHost = aURI.host.replace(/^\./, "");
+    return this.getDomainFromHost(rawHost) == this.selectedDomain.title;
+  },
+
   addDomainOrFlag: function domain_addDomainOrFlag(aHostname, aFlag) {
+    let domain;
     // For existing domains, add flags, for others, add them to the object.
-    let domain = this.getDomainFromHost(aHostname);
+    if (aHostname == "*")
+      domain = aHostname;
+    else
+      domain = this.getDomainFromHost(aHostname);
+
     if (!this.domainObjects[domain]) {
       this.domainObjects[domain] = {title: domain};
       if (/xn--/.test(domain))
         this.domainObjects[domain].displayTitle = gLocSvc.idn.convertToDisplayIDN(domain, {});
       else
         this.domainObjects[domain].displayTitle = this.domainObjects[domain].title;
       this.domainObjects[domain][aFlag] = true;
       gDataman.debugMsg("added domain: " + domain + " (with flag " + aFlag + ")");
@@ -1286,22 +1319,17 @@ var gPerms = {
     this.addButton = document.getElementById("permAddButton");
 
     let enumerator = Services.perms.enumerator;
 
     while (enumerator.hasMoreElements()) {
       let nextPermission = enumerator.getNext();
       nextPermission = nextPermission.QueryInterface(Components.interfaces.nsIPermission);
 
-      if (!gDataman.checkValidPermission(nextPermission))
-         continue;
-
-      let rawHost = nextPermission.principal.URI.host.replace(/^\./, "");
-
-      if (gDomains.hostMatchesSelected(rawHost)) {
+      if (gDomains.hostMatchesSelectedURI(nextPermission.principal.URI)) {
         let permElem = document.createElement("richlistitem");
         permElem.setAttribute("type", nextPermission.type);
         permElem.setAttribute("host", nextPermission.principal.origin);
         permElem.setAttribute("displayHost", nextPermission.principal.origin);
         permElem.setAttribute("capability", nextPermission.capability);
         permElem.setAttribute("class", "permission");
         gDataman.debugMsg("Adding Origin: " + nextPermission.principal.origin);
         this.list.appendChild(permElem);
@@ -1572,22 +1600,31 @@ var gPerms = {
       gDomains.resetFlagToDomains("hasPermissions", domainList);
       return;
     }
 
     gDataman.debugMsg("react to change: " + aSubject.principal.origin + " " + aData);
 
     aSubject.QueryInterface(Components.interfaces.nsIPermission);
 
-    let rawHost = aSubject.principal.URI.host.replace(/^\./, "");
-    let domain = gDomains.getDomainFromHost(rawHost);
+    let rawHost;
+    let domain;
+
+    if (!gDomains.commonScheme(aSubject.principal.URI.scheme)) {
+      rawHost = "*";
+      domain = "*";
+    }
+    else {
+      rawHost = aSubject.principal.URI.host.replace(/^\./, "");
+      domain = gDomains.getDomainFromHost(rawHost);
+    }
 
     // Does change affect possibly loaded Preferences pane?
     let affectsLoaded = this.list && this.list.childElementCount &&
-                        gDomains.hostMatchesSelected(rawHost);
+                        gDomains.hostMatchesSelectedURI(aSubject.principal.URI);
 
     let permElem = null;
 
     if (affectsLoaded) {
       for (let lChild of this.list.children) {
         gDataman.debugMsg("checking type: " + lChild.getAttribute("class") + " " +
                           lChild.getAttribute("type") + " " + aSubject.type);
 
@@ -1605,20 +1642,26 @@ var gPerms = {
       else {
         // Only remove if domain is not shown, note that this may leave an empty domain.
         let haveDomainPerms = false;
         let enumerator = Services.perms.enumerator;
         while (enumerator.hasMoreElements()) {
           let nextPermission = enumerator.getNext();
           nextPermission = nextPermission.QueryInterface(Components.interfaces.nsIPermission);
 
-          if (!gDataman.checkValidPermission(nextPermission))
-            continue;
-
-          if (domain == gDomains.getDomainFromHost(nextPermission.principal.URI.host.replace(/^\./, ""))) {
+          let dDomain;
+
+          if (!gDomains.commonScheme(nextPermission.principal.URI.scheme)) {
+            dDomain = "*";
+          }
+          else {
+            dDomain = gDomains.getDomainFromHost(nextPermission.principal.URI.host.replace(/^\./, ""));
+          }
+
+          if (domain == dDomain) {
             haveDomainPerms = true;
             break;
           }
         }
         if (!haveDomainPerms)
           gDomains.removeDomainOrFlag(domain, "hasPermissions");
       }
     }
@@ -1669,21 +1712,17 @@ var gPerms = {
   // deleted (forget).
   forget: function permissions_forget() {
     let delPerms = [];
     let enumerator = Services.perms.enumerator;
     while (enumerator.hasMoreElements()) {
       let nextPermission = enumerator.getNext();
       nextPermission = nextPermission.QueryInterface(Components.interfaces.nsIPermission);
 
-      if (!gDataman.checkValidPermission(nextPermission))
-        continue;
-
-      let host = nextPermission.principal.URI.host;
-      if (gDomains.hostMatchesSelected(host.replace(/^\./, ""))) {
+      if (gDomains.hostMatchesSelectedURI(nextPermission.principal.URI)) {
         delPerms.push({principal: nextPermission.principal, type: nextPermission.type});
       }
     }
 
     // Loop backwards so later indexes in the list don't change.
     for (let i = delPerms.length - 1; i >= 0; i--) {
       Services.perms.removeFromPrincipal(delPerms[i].principal, delPerms[i].type);
     }
@@ -1857,51 +1896,46 @@ var gPrefs = {
     this.tree = document.getElementById("prefsTree");
     this.tree.view = this;
 
     this.removeButton = document.getElementById("prefsRemove");
 
     this.tree.treeBoxObject.beginUpdateBatch();
     // Get all groups (hosts) that match the domain.
     let domain = gDomains.selectedDomain.title;
+
     if (domain == "*") {
       let enumerator = Services.contentPrefs.getPrefs(null, null).enumerator;
       while (enumerator.hasMoreElements()) {
         let pref = enumerator.getNext().QueryInterface(Components.interfaces.nsIProperty);
         this.prefs.push({host: null, name: pref.name, value: pref.value});
       }
     }
-    else {
-      try {
-        let sql = "SELECT groups.name AS host FROM groups " +
-                  "WHERE host = :hostName OR host = :hostIDNName OR " +
-                         "host LIKE :hostMatch OR host LIKE :hostIDNMatch " +
-                  "ESCAPE '/'";
-        var statement = Services.contentPrefs.DBConnection.createStatement(sql);
-        let idnDomain = gLocSvc.idn.convertToDisplayIDN(domain, {});
-        statement.params.hostName = domain;
-        statement.params.hostIDNName = idnDomain;
-        statement.params.hostMatch = "%." + statement.escapeStringForLIKE(domain, "/");
-        statement.params.hostIDNMatch = "%." + statement.escapeStringForLIKE(idnDomain, "/");
-        while (statement.executeStep()) {
+
+    try {
+      var statement = Services.contentPrefs.DBConnection.createStatement("SELECT groups.name AS host FROM groups");
+
+      while (statement.executeStep()) {
+        if (gDomains.hostMatchesSelected(gDomains.getDomainFromHostWithCheck(statement.row["host"]))) {
           // Now, get all prefs for that host.
           let enumerator =  Services.contentPrefs.getPrefs(statement.row["host"], null).enumerator;
           while (enumerator.hasMoreElements()) {
             let pref = enumerator.getNext().QueryInterface(Components.interfaces.nsIProperty);
             this.prefs.push({host: statement.row["host"],
                              displayHost: gLocSvc.idn.convertToDisplayIDN(statement.row["host"], {}),
                              name: pref.name,
                              value: pref.value});
           }
         }
       }
-      finally {
-        statement.reset();
-      }
     }
+    finally {
+      statement.reset();
+    }
+
     this.sort(null, false, false);
     this.tree.treeBoxObject.endUpdateBatch();
   },
 
   shutdown: function prefs_shutdown() {
     gDataman.debugMsg("Shutting down prefs panel");
     this.tree.view.selection.clearSelection();
     this.tree.view = null;
@@ -2024,109 +2058,117 @@ var gPrefs = {
     document.getElementById("prefs-context-remove").disabled =
       this.removeButton.disabled;
     document.getElementById("prefs-context-selectall").disabled =
       this.tree.view.selection.count >= this.tree.view.rowCount;
   },
 
   reactToChange: function prefs_reactToChange(aSubject, aData) {
     // aData: prefSet, prefRemoved
-
+    gDataman.debugMsg("Observed pref change for: " + aSubject.host);
     // Do "surgical" updates.
-    let domain = gDomains.getDomainFromHost(aSubject.host);
+    let domain = gDomains.getDomainFromHostWithCheck(aSubject.host);
+    gDataman.debugMsg("domain: " + domain);
     // Does change affect possibly loaded Preferences pane?
     let affectsLoaded = this.prefs.length &&
-                        gDomains.hostMatchesSelected(aSubject.host);
+                        (domain == gDomains.selectedDomain.title);
+
     let idx = -1, domainPrefs = 0;
     if (affectsLoaded) {
+      gDataman.debugMsg("affects loaded");
       for (let i = 0; i < this.prefs.length; i++) {
         let cpref = this.prefs[i];
         if (cpref && cpref.host == aSubject.host && cpref.name == aSubject.name) {
-          idx = this.prefs[i];
+          idx = i;
           break;
         }
       }
       if (aData == "prefRemoved")
         domainPrefs = this.prefs.length;
     }
     else if (aData == "prefRemoved") {
       // See if there are any prefs left for that domain.
       if (domain == "*") {
         let enumerator = Services.contentPrefs.getPrefs(null, null).enumerator;
         if (enumerator.hasMoreElements())
           domainPrefs++;
       }
-      else {
-        try {
-          let sql = "SELECT groups.name AS host FROM groups WHERE host = :hostName OR host LIKE :hostMatch ESCAPE '/'";
-          var statement = Services.contentPrefs.DBConnection.createStatement(sql);
-          statement.params.hostName = domain;
-          statement.params.hostMatch = "%." + statement.escapeStringForLIKE(domain, "/");
-          while (statement.executeStep()) {
+
+      try {
+        let sql = "SELECT groups.name AS host FROM groups";
+        var statement = Services.contentPrefs.DBConnection.createStatement(sql);
+
+        while (statement.executeStep()) {
+          if (gDomains.hostMatchesSelected(gDomains.getDomainFromHostWithCheck(statement.row["host"]))) {
             // Now, get all prefs for that host.
             let enumerator = Services.contentPrefs.getPrefs(statement.row["host"], null).enumerator;
             if (enumerator.hasMoreElements())
               domainPrefs++;
           }
         }
-        finally {
-          statement.reset();
-        }
       }
+      finally {
+        statement.reset();
+      }
+
       if (!domainPrefs)
         gDomains.removeDomainOrFlag(domain, "hasPreferences");
     }
     if (aData == "prefSet")
         aSubject.displayHost = gLocSvc.idn.convertToDisplayIDN(aSubject.host, {});
+
+    // Affects loaded domain and is an existing pref.
     if (idx >= 0) {
       if (aData == "prefSet") {
         this.prefs[idx] = aSubject;
         if (affectsLoaded)
-          this.tree.treeBoxObject.invalidateRow(disp_idx);
+          this.tree.treeBoxObject.invalidateRow(idx);
       }
       else if (aData == "prefRemoved") {
         this.prefs.splice(idx, 1);
         if (affectsLoaded) {
           this.tree.treeBoxObject.rowCountChanged(idx, -1);
         }
         if (domainPrefs == 1)
           gDomains.removeDomainOrFlag(domain, "hasPreferences");
       }
     }
     else if (aData == "prefSet") {
+      // Affects loaded domain but is not an existing pref.
       // Pref set, no prev index known - either new or existing pref domain.
       if (affectsLoaded) {
         this.prefs.push(aSubject);
         this.tree.treeBoxObject.rowCountChanged(this.prefs.length - 1, 1);
         this.sort(null, true, false);
       }
+      // Not the loaded domain but it now has a preference.
       else {
-        gDomains.addDomainOrFlag(aSubject.host, "hasPreferences");
+        gDomains.addDomainOrFlag(domain, "hasPreferences");
       }
     }
   },
 
   forget: function prefs_forget() {
     let delPrefs = [];
     try {
       // Get all groups (hosts) that match the domain.
       let domain = gDomains.selectedDomain.title;
       if (domain == "*") {
         let enumerator =  Services.contentPrefs.getPrefs(null, null).enumerator;
         while (enumerator.hasMoreElements()) {
           let pref = enumerator.getNext().QueryInterface(Components.interfaces.nsIProperty);
           delPrefs.push({host: null, name: pref.name, value: pref.value});
         }
       }
-      else {
-        let sql = "SELECT groups.name AS host FROM groups WHERE host = :hostName OR host LIKE :hostMatch ESCAPE '/'";
-        var statement = Services.contentPrefs.DBConnection.createStatement(sql);
-        statement.params.hostName = domain;
-        statement.params.hostMatch = "%." + statement.escapeStringForLIKE(domain, "/");
-        while (statement.executeStep()) {
+
+      let sql = "SELECT groups.name AS host FROM groups";
+      var statement = Services.contentPrefs.DBConnection.createStatement(sql);
+
+      while (statement.executeStep()) {
+        if (gDomains.hostMatchesSelected(gDomains.getDomainFromHostWithCheck(statement.row["host"]))) {
           // Now, get all prefs for that host.
           let enumerator =  Services.contentPrefs.getPrefs(statement.row["host"], null).enumerator;
           while (enumerator.hasMoreElements()) {
             let pref = enumerator.getNext().QueryInterface(Components.interfaces.nsIProperty);
             delPrefs.push({host: statement.row["host"], name: pref.name, value: pref.value});
           }
         }
       }