1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2 /* vim: set ts=8 sts=2 et sw=2 tw=80: */
3 /* This Source Code Form is subject to the terms of the Mozilla Public
4 * License, v. 2.0. If a copy of the MPL was not distributed with this
5 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
9 #include "nsIPrincipal.h"
10 #include "mozilla/dom/BrowserChild.h"
11 #include "mozilla/dom/BrowserParent.h"
12 #include "mozilla/dom/ContentChild.h"
13 #include "mozilla/dom/ContentParent.h"
14 #include "mozilla/dom/Element.h"
15 #include "mozilla/dom/Event.h"
16 #include "mozilla/dom/PContentPermission.h"
17 #include "mozilla/dom/PermissionMessageUtils.h"
18 #include "mozilla/dom/PContentPermissionRequestParent.h"
19 #include "mozilla/dom/ScriptSettings.h"
20 #include "mozilla/Attributes.h"
21 #include "mozilla/Preferences.h"
22 #include "mozilla/Unused.h"
23 #include "nsComponentManagerUtils.h"
24 #include "nsArrayUtils.h"
25 #include "nsIMutableArray.h"
26 #include "nsContentPermissionHelper.h"
27 #include "nsGlobalWindowInner.h"
28 #include "nsJSUtils.h"
29 #include "nsISupportsPrimitives.h"
30 #include "nsServiceManagerUtils.h"
31 #include "mozilla/dom/Document.h"
32 #include "nsIWeakReferenceUtils.h"
33 #include "js/PropertyAndElement.h" // JS_GetProperty, JS_SetProperty
35 using mozilla::Unused
; // <snicker>
36 using namespace mozilla::dom
;
37 using namespace mozilla
;
38 using DelegateInfo
= PermissionDelegateHandler::PermissionDelegateInfo
;
40 namespace mozilla::dom
{
42 class ContentPermissionRequestParent
: public PContentPermissionRequestParent
{
44 // @param aIsRequestDelegatedToUnsafeThirdParty see
45 // mIsRequestDelegatedToUnsafeThirdParty.
46 ContentPermissionRequestParent(
47 const nsTArray
<PermissionRequest
>& aRequests
, Element
* aElement
,
48 nsIPrincipal
* aPrincipal
, nsIPrincipal
* aTopLevelPrincipal
,
49 const bool aHasValidTransientUserGestureActivation
,
50 const bool aIsRequestDelegatedToUnsafeThirdParty
);
51 virtual ~ContentPermissionRequestParent();
53 bool IsBeingDestroyed();
55 nsCOMPtr
<nsIPrincipal
> mPrincipal
;
56 nsCOMPtr
<nsIPrincipal
> mTopLevelPrincipal
;
57 nsCOMPtr
<Element
> mElement
;
58 bool mHasValidTransientUserGestureActivation
;
60 // See nsIPermissionDelegateHandler.maybeUnsafePermissionDelegate.
61 bool mIsRequestDelegatedToUnsafeThirdParty
;
63 RefPtr
<nsContentPermissionRequestProxy
> mProxy
;
64 nsTArray
<PermissionRequest
> mRequests
;
67 // Not MOZ_CAN_RUN_SCRIPT because we can't annotate the thing we override yet.
68 MOZ_CAN_RUN_SCRIPT_BOUNDARY
69 virtual mozilla::ipc::IPCResult
Recvprompt() override
;
70 virtual mozilla::ipc::IPCResult
RecvDestroy() override
;
71 virtual void ActorDestroy(ActorDestroyReason why
) override
;
74 ContentPermissionRequestParent::ContentPermissionRequestParent(
75 const nsTArray
<PermissionRequest
>& aRequests
, Element
* aElement
,
76 nsIPrincipal
* aPrincipal
, nsIPrincipal
* aTopLevelPrincipal
,
77 const bool aHasValidTransientUserGestureActivation
,
78 const bool aIsRequestDelegatedToUnsafeThirdParty
) {
79 MOZ_COUNT_CTOR(ContentPermissionRequestParent
);
81 mPrincipal
= aPrincipal
;
82 mTopLevelPrincipal
= aTopLevelPrincipal
;
84 mRequests
= aRequests
.Clone();
85 mHasValidTransientUserGestureActivation
=
86 aHasValidTransientUserGestureActivation
;
87 mIsRequestDelegatedToUnsafeThirdParty
= aIsRequestDelegatedToUnsafeThirdParty
;
90 ContentPermissionRequestParent::~ContentPermissionRequestParent() {
91 MOZ_COUNT_DTOR(ContentPermissionRequestParent
);
94 mozilla::ipc::IPCResult
ContentPermissionRequestParent::Recvprompt() {
95 mProxy
= new nsContentPermissionRequestProxy(this);
96 if (NS_FAILED(mProxy
->Init(mRequests
))) {
97 RefPtr
<nsContentPermissionRequestProxy
> proxy(mProxy
);
103 mozilla::ipc::IPCResult
ContentPermissionRequestParent::RecvDestroy() {
104 Unused
<< PContentPermissionRequestParent::Send__delete__(this);
108 void ContentPermissionRequestParent::ActorDestroy(ActorDestroyReason why
) {
110 mProxy
->OnParentDestroyed();
114 bool ContentPermissionRequestParent::IsBeingDestroyed() {
115 // When ContentParent::MarkAsDead() is called, we are being destroyed.
116 // It's unsafe to send out any message now.
117 ContentParent
* contentParent
= static_cast<ContentParent
*>(Manager());
118 return !contentParent
->IsAlive();
121 NS_IMPL_ISUPPORTS(ContentPermissionType
, nsIContentPermissionType
)
123 ContentPermissionType::ContentPermissionType(
124 const nsACString
& aType
, const nsTArray
<nsString
>& aOptions
) {
126 mOptions
= aOptions
.Clone();
129 ContentPermissionType::~ContentPermissionType() = default;
132 ContentPermissionType::GetType(nsACString
& aType
) {
138 ContentPermissionType::GetOptions(nsIArray
** aOptions
) {
139 NS_ENSURE_ARG_POINTER(aOptions
);
144 nsCOMPtr
<nsIMutableArray
> options
=
145 do_CreateInstance(NS_ARRAY_CONTRACTID
, &rv
);
146 NS_ENSURE_SUCCESS(rv
, rv
);
148 // copy options into JS array
149 for (uint32_t i
= 0; i
< mOptions
.Length(); ++i
) {
150 nsCOMPtr
<nsISupportsString
> isupportsString
=
151 do_CreateInstance(NS_SUPPORTS_STRING_CONTRACTID
, &rv
);
152 NS_ENSURE_SUCCESS(rv
, rv
);
154 rv
= isupportsString
->SetData(mOptions
[i
]);
155 NS_ENSURE_SUCCESS(rv
, rv
);
157 rv
= options
->AppendElement(isupportsString
);
158 NS_ENSURE_SUCCESS(rv
, rv
);
161 options
.forget(aOptions
);
165 // nsContentPermissionUtils
168 uint32_t nsContentPermissionUtils::ConvertPermissionRequestToArray(
169 nsTArray
<PermissionRequest
>& aSrcArray
, nsIMutableArray
* aDesArray
) {
170 uint32_t len
= aSrcArray
.Length();
171 for (uint32_t i
= 0; i
< len
; i
++) {
172 RefPtr
<ContentPermissionType
> cpt
=
173 new ContentPermissionType(aSrcArray
[i
].type(), aSrcArray
[i
].options());
174 aDesArray
->AppendElement(cpt
);
180 void nsContentPermissionUtils::ConvertArrayToPermissionRequest(
181 nsIArray
* aSrcArray
, nsTArray
<PermissionRequest
>& aDesArray
) {
183 aSrcArray
->GetLength(&len
);
184 for (uint32_t i
= 0; i
< len
; i
++) {
185 nsCOMPtr
<nsIContentPermissionType
> cpt
= do_QueryElementAt(aSrcArray
, i
);
189 nsCOMPtr
<nsIArray
> optionArray
;
190 cpt
->GetOptions(getter_AddRefs(optionArray
));
191 uint32_t optionsLength
= 0;
193 optionArray
->GetLength(&optionsLength
);
195 nsTArray
<nsString
> options
;
196 for (uint32_t j
= 0; j
< optionsLength
; ++j
) {
197 nsCOMPtr
<nsISupportsString
> isupportsString
=
198 do_QueryElementAt(optionArray
, j
);
199 if (isupportsString
) {
201 isupportsString
->GetData(option
);
202 options
.AppendElement(option
);
206 aDesArray
.AppendElement(PermissionRequest(type
, options
));
210 static std::map
<PContentPermissionRequestParent
*, TabId
>&
211 ContentPermissionRequestParentMap() {
212 MOZ_ASSERT(NS_IsMainThread());
213 static std::map
<PContentPermissionRequestParent
*, TabId
>
214 sPermissionRequestParentMap
;
215 return sPermissionRequestParentMap
;
218 static std::map
<PContentPermissionRequestChild
*, TabId
>&
219 ContentPermissionRequestChildMap() {
220 MOZ_ASSERT(NS_IsMainThread());
221 static std::map
<PContentPermissionRequestChild
*, TabId
>
222 sPermissionRequestChildMap
;
223 return sPermissionRequestChildMap
;
227 nsresult
nsContentPermissionUtils::CreatePermissionArray(
228 const nsACString
& aType
, const nsTArray
<nsString
>& aOptions
,
229 nsIArray
** aTypesArray
) {
230 nsCOMPtr
<nsIMutableArray
> types
= do_CreateInstance(NS_ARRAY_CONTRACTID
);
231 RefPtr
<ContentPermissionType
> permType
=
232 new ContentPermissionType(aType
, aOptions
);
233 types
->AppendElement(permType
);
234 types
.forget(aTypesArray
);
240 PContentPermissionRequestParent
*
241 nsContentPermissionUtils::CreateContentPermissionRequestParent(
242 const nsTArray
<PermissionRequest
>& aRequests
, Element
* aElement
,
243 nsIPrincipal
* aPrincipal
, nsIPrincipal
* aTopLevelPrincipal
,
244 const bool aHasValidTransientUserGestureActivation
,
245 const bool aIsRequestDelegatedToUnsafeThirdParty
, const TabId
& aTabId
) {
246 PContentPermissionRequestParent
* parent
= new ContentPermissionRequestParent(
247 aRequests
, aElement
, aPrincipal
, aTopLevelPrincipal
,
248 aHasValidTransientUserGestureActivation
,
249 aIsRequestDelegatedToUnsafeThirdParty
);
250 ContentPermissionRequestParentMap()[parent
] = aTabId
;
256 nsresult
nsContentPermissionUtils::AskPermission(
257 nsIContentPermissionRequest
* aRequest
, nsPIDOMWindowInner
* aWindow
) {
258 NS_ENSURE_STATE(aWindow
&& aWindow
->IsCurrentInnerWindow());
260 // for content process
261 if (XRE_IsContentProcess()) {
262 RefPtr
<RemotePermissionRequest
> req
=
263 new RemotePermissionRequest(aRequest
, aWindow
);
265 MOZ_ASSERT(NS_IsMainThread()); // IPC can only be execute on main thread.
267 BrowserChild
* child
= BrowserChild::GetFrom(aWindow
->GetDocShell());
268 NS_ENSURE_TRUE(child
, NS_ERROR_FAILURE
);
270 nsCOMPtr
<nsIArray
> typeArray
;
271 nsresult rv
= aRequest
->GetTypes(getter_AddRefs(typeArray
));
272 NS_ENSURE_SUCCESS(rv
, rv
);
274 nsTArray
<PermissionRequest
> permArray
;
275 ConvertArrayToPermissionRequest(typeArray
, permArray
);
277 nsCOMPtr
<nsIPrincipal
> principal
;
278 rv
= aRequest
->GetPrincipal(getter_AddRefs(principal
));
279 NS_ENSURE_SUCCESS(rv
, rv
);
281 nsCOMPtr
<nsIPrincipal
> topLevelPrincipal
;
282 rv
= aRequest
->GetTopLevelPrincipal(getter_AddRefs(topLevelPrincipal
));
283 NS_ENSURE_SUCCESS(rv
, rv
);
285 bool hasValidTransientUserGestureActivation
;
286 rv
= aRequest
->GetHasValidTransientUserGestureActivation(
287 &hasValidTransientUserGestureActivation
);
288 NS_ENSURE_SUCCESS(rv
, rv
);
290 bool isRequestDelegatedToUnsafeThirdParty
;
291 rv
= aRequest
->GetIsRequestDelegatedToUnsafeThirdParty(
292 &isRequestDelegatedToUnsafeThirdParty
);
293 NS_ENSURE_SUCCESS(rv
, rv
);
296 if (!ContentChild::GetSingleton()->SendPContentPermissionRequestConstructor(
297 req
, permArray
, principal
, topLevelPrincipal
,
298 hasValidTransientUserGestureActivation
,
299 isRequestDelegatedToUnsafeThirdParty
, child
->GetTabId())) {
300 return NS_ERROR_FAILURE
;
302 ContentPermissionRequestChildMap()[req
.get()] = child
->GetTabId();
308 // for chrome process
309 nsCOMPtr
<nsIContentPermissionPrompt
> prompt
=
310 do_GetService(NS_CONTENT_PERMISSION_PROMPT_CONTRACTID
);
312 if (NS_FAILED(prompt
->Prompt(aRequest
))) {
313 return NS_ERROR_FAILURE
;
320 nsTArray
<PContentPermissionRequestParent
*>
321 nsContentPermissionUtils::GetContentPermissionRequestParentById(
322 const TabId
& aTabId
) {
323 nsTArray
<PContentPermissionRequestParent
*> parentArray
;
324 for (auto& it
: ContentPermissionRequestParentMap()) {
325 if (it
.second
== aTabId
) {
326 parentArray
.AppendElement(it
.first
);
334 void nsContentPermissionUtils::NotifyRemoveContentPermissionRequestParent(
335 PContentPermissionRequestParent
* aParent
) {
336 auto it
= ContentPermissionRequestParentMap().find(aParent
);
337 MOZ_ASSERT(it
!= ContentPermissionRequestParentMap().end());
339 ContentPermissionRequestParentMap().erase(it
);
343 nsTArray
<PContentPermissionRequestChild
*>
344 nsContentPermissionUtils::GetContentPermissionRequestChildById(
345 const TabId
& aTabId
) {
346 nsTArray
<PContentPermissionRequestChild
*> childArray
;
347 for (auto& it
: ContentPermissionRequestChildMap()) {
348 if (it
.second
== aTabId
) {
349 childArray
.AppendElement(it
.first
);
357 void nsContentPermissionUtils::NotifyRemoveContentPermissionRequestChild(
358 PContentPermissionRequestChild
* aChild
) {
359 auto it
= ContentPermissionRequestChildMap().find(aChild
);
360 MOZ_ASSERT(it
!= ContentPermissionRequestChildMap().end());
362 ContentPermissionRequestChildMap().erase(it
);
365 static nsIPrincipal
* GetTopLevelPrincipal(nsPIDOMWindowInner
* aWindow
) {
368 BrowsingContext
* top
= aWindow
->GetBrowsingContext()->Top();
371 nsPIDOMWindowOuter
* outer
= top
->GetDOMWindow();
376 nsPIDOMWindowInner
* inner
= outer
->GetCurrentInnerWindow();
381 return nsGlobalWindowInner::Cast(inner
)->GetPrincipal();
384 NS_IMPL_CYCLE_COLLECTION(ContentPermissionRequestBase
, mPrincipal
,
385 mTopLevelPrincipal
, mWindow
)
387 NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(ContentPermissionRequestBase
)
388 NS_INTERFACE_MAP_ENTRY_CONCRETE(nsISupports
)
389 NS_INTERFACE_MAP_ENTRY_CONCRETE(nsIContentPermissionRequest
)
392 NS_IMPL_CYCLE_COLLECTING_ADDREF(ContentPermissionRequestBase
)
393 NS_IMPL_CYCLE_COLLECTING_RELEASE(ContentPermissionRequestBase
)
395 ContentPermissionRequestBase::ContentPermissionRequestBase(
396 nsIPrincipal
* aPrincipal
, nsPIDOMWindowInner
* aWindow
,
397 const nsACString
& aPrefName
, const nsACString
& aType
)
398 : mPrincipal(aPrincipal
),
399 mTopLevelPrincipal(aWindow
? ::GetTopLevelPrincipal(aWindow
) : nullptr),
401 mPrefName(aPrefName
),
403 mHasValidTransientUserGestureActivation(false),
404 mIsRequestDelegatedToUnsafeThirdParty(false) {
409 Document
* doc
= aWindow
->GetExtantDoc();
414 mHasValidTransientUserGestureActivation
=
415 doc
->HasValidTransientUserGestureActivation();
417 mPermissionHandler
= doc
->GetPermissionDelegateHandler();
418 if (mPermissionHandler
) {
419 nsTArray
<nsCString
> types
;
420 types
.AppendElement(mType
);
421 mPermissionHandler
->MaybeUnsafePermissionDelegate(
422 types
, &mIsRequestDelegatedToUnsafeThirdParty
);
427 ContentPermissionRequestBase::GetPrincipal(
428 nsIPrincipal
** aRequestingPrincipal
) {
429 NS_IF_ADDREF(*aRequestingPrincipal
= mPrincipal
);
434 ContentPermissionRequestBase::GetDelegatePrincipal(
435 const nsACString
& aType
, nsIPrincipal
** aRequestingPrincipal
) {
436 return PermissionDelegateHandler::GetDelegatePrincipal(aType
, this,
437 aRequestingPrincipal
);
441 ContentPermissionRequestBase::GetIsRequestDelegatedToUnsafeThirdParty(
442 bool* aIsRequestDelegatedToUnsafeThirdParty
) {
443 *aIsRequestDelegatedToUnsafeThirdParty
=
444 mIsRequestDelegatedToUnsafeThirdParty
;
449 ContentPermissionRequestBase::GetTopLevelPrincipal(
450 nsIPrincipal
** aRequestingPrincipal
) {
451 if (!mTopLevelPrincipal
) {
452 *aRequestingPrincipal
= nullptr;
456 NS_IF_ADDREF(*aRequestingPrincipal
= mTopLevelPrincipal
);
461 ContentPermissionRequestBase::GetWindow(mozIDOMWindow
** aRequestingWindow
) {
462 NS_IF_ADDREF(*aRequestingWindow
= mWindow
);
467 ContentPermissionRequestBase::GetElement(Element
** aElement
) {
468 NS_ENSURE_ARG_POINTER(aElement
);
474 ContentPermissionRequestBase::GetHasValidTransientUserGestureActivation(
475 bool* aHasValidTransientUserGestureActivation
) {
476 *aHasValidTransientUserGestureActivation
=
477 mHasValidTransientUserGestureActivation
;
482 ContentPermissionRequestBase::GetTypes(nsIArray
** aTypes
) {
483 nsTArray
<nsString
> emptyOptions
;
484 return nsContentPermissionUtils::CreatePermissionArray(mType
, emptyOptions
,
488 ContentPermissionRequestBase::PromptResult
489 ContentPermissionRequestBase::CheckPromptPrefs() const {
490 MOZ_ASSERT(!mPrefName
.IsEmpty(),
491 "This derived class must support checking pref types");
493 nsAutoCString
prefName(mPrefName
);
494 prefName
.AppendLiteral(".prompt.testing");
495 if (Preferences::GetBool(PromiseFlatCString(prefName
).get(), false)) {
496 prefName
.AppendLiteral(".allow");
497 if (Preferences::GetBool(PromiseFlatCString(prefName
).get(), true)) {
498 return PromptResult::Granted
;
500 return PromptResult::Denied
;
503 return PromptResult::Pending
;
506 bool ContentPermissionRequestBase::CheckPermissionDelegate() const {
507 // There is case that ContentPermissionRequestBase is constructed without
508 // window, then mPermissionHandler will be null. So we only check permission
509 // delegate if we have non-null mPermissionHandler
510 if (mPermissionHandler
&&
511 !mPermissionHandler
->HasPermissionDelegated(mType
)) {
518 nsresult
ContentPermissionRequestBase::ShowPrompt(
519 ContentPermissionRequestBase::PromptResult
& aResult
) {
520 if (!CheckPermissionDelegate()) {
521 aResult
= PromptResult::Denied
;
525 aResult
= CheckPromptPrefs();
527 if (aResult
!= PromptResult::Pending
) {
531 return nsContentPermissionUtils::AskPermission(this, mWindow
);
534 class RequestPromptEvent
: public Runnable
{
536 RequestPromptEvent(ContentPermissionRequestBase
* aRequest
,
537 nsPIDOMWindowInner
* aWindow
)
538 : mozilla::Runnable("RequestPromptEvent"),
542 NS_IMETHOD
Run() override
{
543 nsContentPermissionUtils::AskPermission(mRequest
, mWindow
);
548 RefPtr
<ContentPermissionRequestBase
> mRequest
;
549 nsCOMPtr
<nsPIDOMWindowInner
> mWindow
;
552 class RequestAllowEvent
: public Runnable
{
554 RequestAllowEvent(bool allow
, ContentPermissionRequestBase
* request
)
555 : mozilla::Runnable("RequestAllowEvent"),
559 // Not MOZ_CAN_RUN_SCRIPT because we can't annotate the thing we override yet.
560 MOZ_CAN_RUN_SCRIPT_BOUNDARY
561 NS_IMETHOD
Run() override
{
562 // MOZ_KnownLive is OK, because we never drop the ref to mRequest.
564 MOZ_KnownLive(mRequest
)->Allow(JS::UndefinedHandleValue
);
566 MOZ_KnownLive(mRequest
)->Cancel();
573 RefPtr
<ContentPermissionRequestBase
> mRequest
;
576 void ContentPermissionRequestBase::RequestDelayedTask(
577 nsIEventTarget
* aTarget
,
578 ContentPermissionRequestBase::DelayedTaskType aType
) {
579 nsCOMPtr
<nsIRunnable
> r
;
581 case DelayedTaskType::Allow
:
582 r
= new RequestAllowEvent(true, this);
584 case DelayedTaskType::Deny
:
585 r
= new RequestAllowEvent(false, this);
588 r
= new RequestPromptEvent(this, mWindow
);
592 aTarget
->Dispatch(r
.forget());
595 nsresult
TranslateChoices(
596 JS::Handle
<JS::Value
> aChoices
,
597 const nsTArray
<PermissionRequest
>& aPermissionRequests
,
598 nsTArray
<PermissionChoice
>& aTranslatedChoices
) {
599 if (aChoices
.isNullOrUndefined()) {
600 // No choice is specified.
601 } else if (aChoices
.isObject()) {
602 // Iterate through all permission types.
603 for (uint32_t i
= 0; i
< aPermissionRequests
.Length(); ++i
) {
604 nsCString type
= aPermissionRequests
[i
].type();
606 JS::Rooted
<JSObject
*> obj(RootingCx(), &aChoices
.toObject());
607 // People really shouldn't be passing WindowProxy or Location
608 // objects for the choices here.
609 obj
= js::CheckedUnwrapStatic(obj
);
611 return NS_ERROR_FAILURE
;
617 JSContext
* cx
= jsapi
.cx();
618 JSAutoRealm
ar(cx
, obj
);
620 JS::Rooted
<JS::Value
> val(cx
);
622 if (!JS_GetProperty(cx
, obj
, type
.BeginReading(), &val
) ||
624 // no setting for the permission type, clear exception and skip it
625 jsapi
.ClearException();
627 nsAutoJSString choice
;
628 if (!choice
.init(cx
, val
)) {
629 jsapi
.ClearException();
630 return NS_ERROR_FAILURE
;
632 aTranslatedChoices
.AppendElement(PermissionChoice(type
, choice
));
636 MOZ_ASSERT(false, "SelectedChoices should be undefined or an JS object");
637 return NS_ERROR_FAILURE
;
643 } // namespace mozilla::dom
645 nsContentPermissionRequestProxy::nsContentPermissionRequestProxy(
646 ContentPermissionRequestParent
* parent
)
648 NS_ASSERTION(mParent
, "null parent");
651 nsContentPermissionRequestProxy::~nsContentPermissionRequestProxy() = default;
653 nsresult
nsContentPermissionRequestProxy::Init(
654 const nsTArray
<PermissionRequest
>& requests
) {
655 mPermissionRequests
= requests
.Clone();
657 nsCOMPtr
<nsIContentPermissionPrompt
> prompt
=
658 do_GetService(NS_CONTENT_PERMISSION_PROMPT_CONTRACTID
);
660 return NS_ERROR_FAILURE
;
663 prompt
->Prompt(this);
667 void nsContentPermissionRequestProxy::OnParentDestroyed() { mParent
= nullptr; }
669 NS_IMPL_ISUPPORTS(nsContentPermissionRequestProxy
, nsIContentPermissionRequest
)
672 nsContentPermissionRequestProxy::GetTypes(nsIArray
** aTypes
) {
673 nsCOMPtr
<nsIMutableArray
> types
= do_CreateInstance(NS_ARRAY_CONTRACTID
);
674 if (mozilla::dom::nsContentPermissionUtils::ConvertPermissionRequestToArray(
675 mPermissionRequests
, types
)) {
676 types
.forget(aTypes
);
679 return NS_ERROR_FAILURE
;
683 nsContentPermissionRequestProxy::GetWindow(mozIDOMWindow
** aRequestingWindow
) {
684 NS_ENSURE_ARG_POINTER(aRequestingWindow
);
685 *aRequestingWindow
= nullptr; // ipc doesn't have a window
690 nsContentPermissionRequestProxy::GetPrincipal(
691 nsIPrincipal
** aRequestingPrincipal
) {
692 NS_ENSURE_ARG_POINTER(aRequestingPrincipal
);
693 if (mParent
== nullptr) {
694 return NS_ERROR_FAILURE
;
697 NS_IF_ADDREF(*aRequestingPrincipal
= mParent
->mPrincipal
);
702 nsContentPermissionRequestProxy::GetTopLevelPrincipal(
703 nsIPrincipal
** aRequestingPrincipal
) {
704 NS_ENSURE_ARG_POINTER(aRequestingPrincipal
);
705 if (mParent
== nullptr) {
706 return NS_ERROR_FAILURE
;
709 NS_IF_ADDREF(*aRequestingPrincipal
= mParent
->mTopLevelPrincipal
);
714 nsContentPermissionRequestProxy::GetDelegatePrincipal(
715 const nsACString
& aType
, nsIPrincipal
** aRequestingPrincipal
) {
716 NS_ENSURE_ARG_POINTER(aRequestingPrincipal
);
717 if (mParent
== nullptr) {
718 return NS_ERROR_FAILURE
;
721 return PermissionDelegateHandler::GetDelegatePrincipal(aType
, this,
722 aRequestingPrincipal
);
726 nsContentPermissionRequestProxy::GetElement(Element
** aRequestingElement
) {
727 NS_ENSURE_ARG_POINTER(aRequestingElement
);
728 if (mParent
== nullptr) {
729 return NS_ERROR_FAILURE
;
732 nsCOMPtr
<Element
> elem
= mParent
->mElement
;
733 elem
.forget(aRequestingElement
);
738 nsContentPermissionRequestProxy::GetHasValidTransientUserGestureActivation(
739 bool* aHasValidTransientUserGestureActivation
) {
740 NS_ENSURE_ARG_POINTER(aHasValidTransientUserGestureActivation
);
741 if (mParent
== nullptr) {
742 return NS_ERROR_FAILURE
;
744 *aHasValidTransientUserGestureActivation
=
745 mParent
->mHasValidTransientUserGestureActivation
;
750 nsContentPermissionRequestProxy::GetIsRequestDelegatedToUnsafeThirdParty(
751 bool* aIsRequestDelegatedToUnsafeThirdParty
) {
752 NS_ENSURE_ARG_POINTER(aIsRequestDelegatedToUnsafeThirdParty
);
753 if (mParent
== nullptr) {
754 return NS_ERROR_FAILURE
;
756 *aIsRequestDelegatedToUnsafeThirdParty
=
757 mParent
->mIsRequestDelegatedToUnsafeThirdParty
;
762 nsContentPermissionRequestProxy::Cancel() {
763 if (mParent
== nullptr) {
764 return NS_ERROR_FAILURE
;
767 // Don't send out the delete message when the managing protocol (PBrowser) is
768 // being destroyed and PContentPermissionRequest will soon be.
769 if (mParent
->IsBeingDestroyed()) {
770 return NS_ERROR_FAILURE
;
773 nsTArray
<PermissionChoice
> emptyChoices
;
775 Unused
<< mParent
->SendNotifyResult(false, emptyChoices
);
780 nsContentPermissionRequestProxy::Allow(JS::Handle
<JS::Value
> aChoices
) {
781 if (mParent
== nullptr) {
782 return NS_ERROR_FAILURE
;
785 // Don't send out the delete message when the managing protocol (PBrowser) is
786 // being destroyed and PContentPermissionRequest will soon be.
787 if (mParent
->IsBeingDestroyed()) {
788 return NS_ERROR_FAILURE
;
791 nsTArray
<PermissionChoice
> choices
;
792 nsresult rv
= TranslateChoices(aChoices
, mPermissionRequests
, choices
);
797 Unused
<< mParent
->SendNotifyResult(true, choices
);
801 // RemotePermissionRequest
803 RemotePermissionRequest::RemotePermissionRequest(
804 nsIContentPermissionRequest
* aRequest
, nsPIDOMWindowInner
* aWindow
)
805 : mRequest(aRequest
),
810 RemotePermissionRequest::~RemotePermissionRequest() {
813 "Protocol must not be open when RemotePermissionRequest is destroyed.");
816 void RemotePermissionRequest::DoCancel() {
817 NS_ASSERTION(mRequest
, "We need a request");
818 nsCOMPtr
<nsIContentPermissionRequest
> request(mRequest
);
822 void RemotePermissionRequest::DoAllow(JS::Handle
<JS::Value
> aChoices
) {
823 NS_ASSERTION(mRequest
, "We need a request");
824 nsCOMPtr
<nsIContentPermissionRequest
> request(mRequest
);
825 request
->Allow(aChoices
);
828 // PContentPermissionRequestChild
829 mozilla::ipc::IPCResult
RemotePermissionRequest::RecvNotifyResult(
830 const bool& aAllow
, nsTArray
<PermissionChoice
>&& aChoices
) {
833 if (aAllow
&& mWindow
->IsCurrentInnerWindow()) {
834 // Use 'undefined' if no choice is provided.
835 if (aChoices
.IsEmpty()) {
836 DoAllow(JS::UndefinedHandleValue
);
840 // Convert choices to a JS val if any.
841 // {"type1": "choice1", "type2": "choiceA"}
843 if (NS_WARN_IF(!jsapi
.Init(mWindow
))) {
844 return IPC_OK(); // This is not an IPC error.
847 JSContext
* cx
= jsapi
.cx();
848 JS::Rooted
<JSObject
*> obj(cx
);
849 obj
= JS_NewPlainObject(cx
);
850 for (uint32_t i
= 0; i
< aChoices
.Length(); ++i
) {
851 const nsString
& choice
= aChoices
[i
].choice();
852 const nsCString
& type
= aChoices
[i
].type();
853 JS::Rooted
<JSString
*> jChoice(
854 cx
, JS_NewUCStringCopyN(cx
, choice
.get(), choice
.Length()));
855 JS::Rooted
<JS::Value
> vChoice(cx
, StringValue(jChoice
));
856 if (!JS_SetProperty(cx
, obj
, type
.get(), vChoice
)) {
857 return IPC_FAIL_NO_REASON(this);
860 JS::Rooted
<JS::Value
> val(cx
, JS::ObjectValue(*obj
));
868 void RemotePermissionRequest::Destroy() {
872 Unused
<< this->SendDestroy();