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_context_core.h"
6
7 #include "base/files/file_path.h"
8 #include "base/message_loop/message_loop_proxy.h"
9 #include "base/strings/string_util.h"
10 #include "content/browser/service_worker/embedded_worker_registry.h"
11 #include "content/browser/service_worker/service_worker_context_observer.h"
12 #include "content/browser/service_worker/service_worker_context_wrapper.h"
13 #include "content/browser/service_worker/service_worker_info.h"
14 #include "content/browser/service_worker/service_worker_job_coordinator.h"
15 #include "content/browser/service_worker/service_worker_process_manager.h"
16 #include "content/browser/service_worker/service_worker_provider_host.h"
17 #include "content/browser/service_worker/service_worker_register_job.h"
18 #include "content/browser/service_worker/service_worker_registration.h"
19 #include "content/browser/service_worker/service_worker_storage.h"
20 #include "content/public/browser/browser_thread.h"
21 #include "url/gurl.h"
22
23 namespace content {
24
~ProviderHostIterator()25 ServiceWorkerContextCore::ProviderHostIterator::~ProviderHostIterator() {}
26
27 ServiceWorkerProviderHost*
GetProviderHost()28 ServiceWorkerContextCore::ProviderHostIterator::GetProviderHost() {
29 DCHECK(!IsAtEnd());
30 return provider_host_iterator_->GetCurrentValue();
31 }
32
Advance()33 void ServiceWorkerContextCore::ProviderHostIterator::Advance() {
34 DCHECK(!IsAtEnd());
35 DCHECK(!provider_host_iterator_->IsAtEnd());
36 DCHECK(!provider_iterator_->IsAtEnd());
37
38 // Advance the inner iterator. If an element is reached, we're done.
39 provider_host_iterator_->Advance();
40 if (!provider_host_iterator_->IsAtEnd())
41 return;
42
43 // Advance the outer iterator until an element is reached, or end is hit.
44 while (true) {
45 provider_iterator_->Advance();
46 if (provider_iterator_->IsAtEnd())
47 return;
48 ProviderMap* provider_map = provider_iterator_->GetCurrentValue();
49 provider_host_iterator_.reset(new ProviderMap::iterator(provider_map));
50 if (!provider_host_iterator_->IsAtEnd())
51 return;
52 }
53 }
54
IsAtEnd()55 bool ServiceWorkerContextCore::ProviderHostIterator::IsAtEnd() {
56 return provider_iterator_->IsAtEnd() &&
57 (!provider_host_iterator_ || provider_host_iterator_->IsAtEnd());
58 }
59
ProviderHostIterator(ProcessToProviderMap * map)60 ServiceWorkerContextCore::ProviderHostIterator::ProviderHostIterator(
61 ProcessToProviderMap* map)
62 : map_(map) {
63 DCHECK(map);
64 Initialize();
65 }
66
Initialize()67 void ServiceWorkerContextCore::ProviderHostIterator::Initialize() {
68 provider_iterator_.reset(new ProcessToProviderMap::iterator(map_));
69 // Advance to the first element.
70 while (!provider_iterator_->IsAtEnd()) {
71 ProviderMap* provider_map = provider_iterator_->GetCurrentValue();
72 provider_host_iterator_.reset(new ProviderMap::iterator(provider_map));
73 if (!provider_host_iterator_->IsAtEnd())
74 return;
75 provider_iterator_->Advance();
76 }
77 }
78
ServiceWorkerContextCore(const base::FilePath & path,base::SequencedTaskRunner * database_task_runner,base::MessageLoopProxy * disk_cache_thread,quota::QuotaManagerProxy * quota_manager_proxy,ObserverListThreadSafe<ServiceWorkerContextObserver> * observer_list,ServiceWorkerContextWrapper * wrapper)79 ServiceWorkerContextCore::ServiceWorkerContextCore(
80 const base::FilePath& path,
81 base::SequencedTaskRunner* database_task_runner,
82 base::MessageLoopProxy* disk_cache_thread,
83 quota::QuotaManagerProxy* quota_manager_proxy,
84 ObserverListThreadSafe<ServiceWorkerContextObserver>* observer_list,
85 ServiceWorkerContextWrapper* wrapper)
86 : weak_factory_(this),
87 wrapper_(wrapper),
88 storage_(new ServiceWorkerStorage(path,
89 AsWeakPtr(),
90 database_task_runner,
91 disk_cache_thread,
92 quota_manager_proxy)),
93 embedded_worker_registry_(new EmbeddedWorkerRegistry(AsWeakPtr())),
94 job_coordinator_(new ServiceWorkerJobCoordinator(AsWeakPtr())),
95 next_handle_id_(0),
96 observer_list_(observer_list) {
97 }
98
~ServiceWorkerContextCore()99 ServiceWorkerContextCore::~ServiceWorkerContextCore() {
100 for (VersionMap::iterator it = live_versions_.begin();
101 it != live_versions_.end();
102 ++it) {
103 it->second->RemoveListener(this);
104 }
105 weak_factory_.InvalidateWeakPtrs();
106 }
107
GetProviderHost(int process_id,int provider_id)108 ServiceWorkerProviderHost* ServiceWorkerContextCore::GetProviderHost(
109 int process_id, int provider_id) {
110 ProviderMap* map = GetProviderMapForProcess(process_id);
111 if (!map)
112 return NULL;
113 return map->Lookup(provider_id);
114 }
115
AddProviderHost(scoped_ptr<ServiceWorkerProviderHost> host)116 void ServiceWorkerContextCore::AddProviderHost(
117 scoped_ptr<ServiceWorkerProviderHost> host) {
118 ServiceWorkerProviderHost* host_ptr = host.release(); // we take ownership
119 ProviderMap* map = GetProviderMapForProcess(host_ptr->process_id());
120 if (!map) {
121 map = new ProviderMap;
122 providers_.AddWithID(map, host_ptr->process_id());
123 }
124 map->AddWithID(host_ptr, host_ptr->provider_id());
125 }
126
RemoveProviderHost(int process_id,int provider_id)127 void ServiceWorkerContextCore::RemoveProviderHost(
128 int process_id, int provider_id) {
129 ProviderMap* map = GetProviderMapForProcess(process_id);
130 DCHECK(map);
131 map->Remove(provider_id);
132 }
133
RemoveAllProviderHostsForProcess(int process_id)134 void ServiceWorkerContextCore::RemoveAllProviderHostsForProcess(
135 int process_id) {
136 if (providers_.Lookup(process_id))
137 providers_.Remove(process_id);
138 }
139
140 scoped_ptr<ServiceWorkerContextCore::ProviderHostIterator>
GetProviderHostIterator()141 ServiceWorkerContextCore::GetProviderHostIterator() {
142 return make_scoped_ptr(new ProviderHostIterator(&providers_));
143 }
144
RegisterServiceWorker(const GURL & pattern,const GURL & script_url,int source_process_id,ServiceWorkerProviderHost * provider_host,const RegistrationCallback & callback)145 void ServiceWorkerContextCore::RegisterServiceWorker(
146 const GURL& pattern,
147 const GURL& script_url,
148 int source_process_id,
149 ServiceWorkerProviderHost* provider_host,
150 const RegistrationCallback& callback) {
151 DCHECK_CURRENTLY_ON(BrowserThread::IO);
152
153 // TODO(kinuko): Wire the provider_host so that we can tell which document
154 // is calling .register.
155
156 job_coordinator_->Register(
157 pattern,
158 script_url,
159 source_process_id,
160 base::Bind(&ServiceWorkerContextCore::RegistrationComplete,
161 AsWeakPtr(),
162 pattern,
163 callback));
164 }
165
UnregisterServiceWorker(const GURL & pattern,const UnregistrationCallback & callback)166 void ServiceWorkerContextCore::UnregisterServiceWorker(
167 const GURL& pattern,
168 const UnregistrationCallback& callback) {
169 DCHECK_CURRENTLY_ON(BrowserThread::IO);
170
171 job_coordinator_->Unregister(
172 pattern,
173 base::Bind(&ServiceWorkerContextCore::UnregistrationComplete,
174 AsWeakPtr(),
175 pattern,
176 callback));
177 }
178
RegistrationComplete(const GURL & pattern,const ServiceWorkerContextCore::RegistrationCallback & callback,ServiceWorkerStatusCode status,ServiceWorkerRegistration * registration,ServiceWorkerVersion * version)179 void ServiceWorkerContextCore::RegistrationComplete(
180 const GURL& pattern,
181 const ServiceWorkerContextCore::RegistrationCallback& callback,
182 ServiceWorkerStatusCode status,
183 ServiceWorkerRegistration* registration,
184 ServiceWorkerVersion* version) {
185 if (status != SERVICE_WORKER_OK) {
186 DCHECK(!version);
187 callback.Run(status,
188 kInvalidServiceWorkerRegistrationId,
189 kInvalidServiceWorkerVersionId);
190 return;
191 }
192
193 DCHECK(version);
194 DCHECK_EQ(version->registration_id(), registration->id());
195 callback.Run(status,
196 registration->id(),
197 version->version_id());
198 if (observer_list_) {
199 observer_list_->Notify(&ServiceWorkerContextObserver::OnRegistrationStored,
200 pattern);
201 }
202 }
203
UnregistrationComplete(const GURL & pattern,const ServiceWorkerContextCore::UnregistrationCallback & callback,ServiceWorkerStatusCode status)204 void ServiceWorkerContextCore::UnregistrationComplete(
205 const GURL& pattern,
206 const ServiceWorkerContextCore::UnregistrationCallback& callback,
207 ServiceWorkerStatusCode status) {
208 callback.Run(status);
209 if (observer_list_) {
210 observer_list_->Notify(&ServiceWorkerContextObserver::OnRegistrationDeleted,
211 pattern);
212 }
213 }
214
GetLiveRegistration(int64 id)215 ServiceWorkerRegistration* ServiceWorkerContextCore::GetLiveRegistration(
216 int64 id) {
217 RegistrationsMap::iterator it = live_registrations_.find(id);
218 return (it != live_registrations_.end()) ? it->second : NULL;
219 }
220
AddLiveRegistration(ServiceWorkerRegistration * registration)221 void ServiceWorkerContextCore::AddLiveRegistration(
222 ServiceWorkerRegistration* registration) {
223 DCHECK(!GetLiveRegistration(registration->id()));
224 live_registrations_[registration->id()] = registration;
225 }
226
RemoveLiveRegistration(int64 id)227 void ServiceWorkerContextCore::RemoveLiveRegistration(int64 id) {
228 live_registrations_.erase(id);
229 }
230
GetLiveVersion(int64 id)231 ServiceWorkerVersion* ServiceWorkerContextCore::GetLiveVersion(
232 int64 id) {
233 VersionMap::iterator it = live_versions_.find(id);
234 return (it != live_versions_.end()) ? it->second : NULL;
235 }
236
AddLiveVersion(ServiceWorkerVersion * version)237 void ServiceWorkerContextCore::AddLiveVersion(ServiceWorkerVersion* version) {
238 DCHECK(!GetLiveVersion(version->version_id()));
239 live_versions_[version->version_id()] = version;
240 version->AddListener(this);
241 }
242
RemoveLiveVersion(int64 id)243 void ServiceWorkerContextCore::RemoveLiveVersion(int64 id) {
244 live_versions_.erase(id);
245 }
246
247 std::vector<ServiceWorkerRegistrationInfo>
GetAllLiveRegistrationInfo()248 ServiceWorkerContextCore::GetAllLiveRegistrationInfo() {
249 std::vector<ServiceWorkerRegistrationInfo> infos;
250 for (std::map<int64, ServiceWorkerRegistration*>::const_iterator iter =
251 live_registrations_.begin();
252 iter != live_registrations_.end();
253 ++iter) {
254 infos.push_back(iter->second->GetInfo());
255 }
256 return infos;
257 }
258
259 std::vector<ServiceWorkerVersionInfo>
GetAllLiveVersionInfo()260 ServiceWorkerContextCore::GetAllLiveVersionInfo() {
261 std::vector<ServiceWorkerVersionInfo> infos;
262 for (std::map<int64, ServiceWorkerVersion*>::const_iterator iter =
263 live_versions_.begin();
264 iter != live_versions_.end();
265 ++iter) {
266 infos.push_back(iter->second->GetInfo());
267 }
268 return infos;
269 }
270
GetNewServiceWorkerHandleId()271 int ServiceWorkerContextCore::GetNewServiceWorkerHandleId() {
272 return next_handle_id_++;
273 }
274
OnWorkerStarted(ServiceWorkerVersion * version)275 void ServiceWorkerContextCore::OnWorkerStarted(ServiceWorkerVersion* version) {
276 if (!observer_list_)
277 return;
278 observer_list_->Notify(&ServiceWorkerContextObserver::OnWorkerStarted,
279 version->version_id(),
280 version->embedded_worker()->process_id(),
281 version->embedded_worker()->thread_id());
282 }
283
OnWorkerStopped(ServiceWorkerVersion * version)284 void ServiceWorkerContextCore::OnWorkerStopped(ServiceWorkerVersion* version) {
285 if (!observer_list_)
286 return;
287 observer_list_->Notify(&ServiceWorkerContextObserver::OnWorkerStopped,
288 version->version_id(),
289 version->embedded_worker()->process_id(),
290 version->embedded_worker()->thread_id());
291 }
292
OnVersionStateChanged(ServiceWorkerVersion * version)293 void ServiceWorkerContextCore::OnVersionStateChanged(
294 ServiceWorkerVersion* version) {
295 if (!observer_list_)
296 return;
297 observer_list_->Notify(&ServiceWorkerContextObserver::OnVersionStateChanged,
298 version->version_id());
299 }
300
OnErrorReported(ServiceWorkerVersion * version,const base::string16 & error_message,int line_number,int column_number,const GURL & source_url)301 void ServiceWorkerContextCore::OnErrorReported(
302 ServiceWorkerVersion* version,
303 const base::string16& error_message,
304 int line_number,
305 int column_number,
306 const GURL& source_url) {
307 if (!observer_list_)
308 return;
309 observer_list_->Notify(
310 &ServiceWorkerContextObserver::OnErrorReported,
311 version->version_id(),
312 version->embedded_worker()->process_id(),
313 version->embedded_worker()->thread_id(),
314 ServiceWorkerContextObserver::ErrorInfo(
315 error_message, line_number, column_number, source_url));
316 }
317
OnReportConsoleMessage(ServiceWorkerVersion * version,int source_identifier,int message_level,const base::string16 & message,int line_number,const GURL & source_url)318 void ServiceWorkerContextCore::OnReportConsoleMessage(
319 ServiceWorkerVersion* version,
320 int source_identifier,
321 int message_level,
322 const base::string16& message,
323 int line_number,
324 const GURL& source_url) {
325 if (!observer_list_)
326 return;
327 observer_list_->Notify(
328 &ServiceWorkerContextObserver::OnReportConsoleMessage,
329 version->version_id(),
330 version->embedded_worker()->process_id(),
331 version->embedded_worker()->thread_id(),
332 ServiceWorkerContextObserver::ConsoleMessage(
333 source_identifier, message_level, message, line_number, source_url));
334 }
335
process_manager()336 ServiceWorkerProcessManager* ServiceWorkerContextCore::process_manager() {
337 return wrapper_->process_manager();
338 }
339
340 } // namespace content
341