Line data Source code
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/. */
6 :
7 : #include <map>
8 : #ifdef MOZ_WIDGET_GONK
9 : #include "GonkPermission.h"
10 : #endif // MOZ_WIDGET_GONK
11 : #include "nsCOMPtr.h"
12 : #include "nsIDOMElement.h"
13 : #include "nsIPrincipal.h"
14 : #include "mozilla/dom/ContentChild.h"
15 : #include "mozilla/dom/ContentParent.h"
16 : #include "mozilla/dom/Element.h"
17 : #include "mozilla/dom/Event.h"
18 : #include "mozilla/dom/PContentPermission.h"
19 : #include "mozilla/dom/PermissionMessageUtils.h"
20 : #include "mozilla/dom/PContentPermissionRequestParent.h"
21 : #include "mozilla/dom/ScriptSettings.h"
22 : #include "mozilla/dom/TabChild.h"
23 : #include "mozilla/dom/TabParent.h"
24 : #include "mozilla/Unused.h"
25 : #include "nsComponentManagerUtils.h"
26 : #include "nsArrayUtils.h"
27 : #include "nsIMutableArray.h"
28 : #include "nsContentPermissionHelper.h"
29 : #include "nsJSUtils.h"
30 : #include "nsISupportsPrimitives.h"
31 : #include "nsServiceManagerUtils.h"
32 : #include "nsIDocument.h"
33 : #include "nsIDOMEvent.h"
34 : #include "nsWeakPtr.h"
35 :
36 : using mozilla::Unused; // <snicker>
37 : using namespace mozilla::dom;
38 : using namespace mozilla;
39 :
40 : #define kVisibilityChange "visibilitychange"
41 :
42 : class VisibilityChangeListener final : public nsIDOMEventListener
43 : {
44 : public:
45 : NS_DECL_ISUPPORTS
46 : NS_DECL_NSIDOMEVENTLISTENER
47 :
48 : explicit VisibilityChangeListener(nsPIDOMWindowInner* aWindow);
49 :
50 : void RemoveListener();
51 : void SetCallback(nsIContentPermissionRequestCallback* aCallback);
52 : already_AddRefed<nsIContentPermissionRequestCallback> GetCallback();
53 :
54 : private:
55 0 : virtual ~VisibilityChangeListener() {}
56 :
57 : nsWeakPtr mWindow;
58 : nsCOMPtr<nsIContentPermissionRequestCallback> mCallback;
59 : };
60 :
61 0 : NS_IMPL_ISUPPORTS(VisibilityChangeListener, nsIDOMEventListener)
62 :
63 0 : VisibilityChangeListener::VisibilityChangeListener(nsPIDOMWindowInner* aWindow)
64 : {
65 0 : MOZ_ASSERT(aWindow);
66 :
67 0 : mWindow = do_GetWeakReference(aWindow);
68 0 : nsCOMPtr<nsIDocument> doc = aWindow->GetExtantDoc();
69 0 : if (doc) {
70 0 : doc->AddSystemEventListener(NS_LITERAL_STRING(kVisibilityChange),
71 : /* listener */ this,
72 : /* use capture */ true,
73 0 : /* wants untrusted */ false);
74 : }
75 :
76 0 : }
77 :
78 : NS_IMETHODIMP
79 0 : VisibilityChangeListener::HandleEvent(nsIDOMEvent* aEvent)
80 : {
81 0 : nsAutoString type;
82 0 : aEvent->GetType(type);
83 0 : if (!type.EqualsLiteral(kVisibilityChange)) {
84 0 : return NS_ERROR_FAILURE;
85 : }
86 :
87 : nsCOMPtr<nsIDocument> doc =
88 0 : do_QueryInterface(aEvent->InternalDOMEvent()->GetTarget());
89 0 : MOZ_ASSERT(doc);
90 :
91 0 : if (mCallback) {
92 0 : mCallback->NotifyVisibility(!doc->Hidden());
93 : }
94 :
95 0 : return NS_OK;
96 : }
97 :
98 : void
99 0 : VisibilityChangeListener::RemoveListener()
100 : {
101 0 : nsCOMPtr<nsPIDOMWindowInner> window = do_QueryReferent(mWindow);
102 0 : if (!window) {
103 0 : return;
104 : }
105 :
106 0 : nsCOMPtr<EventTarget> target = do_QueryInterface(window->GetExtantDoc());
107 0 : if (target) {
108 0 : target->RemoveSystemEventListener(NS_LITERAL_STRING(kVisibilityChange),
109 : /* listener */ this,
110 0 : /* use capture */ true);
111 : }
112 : }
113 :
114 : void
115 0 : VisibilityChangeListener::SetCallback(nsIContentPermissionRequestCallback *aCallback)
116 : {
117 0 : mCallback = aCallback;
118 0 : }
119 :
120 : already_AddRefed<nsIContentPermissionRequestCallback>
121 0 : VisibilityChangeListener::GetCallback()
122 : {
123 0 : nsCOMPtr<nsIContentPermissionRequestCallback> callback = mCallback;
124 0 : return callback.forget();
125 : }
126 :
127 : namespace mozilla {
128 : namespace dom {
129 :
130 : class ContentPermissionRequestParent : public PContentPermissionRequestParent
131 : {
132 : public:
133 : ContentPermissionRequestParent(const nsTArray<PermissionRequest>& aRequests,
134 : Element* element,
135 : const IPC::Principal& principal);
136 : virtual ~ContentPermissionRequestParent();
137 :
138 : bool IsBeingDestroyed();
139 :
140 : nsCOMPtr<nsIPrincipal> mPrincipal;
141 : nsCOMPtr<Element> mElement;
142 : RefPtr<nsContentPermissionRequestProxy> mProxy;
143 : nsTArray<PermissionRequest> mRequests;
144 :
145 : private:
146 : virtual mozilla::ipc::IPCResult Recvprompt();
147 : virtual mozilla::ipc::IPCResult RecvNotifyVisibility(const bool& aIsVisible);
148 : virtual mozilla::ipc::IPCResult RecvDestroy();
149 : virtual void ActorDestroy(ActorDestroyReason why);
150 : };
151 :
152 0 : ContentPermissionRequestParent::ContentPermissionRequestParent(const nsTArray<PermissionRequest>& aRequests,
153 : Element* aElement,
154 0 : const IPC::Principal& aPrincipal)
155 : {
156 0 : MOZ_COUNT_CTOR(ContentPermissionRequestParent);
157 :
158 0 : mPrincipal = aPrincipal;
159 0 : mElement = aElement;
160 0 : mRequests = aRequests;
161 0 : }
162 :
163 0 : ContentPermissionRequestParent::~ContentPermissionRequestParent()
164 : {
165 0 : MOZ_COUNT_DTOR(ContentPermissionRequestParent);
166 0 : }
167 :
168 : mozilla::ipc::IPCResult
169 0 : ContentPermissionRequestParent::Recvprompt()
170 : {
171 0 : mProxy = new nsContentPermissionRequestProxy();
172 0 : if (NS_FAILED(mProxy->Init(mRequests, this))) {
173 0 : mProxy->Cancel();
174 : }
175 0 : return IPC_OK();
176 : }
177 :
178 : mozilla::ipc::IPCResult
179 0 : ContentPermissionRequestParent::RecvNotifyVisibility(const bool& aIsVisible)
180 : {
181 0 : if (!mProxy) {
182 0 : return IPC_FAIL_NO_REASON(this);
183 : }
184 0 : mProxy->NotifyVisibility(aIsVisible);
185 0 : return IPC_OK();
186 : }
187 :
188 : mozilla::ipc::IPCResult
189 0 : ContentPermissionRequestParent::RecvDestroy()
190 : {
191 0 : Unused << PContentPermissionRequestParent::Send__delete__(this);
192 0 : return IPC_OK();
193 : }
194 :
195 : void
196 0 : ContentPermissionRequestParent::ActorDestroy(ActorDestroyReason why)
197 : {
198 0 : if (mProxy) {
199 0 : mProxy->OnParentDestroyed();
200 : }
201 0 : }
202 :
203 : bool
204 0 : ContentPermissionRequestParent::IsBeingDestroyed()
205 : {
206 : // When ContentParent::MarkAsDead() is called, we are being destroyed.
207 : // It's unsafe to send out any message now.
208 0 : ContentParent* contentParent = static_cast<ContentParent*>(Manager());
209 0 : return !contentParent->IsAlive();
210 : }
211 :
212 0 : NS_IMPL_ISUPPORTS(ContentPermissionType, nsIContentPermissionType)
213 :
214 0 : ContentPermissionType::ContentPermissionType(const nsACString& aType,
215 : const nsACString& aAccess,
216 0 : const nsTArray<nsString>& aOptions)
217 : {
218 0 : mType = aType;
219 0 : mAccess = aAccess;
220 0 : mOptions = aOptions;
221 0 : }
222 :
223 0 : ContentPermissionType::~ContentPermissionType()
224 : {
225 0 : }
226 :
227 : NS_IMETHODIMP
228 0 : ContentPermissionType::GetType(nsACString& aType)
229 : {
230 0 : aType = mType;
231 0 : return NS_OK;
232 : }
233 :
234 : NS_IMETHODIMP
235 0 : ContentPermissionType::GetAccess(nsACString& aAccess)
236 : {
237 0 : aAccess = mAccess;
238 0 : return NS_OK;
239 : }
240 :
241 : NS_IMETHODIMP
242 0 : ContentPermissionType::GetOptions(nsIArray** aOptions)
243 : {
244 0 : NS_ENSURE_ARG_POINTER(aOptions);
245 :
246 0 : *aOptions = nullptr;
247 :
248 : nsresult rv;
249 : nsCOMPtr<nsIMutableArray> options =
250 0 : do_CreateInstance(NS_ARRAY_CONTRACTID, &rv);
251 0 : NS_ENSURE_SUCCESS(rv, rv);
252 :
253 : // copy options into JS array
254 0 : for (uint32_t i = 0; i < mOptions.Length(); ++i) {
255 : nsCOMPtr<nsISupportsString> isupportsString =
256 0 : do_CreateInstance(NS_SUPPORTS_STRING_CONTRACTID, &rv);
257 0 : NS_ENSURE_SUCCESS(rv, rv);
258 :
259 0 : rv = isupportsString->SetData(mOptions[i]);
260 0 : NS_ENSURE_SUCCESS(rv, rv);
261 :
262 0 : rv = options->AppendElement(isupportsString, false);
263 0 : NS_ENSURE_SUCCESS(rv, rv);
264 : }
265 :
266 0 : options.forget(aOptions);
267 0 : return NS_OK;
268 : }
269 :
270 : // nsContentPermissionUtils
271 :
272 : /* static */ uint32_t
273 0 : nsContentPermissionUtils::ConvertPermissionRequestToArray(nsTArray<PermissionRequest>& aSrcArray,
274 : nsIMutableArray* aDesArray)
275 : {
276 0 : uint32_t len = aSrcArray.Length();
277 0 : for (uint32_t i = 0; i < len; i++) {
278 : RefPtr<ContentPermissionType> cpt =
279 0 : new ContentPermissionType(aSrcArray[i].type(),
280 0 : aSrcArray[i].access(),
281 0 : aSrcArray[i].options());
282 0 : aDesArray->AppendElement(cpt, false);
283 : }
284 0 : return len;
285 : }
286 :
287 : /* static */ uint32_t
288 0 : nsContentPermissionUtils::ConvertArrayToPermissionRequest(nsIArray* aSrcArray,
289 : nsTArray<PermissionRequest>& aDesArray)
290 : {
291 0 : uint32_t len = 0;
292 0 : aSrcArray->GetLength(&len);
293 0 : for (uint32_t i = 0; i < len; i++) {
294 0 : nsCOMPtr<nsIContentPermissionType> cpt = do_QueryElementAt(aSrcArray, i);
295 0 : nsAutoCString type;
296 0 : nsAutoCString access;
297 0 : cpt->GetType(type);
298 0 : cpt->GetAccess(access);
299 :
300 0 : nsCOMPtr<nsIArray> optionArray;
301 0 : cpt->GetOptions(getter_AddRefs(optionArray));
302 0 : uint32_t optionsLength = 0;
303 0 : if (optionArray) {
304 0 : optionArray->GetLength(&optionsLength);
305 : }
306 0 : nsTArray<nsString> options;
307 0 : for (uint32_t j = 0; j < optionsLength; ++j) {
308 0 : nsCOMPtr<nsISupportsString> isupportsString = do_QueryElementAt(optionArray, j);
309 0 : if (isupportsString) {
310 0 : nsString option;
311 0 : isupportsString->GetData(option);
312 0 : options.AppendElement(option);
313 : }
314 : }
315 :
316 0 : aDesArray.AppendElement(PermissionRequest(type, access, options));
317 : }
318 0 : return len;
319 : }
320 :
321 : static std::map<PContentPermissionRequestParent*, TabId>&
322 0 : ContentPermissionRequestParentMap()
323 : {
324 0 : MOZ_ASSERT(NS_IsMainThread());
325 0 : static std::map<PContentPermissionRequestParent*, TabId> sPermissionRequestParentMap;
326 0 : return sPermissionRequestParentMap;
327 : }
328 :
329 : static std::map<PContentPermissionRequestChild*, TabId>&
330 0 : ContentPermissionRequestChildMap()
331 : {
332 0 : MOZ_ASSERT(NS_IsMainThread());
333 0 : static std::map<PContentPermissionRequestChild*, TabId> sPermissionRequestChildMap;
334 0 : return sPermissionRequestChildMap;
335 : }
336 :
337 : /* static */ nsresult
338 0 : nsContentPermissionUtils::CreatePermissionArray(const nsACString& aType,
339 : const nsACString& aAccess,
340 : const nsTArray<nsString>& aOptions,
341 : nsIArray** aTypesArray)
342 : {
343 0 : nsCOMPtr<nsIMutableArray> types = do_CreateInstance(NS_ARRAY_CONTRACTID);
344 : RefPtr<ContentPermissionType> permType = new ContentPermissionType(aType,
345 : aAccess,
346 0 : aOptions);
347 0 : types->AppendElement(permType, false);
348 0 : types.forget(aTypesArray);
349 :
350 0 : return NS_OK;
351 : }
352 :
353 : /* static */ PContentPermissionRequestParent*
354 0 : nsContentPermissionUtils::CreateContentPermissionRequestParent(const nsTArray<PermissionRequest>& aRequests,
355 : Element* element,
356 : const IPC::Principal& principal,
357 : const TabId& aTabId)
358 : {
359 : PContentPermissionRequestParent* parent =
360 0 : new ContentPermissionRequestParent(aRequests, element, principal);
361 0 : ContentPermissionRequestParentMap()[parent] = aTabId;
362 :
363 0 : return parent;
364 : }
365 :
366 : /* static */ nsresult
367 0 : nsContentPermissionUtils::AskPermission(nsIContentPermissionRequest* aRequest,
368 : nsPIDOMWindowInner* aWindow)
369 : {
370 0 : MOZ_ASSERT(!aWindow || aWindow->IsInnerWindow());
371 0 : NS_ENSURE_STATE(aWindow && aWindow->IsCurrentInnerWindow());
372 :
373 : // for content process
374 0 : if (XRE_IsContentProcess()) {
375 :
376 : RefPtr<RemotePermissionRequest> req =
377 0 : new RemotePermissionRequest(aRequest, aWindow);
378 :
379 0 : MOZ_ASSERT(NS_IsMainThread()); // IPC can only be execute on main thread.
380 :
381 0 : TabChild* child = TabChild::GetFrom(aWindow->GetDocShell());
382 0 : NS_ENSURE_TRUE(child, NS_ERROR_FAILURE);
383 :
384 0 : nsCOMPtr<nsIArray> typeArray;
385 0 : nsresult rv = aRequest->GetTypes(getter_AddRefs(typeArray));
386 0 : NS_ENSURE_SUCCESS(rv, rv);
387 :
388 0 : nsTArray<PermissionRequest> permArray;
389 0 : ConvertArrayToPermissionRequest(typeArray, permArray);
390 :
391 0 : nsCOMPtr<nsIPrincipal> principal;
392 0 : rv = aRequest->GetPrincipal(getter_AddRefs(principal));
393 0 : NS_ENSURE_SUCCESS(rv, rv);
394 :
395 0 : req->IPDLAddRef();
396 0 : ContentChild::GetSingleton()->SendPContentPermissionRequestConstructor(
397 : req,
398 : permArray,
399 0 : IPC::Principal(principal),
400 0 : child->GetTabId());
401 0 : ContentPermissionRequestChildMap()[req.get()] = child->GetTabId();
402 :
403 0 : req->Sendprompt();
404 0 : return NS_OK;
405 : }
406 :
407 : // for chrome process
408 : nsCOMPtr<nsIContentPermissionPrompt> prompt =
409 0 : do_GetService(NS_CONTENT_PERMISSION_PROMPT_CONTRACTID);
410 0 : if (prompt) {
411 0 : if (NS_FAILED(prompt->Prompt(aRequest))) {
412 0 : return NS_ERROR_FAILURE;
413 : }
414 : }
415 0 : return NS_OK;
416 : }
417 :
418 : /* static */ nsTArray<PContentPermissionRequestParent*>
419 0 : nsContentPermissionUtils::GetContentPermissionRequestParentById(const TabId& aTabId)
420 : {
421 0 : nsTArray<PContentPermissionRequestParent*> parentArray;
422 0 : for (auto& it : ContentPermissionRequestParentMap()) {
423 0 : if (it.second == aTabId) {
424 0 : parentArray.AppendElement(it.first);
425 : }
426 : }
427 :
428 0 : return Move(parentArray);
429 : }
430 :
431 : /* static */ void
432 0 : nsContentPermissionUtils::NotifyRemoveContentPermissionRequestParent(
433 : PContentPermissionRequestParent* aParent)
434 : {
435 0 : auto it = ContentPermissionRequestParentMap().find(aParent);
436 0 : MOZ_ASSERT(it != ContentPermissionRequestParentMap().end());
437 :
438 0 : ContentPermissionRequestParentMap().erase(it);
439 0 : }
440 :
441 : /* static */ nsTArray<PContentPermissionRequestChild*>
442 0 : nsContentPermissionUtils::GetContentPermissionRequestChildById(const TabId& aTabId)
443 : {
444 0 : nsTArray<PContentPermissionRequestChild*> childArray;
445 0 : for (auto& it : ContentPermissionRequestChildMap()) {
446 0 : if (it.second == aTabId) {
447 0 : childArray.AppendElement(it.first);
448 : }
449 : }
450 :
451 0 : return Move(childArray);
452 : }
453 :
454 : /* static */ void
455 0 : nsContentPermissionUtils::NotifyRemoveContentPermissionRequestChild(
456 : PContentPermissionRequestChild* aChild)
457 : {
458 0 : auto it = ContentPermissionRequestChildMap().find(aChild);
459 0 : MOZ_ASSERT(it != ContentPermissionRequestChildMap().end());
460 :
461 0 : ContentPermissionRequestChildMap().erase(it);
462 0 : }
463 :
464 0 : NS_IMPL_ISUPPORTS(nsContentPermissionRequester, nsIContentPermissionRequester)
465 :
466 0 : nsContentPermissionRequester::nsContentPermissionRequester(nsPIDOMWindowInner* aWindow)
467 0 : : mWindow(do_GetWeakReference(aWindow))
468 0 : , mListener(new VisibilityChangeListener(aWindow))
469 : {
470 0 : }
471 :
472 0 : nsContentPermissionRequester::~nsContentPermissionRequester()
473 : {
474 0 : mListener->RemoveListener();
475 0 : mListener = nullptr;
476 0 : }
477 :
478 : NS_IMETHODIMP
479 0 : nsContentPermissionRequester::GetVisibility(nsIContentPermissionRequestCallback* aCallback)
480 : {
481 0 : NS_ENSURE_ARG_POINTER(aCallback);
482 :
483 0 : nsCOMPtr<nsPIDOMWindowInner> window = do_QueryReferent(mWindow);
484 0 : if (!window) {
485 0 : return NS_ERROR_FAILURE;
486 : }
487 :
488 0 : nsCOMPtr<nsIDocShell> docshell = window->GetDocShell();
489 0 : if (!docshell) {
490 0 : return NS_ERROR_FAILURE;
491 : }
492 :
493 0 : bool isActive = false;
494 0 : docshell->GetIsActive(&isActive);
495 0 : aCallback->NotifyVisibility(isActive);
496 0 : return NS_OK;
497 : }
498 :
499 : NS_IMETHODIMP
500 0 : nsContentPermissionRequester::SetOnVisibilityChange(nsIContentPermissionRequestCallback* aCallback)
501 : {
502 0 : mListener->SetCallback(aCallback);
503 :
504 0 : if (!aCallback) {
505 0 : mListener->RemoveListener();
506 : }
507 :
508 0 : return NS_OK;
509 : }
510 :
511 : NS_IMETHODIMP
512 0 : nsContentPermissionRequester::GetOnVisibilityChange(nsIContentPermissionRequestCallback** aCallback)
513 : {
514 0 : NS_ENSURE_ARG_POINTER(aCallback);
515 :
516 0 : nsCOMPtr<nsIContentPermissionRequestCallback> callback = mListener->GetCallback();
517 0 : callback.forget(aCallback);
518 0 : return NS_OK;
519 : }
520 :
521 : } // namespace dom
522 : } // namespace mozilla
523 :
524 0 : NS_IMPL_ISUPPORTS(nsContentPermissionRequestProxy::nsContentPermissionRequesterProxy,
525 : nsIContentPermissionRequester)
526 :
527 : NS_IMETHODIMP
528 0 : nsContentPermissionRequestProxy::nsContentPermissionRequesterProxy
529 : ::GetVisibility(nsIContentPermissionRequestCallback* aCallback)
530 : {
531 0 : NS_ENSURE_ARG_POINTER(aCallback);
532 :
533 0 : mGetCallback = aCallback;
534 0 : mWaitGettingResult = true;
535 0 : Unused << mParent->SendGetVisibility();
536 0 : return NS_OK;
537 : }
538 :
539 : NS_IMETHODIMP
540 0 : nsContentPermissionRequestProxy::nsContentPermissionRequesterProxy
541 : ::SetOnVisibilityChange(nsIContentPermissionRequestCallback* aCallback)
542 : {
543 0 : mOnChangeCallback = aCallback;
544 0 : return NS_OK;
545 : }
546 :
547 : NS_IMETHODIMP
548 0 : nsContentPermissionRequestProxy::nsContentPermissionRequesterProxy
549 : ::GetOnVisibilityChange(nsIContentPermissionRequestCallback** aCallback)
550 : {
551 0 : NS_ENSURE_ARG_POINTER(aCallback);
552 :
553 0 : nsCOMPtr<nsIContentPermissionRequestCallback> callback = mOnChangeCallback;
554 0 : callback.forget(aCallback);
555 0 : return NS_OK;
556 : }
557 :
558 : void
559 0 : nsContentPermissionRequestProxy::nsContentPermissionRequesterProxy
560 : ::NotifyVisibilityResult(const bool& aIsVisible)
561 : {
562 0 : if (mWaitGettingResult) {
563 0 : MOZ_ASSERT(mGetCallback);
564 0 : mWaitGettingResult = false;
565 0 : mGetCallback->NotifyVisibility(aIsVisible);
566 0 : return;
567 : }
568 :
569 0 : if (mOnChangeCallback) {
570 0 : mOnChangeCallback->NotifyVisibility(aIsVisible);
571 : }
572 : }
573 :
574 0 : nsContentPermissionRequestProxy::nsContentPermissionRequestProxy()
575 : {
576 0 : }
577 :
578 0 : nsContentPermissionRequestProxy::~nsContentPermissionRequestProxy()
579 : {
580 0 : }
581 :
582 : nsresult
583 0 : nsContentPermissionRequestProxy::Init(const nsTArray<PermissionRequest>& requests,
584 : ContentPermissionRequestParent* parent)
585 : {
586 0 : NS_ASSERTION(parent, "null parent");
587 0 : mParent = parent;
588 0 : mPermissionRequests = requests;
589 0 : mRequester = new nsContentPermissionRequesterProxy(mParent);
590 :
591 0 : nsCOMPtr<nsIContentPermissionPrompt> prompt = do_GetService(NS_CONTENT_PERMISSION_PROMPT_CONTRACTID);
592 0 : if (!prompt) {
593 0 : return NS_ERROR_FAILURE;
594 : }
595 :
596 0 : prompt->Prompt(this);
597 0 : return NS_OK;
598 : }
599 :
600 : void
601 0 : nsContentPermissionRequestProxy::OnParentDestroyed()
602 : {
603 0 : mRequester = nullptr;
604 0 : mParent = nullptr;
605 0 : }
606 :
607 0 : NS_IMPL_ISUPPORTS(nsContentPermissionRequestProxy, nsIContentPermissionRequest)
608 :
609 : NS_IMETHODIMP
610 0 : nsContentPermissionRequestProxy::GetTypes(nsIArray** aTypes)
611 : {
612 0 : nsCOMPtr<nsIMutableArray> types = do_CreateInstance(NS_ARRAY_CONTRACTID);
613 0 : if (mozilla::dom::nsContentPermissionUtils::ConvertPermissionRequestToArray(mPermissionRequests, types)) {
614 0 : types.forget(aTypes);
615 0 : return NS_OK;
616 : }
617 0 : return NS_ERROR_FAILURE;
618 : }
619 :
620 : NS_IMETHODIMP
621 0 : nsContentPermissionRequestProxy::GetWindow(mozIDOMWindow * *aRequestingWindow)
622 : {
623 0 : NS_ENSURE_ARG_POINTER(aRequestingWindow);
624 0 : *aRequestingWindow = nullptr; // ipc doesn't have a window
625 0 : return NS_OK;
626 : }
627 :
628 : NS_IMETHODIMP
629 0 : nsContentPermissionRequestProxy::GetPrincipal(nsIPrincipal * *aRequestingPrincipal)
630 : {
631 0 : NS_ENSURE_ARG_POINTER(aRequestingPrincipal);
632 0 : if (mParent == nullptr) {
633 0 : return NS_ERROR_FAILURE;
634 : }
635 :
636 0 : NS_ADDREF(*aRequestingPrincipal = mParent->mPrincipal);
637 0 : return NS_OK;
638 : }
639 :
640 : NS_IMETHODIMP
641 0 : nsContentPermissionRequestProxy::GetElement(nsIDOMElement * *aRequestingElement)
642 : {
643 0 : NS_ENSURE_ARG_POINTER(aRequestingElement);
644 0 : if (mParent == nullptr) {
645 0 : return NS_ERROR_FAILURE;
646 : }
647 :
648 0 : nsCOMPtr<nsIDOMElement> elem = do_QueryInterface(mParent->mElement);
649 0 : elem.forget(aRequestingElement);
650 0 : return NS_OK;
651 : }
652 :
653 : NS_IMETHODIMP
654 0 : nsContentPermissionRequestProxy::Cancel()
655 : {
656 0 : if (mParent == nullptr) {
657 0 : return NS_ERROR_FAILURE;
658 : }
659 :
660 : // Don't send out the delete message when the managing protocol (PBrowser) is
661 : // being destroyed and PContentPermissionRequest will soon be.
662 0 : if (mParent->IsBeingDestroyed()) {
663 0 : return NS_ERROR_FAILURE;
664 : }
665 :
666 0 : nsTArray<PermissionChoice> emptyChoices;
667 :
668 0 : Unused << mParent->SendNotifyResult(false, emptyChoices);
669 0 : mParent = nullptr;
670 0 : return NS_OK;
671 : }
672 :
673 : NS_IMETHODIMP
674 0 : nsContentPermissionRequestProxy::Allow(JS::HandleValue aChoices)
675 : {
676 0 : if (mParent == nullptr) {
677 0 : return NS_ERROR_FAILURE;
678 : }
679 :
680 : // Don't send out the delete message when the managing protocol (PBrowser) is
681 : // being destroyed and PContentPermissionRequest will soon be.
682 0 : if (mParent->IsBeingDestroyed()) {
683 0 : return NS_ERROR_FAILURE;
684 : }
685 :
686 0 : nsTArray<PermissionChoice> choices;
687 0 : if (aChoices.isNullOrUndefined()) {
688 : // No choice is specified.
689 0 : } else if (aChoices.isObject()) {
690 : // Iterate through all permission types.
691 0 : for (uint32_t i = 0; i < mPermissionRequests.Length(); ++i) {
692 0 : nsCString type = mPermissionRequests[i].type();
693 :
694 0 : AutoJSAPI jsapi;
695 0 : jsapi.Init();
696 :
697 0 : JSContext* cx = jsapi.cx();
698 0 : JS::Rooted<JSObject*> obj(cx, &aChoices.toObject());
699 0 : JSAutoCompartment ac(cx, obj);
700 :
701 0 : JS::Rooted<JS::Value> val(cx);
702 :
703 0 : if (!JS_GetProperty(cx, obj, type.BeginReading(), &val) ||
704 0 : !val.isString()) {
705 : // no setting for the permission type, clear exception and skip it
706 0 : jsapi.ClearException();
707 : } else {
708 0 : nsAutoJSString choice;
709 0 : if (!choice.init(cx, val)) {
710 0 : jsapi.ClearException();
711 0 : return NS_ERROR_FAILURE;
712 : }
713 0 : choices.AppendElement(PermissionChoice(type, choice));
714 : }
715 : }
716 : } else {
717 0 : MOZ_ASSERT(false, "SelectedChoices should be undefined or an JS object");
718 : return NS_ERROR_FAILURE;
719 : }
720 :
721 0 : Unused << mParent->SendNotifyResult(true, choices);
722 0 : mParent = nullptr;
723 0 : return NS_OK;
724 : }
725 :
726 : void
727 0 : nsContentPermissionRequestProxy::NotifyVisibility(const bool& aIsVisible)
728 : {
729 0 : MOZ_ASSERT(mRequester);
730 :
731 0 : mRequester->NotifyVisibilityResult(aIsVisible);
732 0 : }
733 :
734 : NS_IMETHODIMP
735 0 : nsContentPermissionRequestProxy::GetRequester(nsIContentPermissionRequester** aRequester)
736 : {
737 0 : NS_ENSURE_ARG_POINTER(aRequester);
738 :
739 0 : RefPtr<nsContentPermissionRequesterProxy> requester = mRequester;
740 0 : requester.forget(aRequester);
741 0 : return NS_OK;
742 : }
743 :
744 : // RemotePermissionRequest
745 :
746 0 : NS_IMPL_ISUPPORTS(RemotePermissionRequest, nsIContentPermissionRequestCallback);
747 :
748 0 : RemotePermissionRequest::RemotePermissionRequest(
749 : nsIContentPermissionRequest* aRequest,
750 0 : nsPIDOMWindowInner* aWindow)
751 : : mRequest(aRequest)
752 : , mWindow(aWindow)
753 : , mIPCOpen(false)
754 0 : , mDestroyed(false)
755 : {
756 0 : mListener = new VisibilityChangeListener(mWindow);
757 0 : mListener->SetCallback(this);
758 0 : }
759 :
760 0 : RemotePermissionRequest::~RemotePermissionRequest()
761 : {
762 0 : MOZ_ASSERT(!mIPCOpen, "Protocol must not be open when RemotePermissionRequest is destroyed.");
763 0 : }
764 :
765 : void
766 0 : RemotePermissionRequest::DoCancel()
767 : {
768 0 : NS_ASSERTION(mRequest, "We need a request");
769 0 : mRequest->Cancel();
770 0 : }
771 :
772 : void
773 0 : RemotePermissionRequest::DoAllow(JS::HandleValue aChoices)
774 : {
775 0 : NS_ASSERTION(mRequest, "We need a request");
776 0 : mRequest->Allow(aChoices);
777 0 : }
778 :
779 : // PContentPermissionRequestChild
780 : mozilla::ipc::IPCResult
781 0 : RemotePermissionRequest::RecvNotifyResult(const bool& aAllow,
782 : InfallibleTArray<PermissionChoice>&& aChoices)
783 : {
784 0 : Destroy();
785 :
786 0 : if (aAllow && mWindow->IsCurrentInnerWindow()) {
787 : // Use 'undefined' if no choice is provided.
788 0 : if (aChoices.IsEmpty()) {
789 0 : DoAllow(JS::UndefinedHandleValue);
790 0 : return IPC_OK();
791 : }
792 :
793 : // Convert choices to a JS val if any.
794 : // {"type1": "choice1", "type2": "choiceA"}
795 0 : AutoJSAPI jsapi;
796 0 : if (NS_WARN_IF(!jsapi.Init(mWindow))) {
797 0 : return IPC_OK(); // This is not an IPC error.
798 : }
799 :
800 0 : JSContext* cx = jsapi.cx();
801 0 : JS::Rooted<JSObject*> obj(cx);
802 0 : obj = JS_NewPlainObject(cx);
803 0 : for (uint32_t i = 0; i < aChoices.Length(); ++i) {
804 0 : const nsString& choice = aChoices[i].choice();
805 0 : const nsCString& type = aChoices[i].type();
806 0 : JS::Rooted<JSString*> jChoice(cx, JS_NewUCStringCopyN(cx, choice.get(), choice.Length()));
807 0 : JS::Rooted<JS::Value> vChoice(cx, StringValue(jChoice));
808 0 : if (!JS_SetProperty(cx, obj, type.get(), vChoice)) {
809 0 : return IPC_FAIL_NO_REASON(this);
810 : }
811 : }
812 0 : JS::RootedValue val(cx, JS::ObjectValue(*obj));
813 0 : DoAllow(val);
814 : } else {
815 0 : DoCancel();
816 : }
817 0 : return IPC_OK();
818 : }
819 :
820 : mozilla::ipc::IPCResult
821 0 : RemotePermissionRequest::RecvGetVisibility()
822 : {
823 0 : nsCOMPtr<nsIDocShell> docshell = mWindow->GetDocShell();
824 0 : if (!docshell) {
825 0 : return IPC_FAIL_NO_REASON(this);
826 : }
827 :
828 0 : bool isActive = false;
829 0 : docshell->GetIsActive(&isActive);
830 0 : Unused << SendNotifyVisibility(isActive);
831 0 : return IPC_OK();
832 : }
833 :
834 : void
835 0 : RemotePermissionRequest::Destroy()
836 : {
837 0 : if (!IPCOpen()) {
838 0 : return;
839 : }
840 0 : Unused << this->SendDestroy();
841 0 : mListener->RemoveListener();
842 0 : mListener = nullptr;
843 0 : mDestroyed = true;
844 : }
845 :
846 : NS_IMETHODIMP
847 0 : RemotePermissionRequest::NotifyVisibility(bool isVisible)
848 : {
849 0 : if (!IPCOpen()) {
850 0 : return NS_OK;
851 : }
852 :
853 0 : Unused << SendNotifyVisibility(isVisible);
854 0 : return NS_OK;
855 : }
|