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