Coverage Report

Created: 2018-09-25 14:53

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