michael@0: /* This Source Code Form is subject to the terms of the Mozilla Public michael@0: * License, v. 2.0. If a copy of the MPL was not distributed with this michael@0: * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ michael@0: michael@0: #ifdef MOZ_WIDGET_GONK michael@0: #include "GonkPermission.h" michael@0: #include "mozilla/dom/ContentParent.h" michael@0: #endif // MOZ_WIDGET_GONK michael@0: #include "nsCOMPtr.h" michael@0: #include "nsIDOMElement.h" michael@0: #include "nsIPrincipal.h" michael@0: #include "mozilla/dom/Element.h" michael@0: #include "mozilla/dom/PContentPermission.h" michael@0: #include "mozilla/dom/PermissionMessageUtils.h" michael@0: #include "mozilla/dom/PContentPermissionRequestParent.h" michael@0: #include "mozilla/dom/TabParent.h" michael@0: #include "mozilla/unused.h" michael@0: #include "nsComponentManagerUtils.h" michael@0: #include "nsArrayUtils.h" michael@0: #include "nsIMutableArray.h" michael@0: #include "nsContentPermissionHelper.h" michael@0: #include "nsCxPusher.h" michael@0: #include "nsJSUtils.h" michael@0: #include "nsISupportsPrimitives.h" michael@0: michael@0: using mozilla::unused; // michael@0: using namespace mozilla::dom; michael@0: using namespace mozilla; michael@0: michael@0: namespace mozilla { michael@0: namespace dom { michael@0: michael@0: class ContentPermissionRequestParent : public PContentPermissionRequestParent michael@0: { michael@0: public: michael@0: ContentPermissionRequestParent(const nsTArray& aRequests, michael@0: Element* element, michael@0: const IPC::Principal& principal); michael@0: virtual ~ContentPermissionRequestParent(); michael@0: michael@0: bool IsBeingDestroyed(); michael@0: michael@0: nsCOMPtr mPrincipal; michael@0: nsCOMPtr mElement; michael@0: nsRefPtr mProxy; michael@0: nsTArray mRequests; michael@0: michael@0: private: michael@0: virtual bool Recvprompt(); michael@0: virtual void ActorDestroy(ActorDestroyReason why); michael@0: }; michael@0: michael@0: ContentPermissionRequestParent::ContentPermissionRequestParent(const nsTArray& aRequests, michael@0: Element* aElement, michael@0: const IPC::Principal& aPrincipal) michael@0: { michael@0: MOZ_COUNT_CTOR(ContentPermissionRequestParent); michael@0: michael@0: mPrincipal = aPrincipal; michael@0: mElement = aElement; michael@0: mRequests = aRequests; michael@0: } michael@0: michael@0: ContentPermissionRequestParent::~ContentPermissionRequestParent() michael@0: { michael@0: MOZ_COUNT_DTOR(ContentPermissionRequestParent); michael@0: } michael@0: michael@0: bool michael@0: ContentPermissionRequestParent::Recvprompt() michael@0: { michael@0: mProxy = new nsContentPermissionRequestProxy(); michael@0: NS_ASSERTION(mProxy, "Alloc of request proxy failed"); michael@0: if (NS_FAILED(mProxy->Init(mRequests, this))) { michael@0: mProxy->Cancel(); michael@0: } michael@0: return true; michael@0: } michael@0: michael@0: void michael@0: ContentPermissionRequestParent::ActorDestroy(ActorDestroyReason why) michael@0: { michael@0: if (mProxy) { michael@0: mProxy->OnParentDestroyed(); michael@0: } michael@0: } michael@0: michael@0: bool michael@0: ContentPermissionRequestParent::IsBeingDestroyed() michael@0: { michael@0: // When TabParent::Destroy() is called, we are being destroyed. It's unsafe michael@0: // to send out any message now. michael@0: TabParent* tabParent = static_cast(Manager()); michael@0: return tabParent->IsDestroyed(); michael@0: } michael@0: michael@0: NS_IMPL_ISUPPORTS(ContentPermissionType, nsIContentPermissionType) michael@0: michael@0: ContentPermissionType::ContentPermissionType(const nsACString& aType, michael@0: const nsACString& aAccess, michael@0: const nsTArray& aOptions) michael@0: { michael@0: mType = aType; michael@0: mAccess = aAccess; michael@0: mOptions = aOptions; michael@0: } michael@0: michael@0: ContentPermissionType::~ContentPermissionType() michael@0: { michael@0: } michael@0: michael@0: NS_IMETHODIMP michael@0: ContentPermissionType::GetType(nsACString& aType) michael@0: { michael@0: aType = mType; michael@0: return NS_OK; michael@0: } michael@0: michael@0: NS_IMETHODIMP michael@0: ContentPermissionType::GetAccess(nsACString& aAccess) michael@0: { michael@0: aAccess = mAccess; michael@0: return NS_OK; michael@0: } michael@0: michael@0: NS_IMETHODIMP michael@0: ContentPermissionType::GetOptions(nsIArray** aOptions) michael@0: { michael@0: NS_ENSURE_ARG_POINTER(aOptions); michael@0: michael@0: *aOptions = nullptr; michael@0: michael@0: nsresult rv; michael@0: nsCOMPtr options = michael@0: do_CreateInstance(NS_ARRAY_CONTRACTID, &rv); michael@0: NS_ENSURE_SUCCESS(rv, rv); michael@0: michael@0: // copy options into JS array michael@0: for (uint32_t i = 0; i < mOptions.Length(); ++i) { michael@0: nsCOMPtr isupportsString = michael@0: do_CreateInstance(NS_SUPPORTS_STRING_CONTRACTID, &rv); michael@0: NS_ENSURE_SUCCESS(rv, rv); michael@0: michael@0: rv = isupportsString->SetData(mOptions[i]); michael@0: NS_ENSURE_SUCCESS(rv, rv); michael@0: michael@0: rv = options->AppendElement(isupportsString, false); michael@0: NS_ENSURE_SUCCESS(rv, rv); michael@0: } michael@0: michael@0: NS_ADDREF(*aOptions = options); michael@0: return NS_OK; michael@0: } michael@0: michael@0: uint32_t michael@0: ConvertPermissionRequestToArray(nsTArray& aSrcArray, michael@0: nsIMutableArray* aDesArray) michael@0: { michael@0: uint32_t len = aSrcArray.Length(); michael@0: for (uint32_t i = 0; i < len; i++) { michael@0: nsRefPtr cpt = michael@0: new ContentPermissionType(aSrcArray[i].type(), michael@0: aSrcArray[i].access(), michael@0: aSrcArray[i].options()); michael@0: aDesArray->AppendElement(cpt, false); michael@0: } michael@0: return len; michael@0: } michael@0: michael@0: nsresult michael@0: CreatePermissionArray(const nsACString& aType, michael@0: const nsACString& aAccess, michael@0: const nsTArray& aOptions, michael@0: nsIArray** aTypesArray) michael@0: { michael@0: nsCOMPtr types = do_CreateInstance(NS_ARRAY_CONTRACTID); michael@0: nsRefPtr permType = new ContentPermissionType(aType, michael@0: aAccess, michael@0: aOptions); michael@0: types->AppendElement(permType, false); michael@0: types.forget(aTypesArray); michael@0: michael@0: return NS_OK; michael@0: } michael@0: michael@0: PContentPermissionRequestParent* michael@0: CreateContentPermissionRequestParent(const nsTArray& aRequests, michael@0: Element* element, michael@0: const IPC::Principal& principal) michael@0: { michael@0: return new ContentPermissionRequestParent(aRequests, element, principal); michael@0: } michael@0: michael@0: } // namespace dom michael@0: } // namespace mozilla michael@0: michael@0: nsContentPermissionRequestProxy::nsContentPermissionRequestProxy() michael@0: { michael@0: MOZ_COUNT_CTOR(nsContentPermissionRequestProxy); michael@0: } michael@0: michael@0: nsContentPermissionRequestProxy::~nsContentPermissionRequestProxy() michael@0: { michael@0: MOZ_COUNT_DTOR(nsContentPermissionRequestProxy); michael@0: } michael@0: michael@0: nsresult michael@0: nsContentPermissionRequestProxy::Init(const nsTArray& requests, michael@0: ContentPermissionRequestParent* parent) michael@0: { michael@0: NS_ASSERTION(parent, "null parent"); michael@0: mParent = parent; michael@0: mPermissionRequests = requests; michael@0: michael@0: nsCOMPtr prompt = do_CreateInstance(NS_CONTENT_PERMISSION_PROMPT_CONTRACTID); michael@0: if (!prompt) { michael@0: return NS_ERROR_FAILURE; michael@0: } michael@0: michael@0: prompt->Prompt(this); michael@0: return NS_OK; michael@0: } michael@0: michael@0: void michael@0: nsContentPermissionRequestProxy::OnParentDestroyed() michael@0: { michael@0: mParent = nullptr; michael@0: } michael@0: michael@0: NS_IMPL_ISUPPORTS(nsContentPermissionRequestProxy, nsIContentPermissionRequest) michael@0: michael@0: NS_IMETHODIMP michael@0: nsContentPermissionRequestProxy::GetTypes(nsIArray** aTypes) michael@0: { michael@0: nsCOMPtr types = do_CreateInstance(NS_ARRAY_CONTRACTID); michael@0: if (ConvertPermissionRequestToArray(mPermissionRequests, types)) { michael@0: types.forget(aTypes); michael@0: return NS_OK; michael@0: } michael@0: return NS_ERROR_FAILURE; michael@0: } michael@0: michael@0: NS_IMETHODIMP michael@0: nsContentPermissionRequestProxy::GetWindow(nsIDOMWindow * *aRequestingWindow) michael@0: { michael@0: NS_ENSURE_ARG_POINTER(aRequestingWindow); michael@0: *aRequestingWindow = nullptr; // ipc doesn't have a window michael@0: return NS_OK; michael@0: } michael@0: michael@0: NS_IMETHODIMP michael@0: nsContentPermissionRequestProxy::GetPrincipal(nsIPrincipal * *aRequestingPrincipal) michael@0: { michael@0: NS_ENSURE_ARG_POINTER(aRequestingPrincipal); michael@0: if (mParent == nullptr) { michael@0: return NS_ERROR_FAILURE; michael@0: } michael@0: michael@0: NS_ADDREF(*aRequestingPrincipal = mParent->mPrincipal); michael@0: return NS_OK; michael@0: } michael@0: michael@0: NS_IMETHODIMP michael@0: nsContentPermissionRequestProxy::GetElement(nsIDOMElement * *aRequestingElement) michael@0: { michael@0: NS_ENSURE_ARG_POINTER(aRequestingElement); michael@0: if (mParent == nullptr) { michael@0: return NS_ERROR_FAILURE; michael@0: } michael@0: michael@0: nsCOMPtr elem = do_QueryInterface(mParent->mElement); michael@0: elem.forget(aRequestingElement); michael@0: return NS_OK; michael@0: } michael@0: michael@0: NS_IMETHODIMP michael@0: nsContentPermissionRequestProxy::Cancel() michael@0: { michael@0: if (mParent == nullptr) { michael@0: return NS_ERROR_FAILURE; michael@0: } michael@0: michael@0: // Don't send out the delete message when the managing protocol (PBrowser) is michael@0: // being destroyed and PContentPermissionRequest will soon be. michael@0: if (mParent->IsBeingDestroyed()) { michael@0: return NS_ERROR_FAILURE; michael@0: } michael@0: michael@0: nsTArray emptyChoices; michael@0: michael@0: unused << ContentPermissionRequestParent::Send__delete__(mParent, false, emptyChoices); michael@0: mParent = nullptr; michael@0: return NS_OK; michael@0: } michael@0: michael@0: NS_IMETHODIMP michael@0: nsContentPermissionRequestProxy::Allow(JS::HandleValue aChoices) michael@0: { michael@0: if (mParent == nullptr) { michael@0: return NS_ERROR_FAILURE; michael@0: } michael@0: michael@0: // Don't send out the delete message when the managing protocol (PBrowser) is michael@0: // being destroyed and PContentPermissionRequest will soon be. michael@0: if (mParent->IsBeingDestroyed()) { michael@0: return NS_ERROR_FAILURE; michael@0: } michael@0: michael@0: #ifdef MOZ_WIDGET_GONK michael@0: uint32_t len = mPermissionRequests.Length(); michael@0: for (uint32_t i = 0; i < len; i++) { michael@0: if (mPermissionRequests[i].type().Equals("audio-capture")) { michael@0: GonkPermissionService::GetInstance()->addGrantInfo( michael@0: "android.permission.RECORD_AUDIO", michael@0: static_cast(mParent->Manager())->Manager()->Pid()); michael@0: } michael@0: if (mPermissionRequests[i].type().Equals("video-capture")) { michael@0: GonkPermissionService::GetInstance()->addGrantInfo( michael@0: "android.permission.CAMERA", michael@0: static_cast(mParent->Manager())->Manager()->Pid()); michael@0: } michael@0: } michael@0: #endif michael@0: michael@0: nsTArray choices; michael@0: if (aChoices.isNullOrUndefined()) { michael@0: // No choice is specified. michael@0: } else if (aChoices.isObject()) { michael@0: // Iterate through all permission types. michael@0: for (uint32_t i = 0; i < mPermissionRequests.Length(); ++i) { michael@0: nsCString type = mPermissionRequests[i].type(); michael@0: michael@0: mozilla::AutoSafeJSContext cx; michael@0: JS::Rooted obj(cx, &aChoices.toObject()); michael@0: JSAutoCompartment ac(cx, obj); michael@0: michael@0: JS::Rooted val(cx); michael@0: michael@0: if (!JS_GetProperty(cx, obj, type.BeginReading(), &val) || michael@0: !val.isString()) { michael@0: // no setting for the permission type, skip it michael@0: } else { michael@0: nsDependentJSString choice; michael@0: if (!choice.init(cx, val)) { michael@0: return NS_ERROR_FAILURE; michael@0: } michael@0: choices.AppendElement(PermissionChoice(type, choice)); michael@0: } michael@0: } michael@0: } else { michael@0: MOZ_ASSERT(false, "SelectedChoices should be undefined or an JS object"); michael@0: return NS_ERROR_FAILURE; michael@0: } michael@0: michael@0: unused << ContentPermissionRequestParent::Send__delete__(mParent, true, choices); michael@0: mParent = nullptr; michael@0: return NS_OK; michael@0: }