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 "nsJSUtils.h"
28 #include "nsISupportsPrimitives.h"
29 #include "nsServiceManagerUtils.h"
30 #include "mozilla/dom/Document.h"
31 #include "nsIWeakReferenceUtils.h"
32 #include "js/PropertyAndElement.h" // JS_GetProperty, JS_SetProperty
34 using mozilla::Unused
; // <snicker>
35 using namespace mozilla::dom
;
36 using namespace mozilla
;
37 using DelegateInfo
= PermissionDelegateHandler::PermissionDelegateInfo
;
39 namespace mozilla::dom
{
41 class ContentPermissionRequestParent
: public PContentPermissionRequestParent
{
43 ContentPermissionRequestParent(const nsTArray
<PermissionRequest
>& aRequests
,
44 Element
* aElement
, nsIPrincipal
* aPrincipal
,
45 nsIPrincipal
* aTopLevelPrincipal
,
46 const bool aIsHandlingUserInput
,
47 const bool aMaybeUnsafePermissionDelegate
);
48 virtual ~ContentPermissionRequestParent();
50 bool IsBeingDestroyed();
52 nsCOMPtr
<nsIPrincipal
> mPrincipal
;
53 nsCOMPtr
<nsIPrincipal
> mTopLevelPrincipal
;
54 nsCOMPtr
<Element
> mElement
;
55 bool mIsHandlingUserInput
;
56 bool mMaybeUnsafePermissionDelegate
;
57 RefPtr
<nsContentPermissionRequestProxy
> mProxy
;
58 nsTArray
<PermissionRequest
> mRequests
;
61 // Not MOZ_CAN_RUN_SCRIPT because we can't annotate the thing we override yet.
62 MOZ_CAN_RUN_SCRIPT_BOUNDARY
63 virtual mozilla::ipc::IPCResult
Recvprompt() override
;
64 virtual mozilla::ipc::IPCResult
RecvDestroy() override
;
65 virtual void ActorDestroy(ActorDestroyReason why
) override
;
68 ContentPermissionRequestParent::ContentPermissionRequestParent(
69 const nsTArray
<PermissionRequest
>& aRequests
, Element
* aElement
,
70 nsIPrincipal
* aPrincipal
, nsIPrincipal
* aTopLevelPrincipal
,
71 const bool aIsHandlingUserInput
,
72 const bool aMaybeUnsafePermissionDelegate
) {
73 MOZ_COUNT_CTOR(ContentPermissionRequestParent
);
75 mPrincipal
= aPrincipal
;
76 mTopLevelPrincipal
= aTopLevelPrincipal
;
78 mRequests
= aRequests
.Clone();
79 mIsHandlingUserInput
= aIsHandlingUserInput
;
80 mMaybeUnsafePermissionDelegate
= aMaybeUnsafePermissionDelegate
;
83 ContentPermissionRequestParent::~ContentPermissionRequestParent() {
84 MOZ_COUNT_DTOR(ContentPermissionRequestParent
);
87 mozilla::ipc::IPCResult
ContentPermissionRequestParent::Recvprompt() {
88 mProxy
= new nsContentPermissionRequestProxy(this);
89 if (NS_FAILED(mProxy
->Init(mRequests
))) {
90 RefPtr
<nsContentPermissionRequestProxy
> proxy(mProxy
);
96 mozilla::ipc::IPCResult
ContentPermissionRequestParent::RecvDestroy() {
97 Unused
<< PContentPermissionRequestParent::Send__delete__(this);
101 void ContentPermissionRequestParent::ActorDestroy(ActorDestroyReason why
) {
103 mProxy
->OnParentDestroyed();
107 bool ContentPermissionRequestParent::IsBeingDestroyed() {
108 // When ContentParent::MarkAsDead() is called, we are being destroyed.
109 // It's unsafe to send out any message now.
110 ContentParent
* contentParent
= static_cast<ContentParent
*>(Manager());
111 return !contentParent
->IsAlive();
114 NS_IMPL_ISUPPORTS(ContentPermissionType
, nsIContentPermissionType
)
116 ContentPermissionType::ContentPermissionType(
117 const nsACString
& aType
, const nsTArray
<nsString
>& aOptions
) {
119 mOptions
= aOptions
.Clone();
122 ContentPermissionType::~ContentPermissionType() = default;
125 ContentPermissionType::GetType(nsACString
& aType
) {
131 ContentPermissionType::GetOptions(nsIArray
** aOptions
) {
132 NS_ENSURE_ARG_POINTER(aOptions
);
137 nsCOMPtr
<nsIMutableArray
> options
=
138 do_CreateInstance(NS_ARRAY_CONTRACTID
, &rv
);
139 NS_ENSURE_SUCCESS(rv
, rv
);
141 // copy options into JS array
142 for (uint32_t i
= 0; i
< mOptions
.Length(); ++i
) {
143 nsCOMPtr
<nsISupportsString
> isupportsString
=
144 do_CreateInstance(NS_SUPPORTS_STRING_CONTRACTID
, &rv
);
145 NS_ENSURE_SUCCESS(rv
, rv
);
147 rv
= isupportsString
->SetData(mOptions
[i
]);
148 NS_ENSURE_SUCCESS(rv
, rv
);
150 rv
= options
->AppendElement(isupportsString
);
151 NS_ENSURE_SUCCESS(rv
, rv
);
154 options
.forget(aOptions
);
158 // nsContentPermissionUtils
161 uint32_t nsContentPermissionUtils::ConvertPermissionRequestToArray(
162 nsTArray
<PermissionRequest
>& aSrcArray
, nsIMutableArray
* aDesArray
) {
163 uint32_t len
= aSrcArray
.Length();
164 for (uint32_t i
= 0; i
< len
; i
++) {
165 RefPtr
<ContentPermissionType
> cpt
=
166 new ContentPermissionType(aSrcArray
[i
].type(), aSrcArray
[i
].options());
167 aDesArray
->AppendElement(cpt
);
173 void nsContentPermissionUtils::ConvertArrayToPermissionRequest(
174 nsIArray
* aSrcArray
, nsTArray
<PermissionRequest
>& aDesArray
) {
176 aSrcArray
->GetLength(&len
);
177 for (uint32_t i
= 0; i
< len
; i
++) {
178 nsCOMPtr
<nsIContentPermissionType
> cpt
= do_QueryElementAt(aSrcArray
, i
);
182 nsCOMPtr
<nsIArray
> optionArray
;
183 cpt
->GetOptions(getter_AddRefs(optionArray
));
184 uint32_t optionsLength
= 0;
186 optionArray
->GetLength(&optionsLength
);
188 nsTArray
<nsString
> options
;
189 for (uint32_t j
= 0; j
< optionsLength
; ++j
) {
190 nsCOMPtr
<nsISupportsString
> isupportsString
=
191 do_QueryElementAt(optionArray
, j
);
192 if (isupportsString
) {
194 isupportsString
->GetData(option
);
195 options
.AppendElement(option
);
199 aDesArray
.AppendElement(PermissionRequest(type
, options
));
203 static std::map
<PContentPermissionRequestParent
*, TabId
>&
204 ContentPermissionRequestParentMap() {
205 MOZ_ASSERT(NS_IsMainThread());
206 static std::map
<PContentPermissionRequestParent
*, TabId
>
207 sPermissionRequestParentMap
;
208 return sPermissionRequestParentMap
;
211 static std::map
<PContentPermissionRequestChild
*, TabId
>&
212 ContentPermissionRequestChildMap() {
213 MOZ_ASSERT(NS_IsMainThread());
214 static std::map
<PContentPermissionRequestChild
*, TabId
>
215 sPermissionRequestChildMap
;
216 return sPermissionRequestChildMap
;
220 nsresult
nsContentPermissionUtils::CreatePermissionArray(
221 const nsACString
& aType
, const nsTArray
<nsString
>& aOptions
,
222 nsIArray
** aTypesArray
) {
223 nsCOMPtr
<nsIMutableArray
> types
= do_CreateInstance(NS_ARRAY_CONTRACTID
);
224 RefPtr
<ContentPermissionType
> permType
=
225 new ContentPermissionType(aType
, aOptions
);
226 types
->AppendElement(permType
);
227 types
.forget(aTypesArray
);
233 PContentPermissionRequestParent
*
234 nsContentPermissionUtils::CreateContentPermissionRequestParent(
235 const nsTArray
<PermissionRequest
>& aRequests
, Element
* aElement
,
236 nsIPrincipal
* aPrincipal
, nsIPrincipal
* aTopLevelPrincipal
,
237 const bool aIsHandlingUserInput
, const bool aMaybeUnsafePermissionDelegate
,
238 const TabId
& aTabId
) {
239 PContentPermissionRequestParent
* parent
= new ContentPermissionRequestParent(
240 aRequests
, aElement
, aPrincipal
, aTopLevelPrincipal
, aIsHandlingUserInput
,
241 aMaybeUnsafePermissionDelegate
);
242 ContentPermissionRequestParentMap()[parent
] = aTabId
;
248 nsresult
nsContentPermissionUtils::AskPermission(
249 nsIContentPermissionRequest
* aRequest
, nsPIDOMWindowInner
* aWindow
) {
250 NS_ENSURE_STATE(aWindow
&& aWindow
->IsCurrentInnerWindow());
252 // for content process
253 if (XRE_IsContentProcess()) {
254 RefPtr
<RemotePermissionRequest
> req
=
255 new RemotePermissionRequest(aRequest
, aWindow
);
257 MOZ_ASSERT(NS_IsMainThread()); // IPC can only be execute on main thread.
259 BrowserChild
* child
= BrowserChild::GetFrom(aWindow
->GetDocShell());
260 NS_ENSURE_TRUE(child
, NS_ERROR_FAILURE
);
262 nsCOMPtr
<nsIArray
> typeArray
;
263 nsresult rv
= aRequest
->GetTypes(getter_AddRefs(typeArray
));
264 NS_ENSURE_SUCCESS(rv
, rv
);
266 nsTArray
<PermissionRequest
> permArray
;
267 ConvertArrayToPermissionRequest(typeArray
, permArray
);
269 nsCOMPtr
<nsIPrincipal
> principal
;
270 rv
= aRequest
->GetPrincipal(getter_AddRefs(principal
));
271 NS_ENSURE_SUCCESS(rv
, rv
);
273 nsCOMPtr
<nsIPrincipal
> topLevelPrincipal
;
274 rv
= aRequest
->GetTopLevelPrincipal(getter_AddRefs(topLevelPrincipal
));
275 NS_ENSURE_SUCCESS(rv
, rv
);
277 bool isHandlingUserInput
;
278 rv
= aRequest
->GetIsHandlingUserInput(&isHandlingUserInput
);
279 NS_ENSURE_SUCCESS(rv
, rv
);
281 bool maybeUnsafePermissionDelegate
;
282 rv
= aRequest
->GetMaybeUnsafePermissionDelegate(
283 &maybeUnsafePermissionDelegate
);
284 NS_ENSURE_SUCCESS(rv
, rv
);
286 ContentChild::GetSingleton()->SetEventTargetForActor(
287 req
, aWindow
->EventTargetFor(TaskCategory::Other
));
290 ContentChild::GetSingleton()->SendPContentPermissionRequestConstructor(
291 req
, permArray
, IPC::Principal(principal
),
292 IPC::Principal(topLevelPrincipal
), isHandlingUserInput
,
293 maybeUnsafePermissionDelegate
, child
->GetTabId());
294 ContentPermissionRequestChildMap()[req
.get()] = child
->GetTabId();
300 // for chrome process
301 nsCOMPtr
<nsIContentPermissionPrompt
> prompt
=
302 do_GetService(NS_CONTENT_PERMISSION_PROMPT_CONTRACTID
);
304 if (NS_FAILED(prompt
->Prompt(aRequest
))) {
305 return NS_ERROR_FAILURE
;
312 nsTArray
<PContentPermissionRequestParent
*>
313 nsContentPermissionUtils::GetContentPermissionRequestParentById(
314 const TabId
& aTabId
) {
315 nsTArray
<PContentPermissionRequestParent
*> parentArray
;
316 for (auto& it
: ContentPermissionRequestParentMap()) {
317 if (it
.second
== aTabId
) {
318 parentArray
.AppendElement(it
.first
);
326 void nsContentPermissionUtils::NotifyRemoveContentPermissionRequestParent(
327 PContentPermissionRequestParent
* aParent
) {
328 auto it
= ContentPermissionRequestParentMap().find(aParent
);
329 MOZ_ASSERT(it
!= ContentPermissionRequestParentMap().end());
331 ContentPermissionRequestParentMap().erase(it
);
335 nsTArray
<PContentPermissionRequestChild
*>
336 nsContentPermissionUtils::GetContentPermissionRequestChildById(
337 const TabId
& aTabId
) {
338 nsTArray
<PContentPermissionRequestChild
*> childArray
;
339 for (auto& it
: ContentPermissionRequestChildMap()) {
340 if (it
.second
== aTabId
) {
341 childArray
.AppendElement(it
.first
);
349 void nsContentPermissionUtils::NotifyRemoveContentPermissionRequestChild(
350 PContentPermissionRequestChild
* aChild
) {
351 auto it
= ContentPermissionRequestChildMap().find(aChild
);
352 MOZ_ASSERT(it
!= ContentPermissionRequestChildMap().end());
354 ContentPermissionRequestChildMap().erase(it
);
357 static nsIPrincipal
* GetTopLevelPrincipal(nsPIDOMWindowInner
* aWindow
) {
360 BrowsingContext
* top
= aWindow
->GetBrowsingContext()->Top();
363 nsPIDOMWindowOuter
* outer
= top
->GetDOMWindow();
368 nsPIDOMWindowInner
* inner
= outer
->GetCurrentInnerWindow();
373 return nsGlobalWindowInner::Cast(inner
)->GetPrincipal();
376 NS_IMPL_CYCLE_COLLECTION(ContentPermissionRequestBase
, mPrincipal
,
377 mTopLevelPrincipal
, mWindow
)
379 NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(ContentPermissionRequestBase
)
380 NS_INTERFACE_MAP_ENTRY_CONCRETE(nsISupports
)
381 NS_INTERFACE_MAP_ENTRY_CONCRETE(nsIContentPermissionRequest
)
384 NS_IMPL_CYCLE_COLLECTING_ADDREF(ContentPermissionRequestBase
)
385 NS_IMPL_CYCLE_COLLECTING_RELEASE(ContentPermissionRequestBase
)
387 ContentPermissionRequestBase::ContentPermissionRequestBase(
388 nsIPrincipal
* aPrincipal
, nsPIDOMWindowInner
* aWindow
,
389 const nsACString
& aPrefName
, const nsACString
& aType
)
390 : mPrincipal(aPrincipal
),
391 mTopLevelPrincipal(aWindow
? ::GetTopLevelPrincipal(aWindow
) : nullptr),
393 mPrefName(aPrefName
),
395 mIsHandlingUserInput(false),
396 mMaybeUnsafePermissionDelegate(false) {
401 Document
* doc
= aWindow
->GetExtantDoc();
406 mIsHandlingUserInput
= doc
->HasValidTransientUserGestureActivation();
408 mPermissionHandler
= doc
->GetPermissionDelegateHandler();
409 if (mPermissionHandler
) {
410 nsTArray
<nsCString
> types
;
411 types
.AppendElement(mType
);
412 mPermissionHandler
->MaybeUnsafePermissionDelegate(
413 types
, &mMaybeUnsafePermissionDelegate
);
418 ContentPermissionRequestBase::GetPrincipal(
419 nsIPrincipal
** aRequestingPrincipal
) {
420 NS_IF_ADDREF(*aRequestingPrincipal
= mPrincipal
);
425 ContentPermissionRequestBase::GetDelegatePrincipal(
426 const nsACString
& aType
, nsIPrincipal
** aRequestingPrincipal
) {
427 return PermissionDelegateHandler::GetDelegatePrincipal(aType
, this,
428 aRequestingPrincipal
);
432 ContentPermissionRequestBase::GetMaybeUnsafePermissionDelegate(
433 bool* aMaybeUnsafePermissionDelegate
) {
434 *aMaybeUnsafePermissionDelegate
= mMaybeUnsafePermissionDelegate
;
439 ContentPermissionRequestBase::GetTopLevelPrincipal(
440 nsIPrincipal
** aRequestingPrincipal
) {
441 if (!mTopLevelPrincipal
) {
442 *aRequestingPrincipal
= nullptr;
446 NS_IF_ADDREF(*aRequestingPrincipal
= mTopLevelPrincipal
);
451 ContentPermissionRequestBase::GetWindow(mozIDOMWindow
** aRequestingWindow
) {
452 NS_IF_ADDREF(*aRequestingWindow
= mWindow
);
457 ContentPermissionRequestBase::GetElement(Element
** aElement
) {
458 NS_ENSURE_ARG_POINTER(aElement
);
464 ContentPermissionRequestBase::GetIsHandlingUserInput(
465 bool* aIsHandlingUserInput
) {
466 *aIsHandlingUserInput
= mIsHandlingUserInput
;
471 ContentPermissionRequestBase::GetTypes(nsIArray
** aTypes
) {
472 nsTArray
<nsString
> emptyOptions
;
473 return nsContentPermissionUtils::CreatePermissionArray(mType
, emptyOptions
,
477 ContentPermissionRequestBase::PromptResult
478 ContentPermissionRequestBase::CheckPromptPrefs() {
479 MOZ_ASSERT(!mPrefName
.IsEmpty(),
480 "This derived class must support checking pref types");
482 nsAutoCString
prefName(mPrefName
);
483 prefName
.AppendLiteral(".prompt.testing");
484 if (Preferences::GetBool(PromiseFlatCString(prefName
).get(), false)) {
485 prefName
.AppendLiteral(".allow");
486 if (Preferences::GetBool(PromiseFlatCString(prefName
).get(), true)) {
487 return PromptResult::Granted
;
489 return PromptResult::Denied
;
492 return PromptResult::Pending
;
495 bool ContentPermissionRequestBase::CheckPermissionDelegate() {
496 // There is case that ContentPermissionRequestBase is constructed without
497 // window, then mPermissionHandler will be null. So we only check permission
498 // delegate if we have non-null mPermissionHandler
499 if (mPermissionHandler
&&
500 !mPermissionHandler
->HasPermissionDelegated(mType
)) {
507 nsresult
ContentPermissionRequestBase::ShowPrompt(
508 ContentPermissionRequestBase::PromptResult
& aResult
) {
509 if (!CheckPermissionDelegate()) {
510 aResult
= PromptResult::Denied
;
514 aResult
= CheckPromptPrefs();
516 if (aResult
!= PromptResult::Pending
) {
520 return nsContentPermissionUtils::AskPermission(this, mWindow
);
523 class RequestPromptEvent
: public Runnable
{
525 RequestPromptEvent(ContentPermissionRequestBase
* aRequest
,
526 nsPIDOMWindowInner
* aWindow
)
527 : mozilla::Runnable("RequestPromptEvent"),
531 NS_IMETHOD
Run() override
{
532 nsContentPermissionUtils::AskPermission(mRequest
, mWindow
);
537 RefPtr
<ContentPermissionRequestBase
> mRequest
;
538 nsCOMPtr
<nsPIDOMWindowInner
> mWindow
;
541 class RequestAllowEvent
: public Runnable
{
543 RequestAllowEvent(bool allow
, ContentPermissionRequestBase
* request
)
544 : mozilla::Runnable("RequestAllowEvent"),
548 // Not MOZ_CAN_RUN_SCRIPT because we can't annotate the thing we override yet.
549 MOZ_CAN_RUN_SCRIPT_BOUNDARY
550 NS_IMETHOD
Run() override
{
551 // MOZ_KnownLive is OK, because we never drop the ref to mRequest.
553 MOZ_KnownLive(mRequest
)->Allow(JS::UndefinedHandleValue
);
555 MOZ_KnownLive(mRequest
)->Cancel();
562 RefPtr
<ContentPermissionRequestBase
> mRequest
;
565 void ContentPermissionRequestBase::RequestDelayedTask(
566 nsIEventTarget
* aTarget
,
567 ContentPermissionRequestBase::DelayedTaskType aType
) {
568 nsCOMPtr
<nsIRunnable
> r
;
570 case DelayedTaskType::Allow
:
571 r
= new RequestAllowEvent(true, this);
573 case DelayedTaskType::Deny
:
574 r
= new RequestAllowEvent(false, this);
577 r
= new RequestPromptEvent(this, mWindow
);
581 aTarget
->Dispatch(r
.forget());
584 nsresult
TranslateChoices(
585 JS::HandleValue aChoices
,
586 const nsTArray
<PermissionRequest
>& aPermissionRequests
,
587 nsTArray
<PermissionChoice
>& aTranslatedChoices
) {
588 if (aChoices
.isNullOrUndefined()) {
589 // No choice is specified.
590 } else if (aChoices
.isObject()) {
591 // Iterate through all permission types.
592 for (uint32_t i
= 0; i
< aPermissionRequests
.Length(); ++i
) {
593 nsCString type
= aPermissionRequests
[i
].type();
595 JS::Rooted
<JSObject
*> obj(RootingCx(), &aChoices
.toObject());
596 // People really shouldn't be passing WindowProxy or Location
597 // objects for the choices here.
598 obj
= js::CheckedUnwrapStatic(obj
);
600 return NS_ERROR_FAILURE
;
606 JSContext
* cx
= jsapi
.cx();
607 JSAutoRealm
ar(cx
, obj
);
609 JS::Rooted
<JS::Value
> val(cx
);
611 if (!JS_GetProperty(cx
, obj
, type
.BeginReading(), &val
) ||
613 // no setting for the permission type, clear exception and skip it
614 jsapi
.ClearException();
616 nsAutoJSString choice
;
617 if (!choice
.init(cx
, val
)) {
618 jsapi
.ClearException();
619 return NS_ERROR_FAILURE
;
621 aTranslatedChoices
.AppendElement(PermissionChoice(type
, choice
));
625 MOZ_ASSERT(false, "SelectedChoices should be undefined or an JS object");
626 return NS_ERROR_FAILURE
;
632 } // namespace mozilla::dom
634 nsContentPermissionRequestProxy::nsContentPermissionRequestProxy(
635 ContentPermissionRequestParent
* parent
)
637 NS_ASSERTION(mParent
, "null parent");
640 nsContentPermissionRequestProxy::~nsContentPermissionRequestProxy() = default;
642 nsresult
nsContentPermissionRequestProxy::Init(
643 const nsTArray
<PermissionRequest
>& requests
) {
644 mPermissionRequests
= requests
.Clone();
646 nsCOMPtr
<nsIContentPermissionPrompt
> prompt
=
647 do_GetService(NS_CONTENT_PERMISSION_PROMPT_CONTRACTID
);
649 return NS_ERROR_FAILURE
;
652 prompt
->Prompt(this);
656 void nsContentPermissionRequestProxy::OnParentDestroyed() { mParent
= nullptr; }
658 NS_IMPL_ISUPPORTS(nsContentPermissionRequestProxy
, nsIContentPermissionRequest
)
661 nsContentPermissionRequestProxy::GetTypes(nsIArray
** aTypes
) {
662 nsCOMPtr
<nsIMutableArray
> types
= do_CreateInstance(NS_ARRAY_CONTRACTID
);
663 if (mozilla::dom::nsContentPermissionUtils::ConvertPermissionRequestToArray(
664 mPermissionRequests
, types
)) {
665 types
.forget(aTypes
);
668 return NS_ERROR_FAILURE
;
672 nsContentPermissionRequestProxy::GetWindow(mozIDOMWindow
** aRequestingWindow
) {
673 NS_ENSURE_ARG_POINTER(aRequestingWindow
);
674 *aRequestingWindow
= nullptr; // ipc doesn't have a window
679 nsContentPermissionRequestProxy::GetPrincipal(
680 nsIPrincipal
** aRequestingPrincipal
) {
681 NS_ENSURE_ARG_POINTER(aRequestingPrincipal
);
682 if (mParent
== nullptr) {
683 return NS_ERROR_FAILURE
;
686 NS_ADDREF(*aRequestingPrincipal
= mParent
->mPrincipal
);
691 nsContentPermissionRequestProxy::GetTopLevelPrincipal(
692 nsIPrincipal
** aRequestingPrincipal
) {
693 NS_ENSURE_ARG_POINTER(aRequestingPrincipal
);
694 if (mParent
== nullptr) {
695 return NS_ERROR_FAILURE
;
698 if (!mParent
->mTopLevelPrincipal
) {
699 *aRequestingPrincipal
= nullptr;
703 NS_ADDREF(*aRequestingPrincipal
= mParent
->mTopLevelPrincipal
);
708 nsContentPermissionRequestProxy::GetDelegatePrincipal(
709 const nsACString
& aType
, nsIPrincipal
** aRequestingPrincipal
) {
710 NS_ENSURE_ARG_POINTER(aRequestingPrincipal
);
711 if (mParent
== nullptr) {
712 return NS_ERROR_FAILURE
;
715 return PermissionDelegateHandler::GetDelegatePrincipal(aType
, this,
716 aRequestingPrincipal
);
720 nsContentPermissionRequestProxy::GetElement(Element
** aRequestingElement
) {
721 NS_ENSURE_ARG_POINTER(aRequestingElement
);
722 if (mParent
== nullptr) {
723 return NS_ERROR_FAILURE
;
726 nsCOMPtr
<Element
> elem
= mParent
->mElement
;
727 elem
.forget(aRequestingElement
);
732 nsContentPermissionRequestProxy::GetIsHandlingUserInput(
733 bool* aIsHandlingUserInput
) {
734 NS_ENSURE_ARG_POINTER(aIsHandlingUserInput
);
735 if (mParent
== nullptr) {
736 return NS_ERROR_FAILURE
;
738 *aIsHandlingUserInput
= mParent
->mIsHandlingUserInput
;
743 nsContentPermissionRequestProxy::GetMaybeUnsafePermissionDelegate(
744 bool* aMaybeUnsafePermissionDelegate
) {
745 NS_ENSURE_ARG_POINTER(aMaybeUnsafePermissionDelegate
);
746 if (mParent
== nullptr) {
747 return NS_ERROR_FAILURE
;
749 *aMaybeUnsafePermissionDelegate
= mParent
->mMaybeUnsafePermissionDelegate
;
754 nsContentPermissionRequestProxy::Cancel() {
755 if (mParent
== nullptr) {
756 return NS_ERROR_FAILURE
;
759 // Don't send out the delete message when the managing protocol (PBrowser) is
760 // being destroyed and PContentPermissionRequest will soon be.
761 if (mParent
->IsBeingDestroyed()) {
762 return NS_ERROR_FAILURE
;
765 nsTArray
<PermissionChoice
> emptyChoices
;
767 Unused
<< mParent
->SendNotifyResult(false, emptyChoices
);
772 nsContentPermissionRequestProxy::Allow(JS::HandleValue aChoices
) {
773 if (mParent
== nullptr) {
774 return NS_ERROR_FAILURE
;
777 // Don't send out the delete message when the managing protocol (PBrowser) is
778 // being destroyed and PContentPermissionRequest will soon be.
779 if (mParent
->IsBeingDestroyed()) {
780 return NS_ERROR_FAILURE
;
783 nsTArray
<PermissionChoice
> choices
;
784 nsresult rv
= TranslateChoices(aChoices
, mPermissionRequests
, choices
);
789 Unused
<< mParent
->SendNotifyResult(true, choices
);
793 // RemotePermissionRequest
795 RemotePermissionRequest::RemotePermissionRequest(
796 nsIContentPermissionRequest
* aRequest
, nsPIDOMWindowInner
* aWindow
)
797 : mRequest(aRequest
),
802 RemotePermissionRequest::~RemotePermissionRequest() {
805 "Protocol must not be open when RemotePermissionRequest is destroyed.");
808 void RemotePermissionRequest::DoCancel() {
809 NS_ASSERTION(mRequest
, "We need a request");
810 nsCOMPtr
<nsIContentPermissionRequest
> request(mRequest
);
814 void RemotePermissionRequest::DoAllow(JS::HandleValue aChoices
) {
815 NS_ASSERTION(mRequest
, "We need a request");
816 nsCOMPtr
<nsIContentPermissionRequest
> request(mRequest
);
817 request
->Allow(aChoices
);
820 // PContentPermissionRequestChild
821 mozilla::ipc::IPCResult
RemotePermissionRequest::RecvNotifyResult(
822 const bool& aAllow
, nsTArray
<PermissionChoice
>&& aChoices
) {
825 if (aAllow
&& mWindow
->IsCurrentInnerWindow()) {
826 // Use 'undefined' if no choice is provided.
827 if (aChoices
.IsEmpty()) {
828 DoAllow(JS::UndefinedHandleValue
);
832 // Convert choices to a JS val if any.
833 // {"type1": "choice1", "type2": "choiceA"}
835 if (NS_WARN_IF(!jsapi
.Init(mWindow
))) {
836 return IPC_OK(); // This is not an IPC error.
839 JSContext
* cx
= jsapi
.cx();
840 JS::Rooted
<JSObject
*> obj(cx
);
841 obj
= JS_NewPlainObject(cx
);
842 for (uint32_t i
= 0; i
< aChoices
.Length(); ++i
) {
843 const nsString
& choice
= aChoices
[i
].choice();
844 const nsCString
& type
= aChoices
[i
].type();
845 JS::Rooted
<JSString
*> jChoice(
846 cx
, JS_NewUCStringCopyN(cx
, choice
.get(), choice
.Length()));
847 JS::Rooted
<JS::Value
> vChoice(cx
, StringValue(jChoice
));
848 if (!JS_SetProperty(cx
, obj
, type
.get(), vChoice
)) {
849 return IPC_FAIL_NO_REASON(this);
852 JS::RootedValue
val(cx
, JS::ObjectValue(*obj
));
860 void RemotePermissionRequest::Destroy() {
864 Unused
<< this->SendDestroy();