Coverage Report

Created: 2018-09-25 14:53

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