[Storage] Blob Storage Refactoring pt 1:
[chromium-blink-merge.git] / content / browser / service_worker / service_worker_registration.cc
bloba4fac5c65873a9c9afe96c3b0e8b6fa92fe493b0
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(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 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(BrowserThread::CurrentlyOn(BrowserThread::IO));
77 return ServiceWorkerRegistrationInfo(
78 pattern(),
79 registration_id_,
80 GetVersionInfo(active_version_.get()),
81 GetVersionInfo(waiting_version_.get()),
82 GetVersionInfo(installing_version_.get()),
83 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;
159 if (!active_version() || !active_version()->HasControllee() ||
160 waiting_version()->skip_waiting())
161 ActivateWaitingVersion();
164 void ServiceWorkerRegistration::ClearWhenReady() {
165 DCHECK(context_);
166 if (is_uninstalling_)
167 return;
168 is_uninstalling_ = true;
170 context_->storage()->NotifyUninstallingRegistration(this);
171 context_->storage()->DeleteRegistration(
172 id(),
173 pattern().GetOrigin(),
174 base::Bind(&ServiceWorkerUtils::NoOpStatusCallback));
176 if (!active_version() || !active_version()->HasControllee())
177 Clear();
180 void ServiceWorkerRegistration::AbortPendingClear(
181 const StatusCallback& callback) {
182 DCHECK(context_);
183 if (!is_uninstalling()) {
184 callback.Run(SERVICE_WORKER_OK);
185 return;
187 is_uninstalling_ = false;
188 context_->storage()->NotifyDoneUninstallingRegistration(this);
190 scoped_refptr<ServiceWorkerVersion> most_recent_version =
191 waiting_version() ? waiting_version() : active_version();
192 DCHECK(most_recent_version.get());
193 context_->storage()->NotifyInstallingRegistration(this);
194 context_->storage()->StoreRegistration(
195 this,
196 most_recent_version.get(),
197 base::Bind(&ServiceWorkerRegistration::OnRestoreFinished,
198 this,
199 callback,
200 most_recent_version));
203 void ServiceWorkerRegistration::GetUserData(
204 const std::string& key,
205 const GetUserDataCallback& callback) {
206 DCHECK(context_);
207 context_->storage()->GetUserData(registration_id_, key, callback);
210 void ServiceWorkerRegistration::StoreUserData(
211 const std::string& key,
212 const std::string& data,
213 const StatusCallback& callback) {
214 DCHECK(context_);
215 context_->storage()->StoreUserData(
216 registration_id_, pattern().GetOrigin(), key, data, callback);
219 void ServiceWorkerRegistration::ClearUserData(
220 const std::string& key,
221 const StatusCallback& callback) {
222 DCHECK(context_);
223 context_->storage()->ClearUserData(registration_id_, key, callback);
226 void ServiceWorkerRegistration::OnNoControllees(ServiceWorkerVersion* version) {
227 DCHECK_EQ(active_version(), version);
228 if (is_uninstalling_)
229 Clear();
230 else if (should_activate_when_ready_)
231 ActivateWaitingVersion();
232 is_uninstalling_ = false;
233 should_activate_when_ready_ = false;
236 void ServiceWorkerRegistration::ActivateWaitingVersion() {
237 DCHECK(context_);
238 DCHECK(waiting_version());
239 DCHECK(should_activate_when_ready_);
240 should_activate_when_ready_ = false;
241 scoped_refptr<ServiceWorkerVersion> activating_version = waiting_version();
242 scoped_refptr<ServiceWorkerVersion> exiting_version = active_version();
244 if (activating_version->is_doomed() ||
245 activating_version->status() == ServiceWorkerVersion::REDUNDANT) {
246 return; // Activation is no longer relevant.
249 // "5. If exitingWorker is not null,
250 if (exiting_version.get()) {
251 // TODO(michaeln): should wait for events to be complete
252 // "1. Wait for exitingWorker to finish handling any in-progress requests."
253 // "2. Terminate exitingWorker."
254 exiting_version->StopWorker(
255 base::Bind(&ServiceWorkerUtils::NoOpStatusCallback));
256 // "3. Run the [[UpdateState]] algorithm passing exitingWorker and
257 // "redundant" as the arguments."
258 exiting_version->SetStatus(ServiceWorkerVersion::REDUNDANT);
261 // "6. Set serviceWorkerRegistration.activeWorker to activatingWorker."
262 // "7. Set serviceWorkerRegistration.waitingWorker to null."
263 SetActiveVersion(activating_version.get());
265 // "8. Run the [[UpdateState]] algorithm passing registration.activeWorker and
266 // "activating" as arguments."
267 activating_version->SetStatus(ServiceWorkerVersion::ACTIVATING);
268 // "9. Fire a simple event named controllerchange..."
269 if (activating_version->skip_waiting())
270 FOR_EACH_OBSERVER(Listener, listeners_, OnSkippedWaiting(this));
272 // "10. Queue a task to fire an event named activate..."
273 activating_version->DispatchActivateEvent(
274 base::Bind(&ServiceWorkerRegistration::OnActivateEventFinished,
275 this, activating_version));
278 void ServiceWorkerRegistration::OnActivateEventFinished(
279 ServiceWorkerVersion* activating_version,
280 ServiceWorkerStatusCode status) {
281 if (!context_ || activating_version != active_version())
282 return;
283 // TODO(kinuko,falken): For some error cases (e.g. ServiceWorker is
284 // unexpectedly terminated) we may want to retry sending the event again.
285 if (status != SERVICE_WORKER_OK) {
286 // "11. If activateFailed is true, then:..."
287 UnsetVersion(activating_version);
288 activating_version->Doom();
289 if (!waiting_version()) {
290 // Delete the records from the db.
291 context_->storage()->DeleteRegistration(
292 id(), pattern().GetOrigin(),
293 base::Bind(&ServiceWorkerRegistration::OnDeleteFinished, this));
294 // But not from memory if there is a version in the pipeline.
295 if (installing_version())
296 is_deleted_ = false;
298 return;
301 // "12. Run the [[UpdateState]] algorithm passing registration.activeWorker
302 // and "activated" as the arguments."
303 activating_version->SetStatus(ServiceWorkerVersion::ACTIVATED);
304 if (context_) {
305 context_->storage()->UpdateToActiveState(
306 this,
307 base::Bind(&ServiceWorkerUtils::NoOpStatusCallback));
311 void ServiceWorkerRegistration::OnDeleteFinished(
312 ServiceWorkerStatusCode status) {
313 // Intentionally empty completion callback, used to prevent
314 // |this| from being deleted until the storage method completes.
317 void ServiceWorkerRegistration::Clear() {
318 is_uninstalling_ = false;
319 is_uninstalled_ = true;
320 if (context_)
321 context_->storage()->NotifyDoneUninstallingRegistration(this);
323 ChangedVersionAttributesMask mask;
324 if (installing_version_.get()) {
325 installing_version_->Doom();
326 installing_version_ = NULL;
327 mask.add(ChangedVersionAttributesMask::INSTALLING_VERSION);
329 if (waiting_version_.get()) {
330 waiting_version_->Doom();
331 waiting_version_ = NULL;
332 mask.add(ChangedVersionAttributesMask::WAITING_VERSION);
334 if (active_version_.get()) {
335 active_version_->Doom();
336 active_version_->RemoveListener(this);
337 active_version_ = NULL;
338 mask.add(ChangedVersionAttributesMask::ACTIVE_VERSION);
340 if (mask.changed()) {
341 ServiceWorkerRegistrationInfo info = GetInfo();
342 FOR_EACH_OBSERVER(Listener, listeners_,
343 OnVersionAttributesChanged(this, mask, info));
346 FOR_EACH_OBSERVER(
347 Listener, listeners_, OnRegistrationFinishedUninstalling(this));
350 void ServiceWorkerRegistration::OnRestoreFinished(
351 const StatusCallback& callback,
352 scoped_refptr<ServiceWorkerVersion> version,
353 ServiceWorkerStatusCode status) {
354 if (!context_) {
355 callback.Run(SERVICE_WORKER_ERROR_ABORT);
356 return;
358 context_->storage()->NotifyDoneInstallingRegistration(
359 this, version.get(), status);
360 callback.Run(status);
363 } // namespace content