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 "SharedWorkerManager.h"
8 #include "SharedWorkerParent.h"
9 #include "SharedWorkerService.h"
10 #include "mozilla/dom/PSharedWorker.h"
11 #include "mozilla/ipc/BackgroundParent.h"
12 #include "mozilla/ipc/URIUtils.h"
13 #include "mozilla/dom/RemoteWorkerController.h"
14 #include "nsIConsoleReportCollector.h"
15 #include "nsIPrincipal.h"
16 #include "nsProxyRelease.h"
17
18 namespace mozilla {
19 namespace dom {
20
21 // static
Create(SharedWorkerService * aService,nsIEventTarget * aPBackgroundEventTarget,const RemoteWorkerData & aData,nsIPrincipal * aLoadingPrincipal,const OriginAttributes & aStoragePrincipalAttrs)22 already_AddRefed<SharedWorkerManagerHolder> SharedWorkerManager::Create(
23 SharedWorkerService* aService, nsIEventTarget* aPBackgroundEventTarget,
24 const RemoteWorkerData& aData, nsIPrincipal* aLoadingPrincipal,
25 const OriginAttributes& aStoragePrincipalAttrs) {
26 MOZ_ASSERT(NS_IsMainThread());
27
28 RefPtr<SharedWorkerManager> manager =
29 new SharedWorkerManager(aPBackgroundEventTarget, aData, aLoadingPrincipal,
30 aStoragePrincipalAttrs);
31
32 RefPtr<SharedWorkerManagerHolder> holder =
33 new SharedWorkerManagerHolder(manager, aService);
34 return holder.forget();
35 }
36
SharedWorkerManager(nsIEventTarget * aPBackgroundEventTarget,const RemoteWorkerData & aData,nsIPrincipal * aLoadingPrincipal,const OriginAttributes & aStoragePrincipalAttrs)37 SharedWorkerManager::SharedWorkerManager(
38 nsIEventTarget* aPBackgroundEventTarget, const RemoteWorkerData& aData,
39 nsIPrincipal* aLoadingPrincipal,
40 const OriginAttributes& aStoragePrincipalAttrs)
41 : mPBackgroundEventTarget(aPBackgroundEventTarget),
42 mLoadingPrincipal(aLoadingPrincipal),
43 mDomain(aData.domain()),
44 mStoragePrincipalAttrs(aStoragePrincipalAttrs),
45 mResolvedScriptURL(DeserializeURI(aData.resolvedScriptURL())),
46 mName(aData.name()),
47 mIsSecureContext(aData.isSecureContext()),
48 mSuspended(false),
49 mFrozen(false) {
50 MOZ_ASSERT(NS_IsMainThread());
51 MOZ_ASSERT(aLoadingPrincipal);
52 }
53
~SharedWorkerManager()54 SharedWorkerManager::~SharedWorkerManager() {
55 NS_ReleaseOnMainThread("SharedWorkerManager::mLoadingPrincipal",
56 mLoadingPrincipal.forget());
57 NS_ProxyRelease("SharedWorkerManager::mRemoteWorkerController",
58 mPBackgroundEventTarget, mRemoteWorkerController.forget());
59 }
60
MaybeCreateRemoteWorker(const RemoteWorkerData & aData,uint64_t aWindowID,UniqueMessagePortId & aPortIdentifier,base::ProcessId aProcessId)61 bool SharedWorkerManager::MaybeCreateRemoteWorker(
62 const RemoteWorkerData& aData, uint64_t aWindowID,
63 UniqueMessagePortId& aPortIdentifier, base::ProcessId aProcessId) {
64 AssertIsOnBackgroundThread();
65
66 if (!mRemoteWorkerController) {
67 mRemoteWorkerController =
68 RemoteWorkerController::Create(aData, this, aProcessId);
69 if (NS_WARN_IF(!mRemoteWorkerController)) {
70 return false;
71 }
72 }
73
74 if (aWindowID) {
75 mRemoteWorkerController->AddWindowID(aWindowID);
76 }
77
78 mRemoteWorkerController->AddPortIdentifier(aPortIdentifier.release());
79 return true;
80 }
81
82 already_AddRefed<SharedWorkerManagerHolder>
MatchOnMainThread(SharedWorkerService * aService,const nsACString & aDomain,nsIURI * aScriptURL,const nsAString & aName,nsIPrincipal * aLoadingPrincipal,const OriginAttributes & aStoragePrincipalAttrs)83 SharedWorkerManager::MatchOnMainThread(
84 SharedWorkerService* aService, const nsACString& aDomain,
85 nsIURI* aScriptURL, const nsAString& aName, nsIPrincipal* aLoadingPrincipal,
86 const OriginAttributes& aStoragePrincipalAttrs) {
87 MOZ_ASSERT(NS_IsMainThread());
88
89 bool urlEquals;
90 if (NS_FAILED(aScriptURL->Equals(mResolvedScriptURL, &urlEquals))) {
91 return nullptr;
92 }
93
94 bool match = aDomain == mDomain && urlEquals && aName == mName &&
95 // We want to be sure that the window's principal subsumes the
96 // SharedWorker's loading principal and vice versa.
97 mLoadingPrincipal->Subsumes(aLoadingPrincipal) &&
98 aLoadingPrincipal->Subsumes(mLoadingPrincipal) &&
99 mStoragePrincipalAttrs == aStoragePrincipalAttrs;
100 if (!match) {
101 return nullptr;
102 }
103
104 RefPtr<SharedWorkerManagerHolder> holder =
105 new SharedWorkerManagerHolder(this, aService);
106 return holder.forget();
107 }
108
AddActor(SharedWorkerParent * aParent)109 void SharedWorkerManager::AddActor(SharedWorkerParent* aParent) {
110 AssertIsOnBackgroundThread();
111 MOZ_ASSERT(aParent);
112 MOZ_ASSERT(!mActors.Contains(aParent));
113
114 mActors.AppendElement(aParent);
115
116 // NB: We don't update our Suspended/Frozen state here, yet. The aParent is
117 // responsible for doing so from SharedWorkerParent::ManagerCreated.
118 // XXX But we could avoid iterating all of our actors because if aParent is
119 // not frozen and we are, we would just need to thaw ourselves.
120 }
121
RemoveActor(SharedWorkerParent * aParent)122 void SharedWorkerManager::RemoveActor(SharedWorkerParent* aParent) {
123 AssertIsOnBackgroundThread();
124 MOZ_ASSERT(aParent);
125 MOZ_ASSERT(mActors.Contains(aParent));
126
127 uint64_t windowID = aParent->WindowID();
128 if (windowID) {
129 mRemoteWorkerController->RemoveWindowID(windowID);
130 }
131
132 mActors.RemoveElement(aParent);
133
134 if (!mActors.IsEmpty()) {
135 // Our remaining actors could be all suspended or frozen.
136 UpdateSuspend();
137 UpdateFrozen();
138 return;
139 }
140 }
141
Terminate()142 void SharedWorkerManager::Terminate() {
143 AssertIsOnBackgroundThread();
144 MOZ_ASSERT(mActors.IsEmpty());
145 MOZ_ASSERT(mHolders.IsEmpty());
146
147 mRemoteWorkerController->Terminate();
148 mRemoteWorkerController = nullptr;
149 }
150
UpdateSuspend()151 void SharedWorkerManager::UpdateSuspend() {
152 AssertIsOnBackgroundThread();
153 MOZ_ASSERT(mRemoteWorkerController);
154
155 uint32_t suspended = 0;
156
157 for (SharedWorkerParent* actor : mActors) {
158 if (actor->IsSuspended()) {
159 ++suspended;
160 }
161 }
162
163 // Call Suspend only when all of our actors' windows are suspended and call
164 // Resume only when one of them resumes.
165 if ((mSuspended && suspended == mActors.Length()) ||
166 (!mSuspended && suspended != mActors.Length())) {
167 return;
168 }
169
170 if (!mSuspended) {
171 mSuspended = true;
172 mRemoteWorkerController->Suspend();
173 } else {
174 mSuspended = false;
175 mRemoteWorkerController->Resume();
176 }
177 }
178
UpdateFrozen()179 void SharedWorkerManager::UpdateFrozen() {
180 AssertIsOnBackgroundThread();
181 MOZ_ASSERT(mRemoteWorkerController);
182
183 uint32_t frozen = 0;
184
185 for (SharedWorkerParent* actor : mActors) {
186 if (actor->IsFrozen()) {
187 ++frozen;
188 }
189 }
190
191 // Similar to UpdateSuspend, above, we only want to be frozen when all of our
192 // actors are frozen.
193 if ((mFrozen && frozen == mActors.Length()) ||
194 (!mFrozen && frozen != mActors.Length())) {
195 return;
196 }
197
198 if (!mFrozen) {
199 mFrozen = true;
200 mRemoteWorkerController->Freeze();
201 } else {
202 mFrozen = false;
203 mRemoteWorkerController->Thaw();
204 }
205 }
206
IsSecureContext() const207 bool SharedWorkerManager::IsSecureContext() const { return mIsSecureContext; }
208
CreationFailed()209 void SharedWorkerManager::CreationFailed() {
210 AssertIsOnBackgroundThread();
211
212 for (SharedWorkerParent* actor : mActors) {
213 Unused << actor->SendError(NS_ERROR_FAILURE);
214 }
215 }
216
CreationSucceeded()217 void SharedWorkerManager::CreationSucceeded() {
218 AssertIsOnBackgroundThread();
219 // Nothing to do here.
220 }
221
ErrorReceived(const ErrorValue & aValue)222 void SharedWorkerManager::ErrorReceived(const ErrorValue& aValue) {
223 AssertIsOnBackgroundThread();
224
225 for (SharedWorkerParent* actor : mActors) {
226 Unused << actor->SendError(aValue);
227 }
228 }
229
Terminated()230 void SharedWorkerManager::Terminated() {
231 AssertIsOnBackgroundThread();
232
233 for (SharedWorkerParent* actor : mActors) {
234 Unused << actor->SendTerminate();
235 }
236 }
237
RegisterHolder(SharedWorkerManagerHolder * aHolder)238 void SharedWorkerManager::RegisterHolder(SharedWorkerManagerHolder* aHolder) {
239 MOZ_ASSERT(NS_IsMainThread());
240 MOZ_ASSERT(aHolder);
241 MOZ_ASSERT(!mHolders.Contains(aHolder));
242
243 mHolders.AppendElement(aHolder);
244 }
245
UnregisterHolder(SharedWorkerManagerHolder * aHolder)246 void SharedWorkerManager::UnregisterHolder(SharedWorkerManagerHolder* aHolder) {
247 MOZ_ASSERT(NS_IsMainThread());
248 MOZ_ASSERT(aHolder);
249 MOZ_ASSERT(mHolders.Contains(aHolder));
250
251 mHolders.RemoveElement(aHolder);
252
253 if (!mHolders.IsEmpty()) {
254 return;
255 }
256
257 // Time to go.
258
259 aHolder->Service()->RemoveWorkerManagerOnMainThread(this);
260
261 RefPtr<SharedWorkerManager> self = this;
262 mPBackgroundEventTarget->Dispatch(
263 NS_NewRunnableFunction(
264 "SharedWorkerService::RemoveWorkerManagerOnMainThread",
265 [self]() { self->Terminate(); }),
266 NS_DISPATCH_NORMAL);
267 }
268
SharedWorkerManagerHolder(SharedWorkerManager * aManager,SharedWorkerService * aService)269 SharedWorkerManagerHolder::SharedWorkerManagerHolder(
270 SharedWorkerManager* aManager, SharedWorkerService* aService)
271 : mManager(aManager), mService(aService) {
272 MOZ_ASSERT(NS_IsMainThread());
273 MOZ_ASSERT(aManager);
274 MOZ_ASSERT(aService);
275
276 aManager->RegisterHolder(this);
277 }
278
~SharedWorkerManagerHolder()279 SharedWorkerManagerHolder::~SharedWorkerManagerHolder() {
280 MOZ_ASSERT(NS_IsMainThread());
281 mManager->UnregisterHolder(this);
282 }
283
SharedWorkerManagerWrapper(already_AddRefed<SharedWorkerManagerHolder> aHolder)284 SharedWorkerManagerWrapper::SharedWorkerManagerWrapper(
285 already_AddRefed<SharedWorkerManagerHolder> aHolder)
286 : mHolder(aHolder) {
287 MOZ_ASSERT(NS_IsMainThread());
288 }
289
~SharedWorkerManagerWrapper()290 SharedWorkerManagerWrapper::~SharedWorkerManagerWrapper() {
291 NS_ReleaseOnMainThread("SharedWorkerManagerWrapper::mHolder",
292 mHolder.forget());
293 }
294
295 } // namespace dom
296 } // namespace mozilla
297