Dispatch install event during ServiceWorker registration
[chromium-blink-merge.git] / content / browser / service_worker / service_worker_register_job.cc
blob5235415c3ea86dad482acefe69a4e828025357a0
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"
7 #include <vector>
9 #include "content/browser/service_worker/service_worker_context_core.h"
10 #include "content/browser/service_worker/service_worker_job_coordinator.h"
11 #include "content/browser/service_worker/service_worker_registration.h"
12 #include "content/browser/service_worker/service_worker_storage.h"
14 namespace content {
16 typedef ServiceWorkerRegisterJobBase::RegistrationJobType RegistrationJobType;
18 ServiceWorkerRegisterJob::ServiceWorkerRegisterJob(
19 base::WeakPtr<ServiceWorkerContextCore> context,
20 const GURL& pattern,
21 const GURL& script_url)
22 : context_(context),
23 pattern_(pattern),
24 script_url_(script_url),
25 weak_factory_(this) {}
27 ServiceWorkerRegisterJob::~ServiceWorkerRegisterJob() {}
29 void ServiceWorkerRegisterJob::AddCallback(const RegistrationCallback& callback,
30 int process_id) {
31 // If we've created a pending version, associate source_provider it with that,
32 // otherwise queue it up.
33 callbacks_.push_back(callback);
34 DCHECK_NE(-1, process_id);
35 if (pending_version_) {
36 pending_version_->AddProcessToWorker(process_id);
37 } else {
38 pending_process_ids_.push_back(process_id);
42 void ServiceWorkerRegisterJob::Start() {
43 context_->storage()->FindRegistrationForPattern(
44 pattern_,
45 base::Bind(
46 &ServiceWorkerRegisterJob::HandleExistingRegistrationAndContinue,
47 weak_factory_.GetWeakPtr()));
50 bool ServiceWorkerRegisterJob::Equals(ServiceWorkerRegisterJobBase* job) {
51 if (job->GetType() != GetType())
52 return false;
53 ServiceWorkerRegisterJob* register_job =
54 static_cast<ServiceWorkerRegisterJob*>(job);
55 return register_job->pattern_ == pattern_ &&
56 register_job->script_url_ == script_url_;
59 RegistrationJobType ServiceWorkerRegisterJob::GetType() {
60 return REGISTER;
63 // This function corresponds to the steps in Register following
64 // "Let serviceWorkerRegistration be _GetRegistration(scope)"
65 // |registration| corresponds to serviceWorkerRegistration.
66 // Throughout this file, comments in quotes are excerpts from the spec.
67 void ServiceWorkerRegisterJob::HandleExistingRegistrationAndContinue(
68 ServiceWorkerStatusCode status,
69 const scoped_refptr<ServiceWorkerRegistration>& registration) {
70 // On unexpected error, abort this registration job.
71 if (status != SERVICE_WORKER_ERROR_NOT_FOUND && status != SERVICE_WORKER_OK) {
72 Complete(status);
73 return;
76 // "If serviceWorkerRegistration is not null and script is equal to
77 // serviceWorkerRegistration.scriptUrl..." resolve with the existing
78 // registration and abort.
79 if (registration.get() && registration->script_url() == script_url_) {
80 registration_ = registration;
81 // 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
83 // Update otherwise).
84 if (!registration_->active_version()) {
85 UpdateAndContinue(status);
86 return;
88 Complete(SERVICE_WORKER_OK);
89 return;
92 // "If serviceWorkerRegistration is null..." create a new registration.
93 if (!registration.get()) {
94 RegisterAndContinue(SERVICE_WORKER_OK);
95 return;
98 // On script URL mismatch, "set serviceWorkerRegistration.scriptUrl to
99 // script." We accomplish this by deleting the existing registration and
100 // registering a new one.
101 // TODO(falken): Match the spec. We now throw away the active_version_ and
102 // pending_version_ of the existing registration, which isn't in the spec.
103 registration->Shutdown();
104 context_->storage()->DeleteRegistration(
105 pattern_,
106 base::Bind(&ServiceWorkerRegisterJob::RegisterAndContinue,
107 weak_factory_.GetWeakPtr()));
110 // Registers a new ServiceWorkerRegistration.
111 void ServiceWorkerRegisterJob::RegisterAndContinue(
112 ServiceWorkerStatusCode status) {
113 DCHECK(!registration_);
114 if (status != SERVICE_WORKER_OK) {
115 // Abort this registration job.
116 Complete(status);
117 return;
120 registration_ = new ServiceWorkerRegistration(
121 pattern_, script_url_, context_->storage()->NewRegistrationId(),
122 context_);
123 context_->storage()->StoreRegistration(
124 registration_.get(),
125 base::Bind(&ServiceWorkerRegisterJob::UpdateAndContinue,
126 weak_factory_.GetWeakPtr()));
129 // This function corresponds to the spec's _Update algorithm.
130 void ServiceWorkerRegisterJob::UpdateAndContinue(
131 ServiceWorkerStatusCode status) {
132 DCHECK(registration_);
133 if (status != SERVICE_WORKER_OK) {
134 // Abort this registration job.
135 Complete(status);
136 return;
139 // TODO: "If serviceWorkerRegistration.pendingWorker is not null..." then
140 // 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
142 // pending worker at this point.
143 DCHECK(!registration_->pending_version());
145 // TODO: Script fetching and comparing the old and new script belongs here.
147 // "Let serviceWorker be a newly-created ServiceWorker object..." and start
148 // the worker.
149 pending_version_ = new ServiceWorkerVersion(
150 registration_, context_->storage()->NewVersionId(), context_);
151 for (std::vector<int>::const_iterator it = pending_process_ids_.begin();
152 it != pending_process_ids_.end();
153 ++it)
154 pending_version_->AddProcessToWorker(*it);
156 pending_version_->StartWorker(
157 base::Bind(&ServiceWorkerRegisterJob::OnStartWorkerFinished,
158 weak_factory_.GetWeakPtr()));
161 void ServiceWorkerRegisterJob::OnStartWorkerFinished(
162 ServiceWorkerStatusCode status) {
163 // "If serviceWorker fails to start up..." then reject the promise with an
164 // error and abort.
165 if (status != SERVICE_WORKER_OK) {
166 Complete(status);
167 return;
170 // "Resolve promise with serviceWorker."
171 // Although the spec doesn't set pendingWorker until after resolving the
172 // promise, our system's resolving works by passing ServiceWorkerRegistration
173 // to the callbacks, so pendingWorker must be set first.
174 DCHECK(!registration_->pending_version());
175 registration_->set_pending_version(pending_version_);
176 RunCallbacks(status);
178 InstallAndContinue();
181 // This function corresponds to the spec's _Install algorithm.
182 void ServiceWorkerRegisterJob::InstallAndContinue() {
183 // "Set serviceWorkerRegistration.pendingWorker._state to installing."
184 // "Fire install event on the associated ServiceWorkerGlobalScope object."
185 pending_version_->DispatchInstallEvent(
187 base::Bind(&ServiceWorkerRegisterJob::OnInstallFinished,
188 weak_factory_.GetWeakPtr()));
191 void ServiceWorkerRegisterJob::OnInstallFinished(
192 ServiceWorkerStatusCode status) {
193 // "If any handler called waitUntil()..." and the resulting promise
194 // is rejected, abort.
195 if (status != SERVICE_WORKER_OK) {
196 registration_->set_pending_version(NULL);
197 Complete(status);
198 return;
201 // TODO: Per spec, only activate if no document is using the registration.
202 ActivateAndContinue();
205 // This function corresponds to the spec's _Activate algorithm.
206 void ServiceWorkerRegisterJob::ActivateAndContinue() {
207 // "Set serviceWorkerRegistration.pendingWorker to null."
208 registration_->set_pending_version(NULL);
210 // TODO: Dispatch the activate event.
211 // TODO(michaeln): Persist the newly ACTIVE version.
212 pending_version_->SetStatus(ServiceWorkerVersion::ACTIVE);
213 DCHECK(!registration_->active_version());
214 registration_->set_active_version(pending_version_);
215 pending_version_ = NULL;
216 Complete(SERVICE_WORKER_OK);
219 void ServiceWorkerRegisterJob::Complete(ServiceWorkerStatusCode status) {
220 RunCallbacks(status);
222 // If |pending_version_| exists, it was not activated, so we are the sole
223 // owner of it, so it will be destroyed when this job ends, so Shutdown here.
224 // We should be able to remove this code later, when something else holds a
225 // reference to |pending_version_|.
226 // TODO(kinuko): Fix these ownership and shutdown semantics.
227 if (pending_version_) {
228 DCHECK(!registration_->pending_version());
229 DCHECK(!registration_->active_version());
230 pending_version_->Shutdown();
233 context_->job_coordinator()->FinishJob(pattern_, this);
236 void ServiceWorkerRegisterJob::RunCallbacks(ServiceWorkerStatusCode status) {
237 for (std::vector<RegistrationCallback>::iterator it = callbacks_.begin();
238 it != callbacks_.end();
239 ++it) {
240 it->Run(status, status == SERVICE_WORKER_OK ? registration_ : NULL);
242 callbacks_.clear();
245 } // namespace content