Coverage Report

Created: 2018-09-25 14:53

/src/mozilla-central/dom/quota/StorageManager.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 file,
5
 * You can obtain one at http://mozilla.org/MPL/2.0/. */
6
7
#include "StorageManager.h"
8
9
#include "mozilla/dom/DOMPrefs.h"
10
#include "mozilla/dom/PromiseWorkerProxy.h"
11
#include "mozilla/dom/quota/QuotaManagerService.h"
12
#include "mozilla/dom/StorageManagerBinding.h"
13
#include "mozilla/dom/WorkerPrivate.h"
14
#include "mozilla/ErrorResult.h"
15
#include "mozilla/EventStateManager.h"
16
#include "mozilla/Telemetry.h"
17
#include "nsContentPermissionHelper.h"
18
#include "nsIQuotaCallbacks.h"
19
#include "nsIQuotaRequests.h"
20
#include "nsPIDOMWindow.h"
21
22
using namespace mozilla::dom::quota;
23
24
namespace mozilla {
25
namespace dom {
26
27
namespace {
28
29
// This class is used to get quota usage, request persist and check persisted
30
// status callbacks.
31
class RequestResolver final
32
  : public nsIQuotaCallback
33
  , public nsIQuotaUsageCallback
34
{
35
public:
36
  enum Type
37
  {
38
    Estimate,
39
    Persist,
40
    Persisted
41
  };
42
43
private:
44
  class FinishWorkerRunnable;
45
46
  // If this resolver was created for a window then mPromise must be non-null.
47
  // Otherwise mProxy must be non-null.
48
  RefPtr<Promise> mPromise;
49
  RefPtr<PromiseWorkerProxy> mProxy;
50
51
  nsresult mResultCode;
52
  StorageEstimate mStorageEstimate;
53
  const Type mType;
54
  bool mPersisted;
55
56
public:
57
  RequestResolver(Type aType, Promise* aPromise)
58
    : mPromise(aPromise)
59
    , mResultCode(NS_OK)
60
    , mType(aType)
61
    , mPersisted(false)
62
0
  {
63
0
    MOZ_ASSERT(NS_IsMainThread());
64
0
    MOZ_ASSERT(aPromise);
65
0
  }
66
67
  RequestResolver(Type aType, PromiseWorkerProxy* aProxy)
68
    : mProxy(aProxy)
69
    , mResultCode(NS_OK)
70
    , mType(aType)
71
    , mPersisted(false)
72
0
  {
73
0
    MOZ_ASSERT(NS_IsMainThread());
74
0
    MOZ_ASSERT(aProxy);
75
0
  }
76
77
  void
78
  ResolveOrReject();
79
80
  NS_DECL_THREADSAFE_ISUPPORTS
81
  NS_DECL_NSIQUOTACALLBACK
82
  NS_DECL_NSIQUOTAUSAGECALLBACK
83
84
private:
85
  ~RequestResolver()
86
0
  { }
87
88
  nsresult
89
  GetStorageEstimate(nsIVariant* aResult);
90
91
  nsresult
92
  GetPersisted(nsIVariant* aResult);
93
94
  template <typename T>
95
  nsresult
96
  OnCompleteOrUsageResult(T* aRequest);
97
98
  nsresult
99
  Finish();
100
};
101
102
// This class is used to return promise on worker thread.
103
class RequestResolver::FinishWorkerRunnable final
104
  : public WorkerRunnable
105
{
106
  RefPtr<RequestResolver> mResolver;
107
108
public:
109
  explicit FinishWorkerRunnable(RequestResolver* aResolver)
110
    : WorkerRunnable(aResolver->mProxy->GetWorkerPrivate())
111
    , mResolver(aResolver)
112
0
  {
113
0
    MOZ_ASSERT(NS_IsMainThread());
114
0
    MOZ_ASSERT(aResolver);
115
0
  }
116
117
  bool
118
  WorkerRun(JSContext* aCx, WorkerPrivate* aWorkerPrivate) override;
119
};
120
121
class EstimateWorkerMainThreadRunnable final
122
  : public WorkerMainThreadRunnable
123
{
124
  RefPtr<PromiseWorkerProxy> mProxy;
125
126
public:
127
  EstimateWorkerMainThreadRunnable(WorkerPrivate* aWorkerPrivate,
128
                                   PromiseWorkerProxy* aProxy)
129
    : WorkerMainThreadRunnable(aWorkerPrivate,
130
                               NS_LITERAL_CSTRING("StorageManager :: Estimate"))
131
    , mProxy(aProxy)
132
0
  {
133
0
    MOZ_ASSERT(aWorkerPrivate);
134
0
    aWorkerPrivate->AssertIsOnWorkerThread();
135
0
    MOZ_ASSERT(aProxy);
136
0
  }
137
138
  bool
139
  MainThreadRun() override;
140
};
141
142
class PersistedWorkerMainThreadRunnable final
143
  : public WorkerMainThreadRunnable
144
{
145
  RefPtr<PromiseWorkerProxy> mProxy;
146
147
public:
148
  PersistedWorkerMainThreadRunnable(WorkerPrivate* aWorkerPrivate,
149
                                    PromiseWorkerProxy* aProxy)
150
    : WorkerMainThreadRunnable(aWorkerPrivate,
151
                               NS_LITERAL_CSTRING("StorageManager :: Persisted"))
152
    , mProxy(aProxy)
153
0
  {
154
0
    MOZ_ASSERT(aWorkerPrivate);
155
0
    aWorkerPrivate->AssertIsOnWorkerThread();
156
0
    MOZ_ASSERT(aProxy);
157
0
  }
158
159
  bool
160
  MainThreadRun() override;
161
};
162
163
/*******************************************************************************
164
 * PersistentStoragePermissionRequest
165
 ******************************************************************************/
166
167
class PersistentStoragePermissionRequest final
168
  : public nsIContentPermissionRequest
169
{
170
  nsCOMPtr<nsIPrincipal> mPrincipal;
171
  nsCOMPtr<nsPIDOMWindowInner> mWindow;
172
  bool mIsHandlingUserInput;
173
  RefPtr<Promise> mPromise;
174
  nsCOMPtr<nsIContentPermissionRequester> mRequester;
175
176
public:
177
  PersistentStoragePermissionRequest(nsIPrincipal* aPrincipal,
178
                                     nsPIDOMWindowInner* aWindow,
179
                                     bool aIsHandlingUserInput,
180
                                     Promise* aPromise)
181
    : mPrincipal(aPrincipal)
182
    , mWindow(aWindow)
183
    , mIsHandlingUserInput(aIsHandlingUserInput)
184
    , mPromise(aPromise)
185
0
  {
186
0
    MOZ_ASSERT(aPrincipal);
187
0
    MOZ_ASSERT(aWindow);
188
0
    MOZ_ASSERT(aPromise);
189
0
190
0
    mRequester = new nsContentPermissionRequester(mWindow);
191
0
  }
192
193
  nsresult
194
  Start();
195
196
  NS_DECL_CYCLE_COLLECTING_ISUPPORTS
197
  NS_DECL_NSICONTENTPERMISSIONREQUEST
198
  NS_DECL_CYCLE_COLLECTION_CLASS(PersistentStoragePermissionRequest)
199
200
private:
201
  ~PersistentStoragePermissionRequest()
202
0
  { }
203
};
204
205
nsresult
206
GetUsageForPrincipal(nsIPrincipal* aPrincipal,
207
                     nsIQuotaUsageCallback* aCallback,
208
                     nsIQuotaUsageRequest** aRequest)
209
0
{
210
0
  MOZ_ASSERT(aPrincipal);
211
0
  MOZ_ASSERT(aCallback);
212
0
  MOZ_ASSERT(aRequest);
213
0
214
0
  nsCOMPtr<nsIQuotaManagerService> qms = QuotaManagerService::GetOrCreate();
215
0
  if (NS_WARN_IF(!qms)) {
216
0
    return NS_ERROR_FAILURE;
217
0
  }
218
0
219
0
  nsresult rv = qms->GetUsageForPrincipal(aPrincipal,
220
0
                                          aCallback,
221
0
                                          true,
222
0
                                          aRequest);
223
0
  if (NS_WARN_IF(NS_FAILED(rv))) {
224
0
    return rv;
225
0
  }
226
0
227
0
  return NS_OK;
228
0
};
229
230
nsresult
231
Persisted(nsIPrincipal* aPrincipal,
232
          nsIQuotaCallback* aCallback,
233
          nsIQuotaRequest** aRequest)
234
0
{
235
0
  MOZ_ASSERT(aPrincipal);
236
0
  MOZ_ASSERT(aCallback);
237
0
  MOZ_ASSERT(aRequest);
238
0
239
0
  nsCOMPtr<nsIQuotaManagerService> qms = QuotaManagerService::GetOrCreate();
240
0
  if (NS_WARN_IF(!qms)) {
241
0
    return NS_ERROR_FAILURE;
242
0
  }
243
0
244
0
  nsCOMPtr<nsIQuotaRequest> request;
245
0
  nsresult rv = qms->Persisted(aPrincipal, getter_AddRefs(request));
246
0
  if (NS_WARN_IF(NS_FAILED(rv))) {
247
0
    return rv;
248
0
  }
249
0
250
0
  // All the methods in nsIQuotaManagerService shouldn't synchronously fire
251
0
  // any callbacks when they are being executed. Even when a result is ready,
252
0
  // a new runnable should be dispatched to current thread to fire the callback
253
0
  // asynchronously. It's safe to set the callback after we call Persisted().
254
0
  MOZ_ALWAYS_SUCCEEDS(request->SetCallback(aCallback));
255
0
256
0
  request.forget(aRequest);
257
0
258
0
  return NS_OK;
259
0
};
260
261
already_AddRefed<Promise>
262
ExecuteOpOnMainOrWorkerThread(nsIGlobalObject* aGlobal,
263
                              RequestResolver::Type aType,
264
                              ErrorResult& aRv)
265
0
{
266
0
  MOZ_ASSERT(aGlobal);
267
0
  MOZ_ASSERT_IF(aType == RequestResolver::Type::Persist,
268
0
                NS_IsMainThread());
269
0
270
0
  RefPtr<Promise> promise = Promise::Create(aGlobal, aRv);
271
0
  if (NS_WARN_IF(!promise)) {
272
0
    return nullptr;
273
0
  }
274
0
275
0
  if (NS_IsMainThread()) {
276
0
    nsCOMPtr<nsPIDOMWindowInner> window = do_QueryInterface(aGlobal);
277
0
    if (NS_WARN_IF(!window)) {
278
0
      aRv.Throw(NS_ERROR_FAILURE);
279
0
      return nullptr;
280
0
    }
281
0
282
0
    nsCOMPtr<nsIDocument> doc = window->GetExtantDoc();
283
0
    if (NS_WARN_IF(!doc)) {
284
0
      aRv.Throw(NS_ERROR_FAILURE);
285
0
      return nullptr;
286
0
    }
287
0
288
0
    nsCOMPtr<nsIPrincipal> principal = doc->NodePrincipal();
289
0
    MOZ_ASSERT(principal);
290
0
291
0
    // Storage Standard 7. API
292
0
    // If origin is an opaque origin, then reject promise with a TypeError.
293
0
    if (principal->GetIsNullPrincipal()) {
294
0
      promise->MaybeReject(NS_ERROR_DOM_TYPE_ERR);
295
0
      return promise.forget();
296
0
    }
297
0
298
0
    switch (aType) {
299
0
      case RequestResolver::Type::Persisted: {
300
0
        RefPtr<RequestResolver> resolver =
301
0
          new RequestResolver(RequestResolver::Type::Persisted, promise);
302
0
303
0
        RefPtr<nsIQuotaRequest> request;
304
0
        aRv = Persisted(principal, resolver, getter_AddRefs(request));
305
0
306
0
        break;
307
0
      }
308
0
309
0
      case RequestResolver::Type::Persist: {
310
0
        RefPtr<PersistentStoragePermissionRequest> request =
311
0
          new PersistentStoragePermissionRequest(principal,
312
0
                                                 window,
313
0
                                                 EventStateManager::IsHandlingUserInput(),
314
0
                                                 promise);
315
0
316
0
        // In private browsing mode, no permission prompt.
317
0
        if (nsContentUtils::IsInPrivateBrowsing(doc)) {
318
0
          aRv = request->Cancel();
319
0
        } else {
320
0
          aRv = request->Start();
321
0
        }
322
0
323
0
        break;
324
0
      }
325
0
326
0
      case RequestResolver::Type::Estimate: {
327
0
        RefPtr<RequestResolver> resolver =
328
0
          new RequestResolver(RequestResolver::Type::Estimate, promise);
329
0
330
0
        RefPtr<nsIQuotaUsageRequest> request;
331
0
        aRv = GetUsageForPrincipal(principal,
332
0
                                   resolver,
333
0
                                   getter_AddRefs(request));
334
0
335
0
        break;
336
0
      }
337
0
338
0
      default:
339
0
        MOZ_CRASH("Invalid aRequest type!");
340
0
    }
341
0
342
0
    if (NS_WARN_IF(aRv.Failed())) {
343
0
      return nullptr;
344
0
    }
345
0
346
0
    return promise.forget();
347
0
  }
348
0
349
0
  WorkerPrivate* workerPrivate = GetCurrentThreadWorkerPrivate();
350
0
  MOZ_ASSERT(workerPrivate);
351
0
352
0
  RefPtr<PromiseWorkerProxy> promiseProxy =
353
0
    PromiseWorkerProxy::Create(workerPrivate, promise);
354
0
  if (NS_WARN_IF(!promiseProxy)) {
355
0
    return nullptr;
356
0
  }
357
0
358
0
  switch (aType) {
359
0
    case RequestResolver::Type::Estimate: {
360
0
      RefPtr<EstimateWorkerMainThreadRunnable> runnnable =
361
0
        new EstimateWorkerMainThreadRunnable(promiseProxy->GetWorkerPrivate(),
362
0
                                             promiseProxy);
363
0
      runnnable->Dispatch(Canceling, aRv);
364
0
365
0
      break;
366
0
    }
367
0
368
0
    case RequestResolver::Type::Persisted: {
369
0
      RefPtr<PersistedWorkerMainThreadRunnable> runnnable =
370
0
        new PersistedWorkerMainThreadRunnable(promiseProxy->GetWorkerPrivate(),
371
0
                                              promiseProxy);
372
0
      runnnable->Dispatch(Canceling, aRv);
373
0
374
0
      break;
375
0
    }
376
0
377
0
    default:
378
0
      MOZ_CRASH("Invalid aRequest type");
379
0
  }
380
0
381
0
  if (NS_WARN_IF(aRv.Failed())) {
382
0
    return nullptr;
383
0
  }
384
0
385
0
  return promise.forget();
386
0
};
387
388
} // namespace
389
390
/*******************************************************************************
391
 * Local class implementations
392
 ******************************************************************************/
393
394
void
395
RequestResolver::ResolveOrReject()
396
0
{
397
0
  class MOZ_STACK_CLASS AutoCleanup final
398
0
  {
399
0
    RefPtr<PromiseWorkerProxy> mProxy;
400
0
401
0
  public:
402
0
    explicit AutoCleanup(PromiseWorkerProxy* aProxy)
403
0
      : mProxy(aProxy)
404
0
    {
405
0
      MOZ_ASSERT(aProxy);
406
0
    }
407
0
408
0
    ~AutoCleanup()
409
0
    {
410
0
      MOZ_ASSERT(mProxy);
411
0
412
0
      mProxy->CleanUp();
413
0
    }
414
0
  };
415
0
416
0
  RefPtr<Promise> promise;
417
0
  Maybe<AutoCleanup> autoCleanup;
418
0
419
0
  if (mPromise) {
420
0
    promise = mPromise;
421
0
  } else {
422
0
    MOZ_ASSERT(mProxy);
423
0
424
0
    promise = mProxy->WorkerPromise();
425
0
426
0
    // Only clean up for worker case.
427
0
    autoCleanup.emplace(mProxy);
428
0
  }
429
0
430
0
  MOZ_ASSERT(promise);
431
0
432
0
  if (mType == Type::Estimate) {
433
0
    if (NS_SUCCEEDED(mResultCode)) {
434
0
      promise->MaybeResolve(mStorageEstimate);
435
0
    } else {
436
0
      promise->MaybeReject(NS_ERROR_DOM_TYPE_ERR);
437
0
    }
438
0
439
0
    return;
440
0
  }
441
0
442
0
  MOZ_ASSERT(mType == Type::Persist || mType == Type::Persisted);
443
0
444
0
  if (NS_SUCCEEDED(mResultCode)) {
445
0
    promise->MaybeResolve(mPersisted);
446
0
  } else {
447
0
    promise->MaybeResolve(false);
448
0
  }
449
0
}
450
451
NS_IMPL_ISUPPORTS(RequestResolver, nsIQuotaUsageCallback, nsIQuotaCallback)
452
453
nsresult
454
RequestResolver::GetStorageEstimate(nsIVariant* aResult)
455
0
{
456
0
  MOZ_ASSERT(aResult);
457
0
  MOZ_ASSERT(mType == Type::Estimate);
458
0
459
#ifdef DEBUG
460
  uint16_t dataType;
461
  MOZ_ALWAYS_SUCCEEDS(aResult->GetDataType(&dataType));
462
  MOZ_ASSERT(dataType == nsIDataType::VTYPE_INTERFACE_IS);
463
#endif
464
465
0
  nsID* iid;
466
0
  nsCOMPtr<nsISupports> supports;
467
0
  nsresult rv = aResult->GetAsInterface(&iid, getter_AddRefs(supports));
468
0
  if (NS_WARN_IF(NS_FAILED(rv))) {
469
0
    return rv;
470
0
  }
471
0
472
0
  free(iid);
473
0
474
0
  nsCOMPtr<nsIQuotaOriginUsageResult> originUsageResult =
475
0
    do_QueryInterface(supports);
476
0
  MOZ_ASSERT(originUsageResult);
477
0
478
0
  MOZ_ALWAYS_SUCCEEDS(
479
0
    originUsageResult->GetUsage(&mStorageEstimate.mUsage.Construct()));
480
0
481
0
  MOZ_ALWAYS_SUCCEEDS(
482
0
    originUsageResult->GetLimit(&mStorageEstimate.mQuota.Construct()));
483
0
484
0
  return NS_OK;
485
0
}
486
487
nsresult
488
RequestResolver::GetPersisted(nsIVariant* aResult)
489
0
{
490
0
  MOZ_ASSERT(aResult);
491
0
  MOZ_ASSERT(mType == Type::Persist || mType == Type::Persisted);
492
0
493
#ifdef DEBUG
494
  uint16_t dataType;
495
  MOZ_ALWAYS_SUCCEEDS(aResult->GetDataType(&dataType));
496
#endif
497
498
0
  if (mType == Type::Persist) {
499
0
    MOZ_ASSERT(dataType == nsIDataType::VTYPE_VOID);
500
0
501
0
    mPersisted = true;
502
0
    return NS_OK;
503
0
  }
504
0
505
0
  MOZ_ASSERT(dataType == nsIDataType::VTYPE_BOOL);
506
0
507
0
  bool persisted;
508
0
  nsresult rv = aResult->GetAsBool(&persisted);
509
0
  if (NS_WARN_IF(NS_FAILED(rv))) {
510
0
    return rv;
511
0
  }
512
0
513
0
  mPersisted = persisted;
514
0
  return NS_OK;
515
0
}
516
517
template <typename T>
518
nsresult
519
RequestResolver::OnCompleteOrUsageResult(T* aRequest)
520
0
{
521
0
  MOZ_ASSERT(NS_IsMainThread());
522
0
  MOZ_ASSERT(aRequest);
523
0
524
0
  nsresult resultCode;
525
0
  nsresult rv = aRequest->GetResultCode(&resultCode);
526
0
  if (NS_WARN_IF(NS_FAILED(rv))) {
527
0
    return rv;
528
0
  }
529
0
530
0
  if (NS_FAILED(resultCode)) {
531
0
    return resultCode;
532
0
  }
533
0
534
0
  nsCOMPtr<nsIVariant> result;
535
0
  rv = aRequest->GetResult(getter_AddRefs(result));
536
0
  if (NS_WARN_IF(NS_FAILED(rv))) {
537
0
    return rv;
538
0
  }
539
0
540
0
  if (mType == Type::Estimate) {
541
0
    rv = GetStorageEstimate(result);
542
0
  } else {
543
0
    MOZ_ASSERT(mType == Type::Persist || mType == Type::Persisted);
544
0
545
0
    rv = GetPersisted(result);
546
0
  }
547
0
  if (NS_WARN_IF(NS_FAILED(rv))) {
548
0
    return rv;
549
0
  }
550
0
551
0
  return NS_OK;
552
0
}
Unexecuted instantiation: Unified_cpp_dom_quota0.cpp:nsresult mozilla::dom::(anonymous namespace)::RequestResolver::OnCompleteOrUsageResult<nsIQuotaRequest>(nsIQuotaRequest*)
Unexecuted instantiation: Unified_cpp_dom_quota0.cpp:nsresult mozilla::dom::(anonymous namespace)::RequestResolver::OnCompleteOrUsageResult<nsIQuotaUsageRequest>(nsIQuotaUsageRequest*)
553
554
nsresult
555
RequestResolver::Finish()
556
0
{
557
0
  // In a main thread request.
558
0
  if (!mProxy) {
559
0
    MOZ_ASSERT(mPromise);
560
0
561
0
    ResolveOrReject();
562
0
    return NS_OK;
563
0
  }
564
0
565
0
  {
566
0
    // In a worker thread request.
567
0
    MutexAutoLock lock(mProxy->Lock());
568
0
569
0
    if (NS_WARN_IF(mProxy->CleanedUp())) {
570
0
      return NS_ERROR_FAILURE;
571
0
    }
572
0
573
0
    RefPtr<FinishWorkerRunnable> runnable = new FinishWorkerRunnable(this);
574
0
    if (NS_WARN_IF(!runnable->Dispatch())) {
575
0
      return NS_ERROR_FAILURE;
576
0
    }
577
0
  }
578
0
579
0
  return NS_OK;
580
0
}
581
582
NS_IMETHODIMP
583
RequestResolver::OnComplete(nsIQuotaRequest *aRequest)
584
0
{
585
0
  MOZ_ASSERT(NS_IsMainThread());
586
0
  MOZ_ASSERT(aRequest);
587
0
588
0
  mResultCode = OnCompleteOrUsageResult(aRequest);
589
0
590
0
  nsresult rv = Finish();
591
0
  if (NS_WARN_IF(NS_FAILED(rv))) {
592
0
    return rv;
593
0
  }
594
0
595
0
  return NS_OK;
596
0
}
597
598
NS_IMETHODIMP
599
RequestResolver::OnUsageResult(nsIQuotaUsageRequest *aRequest)
600
0
{
601
0
  MOZ_ASSERT(NS_IsMainThread());
602
0
  MOZ_ASSERT(aRequest);
603
0
604
0
  mResultCode = OnCompleteOrUsageResult(aRequest);
605
0
606
0
  nsresult rv = Finish();
607
0
  if (NS_WARN_IF(NS_FAILED(rv))) {
608
0
    return rv;
609
0
  }
610
0
611
0
  return NS_OK;
612
0
}
613
614
bool
615
RequestResolver::
616
FinishWorkerRunnable::WorkerRun(JSContext* aCx, WorkerPrivate* aWorkerPrivate)
617
0
{
618
0
  MOZ_ASSERT(aCx);
619
0
  MOZ_ASSERT(aWorkerPrivate);
620
0
  aWorkerPrivate->AssertIsOnWorkerThread();
621
0
622
0
  MOZ_ASSERT(mResolver);
623
0
  mResolver->ResolveOrReject();
624
0
625
0
  return true;
626
0
}
627
628
bool
629
EstimateWorkerMainThreadRunnable::MainThreadRun()
630
0
{
631
0
  MOZ_ASSERT(NS_IsMainThread());
632
0
633
0
  nsCOMPtr<nsIPrincipal> principal;
634
0
635
0
  {
636
0
    MutexAutoLock lock(mProxy->Lock());
637
0
    if (mProxy->CleanedUp()) {
638
0
      return true;
639
0
    }
640
0
    principal = mProxy->GetWorkerPrivate()->GetPrincipal();
641
0
  }
642
0
643
0
  MOZ_ASSERT(principal);
644
0
645
0
  RefPtr<RequestResolver> resolver =
646
0
    new RequestResolver(RequestResolver::Type::Estimate, mProxy);
647
0
648
0
  RefPtr<nsIQuotaUsageRequest> request;
649
0
  nsresult rv =
650
0
    GetUsageForPrincipal(principal, resolver, getter_AddRefs(request));
651
0
  if (NS_WARN_IF(NS_FAILED(rv))) {
652
0
    return false;
653
0
  }
654
0
655
0
  return true;
656
0
}
657
658
bool
659
PersistedWorkerMainThreadRunnable::MainThreadRun()
660
0
{
661
0
  MOZ_ASSERT(NS_IsMainThread());
662
0
663
0
  nsCOMPtr<nsIPrincipal> principal;
664
0
665
0
  {
666
0
    MutexAutoLock lock(mProxy->Lock());
667
0
    if (mProxy->CleanedUp()) {
668
0
      return true;
669
0
    }
670
0
    principal = mProxy->GetWorkerPrivate()->GetPrincipal();
671
0
  }
672
0
673
0
  MOZ_ASSERT(principal);
674
0
675
0
  RefPtr<RequestResolver> resolver =
676
0
    new RequestResolver(RequestResolver::Type::Persisted, mProxy);
677
0
678
0
  RefPtr<nsIQuotaRequest> request;
679
0
  nsresult rv = Persisted(principal, resolver, getter_AddRefs(request));
680
0
  if (NS_WARN_IF(NS_FAILED(rv))) {
681
0
    return false;
682
0
  }
683
0
684
0
  return true;
685
0
}
686
687
nsresult
688
PersistentStoragePermissionRequest::Start()
689
0
{
690
0
  MOZ_ASSERT(NS_IsMainThread());
691
0
692
0
  // Grant permission if pref'ed on.
693
0
  if (Preferences::GetBool("dom.storageManager.prompt.testing", false)) {
694
0
    if (Preferences::GetBool("dom.storageManager.prompt.testing.allow",
695
0
                             false)) {
696
0
      return Allow(JS::UndefinedHandleValue);
697
0
    }
698
0
699
0
    return Cancel();
700
0
  }
701
0
702
0
  return nsContentPermissionUtils::AskPermission(this, mWindow);
703
0
}
704
705
NS_IMPL_CYCLE_COLLECTING_ADDREF(PersistentStoragePermissionRequest)
706
NS_IMPL_CYCLE_COLLECTING_RELEASE(PersistentStoragePermissionRequest)
707
708
0
NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(PersistentStoragePermissionRequest)
709
0
  NS_INTERFACE_MAP_ENTRY(nsIContentPermissionRequest)
710
0
  NS_INTERFACE_MAP_ENTRY(nsISupports)
711
0
NS_INTERFACE_MAP_END
712
713
NS_IMPL_CYCLE_COLLECTION(PersistentStoragePermissionRequest, mWindow, mPromise)
714
715
NS_IMETHODIMP
716
PersistentStoragePermissionRequest::GetPrincipal(nsIPrincipal** aPrincipal)
717
0
{
718
0
  MOZ_ASSERT(NS_IsMainThread());
719
0
  MOZ_ASSERT(aPrincipal);
720
0
  MOZ_ASSERT(mPrincipal);
721
0
722
0
  NS_ADDREF(*aPrincipal = mPrincipal);
723
0
724
0
  return NS_OK;
725
0
}
726
727
NS_IMETHODIMP
728
PersistentStoragePermissionRequest::GetIsHandlingUserInput(bool* aIsHandlingUserInput)
729
0
{
730
0
  *aIsHandlingUserInput = mIsHandlingUserInput;
731
0
  return NS_OK;
732
0
}
733
734
NS_IMETHODIMP
735
PersistentStoragePermissionRequest::GetWindow(mozIDOMWindow** aRequestingWindow)
736
0
{
737
0
  MOZ_ASSERT(NS_IsMainThread());
738
0
  MOZ_ASSERT(aRequestingWindow);
739
0
  MOZ_ASSERT(mWindow);
740
0
741
0
  NS_ADDREF(*aRequestingWindow = mWindow);
742
0
743
0
  return NS_OK;
744
0
}
745
746
NS_IMETHODIMP
747
PersistentStoragePermissionRequest::GetElement(Element** aElement)
748
0
{
749
0
  MOZ_ASSERT(NS_IsMainThread());
750
0
  MOZ_ASSERT(aElement);
751
0
752
0
  *aElement = nullptr;
753
0
  return NS_OK;
754
0
}
755
756
NS_IMETHODIMP
757
PersistentStoragePermissionRequest::Cancel()
758
0
{
759
0
  MOZ_ASSERT(NS_IsMainThread());
760
0
  MOZ_ASSERT(mPromise);
761
0
762
0
  RefPtr<RequestResolver> resolver =
763
0
    new RequestResolver(RequestResolver::Type::Persisted, mPromise);
764
0
765
0
  RefPtr<nsIQuotaRequest> request;
766
0
767
0
  return Persisted(mPrincipal, resolver, getter_AddRefs(request));
768
0
}
769
770
NS_IMETHODIMP
771
PersistentStoragePermissionRequest::Allow(JS::HandleValue aChoices)
772
0
{
773
0
  MOZ_ASSERT(NS_IsMainThread());
774
0
775
0
  RefPtr<RequestResolver> resolver =
776
0
    new RequestResolver(RequestResolver::Type::Persist, mPromise);
777
0
778
0
  nsCOMPtr<nsIQuotaManagerService> qms = QuotaManagerService::GetOrCreate();
779
0
  if (NS_WARN_IF(!qms)) {
780
0
    return NS_ERROR_FAILURE;
781
0
  }
782
0
783
0
  RefPtr<nsIQuotaRequest> request;
784
0
785
0
  nsresult rv = qms->Persist(mPrincipal, getter_AddRefs(request));
786
0
  if (NS_WARN_IF(NS_FAILED(rv))) {
787
0
    return rv;
788
0
  }
789
0
790
0
  MOZ_ALWAYS_SUCCEEDS(request->SetCallback(resolver));
791
0
792
0
  return NS_OK;
793
0
}
794
795
NS_IMETHODIMP
796
PersistentStoragePermissionRequest::GetRequester(
797
                                     nsIContentPermissionRequester** aRequester)
798
0
{
799
0
  MOZ_ASSERT(NS_IsMainThread());
800
0
  MOZ_ASSERT(aRequester);
801
0
802
0
  nsCOMPtr<nsIContentPermissionRequester> requester = mRequester;
803
0
  requester.forget(aRequester);
804
0
805
0
  return NS_OK;
806
0
}
807
808
NS_IMETHODIMP
809
PersistentStoragePermissionRequest::GetTypes(nsIArray** aTypes)
810
0
{
811
0
  MOZ_ASSERT(aTypes);
812
0
813
0
  nsTArray<nsString> emptyOptions;
814
0
815
0
  return nsContentPermissionUtils::CreatePermissionArray(
816
0
                                       NS_LITERAL_CSTRING("persistent-storage"),
817
0
                                       NS_LITERAL_CSTRING("unused"),
818
0
                                       emptyOptions,
819
0
                                       aTypes);
820
0
}
821
822
/*******************************************************************************
823
 * StorageManager
824
 ******************************************************************************/
825
826
StorageManager::StorageManager(nsIGlobalObject* aGlobal)
827
  : mOwner(aGlobal)
828
0
{
829
0
  MOZ_ASSERT(aGlobal);
830
0
}
831
832
StorageManager::~StorageManager()
833
0
{
834
0
}
835
836
already_AddRefed<Promise>
837
StorageManager::Persisted(ErrorResult& aRv)
838
0
{
839
0
  MOZ_ASSERT(mOwner);
840
0
841
0
  return ExecuteOpOnMainOrWorkerThread(mOwner,
842
0
                                       RequestResolver::Type::Persisted,
843
0
                                       aRv);
844
0
}
845
846
already_AddRefed<Promise>
847
StorageManager::Persist(ErrorResult& aRv)
848
0
{
849
0
  MOZ_ASSERT(mOwner);
850
0
851
0
  Telemetry::ScalarAdd(Telemetry::ScalarID::NAVIGATOR_STORAGE_PERSIST_COUNT, 1);
852
0
  return ExecuteOpOnMainOrWorkerThread(mOwner,
853
0
                                       RequestResolver::Type::Persist,
854
0
                                       aRv);
855
0
}
856
857
already_AddRefed<Promise>
858
StorageManager::Estimate(ErrorResult& aRv)
859
0
{
860
0
  MOZ_ASSERT(mOwner);
861
0
862
0
  Telemetry::ScalarAdd(Telemetry::ScalarID::NAVIGATOR_STORAGE_ESTIMATE_COUNT,
863
0
                       1);
864
0
  return ExecuteOpOnMainOrWorkerThread(mOwner,
865
0
                                       RequestResolver::Type::Estimate,
866
0
                                       aRv);
867
0
}
868
869
NS_IMPL_CYCLE_COLLECTION_WRAPPERCACHE(StorageManager, mOwner)
870
871
NS_IMPL_CYCLE_COLLECTING_ADDREF(StorageManager)
872
NS_IMPL_CYCLE_COLLECTING_RELEASE(StorageManager)
873
874
0
NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(StorageManager)
875
0
  NS_WRAPPERCACHE_INTERFACE_MAP_ENTRY
876
0
  NS_INTERFACE_MAP_ENTRY(nsISupports)
877
0
NS_INTERFACE_MAP_END
878
879
JSObject*
880
StorageManager::WrapObject(JSContext* aCx,
881
                           JS::Handle<JSObject*> aGivenProto)
882
0
{
883
0
  return StorageManager_Binding::Wrap(aCx, this, aGivenProto);
884
0
}
885
886
} // namespace dom
887
} // namespace mozilla