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