no bug - Bumping Firefox l10n changesets r=release a=l10n-bump DONTBUILD CLOSED TREE
[gecko.git] / dom / clients / manager / ClientSourceParent.cpp
blobe2c02c0bfd5777354a92f3e9f0070bcfad081b09
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/. */
7 #include "ClientSourceParent.h"
9 #include "ClientHandleParent.h"
10 #include "ClientManagerService.h"
11 #include "ClientSourceOpParent.h"
12 #include "ClientValidation.h"
13 #include "mozilla/dom/ClientIPCTypes.h"
14 #include "mozilla/dom/ContentParent.h"
15 #include "mozilla/dom/PClientManagerParent.h"
16 #include "mozilla/dom/ServiceWorkerManager.h"
17 #include "mozilla/dom/ServiceWorkerUtils.h"
18 #include "mozilla/ipc/BackgroundParent.h"
19 #include "mozilla/SchedulerGroup.h"
20 #include "mozilla/Unused.h"
22 namespace mozilla::dom {
24 using mozilla::ipc::AssertIsOnBackgroundThread;
25 using mozilla::ipc::BackgroundParent;
26 using mozilla::ipc::IPCResult;
27 using mozilla::ipc::PrincipalInfo;
29 mozilla::ipc::IPCResult ClientSourceParent::RecvWorkerSyncPing() {
30 AssertIsOnBackgroundThread();
31 // Do nothing here. This is purely a sync message allowing the child to
32 // confirm that the actor has been created on the parent process.
33 return IPC_OK();
36 IPCResult ClientSourceParent::RecvTeardown() {
37 Unused << Send__delete__(this);
38 return IPC_OK();
41 IPCResult ClientSourceParent::RecvExecutionReady(
42 const ClientSourceExecutionReadyArgs& aArgs) {
43 // Now that we have the creation URL for the Client we can do some validation
44 // to make sure the child actor is not giving us garbage. Since we validate
45 // on the child side as well we treat a failure here as fatal.
46 if (!ClientIsValidCreationURL(mClientInfo.PrincipalInfo(), aArgs.url())) {
47 return IPC_FAIL(this, "Invalid creation URL!");
50 mClientInfo.SetURL(aArgs.url());
51 mClientInfo.SetFrameType(aArgs.frameType());
52 mExecutionReady = true;
54 for (ClientHandleParent* handle : mHandleList) {
55 Unused << handle->SendExecutionReady(mClientInfo.ToIPC());
58 mExecutionReadyPromise.ResolveIfExists(true, __func__);
60 return IPC_OK();
63 IPCResult ClientSourceParent::RecvFreeze() {
64 #ifdef FUZZING_SNAPSHOT
65 if (mFrozen) {
66 return IPC_FAIL(this, "Freezing when already frozen");
68 #endif
69 MOZ_DIAGNOSTIC_ASSERT(!mFrozen);
70 mFrozen = true;
72 return IPC_OK();
75 IPCResult ClientSourceParent::RecvThaw() {
76 #ifdef FUZZING_SNAPSHOT
77 if (!mFrozen) {
78 return IPC_FAIL(this, "Thawing when not already frozen");
80 #endif
81 MOZ_DIAGNOSTIC_ASSERT(mFrozen);
82 mFrozen = false;
83 return IPC_OK();
86 IPCResult ClientSourceParent::RecvInheritController(
87 const ClientControlledArgs& aArgs) {
88 mController.reset();
89 mController.emplace(aArgs.serviceWorker());
91 // We must tell the parent-side SWM about this controller inheritance.
92 nsCOMPtr<nsIRunnable> r = NS_NewRunnableFunction(
93 "ClientSourceParent::RecvInheritController",
94 [clientInfo = mClientInfo, controller = mController.ref()]() {
95 RefPtr<ServiceWorkerManager> swm = ServiceWorkerManager::GetInstance();
96 NS_ENSURE_TRUE_VOID(swm);
98 swm->NoteInheritedController(clientInfo, controller);
99 });
101 MOZ_ALWAYS_SUCCEEDS(SchedulerGroup::Dispatch(r.forget()));
103 return IPC_OK();
106 IPCResult ClientSourceParent::RecvNoteDOMContentLoaded() {
107 if (mController.isSome()) {
108 nsCOMPtr<nsIRunnable> r =
109 NS_NewRunnableFunction("ClientSourceParent::RecvNoteDOMContentLoaded",
110 [clientInfo = mClientInfo]() {
111 RefPtr<ServiceWorkerManager> swm =
112 ServiceWorkerManager::GetInstance();
113 NS_ENSURE_TRUE_VOID(swm);
115 swm->MaybeCheckNavigationUpdate(clientInfo);
118 MOZ_ALWAYS_SUCCEEDS(SchedulerGroup::Dispatch(r.forget()));
120 return IPC_OK();
123 void ClientSourceParent::ActorDestroy(ActorDestroyReason aReason) {
124 DebugOnly<bool> removed = mService->RemoveSource(this);
125 MOZ_ASSERT(removed);
127 for (ClientHandleParent* handle : mHandleList.Clone()) {
128 // This should trigger DetachHandle() to be called removing
129 // the entry from the mHandleList.
130 Unused << ClientHandleParent::Send__delete__(handle);
132 MOZ_DIAGNOSTIC_ASSERT(mHandleList.IsEmpty());
135 PClientSourceOpParent* ClientSourceParent::AllocPClientSourceOpParent(
136 const ClientOpConstructorArgs& aArgs) {
137 MOZ_ASSERT_UNREACHABLE(
138 "ClientSourceOpParent should be explicitly constructed.");
139 return nullptr;
142 bool ClientSourceParent::DeallocPClientSourceOpParent(
143 PClientSourceOpParent* aActor) {
144 delete aActor;
145 return true;
148 ClientSourceParent::ClientSourceParent(
149 const ClientSourceConstructorArgs& aArgs,
150 const Maybe<ContentParentId>& aContentParentId)
151 : mClientInfo(aArgs.id(), aArgs.type(), aArgs.principalInfo(),
152 aArgs.creationTime()),
153 mContentParentId(aContentParentId),
154 mService(ClientManagerService::GetOrCreateInstance()),
155 mExecutionReady(false),
156 mFrozen(false) {}
158 ClientSourceParent::~ClientSourceParent() {
159 MOZ_DIAGNOSTIC_ASSERT(mHandleList.IsEmpty());
161 mExecutionReadyPromise.RejectIfExists(NS_ERROR_FAILURE, __func__);
164 IPCResult ClientSourceParent::Init() {
165 // Ensure the principal is reasonable before adding ourself to the service.
166 // Since we validate the principal on the child side as well, any failure
167 // here is treated as fatal.
168 if (NS_WARN_IF(!ClientIsValidPrincipalInfo(mClientInfo.PrincipalInfo()))) {
169 mService->ForgetFutureSource(mClientInfo.ToIPC());
170 return IPC_FAIL(Manager(), "Invalid PrincipalInfo!");
173 // Its possible for AddSource() to fail if there is already an entry for
174 // our UUID. This should not normally happen, but could if someone is
175 // spoofing IPC messages.
176 if (NS_WARN_IF(!mService->AddSource(this))) {
177 return IPC_FAIL(Manager(), "Already registered!");
180 return IPC_OK();
183 const ClientInfo& ClientSourceParent::Info() const { return mClientInfo; }
185 bool ClientSourceParent::IsFrozen() const { return mFrozen; }
187 bool ClientSourceParent::ExecutionReady() const { return mExecutionReady; }
189 RefPtr<GenericNonExclusivePromise> ClientSourceParent::ExecutionReadyPromise() {
190 // Only call if ClientSourceParent::ExecutionReady() is false; otherwise,
191 // the promise will never resolve
192 MOZ_ASSERT(!mExecutionReady);
193 return mExecutionReadyPromise.Ensure(__func__);
196 const Maybe<ServiceWorkerDescriptor>& ClientSourceParent::GetController()
197 const {
198 return mController;
201 void ClientSourceParent::ClearController() { mController.reset(); }
203 void ClientSourceParent::AttachHandle(ClientHandleParent* aClientHandle) {
204 MOZ_DIAGNOSTIC_ASSERT(aClientHandle);
205 MOZ_ASSERT(!mHandleList.Contains(aClientHandle));
206 mHandleList.AppendElement(aClientHandle);
209 void ClientSourceParent::DetachHandle(ClientHandleParent* aClientHandle) {
210 MOZ_DIAGNOSTIC_ASSERT(aClientHandle);
211 MOZ_ASSERT(mHandleList.Contains(aClientHandle));
212 mHandleList.RemoveElement(aClientHandle);
215 RefPtr<ClientOpPromise> ClientSourceParent::StartOp(
216 ClientOpConstructorArgs&& aArgs) {
217 RefPtr<ClientOpPromise::Private> promise =
218 new ClientOpPromise::Private(__func__);
220 // If we are being controlled, remember that data before propagating
221 // on to the ClientSource. This must be set prior to triggering
222 // the controllerchange event from the ClientSource since some tests
223 // expect matchAll() to find the controlled client immediately after.
224 // If the control operation fails, then we reset the controller value
225 // to reflect the final state.
226 if (aArgs.type() == ClientOpConstructorArgs::TClientControlledArgs) {
227 mController.reset();
228 mController.emplace(aArgs.get_ClientControlledArgs().serviceWorker());
231 // Constructor failure will reject the promise via ActorDestroy().
232 ClientSourceOpParent* actor =
233 new ClientSourceOpParent(std::move(aArgs), promise);
234 Unused << SendPClientSourceOpConstructor(actor, actor->Args());
236 return promise;
239 } // namespace mozilla::dom