Attachment #8854478: Bug 1286717 - Part 1: Expose persist/persisted to StorageManager, r=janv for bug #1286717

View | Details | Raw Unified | Return to bug 1286717
Collapse All | Expand All

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

Return to bug 1286717