FileSystemManagerParentFactory.cpp (8021B)
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 5 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ 6 7 #include "FileSystemManagerParentFactory.h" 8 9 #include "mozilla/OriginAttributes.h" 10 #include "mozilla/StaticPrefs_dom.h" 11 #include "mozilla/dom/FileSystemDataManager.h" 12 #include "mozilla/dom/FileSystemLog.h" 13 #include "mozilla/dom/FileSystemManagerParent.h" 14 #include "mozilla/dom/FileSystemTypes.h" 15 #include "mozilla/dom/quota/PrincipalUtils.h" 16 #include "mozilla/dom/quota/QuotaCommon.h" 17 #include "mozilla/dom/quota/QuotaManager.h" 18 #include "mozilla/dom/quota/ResultExtensions.h" 19 #include "mozilla/ipc/Endpoint.h" 20 #include "mozilla/ipc/PBackgroundParent.h" 21 #include "nsIScriptObjectPrincipal.h" 22 #include "nsString.h" 23 24 namespace mozilla::dom { 25 mozilla::ipc::IPCResult CreateFileSystemManagerParent( 26 RefPtr<mozilla::ipc::PBackgroundParent> aBackgroundActor, 27 const mozilla::ipc::PrincipalInfo& aPrincipalInfo, 28 mozilla::ipc::Endpoint<PFileSystemManagerParent>&& aParentEndpoint, 29 std::function<void(const nsresult&)>&& aResolver) { 30 using CreateActorPromise = 31 MozPromise<RefPtr<FileSystemManagerParent>, nsresult, true>; 32 33 QM_TRY(OkIf(StaticPrefs::dom_fs_enabled()), IPC_OK(), 34 [aResolver](const auto&) { aResolver(NS_ERROR_DOM_NOT_ALLOWED_ERR); }); 35 36 QM_TRY(OkIf(aParentEndpoint.IsValid()), IPC_OK(), 37 [aResolver](const auto&) { aResolver(NS_ERROR_INVALID_ARG); }); 38 39 // This blocks Null and Expanded principals 40 QM_TRY(OkIf(quota::IsPrincipalInfoValid(aPrincipalInfo)), IPC_OK(), 41 [aResolver](const auto&) { aResolver(NS_ERROR_DOM_SECURITY_ERR); }); 42 43 QM_TRY(quota::QuotaManager::EnsureCreated(), IPC_OK(), 44 [aResolver](const auto rv) { aResolver(rv); }); 45 46 auto* const quotaManager = quota::QuotaManager::Get(); 47 MOZ_ASSERT(quotaManager); 48 49 QM_TRY_UNWRAP( 50 auto principalMetadata, 51 quota::GetInfoFromValidatedPrincipalInfo(*quotaManager, aPrincipalInfo), 52 IPC_OK(), [aResolver](const auto rv) { aResolver(rv); }); 53 54 quota::OriginMetadata originMetadata(std::move(principalMetadata), 55 quota::PERSISTENCE_TYPE_DEFAULT); 56 57 // Block use for now in PrivateBrowsing 58 QM_TRY(OkIf(!OriginAttributes::IsPrivateBrowsing(originMetadata.mOrigin)), 59 IPC_OK(), 60 [aResolver](const auto&) { aResolver(NS_ERROR_DOM_NOT_ALLOWED_ERR); }); 61 62 LOG(("CreateFileSystemManagerParent, origin: %s", 63 originMetadata.mOrigin.get())); 64 65 RefPtr<mozilla::ipc::PBackgroundParent> backgroundActor = 66 std::move(aBackgroundActor); 67 68 // This creates the file system data manager, which has to be done on 69 // PBackground 70 fs::data::FileSystemDataManager::GetOrCreateFileSystemDataManager( 71 originMetadata) 72 ->Then( 73 GetCurrentSerialEventTarget(), __func__, 74 [origin = originMetadata.mOrigin, 75 parentEndpoint = std::move(aParentEndpoint), backgroundActor, 76 aResolver](const fs::Registered<fs::data::FileSystemDataManager>& 77 dataManager) mutable { 78 QM_TRY_UNWRAP(fs::EntryId rootId, fs::data::GetRootHandle(origin), 79 QM_VOID, 80 ([backgroundActor, aResolver](const auto& aRv) { 81 if (!backgroundActor->CanSend()) { 82 return; 83 } 84 85 aResolver(ToNSResult(aRv)); 86 })); 87 88 InvokeAsync( 89 dataManager->MutableIOTaskQueuePtr(), __func__, 90 [dataManager = dataManager, rootId, 91 parentEndpoint = std::move(parentEndpoint)]() mutable { 92 RefPtr<FileSystemManagerParent> parent = 93 new FileSystemManagerParent(dataManager.inspect(), 94 rootId); 95 96 auto autoProxyDestroyFileSystemDataManagerHandle = 97 MakeScopeExit([&dataManager] { 98 nsCOMPtr<nsISerialEventTarget> target = 99 dataManager->MutableBackgroundTargetPtr(); 100 101 MOZ_ALWAYS_SUCCEEDS(target->Dispatch( 102 NS_NewRunnableFunction( 103 "DestroyFileSystemDataManagerHandle", 104 [dataManager = std::move(dataManager)]() {}), 105 NS_DISPATCH_NORMAL)); 106 }); 107 108 LOG(("Binding parent endpoint")); 109 if (!parentEndpoint.Bind(parent)) { 110 return CreateActorPromise::CreateAndReject(NS_ERROR_FAILURE, 111 __func__); 112 } 113 114 return CreateActorPromise::CreateAndResolve(std::move(parent), 115 __func__); 116 }) 117 ->Then(GetCurrentSerialEventTarget(), __func__, 118 [dataManager = dataManager]( 119 CreateActorPromise::ResolveOrRejectValue&& aValue) { 120 if (aValue.IsReject()) { 121 return BoolPromise::CreateAndReject( 122 aValue.RejectValue(), __func__); 123 } 124 125 RefPtr<FileSystemManagerParent> parent = 126 std::move(aValue.ResolveValue()); 127 128 if (!parent->IsAlive()) { 129 return BoolPromise::CreateAndReject(NS_ERROR_ABORT, 130 __func__); 131 } 132 133 dataManager->RegisterActor(WrapNotNull(parent)); 134 135 return BoolPromise::CreateAndResolve(true, __func__); 136 }) 137 ->Then(dataManager->MutableIOTaskQueuePtr(), __func__, 138 [](const BoolPromise::ResolveOrRejectValue& aValue) { 139 // Hopping to the I/O task queue is needed to avoid 140 // a potential race triggered by 141 // FileSystemManagerParent::SendCloseAll called by 142 // FileSystemManagerParent::RequestAllowToClose called 143 // by FileSystemDataManager::RegisterActor when the 144 // directory lock has been invalidated in the 145 // meantime. The race would cause that the child side 146 // could sometimes use the child actor for sending 147 // messages and sometimes not. This extra hop 148 // guarantees that the created child actor will always 149 // refuse to send messages. 150 return BoolPromise::CreateAndResolveOrReject(aValue, 151 __func__); 152 }) 153 ->Then(GetCurrentSerialEventTarget(), __func__, 154 [backgroundActor, aResolver]( 155 const BoolPromise::ResolveOrRejectValue& aValue) { 156 if (!backgroundActor->CanSend()) { 157 return; 158 } 159 160 if (aValue.IsReject()) { 161 aResolver(aValue.RejectValue()); 162 } else { 163 aResolver(NS_OK); 164 } 165 }); 166 }, 167 [backgroundActor, aResolver](nsresult aRejectValue) { 168 if (!backgroundActor->CanSend()) { 169 return; 170 } 171 172 aResolver(aRejectValue); 173 }); 174 175 return IPC_OK(); 176 } 177 178 } // namespace mozilla::dom