Coverage Report

Created: 2018-09-25 14:53

/src/mozilla-central/dom/serviceworkers/ServiceWorkerRegistrationProxy.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 "ServiceWorkerRegistrationProxy.h"
8
9
#include "mozilla/ipc/BackgroundParent.h"
10
#include "ServiceWorkerManager.h"
11
#include "ServiceWorkerRegistrationParent.h"
12
13
namespace mozilla {
14
namespace dom {
15
16
using mozilla::ipc::AssertIsOnBackgroundThread;
17
18
ServiceWorkerRegistrationProxy::~ServiceWorkerRegistrationProxy()
19
0
{
20
0
  // Any thread
21
0
  MOZ_DIAGNOSTIC_ASSERT(!mActor);
22
0
  MOZ_DIAGNOSTIC_ASSERT(!mReg);
23
0
}
24
25
void
26
ServiceWorkerRegistrationProxy::MaybeShutdownOnBGThread()
27
0
{
28
0
  AssertIsOnBackgroundThread();
29
0
  if (!mActor) {
30
0
    return;
31
0
  }
32
0
  mActor->MaybeSendDelete();
33
0
}
34
35
void
36
ServiceWorkerRegistrationProxy::UpdateStateOnBGThread(const ServiceWorkerRegistrationDescriptor& aDescriptor)
37
0
{
38
0
  AssertIsOnBackgroundThread();
39
0
  if (!mActor) {
40
0
    return;
41
0
  }
42
0
  Unused << mActor->SendUpdateState(aDescriptor.ToIPC());
43
0
}
44
45
void
46
ServiceWorkerRegistrationProxy::InitOnMainThread()
47
0
{
48
0
  AssertIsOnMainThread();
49
0
50
0
  auto scopeExit = MakeScopeExit([&] {
51
0
    MaybeShutdownOnMainThread();
52
0
  });
53
0
54
0
  RefPtr<ServiceWorkerManager> swm = ServiceWorkerManager::GetInstance();
55
0
  NS_ENSURE_TRUE_VOID(swm);
56
0
57
0
  RefPtr<ServiceWorkerRegistrationInfo> reg =
58
0
    swm->GetRegistration(mDescriptor.PrincipalInfo(), mDescriptor.Scope());
59
0
  NS_ENSURE_TRUE_VOID(reg);
60
0
61
0
  scopeExit.release();
62
0
63
0
  mReg = new nsMainThreadPtrHolder<ServiceWorkerRegistrationInfo>(
64
0
    "ServiceWorkerRegistrationProxy::mInfo", reg);
65
0
66
0
  mReg->AddInstance(this, mDescriptor);
67
0
}
68
69
void
70
ServiceWorkerRegistrationProxy::MaybeShutdownOnMainThread()
71
0
{
72
0
  AssertIsOnMainThread();
73
0
74
0
  nsCOMPtr<nsIRunnable> r =
75
0
    NewRunnableMethod(__func__, this,
76
0
                      &ServiceWorkerRegistrationProxy::MaybeShutdownOnBGThread);
77
0
78
0
  MOZ_ALWAYS_SUCCEEDS(mEventTarget->Dispatch(r.forget(), NS_DISPATCH_NORMAL));
79
0
}
80
81
void
82
ServiceWorkerRegistrationProxy::StopListeningOnMainThread()
83
0
{
84
0
  AssertIsOnMainThread();
85
0
86
0
  if (!mReg) {
87
0
    return;
88
0
  }
89
0
90
0
  mReg->RemoveInstance(this);
91
0
  mReg = nullptr;
92
0
}
93
94
void
95
ServiceWorkerRegistrationProxy::UpdateState(const ServiceWorkerRegistrationDescriptor& aDescriptor)
96
0
{
97
0
  AssertIsOnMainThread();
98
0
99
0
  if (mDescriptor == aDescriptor) {
100
0
    return;
101
0
  }
102
0
  mDescriptor = aDescriptor;
103
0
104
0
  nsCOMPtr<nsIRunnable> r = NewRunnableMethod<ServiceWorkerRegistrationDescriptor>(
105
0
    __func__, this, &ServiceWorkerRegistrationProxy::UpdateStateOnBGThread,
106
0
    aDescriptor);
107
0
108
0
  MOZ_ALWAYS_SUCCEEDS(mEventTarget->Dispatch(r.forget(), NS_DISPATCH_NORMAL));
109
0
}
110
111
void
112
ServiceWorkerRegistrationProxy::RegistrationRemoved()
113
0
{
114
0
  MaybeShutdownOnMainThread();
115
0
}
116
117
void
118
ServiceWorkerRegistrationProxy::GetScope(nsAString& aScope) const
119
0
{
120
0
  CopyUTF8toUTF16(mDescriptor.Scope(), aScope);
121
0
}
122
123
bool
124
ServiceWorkerRegistrationProxy::MatchesDescriptor(const ServiceWorkerRegistrationDescriptor& aDescriptor)
125
0
{
126
0
  AssertIsOnMainThread();
127
0
  return aDescriptor.Id() == mDescriptor.Id() &&
128
0
         aDescriptor.PrincipalInfo() == mDescriptor.PrincipalInfo() &&
129
0
         aDescriptor.Scope() == mDescriptor.Scope();
130
0
}
131
132
ServiceWorkerRegistrationProxy::ServiceWorkerRegistrationProxy(const ServiceWorkerRegistrationDescriptor& aDescriptor)
133
  : mActor(nullptr)
134
  , mEventTarget(GetCurrentThreadSerialEventTarget())
135
  , mDescriptor(aDescriptor)
136
0
{
137
0
}
138
139
void
140
ServiceWorkerRegistrationProxy::Init(ServiceWorkerRegistrationParent* aActor)
141
0
{
142
0
  AssertIsOnBackgroundThread();
143
0
  MOZ_DIAGNOSTIC_ASSERT(aActor);
144
0
  MOZ_DIAGNOSTIC_ASSERT(!mActor);
145
0
  MOZ_DIAGNOSTIC_ASSERT(mEventTarget);
146
0
147
0
  mActor = aActor;
148
0
149
0
  // Note, this must be done from a separate Init() method and not in
150
0
  // the constructor.  If done from the constructor the runnable can
151
0
  // execute, complete, and release its reference before the constructor
152
0
  // returns.
153
0
  nsCOMPtr<nsIRunnable> r = NewRunnableMethod(
154
0
    "ServiceWorkerRegistrationProxy::Init", this,
155
0
    &ServiceWorkerRegistrationProxy::InitOnMainThread);
156
0
  MOZ_ALWAYS_SUCCEEDS(SystemGroup::Dispatch(TaskCategory::Other, r.forget()));
157
0
}
158
159
void
160
ServiceWorkerRegistrationProxy::RevokeActor(ServiceWorkerRegistrationParent* aActor)
161
0
{
162
0
  AssertIsOnBackgroundThread();
163
0
  MOZ_DIAGNOSTIC_ASSERT(mActor);
164
0
  MOZ_DIAGNOSTIC_ASSERT(mActor == aActor);
165
0
  mActor = nullptr;
166
0
167
0
  nsCOMPtr<nsIRunnable> r =
168
0
    NewRunnableMethod(__func__, this,
169
0
                      &ServiceWorkerRegistrationProxy::StopListeningOnMainThread);
170
0
  MOZ_ALWAYS_SUCCEEDS(SystemGroup::Dispatch(TaskCategory::Other, r.forget()));
171
0
}
172
173
namespace {
174
175
class UnregisterCallback final : public nsIServiceWorkerUnregisterCallback
176
{
177
  RefPtr<GenericPromise::Private> mPromise;
178
179
0
  ~UnregisterCallback() = default;
180
181
public:
182
  explicit UnregisterCallback(GenericPromise::Private* aPromise)
183
    : mPromise(aPromise)
184
0
  {
185
0
    MOZ_DIAGNOSTIC_ASSERT(mPromise);
186
0
  }
187
188
  NS_IMETHOD
189
  UnregisterSucceeded(bool aState) override
190
0
  {
191
0
    mPromise->Resolve(aState, __func__);
192
0
    return NS_OK;
193
0
  }
194
195
  NS_IMETHOD
196
  UnregisterFailed() override
197
0
  {
198
0
    mPromise->Reject(NS_ERROR_DOM_SECURITY_ERR, __func__);
199
0
    return NS_OK;
200
0
  }
201
202
  NS_DECL_ISUPPORTS
203
};
204
205
NS_IMPL_ISUPPORTS(UnregisterCallback, nsIServiceWorkerUnregisterCallback)
206
207
} // anonymous namespace
208
209
RefPtr<GenericPromise>
210
ServiceWorkerRegistrationProxy::Unregister()
211
0
{
212
0
  AssertIsOnBackgroundThread();
213
0
214
0
  RefPtr<ServiceWorkerRegistrationProxy> self = this;
215
0
  RefPtr<GenericPromise::Private> promise =
216
0
    new GenericPromise::Private(__func__);
217
0
218
0
  nsCOMPtr<nsIRunnable> r = NS_NewRunnableFunction(__func__,
219
0
    [self, promise] () mutable {
220
0
      nsresult rv = NS_ERROR_DOM_INVALID_STATE_ERR;
221
0
      auto scopeExit = MakeScopeExit([&] {
222
0
        promise->Reject(rv, __func__);
223
0
      });
224
0
225
0
      NS_ENSURE_TRUE_VOID(self->mReg);
226
0
227
0
      RefPtr<ServiceWorkerManager> swm = ServiceWorkerManager::GetInstance();
228
0
      NS_ENSURE_TRUE_VOID(swm);
229
0
230
0
      RefPtr<UnregisterCallback> cb = new UnregisterCallback(promise);
231
0
232
0
      rv = swm->Unregister(self->mReg->Principal(), cb,
233
0
                           NS_ConvertUTF8toUTF16(self->mReg->Scope()));
234
0
      NS_ENSURE_SUCCESS_VOID(rv);
235
0
236
0
237
0
      scopeExit.release();
238
0
    });
239
0
240
0
  MOZ_ALWAYS_SUCCEEDS(SystemGroup::Dispatch(TaskCategory::Other, r.forget()));
241
0
242
0
  return promise;
243
0
}
244
245
namespace {
246
247
class UpdateCallback final : public ServiceWorkerUpdateFinishCallback
248
{
249
  RefPtr<ServiceWorkerRegistrationPromise::Private> mPromise;
250
251
0
  ~UpdateCallback() = default;
252
253
public:
254
  explicit UpdateCallback(RefPtr<ServiceWorkerRegistrationPromise::Private>&& aPromise)
255
    : mPromise(std::move(aPromise))
256
0
  {
257
0
    MOZ_DIAGNOSTIC_ASSERT(mPromise);
258
0
  }
259
260
  void
261
  UpdateSucceeded(ServiceWorkerRegistrationInfo* aInfo) override
262
0
  {
263
0
    mPromise->Resolve(aInfo->Descriptor(), __func__);
264
0
  }
265
266
  void
267
  UpdateFailed(ErrorResult& aResult) override
268
0
  {
269
0
    mPromise->Reject(CopyableErrorResult(aResult), __func__);
270
0
  }
271
};
272
273
} // anonymous namespace
274
275
RefPtr<ServiceWorkerRegistrationPromise>
276
ServiceWorkerRegistrationProxy::Update()
277
0
{
278
0
  AssertIsOnBackgroundThread();
279
0
280
0
  RefPtr<ServiceWorkerRegistrationProxy> self = this;
281
0
  RefPtr<ServiceWorkerRegistrationPromise::Private> promise =
282
0
    new ServiceWorkerRegistrationPromise::Private(__func__);
283
0
284
0
  nsCOMPtr<nsIRunnable> r = NS_NewRunnableFunction(__func__,
285
0
    [self, promise] () mutable {
286
0
      auto scopeExit = MakeScopeExit([&] {
287
0
        promise->Reject(NS_ERROR_DOM_INVALID_STATE_ERR, __func__);
288
0
      });
289
0
290
0
      NS_ENSURE_TRUE_VOID(self->mReg);
291
0
292
0
      RefPtr<ServiceWorkerManager> swm = ServiceWorkerManager::GetInstance();
293
0
      NS_ENSURE_TRUE_VOID(swm);
294
0
295
0
      RefPtr<UpdateCallback> cb = new UpdateCallback(std::move(promise));
296
0
      swm->Update(self->mReg->Principal(), self->mReg->Scope(), cb);
297
0
298
0
      scopeExit.release();
299
0
    });
300
0
301
0
  MOZ_ALWAYS_SUCCEEDS(SystemGroup::Dispatch(TaskCategory::Other, r.forget()));
302
0
303
0
  return promise;
304
0
}
305
306
} // namespace dom
307
} // namespace mozilla