Bug 1728955: part 3) Add logging to `nsBaseClipboard`. r=masayuki
[gecko.git] / dom / base / nsContentPermissionHelper.cpp
blobaaebc6f141dc9fce7ac132179fd92e2a7e756207
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/. */
7 #include <map>
8 #include "nsCOMPtr.h"
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 {
42 public:
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;
60 private:
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;
77 mElement = aElement;
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);
91 proxy->Cancel();
93 return IPC_OK();
96 mozilla::ipc::IPCResult ContentPermissionRequestParent::RecvDestroy() {
97 Unused << PContentPermissionRequestParent::Send__delete__(this);
98 return IPC_OK();
101 void ContentPermissionRequestParent::ActorDestroy(ActorDestroyReason why) {
102 if (mProxy) {
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) {
118 mType = aType;
119 mOptions = aOptions.Clone();
122 ContentPermissionType::~ContentPermissionType() = default;
124 NS_IMETHODIMP
125 ContentPermissionType::GetType(nsACString& aType) {
126 aType = mType;
127 return NS_OK;
130 NS_IMETHODIMP
131 ContentPermissionType::GetOptions(nsIArray** aOptions) {
132 NS_ENSURE_ARG_POINTER(aOptions);
134 *aOptions = nullptr;
136 nsresult rv;
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);
155 return NS_OK;
158 // nsContentPermissionUtils
160 /* static */
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);
169 return len;
172 /* static */
173 void nsContentPermissionUtils::ConvertArrayToPermissionRequest(
174 nsIArray* aSrcArray, nsTArray<PermissionRequest>& aDesArray) {
175 uint32_t len = 0;
176 aSrcArray->GetLength(&len);
177 for (uint32_t i = 0; i < len; i++) {
178 nsCOMPtr<nsIContentPermissionType> cpt = do_QueryElementAt(aSrcArray, i);
179 nsAutoCString type;
180 cpt->GetType(type);
182 nsCOMPtr<nsIArray> optionArray;
183 cpt->GetOptions(getter_AddRefs(optionArray));
184 uint32_t optionsLength = 0;
185 if (optionArray) {
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) {
193 nsString option;
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;
219 /* static */
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);
229 return NS_OK;
232 /* static */
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;
244 return parent;
247 /* static */
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));
289 req->IPDLAddRef();
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();
296 req->Sendprompt();
297 return NS_OK;
300 // for chrome process
301 nsCOMPtr<nsIContentPermissionPrompt> prompt =
302 do_GetService(NS_CONTENT_PERMISSION_PROMPT_CONTRACTID);
303 if (prompt) {
304 if (NS_FAILED(prompt->Prompt(aRequest))) {
305 return NS_ERROR_FAILURE;
308 return NS_OK;
311 /* static */
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);
322 return parentArray;
325 /* static */
326 void nsContentPermissionUtils::NotifyRemoveContentPermissionRequestParent(
327 PContentPermissionRequestParent* aParent) {
328 auto it = ContentPermissionRequestParentMap().find(aParent);
329 MOZ_ASSERT(it != ContentPermissionRequestParentMap().end());
331 ContentPermissionRequestParentMap().erase(it);
334 /* static */
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);
345 return childArray;
348 /* static */
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) {
358 MOZ_ASSERT(aWindow);
360 BrowsingContext* top = aWindow->GetBrowsingContext()->Top();
361 MOZ_ASSERT(top);
363 nsPIDOMWindowOuter* outer = top->GetDOMWindow();
364 if (!outer) {
365 return nullptr;
368 nsPIDOMWindowInner* inner = outer->GetCurrentInnerWindow();
369 if (!inner) {
370 return nullptr;
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)
382 NS_INTERFACE_MAP_END
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),
392 mWindow(aWindow),
393 mPrefName(aPrefName),
394 mType(aType),
395 mIsHandlingUserInput(false),
396 mMaybeUnsafePermissionDelegate(false) {
397 if (!aWindow) {
398 return;
401 Document* doc = aWindow->GetExtantDoc();
402 if (!doc) {
403 return;
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);
417 NS_IMETHODIMP
418 ContentPermissionRequestBase::GetPrincipal(
419 nsIPrincipal** aRequestingPrincipal) {
420 NS_IF_ADDREF(*aRequestingPrincipal = mPrincipal);
421 return NS_OK;
424 NS_IMETHODIMP
425 ContentPermissionRequestBase::GetDelegatePrincipal(
426 const nsACString& aType, nsIPrincipal** aRequestingPrincipal) {
427 return PermissionDelegateHandler::GetDelegatePrincipal(aType, this,
428 aRequestingPrincipal);
431 NS_IMETHODIMP
432 ContentPermissionRequestBase::GetMaybeUnsafePermissionDelegate(
433 bool* aMaybeUnsafePermissionDelegate) {
434 *aMaybeUnsafePermissionDelegate = mMaybeUnsafePermissionDelegate;
435 return NS_OK;
438 NS_IMETHODIMP
439 ContentPermissionRequestBase::GetTopLevelPrincipal(
440 nsIPrincipal** aRequestingPrincipal) {
441 if (!mTopLevelPrincipal) {
442 *aRequestingPrincipal = nullptr;
443 return NS_OK;
446 NS_IF_ADDREF(*aRequestingPrincipal = mTopLevelPrincipal);
447 return NS_OK;
450 NS_IMETHODIMP
451 ContentPermissionRequestBase::GetWindow(mozIDOMWindow** aRequestingWindow) {
452 NS_IF_ADDREF(*aRequestingWindow = mWindow);
453 return NS_OK;
456 NS_IMETHODIMP
457 ContentPermissionRequestBase::GetElement(Element** aElement) {
458 NS_ENSURE_ARG_POINTER(aElement);
459 *aElement = nullptr;
460 return NS_OK;
463 NS_IMETHODIMP
464 ContentPermissionRequestBase::GetIsHandlingUserInput(
465 bool* aIsHandlingUserInput) {
466 *aIsHandlingUserInput = mIsHandlingUserInput;
467 return NS_OK;
470 NS_IMETHODIMP
471 ContentPermissionRequestBase::GetTypes(nsIArray** aTypes) {
472 nsTArray<nsString> emptyOptions;
473 return nsContentPermissionUtils::CreatePermissionArray(mType, emptyOptions,
474 aTypes);
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)) {
501 return false;
504 return true;
507 nsresult ContentPermissionRequestBase::ShowPrompt(
508 ContentPermissionRequestBase::PromptResult& aResult) {
509 if (!CheckPermissionDelegate()) {
510 aResult = PromptResult::Denied;
511 return NS_OK;
514 aResult = CheckPromptPrefs();
516 if (aResult != PromptResult::Pending) {
517 return NS_OK;
520 return nsContentPermissionUtils::AskPermission(this, mWindow);
523 class RequestPromptEvent : public Runnable {
524 public:
525 RequestPromptEvent(ContentPermissionRequestBase* aRequest,
526 nsPIDOMWindowInner* aWindow)
527 : mozilla::Runnable("RequestPromptEvent"),
528 mRequest(aRequest),
529 mWindow(aWindow) {}
531 NS_IMETHOD Run() override {
532 nsContentPermissionUtils::AskPermission(mRequest, mWindow);
533 return NS_OK;
536 private:
537 RefPtr<ContentPermissionRequestBase> mRequest;
538 nsCOMPtr<nsPIDOMWindowInner> mWindow;
541 class RequestAllowEvent : public Runnable {
542 public:
543 RequestAllowEvent(bool allow, ContentPermissionRequestBase* request)
544 : mozilla::Runnable("RequestAllowEvent"),
545 mAllow(allow),
546 mRequest(request) {}
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.
552 if (mAllow) {
553 MOZ_KnownLive(mRequest)->Allow(JS::UndefinedHandleValue);
554 } else {
555 MOZ_KnownLive(mRequest)->Cancel();
557 return NS_OK;
560 private:
561 bool mAllow;
562 RefPtr<ContentPermissionRequestBase> mRequest;
565 void ContentPermissionRequestBase::RequestDelayedTask(
566 nsIEventTarget* aTarget,
567 ContentPermissionRequestBase::DelayedTaskType aType) {
568 nsCOMPtr<nsIRunnable> r;
569 switch (aType) {
570 case DelayedTaskType::Allow:
571 r = new RequestAllowEvent(true, this);
572 break;
573 case DelayedTaskType::Deny:
574 r = new RequestAllowEvent(false, this);
575 break;
576 default:
577 r = new RequestPromptEvent(this, mWindow);
578 break;
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);
599 if (!obj) {
600 return NS_ERROR_FAILURE;
603 AutoJSAPI jsapi;
604 jsapi.Init();
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) ||
612 !val.isString()) {
613 // no setting for the permission type, clear exception and skip it
614 jsapi.ClearException();
615 } else {
616 nsAutoJSString choice;
617 if (!choice.init(cx, val)) {
618 jsapi.ClearException();
619 return NS_ERROR_FAILURE;
621 aTranslatedChoices.AppendElement(PermissionChoice(type, choice));
624 } else {
625 MOZ_ASSERT(false, "SelectedChoices should be undefined or an JS object");
626 return NS_ERROR_FAILURE;
629 return NS_OK;
632 } // namespace mozilla::dom
634 nsContentPermissionRequestProxy::nsContentPermissionRequestProxy(
635 ContentPermissionRequestParent* parent)
636 : mParent(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);
648 if (!prompt) {
649 return NS_ERROR_FAILURE;
652 prompt->Prompt(this);
653 return NS_OK;
656 void nsContentPermissionRequestProxy::OnParentDestroyed() { mParent = nullptr; }
658 NS_IMPL_ISUPPORTS(nsContentPermissionRequestProxy, nsIContentPermissionRequest)
660 NS_IMETHODIMP
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);
666 return NS_OK;
668 return NS_ERROR_FAILURE;
671 NS_IMETHODIMP
672 nsContentPermissionRequestProxy::GetWindow(mozIDOMWindow** aRequestingWindow) {
673 NS_ENSURE_ARG_POINTER(aRequestingWindow);
674 *aRequestingWindow = nullptr; // ipc doesn't have a window
675 return NS_OK;
678 NS_IMETHODIMP
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);
687 return NS_OK;
690 NS_IMETHODIMP
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;
700 return NS_OK;
703 NS_ADDREF(*aRequestingPrincipal = mParent->mTopLevelPrincipal);
704 return NS_OK;
707 NS_IMETHODIMP
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);
719 NS_IMETHODIMP
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);
728 return NS_OK;
731 NS_IMETHODIMP
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;
739 return NS_OK;
742 NS_IMETHODIMP
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;
750 return NS_OK;
753 NS_IMETHODIMP
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);
768 return NS_OK;
771 NS_IMETHODIMP
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);
785 if (NS_FAILED(rv)) {
786 return rv;
789 Unused << mParent->SendNotifyResult(true, choices);
790 return NS_OK;
793 // RemotePermissionRequest
795 RemotePermissionRequest::RemotePermissionRequest(
796 nsIContentPermissionRequest* aRequest, nsPIDOMWindowInner* aWindow)
797 : mRequest(aRequest),
798 mWindow(aWindow),
799 mIPCOpen(false),
800 mDestroyed(false) {}
802 RemotePermissionRequest::~RemotePermissionRequest() {
803 MOZ_ASSERT(
804 !mIPCOpen,
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);
811 request->Cancel();
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) {
823 Destroy();
825 if (aAllow && mWindow->IsCurrentInnerWindow()) {
826 // Use 'undefined' if no choice is provided.
827 if (aChoices.IsEmpty()) {
828 DoAllow(JS::UndefinedHandleValue);
829 return IPC_OK();
832 // Convert choices to a JS val if any.
833 // {"type1": "choice1", "type2": "choiceA"}
834 AutoJSAPI jsapi;
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));
853 DoAllow(val);
854 } else {
855 DoCancel();
857 return IPC_OK();
860 void RemotePermissionRequest::Destroy() {
861 if (!IPCOpen()) {
862 return;
864 Unused << this->SendDestroy();
865 mDestroyed = true;