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 "ServiceWorkerManagerParent.h"
8
#include "ServiceWorkerManagerService.h"
9
#include "ServiceWorkerUpdaterParent.h"
10
#include "mozilla/dom/ContentParent.h"
11
#include "mozilla/dom/ServiceWorkerRegistrar.h"
12
#include "mozilla/ipc/BackgroundParent.h"
13
#include "mozilla/ipc/BackgroundUtils.h"
14
#include "mozilla/Unused.h"
15
#include "nsThreadUtils.h"
16
17
namespace mozilla {
18
19
using namespace ipc;
20
21
namespace dom {
22
23
namespace {
24
25
uint64_t sServiceWorkerManagerParentID = 0;
26
27
class RegisterServiceWorkerCallback final : public Runnable {
28
public:
29
RegisterServiceWorkerCallback(const ServiceWorkerRegistrationData& aData,
30
uint64_t aParentID)
31
: Runnable("dom::RegisterServiceWorkerCallback"),
32
mData(aData),
33
mParentID(aParentID) {
34
AssertIsInMainProcess();
35
AssertIsOnBackgroundThread();
36
}
37
38
NS_IMETHOD
39
Run() override {
40
AssertIsInMainProcess();
41
AssertIsOnBackgroundThread();
42
43
RefPtr<dom::ServiceWorkerRegistrar> service =
44
dom::ServiceWorkerRegistrar::Get();
45
46
// Shutdown during the process of trying to update the registrar. Give
47
// up on this modification.
48
if (!service) {
49
return NS_OK;
50
}
51
52
service->RegisterServiceWorker(mData);
53
54
RefPtr<ServiceWorkerManagerService> managerService =
55
ServiceWorkerManagerService::Get();
56
if (managerService) {
57
managerService->PropagateRegistration(mParentID, mData);
58
}
59
60
return NS_OK;
61
}
62
63
private:
64
ServiceWorkerRegistrationData mData;
65
const uint64_t mParentID;
66
};
67
68
class UnregisterServiceWorkerCallback final : public Runnable {
69
public:
70
UnregisterServiceWorkerCallback(const PrincipalInfo& aPrincipalInfo,
71
const nsString& aScope, uint64_t aParentID)
72
: Runnable("dom::UnregisterServiceWorkerCallback"),
73
mPrincipalInfo(aPrincipalInfo),
74
mScope(aScope),
75
mParentID(aParentID) {
76
AssertIsInMainProcess();
77
AssertIsOnBackgroundThread();
78
}
79
80
NS_IMETHOD
81
Run() override {
82
AssertIsInMainProcess();
83
AssertIsOnBackgroundThread();
84
85
RefPtr<dom::ServiceWorkerRegistrar> service =
86
dom::ServiceWorkerRegistrar::Get();
87
88
// Shutdown during the process of trying to update the registrar. Give
89
// up on this modification.
90
if (!service) {
91
return NS_OK;
92
}
93
94
service->UnregisterServiceWorker(mPrincipalInfo,
95
NS_ConvertUTF16toUTF8(mScope));
96
97
// We do not propagate the unregister in parent-intercept mode because the
98
// only point of PropagateUnregister historically is:
99
// 1. Tell other ServiceWorkerManagers about the removal. There is only 1
100
// ServiceWorkerManager in parent-intercept mode.
101
// 2. To remove the registration as an awkward API for privacy and devtools
102
// purposes. Although the unregister method is idempotent, it's
103
// preferable to only call the method once if possible. And we're now
104
// re-enabling the removal in PropagateUnregister due to a privacy
105
// regression in bug 1589708, so it makes sense to bail now.
106
if (ServiceWorkerParentInterceptEnabled()) {
107
return NS_OK;
108
}
109
110
RefPtr<ServiceWorkerManagerService> managerService =
111
ServiceWorkerManagerService::Get();
112
if (managerService) {
113
managerService->PropagateUnregister(mParentID, mPrincipalInfo, mScope);
114
}
115
116
return NS_OK;
117
}
118
119
private:
120
const PrincipalInfo mPrincipalInfo;
121
nsString mScope;
122
uint64_t mParentID;
123
};
124
125
class CheckPrincipalWithCallbackRunnable final : public Runnable {
126
public:
127
CheckPrincipalWithCallbackRunnable(already_AddRefed<ContentParent> aParent,
128
const PrincipalInfo& aPrincipalInfo,
129
Runnable* aCallback)
130
: Runnable("dom::CheckPrincipalWithCallbackRunnable"),
131
mContentParent(aParent),
132
mPrincipalInfo(aPrincipalInfo),
133
mCallback(aCallback),
134
mBackgroundEventTarget(GetCurrentThreadEventTarget()) {
135
AssertIsInMainProcess();
136
AssertIsOnBackgroundThread();
137
138
MOZ_ASSERT(mContentParent);
139
MOZ_ASSERT(mCallback);
140
MOZ_ASSERT(mBackgroundEventTarget);
141
}
142
143
NS_IMETHOD Run() override {
144
if (NS_IsMainThread()) {
145
mContentParent = nullptr;
146
147
mBackgroundEventTarget->Dispatch(this, NS_DISPATCH_NORMAL);
148
return NS_OK;
149
}
150
151
AssertIsOnBackgroundThread();
152
mCallback->Run();
153
mCallback = nullptr;
154
155
return NS_OK;
156
}
157
158
private:
159
RefPtr<ContentParent> mContentParent;
160
PrincipalInfo mPrincipalInfo;
161
RefPtr<Runnable> mCallback;
162
nsCOMPtr<nsIEventTarget> mBackgroundEventTarget;
163
};
164
165
} // namespace
166
167
ServiceWorkerManagerParent::ServiceWorkerManagerParent()
168
: mService(ServiceWorkerManagerService::GetOrCreate()),
169
mID(++sServiceWorkerManagerParentID) {
170
AssertIsOnBackgroundThread();
171
mService->RegisterActor(this);
172
}
173
174
ServiceWorkerManagerParent::~ServiceWorkerManagerParent() {
175
AssertIsOnBackgroundThread();
176
}
177
178
mozilla::ipc::IPCResult ServiceWorkerManagerParent::RecvRegister(
179
const ServiceWorkerRegistrationData& aData) {
180
AssertIsInMainProcess();
181
AssertIsOnBackgroundThread();
182
183
// Basic validation.
184
if (aData.scope().IsEmpty() ||
185
aData.principal().type() == PrincipalInfo::TNullPrincipalInfo ||
186
aData.principal().type() == PrincipalInfo::TSystemPrincipalInfo) {
187
return IPC_FAIL_NO_REASON(this);
188
}
189
190
RefPtr<RegisterServiceWorkerCallback> callback =
191
new RegisterServiceWorkerCallback(aData, mID);
192
193
RefPtr<ContentParent> parent = BackgroundParent::GetContentParent(Manager());
194
195
// If the ContentParent is null we are dealing with a same-process actor.
196
if (!parent) {
197
callback->Run();
198
return IPC_OK();
199
}
200
201
RefPtr<CheckPrincipalWithCallbackRunnable> runnable =
202
new CheckPrincipalWithCallbackRunnable(parent.forget(), aData.principal(),
203
callback);
204
MOZ_ALWAYS_SUCCEEDS(NS_DispatchToMainThread(runnable));
205
206
return IPC_OK();
207
}
208
209
mozilla::ipc::IPCResult ServiceWorkerManagerParent::RecvUnregister(
210
const PrincipalInfo& aPrincipalInfo, const nsString& aScope) {
211
AssertIsInMainProcess();
212
AssertIsOnBackgroundThread();
213
214
// Basic validation.
215
if (aScope.IsEmpty() ||
216
aPrincipalInfo.type() == PrincipalInfo::TNullPrincipalInfo ||
217
aPrincipalInfo.type() == PrincipalInfo::TSystemPrincipalInfo) {
218
return IPC_FAIL_NO_REASON(this);
219
}
220
221
RefPtr<UnregisterServiceWorkerCallback> callback =
222
new UnregisterServiceWorkerCallback(aPrincipalInfo, aScope, mID);
223
224
RefPtr<ContentParent> parent = BackgroundParent::GetContentParent(Manager());
225
226
// If the ContentParent is null we are dealing with a same-process actor.
227
if (!parent) {
228
callback->Run();
229
return IPC_OK();
230
}
231
232
RefPtr<CheckPrincipalWithCallbackRunnable> runnable =
233
new CheckPrincipalWithCallbackRunnable(parent.forget(), aPrincipalInfo,
234
callback);
235
MOZ_ALWAYS_SUCCEEDS(NS_DispatchToMainThread(runnable));
236
237
return IPC_OK();
238
}
239
240
mozilla::ipc::IPCResult ServiceWorkerManagerParent::RecvPropagateSoftUpdate(
241
const OriginAttributes& aOriginAttributes, const nsString& aScope) {
242
AssertIsOnBackgroundThread();
243
244
if (NS_WARN_IF(!mService)) {
245
return IPC_FAIL_NO_REASON(this);
246
}
247
248
mService->PropagateSoftUpdate(mID, aOriginAttributes, aScope);
249
return IPC_OK();
250
}
251
252
mozilla::ipc::IPCResult ServiceWorkerManagerParent::RecvPropagateUnregister(
253
const PrincipalInfo& aPrincipalInfo, const nsString& aScope) {
254
AssertIsOnBackgroundThread();
255
256
if (NS_WARN_IF(!mService)) {
257
return IPC_FAIL_NO_REASON(this);
258
}
259
260
mService->PropagateUnregister(mID, aPrincipalInfo, aScope);
261
return IPC_OK();
262
}
263
264
mozilla::ipc::IPCResult ServiceWorkerManagerParent::RecvPropagateRemove(
265
const nsCString& aHost) {
266
AssertIsOnBackgroundThread();
267
268
if (NS_WARN_IF(!mService)) {
269
return IPC_FAIL_NO_REASON(this);
270
}
271
272
mService->PropagateRemove(mID, aHost);
273
return IPC_OK();
274
}
275
276
mozilla::ipc::IPCResult ServiceWorkerManagerParent::RecvPropagateRemoveAll() {
277
AssertIsOnBackgroundThread();
278
279
if (NS_WARN_IF(!mService)) {
280
return IPC_FAIL_NO_REASON(this);
281
}
282
283
mService->PropagateRemoveAll(mID);
284
return IPC_OK();
285
}
286
287
mozilla::ipc::IPCResult ServiceWorkerManagerParent::RecvShutdown() {
288
AssertIsOnBackgroundThread();
289
290
if (NS_WARN_IF(!mService)) {
291
return IPC_FAIL_NO_REASON(this);
292
}
293
294
mService->UnregisterActor(this);
295
mService = nullptr;
296
297
Unused << Send__delete__(this);
298
return IPC_OK();
299
}
300
301
PServiceWorkerUpdaterParent*
302
ServiceWorkerManagerParent::AllocPServiceWorkerUpdaterParent(
303
const OriginAttributes& aOriginAttributes, const nsCString& aScope) {
304
AssertIsOnBackgroundThread();
305
return new ServiceWorkerUpdaterParent();
306
}
307
308
mozilla::ipc::IPCResult
309
ServiceWorkerManagerParent::RecvPServiceWorkerUpdaterConstructor(
310
PServiceWorkerUpdaterParent* aActor,
311
const OriginAttributes& aOriginAttributes, const nsCString& aScope) {
312
AssertIsOnBackgroundThread();
313
314
if (NS_WARN_IF(!mService)) {
315
return IPC_FAIL_NO_REASON(this);
316
}
317
318
mService->ProcessUpdaterActor(
319
static_cast<ServiceWorkerUpdaterParent*>(aActor), aOriginAttributes,
320
aScope, mID);
321
return IPC_OK();
322
}
323
324
bool ServiceWorkerManagerParent::DeallocPServiceWorkerUpdaterParent(
325
PServiceWorkerUpdaterParent* aActor) {
326
AssertIsOnBackgroundThread();
327
delete aActor;
328
return true;
329
}
330
331
void ServiceWorkerManagerParent::ActorDestroy(ActorDestroyReason aWhy) {
332
AssertIsOnBackgroundThread();
333
334
if (mService) {
335
// This object is about to be released and with it, also mService will be
336
// released too.
337
mService->UnregisterActor(this);
338
}
339
}
340
341
} // namespace dom
342
} // namespace mozilla