Bug 874196 - Add an API to get the specifics of a permission given a host/type: this will allow the plugin click-to-activate UI to manage permissions by the matching host and determine whether the current permission is per-session or persistent. r=jdm sr=mounir
authorBenjamin Smedberg <benjamin@smedbergs.us>
Thu, 06 Jun 2013 15:59:31 -0400
changeset 145784 ce333beb74e20982ddf7dfed60218b0b580ed2c4
parent 145783 611893aff336e3149fdf08d2f34a7e63a221976b
child 145785 15df9914a1ad7c4500fd4c145ff1b73f683aaef5
push id2697
push userbbajaj@mozilla.com
push dateMon, 05 Aug 2013 18:49:53 +0000
treeherdermozilla-beta@dfec938c7b63 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersjdm, mounir
bugs874196
milestone24.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 874196 - Add an API to get the specifics of a permission given a host/type: this will allow the plugin click-to-activate UI to manage permissions by the matching host and determine whether the current permission is per-session or persistent. r=jdm sr=mounir
extensions/cookie/nsPermission.cpp
extensions/cookie/nsPermissionManager.cpp
extensions/cookie/test/unit/test_permmanager_getPermissionObject.js
extensions/cookie/test/unit/xpcshell.ini
netwerk/base/public/nsIPermissionManager.idl
--- a/extensions/cookie/nsPermission.cpp
+++ b/extensions/cookie/nsPermission.cpp
@@ -1,18 +1,20 @@
 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #include "nsPermission.h"
+#include "nsIClassInfoImpl.h"
 
 // nsPermission Implementation
 
-NS_IMPL_ISUPPORTS1(nsPermission, nsIPermission)
+NS_IMPL_CLASSINFO(nsPermission, nullptr, 0, {0})
+NS_IMPL_ISUPPORTS1_CI(nsPermission, nsIPermission)
 
 nsPermission::nsPermission(const nsACString &aHost,
                            uint32_t aAppId,
                            bool aIsInBrowserElement,
                            const nsACString &aType,
                            uint32_t         aCapability,
                            uint32_t         aExpireType,
                            int64_t          aExpireTime)
--- a/extensions/cookie/nsPermissionManager.cpp
+++ b/extensions/cookie/nsPermissionManager.cpp
@@ -1013,16 +1013,73 @@ nsPermissionManager::TestPermissionFromP
   if (nsContentUtils::IsSystemPrincipal(aPrincipal)) {
     *aPermission = nsIPermissionManager::ALLOW_ACTION;
     return NS_OK;
   }
 
   return CommonTestPermission(aPrincipal, aType, aPermission, false, true);
 }
 
+NS_IMETHODIMP
+nsPermissionManager::GetPermissionObject(nsIPrincipal* aPrincipal,
+                                         const char* aType,
+                                         bool aExactHostMatch,
+                                         nsIPermission** aResult)
+{
+  NS_ENSURE_ARG_POINTER(aPrincipal);
+  NS_ENSURE_ARG_POINTER(aType);
+
+  *aResult = nullptr;
+
+  if (nsContentUtils::IsSystemPrincipal(aPrincipal)) {
+    return NS_OK;
+  }
+
+  nsAutoCString host;
+  nsresult rv = GetHostForPrincipal(aPrincipal, host);
+  NS_ENSURE_SUCCESS(rv, rv);
+
+  int32_t typeIndex = GetTypeIndex(aType, false);
+  // If type == -1, the type isn't known,
+  // so just return NS_OK
+  if (typeIndex == -1) return NS_OK;
+
+  uint32_t appId;
+  rv = aPrincipal->GetAppId(&appId);
+  NS_ENSURE_SUCCESS(rv, rv);
+
+  bool isInBrowserElement;
+  rv = aPrincipal->GetIsInBrowserElement(&isInBrowserElement);
+  NS_ENSURE_SUCCESS(rv, rv);
+
+  PermissionHashKey* entry = GetPermissionHashKey(host, appId, isInBrowserElement,
+                                                  typeIndex, aExactHostMatch);
+  if (!entry) {
+    return NS_OK;
+  }
+
+  // We don't call GetPermission(typeIndex) because that returns a fake
+  // UNKNOWN_ACTION entry if there is no match.
+  int32_t idx = entry->GetPermissionIndex(typeIndex);
+  if (-1 == idx) {
+    return NS_OK;
+  }
+
+  PermissionEntry& perm = entry->GetPermissions()[idx];
+  nsCOMPtr<nsIPermission> r = new nsPermission(entry->GetKey()->mHost,
+                                               entry->GetKey()->mAppId,
+                                               entry->GetKey()->mIsInBrowserElement,
+                                               mTypeArray.ElementAt(perm.mType),
+                                               perm.mPermission,
+                                               perm.mExpireType,
+                                               perm.mExpireTime);
+  r.forget(aResult);
+  return NS_OK;
+}
+
 nsresult
 nsPermissionManager::CommonTestPermission(nsIPrincipal* aPrincipal,
                                           const char *aType,
                                           uint32_t   *aPermission,
                                           bool        aExactHostMatch,
                                           bool        aIncludingSession)
 {
   NS_ENSURE_ARG_POINTER(aPrincipal);
new file mode 100644
--- /dev/null
+++ b/extensions/cookie/test/unit/test_permmanager_getPermissionObject.js
@@ -0,0 +1,94 @@
+/* Any copyright is dedicated to the Public Domain.
+   http://creativecommons.org/publicdomain/zero/1.0/ */
+
+function getPrincipalFromURI(uri) {
+  return Cc["@mozilla.org/scriptsecuritymanager;1"]
+           .getService(Ci.nsIScriptSecurityManager)
+           .getNoAppCodebasePrincipal(NetUtil.newURI(uri));
+}
+
+function getSystemPrincipal() {
+  return Cc["@mozilla.org/scriptsecuritymanager;1"]
+           .getService(Ci.nsIScriptSecurityManager)
+           .getSystemPrincipal();
+}
+
+function run_test() {
+  var pm = Cc["@mozilla.org/permissionmanager;1"].
+           getService(Ci.nsIPermissionManager);
+
+  do_check_null(pm.getPermissionObject(getSystemPrincipal(), "test/pobject", false));
+
+  let principal = getPrincipalFromURI("http://example.com");
+  let subPrincipal = getPrincipalFromURI("http://sub.example.com");
+  let subSubPrincipal = getPrincipalFromURI("http://sub.sub.example.com");
+
+  do_check_null(pm.getPermissionObject(principal, "test/pobject", false));
+  do_check_null(pm.getPermissionObject(principal, "test/pobject", true));
+
+  pm.addFromPrincipal(principal, "test/pobject", pm.ALLOW_ACTION);
+  var rootPerm = pm.getPermissionObject(principal, "test/pobject", false);
+  do_check_true(rootPerm != null);
+  do_check_eq(rootPerm.host, "example.com");
+  do_check_eq(rootPerm.type, "test/pobject");
+  do_check_eq(rootPerm.capability, pm.ALLOW_ACTION);
+  do_check_eq(rootPerm.expireType, pm.EXPIRE_NEVER);
+
+  var rootPerm2 = pm.getPermissionObject(principal, "test/pobject", true);
+  do_check_true(rootPerm != null);
+  do_check_eq(rootPerm.host, "example.com");
+
+  var subPerm = pm.getPermissionObject(subPrincipal, "test/pobject", true);
+  do_check_null(subPerm);
+  subPerm = pm.getPermissionObject(subPrincipal, "test/pobject", false);
+  do_check_true(subPerm != null);
+  do_check_eq(subPerm.host, "example.com");
+  do_check_eq(subPerm.type, "test/pobject");
+  do_check_eq(subPerm.capability, pm.ALLOW_ACTION);
+
+  subPerm = pm.getPermissionObject(subSubPrincipal, "test/pobject", true);
+  do_check_null(subPerm);
+  subPerm = pm.getPermissionObject(subSubPrincipal, "test/pobject", false);
+  do_check_true(subPerm != null);
+  do_check_eq(subPerm.host, "example.com");
+
+  pm.addFromPrincipal(principal, "test/pobject", pm.DENY_ACTION, pm.EXPIRE_SESSION);
+
+  // make sure permission objects are not dynamic
+  do_check_eq(rootPerm.capability, pm.ALLOW_ACTION);
+
+  // but do update on change
+  rootPerm = pm.getPermissionObject(principal, "test/pobject", true);
+  do_check_eq(rootPerm.capability, pm.DENY_ACTION);
+  do_check_eq(rootPerm.expireType, pm.EXPIRE_SESSION);
+
+  subPerm = pm.getPermissionObject(subPrincipal, "test/pobject", false);
+  do_check_eq(subPerm.host, "example.com");
+  do_check_eq(subPerm.capability, pm.DENY_ACTION);
+  do_check_eq(subPerm.expireType, pm.EXPIRE_SESSION);
+
+  pm.addFromPrincipal(subPrincipal, "test/pobject", pm.PROMPT_ACTION);
+  rootPerm = pm.getPermissionObject(principal, "test/pobject", true);
+  do_check_eq(rootPerm.host, "example.com");
+  do_check_eq(rootPerm.capability, pm.DENY_ACTION);
+
+  subPerm = pm.getPermissionObject(subPrincipal, "test/pobject", true);
+  do_check_eq(subPerm.host, "sub.example.com");
+  do_check_eq(subPerm.capability, pm.PROMPT_ACTION);
+
+  subPerm = pm.getPermissionObject(subPrincipal, "test/pobject", false);
+  do_check_eq(subPerm.host, "sub.example.com");
+  do_check_eq(subPerm.capability, pm.PROMPT_ACTION);
+
+  subPerm = pm.getPermissionObject(subSubPrincipal, "test/pobject", true);
+  do_check_null(subPerm);
+
+  subPerm = pm.getPermissionObject(subSubPrincipal, "test/pobject", false);
+  do_check_eq(subPerm.host, "sub.example.com");
+  do_check_eq(subPerm.capability, pm.PROMPT_ACTION);
+
+  pm.removeFromPrincipal(principal, "test/pobject");
+
+  rootPerm = pm.getPermissionObject(principal, "test/pobject", true);
+  do_check_null(rootPerm);
+}
--- a/extensions/cookie/test/unit/xpcshell.ini
+++ b/extensions/cookie/test/unit/xpcshell.ini
@@ -11,16 +11,17 @@ tail =
 [test_cookies_profile_close.js]
 [test_cookies_read.js]
 [test_cookies_sync_failure.js]
 [test_cookies_thirdparty.js]
 [test_cookies_thirdparty_session.js]
 [test_domain_eviction.js]
 [test_eviction.js]
 [test_permmanager_expiration.js]
+[test_permmanager_getPermissionObject.js]
 [test_permmanager_notifications.js]
 [test_permmanager_removeall.js]
 [test_permmanager_load_invalid_entries.js]
 skip-if = debug == true
 [test_permmanager_idn.js]
 [test_permmanager_subdomains.js]
 [test_permmanager_local_files.js]
 [test_permmanager_cleardata.js]
--- a/netwerk/base/public/nsIPermissionManager.idl
+++ b/netwerk/base/public/nsIPermissionManager.idl
@@ -30,18 +30,19 @@
 
 #include "nsISupports.idl"
 #include "nsISimpleEnumerator.idl"
 
 interface nsIURI;
 interface nsIObserver;
 interface nsIPrincipal;
 interface nsIDOMWindow;
+interface nsIPermission;
 
-[scriptable, uuid(b38c982d-30bc-463f-9afc-0ca339eac03c)]
+[scriptable, uuid(f75e0a32-04cd-4ed4-ad2d-d08ca92bb98e)]
 interface nsIPermissionManager : nsISupports
 {
   /**
    * Predefined return values for the testPermission method and for
    * the permission param of the add method
    * NOTE: UNKNOWN_ACTION (0) is reserved to represent the
    * default permission when no entry is found for a host, and
    * should not be used by consumers to indicate otherwise.
@@ -181,16 +182,33 @@ interface nsIPermissionManager : nsISupp
    * @param principal the principal
    * @param type      a case-sensitive ASCII string, identifying the consumer
    * @param return    see add(), param permission. returns UNKNOWN_ACTION when
    *                  there is no stored permission for this uri and / or type.
    */
   uint32_t testExactPermanentPermission(in nsIPrincipal principal,
                                         in string type);
 
+  /**
+   * Get the permission object associated with the given principal and action.
+   * @param principal The principal
+   * @param type      A case-sensitive ASCII string identifying the consumer
+   * @param exactHost If true, only the specific host will be matched,
+   *                  @see testExactPermission. If false, subdomains will
+   *                  also be searched, @see testPermission.
+   * @returns The matching permission object, or null if no matching object
+   *          was found. No matching object is equivalent to UNKNOWN_ACTION.
+   * @note Clients in general should prefer the test* methods unless they
+   *       need to know the specific stored details.
+   * @note This method will always return null for the system principal.
+   */
+  nsIPermission getPermissionObject(in nsIPrincipal principal,
+                                    in string type,
+                                    in boolean exactHost);
+
    /**
     * Increment or decrement our "refcount" of an app id.
     *
     * We use this refcount to determine an app's lifetime.  When an app's
     * refcount goes to 0, we clear the permissions given to the app which are
     * set to expire at the end of its session.
     */
    void addrefAppId(in unsigned long appId);