Upstream version 5.34.104.0
[platform/framework/web/crosswalk.git] / src / content / browser / service_worker / service_worker_register_job.cc
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.
4
5 #include "content/browser/service_worker/service_worker_register_job.h"
6
7 #include <vector>
8
9 #include "content/browser/service_worker/service_worker_job_coordinator.h"
10 #include "content/browser/service_worker/service_worker_registration.h"
11 #include "content/public/browser/browser_thread.h"
12 #include "url/gurl.h"
13
14 namespace content {
15
16 ServiceWorkerRegisterJob::ServiceWorkerRegisterJob(
17     ServiceWorkerStorage* storage,
18     EmbeddedWorkerRegistry* worker_registry,
19     ServiceWorkerJobCoordinator* coordinator,
20     const GURL& pattern,
21     const GURL& script_url,
22     RegistrationType type)
23     : storage_(storage),
24       worker_registry_(worker_registry),
25       coordinator_(coordinator),
26       pending_version_(NULL),
27       pattern_(pattern),
28       script_url_(script_url),
29       type_(type),
30       weak_factory_(this) {}
31
32 ServiceWorkerRegisterJob::~ServiceWorkerRegisterJob() {}
33
34 void ServiceWorkerRegisterJob::AddCallback(const RegistrationCallback& callback,
35                                            int process_id) {
36   // if we've created a pending version, associate source_provider it with
37   // that, otherwise queue it up
38   callbacks_.push_back(callback);
39   DCHECK(process_id != -1);
40   if (pending_version_) {
41     pending_version_->AddProcessToWorker(process_id);
42   } else {
43     pending_process_ids_.push_back(process_id);
44   }
45 }
46
47 void ServiceWorkerRegisterJob::Start() {
48   if (type_ == REGISTER)
49     StartRegister();
50   else
51     StartUnregister();
52 }
53
54 bool ServiceWorkerRegisterJob::Equals(ServiceWorkerRegisterJob* job) {
55   return job->type_ == type_ &&
56          (type_ == ServiceWorkerRegisterJob::UNREGISTER ||
57           job->script_url_ == script_url_);
58 }
59
60 void ServiceWorkerRegisterJob::StartRegister() {
61   // Set up a chain of callbacks, in reverse order. Each of these
62   // callbacks may be called asynchronously by the previous callback.
63   StatusCallback finish_registration(base::Bind(
64       &ServiceWorkerRegisterJob::RegisterComplete, weak_factory_.GetWeakPtr()));
65
66   RegistrationCallback start_worker(
67       base::Bind(&ServiceWorkerRegisterJob::StartWorkerAndContinue,
68                  weak_factory_.GetWeakPtr(),
69                  finish_registration));
70
71   UnregistrationCallback register_new(
72       base::Bind(&ServiceWorkerRegisterJob::RegisterPatternAndContinue,
73                  weak_factory_.GetWeakPtr(),
74                  start_worker));
75
76   ServiceWorkerStorage::FindRegistrationCallback unregister_old(
77       base::Bind(&ServiceWorkerRegisterJob::UnregisterPatternAndContinue,
78                  weak_factory_.GetWeakPtr(),
79                  register_new));
80
81   storage_->FindRegistrationForPattern(pattern_, unregister_old);
82 }
83
84 void ServiceWorkerRegisterJob::StartUnregister() {
85   // Set up a chain of callbacks, in reverse order. Each of these
86   // callbacks may be called asynchronously by the previous callback.
87   UnregistrationCallback finish_unregistration(
88       base::Bind(&ServiceWorkerRegisterJob::UnregisterComplete,
89                  weak_factory_.GetWeakPtr()));
90
91   ServiceWorkerStorage::FindRegistrationCallback unregister(
92       base::Bind(&ServiceWorkerRegisterJob::UnregisterPatternAndContinue,
93                  weak_factory_.GetWeakPtr(),
94                  finish_unregistration));
95
96   storage_->FindRegistrationForPattern(pattern_, unregister);
97 }
98
99 void ServiceWorkerRegisterJob::StartWorkerAndContinue(
100     const StatusCallback& callback,
101     ServiceWorkerStatusCode status,
102     const scoped_refptr<ServiceWorkerRegistration>& registration) {
103   if (registration->active_version()) {
104     // We have an active version, so we can complete immediately, even
105     // if the service worker isn't running.
106     callback.Run(registration, SERVICE_WORKER_OK);
107     return;
108   }
109
110   pending_version_ = new ServiceWorkerVersion(
111       registration, worker_registry_, registration->next_version_id());
112   for (std::vector<int>::const_iterator it = pending_process_ids_.begin();
113        it != pending_process_ids_.end();
114        ++it)
115     pending_version_->AddProcessToWorker(*it);
116
117   // The callback to watch "installation" actually fires as soon as
118   // the worker is up and running, just before the install event is
119   // dispatched. The job will continue to run even though the main
120   // callback has executed.
121   pending_version_->StartWorker(base::Bind(callback, registration));
122
123   // TODO(alecflett): Don't set the active version until just before
124   // the activate event is dispatched.
125   registration->set_active_version(pending_version_);
126 }
127
128 void ServiceWorkerRegisterJob::RegisterPatternAndContinue(
129     const RegistrationCallback& callback,
130     ServiceWorkerStatusCode previous_status) {
131   if (previous_status != SERVICE_WORKER_OK) {
132     BrowserThread::PostTask(
133         BrowserThread::IO,
134         FROM_HERE,
135         base::Bind(callback,
136                    previous_status,
137                    scoped_refptr<ServiceWorkerRegistration>()));
138     return;
139   }
140
141   // TODO: Eventually RegisterInternal will be replaced by an asynchronous
142   // operation. Pass its resulting status through 'callback'.
143   scoped_refptr<ServiceWorkerRegistration> registration =
144       storage_->RegisterInternal(pattern_, script_url_);
145
146   BrowserThread::PostTask(BrowserThread::IO,
147                           FROM_HERE,
148                           base::Bind(callback, SERVICE_WORKER_OK,
149                                      registration));
150 }
151
152 void ServiceWorkerRegisterJob::UnregisterPatternAndContinue(
153     const UnregistrationCallback& callback,
154     bool found,
155     ServiceWorkerStatusCode previous_status,
156     const scoped_refptr<ServiceWorkerRegistration>& previous_registration) {
157
158   // The previous registration may not exist, which is ok.
159   if (previous_status == SERVICE_WORKER_OK && found &&
160       (script_url_.is_empty() ||
161        previous_registration->script_url() != script_url_)) {
162     // TODO: Eventually UnregisterInternal will be replaced by an
163     // asynchronous operation. Pass its resulting status though
164     // 'callback'.
165     storage_->UnregisterInternal(pattern_);
166     DCHECK(previous_registration->is_shutdown());
167   } else {
168     // TODO(alecflett): We have an existing registration, we should
169     // schedule an update.
170   }
171   BrowserThread::PostTask(
172       BrowserThread::IO, FROM_HERE, base::Bind(callback, previous_status));
173 }
174
175 void ServiceWorkerRegisterJob::RunCallbacks(
176     ServiceWorkerStatusCode status,
177     const scoped_refptr<ServiceWorkerRegistration>& registration) {
178   for (std::vector<RegistrationCallback>::iterator it = callbacks_.begin();
179        it != callbacks_.end();
180        ++it) {
181     it->Run(status, registration);
182   }
183 }
184
185 void ServiceWorkerRegisterJob::RegisterComplete(
186     const scoped_refptr<ServiceWorkerRegistration>& registration,
187     ServiceWorkerStatusCode start_status) {
188   RunCallbacks(start_status, registration);
189   coordinator_->FinishJob(pattern_, this);
190 }
191
192 void ServiceWorkerRegisterJob::UnregisterComplete(
193     ServiceWorkerStatusCode status) {
194   RunCallbacks(status, NULL);
195   coordinator_->FinishJob(pattern_, this);
196 }
197
198 }  // namespace content