Bug 853356 - Part3 Pass a string array instead of a single string to support multiple permissions request. r=khuey
authorAlfredo Yang <ayang@mozilla.com>
Fri, 06 Dec 2013 17:38:52 -0500
changeset 174116 a72c03a07567922c6025b6aa111ae9854ca60863
parent 174115 5a019e26c6b2a82ffd5482f18e08b64081cf7e46
child 174117 1d72742584ad88fdaf7ce6adc900005f745d1ae7
push id3224
push userlsblakk@mozilla.com
push dateTue, 04 Feb 2014 01:06:49 +0000
treeherdermozilla-beta@60c04d0987f1 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewerskhuey
bugs853356
milestone28.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 853356 - Part3 Pass a string array instead of a single string to support multiple permissions request. r=khuey
content/base/src/nsDocument.cpp
dom/base/nsContentPermissionHelper.cpp
dom/base/nsContentPermissionHelper.h
dom/devicestorage/nsDeviceStorage.cpp
dom/interfaces/base/nsIContentPermissionPrompt.idl
dom/ipc/PBrowser.ipdl
dom/ipc/PContentPermission.ipdlh
dom/ipc/TabChild.cpp
dom/ipc/TabChild.h
dom/ipc/TabParent.cpp
dom/ipc/TabParent.h
dom/ipc/moz.build
dom/src/geolocation/nsGeolocation.cpp
dom/src/notification/DesktopNotification.cpp
dom/src/notification/Notification.cpp
--- a/content/base/src/nsDocument.cpp
+++ b/content/base/src/nsDocument.cpp
@@ -212,16 +212,18 @@
 #include "mozilla/css/Rule.h"
 #include "nsIDOMLocation.h"
 #include "nsIHttpChannelInternal.h"
 #include "nsISecurityConsoleMessage.h"
 #include "nsCharSeparatedTokenizer.h"
 #include "mozilla/dom/XPathEvaluator.h"
 #include "nsIDocumentEncoder.h"
 #include "nsIStructuredCloneContainer.h"
+#include "nsIMutableArray.h"
+#include "nsContentPermissionHelper.h"
 
 using namespace mozilla;
 using namespace mozilla::dom;
 
 typedef nsTArray<Link*> LinkArray;
 
 #ifdef PR_LOGGING
 static PRLogModuleInfo* gDocumentLeakPRLog;
@@ -10730,27 +10732,21 @@ public:
   bool mUserInputOrChromeCaller;
 };
 
 NS_IMPL_ISUPPORTS_INHERITED1(nsPointerLockPermissionRequest,
                              nsRunnable,
                              nsIContentPermissionRequest)
 
 NS_IMETHODIMP
-nsPointerLockPermissionRequest::GetType(nsACString& aType)
-{
-  aType = "pointerLock";
-  return NS_OK;
-}
-
-NS_IMETHODIMP
-nsPointerLockPermissionRequest::GetAccess(nsACString& aAccess)
-{
-  aAccess = "unused";
-  return NS_OK;
+nsPointerLockPermissionRequest::GetTypes(nsIArray** aTypes)
+{
+  return CreatePermissionArray(NS_LITERAL_CSTRING("pointerLock"),
+                               NS_LITERAL_CSTRING("unused"),
+                               aTypes);
 }
 
 NS_IMETHODIMP
 nsPointerLockPermissionRequest::GetPrincipal(nsIPrincipal** aPrincipal)
 {
   nsCOMPtr<nsIDocument> d = do_QueryReferent(mDocument);
   if (d) {
     NS_ADDREF(*aPrincipal = d->NodePrincipal());
--- a/dom/base/nsContentPermissionHelper.cpp
+++ b/dom/base/nsContentPermissionHelper.cpp
@@ -1,49 +1,183 @@
 /* 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/. */
 
 #ifdef MOZ_WIDGET_GONK
 #include "GonkPermission.h"
 #include "mozilla/dom/ContentParent.h"
 #endif // MOZ_WIDGET_GONK
-#include "nsContentPermissionHelper.h"
-#include "nsIContentPermissionPrompt.h"
 #include "nsCOMPtr.h"
 #include "nsIDOMElement.h"
 #include "nsIPrincipal.h"
 #include "mozilla/dom/Element.h"
+#include "mozilla/dom/PContentPermission.h"
+#include "mozilla/dom/PermissionMessageUtils.h"
+#include "mozilla/dom/PContentPermissionRequestParent.h"
 #include "mozilla/dom/TabParent.h"
 #include "mozilla/unused.h"
 #include "nsComponentManagerUtils.h"
+#include "nsArrayUtils.h"
+#include "nsIMutableArray.h"
+#include "nsContentPermissionHelper.h"
 
 using mozilla::unused;          // <snicker>
 using namespace mozilla::dom;
 using namespace mozilla;
 
+namespace mozilla {
+namespace dom {
+
+class ContentPermissionRequestParent : public PContentPermissionRequestParent
+{
+ public:
+  ContentPermissionRequestParent(const nsTArray<PermissionRequest>& aRequests,
+                                 Element* element,
+                                 const IPC::Principal& principal);
+  virtual ~ContentPermissionRequestParent();
+
+  bool IsBeingDestroyed();
+
+  nsCOMPtr<nsIPrincipal> mPrincipal;
+  nsCOMPtr<Element> mElement;
+  nsCOMPtr<nsContentPermissionRequestProxy> mProxy;
+  nsTArray<PermissionRequest> mRequests;
+
+ private:
+  virtual bool Recvprompt();
+  virtual void ActorDestroy(ActorDestroyReason why);
+};
+
+ContentPermissionRequestParent::ContentPermissionRequestParent(const nsTArray<PermissionRequest>& aRequests,
+                                                               Element* aElement,
+                                                               const IPC::Principal& aPrincipal)
+{
+  MOZ_COUNT_CTOR(ContentPermissionRequestParent);
+
+  mPrincipal = aPrincipal;
+  mElement   = aElement;
+  mRequests  = aRequests;
+}
+
+ContentPermissionRequestParent::~ContentPermissionRequestParent()
+{
+  MOZ_COUNT_DTOR(ContentPermissionRequestParent);
+}
+
+bool
+ContentPermissionRequestParent::Recvprompt()
+{
+  mProxy = new nsContentPermissionRequestProxy();
+  NS_ASSERTION(mProxy, "Alloc of request proxy failed");
+  if (NS_FAILED(mProxy->Init(mRequests, this))) {
+    mProxy->Cancel();
+  }
+  return true;
+}
+
+void
+ContentPermissionRequestParent::ActorDestroy(ActorDestroyReason why)
+{
+  if (mProxy) {
+    mProxy->OnParentDestroyed();
+  }
+}
+
+bool
+ContentPermissionRequestParent::IsBeingDestroyed()
+{
+  // When TabParent::Destroy() is called, we are being destroyed. It's unsafe
+  // to send out any message now.
+  TabParent* tabParent = static_cast<TabParent*>(Manager());
+  return tabParent->IsDestroyed();
+}
+
+NS_IMPL_ISUPPORTS1(ContentPermissionType, nsIContentPermissionType)
+
+ContentPermissionType::ContentPermissionType(const nsACString& aType,
+                                             const nsACString& aAccess)
+{
+  mType = aType;
+  mAccess = aAccess;
+}
+
+ContentPermissionType::~ContentPermissionType()
+{
+}
+
+NS_IMETHODIMP
+ContentPermissionType::GetType(nsACString& aType)
+{
+  aType = mType;
+  return NS_OK;
+}
+
+NS_IMETHODIMP
+ContentPermissionType::GetAccess(nsACString& aAccess)
+{
+  aAccess = mAccess;
+  return NS_OK;
+}
+
+uint32_t
+ConvertPermissionRequestToArray(nsTArray<PermissionRequest>& aSrcArray,
+                                nsIMutableArray* aDesArray)
+{
+  uint32_t len = aSrcArray.Length();
+  for (uint32_t i = 0; i < len; i++) {
+    nsRefPtr<ContentPermissionType> cpt =
+      new ContentPermissionType(aSrcArray[i].type(), aSrcArray[i].access());
+    aDesArray->AppendElement(cpt, false);
+  }
+  return len;
+}
+
+nsresult
+CreatePermissionArray(const nsACString& aType,
+                      const nsACString& aAccess,
+                      nsIArray** aTypesArray)
+{
+  nsCOMPtr<nsIMutableArray> types = do_CreateInstance(NS_ARRAY_CONTRACTID);
+  nsRefPtr<ContentPermissionType> permType = new ContentPermissionType(aType,
+                                                                       aAccess);
+  types->AppendElement(permType, false);
+  types.forget(aTypesArray);
+
+  return NS_OK;
+}
+
+PContentPermissionRequestParent*
+CreateContentPermissionRequestParent(const nsTArray<PermissionRequest>& aRequests,
+                                     Element* element,
+                                     const IPC::Principal& principal)
+{
+  return new ContentPermissionRequestParent(aRequests, element, principal);
+}
+
+} // namespace dom
+} // namespace mozilla
+
 nsContentPermissionRequestProxy::nsContentPermissionRequestProxy()
 {
   MOZ_COUNT_CTOR(nsContentPermissionRequestProxy);
 }
 
 nsContentPermissionRequestProxy::~nsContentPermissionRequestProxy()
 {
   MOZ_COUNT_DTOR(nsContentPermissionRequestProxy);
 }
 
 nsresult
-nsContentPermissionRequestProxy::Init(const nsACString & type,
-                                      const nsACString & access,
+nsContentPermissionRequestProxy::Init(const nsTArray<PermissionRequest>& requests,
                                       ContentPermissionRequestParent* parent)
 {
   NS_ASSERTION(parent, "null parent");
   mParent = parent;
-  mType   = type;
-  mAccess = access;
+  mPermissionRequests = requests;
 
   nsCOMPtr<nsIContentPermissionPrompt> prompt = do_CreateInstance(NS_CONTENT_PERMISSION_PROMPT_CONTRACTID);
   if (!prompt) {
     return NS_ERROR_FAILURE;
   }
 
   prompt->Prompt(this);
   return NS_OK;
@@ -53,27 +187,24 @@ void
 nsContentPermissionRequestProxy::OnParentDestroyed()
 {
   mParent = nullptr;
 }
 
 NS_IMPL_ISUPPORTS1(nsContentPermissionRequestProxy, nsIContentPermissionRequest)
 
 NS_IMETHODIMP
-nsContentPermissionRequestProxy::GetType(nsACString & aType)
+nsContentPermissionRequestProxy::GetTypes(nsIArray** aTypes)
 {
-  aType = mType;
-  return NS_OK;
-}
-
-NS_IMETHODIMP
-nsContentPermissionRequestProxy::GetAccess(nsACString & aAccess)
-{
-  aAccess = mAccess;
-  return NS_OK;
+  nsCOMPtr<nsIMutableArray> types = do_CreateInstance(NS_ARRAY_CONTRACTID);
+  if (ConvertPermissionRequestToArray(mPermissionRequests, types)) {
+    types.forget(aTypes);
+    return NS_OK;
+  }
+  return NS_ERROR_FAILURE;
 }
 
 NS_IMETHODIMP
 nsContentPermissionRequestProxy::GetWindow(nsIDOMWindow * *aRequestingWindow)
 {
   NS_ENSURE_ARG_POINTER(aRequestingWindow);
   *aRequestingWindow = nullptr; // ipc doesn't have a window
   return NS_OK;
@@ -131,71 +262,27 @@ nsContentPermissionRequestProxy::Allow()
 
   // Don't send out the delete message when the managing protocol (PBrowser) is
   // being destroyed and PContentPermissionRequest will soon be.
   if (mParent->IsBeingDestroyed()) {
     return NS_ERROR_FAILURE;
   }
 
 #ifdef MOZ_WIDGET_GONK
-  if (mType.Equals("audio-capture")) {
-    GonkPermissionService::GetInstance()->addGrantInfo(
-      "android.permission.RECORD_AUDIO",
-      static_cast<TabParent*>(mParent->Manager())->Manager()->Pid());
+  uint32_t len = mPermissionRequests.Length();
+  for (uint32_t i = 0; i < len; i++) {
+    if (mPermissionRequests[i].type().Equals("audio-capture")) {
+      GonkPermissionService::GetInstance()->addGrantInfo(
+        "android.permission.RECORD_AUDIO",
+        static_cast<TabParent*>(mParent->Manager())->Manager()->Pid());
+    }
+    if (mPermissionRequests[i].type().Equals("video-capture")) {
+      GonkPermissionService::GetInstance()->addGrantInfo(
+        "android.permission.CAMERA",
+        static_cast<TabParent*>(mParent->Manager())->Manager()->Pid());
+    }
   }
 #endif
 
   unused << ContentPermissionRequestParent::Send__delete__(mParent, true);
   mParent = nullptr;
   return NS_OK;
 }
-
-namespace mozilla {
-namespace dom {
-
-ContentPermissionRequestParent::ContentPermissionRequestParent(const nsACString& aType,
-                                                               const nsACString& aAccess,
-                                                               Element* aElement,
-                                                               const IPC::Principal& aPrincipal)
-{
-  MOZ_COUNT_CTOR(ContentPermissionRequestParent);
-
-  mPrincipal = aPrincipal;
-  mElement   = aElement;
-  mType      = aType;
-  mAccess    = aAccess;
-}
-
-ContentPermissionRequestParent::~ContentPermissionRequestParent()
-{
-  MOZ_COUNT_DTOR(ContentPermissionRequestParent);
-}
-
-bool
-ContentPermissionRequestParent::Recvprompt()
-{
-  mProxy = new nsContentPermissionRequestProxy();
-  NS_ASSERTION(mProxy, "Alloc of request proxy failed");
-  if (NS_FAILED(mProxy->Init(mType, mAccess, this))) {
-    mProxy->Cancel();
-  }
-  return true;
-}
-
-void
-ContentPermissionRequestParent::ActorDestroy(ActorDestroyReason why)
-{
-  if (mProxy) {
-    mProxy->OnParentDestroyed();
-  }
-}
-
-bool
-ContentPermissionRequestParent::IsBeingDestroyed()
-{
-  // When TabParent::Destroy() is called, we are being destroyed. It's unsafe
-  // to send out any message now.
-  TabParent* tabParent = static_cast<TabParent*>(Manager());
-  return tabParent->IsDestroyed();
-}
-
-} // namespace dom
-} // namespace mozilla
--- a/dom/base/nsContentPermissionHelper.h
+++ b/dom/base/nsContentPermissionHelper.h
@@ -1,65 +1,80 @@
 /* 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/. */
 
 #ifndef nsContentPermissionHelper_h
 #define nsContentPermissionHelper_h
 
 #include "nsIContentPermissionPrompt.h"
-#include "nsString.h"
-
-#include "mozilla/dom/PermissionMessageUtils.h"
-#include "mozilla/dom/PContentPermissionRequestParent.h"
+#include "nsTArray.h"
+#include "nsIMutableArray.h"
 
 class nsContentPermissionRequestProxy;
 
+// Forward declare IPC::Principal here which is defined in
+// PermissionMessageUtils.h. Include this file will transitively includes
+// "windows.h" and it defines
+//   #define CreateEvent CreateEventW
+//   #define LoadImage LoadImageW
+// That will mess up windows build.
+namespace IPC {
+class Principal;
+}
+
 namespace mozilla {
 namespace dom {
 
 class Element;
+class PermissionRequest;
+class ContentPermissionRequestParent;
+class PContentPermissionRequestParent;
 
-class ContentPermissionRequestParent : public PContentPermissionRequestParent
+class ContentPermissionType : public nsIContentPermissionType
 {
- public:
-  ContentPermissionRequestParent(const nsACString& type,
-                                 const nsACString& access,
-                                 Element* element,
-                                 const IPC::Principal& principal);
-  virtual ~ContentPermissionRequestParent();
+public:
+  NS_DECL_ISUPPORTS
+  NS_DECL_NSICONTENTPERMISSIONTYPE
 
-  bool IsBeingDestroyed();
+  ContentPermissionType(const nsACString& aType, const nsACString& aAccess);
+  virtual ~ContentPermissionType();
 
-  nsCOMPtr<nsIPrincipal> mPrincipal;
-  nsCOMPtr<Element> mElement;
-  nsCOMPtr<nsContentPermissionRequestProxy> mProxy;
+protected:
   nsCString mType;
   nsCString mAccess;
+};
 
- private:
-  virtual bool Recvprompt();
-  virtual void ActorDestroy(ActorDestroyReason why);
-};
+uint32_t ConvertPermissionRequestToArray(nsTArray<PermissionRequest>& aSrcArray,
+                                         nsIMutableArray* aDesArray);
+
+nsresult CreatePermissionArray(const nsACString& aType,
+                               const nsACString& aAccess,
+                               nsIArray** aTypesArray);
+
+PContentPermissionRequestParent*
+CreateContentPermissionRequestParent(const nsTArray<PermissionRequest>& aRequests,
+                                     Element* element,
+                                     const IPC::Principal& principal);
 
 } // namespace dom
 } // namespace mozilla
 
 class nsContentPermissionRequestProxy : public nsIContentPermissionRequest
 {
  public:
+  NS_DECL_ISUPPORTS
+  NS_DECL_NSICONTENTPERMISSIONREQUEST
+
   nsContentPermissionRequestProxy();
   virtual ~nsContentPermissionRequestProxy();
 
-  nsresult Init(const nsACString& type, const nsACString& access, mozilla::dom::ContentPermissionRequestParent* parent);
+  nsresult Init(const nsTArray<mozilla::dom::PermissionRequest>& requests,
+                mozilla::dom::ContentPermissionRequestParent* parent);
   void OnParentDestroyed();
 
-  NS_DECL_ISUPPORTS
-  NS_DECL_NSICONTENTPERMISSIONREQUEST
-
  private:
   // Non-owning pointer to the ContentPermissionRequestParent object which owns this proxy.
   mozilla::dom::ContentPermissionRequestParent* mParent;
-  nsCString mType;
-  nsCString mAccess;
+  nsTArray<mozilla::dom::PermissionRequest> mPermissionRequests;
 };
+
 #endif // nsContentPermissionHelper_h
-
--- a/dom/devicestorage/nsDeviceStorage.cpp
+++ b/dom/devicestorage/nsDeviceStorage.cpp
@@ -44,16 +44,17 @@
 #include "nsIObserverService.h"
 #include "GeneratedEvents.h"
 #include "nsIMIMEService.h"
 #include "nsCExternalHandlerService.h"
 #include "nsIPermissionManager.h"
 #include "nsIStringBundle.h"
 #include "nsIDocument.h"
 #include <algorithm>
+#include "nsContentPermissionHelper.h"
 
 #include "mozilla/dom/DeviceStorageBinding.h"
 
 // Microsoft's API Name hackery sucks
 #undef CreateEvent
 
 #ifdef MOZ_WIDGET_GONK
 #include "nsIVolume.h"
@@ -1728,27 +1729,24 @@ nsDOMDeviceStorageCursor::~nsDOMDeviceSt
 
 void
 nsDOMDeviceStorageCursor::GetStorageType(nsAString & aType)
 {
   aType = mFile->mStorageType;
 }
 
 NS_IMETHODIMP
-nsDOMDeviceStorageCursor::GetType(nsACString & aType)
+nsDOMDeviceStorageCursor::GetTypes(nsIArray** aTypes)
 {
-  return DeviceStorageTypeChecker::GetPermissionForType(mFile->mStorageType,
-                                                        aType);
-}
-
-NS_IMETHODIMP
-nsDOMDeviceStorageCursor::GetAccess(nsACString & aAccess)
-{
-  aAccess = NS_LITERAL_CSTRING("read");
-  return NS_OK;
+  nsCString type;
+  nsresult rv =
+    DeviceStorageTypeChecker::GetPermissionForType(mFile->mStorageType, type);
+  NS_ENSURE_SUCCESS(rv, rv);
+
+  return CreatePermissionArray(type, NS_LITERAL_CSTRING("read"), aTypes);
 }
 
 NS_IMETHODIMP
 nsDOMDeviceStorageCursor::GetPrincipal(nsIPrincipal * *aRequestingPrincipal)
 {
   NS_IF_ADDREF(*aRequestingPrincipal = mPrincipal);
   return NS_OK;
 }
@@ -2246,51 +2244,50 @@ public:
         return rv;
       }
       nsCString access;
       rv = DeviceStorageTypeChecker::GetAccessForRequest(
         DeviceStorageRequestType(mRequestType), access);
       if (NS_FAILED(rv)) {
         return rv;
       }
+      nsTArray<PermissionRequest> permArray;
+      permArray.AppendElement(PermissionRequest(type, access));
       child->SendPContentPermissionRequestConstructor(
-        this, type, access, IPC::Principal(mPrincipal));
+        this, permArray, IPC::Principal(mPrincipal));
 
       Sendprompt();
       return NS_OK;
     }
 
     nsCOMPtr<nsIContentPermissionPrompt> prompt
       = do_CreateInstance(NS_CONTENT_PERMISSION_PROMPT_CONTRACTID);
     if (prompt) {
       prompt->Prompt(this);
     }
     return NS_OK;
   }
 
-  NS_IMETHOD GetType(nsACString & aType)
+  NS_IMETHODIMP GetTypes(nsIArray** aTypes)
   {
     nsCString type;
-    nsresult rv
-      = DeviceStorageTypeChecker::GetPermissionForType(mFile->mStorageType,
-                                                       aType);
+    nsresult rv =
+      DeviceStorageTypeChecker::GetPermissionForType(mFile->mStorageType, type);
     if (NS_FAILED(rv)) {
       return rv;
     }
-    return NS_OK;
-  }
-
-  NS_IMETHOD GetAccess(nsACString & aAccess)
-  {
-    nsresult rv = DeviceStorageTypeChecker::GetAccessForRequest(
-      DeviceStorageRequestType(mRequestType), aAccess);
+
+    nsCString access;
+    rv = DeviceStorageTypeChecker::GetAccessForRequest(
+      DeviceStorageRequestType(mRequestType), access);
     if (NS_FAILED(rv)) {
       return rv;
     }
-    return NS_OK;
+
+    return CreatePermissionArray(type, access, aTypes);
   }
 
   NS_IMETHOD GetPrincipal(nsIPrincipal * *aRequestingPrincipal)
   {
     NS_IF_ADDREF(*aRequestingPrincipal = mPrincipal);
     return NS_OK;
   }
 
@@ -3294,18 +3291,20 @@ nsDOMDeviceStorage::EnumerateInternal(co
     // Corresponding release occurs in DeallocPContentPermissionRequest.
     r->AddRef();
 
     nsCString type;
     aRv = DeviceStorageTypeChecker::GetPermissionForType(mStorageType, type);
     if (aRv.Failed()) {
       return nullptr;
     }
-    child->SendPContentPermissionRequestConstructor(r, type,
-                                                    NS_LITERAL_CSTRING("read"),
+    nsTArray<PermissionRequest> permArray;
+    permArray.AppendElement(PermissionRequest(type, NS_LITERAL_CSTRING("read")));
+    child->SendPContentPermissionRequestConstructor(r,
+                                                    permArray,
                                                     IPC::Principal(mPrincipal));
 
     r->Sendprompt();
 
     return cursor.forget();
   }
 
   nsCOMPtr<nsIContentPermissionPrompt> prompt
--- a/dom/interfaces/base/nsIContentPermissionPrompt.idl
+++ b/dom/interfaces/base/nsIContentPermissionPrompt.idl
@@ -2,38 +2,50 @@
  * 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 "nsISupports.idl"
 
 interface nsIPrincipal;
 interface nsIDOMWindow;
 interface nsIDOMElement;
+interface nsIArray;
 
 /**
- * Interface allows access to a content to request
- * permission to perform a privileged operation such as
- * geolocation.
+ *  Interface provides the request type and its access.
  */
-[scriptable, uuid(1de67000-2de8-11e2-81c1-0800200c9a66)]
-interface nsIContentPermissionRequest : nsISupports {
-
+[scriptable, builtinclass, uuid(384b6cc4-a66b-4bea-98e0-eb10562a9ba4)]
+interface nsIContentPermissionType : nsISupports {
   /**
    *  The type of the permission request, such as
    *  "geolocation".
    */
   readonly attribute ACString type;
 
   /**
    *  The access of the permission request, such as
    *  "read".
    */
   readonly attribute ACString access;
+};
 
+/**
+ * Interface allows access to a content to request
+ * permission to perform a privileged operation such as
+ * geolocation.
+ */
+[scriptable, uuid(69a39d88-d1c4-4ba9-9b19-bafc7a1bb783)]
+interface nsIContentPermissionRequest : nsISupports {
   /**
+   *  The array will include the request types. Elements of this array are
+   *  nsIContentPermissionType object.
+   */
+  readonly attribute nsIArray types;
+
+  /*
    *  The principal of the permission request.
    */
   readonly attribute nsIPrincipal principal;
 
   /**
    *  The window or element that the permission request was
    *  originated in.  Typically the element will be non-null
    *  in when using out of process content.  window or
--- a/dom/ipc/PBrowser.ipdl
+++ b/dom/ipc/PBrowser.ipdl
@@ -11,16 +11,17 @@ include protocol PContentDialog;
 include protocol PDocumentRenderer;
 include protocol PContentPermissionRequest;
 include protocol PRenderFrame;
 include protocol POfflineCacheUpdate;
 include protocol PIndexedDB;
 include DOMTypes;
 include JavaScriptTypes;
 include URIParams;
+include PContentPermission;
 
 
 using class IPC::Principal from "mozilla/dom/PermissionMessageUtils.h";
 using struct gfxMatrix from "gfxMatrix.h";
 using struct gfxSize from "gfxPoint.h";
 using CSSRect from "Units.h";
 using struct mozilla::layers::FrameMetrics from "FrameMetrics.h";
 using struct mozilla::layers::ScrollableLayerGuid from "FrameMetrics.h";
@@ -201,28 +202,26 @@ parent:
      * Nowadays this is mainly used for link locations on hover.
      */
     SetStatus(uint32_t type, nsString status);
 
     /**
      * Initiates an asynchronous request for permission for the
      * provided principal.
      *
-     * @param aType
-     *   The type of permission to request.
-     * @param aAccess
-     *   Access type. "read" for example.
+     * @param aRequests
+     *   The array of permissions to request.
      * @param aPrincipal
      *   The principal of the request.
      *
      * NOTE: The principal is untrusted in the parent process. Only
      *       principals that can live in the content process should
      *       provided.
      */
-    PContentPermissionRequest(nsCString aType, nsCString aAccess, Principal principal);
+    PContentPermissionRequest(PermissionRequest[] aRequests, Principal aPrincipal);
 
     PContentDialog(uint32_t aType, nsCString aName, nsCString aFeatures,
                    int32_t[] aIntParams, nsString[] aStringParams);
 
     /**
      * Create a layout frame (encapsulating a remote layer tree) for
      * the page that is currently loaded in the <browser>.
      */
new file mode 100644
--- /dev/null
+++ b/dom/ipc/PContentPermission.ipdlh
@@ -0,0 +1,14 @@
+/* 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/. */
+
+namespace mozilla {
+namespace dom {
+
+struct PermissionRequest {
+  nsCString type;
+  nsCString access;
+};
+
+} // namespace dom
+} // namespace mozilla
--- a/dom/ipc/TabChild.cpp
+++ b/dom/ipc/TabChild.cpp
@@ -1152,22 +1152,21 @@ TabChild::ArraysToParams(const Infallibl
       aParams->SetString(j, aStringParams[j].get());
     }
   }
 }
 
 #ifdef DEBUG
 PContentPermissionRequestChild*
 TabChild:: SendPContentPermissionRequestConstructor(PContentPermissionRequestChild* aActor,
-                                                    const nsCString& aType,
-                                                    const nsCString& aAccess,
+                                                    const InfallibleTArray<PermissionRequest>& aRequests,
                                                     const IPC::Principal& aPrincipal)
 {
   PCOMContentPermissionRequestChild* child = static_cast<PCOMContentPermissionRequestChild*>(aActor);
-  PContentPermissionRequestChild* request = PBrowserChild::SendPContentPermissionRequestConstructor(aActor, aType, aAccess, aPrincipal);
+  PContentPermissionRequestChild* request = PBrowserChild::SendPContentPermissionRequestConstructor(aActor, aRequests, aPrincipal);
   child->mIPCOpen = true;
   return request;
 }
 #endif /* DEBUG */
 
 void
 TabChild::DestroyWindow()
 {
@@ -2009,17 +2008,18 @@ TabChild::AllocPContentDialogChild(const
 bool
 TabChild::DeallocPContentDialogChild(PContentDialogChild* aDialog)
 {
   delete aDialog;
   return true;
 }
 
 PContentPermissionRequestChild*
-TabChild::AllocPContentPermissionRequestChild(const nsCString& aType, const nsCString& aAccess, const IPC::Principal&)
+TabChild::AllocPContentPermissionRequestChild(const InfallibleTArray<PermissionRequest>& aRequests,
+                                              const IPC::Principal& aPrincipal)
 {
   NS_RUNTIMEABORT("unused");
   return nullptr;
 }
 
 bool
 TabChild::DeallocPContentPermissionRequestChild(PContentPermissionRequestChild* actor)
 {
--- a/dom/ipc/TabChild.h
+++ b/dom/ipc/TabChild.h
@@ -273,23 +273,21 @@ public:
                                InfallibleTArray<nsString>& aStringParams);
     static void ArraysToParams(const InfallibleTArray<int>& aIntParams,
                                const InfallibleTArray<nsString>& aStringParams,
                                nsIDialogParamBlock* aParams);
 
 #ifdef DEBUG
     virtual PContentPermissionRequestChild*
     SendPContentPermissionRequestConstructor(PContentPermissionRequestChild* aActor,
-                                             const nsCString& aType,
-                                             const nsCString& aAccess,
+                                             const InfallibleTArray<PermissionRequest>& aRequests,
                                              const IPC::Principal& aPrincipal);
 #endif /* DEBUG */
 
-    virtual PContentPermissionRequestChild* AllocPContentPermissionRequestChild(const nsCString& aType,
-                                                                                const nsCString& aAccess,
+    virtual PContentPermissionRequestChild* AllocPContentPermissionRequestChild(const InfallibleTArray<PermissionRequest>& aRequests,
                                                                                 const IPC::Principal& aPrincipal);
     virtual bool DeallocPContentPermissionRequestChild(PContentPermissionRequestChild* actor);
 
     virtual POfflineCacheUpdateChild* AllocPOfflineCacheUpdateChild(
             const URIParams& manifestURI,
             const URIParams& documentURI,
             const bool& stickDocument);
     virtual bool DeallocPOfflineCacheUpdateChild(POfflineCacheUpdateChild* offlineCacheUpdate);
--- a/dom/ipc/TabParent.cpp
+++ b/dom/ipc/TabParent.cpp
@@ -10,16 +10,17 @@
 
 #include "AppProcessChecker.h"
 #include "IDBFactory.h"
 #include "IndexedDBParent.h"
 #include "mozIApplication.h"
 #include "mozilla/BrowserElementParent.h"
 #include "mozilla/docshell/OfflineCacheUpdateParent.h"
 #include "mozilla/dom/ContentParent.h"
+#include "mozilla/dom/PContentPermissionRequestParent.h"
 #include "mozilla/Hal.h"
 #include "mozilla/ipc/DocumentRendererParent.h"
 #include "mozilla/layers/CompositorParent.h"
 #include "mozilla/layout/RenderFrameParent.h"
 #include "mozilla/MouseEvents.h"
 #include "mozilla/Preferences.h"
 #include "mozilla/TextEvents.h"
 #include "mozilla/TouchEvents.h"
@@ -574,19 +575,20 @@ TabParent::AllocPDocumentRendererParent(
 bool
 TabParent::DeallocPDocumentRendererParent(PDocumentRendererParent* actor)
 {
     delete actor;
     return true;
 }
 
 PContentPermissionRequestParent*
-TabParent::AllocPContentPermissionRequestParent(const nsCString& type, const nsCString& access, const IPC::Principal& principal)
+TabParent::AllocPContentPermissionRequestParent(const InfallibleTArray<PermissionRequest>& aRequests,
+                                                const IPC::Principal& aPrincipal)
 {
-  return new ContentPermissionRequestParent(type, access, mFrameElement, principal);
+  return CreateContentPermissionRequestParent(aRequests, mFrameElement, aPrincipal);
 }
 
 bool
 TabParent::DeallocPContentPermissionRequestParent(PContentPermissionRequestParent* actor)
 {
   delete actor;
   return true;
 }
--- a/dom/ipc/TabParent.h
+++ b/dom/ipc/TabParent.h
@@ -220,17 +220,18 @@ public:
     virtual PDocumentRendererParent*
     AllocPDocumentRendererParent(const nsRect& documentRect, const gfxMatrix& transform,
                                  const nsString& bgcolor,
                                  const uint32_t& renderFlags, const bool& flushLayout,
                                  const nsIntSize& renderSize);
     virtual bool DeallocPDocumentRendererParent(PDocumentRendererParent* actor);
 
     virtual PContentPermissionRequestParent*
-    AllocPContentPermissionRequestParent(const nsCString& aType, const nsCString& aAccess, const IPC::Principal& aPrincipal);
+    AllocPContentPermissionRequestParent(const InfallibleTArray<PermissionRequest>& aRequests,
+                                         const IPC::Principal& aPrincipal);
     virtual bool DeallocPContentPermissionRequestParent(PContentPermissionRequestParent* actor);
 
     virtual POfflineCacheUpdateParent* AllocPOfflineCacheUpdateParent(
             const URIParams& aManifestURI,
             const URIParams& aDocumentURI,
             const bool& stickDocument) MOZ_OVERRIDE;
     virtual bool DeallocPOfflineCacheUpdateParent(POfflineCacheUpdateParent* actor);
 
--- a/dom/ipc/moz.build
+++ b/dom/ipc/moz.build
@@ -63,16 +63,17 @@ SOURCES += [
 
 IPDL_SOURCES += [
     'DOMTypes.ipdlh',
     'PBlob.ipdl',
     'PBlobStream.ipdl',
     'PBrowser.ipdl',
     'PContent.ipdl',
     'PContentDialog.ipdl',
+    'PContentPermission.ipdlh',
     'PContentPermissionRequest.ipdl',
     'PCrashReporter.ipdl',
     'PDocumentRenderer.ipdl',
     'PMemoryReportRequest.ipdl',
     'PTabContext.ipdlh',
 ]
 
 FAIL_ON_WARNINGS = True
--- a/dom/src/geolocation/nsGeolocation.cpp
+++ b/dom/src/geolocation/nsGeolocation.cpp
@@ -10,16 +10,17 @@
 #include "nsISettingsService.h"
 
 #include "nsGeolocation.h"
 #include "nsDOMClassInfoID.h"
 #include "nsComponentManagerUtils.h"
 #include "nsServiceManagerUtils.h"
 #include "nsContentUtils.h"
 #include "nsCxPusher.h"
+#include "nsContentPermissionHelper.h"
 #include "nsIDocument.h"
 #include "nsIObserverService.h"
 #include "nsPIDOMWindow.h"
 #include "nsThreadUtils.h"
 #include "mozilla/Services.h"
 #include "mozilla/unused.h"
 #include "mozilla/Preferences.h"
 #include "mozilla/ClearOnShutdown.h"
@@ -380,27 +381,21 @@ nsGeolocationRequest::GetPrincipal(nsIPr
 
   nsCOMPtr<nsIPrincipal> principal = mLocator->GetPrincipal();
   principal.forget(aRequestingPrincipal);
 
   return NS_OK;
 }
 
 NS_IMETHODIMP
-nsGeolocationRequest::GetType(nsACString & aType)
+nsGeolocationRequest::GetTypes(nsIArray** aTypes)
 {
-  aType = "geolocation";
-  return NS_OK;
-}
-
-NS_IMETHODIMP
-nsGeolocationRequest::GetAccess(nsACString & aAccess)
-{
-  aAccess = "unused";
-  return NS_OK;
+  return CreatePermissionArray(NS_LITERAL_CSTRING("geolocation"),
+                               NS_LITERAL_CSTRING("unused"),
+                               aTypes);
 }
 
 NS_IMETHODIMP
 nsGeolocationRequest::GetWindow(nsIDOMWindow * *aRequestingWindow)
 {
   NS_ENSURE_ARG_POINTER(aRequestingWindow);
 
   nsCOMPtr<nsIDOMWindow> window = do_QueryReferent(mLocator->GetOwner());
@@ -1447,22 +1442,25 @@ Geolocation::RegisterRequestWithPrompt(n
 
     // because owner implements nsITabChild, we can assume that it is
     // the one and only TabChild.
     TabChild* child = TabChild::GetFrom(window->GetDocShell());
     if (!child) {
       return false;
     }
 
+    nsTArray<PermissionRequest> permArray;
+    permArray.AppendElement(PermissionRequest(NS_LITERAL_CSTRING("geolocation"),
+                                              NS_LITERAL_CSTRING("unused")));
+
     // Retain a reference so the object isn't deleted without IPDL's knowledge.
     // Corresponding release occurs in DeallocPContentPermissionRequest.
     request->AddRef();
     child->SendPContentPermissionRequestConstructor(request,
-                                                    NS_LITERAL_CSTRING("geolocation"),
-                                                    NS_LITERAL_CSTRING("unused"),
+                                                    permArray,
                                                     IPC::Principal(mPrincipal));
 
     request->Sendprompt();
     return true;
   }
 
   nsCOMPtr<nsIRunnable> ev  = new RequestPromptEvent(request);
   NS_DispatchToMainThread(ev);
--- a/dom/src/notification/DesktopNotification.cpp
+++ b/dom/src/notification/DesktopNotification.cpp
@@ -10,16 +10,17 @@
 #include "nsIDOMDesktopNotification.h"
 #include "TabChild.h"
 #include "mozilla/Preferences.h"
 #include "nsGlobalWindow.h"
 #include "nsIAppsService.h"
 #include "PCOMContentPermissionRequestChild.h"
 #include "nsIScriptSecurityManager.h"
 #include "nsServiceManagerUtils.h"
+#include "PermissionMessageUtils.h"
 
 namespace mozilla {
 namespace dom {
 
 /*
  * Simple Request
  */
 class DesktopNotificationRequest : public nsIContentPermissionRequest,
@@ -174,19 +175,22 @@ DesktopNotification::Init()
     // because owner implements nsITabChild, we can assume that it is
     // the one and only TabChild for this docshell.
     TabChild* child = TabChild::GetFrom(GetOwner()->GetDocShell());
 
     // Retain a reference so the object isn't deleted without IPDL's knowledge.
     // Corresponding release occurs in DeallocPContentPermissionRequest.
     nsRefPtr<DesktopNotificationRequest> copy = request;
 
+    nsTArray<PermissionRequest> permArray;
+    permArray.AppendElement(PermissionRequest(
+                            NS_LITERAL_CSTRING("desktop-notification"),
+                            NS_LITERAL_CSTRING("unused")));
     child->SendPContentPermissionRequestConstructor(copy.forget().get(),
-                                                    NS_LITERAL_CSTRING("desktop-notification"),
-                                                    NS_LITERAL_CSTRING("unused"),
+                                                    permArray,
                                                     IPC::Principal(mPrincipal));
 
     request->Sendprompt();
     return;
   }
 
   // otherwise, dispatch it
   NS_DispatchToMainThread(request);
@@ -348,23 +352,17 @@ NS_IMETHODIMP
 DesktopNotificationRequest::Allow()
 {
   nsresult rv = mDesktopNotification->SetAllow(true);
   mDesktopNotification = nullptr;
   return rv;
 }
 
 NS_IMETHODIMP
-DesktopNotificationRequest::GetType(nsACString & aType)
+DesktopNotificationRequest::GetTypes(nsIArray** aTypes)
 {
-  aType = "desktop-notification";
-  return NS_OK;
-}
-
-NS_IMETHODIMP
-DesktopNotificationRequest::GetAccess(nsACString & aAccess)
-{
-  aAccess = "unused";
-  return NS_OK;
+  return CreatePermissionArray(NS_LITERAL_CSTRING("desktop-notification"),
+                               NS_LITERAL_CSTRING("unused"),
+                               aTypes);
 }
 
 } // namespace dom
 } // namespace mozilla
--- a/dom/src/notification/Notification.cpp
+++ b/dom/src/notification/Notification.cpp
@@ -19,16 +19,17 @@
 #include "nsIPermissionManager.h"
 #include "nsIUUIDGenerator.h"
 #include "nsServiceManagerUtils.h"
 #include "nsToolkitCompsCID.h"
 #include "nsGlobalWindow.h"
 #include "nsDOMJSUtils.h"
 #include "nsIScriptSecurityManager.h"
 #include "mozilla/dom/PermissionMessageUtils.h"
+#include "nsContentPermissionHelper.h"
 #ifdef MOZ_B2G
 #include "nsIDOMDesktopNotification.h"
 #endif
 
 namespace mozilla {
 namespace dom {
 
 class NotificationStorageCallback MOZ_FINAL : public nsINotificationStorageCallback
@@ -262,19 +263,21 @@ NotificationPermissionRequest::Run()
     if (!child) {
       return NS_ERROR_NOT_AVAILABLE;
     }
 
     // Retain a reference so the object isn't deleted without IPDL's knowledge.
     // Corresponding release occurs in DeallocPContentPermissionRequest.
     AddRef();
 
-    NS_NAMED_LITERAL_CSTRING(type, "desktop-notification");
-    NS_NAMED_LITERAL_CSTRING(access, "unused");
-    child->SendPContentPermissionRequestConstructor(this, type, access,
+    nsTArray<PermissionRequest> permArray;
+    permArray.AppendElement(PermissionRequest(
+                            NS_LITERAL_CSTRING("desktop-notification"),
+                            NS_LITERAL_CSTRING("unused")));
+    child->SendPContentPermissionRequestConstructor(this, permArray,
                                                     IPC::Principal(mPrincipal));
 
     Sendprompt();
     return NS_OK;
   }
 
   nsCOMPtr<nsIContentPermissionPrompt> prompt =
     do_GetService(NS_CONTENT_PERMISSION_PROMPT_CONTRACTID);
@@ -337,27 +340,21 @@ nsresult
 NotificationPermissionRequest::CallCallback()
 {
   ErrorResult rv;
   mCallback->Call(mPermission, rv);
   return rv.ErrorCode();
 }
 
 NS_IMETHODIMP
-NotificationPermissionRequest::GetAccess(nsACString& aAccess)
+NotificationPermissionRequest::GetTypes(nsIArray** aTypes)
 {
-  aAccess.AssignLiteral("unused");
-  return NS_OK;
-}
-
-NS_IMETHODIMP
-NotificationPermissionRequest::GetType(nsACString& aType)
-{
-  aType.AssignLiteral("desktop-notification");
-  return NS_OK;
+  return CreatePermissionArray(NS_LITERAL_CSTRING("desktop-notification"),
+                               NS_LITERAL_CSTRING("unused"),
+                               aTypes);
 }
 
 bool
 NotificationPermissionRequest::Recv__delete__(const bool& aAllow)
 {
   if (aAllow) {
     (void) Allow();
   } else {