Bug 1874684 - Part 6: Limit day length calculations to safe integers. r=mgaudet
[gecko.git] / dom / quota / QuotaManagerService.cpp
blob265a621a087e3176b70f0e7f858ec98235201ceb
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/. */
7 #include "QuotaManagerService.h"
9 // Local includes
10 #include "ActorsChild.h"
11 #include "Client.h"
12 #include "QuotaManager.h"
13 #include "QuotaRequests.h"
15 // Global includes
16 #include <cstdint>
17 #include <cstring>
18 #include <utility>
19 #include "MainThreadUtils.h"
20 #include "mozilla/Assertions.h"
21 #include "mozilla/Atomics.h"
22 #include "mozilla/ClearOnShutdown.h"
23 #include "mozilla/Hal.h"
24 #include "mozilla/MacroForEach.h"
25 #include "mozilla/Maybe.h"
26 #include "mozilla/OriginAttributes.h"
27 #include "mozilla/RefPtr.h"
28 #include "mozilla/Services.h"
29 #include "mozilla/StaticPrefs_dom.h"
30 #include "mozilla/StaticPtr.h"
31 #include "mozilla/Unused.h"
32 #include "mozilla/Variant.h"
33 #include "mozilla/dom/quota/PQuota.h"
34 #include "mozilla/dom/quota/PersistenceType.h"
35 #include "mozilla/dom/quota/ResultExtensions.h"
36 #include "mozilla/fallible.h"
37 #include "mozilla/hal_sandbox/PHal.h"
38 #include "mozilla/ipc/BackgroundChild.h"
39 #include "mozilla/ipc/BackgroundUtils.h"
40 #include "mozilla/ipc/PBackgroundChild.h"
41 #include "mozilla/ipc/PBackgroundSharedTypes.h"
42 #include "nsCOMPtr.h"
43 #include "nsContentUtils.h"
44 #include "nsDebug.h"
45 #include "nsError.h"
46 #include "nsIObserverService.h"
47 #include "nsIPrincipal.h"
48 #include "nsIUserIdleService.h"
49 #include "nsServiceManagerUtils.h"
50 #include "nsStringFwd.h"
51 #include "nsVariant.h"
52 #include "nsXULAppAPI.h"
53 #include "nscore.h"
55 #define PROFILE_BEFORE_CHANGE_QM_OBSERVER_ID "profile-before-change-qm"
57 namespace mozilla::dom::quota {
59 using namespace mozilla::ipc;
61 namespace {
63 const char kIdleServiceContractId[] = "@mozilla.org/widget/useridleservice;1";
65 // The number of seconds we will wait after receiving the idle-daily
66 // notification before beginning maintenance.
67 const uint32_t kIdleObserverTimeSec = 1;
69 mozilla::StaticRefPtr<QuotaManagerService> gQuotaManagerService;
71 mozilla::Atomic<bool> gInitialized(false);
72 mozilla::Atomic<bool> gClosed(false);
74 nsresult CheckedPrincipalToPrincipalInfo(nsIPrincipal* aPrincipal,
75 PrincipalInfo& aPrincipalInfo) {
76 MOZ_ASSERT(aPrincipal);
78 nsresult rv = PrincipalToPrincipalInfo(aPrincipal, &aPrincipalInfo);
79 if (NS_WARN_IF(NS_FAILED(rv))) {
80 return rv;
83 if (NS_WARN_IF(!QuotaManager::IsPrincipalInfoValid(aPrincipalInfo))) {
84 return NS_ERROR_FAILURE;
87 if (aPrincipalInfo.type() != PrincipalInfo::TContentPrincipalInfo &&
88 aPrincipalInfo.type() != PrincipalInfo::TSystemPrincipalInfo) {
89 return NS_ERROR_UNEXPECTED;
92 return NS_OK;
95 nsresult GetClearResetOriginParams(nsIPrincipal* aPrincipal,
96 const nsACString& aPersistenceType,
97 const nsAString& aClientType,
98 ClearResetOriginParams& aParams) {
99 MOZ_ASSERT(NS_IsMainThread());
100 MOZ_ASSERT(aPrincipal);
102 nsresult rv =
103 CheckedPrincipalToPrincipalInfo(aPrincipal, aParams.principalInfo());
104 if (NS_WARN_IF(NS_FAILED(rv))) {
105 return rv;
108 if (aPersistenceType.IsVoid()) {
109 aParams.persistenceTypeIsExplicit() = false;
110 } else {
111 const auto maybePersistenceType =
112 PersistenceTypeFromString(aPersistenceType, fallible);
113 if (NS_WARN_IF(maybePersistenceType.isNothing())) {
114 return NS_ERROR_INVALID_ARG;
117 aParams.persistenceType() = maybePersistenceType.value();
118 aParams.persistenceTypeIsExplicit() = true;
121 if (aClientType.IsVoid()) {
122 aParams.clientTypeIsExplicit() = false;
123 } else {
124 Client::Type clientType;
125 bool ok = Client::TypeFromText(aClientType, clientType, fallible);
126 if (NS_WARN_IF(!ok)) {
127 return NS_ERROR_INVALID_ARG;
130 aParams.clientType() = clientType;
131 aParams.clientTypeIsExplicit() = true;
134 return NS_OK;
137 class BoolResponsePromiseResolveOrRejectCallback {
138 public:
139 using PromiseType = BoolResponsePromise;
140 using RequestType = Request;
142 explicit BoolResponsePromiseResolveOrRejectCallback(
143 RefPtr<RequestType> aRequest)
144 : mRequest(std::move(aRequest)) {}
146 void operator()(const PromiseType::ResolveOrRejectValue& aValue) {
147 if (aValue.IsResolve()) {
148 const BoolResponse& response = aValue.ResolveValue();
150 switch (response.type()) {
151 case BoolResponse::Tnsresult:
152 mRequest->SetError(response.get_nsresult());
153 break;
155 case BoolResponse::Tbool: {
156 RefPtr<nsVariant> variant = new nsVariant();
157 variant->SetAsBool(response.get_bool());
159 mRequest->SetResult(variant);
160 break;
162 default:
163 MOZ_CRASH("Unknown response type!");
166 } else {
167 mRequest->SetError(NS_ERROR_FAILURE);
171 private:
172 RefPtr<RequestType> mRequest;
175 } // namespace
177 class QuotaManagerService::PendingRequestInfo {
178 protected:
179 RefPtr<RequestBase> mRequest;
181 public:
182 explicit PendingRequestInfo(RequestBase* aRequest) : mRequest(aRequest) {}
184 virtual ~PendingRequestInfo() = default;
186 RequestBase* GetRequest() const { return mRequest; }
188 virtual nsresult InitiateRequest(QuotaChild* aActor) = 0;
191 class QuotaManagerService::UsageRequestInfo : public PendingRequestInfo {
192 UsageRequestParams mParams;
194 public:
195 UsageRequestInfo(UsageRequest* aRequest, const UsageRequestParams& aParams)
196 : PendingRequestInfo(aRequest), mParams(aParams) {
197 MOZ_ASSERT(aRequest);
198 MOZ_ASSERT(aParams.type() != UsageRequestParams::T__None);
201 virtual nsresult InitiateRequest(QuotaChild* aActor) override;
204 class QuotaManagerService::RequestInfo : public PendingRequestInfo {
205 RequestParams mParams;
207 public:
208 RequestInfo(Request* aRequest, const RequestParams& aParams)
209 : PendingRequestInfo(aRequest), mParams(aParams) {
210 MOZ_ASSERT(aRequest);
211 MOZ_ASSERT(aParams.type() != RequestParams::T__None);
214 virtual nsresult InitiateRequest(QuotaChild* aActor) override;
217 class QuotaManagerService::IdleMaintenanceInfo : public PendingRequestInfo {
218 const bool mStart;
220 public:
221 explicit IdleMaintenanceInfo(bool aStart)
222 : PendingRequestInfo(nullptr), mStart(aStart) {}
224 virtual nsresult InitiateRequest(QuotaChild* aActor) override;
227 QuotaManagerService::QuotaManagerService()
228 : mBackgroundActor(nullptr),
229 mBackgroundActorFailed(false),
230 mIdleObserverRegistered(false) {
231 MOZ_ASSERT(NS_IsMainThread());
234 QuotaManagerService::~QuotaManagerService() {
235 MOZ_ASSERT(NS_IsMainThread());
236 MOZ_ASSERT(!mIdleObserverRegistered);
239 // static
240 QuotaManagerService* QuotaManagerService::GetOrCreate() {
241 MOZ_ASSERT(NS_IsMainThread());
243 if (gClosed) {
244 MOZ_ASSERT(false, "Calling GetOrCreate() after shutdown!");
245 return nullptr;
248 if (!gQuotaManagerService) {
249 RefPtr<QuotaManagerService> instance(new QuotaManagerService());
251 nsresult rv = instance->Init();
252 if (NS_WARN_IF(NS_FAILED(rv))) {
253 return nullptr;
256 if (gInitialized.exchange(true)) {
257 MOZ_ASSERT(false, "Initialized more than once?!");
260 gQuotaManagerService = instance;
262 ClearOnShutdown(&gQuotaManagerService);
265 return gQuotaManagerService;
268 // static
269 QuotaManagerService* QuotaManagerService::Get() {
270 // Does not return an owning reference.
271 return gQuotaManagerService;
274 // static
275 already_AddRefed<QuotaManagerService> QuotaManagerService::FactoryCreate() {
276 RefPtr<QuotaManagerService> quotaManagerService = GetOrCreate();
277 return quotaManagerService.forget();
280 void QuotaManagerService::ClearBackgroundActor() {
281 MOZ_ASSERT(NS_IsMainThread());
283 mBackgroundActor = nullptr;
286 void QuotaManagerService::AbortOperationsForProcess(
287 ContentParentId aContentParentId) {
288 MOZ_ASSERT(XRE_IsParentProcess());
289 MOZ_ASSERT(NS_IsMainThread());
291 nsresult rv = EnsureBackgroundActor();
292 if (NS_WARN_IF(NS_FAILED(rv))) {
293 return;
296 if (NS_WARN_IF(
297 !mBackgroundActor->SendAbortOperationsForProcess(aContentParentId))) {
298 return;
302 nsresult QuotaManagerService::Init() {
303 MOZ_ASSERT(NS_IsMainThread());
305 if (XRE_IsParentProcess()) {
306 nsCOMPtr<nsIObserverService> observerService =
307 mozilla::services::GetObserverService();
308 if (NS_WARN_IF(!observerService)) {
309 return NS_ERROR_FAILURE;
312 nsresult rv = observerService->AddObserver(
313 this, PROFILE_BEFORE_CHANGE_QM_OBSERVER_ID, false);
314 if (NS_WARN_IF(NS_FAILED(rv))) {
315 return rv;
319 return NS_OK;
322 void QuotaManagerService::Destroy() {
323 // Setting the closed flag prevents the service from being recreated.
324 // Don't set it though if there's no real instance created.
325 if (gInitialized && gClosed.exchange(true)) {
326 MOZ_ASSERT(false, "Shutdown more than once?!");
329 delete this;
332 nsresult QuotaManagerService::EnsureBackgroundActor() {
333 MOZ_ASSERT(NS_IsMainThread());
335 // Nothing can be done here if we have previously failed to create a
336 // background actor.
337 if (mBackgroundActorFailed) {
338 return NS_ERROR_FAILURE;
341 if (!mBackgroundActor) {
342 PBackgroundChild* backgroundActor =
343 BackgroundChild::GetOrCreateForCurrentThread();
344 if (NS_WARN_IF(!backgroundActor)) {
345 mBackgroundActorFailed = true;
346 return NS_ERROR_FAILURE;
350 RefPtr<QuotaChild> actor = new QuotaChild(this);
352 mBackgroundActor = static_cast<QuotaChild*>(
353 backgroundActor->SendPQuotaConstructor(actor));
357 if (!mBackgroundActor) {
358 mBackgroundActorFailed = true;
359 return NS_ERROR_FAILURE;
362 return NS_OK;
365 nsresult QuotaManagerService::InitiateRequest(PendingRequestInfo& aInfo) {
366 nsresult rv = EnsureBackgroundActor();
367 if (NS_WARN_IF(NS_FAILED(rv))) {
368 return rv;
371 rv = aInfo.InitiateRequest(mBackgroundActor);
372 if (NS_WARN_IF(NS_FAILED(rv))) {
373 return rv;
376 return NS_OK;
379 void QuotaManagerService::PerformIdleMaintenance() {
380 using namespace mozilla::hal;
382 MOZ_ASSERT(XRE_IsParentProcess());
383 MOZ_ASSERT(NS_IsMainThread());
385 // If we're running on battery power then skip all idle maintenance since we
386 // would otherwise be doing lots of disk I/O.
387 BatteryInformation batteryInfo;
389 #ifdef MOZ_WIDGET_ANDROID
390 // Android XPCShell doesn't load the AndroidBridge that is needed to make
391 // GetCurrentBatteryInformation work...
392 if (!QuotaManager::IsRunningXPCShellTests())
393 #endif
395 // In order to give the correct battery level, hal must have registered
396 // battery observers.
397 RegisterBatteryObserver(this);
398 GetCurrentBatteryInformation(&batteryInfo);
399 UnregisterBatteryObserver(this);
402 // If we're running XPCShell because we always want to be able to test this
403 // code so pretend that we're always charging.
404 if (QuotaManager::IsRunningXPCShellTests()) {
405 batteryInfo.level() = 100;
406 batteryInfo.charging() = true;
409 if (NS_WARN_IF(!batteryInfo.charging())) {
410 return;
413 if (QuotaManager::IsRunningXPCShellTests()) {
414 // We don't want user activity to impact this code if we're running tests.
415 Unused << Observe(nullptr, OBSERVER_TOPIC_IDLE, nullptr);
416 } else if (!mIdleObserverRegistered) {
417 nsCOMPtr<nsIUserIdleService> idleService =
418 do_GetService(kIdleServiceContractId);
419 MOZ_ASSERT(idleService);
421 MOZ_ALWAYS_SUCCEEDS(
422 idleService->AddIdleObserver(this, kIdleObserverTimeSec));
424 mIdleObserverRegistered = true;
428 void QuotaManagerService::RemoveIdleObserver() {
429 MOZ_ASSERT(XRE_IsParentProcess());
430 MOZ_ASSERT(NS_IsMainThread());
432 if (mIdleObserverRegistered) {
433 nsCOMPtr<nsIUserIdleService> idleService =
434 do_GetService(kIdleServiceContractId);
435 MOZ_ASSERT(idleService);
437 // Ignore the return value of RemoveIdleObserver, it may fail if the
438 // observer has already been unregistered during shutdown.
439 Unused << idleService->RemoveIdleObserver(this, kIdleObserverTimeSec);
441 mIdleObserverRegistered = false;
445 NS_IMPL_ADDREF(QuotaManagerService)
446 NS_IMPL_RELEASE_WITH_DESTROY(QuotaManagerService, Destroy())
447 NS_IMPL_QUERY_INTERFACE(QuotaManagerService, nsIQuotaManagerService,
448 nsIObserver)
450 NS_IMETHODIMP
451 QuotaManagerService::StorageName(nsIQuotaRequest** _retval) {
452 MOZ_ASSERT(NS_IsMainThread());
453 MOZ_ASSERT(nsContentUtils::IsCallerChrome());
455 if (NS_WARN_IF(!StaticPrefs::dom_quotaManager_testing())) {
456 return NS_ERROR_UNEXPECTED;
459 RefPtr<Request> request = new Request();
461 StorageNameParams params;
463 RequestInfo info(request, params);
465 nsresult rv = InitiateRequest(info);
466 if (NS_WARN_IF(NS_FAILED(rv))) {
467 return rv;
470 request.forget(_retval);
471 return NS_OK;
474 NS_IMETHODIMP
475 QuotaManagerService::StorageInitialized(nsIQuotaRequest** _retval) {
476 MOZ_ASSERT(NS_IsMainThread());
477 MOZ_ASSERT(nsContentUtils::IsCallerChrome());
479 if (NS_WARN_IF(!StaticPrefs::dom_quotaManager_testing())) {
480 return NS_ERROR_UNEXPECTED;
483 QM_TRY(MOZ_TO_RESULT(EnsureBackgroundActor()));
485 RefPtr<Request> request = new Request();
487 mBackgroundActor->SendStorageInitialized()->Then(
488 GetCurrentSerialEventTarget(), __func__,
489 BoolResponsePromiseResolveOrRejectCallback(request));
491 request.forget(_retval);
492 return NS_OK;
495 NS_IMETHODIMP
496 QuotaManagerService::TemporaryStorageInitialized(nsIQuotaRequest** _retval) {
497 MOZ_ASSERT(NS_IsMainThread());
498 MOZ_ASSERT(nsContentUtils::IsCallerChrome());
500 if (NS_WARN_IF(!StaticPrefs::dom_quotaManager_testing())) {
501 return NS_ERROR_UNEXPECTED;
504 QM_TRY(MOZ_TO_RESULT(EnsureBackgroundActor()));
506 RefPtr<Request> request = new Request();
508 mBackgroundActor->SendTemporaryStorageInitialized()->Then(
509 GetCurrentSerialEventTarget(), __func__,
510 BoolResponsePromiseResolveOrRejectCallback(request));
512 request.forget(_retval);
513 return NS_OK;
516 NS_IMETHODIMP
517 QuotaManagerService::Init(nsIQuotaRequest** _retval) {
518 MOZ_ASSERT(NS_IsMainThread());
519 MOZ_ASSERT(nsContentUtils::IsCallerChrome());
521 if (NS_WARN_IF(!StaticPrefs::dom_quotaManager_testing())) {
522 return NS_ERROR_UNEXPECTED;
525 QM_TRY(MOZ_TO_RESULT(EnsureBackgroundActor()));
527 RefPtr<Request> request = new Request();
529 mBackgroundActor->SendInitializeStorage()->Then(
530 GetCurrentSerialEventTarget(), __func__,
531 BoolResponsePromiseResolveOrRejectCallback(request));
533 request.forget(_retval);
534 return NS_OK;
537 NS_IMETHODIMP
538 QuotaManagerService::InitTemporaryStorage(nsIQuotaRequest** _retval) {
539 MOZ_ASSERT(NS_IsMainThread());
540 MOZ_ASSERT(nsContentUtils::IsCallerChrome());
542 if (NS_WARN_IF(!StaticPrefs::dom_quotaManager_testing())) {
543 return NS_ERROR_UNEXPECTED;
546 QM_TRY(MOZ_TO_RESULT(EnsureBackgroundActor()));
548 RefPtr<Request> request = new Request();
550 mBackgroundActor->SendInitializeTemporaryStorage()->Then(
551 GetCurrentSerialEventTarget(), __func__,
552 BoolResponsePromiseResolveOrRejectCallback(request));
554 request.forget(_retval);
555 return NS_OK;
558 NS_IMETHODIMP
559 QuotaManagerService::InitializePersistentOrigin(nsIPrincipal* aPrincipal,
560 nsIQuotaRequest** _retval) {
561 MOZ_ASSERT(NS_IsMainThread());
562 MOZ_ASSERT(nsContentUtils::IsCallerChrome());
564 if (NS_WARN_IF(!StaticPrefs::dom_quotaManager_testing())) {
565 return NS_ERROR_UNEXPECTED;
568 RefPtr<Request> request = new Request();
570 InitializePersistentOriginParams params;
572 nsresult rv =
573 CheckedPrincipalToPrincipalInfo(aPrincipal, params.principalInfo());
574 if (NS_WARN_IF(NS_FAILED(rv))) {
575 return rv;
578 RequestInfo info(request, params);
580 rv = InitiateRequest(info);
581 if (NS_WARN_IF(NS_FAILED(rv))) {
582 return rv;
585 request.forget(_retval);
586 return NS_OK;
589 NS_IMETHODIMP
590 QuotaManagerService::InitializeTemporaryOrigin(
591 const nsACString& aPersistenceType, nsIPrincipal* aPrincipal,
592 nsIQuotaRequest** _retval) {
593 MOZ_ASSERT(NS_IsMainThread());
594 MOZ_ASSERT(nsContentUtils::IsCallerChrome());
596 if (NS_WARN_IF(!StaticPrefs::dom_quotaManager_testing())) {
597 return NS_ERROR_UNEXPECTED;
600 RefPtr<Request> request = new Request();
602 InitializeTemporaryOriginParams params;
604 const auto maybePersistenceType =
605 PersistenceTypeFromString(aPersistenceType, fallible);
606 if (NS_WARN_IF(maybePersistenceType.isNothing())) {
607 return NS_ERROR_INVALID_ARG;
610 if (NS_WARN_IF(!IsBestEffortPersistenceType(maybePersistenceType.value()))) {
611 return NS_ERROR_FAILURE;
614 params.persistenceType() = maybePersistenceType.value();
616 nsresult rv =
617 CheckedPrincipalToPrincipalInfo(aPrincipal, params.principalInfo());
618 if (NS_WARN_IF(NS_FAILED(rv))) {
619 return rv;
622 RequestInfo info(request, params);
624 rv = InitiateRequest(info);
625 if (NS_WARN_IF(NS_FAILED(rv))) {
626 return rv;
629 request.forget(_retval);
630 return NS_OK;
633 NS_IMETHODIMP
634 QuotaManagerService::InitializePersistentClient(nsIPrincipal* aPrincipal,
635 const nsAString& aClientType,
636 nsIQuotaRequest** _retval) {
637 MOZ_ASSERT(NS_IsMainThread());
638 MOZ_ASSERT(aPrincipal);
639 MOZ_ASSERT(nsContentUtils::IsCallerChrome());
641 QM_TRY(MOZ_TO_RESULT(StaticPrefs::dom_quotaManager_testing()),
642 NS_ERROR_UNEXPECTED);
644 QM_TRY(MOZ_TO_RESULT(EnsureBackgroundActor()));
646 QM_TRY_INSPECT(
647 const auto& principalInfo,
648 ([&aPrincipal]() -> Result<PrincipalInfo, nsresult> {
649 PrincipalInfo principalInfo;
650 QM_TRY(MOZ_TO_RESULT(
651 PrincipalToPrincipalInfo(aPrincipal, &principalInfo)));
653 QM_TRY(MOZ_TO_RESULT(QuotaManager::IsPrincipalInfoValid(principalInfo)),
654 Err(NS_ERROR_INVALID_ARG));
656 return principalInfo;
657 }()));
659 QM_TRY_INSPECT(const auto& clientType,
660 ([&aClientType]() -> Result<Client::Type, nsresult> {
661 Client::Type clientType;
662 QM_TRY(MOZ_TO_RESULT(Client::TypeFromText(
663 aClientType, clientType, fallible)),
664 Err(NS_ERROR_INVALID_ARG));
666 return clientType;
667 }()));
669 RefPtr<Request> request = new Request();
671 mBackgroundActor->SendInitializePersistentClient(principalInfo, clientType)
672 ->Then(GetCurrentSerialEventTarget(), __func__,
673 BoolResponsePromiseResolveOrRejectCallback(request));
675 request.forget(_retval);
676 return NS_OK;
679 NS_IMETHODIMP
680 QuotaManagerService::InitializeTemporaryClient(
681 const nsACString& aPersistenceType, nsIPrincipal* aPrincipal,
682 const nsAString& aClientType, nsIQuotaRequest** _retval) {
683 MOZ_ASSERT(NS_IsMainThread());
684 MOZ_ASSERT(aPrincipal);
685 MOZ_ASSERT(nsContentUtils::IsCallerChrome());
687 QM_TRY(MOZ_TO_RESULT(StaticPrefs::dom_quotaManager_testing()),
688 NS_ERROR_UNEXPECTED);
690 QM_TRY(MOZ_TO_RESULT(EnsureBackgroundActor()));
692 QM_TRY_INSPECT(
693 const auto& persistenceType,
694 ([&aPersistenceType]() -> Result<PersistenceType, nsresult> {
695 const auto persistenceType =
696 PersistenceTypeFromString(aPersistenceType, fallible);
697 QM_TRY(MOZ_TO_RESULT(persistenceType.isSome()),
698 Err(NS_ERROR_INVALID_ARG));
700 QM_TRY(
701 MOZ_TO_RESULT(IsBestEffortPersistenceType(persistenceType.ref())),
702 Err(NS_ERROR_INVALID_ARG));
704 return persistenceType.ref();
705 }()));
707 QM_TRY_INSPECT(
708 const auto& principalInfo,
709 ([&aPrincipal]() -> Result<PrincipalInfo, nsresult> {
710 PrincipalInfo principalInfo;
711 QM_TRY(MOZ_TO_RESULT(
712 PrincipalToPrincipalInfo(aPrincipal, &principalInfo)));
714 QM_TRY(MOZ_TO_RESULT(QuotaManager::IsPrincipalInfoValid(principalInfo)),
715 Err(NS_ERROR_INVALID_ARG));
717 return principalInfo;
718 }()));
720 QM_TRY_INSPECT(const auto& clientType,
721 ([&aClientType]() -> Result<Client::Type, nsresult> {
722 Client::Type clientType;
723 QM_TRY(MOZ_TO_RESULT(Client::TypeFromText(
724 aClientType, clientType, fallible)),
725 Err(NS_ERROR_INVALID_ARG));
727 return clientType;
728 }()));
730 RefPtr<Request> request = new Request();
732 mBackgroundActor
733 ->SendInitializeTemporaryClient(persistenceType, principalInfo,
734 clientType)
735 ->Then(GetCurrentSerialEventTarget(), __func__,
736 BoolResponsePromiseResolveOrRejectCallback(request));
738 request.forget(_retval);
739 return NS_OK;
742 NS_IMETHODIMP
743 QuotaManagerService::GetFullOriginMetadata(const nsACString& aPersistenceType,
744 nsIPrincipal* aPrincipal,
745 nsIQuotaRequest** _retval) {
746 MOZ_ASSERT(NS_IsMainThread());
747 MOZ_ASSERT(nsContentUtils::IsCallerChrome());
749 QM_TRY(OkIf(StaticPrefs::dom_quotaManager_testing()), NS_ERROR_UNEXPECTED);
751 const auto maybePersistenceType =
752 PersistenceTypeFromString(aPersistenceType, fallible);
753 QM_TRY(OkIf(maybePersistenceType.isSome()), NS_ERROR_INVALID_ARG);
754 QM_TRY(OkIf(IsBestEffortPersistenceType(*maybePersistenceType)),
755 NS_ERROR_INVALID_ARG);
757 PrincipalInfo principalInfo;
758 QM_TRY(MOZ_TO_RESULT(PrincipalToPrincipalInfo(aPrincipal, &principalInfo)));
759 QM_TRY(OkIf(QuotaManager::IsPrincipalInfoValid(principalInfo)),
760 NS_ERROR_INVALID_ARG);
762 RefPtr<Request> request = new Request();
764 GetFullOriginMetadataParams params;
766 params.persistenceType() = *maybePersistenceType;
767 params.principalInfo() = std::move(principalInfo);
769 RequestInfo info(request, params);
771 QM_TRY(MOZ_TO_RESULT(InitiateRequest(info)));
773 request.forget(_retval);
774 return NS_OK;
777 NS_IMETHODIMP
778 QuotaManagerService::GetUsage(nsIQuotaUsageCallback* aCallback, bool aGetAll,
779 nsIQuotaUsageRequest** _retval) {
780 MOZ_ASSERT(NS_IsMainThread());
781 MOZ_ASSERT(aCallback);
783 RefPtr<UsageRequest> request = new UsageRequest(aCallback);
785 AllUsageParams params;
787 params.getAll() = aGetAll;
789 UsageRequestInfo info(request, params);
791 nsresult rv = InitiateRequest(info);
792 if (NS_WARN_IF(NS_FAILED(rv))) {
793 return rv;
796 request.forget(_retval);
797 return NS_OK;
800 NS_IMETHODIMP
801 QuotaManagerService::GetUsageForPrincipal(nsIPrincipal* aPrincipal,
802 nsIQuotaUsageCallback* aCallback,
803 bool aFromMemory,
804 nsIQuotaUsageRequest** _retval) {
805 MOZ_ASSERT(NS_IsMainThread());
806 MOZ_ASSERT(aPrincipal);
807 MOZ_ASSERT(aCallback);
809 RefPtr<UsageRequest> request = new UsageRequest(aPrincipal, aCallback);
811 OriginUsageParams params;
813 nsresult rv =
814 CheckedPrincipalToPrincipalInfo(aPrincipal, params.principalInfo());
815 if (NS_WARN_IF(NS_FAILED(rv))) {
816 return rv;
819 params.fromMemory() = aFromMemory;
821 UsageRequestInfo info(request, params);
823 rv = InitiateRequest(info);
824 if (NS_WARN_IF(NS_FAILED(rv))) {
825 return rv;
828 request.forget(_retval);
829 return NS_OK;
832 NS_IMETHODIMP
833 QuotaManagerService::Clear(nsIQuotaRequest** _retval) {
834 MOZ_ASSERT(NS_IsMainThread());
836 if (NS_WARN_IF(!StaticPrefs::dom_quotaManager_testing())) {
837 return NS_ERROR_UNEXPECTED;
840 QM_TRY(MOZ_TO_RESULT(EnsureBackgroundActor()));
842 RefPtr<Request> request = new Request();
844 mBackgroundActor->SendClearStorage()->Then(
845 GetCurrentSerialEventTarget(), __func__,
846 BoolResponsePromiseResolveOrRejectCallback(request));
848 request.forget(_retval);
849 return NS_OK;
852 NS_IMETHODIMP
853 QuotaManagerService::ClearStoragesForPrivateBrowsing(
854 nsIQuotaRequest** _retval) {
855 MOZ_ASSERT(NS_IsMainThread());
857 QM_TRY(MOZ_TO_RESULT(EnsureBackgroundActor()));
859 RefPtr<Request> request = new Request();
861 mBackgroundActor->SendClearStoragesForPrivateBrowsing()->Then(
862 GetCurrentSerialEventTarget(), __func__,
863 BoolResponsePromiseResolveOrRejectCallback(request));
865 request.forget(_retval);
866 return NS_OK;
869 NS_IMETHODIMP
870 QuotaManagerService::ClearStoragesForOriginAttributesPattern(
871 const nsAString& aPattern, nsIQuotaRequest** _retval) {
872 MOZ_ASSERT(NS_IsMainThread());
874 QM_TRY(MOZ_TO_RESULT(EnsureBackgroundActor()));
876 OriginAttributesPattern pattern;
877 MOZ_ALWAYS_TRUE(pattern.Init(aPattern));
879 RefPtr<Request> request = new Request();
881 mBackgroundActor->SendClearStoragesForOriginAttributesPattern(pattern)->Then(
882 GetCurrentSerialEventTarget(), __func__,
883 BoolResponsePromiseResolveOrRejectCallback(request));
885 request.forget(_retval);
886 return NS_OK;
889 NS_IMETHODIMP
890 QuotaManagerService::ClearStoragesForPrincipal(
891 nsIPrincipal* aPrincipal, const nsACString& aPersistenceType,
892 const nsAString& aClientType, nsIQuotaRequest** _retval) {
893 MOZ_ASSERT(NS_IsMainThread());
894 MOZ_ASSERT(aPrincipal);
896 QM_TRY(MOZ_TO_RESULT(EnsureBackgroundActor()));
898 QM_TRY_INSPECT(
899 const auto& persistenceType,
900 ([&aPersistenceType]() -> Result<Maybe<PersistenceType>, nsresult> {
901 if (aPersistenceType.IsVoid()) {
902 return Maybe<PersistenceType>();
905 const auto persistenceType =
906 PersistenceTypeFromString(aPersistenceType, fallible);
907 QM_TRY(MOZ_TO_RESULT(persistenceType.isSome()),
908 Err(NS_ERROR_INVALID_ARG));
910 return persistenceType;
911 }()));
913 QM_TRY_INSPECT(
914 const auto& principalInfo,
915 ([&aPrincipal]() -> Result<PrincipalInfo, nsresult> {
916 PrincipalInfo principalInfo;
917 QM_TRY(MOZ_TO_RESULT(
918 PrincipalToPrincipalInfo(aPrincipal, &principalInfo)));
920 QM_TRY(MOZ_TO_RESULT(QuotaManager::IsPrincipalInfoValid(principalInfo)),
921 Err(NS_ERROR_INVALID_ARG));
923 return principalInfo;
924 }()));
926 QM_TRY_INSPECT(const auto& clientType,
927 ([&aClientType]() -> Result<Maybe<Client::Type>, nsresult> {
928 if (aClientType.IsVoid()) {
929 return Maybe<Client::Type>();
932 Client::Type clientType;
933 QM_TRY(MOZ_TO_RESULT(Client::TypeFromText(
934 aClientType, clientType, fallible)),
935 Err(NS_ERROR_INVALID_ARG));
937 return Some(clientType);
938 }()));
940 RefPtr<Request> request = new Request();
942 mBackgroundActor
943 ->SendClearStoragesForOrigin(persistenceType, principalInfo, clientType)
944 ->Then(GetCurrentSerialEventTarget(), __func__,
945 BoolResponsePromiseResolveOrRejectCallback(request));
947 request.forget(_retval);
948 return NS_OK;
951 NS_IMETHODIMP
952 QuotaManagerService::ClearStoragesForOriginPrefix(
953 nsIPrincipal* aPrincipal, const nsACString& aPersistenceType,
954 nsIQuotaRequest** _retval) {
955 MOZ_ASSERT(NS_IsMainThread());
956 MOZ_ASSERT(aPrincipal);
958 QM_TRY(MOZ_TO_RESULT(EnsureBackgroundActor()));
960 QM_TRY_INSPECT(
961 const auto& persistenceType,
962 ([&aPersistenceType]() -> Result<Maybe<PersistenceType>, nsresult> {
963 if (aPersistenceType.IsVoid()) {
964 return Maybe<PersistenceType>();
967 const auto persistenceType =
968 PersistenceTypeFromString(aPersistenceType, fallible);
969 QM_TRY(MOZ_TO_RESULT(persistenceType.isSome()),
970 Err(NS_ERROR_INVALID_ARG));
972 return persistenceType;
973 }()));
975 QM_TRY_INSPECT(
976 const auto& principalInfo,
977 ([&aPrincipal]() -> Result<PrincipalInfo, nsresult> {
978 PrincipalInfo principalInfo;
979 QM_TRY(MOZ_TO_RESULT(
980 PrincipalToPrincipalInfo(aPrincipal, &principalInfo)));
982 QM_TRY(MOZ_TO_RESULT(QuotaManager::IsPrincipalInfoValid(principalInfo)),
983 Err(NS_ERROR_INVALID_ARG));
985 if (principalInfo.type() == PrincipalInfo::TContentPrincipalInfo) {
986 nsCString suffix;
987 principalInfo.get_ContentPrincipalInfo().attrs().CreateSuffix(suffix);
989 QM_TRY(MOZ_TO_RESULT(suffix.IsEmpty()), Err(NS_ERROR_INVALID_ARG));
992 return principalInfo;
993 }()));
995 RefPtr<Request> request = new Request();
997 mBackgroundActor
998 ->SendClearStoragesForOriginPrefix(persistenceType, principalInfo)
999 ->Then(GetCurrentSerialEventTarget(), __func__,
1000 BoolResponsePromiseResolveOrRejectCallback(request));
1002 request.forget(_retval);
1003 return NS_OK;
1006 NS_IMETHODIMP
1007 QuotaManagerService::Reset(nsIQuotaRequest** _retval) {
1008 MOZ_ASSERT(NS_IsMainThread());
1010 if (NS_WARN_IF(!StaticPrefs::dom_quotaManager_testing())) {
1011 return NS_ERROR_UNEXPECTED;
1014 QM_TRY(MOZ_TO_RESULT(EnsureBackgroundActor()));
1016 RefPtr<Request> request = new Request();
1018 mBackgroundActor->SendShutdownStorage()->Then(
1019 GetCurrentSerialEventTarget(), __func__,
1020 BoolResponsePromiseResolveOrRejectCallback(request));
1022 request.forget(_retval);
1023 return NS_OK;
1026 NS_IMETHODIMP
1027 QuotaManagerService::ResetStoragesForPrincipal(
1028 nsIPrincipal* aPrincipal, const nsACString& aPersistenceType,
1029 const nsAString& aClientType, nsIQuotaRequest** _retval) {
1030 MOZ_ASSERT(NS_IsMainThread());
1031 MOZ_ASSERT(aPrincipal);
1033 if (NS_WARN_IF(!StaticPrefs::dom_quotaManager_testing())) {
1034 return NS_ERROR_UNEXPECTED;
1037 RefPtr<Request> request = new Request(aPrincipal);
1039 ClearResetOriginParams commonParams;
1041 nsresult rv = GetClearResetOriginParams(aPrincipal, aPersistenceType,
1042 aClientType, commonParams);
1043 if (NS_WARN_IF(NS_FAILED(rv))) {
1044 return rv;
1047 RequestParams params;
1048 params = ResetOriginParams(commonParams);
1050 RequestInfo info(request, params);
1052 rv = InitiateRequest(info);
1053 if (NS_WARN_IF(NS_FAILED(rv))) {
1054 return rv;
1057 request.forget(_retval);
1058 return NS_OK;
1061 NS_IMETHODIMP
1062 QuotaManagerService::Persisted(nsIPrincipal* aPrincipal,
1063 nsIQuotaRequest** _retval) {
1064 MOZ_ASSERT(NS_IsMainThread());
1065 MOZ_ASSERT(aPrincipal);
1066 MOZ_ASSERT(_retval);
1068 RefPtr<Request> request = new Request(aPrincipal);
1070 PersistedParams params;
1072 nsresult rv =
1073 CheckedPrincipalToPrincipalInfo(aPrincipal, params.principalInfo());
1074 if (NS_WARN_IF(NS_FAILED(rv))) {
1075 return rv;
1078 RequestInfo info(request, params);
1080 rv = InitiateRequest(info);
1081 if (NS_WARN_IF(NS_FAILED(rv))) {
1082 return rv;
1085 request.forget(_retval);
1086 return NS_OK;
1089 NS_IMETHODIMP
1090 QuotaManagerService::Persist(nsIPrincipal* aPrincipal,
1091 nsIQuotaRequest** _retval) {
1092 MOZ_ASSERT(NS_IsMainThread());
1093 MOZ_ASSERT(aPrincipal);
1094 MOZ_ASSERT(_retval);
1096 RefPtr<Request> request = new Request(aPrincipal);
1098 PersistParams params;
1100 nsresult rv =
1101 CheckedPrincipalToPrincipalInfo(aPrincipal, params.principalInfo());
1102 if (NS_WARN_IF(NS_FAILED(rv))) {
1103 return rv;
1106 RequestInfo info(request, params);
1108 rv = InitiateRequest(info);
1109 if (NS_WARN_IF(NS_FAILED(rv))) {
1110 return rv;
1113 request.forget(_retval);
1114 return NS_OK;
1117 NS_IMETHODIMP
1118 QuotaManagerService::Estimate(nsIPrincipal* aPrincipal,
1119 nsIQuotaRequest** _retval) {
1120 MOZ_ASSERT(NS_IsMainThread());
1121 MOZ_ASSERT(aPrincipal);
1123 RefPtr<Request> request = new Request(aPrincipal);
1125 EstimateParams params;
1127 nsresult rv =
1128 CheckedPrincipalToPrincipalInfo(aPrincipal, params.principalInfo());
1129 if (NS_WARN_IF(NS_FAILED(rv))) {
1130 return rv;
1133 RequestInfo info(request, params);
1135 rv = InitiateRequest(info);
1136 if (NS_WARN_IF(NS_FAILED(rv))) {
1137 return rv;
1140 request.forget(_retval);
1141 return NS_OK;
1144 NS_IMETHODIMP
1145 QuotaManagerService::ListOrigins(nsIQuotaRequest** _retval) {
1146 MOZ_ASSERT(NS_IsMainThread());
1148 RefPtr<Request> request = new Request();
1150 ListOriginsParams params;
1152 RequestInfo info(request, params);
1154 nsresult rv = InitiateRequest(info);
1155 if (NS_WARN_IF(NS_FAILED(rv))) {
1156 return rv;
1159 request.forget(_retval);
1160 return NS_OK;
1163 NS_IMETHODIMP
1164 QuotaManagerService::Observe(nsISupports* aSubject, const char* aTopic,
1165 const char16_t* aData) {
1166 MOZ_ASSERT(XRE_IsParentProcess());
1167 MOZ_ASSERT(NS_IsMainThread());
1169 if (!strcmp(aTopic, PROFILE_BEFORE_CHANGE_QM_OBSERVER_ID)) {
1170 RemoveIdleObserver();
1171 return NS_OK;
1174 if (!strcmp(aTopic, OBSERVER_TOPIC_IDLE_DAILY)) {
1175 PerformIdleMaintenance();
1176 return NS_OK;
1179 if (!strcmp(aTopic, OBSERVER_TOPIC_IDLE)) {
1180 IdleMaintenanceInfo info(/* aStart */ true);
1182 nsresult rv = InitiateRequest(info);
1183 if (NS_WARN_IF(NS_FAILED(rv))) {
1184 return rv;
1187 return NS_OK;
1190 if (!strcmp(aTopic, OBSERVER_TOPIC_ACTIVE)) {
1191 RemoveIdleObserver();
1193 IdleMaintenanceInfo info(/* aStart */ false);
1195 nsresult rv = InitiateRequest(info);
1196 if (NS_WARN_IF(NS_FAILED(rv))) {
1197 return rv;
1200 return NS_OK;
1203 MOZ_ASSERT_UNREACHABLE("Should never get here!");
1204 return NS_OK;
1207 void QuotaManagerService::Notify(const hal::BatteryInformation& aBatteryInfo) {
1208 // This notification is received when battery data changes. We don't need to
1209 // deal with this notification.
1212 nsresult QuotaManagerService::UsageRequestInfo::InitiateRequest(
1213 QuotaChild* aActor) {
1214 MOZ_ASSERT(aActor);
1216 auto request = static_cast<UsageRequest*>(mRequest.get());
1218 auto actor = new QuotaUsageRequestChild(request);
1220 if (!aActor->SendPQuotaUsageRequestConstructor(actor, mParams)) {
1221 request->SetError(NS_ERROR_FAILURE);
1222 return NS_ERROR_FAILURE;
1225 request->SetBackgroundActor(actor);
1227 return NS_OK;
1230 nsresult QuotaManagerService::RequestInfo::InitiateRequest(QuotaChild* aActor) {
1231 MOZ_ASSERT(aActor);
1233 auto request = static_cast<Request*>(mRequest.get());
1235 auto actor = new QuotaRequestChild(request);
1237 if (!aActor->SendPQuotaRequestConstructor(actor, mParams)) {
1238 request->SetError(NS_ERROR_FAILURE);
1239 return NS_ERROR_FAILURE;
1242 return NS_OK;
1245 nsresult QuotaManagerService::IdleMaintenanceInfo::InitiateRequest(
1246 QuotaChild* aActor) {
1247 MOZ_ASSERT(aActor);
1249 bool result;
1251 if (mStart) {
1252 result = aActor->SendStartIdleMaintenance();
1253 } else {
1254 result = aActor->SendStopIdleMaintenance();
1257 if (!result) {
1258 return NS_ERROR_FAILURE;
1261 return NS_OK;
1264 } // namespace mozilla::dom::quota