Source code

Revision control

Other Tools

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 "ServiceWorkerManagerService.h"
8
#include "ServiceWorkerManagerParent.h"
9
#include "ServiceWorkerRegistrar.h"
10
#include "ServiceWorkerUpdaterParent.h"
11
#include "mozilla/dom/ContentParent.h"
12
#include "mozilla/ipc/BackgroundParent.h"
13
#include "mozilla/Unused.h"
14
#include "nsAutoPtr.h"
15
16
namespace mozilla {
17
18
using namespace ipc;
19
20
namespace dom {
21
22
namespace {
23
24
ServiceWorkerManagerService* sInstance = nullptr;
25
26
} // namespace
27
28
ServiceWorkerManagerService::ServiceWorkerManagerService() {
29
AssertIsOnBackgroundThread();
30
31
// sInstance is a raw ServiceWorkerManagerService*.
32
MOZ_ASSERT(!sInstance);
33
sInstance = this;
34
}
35
36
ServiceWorkerManagerService::~ServiceWorkerManagerService() {
37
AssertIsOnBackgroundThread();
38
MOZ_ASSERT(sInstance == this);
39
MOZ_ASSERT(mAgents.Count() == 0);
40
41
sInstance = nullptr;
42
}
43
44
/* static */
45
already_AddRefed<ServiceWorkerManagerService>
46
ServiceWorkerManagerService::Get() {
47
AssertIsOnBackgroundThread();
48
49
RefPtr<ServiceWorkerManagerService> instance = sInstance;
50
return instance.forget();
51
}
52
53
/* static */
54
already_AddRefed<ServiceWorkerManagerService>
55
ServiceWorkerManagerService::GetOrCreate() {
56
AssertIsOnBackgroundThread();
57
58
RefPtr<ServiceWorkerManagerService> instance = sInstance;
59
if (!instance) {
60
instance = new ServiceWorkerManagerService();
61
}
62
return instance.forget();
63
}
64
65
void ServiceWorkerManagerService::RegisterActor(
66
ServiceWorkerManagerParent* aParent) {
67
AssertIsOnBackgroundThread();
68
MOZ_ASSERT(aParent);
69
MOZ_ASSERT(!mAgents.Contains(aParent));
70
71
mAgents.PutEntry(aParent);
72
}
73
74
void ServiceWorkerManagerService::UnregisterActor(
75
ServiceWorkerManagerParent* aParent) {
76
AssertIsOnBackgroundThread();
77
MOZ_ASSERT(aParent);
78
MOZ_ASSERT(mAgents.Contains(aParent));
79
80
mAgents.RemoveEntry(aParent);
81
}
82
83
void ServiceWorkerManagerService::PropagateRegistration(
84
uint64_t aParentID, ServiceWorkerRegistrationData& aData) {
85
AssertIsOnBackgroundThread();
86
87
if (ServiceWorkerParentInterceptEnabled()) {
88
return;
89
}
90
91
DebugOnly<bool> parentFound = false;
92
for (auto iter = mAgents.Iter(); !iter.Done(); iter.Next()) {
93
RefPtr<ServiceWorkerManagerParent> parent = iter.Get()->GetKey();
94
MOZ_ASSERT(parent);
95
96
if (parent->ID() != aParentID) {
97
Unused << parent->SendNotifyRegister(aData);
98
#ifdef DEBUG
99
} else {
100
parentFound = true;
101
#endif
102
}
103
}
104
105
// Send permissions fot the newly registered service worker to all of the
106
// content processes.
107
PrincipalInfo pi = aData.principal();
108
NS_DispatchToMainThread(NS_NewRunnableFunction(
109
"dom::ServiceWorkerManagerService::PropagateRegistration", [pi]() {
110
nsTArray<ContentParent*> cps;
111
ContentParent::GetAll(cps);
112
for (auto* cp : cps) {
113
nsCOMPtr<nsIPrincipal> principal = PrincipalInfoToPrincipal(pi);
114
if (principal) {
115
cp->TransmitPermissionsForPrincipal(principal);
116
}
117
}
118
}));
119
120
#ifdef DEBUG
121
MOZ_ASSERT(parentFound);
122
#endif
123
}
124
125
void ServiceWorkerManagerService::PropagateSoftUpdate(
126
uint64_t aParentID, const OriginAttributes& aOriginAttributes,
127
const nsAString& aScope) {
128
AssertIsOnBackgroundThread();
129
130
if (ServiceWorkerParentInterceptEnabled()) {
131
return;
132
}
133
134
DebugOnly<bool> parentFound = false;
135
for (auto iter = mAgents.Iter(); !iter.Done(); iter.Next()) {
136
RefPtr<ServiceWorkerManagerParent> parent = iter.Get()->GetKey();
137
MOZ_ASSERT(parent);
138
139
nsString scope(aScope);
140
Unused << parent->SendNotifySoftUpdate(aOriginAttributes, scope);
141
142
#ifdef DEBUG
143
if (parent->ID() == aParentID) {
144
parentFound = true;
145
}
146
#endif
147
}
148
149
#ifdef DEBUG
150
MOZ_ASSERT(parentFound);
151
#endif
152
}
153
154
void ServiceWorkerManagerService::PropagateUnregister(
155
uint64_t aParentID, const PrincipalInfo& aPrincipalInfo,
156
const nsAString& aScope) {
157
AssertIsOnBackgroundThread();
158
159
RefPtr<dom::ServiceWorkerRegistrar> service =
160
dom::ServiceWorkerRegistrar::Get();
161
MOZ_ASSERT(service);
162
163
// It's possible that we don't have any ServiceWorkerManager managing this
164
// scope but we still need to unregister it from the ServiceWorkerRegistrar.
165
service->UnregisterServiceWorker(aPrincipalInfo,
166
NS_ConvertUTF16toUTF8(aScope));
167
168
// There is no longer any point to propagating because the only sender is the
169
// one and only ServiceWorkerManager, but it is necessary for us to have run
170
// the unregister call above because until Bug 1183245 is fixed,
171
// nsIServiceWorkerManager.propagateUnregister() is a de facto API for
172
// clearing ServiceWorker registrations by Sanitizer.jsm via
173
// ServiceWorkerCleanUp.jsm, as well as devtools "unregister" affordance and
174
// the no-longer-relevant about:serviceworkers UI.
175
176
if (ServiceWorkerParentInterceptEnabled()) {
177
return;
178
}
179
180
DebugOnly<bool> parentFound = false;
181
for (auto iter = mAgents.Iter(); !iter.Done(); iter.Next()) {
182
RefPtr<ServiceWorkerManagerParent> parent = iter.Get()->GetKey();
183
MOZ_ASSERT(parent);
184
185
if (parent->ID() != aParentID) {
186
nsString scope(aScope);
187
Unused << parent->SendNotifyUnregister(aPrincipalInfo, scope);
188
#ifdef DEBUG
189
} else {
190
parentFound = true;
191
#endif
192
}
193
}
194
195
#ifdef DEBUG
196
MOZ_ASSERT(parentFound);
197
#endif
198
}
199
200
void ServiceWorkerManagerService::PropagateRemove(uint64_t aParentID,
201
const nsACString& aHost) {
202
AssertIsOnBackgroundThread();
203
204
if (ServiceWorkerParentInterceptEnabled()) {
205
return;
206
}
207
208
DebugOnly<bool> parentFound = false;
209
for (auto iter = mAgents.Iter(); !iter.Done(); iter.Next()) {
210
RefPtr<ServiceWorkerManagerParent> parent = iter.Get()->GetKey();
211
MOZ_ASSERT(parent);
212
213
if (parent->ID() != aParentID) {
214
nsCString host(aHost);
215
Unused << parent->SendNotifyRemove(host);
216
#ifdef DEBUG
217
} else {
218
parentFound = true;
219
#endif
220
}
221
}
222
223
#ifdef DEBUG
224
MOZ_ASSERT(parentFound);
225
#endif
226
}
227
228
void ServiceWorkerManagerService::PropagateRemoveAll(uint64_t aParentID) {
229
AssertIsOnBackgroundThread();
230
231
if (ServiceWorkerParentInterceptEnabled()) {
232
return;
233
}
234
235
RefPtr<dom::ServiceWorkerRegistrar> service =
236
dom::ServiceWorkerRegistrar::Get();
237
MOZ_ASSERT(service);
238
239
service->RemoveAll();
240
241
DebugOnly<bool> parentFound = false;
242
for (auto iter = mAgents.Iter(); !iter.Done(); iter.Next()) {
243
RefPtr<ServiceWorkerManagerParent> parent = iter.Get()->GetKey();
244
MOZ_ASSERT(parent);
245
246
if (parent->ID() != aParentID) {
247
Unused << parent->SendNotifyRemoveAll();
248
#ifdef DEBUG
249
} else {
250
parentFound = true;
251
#endif
252
}
253
}
254
255
#ifdef DEBUG
256
MOZ_ASSERT(parentFound);
257
#endif
258
}
259
260
void ServiceWorkerManagerService::ProcessUpdaterActor(
261
ServiceWorkerUpdaterParent* aActor,
262
const OriginAttributes& aOriginAttributes, const nsACString& aScope,
263
uint64_t aParentId) {
264
AssertIsOnBackgroundThread();
265
266
MOZ_DIAGNOSTIC_ASSERT(!ServiceWorkerParentInterceptEnabled());
267
268
nsAutoCString suffix;
269
aOriginAttributes.CreateSuffix(suffix);
270
271
nsCString scope(aScope);
272
scope.Append(suffix);
273
274
for (uint32_t i = 0; i < mPendingUpdaterActors.Length(); ++i) {
275
// We already have an actor doing this update on another process.
276
if (mPendingUpdaterActors[i].mScope.Equals(scope) &&
277
mPendingUpdaterActors[i].mParentId != aParentId) {
278
Unused << aActor->SendProceed(false);
279
return;
280
}
281
}
282
283
if (aActor->Proceed(this)) {
284
PendingUpdaterActor* pua = mPendingUpdaterActors.AppendElement();
285
pua->mActor = aActor;
286
pua->mScope = scope;
287
pua->mParentId = aParentId;
288
}
289
}
290
291
void ServiceWorkerManagerService::UpdaterActorDestroyed(
292
ServiceWorkerUpdaterParent* aActor) {
293
for (uint32_t i = 0; i < mPendingUpdaterActors.Length(); ++i) {
294
// We already have an actor doing the update for this scope.
295
if (mPendingUpdaterActors[i].mActor == aActor) {
296
mPendingUpdaterActors.RemoveElementAt(i);
297
return;
298
}
299
}
300
301
MOZ_CRASH("The actor should be found");
302
}
303
304
} // namespace dom
305
} // namespace mozilla