|
|
|
|
| 6 |
|
6 |
|
| 7 |
#include "StorageManager.h" |
7 |
#include "StorageManager.h" |
| 8 |
|
8 |
|
| 9 |
#include "mozilla/dom/PermissionUtils.h" |
|
|
| 10 |
#include "mozilla/dom/PromiseWorkerProxy.h" |
9 |
#include "mozilla/dom/PromiseWorkerProxy.h" |
| 11 |
#include "mozilla/dom/quota/QuotaManagerService.h" |
10 |
#include "mozilla/dom/quota/QuotaManagerService.h" |
| 12 |
#include "mozilla/dom/StorageManagerBinding.h" |
11 |
#include "mozilla/dom/StorageManagerBinding.h" |
|
|
| 89 |
private: |
88 |
private: |
| 90 |
~RequestResolver() |
89 |
~RequestResolver() |
| 91 |
{ } |
90 |
{ } |
|
|
91 |
|
| 92 |
nsresult |
| 93 |
HandleRequest(); |
| 92 |
}; |
94 |
}; |
| 93 |
|
95 |
|
| 94 |
// This class is used to return promise on worker thread. |
96 |
// This class is used to return promise on worker thread. |
|
|
| 163 |
nsCOMPtr<nsPIDOMWindowInner> mWindow; |
165 |
nsCOMPtr<nsPIDOMWindowInner> mWindow; |
| 164 |
RefPtr<Promise> mPromise; |
166 |
RefPtr<Promise> mPromise; |
| 165 |
nsCOMPtr<nsIContentPermissionRequester> mRequester; |
167 |
nsCOMPtr<nsIContentPermissionRequester> mRequester; |
| 166 |
PermissionState mPermission; |
|
|
| 167 |
|
168 |
|
| 168 |
public: |
169 |
public: |
| 169 |
PersistentStoragePermissionRequest(nsIPrincipal* aPrincipal, |
170 |
PersistentStoragePermissionRequest(nsIPrincipal* aPrincipal, |
|
|
| 172 |
: mPrincipal(aPrincipal) |
173 |
: mPrincipal(aPrincipal) |
| 173 |
, mWindow(aWindow) |
174 |
, mWindow(aWindow) |
| 174 |
, mPromise(aPromise) |
175 |
, mPromise(aPromise) |
| 175 |
, mPermission(PermissionState::Prompt) |
|
|
| 176 |
{ |
176 |
{ |
| 177 |
MOZ_ASSERT(aPrincipal); |
177 |
MOZ_ASSERT(aPrincipal); |
| 178 |
MOZ_ASSERT(aWindow); |
178 |
MOZ_ASSERT(aWindow); |
|
|
| 190 |
private: |
190 |
private: |
| 191 |
~PersistentStoragePermissionRequest() |
191 |
~PersistentStoragePermissionRequest() |
| 192 |
{ } |
192 |
{ } |
| 193 |
|
|
|
| 194 |
nsresult |
| 195 |
ResolvePromise(); |
| 196 |
}; |
193 |
}; |
| 197 |
|
194 |
|
| 198 |
NS_IMPL_ISUPPORTS(PersistentStoragePermissionRequest, |
195 |
NS_IMPL_ISUPPORTS(PersistentStoragePermissionRequest, |
|
|
| 258 |
} |
255 |
} |
| 259 |
|
256 |
|
| 260 |
nsresult |
257 |
nsresult |
| 261 |
Persist(nsIPrincipal* aPrincipal, nsIQuotaRequest** aRequest) |
258 |
Persisted(nsIPrincipal* aPrincipal, |
| 262 |
{ |
259 |
nsIQuotaCallback* aCallback, |
| 263 |
MOZ_ASSERT(aPrincipal); |
260 |
nsIQuotaRequest** aRequest) |
| 264 |
MOZ_ASSERT(aRequest); |
|
|
| 265 |
|
| 266 |
nsCOMPtr<nsIQuotaManagerService> qms = QuotaManagerService::GetOrCreate(); |
| 267 |
if (NS_WARN_IF(!qms)) { |
| 268 |
return NS_ERROR_FAILURE; |
| 269 |
} |
| 270 |
|
| 271 |
nsresult rv = qms->Persist(aPrincipal, aRequest); |
| 272 |
if (NS_WARN_IF(NS_FAILED(rv))) { |
| 273 |
return rv; |
| 274 |
} |
| 275 |
|
| 276 |
return NS_OK; |
| 277 |
}; |
| 278 |
|
| 279 |
nsresult |
| 280 |
Persisted(nsIPrincipal* aPrincipal, nsIQuotaRequest** aRequest) |
| 281 |
{ |
261 |
{ |
| 282 |
MOZ_ASSERT(aPrincipal); |
262 |
MOZ_ASSERT(aPrincipal); |
| 283 |
MOZ_ASSERT(aRequest); |
263 |
MOZ_ASSERT(aRequest); |
|
|
| 292 |
return rv; |
272 |
return rv; |
| 293 |
} |
273 |
} |
| 294 |
|
274 |
|
|
|
275 |
// All the methods in nsIQuotaManagerService shouldn't synchronously fire |
| 276 |
// any callbacks when they are being executed. Even when a result is ready, |
| 277 |
// a new runnable should be dispatched to current thread to fire the callback |
| 278 |
// asynchronously. It's safe to set the callback after we call Persisted(). |
| 279 |
MOZ_ALWAYS_SUCCEEDS((*aRequest)->SetCallback(aCallback)); |
| 280 |
|
| 295 |
return NS_OK; |
281 |
return NS_OK; |
| 296 |
}; |
282 |
}; |
| 297 |
|
283 |
|
|
|
| 325 |
nsCOMPtr<nsIPrincipal> principal = doc->NodePrincipal(); |
311 |
nsCOMPtr<nsIPrincipal> principal = doc->NodePrincipal(); |
| 326 |
MOZ_ASSERT(principal); |
312 |
MOZ_ASSERT(principal); |
| 327 |
|
313 |
|
| 328 |
nsresult rv = NS_OK; |
|
|
| 329 |
|
| 330 |
switch (aType) { |
314 |
switch (aType) { |
| 331 |
case RequestResolver::Type::Persisted: { |
315 |
case RequestResolver::Type::Persisted: { |
| 332 |
RefPtr<RequestResolver> resolver = |
316 |
RefPtr<RequestResolver> resolver = |
| 333 |
new RequestResolver(RequestResolver::Type::Persisted, promise); |
317 |
new RequestResolver(RequestResolver::Type::Persisted, promise); |
| 334 |
|
318 |
|
| 335 |
RefPtr<nsIQuotaRequest> request; |
319 |
RefPtr<nsIQuotaRequest> request; |
| 336 |
rv = Persisted(principal, getter_AddRefs(request)); |
320 |
aRv = Persisted(principal, resolver, getter_AddRefs(request)); |
| 337 |
if (NS_SUCCEEDED(rv)) { |
|
|
| 338 |
request->SetCallback(resolver); |
| 339 |
} |
| 340 |
|
321 |
|
| 341 |
break; |
322 |
break; |
| 342 |
} |
323 |
} |
|
|
| 345 |
RefPtr<PersistentStoragePermissionRequest> request = |
326 |
RefPtr<PersistentStoragePermissionRequest> request = |
| 346 |
new PersistentStoragePermissionRequest(principal, window, promise); |
327 |
new PersistentStoragePermissionRequest(principal, window, promise); |
| 347 |
|
328 |
|
| 348 |
rv = request->Start(); |
329 |
aRv = request->Start(); |
| 349 |
|
330 |
|
| 350 |
break; |
331 |
break; |
| 351 |
} |
332 |
} |
|
|
| 355 |
new RequestResolver(RequestResolver::Type::Estimate, promise); |
336 |
new RequestResolver(RequestResolver::Type::Estimate, promise); |
| 356 |
|
337 |
|
| 357 |
RefPtr<nsIQuotaUsageRequest> request; |
338 |
RefPtr<nsIQuotaUsageRequest> request; |
| 358 |
rv = GetUsageForPrincipal(principal, resolver, getter_AddRefs(request)); |
339 |
aRv = GetUsageForPrincipal(principal, |
|
|
340 |
resolver, |
| 341 |
getter_AddRefs(request)); |
| 359 |
|
342 |
|
| 360 |
break; |
343 |
break; |
| 361 |
} |
344 |
} |
|
|
| 364 |
MOZ_CRASH("Invalid aRequest type!"); |
347 |
MOZ_CRASH("Invalid aRequest type!"); |
| 365 |
} |
348 |
} |
| 366 |
|
349 |
|
| 367 |
if (NS_WARN_IF(NS_FAILED(rv))) { |
350 |
if (NS_WARN_IF(aRv.Failed())) { |
| 368 |
aRv.Throw(rv); |
|
|
| 369 |
return nullptr; |
351 |
return nullptr; |
| 370 |
} |
352 |
} |
| 371 |
|
353 |
|
|
|
| 411 |
return promise.forget(); |
393 |
return promise.forget(); |
| 412 |
}; |
394 |
}; |
| 413 |
|
395 |
|
| 414 |
PermissionState |
|
|
| 415 |
TestPermission(nsIPrincipal* aPrincipal) |
| 416 |
{ |
| 417 |
MOZ_ASSERT(NS_IsMainThread()); |
| 418 |
MOZ_ASSERT(aPrincipal); |
| 419 |
|
| 420 |
uint32_t permission = nsIPermissionManager::UNKNOWN_ACTION; |
| 421 |
|
| 422 |
nsCOMPtr<nsIPermissionManager> permissionManager = |
| 423 |
services::GetPermissionManager(); |
| 424 |
if (!permissionManager) { |
| 425 |
return PermissionState::Prompt; |
| 426 |
} |
| 427 |
|
| 428 |
nsresult rv = |
| 429 |
permissionManager->TestExactPermissionFromPrincipal(aPrincipal, |
| 430 |
"persistent-storage", |
| 431 |
&permission); |
| 432 |
if (NS_WARN_IF(NS_FAILED(rv))) { |
| 433 |
return PermissionState::Denied; |
| 434 |
} |
| 435 |
|
| 436 |
return ActionToPermissionState(permission); |
| 437 |
} |
| 438 |
|
| 439 |
} // namespace |
396 |
} // namespace |
| 440 |
|
397 |
|
| 441 |
/******************************************************************************* |
398 |
/******************************************************************************* |
|
|
| 470 |
mProxy->CleanUp(); |
427 |
mProxy->CleanUp(); |
| 471 |
} |
428 |
} |
| 472 |
} |
429 |
} |
| 473 |
} autoCleanUp(proxy); |
430 |
}; |
|
|
431 |
|
| 432 |
Maybe<CleanupProxy> autoCleanup; |
| 433 |
if (proxy) { |
| 434 |
autoCleanup.emplace(proxy); |
| 435 |
} |
| 474 |
|
436 |
|
| 475 |
if (mType == Type::Estimate) { |
437 |
if (mType == Type::Estimate) { |
| 476 |
if (NS_SUCCEEDED(mResultCode)) { |
438 |
if (NS_SUCCEEDED(mResultCode)) { |
|
|
| 487 |
promise->MaybeResolve(mPersisted); |
449 |
promise->MaybeResolve(mPersisted); |
| 488 |
} |
450 |
} |
| 489 |
|
451 |
|
| 490 |
NS_IMETHODIMP |
452 |
nsresult |
| 491 |
RequestResolver::OnUsageResult(nsIQuotaUsageRequest *aRequest) |
453 |
RequestResolver::HandleRequest() |
| 492 |
{ |
454 |
{ |
| 493 |
MOZ_ASSERT(NS_IsMainThread()); |
|
|
| 494 |
MOZ_ASSERT(aRequest); |
| 495 |
|
| 496 |
nsresult rv = aRequest->GetResultCode(&mResultCode); |
| 497 |
if (NS_WARN_IF(NS_FAILED(rv))) { |
| 498 |
mResultCode = rv; |
| 499 |
} else if (NS_SUCCEEDED(mResultCode)) { |
| 500 |
rv = GetStorageEstimate(aRequest, mStorageEstimate); |
| 501 |
if (NS_WARN_IF(NS_FAILED(rv))) { |
| 502 |
mResultCode = rv; |
| 503 |
} |
| 504 |
} |
| 505 |
|
| 506 |
// In a main thread request. |
455 |
// In a main thread request. |
| 507 |
if (!mProxy) { |
456 |
if (!mProxy) { |
| 508 |
MOZ_ASSERT(mPromise); |
457 |
MOZ_ASSERT(mPromise); |
|
|
| 511 |
return NS_OK; |
460 |
return NS_OK; |
| 512 |
} |
461 |
} |
| 513 |
|
462 |
|
| 514 |
// In a worker thread request. |
463 |
{ |
| 515 |
MutexAutoLock lock(mProxy->Lock()); |
464 |
// In a worker thread request. |
|
|
465 |
MutexAutoLock lock(mProxy->Lock()); |
| 516 |
|
466 |
|
| 517 |
if (NS_WARN_IF(mProxy->CleanedUp())) { |
467 |
if (NS_WARN_IF(mProxy->CleanedUp())) { |
| 518 |
return NS_ERROR_FAILURE; |
468 |
return NS_ERROR_FAILURE; |
| 519 |
} |
469 |
} |
| 520 |
|
470 |
|
| 521 |
RefPtr<FinishWorkerRunnable> runnable = new FinishWorkerRunnable(this); |
471 |
RefPtr<FinishWorkerRunnable> runnable = new FinishWorkerRunnable(this); |
| 522 |
if (NS_WARN_IF(!runnable->Dispatch())) { |
472 |
if (NS_WARN_IF(!runnable->Dispatch())) { |
| 523 |
return NS_ERROR_FAILURE; |
473 |
return NS_ERROR_FAILURE; |
|
|
474 |
} |
| 524 |
} |
475 |
} |
| 525 |
|
476 |
|
| 526 |
return NS_OK; |
477 |
return NS_OK; |
| 527 |
} |
478 |
} |
| 528 |
|
479 |
|
|
|
480 |
NS_IMPL_ISUPPORTS(RequestResolver, nsIQuotaUsageCallback, nsIQuotaCallback) |
| 481 |
|
| 529 |
NS_IMETHODIMP |
482 |
NS_IMETHODIMP |
| 530 |
RequestResolver::OnComplete(nsIQuotaRequest *aRequest) |
483 |
RequestResolver::OnComplete(nsIQuotaRequest *aRequest) |
| 531 |
{ |
484 |
{ |
|
|
| 539 |
return rv; |
492 |
return rv; |
| 540 |
} |
493 |
} |
| 541 |
|
494 |
|
| 542 |
RequestResolver* result = static_cast<RequestResolver*>(callback.get()); |
495 |
auto result = static_cast<RequestResolver*>(callback.get()); |
| 543 |
|
496 |
|
| 544 |
Type type = result->GetType(); |
497 |
Type type = result->GetType(); |
| 545 |
nsresult resultCode; |
498 |
nsresult resultCode; |
|
|
| 567 |
MOZ_CRASH("Invalid callback type!"); |
520 |
MOZ_CRASH("Invalid callback type!"); |
| 568 |
} |
521 |
} |
| 569 |
|
522 |
|
| 570 |
// In a main thread request. |
523 |
return HandleRequest(); |
| 571 |
if (!mProxy) { |
524 |
} |
| 572 |
MOZ_ASSERT(mPromise); |
|
|
| 573 |
|
| 574 |
ResolveOrReject(); |
| 575 |
return NS_OK; |
| 576 |
} |
| 577 |
|
| 578 |
{ |
| 579 |
// In a worker thread request. |
| 580 |
MutexAutoLock lock(mProxy->Lock()); |
| 581 |
|
525 |
|
| 582 |
if (NS_WARN_IF(mProxy->CleanedUp())) { |
526 |
NS_IMETHODIMP |
| 583 |
return NS_ERROR_FAILURE; |
527 |
RequestResolver::OnUsageResult(nsIQuotaUsageRequest *aRequest) |
| 584 |
} |
528 |
{ |
|
|
529 |
MOZ_ASSERT(NS_IsMainThread()); |
| 530 |
MOZ_ASSERT(aRequest); |
| 585 |
|
531 |
|
| 586 |
RefPtr<FinishWorkerRunnable> runnable = new FinishWorkerRunnable(this); |
532 |
nsresult rv = aRequest->GetResultCode(&mResultCode); |
| 587 |
if (NS_WARN_IF(!runnable->Dispatch())) { |
533 |
if (NS_WARN_IF(NS_FAILED(rv))) { |
| 588 |
return NS_ERROR_FAILURE; |
534 |
mResultCode = rv; |
|
|
535 |
} else if (NS_SUCCEEDED(mResultCode)) { |
| 536 |
rv = GetStorageEstimate(aRequest, mStorageEstimate); |
| 537 |
if (NS_WARN_IF(NS_FAILED(rv))) { |
| 538 |
mResultCode = rv; |
| 589 |
} |
539 |
} |
| 590 |
} |
540 |
} |
| 591 |
|
541 |
|
| 592 |
return NS_OK; |
542 |
return HandleRequest(); |
| 593 |
} |
543 |
} |
| 594 |
|
544 |
|
| 595 |
NS_IMPL_ISUPPORTS(RequestResolver, nsIQuotaUsageCallback, nsIQuotaCallback) |
|
|
| 596 |
|
| 597 |
bool |
545 |
bool |
| 598 |
RequestResolver:: |
546 |
RequestResolver:: |
| 599 |
FinishWorkerRunnable::WorkerRun(JSContext* aCx, WorkerPrivate* aWorkerPrivate) |
547 |
FinishWorkerRunnable::WorkerRun(JSContext* aCx, WorkerPrivate* aWorkerPrivate) |
|
|
| 659 |
new RequestResolver(RequestResolver::Type::Persisted, mProxy); |
607 |
new RequestResolver(RequestResolver::Type::Persisted, mProxy); |
| 660 |
|
608 |
|
| 661 |
RefPtr<nsIQuotaRequest> request; |
609 |
RefPtr<nsIQuotaRequest> request; |
| 662 |
nsresult rv = Persisted(principal, getter_AddRefs(request)); |
610 |
nsresult rv = Persisted(principal, resolver, getter_AddRefs(request)); |
| 663 |
if (NS_WARN_IF(NS_FAILED(rv))) { |
611 |
if (NS_WARN_IF(NS_FAILED(rv))) { |
| 664 |
return false; |
612 |
return false; |
| 665 |
} |
613 |
} |
| 666 |
|
614 |
|
| 667 |
// All the methods in nsIQuotaManagerService shouldn't synchronously fire |
|
|
| 668 |
// any callbacks when they are being executed. Even when a result is ready, |
| 669 |
// a new runnable should be dispatched to current thread to fire the callback |
| 670 |
// asynchronously. |
| 671 |
request->SetCallback(resolver); |
| 672 |
|
| 673 |
return true; |
615 |
return true; |
| 674 |
} |
616 |
} |
| 675 |
|
617 |
|
|
|
| 682 |
if (Preferences::GetBool("dom.storageManager.prompt.testing", false)) { |
624 |
if (Preferences::GetBool("dom.storageManager.prompt.testing", false)) { |
| 683 |
if (Preferences::GetBool("dom.storageManager.prompt.testing.allow", |
625 |
if (Preferences::GetBool("dom.storageManager.prompt.testing.allow", |
| 684 |
false)) { |
626 |
false)) { |
| 685 |
mPermission = PermissionState::Granted; |
|
|
| 686 |
return Allow(JS::UndefinedHandleValue); |
627 |
return Allow(JS::UndefinedHandleValue); |
| 687 |
} |
628 |
} |
| 688 |
|
629 |
|
| 689 |
mPermission = PermissionState::Denied; |
630 |
return Cancel(); |
| 690 |
return ResolvePromise(); |
|
|
| 691 |
} |
631 |
} |
| 692 |
|
632 |
|
| 693 |
return nsContentPermissionUtils::AskPermission(this, mWindow); |
633 |
return nsContentPermissionUtils::AskPermission(this, mWindow); |
|
|
| 732 |
{ |
672 |
{ |
| 733 |
MOZ_ASSERT(NS_IsMainThread()); |
673 |
MOZ_ASSERT(NS_IsMainThread()); |
| 734 |
|
674 |
|
| 735 |
// `Cancel` is called if the user denied permission or dismissed the |
675 |
mPromise->MaybeResolve(false); |
| 736 |
// permission request. To distinguish between the two, we set the |
676 |
return NS_OK; |
| 737 |
// permission to "prompt" and query the permission manager in |
|
|
| 738 |
// `ResolvePromise`. |
| 739 |
mPermission = PermissionState::Prompt; |
| 740 |
|
| 741 |
return ResolvePromise(); |
| 742 |
} |
677 |
} |
| 743 |
|
678 |
|
| 744 |
NS_IMETHODIMP |
679 |
NS_IMETHODIMP |
|
|
| 746 |
{ |
681 |
{ |
| 747 |
MOZ_ASSERT(NS_IsMainThread()); |
682 |
MOZ_ASSERT(NS_IsMainThread()); |
| 748 |
|
683 |
|
| 749 |
mPermission = PermissionState::Granted; |
|
|
| 750 |
RefPtr<RequestResolver> resolver = |
684 |
RefPtr<RequestResolver> resolver = |
| 751 |
new RequestResolver(RequestResolver::Type::Persist, mPromise); |
685 |
new RequestResolver(RequestResolver::Type::Persist, mPromise); |
| 752 |
|
686 |
|
|
|
687 |
nsCOMPtr<nsIQuotaManagerService> qms = QuotaManagerService::GetOrCreate(); |
| 688 |
if (NS_WARN_IF(!qms)) { |
| 689 |
return NS_ERROR_FAILURE; |
| 690 |
} |
| 691 |
|
| 753 |
RefPtr<nsIQuotaRequest> request; |
692 |
RefPtr<nsIQuotaRequest> request; |
| 754 |
|
693 |
|
| 755 |
nsresult rv = Persist(mPrincipal, getter_AddRefs(request)); |
694 |
nsresult rv = qms->Persist(mPrincipal, getter_AddRefs(request)); |
| 756 |
if (NS_SUCCEEDED(rv)) { |
695 |
if (NS_WARN_IF(NS_FAILED(rv))) { |
| 757 |
request->SetCallback(resolver); |
696 |
return rv; |
| 758 |
} |
697 |
} |
| 759 |
|
698 |
|
| 760 |
return rv; |
699 |
MOZ_ALWAYS_SUCCEEDS(request->SetCallback(resolver)); |
|
|
700 |
|
| 701 |
return NS_OK; |
| 761 |
} |
702 |
} |
| 762 |
|
703 |
|
| 763 |
NS_IMETHODIMP |
704 |
NS_IMETHODIMP |
|
|
| 773 |
return NS_OK; |
714 |
return NS_OK; |
| 774 |
} |
715 |
} |
| 775 |
|
716 |
|
| 776 |
nsresult |
|
|
| 777 |
PersistentStoragePermissionRequest::ResolvePromise() |
| 778 |
{ |
| 779 |
MOZ_ASSERT(NS_IsMainThread()); |
| 780 |
|
| 781 |
nsresult rv = NS_OK; |
| 782 |
if (mPermission == PermissionState::Prompt) { |
| 783 |
// This will still be "prompt" if the user dismissed the doorhanger, or |
| 784 |
// "denied" otherwise. |
| 785 |
mPermission = TestPermission(mPrincipal); |
| 786 |
} |
| 787 |
|
| 788 |
mPromise->MaybeResolve(mPermission == PermissionState::Granted); |
| 789 |
|
| 790 |
return rv; |
| 791 |
} |
| 792 |
|
| 793 |
NS_IMETHODIMP |
717 |
NS_IMETHODIMP |
| 794 |
PersistentStoragePermissionRequest::GetTypes(nsIArray** aTypes) |
718 |
PersistentStoragePermissionRequest::GetTypes(nsIArray** aTypes) |
| 795 |
{ |
719 |
{ |