Minor ServiceWorker cleanup. The Registration.Clear method potentially generated...
[chromium-blink-merge.git] / content / browser / service_worker / service_worker_registration.cc
blobce5686381e8009f90565288ad05e72d0f52d0433
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 const GURL& script_url,
28 int64 registration_id,
29 base::WeakPtr<ServiceWorkerContextCore> context)
30 : pattern_(pattern),
31 script_url_(script_url),
32 registration_id_(registration_id),
33 is_deleted_(false),
34 is_uninstalling_(false),
35 should_activate_when_ready_(false),
36 context_(context) {
37 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
38 DCHECK(context_);
39 context_->AddLiveRegistration(this);
42 ServiceWorkerRegistration::~ServiceWorkerRegistration() {
43 DCHECK(BrowserThread::CurrentlyOn(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 void ServiceWorkerRegistration::AddListener(Listener* listener) {
52 listeners_.AddObserver(listener);
55 void ServiceWorkerRegistration::RemoveListener(Listener* listener) {
56 listeners_.RemoveObserver(listener);
59 void ServiceWorkerRegistration::NotifyRegistrationFailed() {
60 FOR_EACH_OBSERVER(Listener, listeners_, OnRegistrationFailed(this));
63 ServiceWorkerRegistrationInfo ServiceWorkerRegistration::GetInfo() {
64 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
65 return ServiceWorkerRegistrationInfo(
66 script_url(),
67 pattern(),
68 registration_id_,
69 GetVersionInfo(active_version_),
70 GetVersionInfo(waiting_version_),
71 GetVersionInfo(installing_version_));
74 void ServiceWorkerRegistration::SetActiveVersion(
75 ServiceWorkerVersion* version) {
76 should_activate_when_ready_ = false;
77 SetVersionInternal(version, &active_version_,
78 ChangedVersionAttributesMask::ACTIVE_VERSION);
81 void ServiceWorkerRegistration::SetWaitingVersion(
82 ServiceWorkerVersion* version) {
83 should_activate_when_ready_ = false;
84 SetVersionInternal(version, &waiting_version_,
85 ChangedVersionAttributesMask::WAITING_VERSION);
88 void ServiceWorkerRegistration::SetInstallingVersion(
89 ServiceWorkerVersion* version) {
90 SetVersionInternal(version, &installing_version_,
91 ChangedVersionAttributesMask::INSTALLING_VERSION);
94 void ServiceWorkerRegistration::UnsetVersion(ServiceWorkerVersion* version) {
95 if (!version)
96 return;
97 ChangedVersionAttributesMask mask;
98 UnsetVersionInternal(version, &mask);
99 if (mask.changed()) {
100 ServiceWorkerRegistrationInfo info = GetInfo();
101 FOR_EACH_OBSERVER(Listener, listeners_,
102 OnVersionAttributesChanged(this, mask, info));
106 void ServiceWorkerRegistration::SetVersionInternal(
107 ServiceWorkerVersion* version,
108 scoped_refptr<ServiceWorkerVersion>* data_member,
109 int change_flag) {
110 if (version == data_member->get())
111 return;
112 scoped_refptr<ServiceWorkerVersion> protect(version);
113 ChangedVersionAttributesMask mask;
114 if (version)
115 UnsetVersionInternal(version, &mask);
116 *data_member = version;
117 if (active_version_ && active_version_ == version)
118 active_version_->AddListener(this);
119 mask.add(change_flag);
120 ServiceWorkerRegistrationInfo info = GetInfo();
121 FOR_EACH_OBSERVER(Listener, listeners_,
122 OnVersionAttributesChanged(this, mask, info));
125 void ServiceWorkerRegistration::UnsetVersionInternal(
126 ServiceWorkerVersion* version,
127 ChangedVersionAttributesMask* mask) {
128 DCHECK(version);
129 if (installing_version_ == version) {
130 installing_version_ = NULL;
131 mask->add(ChangedVersionAttributesMask::INSTALLING_VERSION);
132 } else if (waiting_version_ == version) {
133 waiting_version_ = NULL;
134 mask->add(ChangedVersionAttributesMask::WAITING_VERSION);
135 } else if (active_version_ == version) {
136 active_version_->RemoveListener(this);
137 active_version_ = NULL;
138 mask->add(ChangedVersionAttributesMask::ACTIVE_VERSION);
142 void ServiceWorkerRegistration::ActivateWaitingVersionWhenReady() {
143 DCHECK(waiting_version());
144 should_activate_when_ready_ = true;
145 if (!active_version() || !active_version()->HasControllee())
146 ActivateWaitingVersion();
149 void ServiceWorkerRegistration::ClearWhenReady() {
150 DCHECK(context_);
151 if (is_uninstalling_)
152 return;
153 is_uninstalling_ = true;
155 context_->storage()->NotifyUninstallingRegistration(this);
156 context_->storage()->DeleteRegistration(
157 id(),
158 script_url().GetOrigin(),
159 base::Bind(&ServiceWorkerUtils::NoOpStatusCallback));
161 if (!active_version() || !active_version()->HasControllee())
162 Clear();
165 void ServiceWorkerRegistration::AbortPendingClear() {
166 DCHECK(context_);
167 if (!is_uninstalling())
168 return;
169 is_uninstalling_ = false;
170 context_->storage()->NotifyDoneUninstallingRegistration(this);
172 scoped_refptr<ServiceWorkerVersion> most_recent_version =
173 waiting_version() ? waiting_version() : active_version();
174 DCHECK(most_recent_version);
175 context_->storage()->NotifyInstallingRegistration(this);
176 context_->storage()->StoreRegistration(
177 this,
178 most_recent_version,
179 base::Bind(&ServiceWorkerRegistration::OnStoreFinished,
180 this,
181 most_recent_version));
184 void ServiceWorkerRegistration::OnNoControllees(ServiceWorkerVersion* version) {
185 DCHECK_EQ(active_version(), version);
186 if (is_uninstalling_)
187 Clear();
188 else if (should_activate_when_ready_)
189 ActivateWaitingVersion();
190 is_uninstalling_ = false;
191 should_activate_when_ready_ = false;
194 void ServiceWorkerRegistration::ActivateWaitingVersion() {
195 DCHECK(context_);
196 DCHECK(waiting_version());
197 DCHECK(should_activate_when_ready_);
198 should_activate_when_ready_ = false;
199 scoped_refptr<ServiceWorkerVersion> activating_version = waiting_version();
200 scoped_refptr<ServiceWorkerVersion> exiting_version = active_version();
202 if (activating_version->is_doomed() ||
203 activating_version->status() == ServiceWorkerVersion::REDUNDANT) {
204 return; // Activation is no longer relevant.
207 // "4. If exitingWorker is not null,
208 if (exiting_version) {
209 DCHECK(!exiting_version->HasControllee());
210 // TODO(michaeln): should wait for events to be complete
211 // "1. Wait for exitingWorker to finish handling any in-progress requests."
212 // "2. Terminate exitingWorker."
213 exiting_version->StopWorker(
214 base::Bind(&ServiceWorkerUtils::NoOpStatusCallback));
215 // "3. Run the [[UpdateState]] algorithm passing exitingWorker and
216 // "redundant" as the arguments."
217 exiting_version->SetStatus(ServiceWorkerVersion::REDUNDANT);
220 // "5. Set serviceWorkerRegistration.activeWorker to activatingWorker."
221 // "6. Set serviceWorkerRegistration.waitingWorker to null."
222 SetActiveVersion(activating_version);
224 // "7. Run the [[UpdateState]] algorithm passing registration.activeWorker and
225 // "activating" as arguments."
226 activating_version->SetStatus(ServiceWorkerVersion::ACTIVATING);
228 // TODO(nhiroki): "8. Fire a simple event named controllerchange..."
230 // "9. Queue a task to fire an event named activate..."
231 activating_version->DispatchActivateEvent(
232 base::Bind(&ServiceWorkerRegistration::OnActivateEventFinished,
233 this, activating_version));
236 void ServiceWorkerRegistration::OnActivateEventFinished(
237 ServiceWorkerVersion* activating_version,
238 ServiceWorkerStatusCode status) {
239 if (!context_ || activating_version != active_version())
240 return;
241 // TODO(kinuko,falken): For some error cases (e.g. ServiceWorker is
242 // unexpectedly terminated) we may want to retry sending the event again.
243 if (status != SERVICE_WORKER_OK) {
244 // "11. If activateFailed is true, then:..."
245 UnsetVersion(activating_version);
246 activating_version->Doom();
247 if (!waiting_version()) {
248 // Delete the records from the db.
249 context_->storage()->DeleteRegistration(
250 id(), script_url().GetOrigin(),
251 base::Bind(&ServiceWorkerRegistration::OnDeleteFinished, this));
252 // But not from memory if there is a version in the pipeline.
253 if (installing_version())
254 is_deleted_ = false;
256 return;
259 // "12. Run the [[UpdateState]] algorithm passing registration.activeWorker
260 // and "activated" as the arguments."
261 activating_version->SetStatus(ServiceWorkerVersion::ACTIVATED);
262 if (context_) {
263 context_->storage()->UpdateToActiveState(
264 this,
265 base::Bind(&ServiceWorkerUtils::NoOpStatusCallback));
269 void ServiceWorkerRegistration::OnDeleteFinished(
270 ServiceWorkerStatusCode status) {
271 // Intentionally empty completion callback, used to prevent
272 // |this| from being deleted until the storage method completes.
275 void ServiceWorkerRegistration::Clear() {
276 context_->storage()->NotifyDoneUninstallingRegistration(this);
278 ChangedVersionAttributesMask mask;
279 if (installing_version_) {
280 installing_version_->Doom();
281 installing_version_ = NULL;
282 mask.add(ChangedVersionAttributesMask::INSTALLING_VERSION);
284 if (waiting_version_) {
285 waiting_version_->Doom();
286 waiting_version_ = NULL;
287 mask.add(ChangedVersionAttributesMask::WAITING_VERSION);
289 if (active_version_) {
290 active_version_->Doom();
291 active_version_->RemoveListener(this);
292 active_version_ = NULL;
293 mask.add(ChangedVersionAttributesMask::ACTIVE_VERSION);
295 if (mask.changed()) {
296 ServiceWorkerRegistrationInfo info = GetInfo();
297 FOR_EACH_OBSERVER(Listener, listeners_,
298 OnVersionAttributesChanged(this, mask, info));
302 void ServiceWorkerRegistration::OnStoreFinished(
303 scoped_refptr<ServiceWorkerVersion> version,
304 ServiceWorkerStatusCode status) {
305 if (!context_)
306 return;
307 context_->storage()->NotifyDoneInstallingRegistration(
308 this, version.get(), status);
311 } // namespace content