/src/mozilla-central/dom/serviceworkers/ServiceWorkerRegistrationImpl.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 "ServiceWorkerRegistrationImpl.h" |
8 | | |
9 | | #include "ipc/ErrorIPCUtils.h" |
10 | | #include "mozilla/dom/DOMPrefs.h" |
11 | | #include "mozilla/dom/Promise.h" |
12 | | #include "mozilla/dom/PromiseWorkerProxy.h" |
13 | | #include "mozilla/dom/PushManagerBinding.h" |
14 | | #include "mozilla/dom/PushManager.h" |
15 | | #include "mozilla/dom/ServiceWorkerRegistrationBinding.h" |
16 | | #include "mozilla/dom/WorkerCommon.h" |
17 | | #include "mozilla/dom/WorkerPrivate.h" |
18 | | #include "mozilla/dom/WorkerRef.h" |
19 | | #include "mozilla/dom/WorkerScope.h" |
20 | | #include "mozilla/Services.h" |
21 | | #include "mozilla/Unused.h" |
22 | | #include "nsCycleCollectionParticipant.h" |
23 | | #include "nsNetUtil.h" |
24 | | #include "nsServiceManagerUtils.h" |
25 | | #include "ServiceWorker.h" |
26 | | #include "ServiceWorkerManager.h" |
27 | | #include "ServiceWorkerPrivate.h" |
28 | | #include "ServiceWorkerRegistration.h" |
29 | | |
30 | | #include "nsIDocument.h" |
31 | | #include "nsIServiceWorkerManager.h" |
32 | | #include "nsISupportsPrimitives.h" |
33 | | #include "nsPIDOMWindow.h" |
34 | | #include "nsContentUtils.h" |
35 | | |
36 | | namespace mozilla { |
37 | | namespace dom { |
38 | | |
39 | | //////////////////////////////////////////////////// |
40 | | // Main Thread implementation |
41 | | |
42 | | ServiceWorkerRegistrationMainThread::ServiceWorkerRegistrationMainThread(const ServiceWorkerRegistrationDescriptor& aDescriptor) |
43 | | : mOuter(nullptr) |
44 | | , mDescriptor(aDescriptor) |
45 | | , mScope(NS_ConvertUTF8toUTF16(aDescriptor.Scope())) |
46 | | , mListeningForEvents(false) |
47 | 0 | { |
48 | 0 | MOZ_ASSERT(NS_IsMainThread()); |
49 | 0 | } |
50 | | |
51 | | ServiceWorkerRegistrationMainThread::~ServiceWorkerRegistrationMainThread() |
52 | 0 | { |
53 | 0 | MOZ_DIAGNOSTIC_ASSERT(!mListeningForEvents); |
54 | 0 | MOZ_DIAGNOSTIC_ASSERT(!mOuter); |
55 | 0 | } |
56 | | |
57 | | // XXXnsm, maybe this can be optimized to only add when a event handler is |
58 | | // registered. |
59 | | void |
60 | | ServiceWorkerRegistrationMainThread::StartListeningForEvents() |
61 | 0 | { |
62 | 0 | MOZ_ASSERT(NS_IsMainThread()); |
63 | 0 | MOZ_ASSERT(!mListeningForEvents); |
64 | 0 | MOZ_DIAGNOSTIC_ASSERT(!mInfo); |
65 | 0 |
|
66 | 0 | RefPtr<ServiceWorkerManager> swm = ServiceWorkerManager::GetInstance(); |
67 | 0 | NS_ENSURE_TRUE_VOID(swm); |
68 | 0 |
|
69 | 0 | mInfo = swm->GetRegistration(mDescriptor.PrincipalInfo(), |
70 | 0 | mDescriptor.Scope()); |
71 | 0 | NS_ENSURE_TRUE_VOID(mInfo); |
72 | 0 |
|
73 | 0 | mInfo->AddInstance(this, mDescriptor); |
74 | 0 | mListeningForEvents = true; |
75 | 0 | } |
76 | | |
77 | | void |
78 | | ServiceWorkerRegistrationMainThread::StopListeningForEvents() |
79 | 0 | { |
80 | 0 | MOZ_ASSERT(NS_IsMainThread()); |
81 | 0 | if (!mListeningForEvents) { |
82 | 0 | return; |
83 | 0 | } |
84 | 0 | |
85 | 0 | MOZ_DIAGNOSTIC_ASSERT(mInfo); |
86 | 0 | mInfo->RemoveInstance(this); |
87 | 0 | mInfo = nullptr; |
88 | 0 |
|
89 | 0 | mListeningForEvents = false; |
90 | 0 | } |
91 | | |
92 | | void |
93 | | ServiceWorkerRegistrationMainThread::RegistrationRemovedInternal() |
94 | 0 | { |
95 | 0 | MOZ_ASSERT(NS_IsMainThread()); |
96 | 0 | // Its possible for the binding object to be collected while we the |
97 | 0 | // runnable to call this method is in the event queue. Double check |
98 | 0 | // whether there is still anything to do here. |
99 | 0 | if (mOuter) { |
100 | 0 | mOuter->RegistrationRemoved(); |
101 | 0 | } |
102 | 0 | StopListeningForEvents(); |
103 | 0 | } |
104 | | |
105 | | void |
106 | | ServiceWorkerRegistrationMainThread::UpdateState(const ServiceWorkerRegistrationDescriptor& aDescriptor) |
107 | 0 | { |
108 | 0 | NS_ENSURE_TRUE_VOID(mOuter); |
109 | 0 |
|
110 | 0 | nsIGlobalObject* global = mOuter->GetParentObject(); |
111 | 0 | NS_ENSURE_TRUE_VOID(global); |
112 | 0 |
|
113 | 0 | RefPtr<ServiceWorkerRegistrationMainThread> self = this; |
114 | 0 | nsCOMPtr<nsIRunnable> r = NS_NewRunnableFunction( |
115 | 0 | "ServiceWorkerRegistrationMainThread::UpdateState", |
116 | 0 | [self, desc = std::move(aDescriptor)] () mutable { |
117 | 0 | self->mDescriptor = std::move(desc); |
118 | 0 | NS_ENSURE_TRUE_VOID(self->mOuter); |
119 | 0 | self->mOuter->UpdateState(self->mDescriptor); |
120 | 0 | }); |
121 | 0 |
|
122 | 0 | Unused << |
123 | 0 | global->EventTargetFor(TaskCategory::Other)->Dispatch(r.forget(), |
124 | 0 | NS_DISPATCH_NORMAL); |
125 | 0 | } |
126 | | |
127 | | void |
128 | | ServiceWorkerRegistrationMainThread::RegistrationRemoved() |
129 | 0 | { |
130 | 0 | NS_ENSURE_TRUE_VOID(mOuter); |
131 | 0 |
|
132 | 0 | nsIGlobalObject* global = mOuter->GetParentObject(); |
133 | 0 | NS_ENSURE_TRUE_VOID(global); |
134 | 0 |
|
135 | 0 | // Queue a runnable to clean up the registration. This is necessary |
136 | 0 | // because there may be runnables in the event queue already to |
137 | 0 | // update the registration state. We want to let those run |
138 | 0 | // if possible before clearing our mOuter reference. |
139 | 0 | nsCOMPtr<nsIRunnable> r = NewRunnableMethod( |
140 | 0 | "ServiceWorkerRegistrationMainThread::RegistrationRemoved", |
141 | 0 | this, |
142 | 0 | &ServiceWorkerRegistrationMainThread::RegistrationRemovedInternal); |
143 | 0 |
|
144 | 0 | Unused << |
145 | 0 | global->EventTargetFor(TaskCategory::Other)->Dispatch(r.forget(), |
146 | 0 | NS_DISPATCH_NORMAL); |
147 | 0 | } |
148 | | |
149 | | bool |
150 | | ServiceWorkerRegistrationMainThread::MatchesDescriptor(const ServiceWorkerRegistrationDescriptor& aDescriptor) |
151 | 0 | { |
152 | 0 | return mOuter->MatchesDescriptor(aDescriptor); |
153 | 0 | } |
154 | | |
155 | | void |
156 | | ServiceWorkerRegistrationMainThread::SetServiceWorkerRegistration(ServiceWorkerRegistration* aReg) |
157 | 0 | { |
158 | 0 | MOZ_DIAGNOSTIC_ASSERT(aReg); |
159 | 0 | MOZ_DIAGNOSTIC_ASSERT(!mOuter); |
160 | 0 | mOuter = aReg; |
161 | 0 | StartListeningForEvents(); |
162 | 0 | } |
163 | | |
164 | | void |
165 | | ServiceWorkerRegistrationMainThread::ClearServiceWorkerRegistration(ServiceWorkerRegistration* aReg) |
166 | 0 | { |
167 | 0 | MOZ_ASSERT_IF(mOuter, mOuter == aReg); |
168 | 0 | StopListeningForEvents(); |
169 | 0 | mOuter = nullptr; |
170 | 0 | } |
171 | | |
172 | | namespace { |
173 | | |
174 | | void |
175 | | UpdateInternal(nsIPrincipal* aPrincipal, |
176 | | const nsACString& aScope, |
177 | | ServiceWorkerUpdateFinishCallback* aCallback) |
178 | 0 | { |
179 | 0 | MOZ_ASSERT(NS_IsMainThread()); |
180 | 0 | MOZ_ASSERT(aPrincipal); |
181 | 0 | MOZ_ASSERT(aCallback); |
182 | 0 |
|
183 | 0 | RefPtr<ServiceWorkerManager> swm = ServiceWorkerManager::GetInstance(); |
184 | 0 | if (!swm) { |
185 | 0 | // browser shutdown |
186 | 0 | return; |
187 | 0 | } |
188 | 0 | |
189 | 0 | swm->Update(aPrincipal, aScope, aCallback); |
190 | 0 | } |
191 | | |
192 | | class MainThreadUpdateCallback final : public ServiceWorkerUpdateFinishCallback |
193 | | { |
194 | | RefPtr<ServiceWorkerRegistrationPromise::Private> mPromise; |
195 | | |
196 | | ~MainThreadUpdateCallback() |
197 | 0 | { |
198 | 0 | mPromise->Reject(NS_ERROR_DOM_ABORT_ERR, __func__); |
199 | 0 | } |
200 | | |
201 | | public: |
202 | | MainThreadUpdateCallback() |
203 | | : mPromise(new ServiceWorkerRegistrationPromise::Private(__func__)) |
204 | 0 | { |
205 | 0 | } |
206 | | |
207 | | void |
208 | | UpdateSucceeded(ServiceWorkerRegistrationInfo* aRegistration) override |
209 | 0 | { |
210 | 0 | mPromise->Resolve(aRegistration->Descriptor(), __func__); |
211 | 0 | } |
212 | | |
213 | | void |
214 | | UpdateFailed(ErrorResult& aStatus) override |
215 | 0 | { |
216 | 0 | mPromise->Reject(std::move(aStatus), __func__); |
217 | 0 | } |
218 | | |
219 | | RefPtr<ServiceWorkerRegistrationPromise> |
220 | | Promise() const |
221 | 0 | { |
222 | 0 | return mPromise; |
223 | 0 | } |
224 | | }; |
225 | | |
226 | | class WorkerThreadUpdateCallback final : public ServiceWorkerUpdateFinishCallback |
227 | | { |
228 | | RefPtr<ThreadSafeWorkerRef> mWorkerRef; |
229 | | RefPtr<ServiceWorkerRegistrationPromise::Private> mPromise; |
230 | | |
231 | 0 | ~WorkerThreadUpdateCallback() = default; |
232 | | |
233 | | public: |
234 | | WorkerThreadUpdateCallback(RefPtr<ThreadSafeWorkerRef>&& aWorkerRef, |
235 | | ServiceWorkerRegistrationPromise::Private* aPromise) |
236 | | : mWorkerRef(std::move(aWorkerRef)) |
237 | | , mPromise(aPromise) |
238 | 0 | { |
239 | 0 | MOZ_ASSERT(NS_IsMainThread()); |
240 | 0 | } |
241 | | |
242 | | void |
243 | | UpdateSucceeded(ServiceWorkerRegistrationInfo* aRegistration) override |
244 | 0 | { |
245 | 0 | mPromise->Resolve(aRegistration->Descriptor(), __func__); |
246 | 0 | mWorkerRef = nullptr; |
247 | 0 | } |
248 | | |
249 | | void |
250 | | UpdateFailed(ErrorResult& aStatus) override |
251 | 0 | { |
252 | 0 | mPromise->Reject(std::move(aStatus), __func__); |
253 | 0 | mWorkerRef = nullptr; |
254 | 0 | } |
255 | | }; |
256 | | |
257 | | class SWRUpdateRunnable final : public Runnable |
258 | | { |
259 | | class TimerCallback final : public nsITimerCallback |
260 | | { |
261 | | RefPtr<ServiceWorkerPrivate> mPrivate; |
262 | | RefPtr<Runnable> mRunnable; |
263 | | |
264 | | public: |
265 | | TimerCallback(ServiceWorkerPrivate* aPrivate, |
266 | | Runnable* aRunnable) |
267 | | : mPrivate(aPrivate) |
268 | | , mRunnable(aRunnable) |
269 | 0 | { |
270 | 0 | MOZ_ASSERT(mPrivate); |
271 | 0 | MOZ_ASSERT(aRunnable); |
272 | 0 | } |
273 | | |
274 | | NS_IMETHOD |
275 | | Notify(nsITimer *aTimer) override |
276 | 0 | { |
277 | 0 | mRunnable->Run(); |
278 | 0 | mPrivate->RemoveISupports(aTimer); |
279 | 0 |
|
280 | 0 | return NS_OK; |
281 | 0 | } |
282 | | |
283 | | NS_DECL_THREADSAFE_ISUPPORTS |
284 | | |
285 | | private: |
286 | | ~TimerCallback() |
287 | 0 | { } |
288 | | }; |
289 | | |
290 | | public: |
291 | | SWRUpdateRunnable(StrongWorkerRef* aWorkerRef, |
292 | | ServiceWorkerRegistrationPromise::Private* aPromise, |
293 | | const ServiceWorkerDescriptor& aDescriptor) |
294 | | : Runnable("dom::SWRUpdateRunnable") |
295 | | , mMutex("SWRUpdateRunnable") |
296 | | , mWorkerRef(new ThreadSafeWorkerRef(aWorkerRef)) |
297 | | , mPromise(aPromise) |
298 | | , mDescriptor(aDescriptor) |
299 | | , mDelayed(false) |
300 | 0 | { |
301 | 0 | MOZ_DIAGNOSTIC_ASSERT(mWorkerRef); |
302 | 0 | MOZ_DIAGNOSTIC_ASSERT(mPromise); |
303 | 0 | } |
304 | | |
305 | | NS_IMETHOD |
306 | | Run() override |
307 | 0 | { |
308 | 0 | MOZ_ASSERT(NS_IsMainThread()); |
309 | 0 | ErrorResult result; |
310 | 0 |
|
311 | 0 | nsCOMPtr<nsIPrincipal> principal = mDescriptor.GetPrincipal(); |
312 | 0 | if (NS_WARN_IF(!principal)) { |
313 | 0 | mPromise->Reject(NS_ERROR_DOM_INVALID_STATE_ERR, __func__); |
314 | 0 | return NS_OK; |
315 | 0 | } |
316 | 0 | |
317 | 0 | RefPtr<ServiceWorkerManager> swm = ServiceWorkerManager::GetInstance(); |
318 | 0 | if (NS_WARN_IF(!swm)) { |
319 | 0 | mPromise->Reject(NS_ERROR_DOM_INVALID_STATE_ERR, __func__); |
320 | 0 | return NS_OK; |
321 | 0 | } |
322 | 0 | |
323 | 0 | // This will delay update jobs originating from a service worker thread. |
324 | 0 | // We don't currently handle ServiceWorkerRegistration.update() from other |
325 | 0 | // worker types. Also, we assume this registration matches self.registration |
326 | 0 | // on the service worker global. This is ok for now because service worker globals |
327 | 0 | // are the only worker contexts where we expose ServiceWorkerRegistration. |
328 | 0 | RefPtr<ServiceWorkerRegistrationInfo> registration = |
329 | 0 | swm->GetRegistration(principal, mDescriptor.Scope()); |
330 | 0 | if (NS_WARN_IF(!registration)) { |
331 | 0 | return NS_OK; |
332 | 0 | } |
333 | 0 | |
334 | 0 | RefPtr<ServiceWorkerInfo> worker = registration->GetByDescriptor(mDescriptor); |
335 | 0 | uint32_t delay = registration->GetUpdateDelay(); |
336 | 0 |
|
337 | 0 | // if we have a timer object, it means we've already been delayed once. |
338 | 0 | if (delay && !mDelayed) { |
339 | 0 | nsCOMPtr<nsITimerCallback> cb = new TimerCallback(worker->WorkerPrivate(), this); |
340 | 0 | Result<nsCOMPtr<nsITimer>, nsresult> result = |
341 | 0 | NS_NewTimerWithCallback(cb, delay, nsITimer::TYPE_ONE_SHOT, |
342 | 0 | SystemGroup::EventTargetFor(TaskCategory::Other)); |
343 | 0 |
|
344 | 0 | nsCOMPtr<nsITimer> timer = result.unwrapOr(nullptr); |
345 | 0 | if (NS_WARN_IF(!timer)) { |
346 | 0 | return NS_OK; |
347 | 0 | } |
348 | 0 | |
349 | 0 | mDelayed = true; |
350 | 0 |
|
351 | 0 | // We're storing the timer object on the calling service worker's private. |
352 | 0 | // ServiceWorkerPrivate will drop the reference if the worker terminates, |
353 | 0 | // which will cancel the timer. |
354 | 0 | if (!worker->WorkerPrivate()->MaybeStoreISupports(timer)) { |
355 | 0 | // The worker thread is already shutting down. Just cancel the timer |
356 | 0 | // and let the update runnable be destroyed. |
357 | 0 | timer->Cancel(); |
358 | 0 | return NS_OK; |
359 | 0 | } |
360 | 0 | |
361 | 0 | return NS_OK; |
362 | 0 | } |
363 | 0 | |
364 | 0 | RefPtr<ServiceWorkerRegistrationPromise::Private> promise; |
365 | 0 | { |
366 | 0 | MutexAutoLock lock(mMutex); |
367 | 0 | promise.swap(mPromise); |
368 | 0 | } |
369 | 0 |
|
370 | 0 | RefPtr<WorkerThreadUpdateCallback> cb = |
371 | 0 | new WorkerThreadUpdateCallback(std::move(mWorkerRef), promise); |
372 | 0 | UpdateInternal(principal, mDescriptor.Scope(), cb); |
373 | 0 |
|
374 | 0 | return NS_OK; |
375 | 0 | } |
376 | | |
377 | | private: |
378 | | ~SWRUpdateRunnable() |
379 | 0 | { |
380 | 0 | MutexAutoLock lock(mMutex); |
381 | 0 | if (mPromise) { |
382 | 0 | mPromise->Reject(NS_ERROR_DOM_INVALID_STATE_ERR, __func__); |
383 | 0 | } |
384 | 0 | } |
385 | | |
386 | | // Protects promise access across threads |
387 | | Mutex mMutex; |
388 | | |
389 | | RefPtr<ThreadSafeWorkerRef> mWorkerRef; |
390 | | RefPtr<ServiceWorkerRegistrationPromise::Private> mPromise; |
391 | | const ServiceWorkerDescriptor mDescriptor; |
392 | | bool mDelayed; |
393 | | }; |
394 | | |
395 | | NS_IMPL_ISUPPORTS(SWRUpdateRunnable::TimerCallback, nsITimerCallback) |
396 | | |
397 | | class UnregisterCallback final : public nsIServiceWorkerUnregisterCallback |
398 | | { |
399 | | RefPtr<GenericPromise::Private> mPromise; |
400 | | |
401 | | public: |
402 | | NS_DECL_ISUPPORTS |
403 | | |
404 | | UnregisterCallback() |
405 | | : mPromise(new GenericPromise::Private(__func__)) |
406 | 0 | { |
407 | 0 | } |
408 | | |
409 | | NS_IMETHOD |
410 | | UnregisterSucceeded(bool aState) override |
411 | 0 | { |
412 | 0 | mPromise->Resolve(aState, __func__); |
413 | 0 | return NS_OK; |
414 | 0 | } |
415 | | |
416 | | NS_IMETHOD |
417 | | UnregisterFailed() override |
418 | 0 | { |
419 | 0 | mPromise->Reject(NS_ERROR_DOM_SECURITY_ERR, __func__); |
420 | 0 | return NS_OK; |
421 | 0 | } |
422 | | |
423 | | RefPtr<GenericPromise> |
424 | | Promise() const |
425 | 0 | { |
426 | 0 | return mPromise; |
427 | 0 | } |
428 | | |
429 | | private: |
430 | 0 | ~UnregisterCallback() = default; |
431 | | }; |
432 | | |
433 | | NS_IMPL_ISUPPORTS(UnregisterCallback, nsIServiceWorkerUnregisterCallback) |
434 | | |
435 | | class WorkerUnregisterCallback final : public nsIServiceWorkerUnregisterCallback |
436 | | { |
437 | | RefPtr<ThreadSafeWorkerRef> mWorkerRef; |
438 | | RefPtr<GenericPromise::Private> mPromise; |
439 | | public: |
440 | | NS_DECL_ISUPPORTS |
441 | | |
442 | | WorkerUnregisterCallback(RefPtr<ThreadSafeWorkerRef>&& aWorkerRef, |
443 | | RefPtr<GenericPromise::Private>&& aPromise) |
444 | | : mWorkerRef(std::move(aWorkerRef)) |
445 | | , mPromise(std::move(aPromise)) |
446 | 0 | { |
447 | 0 | MOZ_DIAGNOSTIC_ASSERT(mWorkerRef); |
448 | 0 | MOZ_DIAGNOSTIC_ASSERT(mPromise); |
449 | 0 | } |
450 | | |
451 | | NS_IMETHOD |
452 | | UnregisterSucceeded(bool aState) override |
453 | 0 | { |
454 | 0 | mPromise->Resolve(aState, __func__); |
455 | 0 | mWorkerRef = nullptr; |
456 | 0 | return NS_OK; |
457 | 0 | } |
458 | | |
459 | | NS_IMETHOD |
460 | | UnregisterFailed() override |
461 | 0 | { |
462 | 0 | mPromise->Reject(NS_ERROR_DOM_SECURITY_ERR, __func__); |
463 | 0 | mWorkerRef = nullptr; |
464 | 0 | return NS_OK; |
465 | 0 | } |
466 | | |
467 | | private: |
468 | 0 | ~WorkerUnregisterCallback() = default; |
469 | | }; |
470 | | |
471 | | NS_IMPL_ISUPPORTS(WorkerUnregisterCallback, nsIServiceWorkerUnregisterCallback); |
472 | | |
473 | | /* |
474 | | * If the worker goes away, we still continue to unregister, but we don't try to |
475 | | * resolve the worker Promise (which doesn't exist by that point). |
476 | | */ |
477 | | class StartUnregisterRunnable final : public Runnable |
478 | | { |
479 | | // The promise is protected by the mutex. |
480 | | Mutex mMutex; |
481 | | |
482 | | RefPtr<ThreadSafeWorkerRef> mWorkerRef; |
483 | | RefPtr<GenericPromise::Private> mPromise; |
484 | | const ServiceWorkerRegistrationDescriptor mDescriptor; |
485 | | |
486 | | ~StartUnregisterRunnable() |
487 | 0 | { |
488 | 0 | MutexAutoLock lock(mMutex); |
489 | 0 | if (mPromise) { |
490 | 0 | mPromise->Reject(NS_ERROR_DOM_INVALID_STATE_ERR, __func__); |
491 | 0 | } |
492 | 0 | } |
493 | | |
494 | | public: |
495 | | StartUnregisterRunnable(StrongWorkerRef* aWorkerRef, |
496 | | GenericPromise::Private* aPromise, |
497 | | const ServiceWorkerRegistrationDescriptor& aDescriptor) |
498 | | : Runnable("dom::StartUnregisterRunnable") |
499 | | , mMutex("StartUnregisterRunnable") |
500 | | , mWorkerRef(new ThreadSafeWorkerRef(aWorkerRef)) |
501 | | , mPromise(aPromise) |
502 | | , mDescriptor(aDescriptor) |
503 | 0 | { |
504 | 0 | MOZ_DIAGNOSTIC_ASSERT(mWorkerRef); |
505 | 0 | MOZ_DIAGNOSTIC_ASSERT(mPromise); |
506 | 0 | } |
507 | | |
508 | | NS_IMETHOD |
509 | | Run() override |
510 | 0 | { |
511 | 0 | MOZ_ASSERT(NS_IsMainThread()); |
512 | 0 |
|
513 | 0 | nsCOMPtr<nsIPrincipal> principal = mDescriptor.GetPrincipal(); |
514 | 0 | if (!principal) { |
515 | 0 | mPromise->Reject(NS_ERROR_DOM_INVALID_STATE_ERR, __func__); |
516 | 0 | return NS_OK; |
517 | 0 | } |
518 | 0 | |
519 | 0 | nsCOMPtr<nsIServiceWorkerManager> swm = |
520 | 0 | mozilla::services::GetServiceWorkerManager(); |
521 | 0 | if (!swm) { |
522 | 0 | mPromise->Reject(NS_ERROR_DOM_INVALID_STATE_ERR, __func__); |
523 | 0 | return NS_OK; |
524 | 0 | } |
525 | 0 | |
526 | 0 | RefPtr<GenericPromise::Private> promise; |
527 | 0 | { |
528 | 0 | MutexAutoLock lock(mMutex); |
529 | 0 | promise = mPromise.forget(); |
530 | 0 | } |
531 | 0 |
|
532 | 0 | RefPtr<WorkerUnregisterCallback> cb = |
533 | 0 | new WorkerUnregisterCallback(std::move(mWorkerRef), std::move(promise)); |
534 | 0 |
|
535 | 0 | nsresult rv = swm->Unregister(principal, |
536 | 0 | cb, |
537 | 0 | NS_ConvertUTF8toUTF16(mDescriptor.Scope())); |
538 | 0 | if (NS_WARN_IF(NS_FAILED(rv))) { |
539 | 0 | mPromise->Reject(rv, __func__); |
540 | 0 | return NS_OK; |
541 | 0 | } |
542 | 0 | |
543 | 0 | return NS_OK; |
544 | 0 | } |
545 | | }; |
546 | | |
547 | | } // namespace |
548 | | |
549 | | void |
550 | | ServiceWorkerRegistrationMainThread::Update(ServiceWorkerRegistrationCallback&& aSuccessCB, |
551 | | ServiceWorkerFailureCallback&& aFailureCB) |
552 | 0 | { |
553 | 0 | MOZ_ASSERT(NS_IsMainThread()); |
554 | 0 | MOZ_DIAGNOSTIC_ASSERT(mOuter); |
555 | 0 |
|
556 | 0 | nsIGlobalObject* global = mOuter->GetParentObject(); |
557 | 0 | if (!global) { |
558 | 0 | aFailureCB(CopyableErrorResult(NS_ERROR_DOM_INVALID_STATE_ERR)); |
559 | 0 | return; |
560 | 0 | } |
561 | 0 | |
562 | 0 | nsCOMPtr<nsIPrincipal> principal = mDescriptor.GetPrincipal(); |
563 | 0 | if (!principal) { |
564 | 0 | aFailureCB(CopyableErrorResult(NS_ERROR_DOM_INVALID_STATE_ERR)); |
565 | 0 | return; |
566 | 0 | } |
567 | 0 | |
568 | 0 | RefPtr<MainThreadUpdateCallback> cb = new MainThreadUpdateCallback(); |
569 | 0 | UpdateInternal(principal, NS_ConvertUTF16toUTF8(mScope), cb); |
570 | 0 |
|
571 | 0 | auto holder = |
572 | 0 | MakeRefPtr<DOMMozPromiseRequestHolder<ServiceWorkerRegistrationPromise>>(global); |
573 | 0 |
|
574 | 0 | cb->Promise()->Then( |
575 | 0 | global->EventTargetFor(TaskCategory::Other), __func__, |
576 | 0 | [successCB = std::move(aSuccessCB), holder] (const ServiceWorkerRegistrationDescriptor& aDescriptor) { |
577 | 0 | holder->Complete(); |
578 | 0 | successCB(aDescriptor); |
579 | 0 | }, [failureCB = std::move(aFailureCB), holder] (const CopyableErrorResult& aRv) { |
580 | 0 | holder->Complete(); |
581 | 0 | failureCB(CopyableErrorResult(aRv)); |
582 | 0 | })->Track(*holder); |
583 | 0 | } |
584 | | |
585 | | void |
586 | | ServiceWorkerRegistrationMainThread::Unregister(ServiceWorkerBoolCallback&& aSuccessCB, |
587 | | ServiceWorkerFailureCallback&& aFailureCB) |
588 | 0 | { |
589 | 0 | MOZ_ASSERT(NS_IsMainThread()); |
590 | 0 | MOZ_DIAGNOSTIC_ASSERT(mOuter); |
591 | 0 |
|
592 | 0 | nsIGlobalObject* global = mOuter->GetParentObject(); |
593 | 0 | if (!global) { |
594 | 0 | aFailureCB(CopyableErrorResult(NS_ERROR_DOM_INVALID_STATE_ERR)); |
595 | 0 | return; |
596 | 0 | } |
597 | 0 | |
598 | 0 | nsCOMPtr<nsIServiceWorkerManager> swm = |
599 | 0 | mozilla::services::GetServiceWorkerManager(); |
600 | 0 | if (!swm) { |
601 | 0 | aFailureCB(CopyableErrorResult(NS_ERROR_DOM_INVALID_STATE_ERR)); |
602 | 0 | return; |
603 | 0 | } |
604 | 0 | |
605 | 0 | nsCOMPtr<nsIPrincipal> principal = mDescriptor.GetPrincipal(); |
606 | 0 | if (!principal) { |
607 | 0 | aFailureCB(CopyableErrorResult(NS_ERROR_DOM_INVALID_STATE_ERR)); |
608 | 0 | return; |
609 | 0 | } |
610 | 0 | |
611 | 0 | RefPtr<UnregisterCallback> cb = new UnregisterCallback(); |
612 | 0 |
|
613 | 0 | nsresult rv = swm->Unregister(principal, cb, |
614 | 0 | NS_ConvertUTF8toUTF16(mDescriptor.Scope())); |
615 | 0 | if (NS_FAILED(rv)) { |
616 | 0 | aFailureCB(CopyableErrorResult(rv)); |
617 | 0 | return; |
618 | 0 | } |
619 | 0 | |
620 | 0 | auto holder = MakeRefPtr<DOMMozPromiseRequestHolder<GenericPromise>>(global); |
621 | 0 |
|
622 | 0 | cb->Promise()->Then( |
623 | 0 | global->EventTargetFor(TaskCategory::Other), __func__, |
624 | 0 | [successCB = std::move(aSuccessCB), holder] (bool aResult) { |
625 | 0 | holder->Complete(); |
626 | 0 | successCB(aResult); |
627 | 0 | }, [failureCB = std::move(aFailureCB), holder] (nsresult aRv) { |
628 | 0 | holder->Complete(); |
629 | 0 | failureCB(CopyableErrorResult(aRv)); |
630 | 0 | })->Track(*holder); |
631 | 0 | } |
632 | | |
633 | | //////////////////////////////////////////////////// |
634 | | // Worker Thread implementation |
635 | | |
636 | | class WorkerListener final : public ServiceWorkerRegistrationListener |
637 | | { |
638 | | ServiceWorkerRegistrationDescriptor mDescriptor; |
639 | | nsMainThreadPtrHandle<ServiceWorkerRegistrationInfo> mInfo; |
640 | | nsCOMPtr<nsISerialEventTarget> mEventTarget; |
641 | | bool mListeningForEvents; |
642 | | |
643 | | // Set and unset on worker thread, used on main-thread and protected by mutex. |
644 | | ServiceWorkerRegistrationWorkerThread* mRegistration; |
645 | | |
646 | | Mutex mMutex; |
647 | | |
648 | | public: |
649 | | NS_INLINE_DECL_THREADSAFE_REFCOUNTING(WorkerListener, override) |
650 | | |
651 | | WorkerListener(ServiceWorkerRegistrationWorkerThread* aReg, |
652 | | const ServiceWorkerRegistrationDescriptor& aDescriptor, |
653 | | nsISerialEventTarget* aEventTarget) |
654 | | : mDescriptor(aDescriptor) |
655 | | , mEventTarget(aEventTarget) |
656 | | , mListeningForEvents(false) |
657 | | , mRegistration(aReg) |
658 | | , mMutex("WorkerListener::mMutex") |
659 | 0 | { |
660 | 0 | MOZ_ASSERT(IsCurrentThreadRunningWorker()); |
661 | 0 | MOZ_ASSERT(mEventTarget); |
662 | 0 | MOZ_ASSERT(mRegistration); |
663 | 0 | } |
664 | | |
665 | | void |
666 | | StartListeningForEvents() |
667 | 0 | { |
668 | 0 | MOZ_ASSERT(NS_IsMainThread()); |
669 | 0 | MOZ_DIAGNOSTIC_ASSERT(!mListeningForEvents); |
670 | 0 | MOZ_DIAGNOSTIC_ASSERT(!mInfo); |
671 | 0 |
|
672 | 0 | RefPtr<ServiceWorkerManager> swm = ServiceWorkerManager::GetInstance(); |
673 | 0 | NS_ENSURE_TRUE_VOID(swm); |
674 | 0 |
|
675 | 0 | RefPtr<ServiceWorkerRegistrationInfo> info = |
676 | 0 | swm->GetRegistration(mDescriptor.PrincipalInfo(), mDescriptor.Scope()); |
677 | 0 | NS_ENSURE_TRUE_VOID(info); |
678 | 0 |
|
679 | 0 | mInfo = new nsMainThreadPtrHolder<ServiceWorkerRegistrationInfo>( |
680 | 0 | "WorkerListener::mInfo", info); |
681 | 0 |
|
682 | 0 | mInfo->AddInstance(this, mDescriptor); |
683 | 0 | mListeningForEvents = true; |
684 | 0 | } |
685 | | |
686 | | void |
687 | | StopListeningForEvents() |
688 | 0 | { |
689 | 0 | MOZ_ASSERT(NS_IsMainThread()); |
690 | 0 |
|
691 | 0 | if (!mListeningForEvents) { |
692 | 0 | return; |
693 | 0 | } |
694 | 0 | |
695 | 0 | MOZ_DIAGNOSTIC_ASSERT(mInfo); |
696 | 0 | mInfo->RemoveInstance(this); |
697 | 0 | mListeningForEvents = false; |
698 | 0 | } |
699 | | |
700 | | // ServiceWorkerRegistrationListener |
701 | | void |
702 | | UpdateState(const ServiceWorkerRegistrationDescriptor& aDescriptor) override |
703 | 0 | { |
704 | 0 | MOZ_ASSERT(NS_IsMainThread()); |
705 | 0 |
|
706 | 0 | mDescriptor = aDescriptor; |
707 | 0 |
|
708 | 0 | nsCOMPtr<nsIRunnable> r = |
709 | 0 | NewCancelableRunnableMethod<ServiceWorkerRegistrationDescriptor>( |
710 | 0 | "WorkerListener::UpdateState", |
711 | 0 | this, |
712 | 0 | &WorkerListener::UpdateStateOnWorkerThread, |
713 | 0 | aDescriptor); |
714 | 0 |
|
715 | 0 | Unused << mEventTarget->Dispatch(r.forget(), NS_DISPATCH_NORMAL); |
716 | 0 | } |
717 | | |
718 | | void |
719 | | UpdateStateOnWorkerThread(const ServiceWorkerRegistrationDescriptor& aDescriptor) |
720 | 0 | { |
721 | 0 | MOZ_ASSERT(IsCurrentThreadRunningWorker()); |
722 | 0 | if (mRegistration) { |
723 | 0 | mRegistration->UpdateState(aDescriptor); |
724 | 0 | } |
725 | 0 | } |
726 | | |
727 | | void |
728 | | RegistrationRemoved() override; |
729 | | |
730 | | void |
731 | | GetScope(nsAString& aScope) const override |
732 | 0 | { |
733 | 0 | CopyUTF8toUTF16(mDescriptor.Scope(), aScope); |
734 | 0 | } |
735 | | |
736 | | bool |
737 | | MatchesDescriptor(const ServiceWorkerRegistrationDescriptor& aDescriptor) override |
738 | 0 | { |
739 | 0 | // TODO: Not implemented |
740 | 0 | return false; |
741 | 0 | } |
742 | | |
743 | | void |
744 | | ClearRegistration() |
745 | 0 | { |
746 | 0 | MOZ_ASSERT(IsCurrentThreadRunningWorker()); |
747 | 0 | MutexAutoLock lock(mMutex); |
748 | 0 | mRegistration = nullptr; |
749 | 0 | } |
750 | | |
751 | | private: |
752 | | ~WorkerListener() |
753 | 0 | { |
754 | 0 | MOZ_ASSERT(!mListeningForEvents); |
755 | 0 | } |
756 | | }; |
757 | | |
758 | | ServiceWorkerRegistrationWorkerThread::ServiceWorkerRegistrationWorkerThread(const ServiceWorkerRegistrationDescriptor& aDescriptor) |
759 | | : mOuter(nullptr) |
760 | | , mDescriptor(aDescriptor) |
761 | | , mScope(NS_ConvertUTF8toUTF16(aDescriptor.Scope())) |
762 | 0 | { |
763 | 0 | } |
764 | | |
765 | | ServiceWorkerRegistrationWorkerThread::~ServiceWorkerRegistrationWorkerThread() |
766 | 0 | { |
767 | 0 | MOZ_DIAGNOSTIC_ASSERT(!mListener); |
768 | 0 | MOZ_DIAGNOSTIC_ASSERT(!mOuter); |
769 | 0 | } |
770 | | |
771 | | void |
772 | | ServiceWorkerRegistrationWorkerThread::RegistrationRemoved() |
773 | 0 | { |
774 | 0 | // The SWM notifying us that the registration was removed on the MT may |
775 | 0 | // race with ClearServiceWorkerRegistration() on the worker thread. So |
776 | 0 | // double-check that mOuter is still valid. |
777 | 0 | if (mOuter) { |
778 | 0 | mOuter->RegistrationRemoved(); |
779 | 0 | } |
780 | 0 | } |
781 | | |
782 | | void |
783 | | ServiceWorkerRegistrationWorkerThread::SetServiceWorkerRegistration(ServiceWorkerRegistration* aReg) |
784 | 0 | { |
785 | 0 | MOZ_DIAGNOSTIC_ASSERT(aReg); |
786 | 0 | MOZ_DIAGNOSTIC_ASSERT(!mOuter); |
787 | 0 | mOuter = aReg; |
788 | 0 | InitListener(); |
789 | 0 | } |
790 | | |
791 | | void |
792 | | ServiceWorkerRegistrationWorkerThread::ClearServiceWorkerRegistration(ServiceWorkerRegistration* aReg) |
793 | 0 | { |
794 | 0 | MOZ_ASSERT_IF(mOuter, mOuter == aReg); |
795 | 0 | ReleaseListener(); |
796 | 0 | mOuter = nullptr; |
797 | 0 | } |
798 | | |
799 | | void |
800 | | ServiceWorkerRegistrationWorkerThread::Update(ServiceWorkerRegistrationCallback&& aSuccessCB, |
801 | | ServiceWorkerFailureCallback&& aFailureCB) |
802 | 0 | { |
803 | 0 | if (NS_WARN_IF(!mWorkerRef->GetPrivate())) { |
804 | 0 | aFailureCB(CopyableErrorResult(NS_ERROR_DOM_INVALID_STATE_ERR)); |
805 | 0 | return; |
806 | 0 | } |
807 | 0 | |
808 | 0 | RefPtr<StrongWorkerRef> workerRef = |
809 | 0 | StrongWorkerRef::Create(mWorkerRef->GetPrivate(), |
810 | 0 | "ServiceWorkerRegistration::Update"); |
811 | 0 | if (NS_WARN_IF(!workerRef)) { |
812 | 0 | aFailureCB(CopyableErrorResult(NS_ERROR_DOM_INVALID_STATE_ERR)); |
813 | 0 | return; |
814 | 0 | } |
815 | 0 | |
816 | 0 | nsIGlobalObject* global = workerRef->Private()->GlobalScope(); |
817 | 0 | if (NS_WARN_IF(!global)) { |
818 | 0 | aFailureCB(CopyableErrorResult(NS_ERROR_DOM_INVALID_STATE_ERR)); |
819 | 0 | return; |
820 | 0 | } |
821 | 0 | |
822 | 0 | // Eventually we need to support all workers, but for right now this |
823 | 0 | // code assumes we're on a service worker global as self.registration. |
824 | 0 | if (NS_WARN_IF(!workerRef->Private()->IsServiceWorker())) { |
825 | 0 | aFailureCB(CopyableErrorResult(NS_ERROR_DOM_INVALID_STATE_ERR)); |
826 | 0 | return; |
827 | 0 | } |
828 | 0 | |
829 | 0 | // Avoid infinite update loops by ignoring update() calls during top |
830 | 0 | // level script evaluation. See: |
831 | 0 | // https://github.com/slightlyoff/ServiceWorker/issues/800 |
832 | 0 | if (workerRef->Private()->IsLoadingWorkerScript()) { |
833 | 0 | aSuccessCB(mDescriptor); |
834 | 0 | return; |
835 | 0 | } |
836 | 0 | |
837 | 0 | auto promise = MakeRefPtr<ServiceWorkerRegistrationPromise::Private>(__func__); |
838 | 0 | auto holder = |
839 | 0 | MakeRefPtr<DOMMozPromiseRequestHolder<ServiceWorkerRegistrationPromise>>(global); |
840 | 0 |
|
841 | 0 | promise->Then( |
842 | 0 | global->EventTargetFor(TaskCategory::Other), __func__, |
843 | 0 | [successCB = std::move(aSuccessCB), holder] (const ServiceWorkerRegistrationDescriptor& aDescriptor) { |
844 | 0 | holder->Complete(); |
845 | 0 | successCB(aDescriptor); |
846 | 0 | }, [failureCB = std::move(aFailureCB), holder] (const CopyableErrorResult& aRv) { |
847 | 0 | holder->Complete(); |
848 | 0 | failureCB(CopyableErrorResult(aRv)); |
849 | 0 | })->Track(*holder); |
850 | 0 |
|
851 | 0 | RefPtr<SWRUpdateRunnable> r = |
852 | 0 | new SWRUpdateRunnable(workerRef, |
853 | 0 | promise, |
854 | 0 | workerRef->Private()->GetServiceWorkerDescriptor()); |
855 | 0 |
|
856 | 0 | nsresult rv = workerRef->Private()->DispatchToMainThread(r.forget()); |
857 | 0 | if (NS_FAILED(rv)) { |
858 | 0 | promise->Reject(NS_ERROR_DOM_INVALID_STATE_ERR, __func__); |
859 | 0 | return; |
860 | 0 | } |
861 | 0 | } |
862 | | |
863 | | void |
864 | | ServiceWorkerRegistrationWorkerThread::Unregister(ServiceWorkerBoolCallback&& aSuccessCB, |
865 | | ServiceWorkerFailureCallback&& aFailureCB) |
866 | 0 | { |
867 | 0 | if (NS_WARN_IF(!mWorkerRef->GetPrivate())) { |
868 | 0 | aFailureCB(CopyableErrorResult(NS_ERROR_DOM_INVALID_STATE_ERR)); |
869 | 0 | return; |
870 | 0 | } |
871 | 0 | |
872 | 0 | RefPtr<StrongWorkerRef> workerRef = |
873 | 0 | StrongWorkerRef::Create(mWorkerRef->GetPrivate(), __func__); |
874 | 0 | if (NS_WARN_IF(!workerRef)) { |
875 | 0 | aFailureCB(CopyableErrorResult(NS_ERROR_DOM_INVALID_STATE_ERR)); |
876 | 0 | return; |
877 | 0 | } |
878 | 0 | |
879 | 0 | // Eventually we need to support all workers, but for right now this |
880 | 0 | // code assumes we're on a service worker global as self.registration. |
881 | 0 | if (NS_WARN_IF(!workerRef->Private()->IsServiceWorker())) { |
882 | 0 | aFailureCB(CopyableErrorResult(NS_ERROR_DOM_INVALID_STATE_ERR)); |
883 | 0 | return; |
884 | 0 | } |
885 | 0 | |
886 | 0 | nsIGlobalObject* global = workerRef->Private()->GlobalScope(); |
887 | 0 | if (!global) { |
888 | 0 | aFailureCB(CopyableErrorResult(NS_ERROR_DOM_INVALID_STATE_ERR)); |
889 | 0 | return; |
890 | 0 | } |
891 | 0 | |
892 | 0 | auto promise = MakeRefPtr<GenericPromise::Private>(__func__); |
893 | 0 | auto holder = MakeRefPtr<DOMMozPromiseRequestHolder<GenericPromise>>(global); |
894 | 0 |
|
895 | 0 | promise->Then( |
896 | 0 | global->EventTargetFor(TaskCategory::Other), __func__, |
897 | 0 | [successCB = std::move(aSuccessCB), holder] (bool aResult) { |
898 | 0 | holder->Complete(); |
899 | 0 | successCB(aResult); |
900 | 0 | }, [failureCB = std::move(aFailureCB), holder] (nsresult aRv) { |
901 | 0 | holder->Complete(); |
902 | 0 | failureCB(CopyableErrorResult(aRv)); |
903 | 0 | })->Track(*holder); |
904 | 0 |
|
905 | 0 | RefPtr<StartUnregisterRunnable> r = |
906 | 0 | new StartUnregisterRunnable(workerRef, promise, mDescriptor); |
907 | 0 |
|
908 | 0 | nsresult rv = workerRef->Private()->DispatchToMainThread(r); |
909 | 0 | if (NS_FAILED(rv)) { |
910 | 0 | promise->Reject(NS_ERROR_DOM_INVALID_STATE_ERR, __func__); |
911 | 0 | return; |
912 | 0 | } |
913 | 0 | } |
914 | | |
915 | | void |
916 | | ServiceWorkerRegistrationWorkerThread::InitListener() |
917 | 0 | { |
918 | 0 | MOZ_ASSERT(!mListener); |
919 | 0 | WorkerPrivate* worker = GetCurrentThreadWorkerPrivate(); |
920 | 0 | MOZ_ASSERT(worker); |
921 | 0 | worker->AssertIsOnWorkerThread(); |
922 | 0 |
|
923 | 0 | RefPtr<ServiceWorkerRegistrationWorkerThread> self = this; |
924 | 0 | mWorkerRef = WeakWorkerRef::Create(worker, [self]() { |
925 | 0 | self->ReleaseListener(); |
926 | 0 |
|
927 | 0 | // Break the ref-cycle immediately when the worker thread starts to |
928 | 0 | // teardown. We must make sure its GC'd before the worker RuntimeService is |
929 | 0 | // destroyed. The WorkerListener may not be able to post a runnable |
930 | 0 | // clearing this value after shutdown begins and thus delaying cleanup too |
931 | 0 | // late. |
932 | 0 | self->mOuter = nullptr; |
933 | 0 | }); |
934 | 0 |
|
935 | 0 | if (NS_WARN_IF(!mWorkerRef)) { |
936 | 0 | return; |
937 | 0 | } |
938 | 0 | |
939 | 0 | mListener = new WorkerListener(this, mDescriptor, worker->HybridEventTarget()); |
940 | 0 |
|
941 | 0 | nsCOMPtr<nsIRunnable> r = |
942 | 0 | NewRunnableMethod("dom::WorkerListener::StartListeningForEvents", |
943 | 0 | mListener, |
944 | 0 | &WorkerListener::StartListeningForEvents); |
945 | 0 | MOZ_ALWAYS_SUCCEEDS(worker->DispatchToMainThread(r.forget())); |
946 | 0 | } |
947 | | |
948 | | void |
949 | | ServiceWorkerRegistrationWorkerThread::ReleaseListener() |
950 | 0 | { |
951 | 0 | if (!mListener) { |
952 | 0 | return; |
953 | 0 | } |
954 | 0 | |
955 | 0 | MOZ_ASSERT(IsCurrentThreadRunningWorker()); |
956 | 0 |
|
957 | 0 | mListener->ClearRegistration(); |
958 | 0 |
|
959 | 0 | nsCOMPtr<nsIRunnable> r = |
960 | 0 | NewCancelableRunnableMethod("dom::WorkerListener::StopListeningForEvents", |
961 | 0 | mListener, |
962 | 0 | &WorkerListener::StopListeningForEvents); |
963 | 0 | // Calling GetPrivate() is safe because this method is called when the |
964 | 0 | // WorkerRef is notified. |
965 | 0 | MOZ_ALWAYS_SUCCEEDS(mWorkerRef->GetPrivate()->DispatchToMainThread(r.forget())); |
966 | 0 |
|
967 | 0 | mListener = nullptr; |
968 | 0 | mWorkerRef = nullptr; |
969 | 0 | } |
970 | | |
971 | | void |
972 | | ServiceWorkerRegistrationWorkerThread::UpdateState(const ServiceWorkerRegistrationDescriptor& aDescriptor) |
973 | 0 | { |
974 | 0 | if (mOuter) { |
975 | 0 | mOuter->UpdateState(aDescriptor); |
976 | 0 | } |
977 | 0 | } |
978 | | |
979 | | class RegistrationRemovedWorkerRunnable final : public WorkerRunnable |
980 | | { |
981 | | RefPtr<WorkerListener> mListener; |
982 | | public: |
983 | | RegistrationRemovedWorkerRunnable(WorkerPrivate* aWorkerPrivate, |
984 | | WorkerListener* aListener) |
985 | | : WorkerRunnable(aWorkerPrivate) |
986 | | , mListener(aListener) |
987 | 0 | { |
988 | 0 | // Need this assertion for now since runnables which modify busy count can |
989 | 0 | // only be dispatched from parent thread to worker thread and we don't deal |
990 | 0 | // with nested workers. SW threads can't be nested. |
991 | 0 | MOZ_ASSERT(aWorkerPrivate->IsServiceWorker()); |
992 | 0 | } |
993 | | |
994 | | bool |
995 | | WorkerRun(JSContext* aCx, WorkerPrivate* aWorkerPrivate) override |
996 | 0 | { |
997 | 0 | MOZ_ASSERT(aWorkerPrivate); |
998 | 0 | aWorkerPrivate->AssertIsOnWorkerThread(); |
999 | 0 | mListener->RegistrationRemoved(); |
1000 | 0 | return true; |
1001 | 0 | } |
1002 | | }; |
1003 | | |
1004 | | void |
1005 | | WorkerListener::RegistrationRemoved() |
1006 | 0 | { |
1007 | 0 | MutexAutoLock lock(mMutex); |
1008 | 0 | if (!mRegistration) { |
1009 | 0 | return; |
1010 | 0 | } |
1011 | 0 | |
1012 | 0 | if (NS_IsMainThread()) { |
1013 | 0 | RefPtr<WorkerRunnable> r = |
1014 | 0 | new RegistrationRemovedWorkerRunnable(mRegistration->GetWorkerPrivate(lock), this); |
1015 | 0 | Unused << r->Dispatch(); |
1016 | 0 |
|
1017 | 0 | StopListeningForEvents(); |
1018 | 0 | return; |
1019 | 0 | } |
1020 | 0 | |
1021 | 0 | mRegistration->RegistrationRemoved(); |
1022 | 0 | } |
1023 | | |
1024 | | WorkerPrivate* |
1025 | | ServiceWorkerRegistrationWorkerThread::GetWorkerPrivate(const MutexAutoLock& aProofOfLock) |
1026 | 0 | { |
1027 | 0 | // In this case, calling GetUnsafePrivate() is ok because we have a proof of |
1028 | 0 | // mutex lock. |
1029 | 0 | MOZ_ASSERT(mWorkerRef && mWorkerRef->GetUnsafePrivate()); |
1030 | 0 | return mWorkerRef->GetUnsafePrivate(); |
1031 | 0 | } |
1032 | | |
1033 | | } // dom namespace |
1034 | | } // mozilla namespace |