OLD | NEW |
---|---|
1 // Copyright 2013 The Chromium Authors. All rights reserved. | 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 | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 #include "content/browser/service_worker/service_worker_register_job.h" | 5 #include "content/browser/service_worker/service_worker_register_job.h" |
6 | 6 |
7 #include <vector> | 7 #include <vector> |
8 | 8 |
9 #include "content/browser/service_worker/service_worker_context_core.h" | 9 #include "content/browser/service_worker/service_worker_context_core.h" |
10 #include "content/browser/service_worker/service_worker_job_coordinator.h" | 10 #include "content/browser/service_worker/service_worker_job_coordinator.h" |
11 #include "content/browser/service_worker/service_worker_registration.h" | 11 #include "content/browser/service_worker/service_worker_registration.h" |
12 #include "content/browser/service_worker/service_worker_storage.h" | 12 #include "content/browser/service_worker/service_worker_storage.h" |
13 | 13 |
14 namespace content { | 14 namespace content { |
15 | 15 |
16 typedef ServiceWorkerRegisterJobBase::RegistrationJobType RegistrationJobType; | 16 typedef ServiceWorkerRegisterJobBase::RegistrationJobType RegistrationJobType; |
17 | 17 |
18 ServiceWorkerRegisterJob::ServiceWorkerRegisterJob( | 18 ServiceWorkerRegisterJob::ServiceWorkerRegisterJob( |
19 base::WeakPtr<ServiceWorkerContextCore> context, | 19 base::WeakPtr<ServiceWorkerContextCore> context, |
20 const GURL& pattern, | 20 const GURL& pattern, |
21 const GURL& script_url) | 21 const GURL& script_url) |
22 : context_(context), | 22 : context_(context), |
23 pattern_(pattern), | 23 pattern_(pattern), |
24 script_url_(script_url), | 24 script_url_(script_url), |
25 phase_(INITIAL), | |
25 weak_factory_(this) {} | 26 weak_factory_(this) {} |
26 | 27 |
27 ServiceWorkerRegisterJob::~ServiceWorkerRegisterJob() {} | 28 ServiceWorkerRegisterJob::~ServiceWorkerRegisterJob() {} |
28 | 29 |
29 void ServiceWorkerRegisterJob::AddCallback(const RegistrationCallback& callback, | 30 void ServiceWorkerRegisterJob::AddCallback(const RegistrationCallback& callback, |
30 int process_id) { | 31 int process_id) { |
31 // If we've created a pending version, associate source_provider it with that, | 32 // If we've created a pending version, associate source_provider it with that, |
32 // otherwise queue it up. | 33 // otherwise queue it up. |
33 callbacks_.push_back(callback); | 34 callbacks_.push_back(callback); |
34 DCHECK_NE(-1, process_id); | 35 DCHECK_NE(-1, process_id); |
35 if (pending_version_) { | 36 if (phase_ >= UPDATE && pending_version()) { |
36 pending_version_->AddProcessToWorker(process_id); | 37 pending_version()->AddProcessToWorker(process_id); |
37 } else { | 38 } else { |
38 pending_process_ids_.push_back(process_id); | 39 pending_process_ids_.push_back(process_id); |
39 } | 40 } |
40 } | 41 } |
41 | 42 |
42 void ServiceWorkerRegisterJob::Start() { | 43 void ServiceWorkerRegisterJob::Start() { |
44 phase_ = START; | |
dominicc (has gone to gerrit)
2014/04/09 00:09:58
It would be nice to have SetPhase which DCHECKs th
falken
2014/04/09 01:33:20
Done.
| |
43 context_->storage()->FindRegistrationForPattern( | 45 context_->storage()->FindRegistrationForPattern( |
44 pattern_, | 46 pattern_, |
45 base::Bind( | 47 base::Bind( |
46 &ServiceWorkerRegisterJob::HandleExistingRegistrationAndContinue, | 48 &ServiceWorkerRegisterJob::HandleExistingRegistrationAndContinue, |
47 weak_factory_.GetWeakPtr())); | 49 weak_factory_.GetWeakPtr())); |
48 } | 50 } |
49 | 51 |
50 bool ServiceWorkerRegisterJob::Equals(ServiceWorkerRegisterJobBase* job) { | 52 bool ServiceWorkerRegisterJob::Equals(ServiceWorkerRegisterJobBase* job) { |
51 if (job->GetType() != GetType()) | 53 if (job->GetType() != GetType()) |
52 return false; | 54 return false; |
53 ServiceWorkerRegisterJob* register_job = | 55 ServiceWorkerRegisterJob* register_job = |
54 static_cast<ServiceWorkerRegisterJob*>(job); | 56 static_cast<ServiceWorkerRegisterJob*>(job); |
55 return register_job->pattern_ == pattern_ && | 57 return register_job->pattern_ == pattern_ && |
56 register_job->script_url_ == script_url_; | 58 register_job->script_url_ == script_url_; |
57 } | 59 } |
58 | 60 |
59 RegistrationJobType ServiceWorkerRegisterJob::GetType() { | 61 RegistrationJobType ServiceWorkerRegisterJob::GetType() { |
60 return REGISTER; | 62 return REGISTRATION; |
63 } | |
64 | |
65 void ServiceWorkerRegisterJob::set_registration( | |
66 ServiceWorkerRegistration* registration) { | |
67 DCHECK(phase_ == START || phase_ == REGISTER) << phase_; | |
68 DCHECK(!internal_.registration_); | |
69 internal_.registration_ = registration; | |
70 } | |
71 | |
72 ServiceWorkerRegistration* ServiceWorkerRegisterJob::registration() { | |
73 DCHECK(phase_ >= REGISTER) << phase_; | |
74 DCHECK(internal_.registration_); | |
75 return internal_.registration_; | |
76 } | |
77 | |
78 void ServiceWorkerRegisterJob::set_pending_version( | |
79 ServiceWorkerVersion* version) { | |
80 DCHECK(phase_ == UPDATE || phase_ == ACTIVATE) << phase_; | |
81 DCHECK(!internal_.pending_version_ || !version); | |
82 internal_.pending_version_ = version; | |
83 } | |
84 | |
85 ServiceWorkerVersion* ServiceWorkerRegisterJob::pending_version() { | |
86 DCHECK(phase_ >= UPDATE) << phase_; | |
87 return internal_.pending_version_; | |
61 } | 88 } |
62 | 89 |
63 // This function corresponds to the steps in Register following | 90 // This function corresponds to the steps in Register following |
64 // "Let serviceWorkerRegistration be _GetRegistration(scope)" | 91 // "Let serviceWorkerRegistration be _GetRegistration(scope)" |
65 // |registration| corresponds to serviceWorkerRegistration. | 92 // |existing_registration| corresponds to serviceWorkerRegistration. |
66 // Throughout this file, comments in quotes are excerpts from the spec. | 93 // Throughout this file, comments in quotes are excerpts from the spec. |
67 void ServiceWorkerRegisterJob::HandleExistingRegistrationAndContinue( | 94 void ServiceWorkerRegisterJob::HandleExistingRegistrationAndContinue( |
68 ServiceWorkerStatusCode status, | 95 ServiceWorkerStatusCode status, |
69 const scoped_refptr<ServiceWorkerRegistration>& registration) { | 96 const scoped_refptr<ServiceWorkerRegistration>& existing_registration) { |
70 // On unexpected error, abort this registration job. | 97 // On unexpected error, abort this registration job. |
71 if (status != SERVICE_WORKER_ERROR_NOT_FOUND && status != SERVICE_WORKER_OK) { | 98 if (status != SERVICE_WORKER_ERROR_NOT_FOUND && status != SERVICE_WORKER_OK) { |
72 Complete(status); | 99 Complete(status); |
73 return; | 100 return; |
74 } | 101 } |
75 | 102 |
76 // "If serviceWorkerRegistration is not null and script is equal to | 103 // "If serviceWorkerRegistration is not null and script is equal to |
77 // serviceWorkerRegistration.scriptUrl..." resolve with the existing | 104 // serviceWorkerRegistration.scriptUrl..." resolve with the existing |
78 // registration and abort. | 105 // registration and abort. |
79 if (registration.get() && registration->script_url() == script_url_) { | 106 if (existing_registration.get() && |
80 registration_ = registration; | 107 existing_registration->script_url() == script_url_) { |
108 set_registration(existing_registration); | |
81 // If there's no active version, go ahead to Update (this isn't in the spec | 109 // If there's no active version, go ahead to Update (this isn't in the spec |
82 // but seems reasonable, and without SoftUpdate implemented we can never | 110 // but seems reasonable, and without SoftUpdate implemented we can never |
83 // Update otherwise). | 111 // Update otherwise). |
84 if (!registration_->active_version()) { | 112 if (!existing_registration->active_version()) { |
85 UpdateAndContinue(status); | 113 UpdateAndContinue(status); |
86 return; | 114 return; |
87 } | 115 } |
88 RunCallbacks(status, registration_->active_version()); | 116 RunCallbacks(status, existing_registration->active_version()); |
89 Complete(SERVICE_WORKER_OK); | 117 Complete(SERVICE_WORKER_OK); |
90 return; | 118 return; |
91 } | 119 } |
92 | 120 |
93 // "If serviceWorkerRegistration is null..." create a new registration. | 121 // "If serviceWorkerRegistration is null..." create a new registration. |
94 if (!registration.get()) { | 122 if (!existing_registration.get()) { |
95 RegisterAndContinue(SERVICE_WORKER_OK); | 123 RegisterAndContinue(SERVICE_WORKER_OK); |
96 return; | 124 return; |
97 } | 125 } |
98 | 126 |
99 // On script URL mismatch, "set serviceWorkerRegistration.scriptUrl to | 127 // On script URL mismatch, "set serviceWorkerRegistration.scriptUrl to |
100 // script." We accomplish this by deleting the existing registration and | 128 // script." We accomplish this by deleting the existing registration and |
101 // registering a new one. | 129 // registering a new one. |
102 // TODO(falken): Match the spec. We now throw away the active_version_ and | 130 // TODO(falken): Match the spec. We now throw away the active_version_ and |
103 // pending_version_ of the existing registration, which isn't in the spec. | 131 // pending_version_ of the existing registration, which isn't in the spec. |
104 registration->Shutdown(); | 132 existing_registration->Shutdown(); |
105 context_->storage()->DeleteRegistration( | 133 context_->storage()->DeleteRegistration( |
106 pattern_, | 134 pattern_, |
107 base::Bind(&ServiceWorkerRegisterJob::RegisterAndContinue, | 135 base::Bind(&ServiceWorkerRegisterJob::RegisterAndContinue, |
108 weak_factory_.GetWeakPtr())); | 136 weak_factory_.GetWeakPtr())); |
109 } | 137 } |
110 | 138 |
111 // Registers a new ServiceWorkerRegistration. | 139 // Registers a new ServiceWorkerRegistration. |
112 void ServiceWorkerRegisterJob::RegisterAndContinue( | 140 void ServiceWorkerRegisterJob::RegisterAndContinue( |
113 ServiceWorkerStatusCode status) { | 141 ServiceWorkerStatusCode status) { |
114 DCHECK(!registration_); | 142 phase_ = REGISTER; |
115 if (status != SERVICE_WORKER_OK) { | 143 if (status != SERVICE_WORKER_OK) { |
116 // Abort this registration job. | 144 // Abort this registration job. |
117 Complete(status); | 145 Complete(status); |
118 return; | 146 return; |
119 } | 147 } |
120 | 148 |
121 registration_ = new ServiceWorkerRegistration( | 149 set_registration(new ServiceWorkerRegistration( |
122 pattern_, script_url_, context_->storage()->NewRegistrationId(), | 150 pattern_, script_url_, context_->storage()->NewRegistrationId(), |
123 context_); | 151 context_)); |
124 context_->storage()->StoreRegistration( | 152 context_->storage()->StoreRegistration( |
125 registration_.get(), | 153 registration(), |
126 base::Bind(&ServiceWorkerRegisterJob::UpdateAndContinue, | 154 base::Bind(&ServiceWorkerRegisterJob::UpdateAndContinue, |
127 weak_factory_.GetWeakPtr())); | 155 weak_factory_.GetWeakPtr())); |
128 } | 156 } |
129 | 157 |
130 // This function corresponds to the spec's _Update algorithm. | 158 // This function corresponds to the spec's _Update algorithm. |
131 void ServiceWorkerRegisterJob::UpdateAndContinue( | 159 void ServiceWorkerRegisterJob::UpdateAndContinue( |
132 ServiceWorkerStatusCode status) { | 160 ServiceWorkerStatusCode status) { |
133 DCHECK(registration_); | 161 phase_ = UPDATE; |
134 if (status != SERVICE_WORKER_OK) { | 162 if (status != SERVICE_WORKER_OK) { |
135 // Abort this registration job. | 163 // Abort this registration job. |
136 Complete(status); | 164 Complete(status); |
137 return; | 165 return; |
138 } | 166 } |
139 | 167 |
140 // TODO: "If serviceWorkerRegistration.pendingWorker is not null..." then | 168 // TODO: "If serviceWorkerRegistration.pendingWorker is not null..." then |
141 // terminate the pending worker. It doesn't make sense to implement yet since | 169 // terminate the pending worker. It doesn't make sense to implement yet since |
142 // we always activate the worker if install completed, so there can be no | 170 // we always activate the worker if install completed, so there can be no |
143 // pending worker at this point. | 171 // pending worker at this point. |
144 DCHECK(!registration_->pending_version()); | 172 DCHECK(!registration()->pending_version()); |
145 | 173 |
146 // TODO: Script fetching and comparing the old and new script belongs here. | 174 // TODO: Script fetching and comparing the old and new script belongs here. |
147 | 175 |
148 // "Let serviceWorker be a newly-created ServiceWorker object..." and start | 176 // "Let serviceWorker be a newly-created ServiceWorker object..." and start |
149 // the worker. | 177 // the worker. |
150 pending_version_ = new ServiceWorkerVersion( | 178 set_pending_version(new ServiceWorkerVersion( |
151 registration_, context_->storage()->NewVersionId(), context_); | 179 registration(), context_->storage()->NewVersionId(), context_)); |
152 for (std::vector<int>::const_iterator it = pending_process_ids_.begin(); | 180 for (std::vector<int>::const_iterator it = pending_process_ids_.begin(); |
153 it != pending_process_ids_.end(); | 181 it != pending_process_ids_.end(); |
154 ++it) | 182 ++it) |
155 pending_version_->AddProcessToWorker(*it); | 183 pending_version()->AddProcessToWorker(*it); |
156 | 184 |
157 pending_version_->StartWorker( | 185 pending_version()->StartWorker( |
158 base::Bind(&ServiceWorkerRegisterJob::OnStartWorkerFinished, | 186 base::Bind(&ServiceWorkerRegisterJob::OnStartWorkerFinished, |
159 weak_factory_.GetWeakPtr())); | 187 weak_factory_.GetWeakPtr())); |
160 } | 188 } |
161 | 189 |
162 void ServiceWorkerRegisterJob::OnStartWorkerFinished( | 190 void ServiceWorkerRegisterJob::OnStartWorkerFinished( |
163 ServiceWorkerStatusCode status) { | 191 ServiceWorkerStatusCode status) { |
164 // "If serviceWorker fails to start up..." then reject the promise with an | 192 // "If serviceWorker fails to start up..." then reject the promise with an |
165 // error and abort. | 193 // error and abort. |
166 if (status != SERVICE_WORKER_OK) { | 194 if (status != SERVICE_WORKER_OK) { |
167 Complete(status); | 195 Complete(status); |
168 return; | 196 return; |
169 } | 197 } |
170 | 198 |
171 // "Resolve promise with serviceWorker." | 199 // "Resolve promise with serviceWorker." |
172 // Although the spec doesn't set pendingWorker until after resolving the | 200 // Although the spec doesn't set pendingWorker until after resolving the |
173 // promise, our system's resolving works by passing ServiceWorkerRegistration | 201 // promise, our system's resolving works by passing ServiceWorkerRegistration |
174 // to the callbacks, so pendingWorker must be set first. | 202 // to the callbacks, so pendingWorker must be set first. |
175 DCHECK(!registration_->pending_version()); | 203 DCHECK(!registration()->pending_version()); |
176 registration_->set_pending_version(pending_version_); | 204 registration()->set_pending_version(pending_version()); |
177 RunCallbacks(status, pending_version_.get()); | 205 RunCallbacks(status, pending_version()); |
178 | 206 |
179 InstallAndContinue(); | 207 InstallAndContinue(); |
180 } | 208 } |
181 | 209 |
182 // This function corresponds to the spec's _Install algorithm. | 210 // This function corresponds to the spec's _Install algorithm. |
183 void ServiceWorkerRegisterJob::InstallAndContinue() { | 211 void ServiceWorkerRegisterJob::InstallAndContinue() { |
212 phase_ = INSTALL; | |
184 // "Set serviceWorkerRegistration.pendingWorker._state to installing." | 213 // "Set serviceWorkerRegistration.pendingWorker._state to installing." |
185 // "Fire install event on the associated ServiceWorkerGlobalScope object." | 214 // "Fire install event on the associated ServiceWorkerGlobalScope object." |
186 pending_version_->DispatchInstallEvent( | 215 pending_version()->DispatchInstallEvent( |
187 -1, | 216 -1, |
188 base::Bind(&ServiceWorkerRegisterJob::OnInstallFinished, | 217 base::Bind(&ServiceWorkerRegisterJob::OnInstallFinished, |
189 weak_factory_.GetWeakPtr())); | 218 weak_factory_.GetWeakPtr())); |
190 } | 219 } |
191 | 220 |
192 void ServiceWorkerRegisterJob::OnInstallFinished( | 221 void ServiceWorkerRegisterJob::OnInstallFinished( |
193 ServiceWorkerStatusCode status) { | 222 ServiceWorkerStatusCode status) { |
194 // "If any handler called waitUntil()..." and the resulting promise | 223 // "If any handler called waitUntil()..." and the resulting promise |
195 // is rejected, abort. | 224 // is rejected, abort. |
196 if (status != SERVICE_WORKER_OK) { | 225 if (status != SERVICE_WORKER_OK) { |
197 registration_->set_pending_version(NULL); | 226 registration()->set_pending_version(NULL); |
198 Complete(status); | 227 Complete(status); |
199 return; | 228 return; |
200 } | 229 } |
201 | 230 |
202 // TODO: Per spec, only activate if no document is using the registration. | 231 // TODO: Per spec, only activate if no document is using the registration. |
203 ActivateAndContinue(); | 232 ActivateAndContinue(); |
204 } | 233 } |
205 | 234 |
206 // This function corresponds to the spec's _Activate algorithm. | 235 // This function corresponds to the spec's _Activate algorithm. |
207 void ServiceWorkerRegisterJob::ActivateAndContinue() { | 236 void ServiceWorkerRegisterJob::ActivateAndContinue() { |
237 phase_ = ACTIVATE; | |
208 // "Set serviceWorkerRegistration.pendingWorker to null." | 238 // "Set serviceWorkerRegistration.pendingWorker to null." |
209 registration_->set_pending_version(NULL); | 239 registration()->set_pending_version(NULL); |
210 | 240 |
211 // TODO: Dispatch the activate event. | 241 // TODO: Dispatch the activate event. |
212 // TODO(michaeln): Persist the newly ACTIVE version. | 242 // TODO(michaeln): Persist the newly ACTIVE version. |
213 pending_version_->SetStatus(ServiceWorkerVersion::ACTIVE); | 243 pending_version()->SetStatus(ServiceWorkerVersion::ACTIVE); |
214 DCHECK(!registration_->active_version()); | 244 DCHECK(!registration()->active_version()); |
215 registration_->set_active_version(pending_version_); | 245 registration()->set_active_version(pending_version()); |
216 pending_version_ = NULL; | 246 set_pending_version(NULL); |
217 Complete(SERVICE_WORKER_OK); | 247 Complete(SERVICE_WORKER_OK); |
218 } | 248 } |
219 | 249 |
220 void ServiceWorkerRegisterJob::Complete(ServiceWorkerStatusCode status) { | 250 void ServiceWorkerRegisterJob::Complete(ServiceWorkerStatusCode status) { |
251 phase_ = COMPLETE; | |
221 // In success case the callbacks must have been dispatched already | 252 // In success case the callbacks must have been dispatched already |
222 // (so this is no-op), otherwise we must have come here for abort case, | 253 // (so this is no-op), otherwise we must have come here for abort case, |
223 // so dispatch callbacks with NULL. | 254 // so dispatch callbacks with NULL. |
224 DCHECK(callbacks_.empty() || status != SERVICE_WORKER_OK); | 255 DCHECK(callbacks_.empty() || status != SERVICE_WORKER_OK); |
225 RunCallbacks(status, NULL); | 256 RunCallbacks(status, NULL); |
226 | 257 |
227 // If |pending_version_| exists, it was not activated, so we are the sole | 258 // If |pending_version| exists, it was not activated, so we are the sole |
228 // owner of it, so it will be destroyed when this job ends, so Shutdown here. | 259 // owner of it, so it will be destroyed when this job ends, so Shutdown here. |
229 // We should be able to remove this code later, when something else holds a | 260 // We should be able to remove this code later, when something else holds a |
230 // reference to |pending_version_|. | 261 // reference to |pending_version_|. |
231 // TODO(kinuko): Fix these ownership and shutdown semantics. | 262 // TODO(kinuko): Fix these ownership and shutdown semantics. |
232 if (pending_version_) { | 263 if (pending_version()) { |
233 DCHECK(!registration_->pending_version()); | 264 DCHECK(status != SERVICE_WORKER_OK); |
234 DCHECK(!registration_->active_version()); | 265 DCHECK(!registration()->pending_version()); |
235 pending_version_->Shutdown(); | 266 DCHECK(!registration()->active_version()); |
267 pending_version()->Shutdown(); | |
236 } | 268 } |
237 | 269 |
238 context_->job_coordinator()->FinishJob(pattern_, this); | 270 context_->job_coordinator()->FinishJob(pattern_, this); |
239 } | 271 } |
240 | 272 |
241 void ServiceWorkerRegisterJob::RunCallbacks(ServiceWorkerStatusCode status, | 273 void ServiceWorkerRegisterJob::RunCallbacks(ServiceWorkerStatusCode status, |
242 ServiceWorkerVersion* version) { | 274 ServiceWorkerVersion* version) { |
243 for (std::vector<RegistrationCallback>::iterator it = callbacks_.begin(); | 275 for (std::vector<RegistrationCallback>::iterator it = callbacks_.begin(); |
244 it != callbacks_.end(); | 276 it != callbacks_.end(); |
245 ++it) { | 277 ++it) { |
246 it->Run(status, version); | 278 it->Run(status, version); |
247 } | 279 } |
248 callbacks_.clear(); | 280 callbacks_.clear(); |
249 } | 281 } |
250 | 282 |
251 } // namespace content | 283 } // namespace content |
OLD | NEW |