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 SetPhase(START); |
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 ServiceWorkerRegisterJob::Internal::Internal() {} |
| 66 |
| 67 ServiceWorkerRegisterJob::Internal::~Internal() {} |
| 68 |
| 69 void ServiceWorkerRegisterJob::set_registration( |
| 70 ServiceWorkerRegistration* registration) { |
| 71 DCHECK(phase_ == START || phase_ == REGISTER) << phase_; |
| 72 DCHECK(!internal_.registration); |
| 73 internal_.registration = registration; |
| 74 } |
| 75 |
| 76 ServiceWorkerRegistration* ServiceWorkerRegisterJob::registration() { |
| 77 DCHECK(phase_ >= REGISTER) << phase_; |
| 78 DCHECK(internal_.registration); |
| 79 return internal_.registration; |
| 80 } |
| 81 |
| 82 void ServiceWorkerRegisterJob::set_pending_version( |
| 83 ServiceWorkerVersion* version) { |
| 84 DCHECK(phase_ == UPDATE || phase_ == ACTIVATE) << phase_; |
| 85 DCHECK(!internal_.pending_version || !version); |
| 86 internal_.pending_version = version; |
| 87 } |
| 88 |
| 89 ServiceWorkerVersion* ServiceWorkerRegisterJob::pending_version() { |
| 90 DCHECK(phase_ >= UPDATE) << phase_; |
| 91 return internal_.pending_version; |
| 92 } |
| 93 |
| 94 void ServiceWorkerRegisterJob::SetPhase(Phase phase) { |
| 95 switch (phase) { |
| 96 case INITIAL: |
| 97 NOTREACHED(); |
| 98 break; |
| 99 case START: |
| 100 DCHECK(phase_ == INITIAL) << phase_; |
| 101 break; |
| 102 case REGISTER: |
| 103 DCHECK(phase_ == START) << phase_; |
| 104 break; |
| 105 case UPDATE: |
| 106 DCHECK(phase_ == START || phase_ == REGISTER) << phase_; |
| 107 break; |
| 108 case INSTALL: |
| 109 DCHECK(phase_ == UPDATE) << phase_; |
| 110 break; |
| 111 case ACTIVATE: |
| 112 DCHECK(phase_ == INSTALL) << phase_; |
| 113 break; |
| 114 case COMPLETE: |
| 115 DCHECK(phase_ != INITIAL && phase_ != COMPLETE) << phase_; |
| 116 break; |
| 117 } |
| 118 phase_ = phase; |
61 } | 119 } |
62 | 120 |
63 // This function corresponds to the steps in Register following | 121 // This function corresponds to the steps in Register following |
64 // "Let serviceWorkerRegistration be _GetRegistration(scope)" | 122 // "Let serviceWorkerRegistration be _GetRegistration(scope)" |
65 // |registration| corresponds to serviceWorkerRegistration. | 123 // |existing_registration| corresponds to serviceWorkerRegistration. |
66 // Throughout this file, comments in quotes are excerpts from the spec. | 124 // Throughout this file, comments in quotes are excerpts from the spec. |
67 void ServiceWorkerRegisterJob::HandleExistingRegistrationAndContinue( | 125 void ServiceWorkerRegisterJob::HandleExistingRegistrationAndContinue( |
68 ServiceWorkerStatusCode status, | 126 ServiceWorkerStatusCode status, |
69 const scoped_refptr<ServiceWorkerRegistration>& registration) { | 127 const scoped_refptr<ServiceWorkerRegistration>& existing_registration) { |
70 // On unexpected error, abort this registration job. | 128 // On unexpected error, abort this registration job. |
71 if (status != SERVICE_WORKER_ERROR_NOT_FOUND && status != SERVICE_WORKER_OK) { | 129 if (status != SERVICE_WORKER_ERROR_NOT_FOUND && status != SERVICE_WORKER_OK) { |
72 Complete(status); | 130 Complete(status); |
73 return; | 131 return; |
74 } | 132 } |
75 | 133 |
76 // "If serviceWorkerRegistration is not null and script is equal to | 134 // "If serviceWorkerRegistration is not null and script is equal to |
77 // serviceWorkerRegistration.scriptUrl..." resolve with the existing | 135 // serviceWorkerRegistration.scriptUrl..." resolve with the existing |
78 // registration and abort. | 136 // registration and abort. |
79 if (registration.get() && registration->script_url() == script_url_) { | 137 if (existing_registration.get() && |
80 registration_ = registration; | 138 existing_registration->script_url() == script_url_) { |
| 139 set_registration(existing_registration); |
81 // If there's no active version, go ahead to Update (this isn't in the spec | 140 // 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 | 141 // but seems reasonable, and without SoftUpdate implemented we can never |
83 // Update otherwise). | 142 // Update otherwise). |
84 if (!registration_->active_version()) { | 143 if (!existing_registration->active_version()) { |
85 UpdateAndContinue(status); | 144 UpdateAndContinue(status); |
86 return; | 145 return; |
87 } | 146 } |
88 RunCallbacks(status, registration_, registration_->active_version()); | 147 RunCallbacks( |
| 148 status, existing_registration, existing_registration->active_version()); |
89 Complete(SERVICE_WORKER_OK); | 149 Complete(SERVICE_WORKER_OK); |
90 return; | 150 return; |
91 } | 151 } |
92 | 152 |
93 // "If serviceWorkerRegistration is null..." create a new registration. | 153 // "If serviceWorkerRegistration is null..." create a new registration. |
94 if (!registration.get()) { | 154 if (!existing_registration.get()) { |
95 RegisterAndContinue(SERVICE_WORKER_OK); | 155 RegisterAndContinue(SERVICE_WORKER_OK); |
96 return; | 156 return; |
97 } | 157 } |
98 | 158 |
99 // On script URL mismatch, "set serviceWorkerRegistration.scriptUrl to | 159 // On script URL mismatch, "set serviceWorkerRegistration.scriptUrl to |
100 // script." We accomplish this by deleting the existing registration and | 160 // script." We accomplish this by deleting the existing registration and |
101 // registering a new one. | 161 // registering a new one. |
102 // TODO(falken): Match the spec. We now throw away the active_version_ and | 162 // 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. | 163 // pending_version_ of the existing registration, which isn't in the spec. |
104 context_->storage()->DeleteRegistration( | 164 context_->storage()->DeleteRegistration( |
105 pattern_, | 165 pattern_, |
106 base::Bind(&ServiceWorkerRegisterJob::RegisterAndContinue, | 166 base::Bind(&ServiceWorkerRegisterJob::RegisterAndContinue, |
107 weak_factory_.GetWeakPtr())); | 167 weak_factory_.GetWeakPtr())); |
108 } | 168 } |
109 | 169 |
110 // Registers a new ServiceWorkerRegistration. | 170 // Registers a new ServiceWorkerRegistration. |
111 void ServiceWorkerRegisterJob::RegisterAndContinue( | 171 void ServiceWorkerRegisterJob::RegisterAndContinue( |
112 ServiceWorkerStatusCode status) { | 172 ServiceWorkerStatusCode status) { |
113 DCHECK(!registration_); | 173 SetPhase(REGISTER); |
114 if (status != SERVICE_WORKER_OK) { | 174 if (status != SERVICE_WORKER_OK) { |
115 // Abort this registration job. | 175 // Abort this registration job. |
116 Complete(status); | 176 Complete(status); |
117 return; | 177 return; |
118 } | 178 } |
119 | 179 |
120 registration_ = new ServiceWorkerRegistration( | 180 set_registration(new ServiceWorkerRegistration( |
121 pattern_, script_url_, context_->storage()->NewRegistrationId(), | 181 pattern_, script_url_, context_->storage()->NewRegistrationId(), |
122 context_); | 182 context_)); |
123 context_->storage()->StoreRegistration( | 183 context_->storage()->StoreRegistration( |
124 registration_.get(), | 184 registration(), |
125 base::Bind(&ServiceWorkerRegisterJob::UpdateAndContinue, | 185 base::Bind(&ServiceWorkerRegisterJob::UpdateAndContinue, |
126 weak_factory_.GetWeakPtr())); | 186 weak_factory_.GetWeakPtr())); |
127 } | 187 } |
128 | 188 |
129 // This function corresponds to the spec's _Update algorithm. | 189 // This function corresponds to the spec's _Update algorithm. |
130 void ServiceWorkerRegisterJob::UpdateAndContinue( | 190 void ServiceWorkerRegisterJob::UpdateAndContinue( |
131 ServiceWorkerStatusCode status) { | 191 ServiceWorkerStatusCode status) { |
132 DCHECK(registration_); | 192 SetPhase(UPDATE); |
133 if (status != SERVICE_WORKER_OK) { | 193 if (status != SERVICE_WORKER_OK) { |
134 // Abort this registration job. | 194 // Abort this registration job. |
135 Complete(status); | 195 Complete(status); |
136 return; | 196 return; |
137 } | 197 } |
138 | 198 |
139 // TODO: "If serviceWorkerRegistration.pendingWorker is not null..." then | 199 // TODO: "If serviceWorkerRegistration.pendingWorker is not null..." then |
140 // terminate the pending worker. It doesn't make sense to implement yet since | 200 // terminate the pending worker. It doesn't make sense to implement yet since |
141 // we always activate the worker if install completed, so there can be no | 201 // we always activate the worker if install completed, so there can be no |
142 // pending worker at this point. | 202 // pending worker at this point. |
143 DCHECK(!registration_->pending_version()); | 203 DCHECK(!registration()->pending_version()); |
144 | 204 |
145 // TODO: Script fetching and comparing the old and new script belongs here. | 205 // TODO: Script fetching and comparing the old and new script belongs here. |
146 | 206 |
147 // "Let serviceWorker be a newly-created ServiceWorker object..." and start | 207 // "Let serviceWorker be a newly-created ServiceWorker object..." and start |
148 // the worker. | 208 // the worker. |
149 pending_version_ = new ServiceWorkerVersion( | 209 set_pending_version(new ServiceWorkerVersion( |
150 registration_, context_->storage()->NewVersionId(), context_); | 210 registration(), context_->storage()->NewVersionId(), context_)); |
151 for (std::vector<int>::const_iterator it = pending_process_ids_.begin(); | 211 for (std::vector<int>::const_iterator it = pending_process_ids_.begin(); |
152 it != pending_process_ids_.end(); | 212 it != pending_process_ids_.end(); |
153 ++it) | 213 ++it) |
154 pending_version_->AddProcessToWorker(*it); | 214 pending_version()->AddProcessToWorker(*it); |
155 | 215 |
156 pending_version_->StartWorker( | 216 pending_version()->StartWorker( |
157 base::Bind(&ServiceWorkerRegisterJob::OnStartWorkerFinished, | 217 base::Bind(&ServiceWorkerRegisterJob::OnStartWorkerFinished, |
158 weak_factory_.GetWeakPtr())); | 218 weak_factory_.GetWeakPtr())); |
159 } | 219 } |
160 | 220 |
161 void ServiceWorkerRegisterJob::OnStartWorkerFinished( | 221 void ServiceWorkerRegisterJob::OnStartWorkerFinished( |
162 ServiceWorkerStatusCode status) { | 222 ServiceWorkerStatusCode status) { |
163 // "If serviceWorker fails to start up..." then reject the promise with an | 223 // "If serviceWorker fails to start up..." then reject the promise with an |
164 // error and abort. | 224 // error and abort. |
165 if (status != SERVICE_WORKER_OK) { | 225 if (status != SERVICE_WORKER_OK) { |
166 Complete(status); | 226 Complete(status); |
167 return; | 227 return; |
168 } | 228 } |
169 | 229 |
170 // "Resolve promise with serviceWorker." | 230 // "Resolve promise with serviceWorker." |
171 // Although the spec doesn't set pendingWorker until after resolving the | 231 // Although the spec doesn't set pendingWorker until after resolving the |
172 // promise, our system's resolving works by passing ServiceWorkerRegistration | 232 // promise, our system's resolving works by passing ServiceWorkerRegistration |
173 // to the callbacks, so pendingWorker must be set first. | 233 // to the callbacks, so pendingWorker must be set first. |
174 DCHECK(!registration_->pending_version()); | 234 DCHECK(!registration()->pending_version()); |
175 registration_->set_pending_version(pending_version_); | 235 registration()->set_pending_version(pending_version()); |
176 RunCallbacks(status, registration_, pending_version_.get()); | 236 RunCallbacks(status, registration(), pending_version()); |
177 | 237 |
178 // TODO(kinuko): Iterate over all provider hosts and call SetPendingVersion() | 238 // TODO(kinuko): Iterate over all provider hosts and call SetPendingVersion() |
179 // for documents that are in-scope. | 239 // for documents that are in-scope. |
180 | 240 |
181 InstallAndContinue(); | 241 InstallAndContinue(); |
182 } | 242 } |
183 | 243 |
184 // This function corresponds to the spec's _Install algorithm. | 244 // This function corresponds to the spec's _Install algorithm. |
185 void ServiceWorkerRegisterJob::InstallAndContinue() { | 245 void ServiceWorkerRegisterJob::InstallAndContinue() { |
| 246 SetPhase(INSTALL); |
186 // "Set serviceWorkerRegistration.pendingWorker._state to installing." | 247 // "Set serviceWorkerRegistration.pendingWorker._state to installing." |
187 // "Fire install event on the associated ServiceWorkerGlobalScope object." | 248 // "Fire install event on the associated ServiceWorkerGlobalScope object." |
188 pending_version_->DispatchInstallEvent( | 249 pending_version()->DispatchInstallEvent( |
189 -1, | 250 -1, |
190 base::Bind(&ServiceWorkerRegisterJob::OnInstallFinished, | 251 base::Bind(&ServiceWorkerRegisterJob::OnInstallFinished, |
191 weak_factory_.GetWeakPtr())); | 252 weak_factory_.GetWeakPtr())); |
192 } | 253 } |
193 | 254 |
194 void ServiceWorkerRegisterJob::OnInstallFinished( | 255 void ServiceWorkerRegisterJob::OnInstallFinished( |
195 ServiceWorkerStatusCode status) { | 256 ServiceWorkerStatusCode status) { |
196 // "If any handler called waitUntil()..." and the resulting promise | 257 // "If any handler called waitUntil()..." and the resulting promise |
197 // is rejected, abort. | 258 // is rejected, abort. |
198 if (status != SERVICE_WORKER_OK) { | 259 if (status != SERVICE_WORKER_OK) { |
199 registration_->set_pending_version(NULL); | 260 registration()->set_pending_version(NULL); |
200 Complete(status); | 261 Complete(status); |
201 return; | 262 return; |
202 } | 263 } |
203 | 264 |
204 // TODO: Per spec, only activate if no document is using the registration. | 265 // TODO: Per spec, only activate if no document is using the registration. |
205 ActivateAndContinue(); | 266 ActivateAndContinue(); |
206 } | 267 } |
207 | 268 |
208 // This function corresponds to the spec's _Activate algorithm. | 269 // This function corresponds to the spec's _Activate algorithm. |
209 void ServiceWorkerRegisterJob::ActivateAndContinue() { | 270 void ServiceWorkerRegisterJob::ActivateAndContinue() { |
| 271 SetPhase(ACTIVATE); |
210 // "Set serviceWorkerRegistration.pendingWorker to null." | 272 // "Set serviceWorkerRegistration.pendingWorker to null." |
211 registration_->set_pending_version(NULL); | 273 registration()->set_pending_version(NULL); |
212 | 274 |
213 // TODO: Dispatch the activate event. | 275 // TODO: Dispatch the activate event. |
214 // TODO(michaeln): Persist the newly ACTIVE version. | 276 // TODO(michaeln): Persist the newly ACTIVE version. |
215 pending_version_->SetStatus(ServiceWorkerVersion::ACTIVE); | 277 pending_version()->SetStatus(ServiceWorkerVersion::ACTIVE); |
216 DCHECK(!registration_->active_version()); | 278 DCHECK(!registration()->active_version()); |
217 registration_->set_active_version(pending_version_); | 279 registration()->set_active_version(pending_version()); |
218 pending_version_ = NULL; | 280 set_pending_version(NULL); |
219 Complete(SERVICE_WORKER_OK); | 281 Complete(SERVICE_WORKER_OK); |
220 } | 282 } |
221 | 283 |
222 void ServiceWorkerRegisterJob::Complete(ServiceWorkerStatusCode status) { | 284 void ServiceWorkerRegisterJob::Complete(ServiceWorkerStatusCode status) { |
| 285 SetPhase(COMPLETE); |
223 // In success case the callbacks must have been dispatched already | 286 // In success case the callbacks must have been dispatched already |
224 // (so this is no-op), otherwise we must have come here for abort case, | 287 // (so this is no-op), otherwise we must have come here for abort case, |
225 // so dispatch callbacks with NULL. | 288 // so dispatch callbacks with NULL. |
226 DCHECK(callbacks_.empty() || status != SERVICE_WORKER_OK); | 289 DCHECK(callbacks_.empty() || status != SERVICE_WORKER_OK); |
227 RunCallbacks(status, NULL, NULL); | 290 RunCallbacks(status, NULL, NULL); |
228 | 291 |
229 context_->job_coordinator()->FinishJob(pattern_, this); | 292 context_->job_coordinator()->FinishJob(pattern_, this); |
230 } | 293 } |
231 | 294 |
232 void ServiceWorkerRegisterJob::RunCallbacks( | 295 void ServiceWorkerRegisterJob::RunCallbacks( |
233 ServiceWorkerStatusCode status, | 296 ServiceWorkerStatusCode status, |
234 ServiceWorkerRegistration* registration, | 297 ServiceWorkerRegistration* registration, |
235 ServiceWorkerVersion* version) { | 298 ServiceWorkerVersion* version) { |
236 for (std::vector<RegistrationCallback>::iterator it = callbacks_.begin(); | 299 for (std::vector<RegistrationCallback>::iterator it = callbacks_.begin(); |
237 it != callbacks_.end(); | 300 it != callbacks_.end(); |
238 ++it) { | 301 ++it) { |
239 it->Run(status, registration, version); | 302 it->Run(status, registration, version); |
240 } | 303 } |
241 callbacks_.clear(); | 304 callbacks_.clear(); |
242 } | 305 } |
243 | 306 |
244 } // namespace content | 307 } // namespace content |
OLD | NEW |