Re-subimission of https://codereview.chromium.org/1041213003/
[chromium-blink-merge.git] / content / browser / service_worker / service_worker_registration.cc
blob26d45285dec88a02aede08a2a5ff296807917566
1 // Copyright 2013 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
5 #include "content/browser/service_worker/service_worker_registration.h"
7 #include "content/browser/service_worker/service_worker_context_core.h"
8 #include "content/browser/service_worker/service_worker_info.h"
9 #include "content/browser/service_worker/service_worker_register_job.h"
10 #include "content/browser/service_worker/service_worker_utils.h"
11 #include "content/public/browser/browser_thread.h"
13 namespace content {
15 namespace {
17 ServiceWorkerVersionInfo GetVersionInfo(ServiceWorkerVersion* version) {
18 if (!version)
19 return ServiceWorkerVersionInfo();
20 return version->GetInfo();
23 } // namespace
25 ServiceWorkerRegistration::ServiceWorkerRegistration(
26 const GURL& pattern,
27 int64 registration_id,
28 base::WeakPtr<ServiceWorkerContextCore> context)
29 : pattern_(pattern),
30 registration_id_(registration_id),
31 is_deleted_(false),
32 is_uninstalling_(false),
33 is_uninstalled_(false),
34 should_activate_when_ready_(false),
35 resources_total_size_bytes_(0),
36 context_(context) {
37 DCHECK_CURRENTLY_ON(BrowserThread::IO);
38 DCHECK(context_);
39 context_->AddLiveRegistration(this);
42 ServiceWorkerRegistration::~ServiceWorkerRegistration() {
43 DCHECK_CURRENTLY_ON(BrowserThread::IO);
44 DCHECK(!listeners_.might_have_observers());
45 if (context_)
46 context_->RemoveLiveRegistration(registration_id_);
47 if (active_version())
48 active_version()->RemoveListener(this);
51 ServiceWorkerVersion* ServiceWorkerRegistration::GetNewestVersion() const {
52 if (installing_version())
53 return installing_version();
54 if (waiting_version())
55 return waiting_version();
56 return active_version();
59 void ServiceWorkerRegistration::AddListener(Listener* listener) {
60 listeners_.AddObserver(listener);
63 void ServiceWorkerRegistration::RemoveListener(Listener* listener) {
64 listeners_.RemoveObserver(listener);
67 void ServiceWorkerRegistration::NotifyRegistrationFailed() {
68 FOR_EACH_OBSERVER(Listener, listeners_, OnRegistrationFailed(this));
71 void ServiceWorkerRegistration::NotifyUpdateFound() {
72 FOR_EACH_OBSERVER(Listener, listeners_, OnUpdateFound(this));
75 ServiceWorkerRegistrationInfo ServiceWorkerRegistration::GetInfo() {
76 DCHECK_CURRENTLY_ON(BrowserThread::IO);
77 return ServiceWorkerRegistrationInfo(
78 pattern(), registration_id_,
79 is_deleted_ ? ServiceWorkerRegistrationInfo::IS_DELETED
80 : ServiceWorkerRegistrationInfo::IS_NOT_DELETED,
81 GetVersionInfo(active_version_.get()),
82 GetVersionInfo(waiting_version_.get()),
83 GetVersionInfo(installing_version_.get()), resources_total_size_bytes_);
86 void ServiceWorkerRegistration::SetActiveVersion(
87 ServiceWorkerVersion* version) {
88 should_activate_when_ready_ = false;
89 SetVersionInternal(version, &active_version_,
90 ChangedVersionAttributesMask::ACTIVE_VERSION);
93 void ServiceWorkerRegistration::SetWaitingVersion(
94 ServiceWorkerVersion* version) {
95 should_activate_when_ready_ = false;
96 SetVersionInternal(version, &waiting_version_,
97 ChangedVersionAttributesMask::WAITING_VERSION);
100 void ServiceWorkerRegistration::SetInstallingVersion(
101 ServiceWorkerVersion* version) {
102 SetVersionInternal(version, &installing_version_,
103 ChangedVersionAttributesMask::INSTALLING_VERSION);
106 void ServiceWorkerRegistration::UnsetVersion(ServiceWorkerVersion* version) {
107 if (!version)
108 return;
109 ChangedVersionAttributesMask mask;
110 UnsetVersionInternal(version, &mask);
111 if (mask.changed()) {
112 ServiceWorkerRegistrationInfo info = GetInfo();
113 FOR_EACH_OBSERVER(Listener, listeners_,
114 OnVersionAttributesChanged(this, mask, info));
118 void ServiceWorkerRegistration::SetVersionInternal(
119 ServiceWorkerVersion* version,
120 scoped_refptr<ServiceWorkerVersion>* data_member,
121 int change_flag) {
122 if (version == data_member->get())
123 return;
124 scoped_refptr<ServiceWorkerVersion> protect(version);
125 ChangedVersionAttributesMask mask;
126 if (version)
127 UnsetVersionInternal(version, &mask);
128 if (*data_member && *data_member == active_version_)
129 active_version_->RemoveListener(this);
130 *data_member = version;
131 if (active_version_.get() && active_version_.get() == version)
132 active_version_->AddListener(this);
133 mask.add(change_flag);
134 ServiceWorkerRegistrationInfo info = GetInfo();
135 FOR_EACH_OBSERVER(Listener, listeners_,
136 OnVersionAttributesChanged(this, mask, info));
139 void ServiceWorkerRegistration::UnsetVersionInternal(
140 ServiceWorkerVersion* version,
141 ChangedVersionAttributesMask* mask) {
142 DCHECK(version);
143 if (installing_version_.get() == version) {
144 installing_version_ = NULL;
145 mask->add(ChangedVersionAttributesMask::INSTALLING_VERSION);
146 } else if (waiting_version_.get() == version) {
147 waiting_version_ = NULL;
148 mask->add(ChangedVersionAttributesMask::WAITING_VERSION);
149 } else if (active_version_.get() == version) {
150 active_version_->RemoveListener(this);
151 active_version_ = NULL;
152 mask->add(ChangedVersionAttributesMask::ACTIVE_VERSION);
156 void ServiceWorkerRegistration::ActivateWaitingVersionWhenReady() {
157 DCHECK(waiting_version());
158 should_activate_when_ready_ = true;
160 if (!active_version() || !active_version()->HasControllee() ||
161 waiting_version()->skip_waiting())
162 ActivateWaitingVersion();
165 void ServiceWorkerRegistration::ClaimClients() {
166 DCHECK(context_);
167 DCHECK(active_version());
169 for (scoped_ptr<ServiceWorkerContextCore::ProviderHostIterator> it =
170 context_->GetProviderHostIterator();
171 !it->IsAtEnd(); it->Advance()) {
172 ServiceWorkerProviderHost* host = it->GetProviderHost();
173 if (host->IsHostToRunningServiceWorker())
174 continue;
175 if (host->controlling_version() == active_version())
176 continue;
177 if (host->MatchRegistration() == this)
178 host->ClaimedByRegistration(this);
182 void ServiceWorkerRegistration::ClearWhenReady() {
183 DCHECK(context_);
184 if (is_uninstalling_)
185 return;
186 is_uninstalling_ = true;
188 context_->storage()->NotifyUninstallingRegistration(this);
189 context_->storage()->DeleteRegistration(
190 id(),
191 pattern().GetOrigin(),
192 base::Bind(&ServiceWorkerUtils::NoOpStatusCallback));
194 if (!active_version() || !active_version()->HasControllee())
195 Clear();
198 void ServiceWorkerRegistration::AbortPendingClear(
199 const StatusCallback& callback) {
200 DCHECK(context_);
201 if (!is_uninstalling()) {
202 callback.Run(SERVICE_WORKER_OK);
203 return;
205 is_uninstalling_ = false;
206 context_->storage()->NotifyDoneUninstallingRegistration(this);
208 scoped_refptr<ServiceWorkerVersion> most_recent_version =
209 waiting_version() ? waiting_version() : active_version();
210 DCHECK(most_recent_version.get());
211 context_->storage()->NotifyInstallingRegistration(this);
212 context_->storage()->StoreRegistration(
213 this,
214 most_recent_version.get(),
215 base::Bind(&ServiceWorkerRegistration::OnRestoreFinished,
216 this,
217 callback,
218 most_recent_version));
221 void ServiceWorkerRegistration::GetUserData(
222 const std::string& key,
223 const GetUserDataCallback& callback) {
224 DCHECK(context_);
225 context_->storage()->GetUserData(registration_id_, key, callback);
228 void ServiceWorkerRegistration::StoreUserData(
229 const std::string& key,
230 const std::string& data,
231 const StatusCallback& callback) {
232 DCHECK(context_);
233 context_->storage()->StoreUserData(
234 registration_id_, pattern().GetOrigin(), key, data, callback);
237 void ServiceWorkerRegistration::ClearUserData(
238 const std::string& key,
239 const StatusCallback& callback) {
240 DCHECK(context_);
241 context_->storage()->ClearUserData(registration_id_, key, callback);
244 void ServiceWorkerRegistration::OnNoControllees(ServiceWorkerVersion* version) {
245 DCHECK_EQ(active_version(), version);
246 if (is_uninstalling_)
247 Clear();
248 else if (should_activate_when_ready_)
249 ActivateWaitingVersion();
250 is_uninstalling_ = false;
251 should_activate_when_ready_ = false;
254 void ServiceWorkerRegistration::ActivateWaitingVersion() {
255 DCHECK(context_);
256 DCHECK(waiting_version());
257 DCHECK(should_activate_when_ready_);
258 should_activate_when_ready_ = false;
259 scoped_refptr<ServiceWorkerVersion> activating_version = waiting_version();
260 scoped_refptr<ServiceWorkerVersion> exiting_version = active_version();
262 if (activating_version->is_doomed() ||
263 activating_version->status() == ServiceWorkerVersion::REDUNDANT) {
264 return; // Activation is no longer relevant.
267 // "5. If exitingWorker is not null,
268 if (exiting_version.get()) {
269 // TODO(michaeln): should wait for events to be complete
270 // "1. Wait for exitingWorker to finish handling any in-progress requests."
271 // "2. Terminate exitingWorker."
272 exiting_version->StopWorker(
273 base::Bind(&ServiceWorkerUtils::NoOpStatusCallback));
274 // "3. Run the [[UpdateState]] algorithm passing exitingWorker and
275 // "redundant" as the arguments."
276 exiting_version->SetStatus(ServiceWorkerVersion::REDUNDANT);
279 // "6. Set serviceWorkerRegistration.activeWorker to activatingWorker."
280 // "7. Set serviceWorkerRegistration.waitingWorker to null."
281 SetActiveVersion(activating_version.get());
283 // "8. Run the [[UpdateState]] algorithm passing registration.activeWorker and
284 // "activating" as arguments."
285 activating_version->SetStatus(ServiceWorkerVersion::ACTIVATING);
286 // "9. Fire a simple event named controllerchange..."
287 if (activating_version->skip_waiting())
288 FOR_EACH_OBSERVER(Listener, listeners_, OnSkippedWaiting(this));
290 // "10. Queue a task to fire an event named activate..."
291 activating_version->DispatchActivateEvent(
292 base::Bind(&ServiceWorkerRegistration::OnActivateEventFinished,
293 this, activating_version));
296 void ServiceWorkerRegistration::OnActivateEventFinished(
297 ServiceWorkerVersion* activating_version,
298 ServiceWorkerStatusCode status) {
299 if (!context_ || activating_version != active_version())
300 return;
301 // "If activateFailed is true, then:..."
302 if (status != SERVICE_WORKER_OK) {
303 // "Set registration's active worker to null." (The spec's step order may
304 // differ. It's OK because the other steps queue a task.)
305 UnsetVersion(activating_version);
307 // "Run the Update State algorithm passing registration's active worker and
308 // 'redundant' as the arguments."
309 activating_version->SetStatus(ServiceWorkerVersion::REDUNDANT);
311 // "For each service worker client client whose active worker is
312 // registration's active worker..." set the active worker to null.
313 for (scoped_ptr<ServiceWorkerContextCore::ProviderHostIterator> it =
314 context_->GetProviderHostIterator();
315 !it->IsAtEnd(); it->Advance()) {
316 ServiceWorkerProviderHost* host = it->GetProviderHost();
317 if (host->controlling_version() == activating_version)
318 host->NotifyControllerActivationFailed();
321 activating_version->Doom();
322 if (!waiting_version()) {
323 // Delete the records from the db.
324 context_->storage()->DeleteRegistration(
325 id(), pattern().GetOrigin(),
326 base::Bind(&ServiceWorkerRegistration::OnDeleteFinished, this));
327 // But not from memory if there is a version in the pipeline.
328 if (installing_version()) {
329 is_deleted_ = false;
330 } else {
331 is_uninstalled_ = true;
332 FOR_EACH_OBSERVER(Listener, listeners_, OnRegistrationFailed(this));
335 return;
338 // "Run the Update State algorithm passing registration's active worker and
339 // 'activated' as the arguments."
340 activating_version->SetStatus(ServiceWorkerVersion::ACTIVATED);
341 if (context_) {
342 context_->storage()->UpdateToActiveState(
343 this,
344 base::Bind(&ServiceWorkerUtils::NoOpStatusCallback));
348 void ServiceWorkerRegistration::OnDeleteFinished(
349 ServiceWorkerStatusCode status) {
350 // Intentionally empty completion callback, used to prevent
351 // |this| from being deleted until the storage method completes.
354 void ServiceWorkerRegistration::Clear() {
355 is_uninstalling_ = false;
356 is_uninstalled_ = true;
357 if (context_)
358 context_->storage()->NotifyDoneUninstallingRegistration(this);
360 ChangedVersionAttributesMask mask;
361 if (installing_version_.get()) {
362 installing_version_->Doom();
363 installing_version_ = NULL;
364 mask.add(ChangedVersionAttributesMask::INSTALLING_VERSION);
366 if (waiting_version_.get()) {
367 waiting_version_->Doom();
368 waiting_version_ = NULL;
369 mask.add(ChangedVersionAttributesMask::WAITING_VERSION);
371 if (active_version_.get()) {
372 active_version_->Doom();
373 active_version_->RemoveListener(this);
374 active_version_ = NULL;
375 mask.add(ChangedVersionAttributesMask::ACTIVE_VERSION);
377 if (mask.changed()) {
378 ServiceWorkerRegistrationInfo info = GetInfo();
379 FOR_EACH_OBSERVER(Listener, listeners_,
380 OnVersionAttributesChanged(this, mask, info));
383 FOR_EACH_OBSERVER(
384 Listener, listeners_, OnRegistrationFinishedUninstalling(this));
387 void ServiceWorkerRegistration::OnRestoreFinished(
388 const StatusCallback& callback,
389 scoped_refptr<ServiceWorkerVersion> version,
390 ServiceWorkerStatusCode status) {
391 if (!context_) {
392 callback.Run(SERVICE_WORKER_ERROR_ABORT);
393 return;
395 context_->storage()->NotifyDoneInstallingRegistration(
396 this, version.get(), status);
397 callback.Run(status);
400 } // namespace content