Bug 1509047 - Part 1: Add a permission manager API for enumerating all permissions with a type prefix r=nika
authorEhsan Akhgari <ehsan@mozilla.com>
Tue, 27 Nov 2018 16:50:39 +0000
changeset 507551 7f46f3f93ec7cf9d3374178eb801e9804299ad3b
parent 507550 b11a6804aaca52027b9df7c228d28f1b317ad2d0
child 507552 7ac08d9d34640922c7b9593eb9ca3d12f56432b7
push id1905
push userffxbld-merge
push dateMon, 21 Jan 2019 12:33:13 +0000
treeherdermozilla-release@c2fca1944d8c [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersnika
bugs1509047
milestone65.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 1509047 - Part 1: Add a permission manager API for enumerating all permissions with a type prefix r=nika Differential Revision: https://phabricator.services.mozilla.com/D12862
extensions/cookie/nsPermissionManager.cpp
extensions/cookie/test/unit/test_permmanager_getAllWithTypePrefix.js
extensions/cookie/test/unit/xpcshell.ini
netwerk/base/nsIPermissionManager.idl
--- a/extensions/cookie/nsPermissionManager.cpp
+++ b/extensions/cookie/nsPermissionManager.cpp
@@ -2570,57 +2570,77 @@ nsPermissionManager::GetPermissionHashKe
   }
 
   // No entry, really...
   return nullptr;
 }
 
 NS_IMETHODIMP nsPermissionManager::GetEnumerator(nsISimpleEnumerator **aEnum)
 {
+  nsTArray<RefPtr<nsIPermission>> array;
+  nsresult rv = GetAllWithTypePrefix(NS_LITERAL_CSTRING(""), array);
+  if (NS_WARN_IF(NS_FAILED(rv))) {
+    return rv;
+  }
+
+  nsCOMArray<nsIPermission> comArray;
+  comArray.SetCapacity(array.Length());
+  for (size_t i = 0; i < array.Length(); i++) {
+    comArray.AppendElement(array[i].forget());
+  }
+
+  return NS_NewArrayEnumerator(aEnum, comArray, NS_GET_IID(nsIPermission));
+}
+
+NS_IMETHODIMP nsPermissionManager::GetAllWithTypePrefix(const nsACString& aPrefix,
+                                                        nsTArray<RefPtr<nsIPermission>>& aResult)
+{
+  aResult.Clear();
   if (XRE_IsContentProcess()) {
-    NS_WARNING("nsPermissionManager's enumerator is not available in the "
+    NS_WARNING("nsPermissionManager's getAllWithTypePrefix is not available in the "
                "content process, as not all permissions may be available.");
-    *aEnum = nullptr;
     return NS_ERROR_NOT_AVAILABLE;
   }
 
-  // roll an nsCOMArray of all our permissions, then hand out an enumerator
-  nsCOMArray<nsIPermission> array;
-
   for (auto iter = mPermissionTable.Iter(); !iter.Done(); iter.Next()) {
     PermissionHashKey* entry = iter.Get();
     for (const auto& permEntry : entry->GetPermissions()) {
       // Given how "default" permissions work and the possibility of them being
       // overridden with UNKNOWN_ACTION, we might see this value here - but we
       // do *not* want to return them via the enumerator.
       if (permEntry.mPermission == nsIPermissionManager::UNKNOWN_ACTION) {
         continue;
       }
 
+      if (!aPrefix.IsEmpty() &&
+          !StringBeginsWith(mTypeArray.ElementAt(permEntry.mType), aPrefix)) {
+        continue;
+      }
+
       nsCOMPtr<nsIPrincipal> principal;
       nsresult rv = GetPrincipalFromOrigin(entry->GetKey()->mOrigin,
                                            getter_AddRefs(principal));
       if (NS_FAILED(rv)) {
         continue;
       }
 
-      nsCOMPtr<nsIPermission> permission =
+      RefPtr<nsIPermission> permission =
         nsPermission::Create(principal,
                              mTypeArray.ElementAt(permEntry.mType),
                              permEntry.mPermission,
                              permEntry.mExpireType,
                              permEntry.mExpireTime);
       if (NS_WARN_IF(!permission)) {
         continue;
       }
-      array.AppendObject(permission);
+      aResult.AppendElement(std::move(permission));
     }
   }
 
-  return NS_NewArrayEnumerator(aEnum, array, NS_GET_IID(nsIPermission));
+  return NS_OK;
 }
 
 NS_IMETHODIMP nsPermissionManager::GetAllForURI(nsIURI* aURI, nsISimpleEnumerator **aEnum)
 {
   nsCOMPtr<nsIPrincipal> principal;
   nsresult rv = GetPrincipal(aURI, getter_AddRefs(principal));
   NS_ENSURE_SUCCESS(rv, rv);
 
new file mode 100644
--- /dev/null
+++ b/extensions/cookie/test/unit/test_permmanager_getAllWithTypePrefix.js
@@ -0,0 +1,69 @@
+/* Any copyright is dedicated to the Public Domain.
+   http://creativecommons.org/publicdomain/zero/1.0/ */
+
+function check_enumerator(prefix, permissions) {
+  let pm = Cc["@mozilla.org/permissionmanager;1"]
+           .getService(Ci.nsIPermissionManager);
+
+  let array = pm.getAllWithTypePrefix(prefix);
+  for (let [uri, type, capability] of permissions) {
+    let perm = array.shift();
+    Assert.ok(perm != null);
+    Assert.ok(perm.principal.URI.equals(uri));
+    Assert.equal(perm.type, type);
+    Assert.equal(perm.capability, capability);
+    Assert.equal(perm.expireType, pm.EXPIRE_NEVER);
+  }
+  Assert.equal(array.length, 0);
+}
+
+function run_test() {
+  let pm = Cc["@mozilla.org/permissionmanager;1"]
+           .getService(Ci.nsIPermissionManager);
+
+  let uri = NetUtil.newURI("http://example.com");
+  let sub = NetUtil.newURI("http://sub.example.com");
+
+  check_enumerator("test/", [ ]);
+
+  pm.add(uri, "test/getallwithtypeprefix", pm.ALLOW_ACTION);
+  pm.add(sub, "other-test/getallwithtypeprefix", pm.PROMPT_ACTION);
+  check_enumerator("test/", [
+    [ uri, "test/getallwithtypeprefix", pm.ALLOW_ACTION ],
+  ]);
+
+  pm.add(sub, "test/getallwithtypeprefix", pm.PROMPT_ACTION);
+  check_enumerator("test/", [
+    [ sub, "test/getallwithtypeprefix", pm.PROMPT_ACTION ],
+    [ uri, "test/getallwithtypeprefix", pm.ALLOW_ACTION ],
+  ]);
+
+  check_enumerator("test/getallwithtypeprefix", [
+    [ sub, "test/getallwithtypeprefix", pm.PROMPT_ACTION ],
+    [ uri, "test/getallwithtypeprefix", pm.ALLOW_ACTION ],
+  ]);
+
+  // check that UNKNOWN_ACTION permissions are ignored
+  pm.add(uri, "test/getallwithtypeprefix2", pm.UNKNOWN_ACTION);
+  check_enumerator("test/", [
+    [ sub, "test/getallwithtypeprefix", pm.PROMPT_ACTION ],
+    [ uri, "test/getallwithtypeprefix", pm.ALLOW_ACTION ],
+  ]);
+
+  // check that permission updates are reflected
+  pm.add(uri, "test/getallwithtypeprefix", pm.PROMPT_ACTION);
+  check_enumerator("test/", [
+    [ sub, "test/getallwithtypeprefix", pm.PROMPT_ACTION ],
+    [ uri, "test/getallwithtypeprefix", pm.PROMPT_ACTION ],
+  ]);
+
+  // check that permission removals are reflected
+  pm.remove(uri, "test/getallwithtypeprefix");
+  check_enumerator("test/", [
+    [ sub, "test/getallwithtypeprefix", pm.PROMPT_ACTION ],
+  ]);
+
+  pm.removeAll();
+  check_enumerator("test/", [ ]);
+}
+
--- a/extensions/cookie/test/unit/xpcshell.ini
+++ b/extensions/cookie/test/unit/xpcshell.ini
@@ -16,16 +16,17 @@ skip-if = true # Bug 863738
 [test_cookies_thirdparty_nonsecure_session.js]
 [test_cookies_thirdparty_session.js]
 [test_domain_eviction.js]
 [test_eviction.js]
 [test_permmanager_default_pref.js]
 [test_permmanager_defaults.js]
 [test_permmanager_expiration.js]
 [test_permmanager_getAllForURI.js]
+[test_permmanager_getAllWithTypePrefix.js]
 [test_permmanager_getPermissionObject.js]
 [test_permmanager_notifications.js]
 [test_permmanager_removeall.js]
 [test_permmanager_removebytype.js]
 [test_permmanager_removesince.js]
 [test_permmanager_removeforapp.js]
 [test_permmanager_load_invalid_entries.js]
 skip-if = debug == true
--- a/netwerk/base/nsIPermissionManager.idl
+++ b/netwerk/base/nsIPermissionManager.idl
@@ -121,16 +121,26 @@ interface nsIPermissionManager : nsISupp
    * enumerator of all permissions which are not set to default and which
    * belong to the matching principal of the given nsIPrincipal.
    *
    * @param principal  the URI to get all permissions for
    */
   nsISimpleEnumerator getAllForPrincipal(in nsIPrincipal principal);
 
   /**
+   * Get all custom permissions of a specific type, specified with a prefix
+   * string.  This will return an array of all permissions which are not set to
+   * default.  Also the passed type argument is either equal to or a prefix of
+   * the type of the returned permissions.
+   *
+   * @param prefix  the type prefix string
+   */
+  Array<nsIPermission> getAllWithTypePrefix(in ACString prefix);
+
+  /**
    * Add permission information for a given principal.
    * It is internally calling the other add() method using the nsIURI from the
    * principal.
    * Passing a system principal will be a no-op because they will always be
    * granted permissions.
    */
   void addFromPrincipal(in nsIPrincipal principal, in string type,
                         in uint32_t permission,