diff -r 000000000000 -r 6474c204b198 dom/base/nsContentPermissionHelper.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/dom/base/nsContentPermissionHelper.cpp Wed Dec 31 06:09:35 2014 +0100 @@ -0,0 +1,358 @@ +/* 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 "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" +#include "nsCxPusher.h" +#include "nsJSUtils.h" +#include "nsISupportsPrimitives.h" + +using mozilla::unused; // +using namespace mozilla::dom; +using namespace mozilla; + +namespace mozilla { +namespace dom { + +class ContentPermissionRequestParent : public PContentPermissionRequestParent +{ + public: + ContentPermissionRequestParent(const nsTArray& aRequests, + Element* element, + const IPC::Principal& principal); + virtual ~ContentPermissionRequestParent(); + + bool IsBeingDestroyed(); + + nsCOMPtr mPrincipal; + nsCOMPtr mElement; + nsRefPtr mProxy; + nsTArray mRequests; + + private: + virtual bool Recvprompt(); + virtual void ActorDestroy(ActorDestroyReason why); +}; + +ContentPermissionRequestParent::ContentPermissionRequestParent(const nsTArray& 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(Manager()); + return tabParent->IsDestroyed(); +} + +NS_IMPL_ISUPPORTS(ContentPermissionType, nsIContentPermissionType) + +ContentPermissionType::ContentPermissionType(const nsACString& aType, + const nsACString& aAccess, + const nsTArray& aOptions) +{ + mType = aType; + mAccess = aAccess; + mOptions = aOptions; +} + +ContentPermissionType::~ContentPermissionType() +{ +} + +NS_IMETHODIMP +ContentPermissionType::GetType(nsACString& aType) +{ + aType = mType; + return NS_OK; +} + +NS_IMETHODIMP +ContentPermissionType::GetAccess(nsACString& aAccess) +{ + aAccess = mAccess; + return NS_OK; +} + +NS_IMETHODIMP +ContentPermissionType::GetOptions(nsIArray** aOptions) +{ + NS_ENSURE_ARG_POINTER(aOptions); + + *aOptions = nullptr; + + nsresult rv; + nsCOMPtr options = + do_CreateInstance(NS_ARRAY_CONTRACTID, &rv); + NS_ENSURE_SUCCESS(rv, rv); + + // copy options into JS array + for (uint32_t i = 0; i < mOptions.Length(); ++i) { + nsCOMPtr isupportsString = + do_CreateInstance(NS_SUPPORTS_STRING_CONTRACTID, &rv); + NS_ENSURE_SUCCESS(rv, rv); + + rv = isupportsString->SetData(mOptions[i]); + NS_ENSURE_SUCCESS(rv, rv); + + rv = options->AppendElement(isupportsString, false); + NS_ENSURE_SUCCESS(rv, rv); + } + + NS_ADDREF(*aOptions = options); + return NS_OK; +} + +uint32_t +ConvertPermissionRequestToArray(nsTArray& aSrcArray, + nsIMutableArray* aDesArray) +{ + uint32_t len = aSrcArray.Length(); + for (uint32_t i = 0; i < len; i++) { + nsRefPtr cpt = + new ContentPermissionType(aSrcArray[i].type(), + aSrcArray[i].access(), + aSrcArray[i].options()); + aDesArray->AppendElement(cpt, false); + } + return len; +} + +nsresult +CreatePermissionArray(const nsACString& aType, + const nsACString& aAccess, + const nsTArray& aOptions, + nsIArray** aTypesArray) +{ + nsCOMPtr types = do_CreateInstance(NS_ARRAY_CONTRACTID); + nsRefPtr permType = new ContentPermissionType(aType, + aAccess, + aOptions); + types->AppendElement(permType, false); + types.forget(aTypesArray); + + return NS_OK; +} + +PContentPermissionRequestParent* +CreateContentPermissionRequestParent(const nsTArray& 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 nsTArray& requests, + ContentPermissionRequestParent* parent) +{ + NS_ASSERTION(parent, "null parent"); + mParent = parent; + mPermissionRequests = requests; + + nsCOMPtr prompt = do_CreateInstance(NS_CONTENT_PERMISSION_PROMPT_CONTRACTID); + if (!prompt) { + return NS_ERROR_FAILURE; + } + + prompt->Prompt(this); + return NS_OK; +} + +void +nsContentPermissionRequestProxy::OnParentDestroyed() +{ + mParent = nullptr; +} + +NS_IMPL_ISUPPORTS(nsContentPermissionRequestProxy, nsIContentPermissionRequest) + +NS_IMETHODIMP +nsContentPermissionRequestProxy::GetTypes(nsIArray** aTypes) +{ + nsCOMPtr 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; +} + +NS_IMETHODIMP +nsContentPermissionRequestProxy::GetPrincipal(nsIPrincipal * *aRequestingPrincipal) +{ + NS_ENSURE_ARG_POINTER(aRequestingPrincipal); + if (mParent == nullptr) { + return NS_ERROR_FAILURE; + } + + NS_ADDREF(*aRequestingPrincipal = mParent->mPrincipal); + return NS_OK; +} + +NS_IMETHODIMP +nsContentPermissionRequestProxy::GetElement(nsIDOMElement * *aRequestingElement) +{ + NS_ENSURE_ARG_POINTER(aRequestingElement); + if (mParent == nullptr) { + return NS_ERROR_FAILURE; + } + + nsCOMPtr elem = do_QueryInterface(mParent->mElement); + elem.forget(aRequestingElement); + return NS_OK; +} + +NS_IMETHODIMP +nsContentPermissionRequestProxy::Cancel() +{ + if (mParent == nullptr) { + return NS_ERROR_FAILURE; + } + + // 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; + } + + nsTArray emptyChoices; + + unused << ContentPermissionRequestParent::Send__delete__(mParent, false, emptyChoices); + mParent = nullptr; + return NS_OK; +} + +NS_IMETHODIMP +nsContentPermissionRequestProxy::Allow(JS::HandleValue aChoices) +{ + if (mParent == nullptr) { + return NS_ERROR_FAILURE; + } + + // 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 + 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(mParent->Manager())->Manager()->Pid()); + } + if (mPermissionRequests[i].type().Equals("video-capture")) { + GonkPermissionService::GetInstance()->addGrantInfo( + "android.permission.CAMERA", + static_cast(mParent->Manager())->Manager()->Pid()); + } + } +#endif + + nsTArray choices; + if (aChoices.isNullOrUndefined()) { + // No choice is specified. + } else if (aChoices.isObject()) { + // Iterate through all permission types. + for (uint32_t i = 0; i < mPermissionRequests.Length(); ++i) { + nsCString type = mPermissionRequests[i].type(); + + mozilla::AutoSafeJSContext cx; + JS::Rooted obj(cx, &aChoices.toObject()); + JSAutoCompartment ac(cx, obj); + + JS::Rooted val(cx); + + if (!JS_GetProperty(cx, obj, type.BeginReading(), &val) || + !val.isString()) { + // no setting for the permission type, skip it + } else { + nsDependentJSString choice; + if (!choice.init(cx, val)) { + return NS_ERROR_FAILURE; + } + choices.AppendElement(PermissionChoice(type, choice)); + } + } + } else { + MOZ_ASSERT(false, "SelectedChoices should be undefined or an JS object"); + return NS_ERROR_FAILURE; + } + + unused << ContentPermissionRequestParent::Send__delete__(mParent, true, choices); + mParent = nullptr; + return NS_OK; +}