ClientHandle.cpp (6115B)
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 "ClientHandle.h" 8 9 #include "ClientHandleChild.h" 10 #include "ClientHandleOpChild.h" 11 #include "ClientManager.h" 12 #include "ClientPrincipalUtils.h" 13 #include "ClientState.h" 14 #include "mozilla/dom/PClientManagerChild.h" 15 #include "mozilla/dom/ServiceWorkerDescriptor.h" 16 #include "mozilla/dom/ipc/StructuredCloneData.h" 17 18 namespace mozilla::dom { 19 20 using mozilla::dom::ipc::StructuredCloneData; 21 22 ClientHandle::~ClientHandle() { Shutdown(); } 23 24 void ClientHandle::Shutdown() { 25 NS_ASSERT_OWNINGTHREAD(ClientSource); 26 if (IsShutdown()) { 27 return; 28 } 29 30 ShutdownThing(); 31 32 mManager = nullptr; 33 } 34 35 void ClientHandle::StartOp(const ClientOpConstructorArgs& aArgs, 36 const ClientOpCallback&& aResolveCallback, 37 const ClientOpCallback&& aRejectCallback) { 38 // Hold a ref to the client until the remote operation completes. Otherwise 39 // the ClientHandle might get de-refed and teardown the actor before we 40 // get an answer. 41 RefPtr<ClientHandle> kungFuGrip = this; 42 43 MaybeExecute( 44 [&aArgs, kungFuGrip, aRejectCallback, 45 resolve = std::move(aResolveCallback)](ClientHandleChild* aActor) { 46 MOZ_DIAGNOSTIC_ASSERT(aActor); 47 ClientHandleOpChild* actor = new ClientHandleOpChild( 48 kungFuGrip, aArgs, std::move(resolve), std::move(aRejectCallback)); 49 if (!aActor->SendPClientHandleOpConstructor(actor, aArgs)) { 50 // Constructor failure will call reject callback via ActorDestroy() 51 return; 52 } 53 }, 54 [aRejectCallback] { 55 MOZ_DIAGNOSTIC_ASSERT(aRejectCallback); 56 CopyableErrorResult rv; 57 rv.ThrowInvalidStateError("Client has been destroyed"); 58 aRejectCallback(rv); 59 }); 60 } 61 62 void ClientHandle::OnShutdownThing() { 63 NS_ASSERT_OWNINGTHREAD(ClientHandle); 64 if (!mDetachPromise) { 65 return; 66 } 67 mDetachPromise->Resolve(true, __func__); 68 } 69 70 ClientHandle::ClientHandle(ClientManager* aManager, 71 nsISerialEventTarget* aSerialEventTarget, 72 const ClientInfo& aClientInfo) 73 : mManager(aManager), 74 mSerialEventTarget(aSerialEventTarget), 75 mClientInfo(aClientInfo) { 76 MOZ_DIAGNOSTIC_ASSERT(mManager); 77 MOZ_DIAGNOSTIC_ASSERT(mSerialEventTarget); 78 MOZ_ASSERT(mSerialEventTarget->IsOnCurrentThread()); 79 } 80 81 void ClientHandle::Activate(PClientManagerChild* aActor) { 82 NS_ASSERT_OWNINGTHREAD(ClientHandle); 83 84 if (IsShutdown()) { 85 return; 86 } 87 88 RefPtr<ClientHandleChild> actor = new ClientHandleChild(); 89 if (!aActor->SendPClientHandleConstructor(actor, mClientInfo.ToIPC())) { 90 Shutdown(); 91 return; 92 } 93 94 ActivateThing(actor); 95 } 96 97 void ClientHandle::ExecutionReady(const ClientInfo& aClientInfo) { 98 mClientInfo = aClientInfo; 99 } 100 101 const ClientInfo& ClientHandle::Info() const { return mClientInfo; } 102 103 RefPtr<GenericErrorResultPromise> ClientHandle::Control( 104 const ServiceWorkerDescriptor& aServiceWorker) { 105 RefPtr<GenericErrorResultPromise::Private> outerPromise = 106 new GenericErrorResultPromise::Private(__func__); 107 108 // We should never have a cross-origin controller. Since this would be 109 // same-origin policy violation we do a full release assertion here. 110 MOZ_RELEASE_ASSERT(ClientMatchPrincipalInfo(mClientInfo.PrincipalInfo(), 111 aServiceWorker.PrincipalInfo())); 112 113 StartOp( 114 ClientControlledArgs(aServiceWorker.ToIPC()), 115 [outerPromise](const ClientOpResult& aResult) { 116 outerPromise->Resolve(true, __func__); 117 }, 118 [outerPromise](const ClientOpResult& aResult) { 119 outerPromise->Reject(aResult.get_CopyableErrorResult(), __func__); 120 }); 121 122 return outerPromise; 123 } 124 125 RefPtr<ClientStatePromise> ClientHandle::Focus(CallerType aCallerType) { 126 RefPtr<ClientStatePromise::Private> outerPromise = 127 new ClientStatePromise::Private(__func__); 128 129 StartOp( 130 ClientFocusArgs(aCallerType), 131 [outerPromise](const ClientOpResult& aResult) { 132 outerPromise->Resolve( 133 ClientState::FromIPC(aResult.get_IPCClientState()), __func__); 134 }, 135 [outerPromise](const ClientOpResult& aResult) { 136 outerPromise->Reject(aResult.get_CopyableErrorResult(), __func__); 137 }); 138 139 return outerPromise; 140 } 141 142 RefPtr<GenericErrorResultPromise> ClientHandle::PostMessage( 143 StructuredCloneData& aData, const ServiceWorkerDescriptor& aSource) { 144 if (IsShutdown()) { 145 CopyableErrorResult rv; 146 rv.ThrowInvalidStateError("Client has been destroyed"); 147 return GenericErrorResultPromise::CreateAndReject(rv, __func__); 148 } 149 150 ClientPostMessageArgs args; 151 args.serviceWorker() = aSource.ToIPC(); 152 153 if (!aData.BuildClonedMessageData(args.clonedData())) { 154 CopyableErrorResult rv; 155 rv.ThrowInvalidStateError("Failed to clone data"); 156 return GenericErrorResultPromise::CreateAndReject(rv, __func__); 157 } 158 159 RefPtr<GenericErrorResultPromise::Private> outerPromise = 160 new GenericErrorResultPromise::Private(__func__); 161 162 StartOp( 163 std::move(args), 164 [outerPromise](const ClientOpResult& aResult) { 165 outerPromise->Resolve(true, __func__); 166 }, 167 [outerPromise](const ClientOpResult& aResult) { 168 outerPromise->Reject(aResult.get_CopyableErrorResult(), __func__); 169 }); 170 171 return outerPromise; 172 } 173 174 RefPtr<GenericPromise> ClientHandle::OnDetach() { 175 NS_ASSERT_OWNINGTHREAD(ClientSource); 176 177 if (!mDetachPromise) { 178 mDetachPromise = new GenericPromise::Private(__func__); 179 if (IsShutdown()) { 180 mDetachPromise->Resolve(true, __func__); 181 } 182 } 183 184 return mDetachPromise; 185 } 186 187 void ClientHandle::EvictFromBFCache() { 188 ClientEvictBFCacheArgs args; 189 StartOp( 190 std::move(args), [](const ClientOpResult& aResult) {}, 191 [](const ClientOpResult& aResult) {}); 192 } 193 194 } // namespace mozilla::dom