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_wrapper.h"
6
7 #include <map>
8
9 #include "base/files/file_path.h"
10 #include "base/logging.h"
11 #include "base/threading/sequenced_worker_pool.h"
12 #include "content/browser/fileapi/chrome_blob_storage_context.h"
13 #include "content/browser/service_worker/service_worker_context_core.h"
14 #include "content/browser/service_worker/service_worker_context_observer.h"
15 #include "content/browser/service_worker/service_worker_process_manager.h"
16 #include "content/public/browser/browser_context.h"
17 #include "content/public/browser/browser_thread.h"
18 #include "net/url_request/url_request_context_getter.h"
19 #include "storage/browser/blob/blob_storage_context.h"
20 #include "storage/browser/quota/quota_manager_proxy.h"
21
22 namespace content {
23
ServiceWorkerContextWrapper(BrowserContext * browser_context)24 ServiceWorkerContextWrapper::ServiceWorkerContextWrapper(
25 BrowserContext* browser_context)
26 : observer_list_(
27 new ObserverListThreadSafe<ServiceWorkerContextObserver>()),
28 process_manager_(new ServiceWorkerProcessManager(browser_context)),
29 is_incognito_(false) {
30 }
31
~ServiceWorkerContextWrapper()32 ServiceWorkerContextWrapper::~ServiceWorkerContextWrapper() {
33 }
34
Init(const base::FilePath & user_data_directory,storage::QuotaManagerProxy * quota_manager_proxy)35 void ServiceWorkerContextWrapper::Init(
36 const base::FilePath& user_data_directory,
37 storage::QuotaManagerProxy* quota_manager_proxy) {
38 is_incognito_ = user_data_directory.empty();
39 scoped_refptr<base::SequencedTaskRunner> database_task_runner =
40 BrowserThread::GetBlockingPool()->
41 GetSequencedTaskRunnerWithShutdownBehavior(
42 BrowserThread::GetBlockingPool()->GetSequenceToken(),
43 base::SequencedWorkerPool::SKIP_ON_SHUTDOWN);
44 scoped_refptr<base::SingleThreadTaskRunner> disk_cache_thread =
45 BrowserThread::GetMessageLoopProxyForThread(BrowserThread::CACHE);
46 scoped_refptr<base::SequencedTaskRunner> cache_task_runner =
47 BrowserThread::GetBlockingPool()
48 ->GetSequencedTaskRunnerWithShutdownBehavior(
49 BrowserThread::GetBlockingPool()->GetSequenceToken(),
50 base::SequencedWorkerPool::SKIP_ON_SHUTDOWN);
51 InitInternal(user_data_directory,
52 cache_task_runner,
53 database_task_runner,
54 disk_cache_thread,
55 quota_manager_proxy);
56 }
57
Shutdown()58 void ServiceWorkerContextWrapper::Shutdown() {
59 DCHECK_CURRENTLY_ON(BrowserThread::UI);
60 process_manager_->Shutdown();
61 BrowserThread::PostTask(
62 BrowserThread::IO,
63 FROM_HERE,
64 base::Bind(&ServiceWorkerContextWrapper::ShutdownOnIO, this));
65 }
66
DeleteAndStartOver()67 void ServiceWorkerContextWrapper::DeleteAndStartOver() {
68 DCHECK_CURRENTLY_ON(BrowserThread::IO);
69 context_core_->DeleteAndStartOver(
70 base::Bind(&ServiceWorkerContextWrapper::DidDeleteAndStartOver, this));
71 }
72
context()73 ServiceWorkerContextCore* ServiceWorkerContextWrapper::context() {
74 DCHECK_CURRENTLY_ON(BrowserThread::IO);
75 return context_core_.get();
76 }
77
FinishRegistrationOnIO(const ServiceWorkerContext::ResultCallback & continuation,ServiceWorkerStatusCode status,int64 registration_id,int64 version_id)78 static void FinishRegistrationOnIO(
79 const ServiceWorkerContext::ResultCallback& continuation,
80 ServiceWorkerStatusCode status,
81 int64 registration_id,
82 int64 version_id) {
83 DCHECK_CURRENTLY_ON(BrowserThread::IO);
84 BrowserThread::PostTask(
85 BrowserThread::UI,
86 FROM_HERE,
87 base::Bind(continuation, status == SERVICE_WORKER_OK));
88 }
89
RegisterServiceWorker(const GURL & pattern,const GURL & script_url,const ResultCallback & continuation)90 void ServiceWorkerContextWrapper::RegisterServiceWorker(
91 const GURL& pattern,
92 const GURL& script_url,
93 const ResultCallback& continuation) {
94 if (!BrowserThread::CurrentlyOn(BrowserThread::IO)) {
95 BrowserThread::PostTask(
96 BrowserThread::IO,
97 FROM_HERE,
98 base::Bind(&ServiceWorkerContextWrapper::RegisterServiceWorker,
99 this,
100 pattern,
101 script_url,
102 continuation));
103 return;
104 }
105
106 context()->RegisterServiceWorker(
107 pattern,
108 script_url,
109 NULL /* provider_host */,
110 base::Bind(&FinishRegistrationOnIO, continuation));
111 }
112
FinishUnregistrationOnIO(const ServiceWorkerContext::ResultCallback & continuation,ServiceWorkerStatusCode status)113 static void FinishUnregistrationOnIO(
114 const ServiceWorkerContext::ResultCallback& continuation,
115 ServiceWorkerStatusCode status) {
116 DCHECK_CURRENTLY_ON(BrowserThread::IO);
117 BrowserThread::PostTask(
118 BrowserThread::UI,
119 FROM_HERE,
120 base::Bind(continuation, status == SERVICE_WORKER_OK));
121 }
122
UnregisterServiceWorker(const GURL & pattern,const ResultCallback & continuation)123 void ServiceWorkerContextWrapper::UnregisterServiceWorker(
124 const GURL& pattern,
125 const ResultCallback& continuation) {
126 if (!BrowserThread::CurrentlyOn(BrowserThread::IO)) {
127 BrowserThread::PostTask(
128 BrowserThread::IO,
129 FROM_HERE,
130 base::Bind(&ServiceWorkerContextWrapper::UnregisterServiceWorker,
131 this,
132 pattern,
133 continuation));
134 return;
135 }
136
137 context()->UnregisterServiceWorker(
138 pattern,
139 base::Bind(&FinishUnregistrationOnIO, continuation));
140 }
141
Terminate()142 void ServiceWorkerContextWrapper::Terminate() {
143 DCHECK_CURRENTLY_ON(BrowserThread::UI);
144 process_manager_->Shutdown();
145 }
146
GetAllOriginsInfo(const GetUsageInfoCallback & callback)147 void ServiceWorkerContextWrapper::GetAllOriginsInfo(
148 const GetUsageInfoCallback& callback) {
149 DCHECK_CURRENTLY_ON(BrowserThread::IO);
150 context_core_->storage()->GetAllRegistrations(base::Bind(
151 &ServiceWorkerContextWrapper::DidGetAllRegistrationsForGetAllOrigins,
152 this,
153 callback));
154 }
155
DidGetAllRegistrationsForGetAllOrigins(const GetUsageInfoCallback & callback,const std::vector<ServiceWorkerRegistrationInfo> & registrations)156 void ServiceWorkerContextWrapper::DidGetAllRegistrationsForGetAllOrigins(
157 const GetUsageInfoCallback& callback,
158 const std::vector<ServiceWorkerRegistrationInfo>& registrations) {
159 DCHECK_CURRENTLY_ON(BrowserThread::IO);
160 std::vector<ServiceWorkerUsageInfo> usage_infos;
161
162 std::map<GURL, ServiceWorkerUsageInfo> origins;
163 for (std::vector<ServiceWorkerRegistrationInfo>::const_iterator it =
164 registrations.begin();
165 it != registrations.end();
166 ++it) {
167 const ServiceWorkerRegistrationInfo& registration_info = *it;
168 GURL origin = registration_info.pattern.GetOrigin();
169
170 ServiceWorkerUsageInfo& usage_info = origins[origin];
171 if (usage_info.origin.is_empty())
172 usage_info.origin = origin;
173 usage_info.scopes.push_back(registration_info.pattern);
174 }
175
176 for (std::map<GURL, ServiceWorkerUsageInfo>::const_iterator it =
177 origins.begin();
178 it != origins.end();
179 ++it) {
180 usage_infos.push_back(it->second);
181 }
182
183 callback.Run(usage_infos);
184 }
185
186 namespace {
187
EmptySuccessCallback(bool success)188 void EmptySuccessCallback(bool success) {
189 }
190
191 } // namespace
192
DeleteForOrigin(const GURL & origin_url)193 void ServiceWorkerContextWrapper::DeleteForOrigin(const GURL& origin_url) {
194 DCHECK_CURRENTLY_ON(BrowserThread::IO);
195 context_core_->storage()->GetAllRegistrations(base::Bind(
196 &ServiceWorkerContextWrapper::DidGetAllRegistrationsForDeleteForOrigin,
197 this,
198 origin_url));
199 }
200
DidGetAllRegistrationsForDeleteForOrigin(const GURL & origin,const std::vector<ServiceWorkerRegistrationInfo> & registrations)201 void ServiceWorkerContextWrapper::DidGetAllRegistrationsForDeleteForOrigin(
202 const GURL& origin,
203 const std::vector<ServiceWorkerRegistrationInfo>& registrations) {
204 DCHECK_CURRENTLY_ON(BrowserThread::IO);
205
206 for (std::vector<ServiceWorkerRegistrationInfo>::const_iterator it =
207 registrations.begin();
208 it != registrations.end();
209 ++it) {
210 const ServiceWorkerRegistrationInfo& registration_info = *it;
211 if (origin == registration_info.pattern.GetOrigin()) {
212 UnregisterServiceWorker(registration_info.pattern,
213 base::Bind(&EmptySuccessCallback));
214 }
215 }
216 }
217
AddObserver(ServiceWorkerContextObserver * observer)218 void ServiceWorkerContextWrapper::AddObserver(
219 ServiceWorkerContextObserver* observer) {
220 observer_list_->AddObserver(observer);
221 }
222
RemoveObserver(ServiceWorkerContextObserver * observer)223 void ServiceWorkerContextWrapper::RemoveObserver(
224 ServiceWorkerContextObserver* observer) {
225 observer_list_->RemoveObserver(observer);
226 }
227
SetBlobParametersForCache(net::URLRequestContextGetter * request_context,ChromeBlobStorageContext * blob_storage_context)228 void ServiceWorkerContextWrapper::SetBlobParametersForCache(
229 net::URLRequestContextGetter* request_context,
230 ChromeBlobStorageContext* blob_storage_context) {
231 DCHECK_CURRENTLY_ON(BrowserThread::IO);
232
233 if (context_core_ && request_context && blob_storage_context) {
234 context_core_->SetBlobParametersForCache(
235 request_context->GetURLRequestContext(),
236 blob_storage_context->context()->AsWeakPtr());
237 }
238 }
239
InitInternal(const base::FilePath & user_data_directory,const scoped_refptr<base::SequencedTaskRunner> & stores_task_runner,const scoped_refptr<base::SequencedTaskRunner> & database_task_runner,const scoped_refptr<base::SingleThreadTaskRunner> & disk_cache_thread,storage::QuotaManagerProxy * quota_manager_proxy)240 void ServiceWorkerContextWrapper::InitInternal(
241 const base::FilePath& user_data_directory,
242 const scoped_refptr<base::SequencedTaskRunner>& stores_task_runner,
243 const scoped_refptr<base::SequencedTaskRunner>& database_task_runner,
244 const scoped_refptr<base::SingleThreadTaskRunner>& disk_cache_thread,
245 storage::QuotaManagerProxy* quota_manager_proxy) {
246 if (!BrowserThread::CurrentlyOn(BrowserThread::IO)) {
247 BrowserThread::PostTask(
248 BrowserThread::IO,
249 FROM_HERE,
250 base::Bind(&ServiceWorkerContextWrapper::InitInternal,
251 this,
252 user_data_directory,
253 stores_task_runner,
254 database_task_runner,
255 disk_cache_thread,
256 make_scoped_refptr(quota_manager_proxy)));
257 return;
258 }
259 DCHECK(!context_core_);
260 context_core_.reset(new ServiceWorkerContextCore(user_data_directory,
261 stores_task_runner,
262 database_task_runner,
263 disk_cache_thread,
264 quota_manager_proxy,
265 observer_list_.get(),
266 this));
267 }
268
ShutdownOnIO()269 void ServiceWorkerContextWrapper::ShutdownOnIO() {
270 DCHECK_CURRENTLY_ON(BrowserThread::IO);
271 context_core_.reset();
272 }
273
DidDeleteAndStartOver(ServiceWorkerStatusCode status)274 void ServiceWorkerContextWrapper::DidDeleteAndStartOver(
275 ServiceWorkerStatusCode status) {
276 DCHECK_CURRENTLY_ON(BrowserThread::IO);
277 if (status != SERVICE_WORKER_OK) {
278 context_core_.reset();
279 return;
280 }
281 context_core_.reset(new ServiceWorkerContextCore(context_core_.get(), this));
282 DVLOG(1) << "Restarted ServiceWorkerContextCore successfully.";
283 }
284
285 } // namespace content
286