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_register_job.h"
9 #include "base/message_loop/message_loop.h"
10 #include "content/browser/service_worker/service_worker_job_coordinator.h"
11 #include "content/browser/service_worker/service_worker_registration.h"
16 static void RunSoon(const base::Closure
& closure
) {
17 base::MessageLoop::current()->PostTask(FROM_HERE
, closure
);
20 ServiceWorkerRegisterJob::ServiceWorkerRegisterJob(
21 ServiceWorkerStorage
* storage
,
22 EmbeddedWorkerRegistry
* worker_registry
,
23 ServiceWorkerJobCoordinator
* coordinator
,
25 const GURL
& script_url
,
26 RegistrationType type
)
28 worker_registry_(worker_registry
),
29 coordinator_(coordinator
),
31 script_url_(script_url
),
33 weak_factory_(this) {}
35 ServiceWorkerRegisterJob::~ServiceWorkerRegisterJob() {}
37 void ServiceWorkerRegisterJob::AddCallback(const RegistrationCallback
& callback
,
39 // if we've created a pending version, associate source_provider it with
40 // that, otherwise queue it up
41 callbacks_
.push_back(callback
);
42 DCHECK(process_id
!= -1);
43 if (pending_version_
) {
44 pending_version_
->AddProcessToWorker(process_id
);
46 pending_process_ids_
.push_back(process_id
);
50 void ServiceWorkerRegisterJob::Start() {
51 if (type_
== REGISTER
)
57 bool ServiceWorkerRegisterJob::Equals(ServiceWorkerRegisterJob
* job
) {
58 return job
->type_
== type_
&&
59 (type_
== ServiceWorkerRegisterJob::UNREGISTER
||
60 job
->script_url_
== script_url_
);
63 void ServiceWorkerRegisterJob::StartRegister() {
64 // Set up a chain of callbacks, in reverse order. Each of these
65 // callbacks may be called asynchronously by the previous callback.
66 StatusCallback
finish_registration(base::Bind(
67 &ServiceWorkerRegisterJob::Complete
, weak_factory_
.GetWeakPtr()));
69 StatusCallback
start_worker(
70 base::Bind(&ServiceWorkerRegisterJob::StartWorkerAndContinue
,
71 weak_factory_
.GetWeakPtr(),
72 finish_registration
));
74 StatusCallback
register_new(
75 base::Bind(&ServiceWorkerRegisterJob::RegisterPatternAndContinue
,
76 weak_factory_
.GetWeakPtr(),
79 ServiceWorkerStorage::FindRegistrationCallback
unregister_old(
80 base::Bind(&ServiceWorkerRegisterJob::UnregisterPatternAndContinue
,
81 weak_factory_
.GetWeakPtr(),
84 storage_
->FindRegistrationForPattern(pattern_
, unregister_old
);
87 void ServiceWorkerRegisterJob::StartUnregister() {
88 // Set up a chain of callbacks, in reverse order. Each of these
89 // callbacks may be called asynchronously by the previous callback.
90 StatusCallback
finish_unregistration(
91 base::Bind(&ServiceWorkerRegisterJob::Complete
,
92 weak_factory_
.GetWeakPtr()));
94 ServiceWorkerStorage::FindRegistrationCallback
unregister(
95 base::Bind(&ServiceWorkerRegisterJob::UnregisterPatternAndContinue
,
96 weak_factory_
.GetWeakPtr(),
97 finish_unregistration
));
99 storage_
->FindRegistrationForPattern(pattern_
, unregister
);
102 void ServiceWorkerRegisterJob::StartWorkerAndContinue(
103 const StatusCallback
& callback
,
104 ServiceWorkerStatusCode status
) {
105 DCHECK(registration_
);
106 if (registration_
->active_version()) {
107 // We have an active version, so we can complete immediately, even
108 // if the service worker isn't running.
109 callback
.Run(SERVICE_WORKER_OK
);
113 pending_version_
= new ServiceWorkerVersion(
114 registration_
, worker_registry_
, registration_
->next_version_id());
115 for (std::vector
<int>::const_iterator it
= pending_process_ids_
.begin();
116 it
!= pending_process_ids_
.end();
118 pending_version_
->AddProcessToWorker(*it
);
120 // The callback to watch "installation" actually fires as soon as
121 // the worker is up and running, just before the install event is
122 // dispatched. The job will continue to run even though the main
123 // callback has executed.
124 pending_version_
->StartWorker(callback
);
126 // TODO(alecflett): Don't set the active version until just before
127 // the activate event is dispatched.
128 registration_
->set_active_version(pending_version_
);
131 void ServiceWorkerRegisterJob::RegisterPatternAndContinue(
132 const StatusCallback
& callback
,
133 ServiceWorkerStatusCode previous_status
) {
134 if (previous_status
== SERVICE_WORKER_ERROR_EXISTS
) {
135 // Registration already exists, call to the next step.
136 RunSoon(base::Bind(callback
, SERVICE_WORKER_OK
));
140 if (previous_status
!= SERVICE_WORKER_OK
) {
142 registration_
= NULL
;
143 Complete(previous_status
);
147 DCHECK(!registration_
);
148 registration_
= new ServiceWorkerRegistration(pattern_
, script_url_
,
149 storage_
->NewRegistrationId());
150 storage_
->StoreRegistration(registration_
.get(), callback
);
153 void ServiceWorkerRegisterJob::UnregisterPatternAndContinue(
154 const StatusCallback
& callback
,
155 ServiceWorkerStatusCode previous_status
,
156 const scoped_refptr
<ServiceWorkerRegistration
>& previous_registration
) {
157 if (previous_status
== SERVICE_WORKER_OK
&&
158 (type_
== UNREGISTER
||
159 previous_registration
->script_url() != script_url_
)) {
160 // It's unregister, or we have conflicting registration.
161 // Unregister it and continue to the next step.
162 previous_registration
->Shutdown();
163 storage_
->DeleteRegistration(pattern_
, callback
);
167 if (previous_status
== SERVICE_WORKER_ERROR_NOT_FOUND
) {
168 // The previous registration does not exist, which is ok.
169 RunSoon(base::Bind(callback
, SERVICE_WORKER_OK
));
173 if (previous_status
== SERVICE_WORKER_OK
) {
174 // We have an existing registration.
175 registration_
= previous_registration
;
176 RunSoon(base::Bind(callback
, SERVICE_WORKER_ERROR_EXISTS
));
180 RunSoon(base::Bind(callback
, previous_status
));
183 void ServiceWorkerRegisterJob::Complete(ServiceWorkerStatusCode status
) {
184 for (std::vector
<RegistrationCallback
>::iterator it
= callbacks_
.begin();
185 it
!= callbacks_
.end();
187 it
->Run(status
, registration_
);
189 coordinator_
->FinishJob(pattern_
, this);
192 } // namespace content