[Android WebView] Upstream WebViewShell to chromium.
[chromium-blink-merge.git] / content / browser / service_worker / service_worker_context_wrapper.cc
blob0c092519cd722da3b6c7076ae94d4cbc750753a7
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_context_wrapper.h"
7 #include <map>
8 #include <set>
9 #include <string>
10 #include <vector>
12 #include "base/barrier_closure.h"
13 #include "base/bind.h"
14 #include "base/files/file_path.h"
15 #include "base/lazy_instance.h"
16 #include "base/logging.h"
17 #include "base/profiler/scoped_tracker.h"
18 #include "base/threading/sequenced_worker_pool.h"
19 #include "content/browser/service_worker/service_worker_context_core.h"
20 #include "content/browser/service_worker/service_worker_context_observer.h"
21 #include "content/browser/service_worker/service_worker_process_manager.h"
22 #include "content/browser/service_worker/service_worker_quota_client.h"
23 #include "content/browser/service_worker/service_worker_request_handler.h"
24 #include "content/browser/service_worker/service_worker_utils.h"
25 #include "content/browser/service_worker/service_worker_version.h"
26 #include "content/browser/storage_partition_impl.h"
27 #include "content/public/browser/browser_context.h"
28 #include "content/public/browser/browser_thread.h"
29 #include "content/public/browser/service_worker_context.h"
30 #include "net/base/net_errors.h"
31 #include "net/base/net_util.h"
32 #include "storage/browser/quota/quota_manager_proxy.h"
33 #include "storage/browser/quota/special_storage_policy.h"
35 namespace content {
37 namespace {
39 typedef std::set<std::string> HeaderNameSet;
40 base::LazyInstance<HeaderNameSet> g_excluded_header_name_set =
41 LAZY_INSTANCE_INITIALIZER;
43 void RunSoon(const base::Closure& closure) {
44 base::MessageLoop::current()->PostTask(FROM_HERE, closure);
47 void WorkerStarted(const ServiceWorkerContextWrapper::StatusCallback& callback,
48 ServiceWorkerStatusCode status) {
49 DCHECK_CURRENTLY_ON(BrowserThread::IO);
50 BrowserThread::PostTask(BrowserThread::UI, FROM_HERE,
51 base::Bind(callback, status));
54 void StartActiveWorkerOnIO(
55 const ServiceWorkerContextWrapper::StatusCallback& callback,
56 ServiceWorkerStatusCode status,
57 const scoped_refptr<ServiceWorkerRegistration>& registration) {
58 DCHECK_CURRENTLY_ON(BrowserThread::IO);
59 if (status == SERVICE_WORKER_OK) {
60 // Pass the reference of |registration| to WorkerStarted callback to prevent
61 // it from being deleted while starting the worker. If the refcount of
62 // |registration| is 1, it will be deleted after WorkerStarted is called.
63 registration->active_version()->StartWorker(
64 base::Bind(WorkerStarted, callback));
65 return;
67 BrowserThread::PostTask(BrowserThread::UI, FROM_HERE,
68 base::Bind(callback, SERVICE_WORKER_ERROR_NOT_FOUND));
71 } // namespace
73 void ServiceWorkerContext::AddExcludedHeadersForFetchEvent(
74 const std::set<std::string>& header_names) {
75 // TODO(pkasting): Remove ScopedTracker below once crbug.com/477117 is fixed.
76 tracked_objects::ScopedTracker tracking_profile(
77 FROM_HERE_WITH_EXPLICIT_FUNCTION(
78 "477117 ServiceWorkerContext::AddExcludedHeadersForFetchEvent"));
79 DCHECK_CURRENTLY_ON(BrowserThread::IO);
80 g_excluded_header_name_set.Get().insert(header_names.begin(),
81 header_names.end());
84 bool ServiceWorkerContext::IsExcludedHeaderNameForFetchEvent(
85 const std::string& header_name) {
86 DCHECK_CURRENTLY_ON(BrowserThread::IO);
87 return g_excluded_header_name_set.Get().find(header_name) !=
88 g_excluded_header_name_set.Get().end();
91 ServiceWorkerContext* ServiceWorkerContext::GetServiceWorkerContext(
92 net::URLRequest* request) {
93 DCHECK_CURRENTLY_ON(BrowserThread::IO);
94 ServiceWorkerRequestHandler* handler =
95 ServiceWorkerRequestHandler::GetHandler(request);
96 if (!handler || !handler->context())
97 return nullptr;
98 return handler->context()->wrapper_;
101 ServiceWorkerContextWrapper::ServiceWorkerContextWrapper(
102 BrowserContext* browser_context)
103 : observer_list_(
104 new ObserverListThreadSafe<ServiceWorkerContextObserver>()),
105 process_manager_(new ServiceWorkerProcessManager(browser_context)),
106 is_incognito_(false),
107 storage_partition_(nullptr) {
108 DCHECK_CURRENTLY_ON(BrowserThread::UI);
111 ServiceWorkerContextWrapper::~ServiceWorkerContextWrapper() {
114 void ServiceWorkerContextWrapper::Init(
115 const base::FilePath& user_data_directory,
116 storage::QuotaManagerProxy* quota_manager_proxy,
117 storage::SpecialStoragePolicy* special_storage_policy) {
118 DCHECK_CURRENTLY_ON(BrowserThread::UI);
120 is_incognito_ = user_data_directory.empty();
121 base::SequencedWorkerPool* pool = BrowserThread::GetBlockingPool();
122 scoped_ptr<ServiceWorkerDatabaseTaskManager> database_task_manager(
123 new ServiceWorkerDatabaseTaskManagerImpl(pool));
124 scoped_refptr<base::SingleThreadTaskRunner> disk_cache_thread =
125 BrowserThread::GetMessageLoopProxyForThread(BrowserThread::CACHE);
126 InitInternal(user_data_directory,
127 database_task_manager.Pass(),
128 disk_cache_thread,
129 quota_manager_proxy,
130 special_storage_policy);
133 void ServiceWorkerContextWrapper::Shutdown() {
134 DCHECK_CURRENTLY_ON(BrowserThread::UI);
136 storage_partition_ = nullptr;
137 process_manager_->Shutdown();
138 BrowserThread::PostTask(
139 BrowserThread::IO,
140 FROM_HERE,
141 base::Bind(&ServiceWorkerContextWrapper::ShutdownOnIO, this));
144 void ServiceWorkerContextWrapper::DeleteAndStartOver() {
145 DCHECK_CURRENTLY_ON(BrowserThread::IO);
146 context_core_->DeleteAndStartOver(
147 base::Bind(&ServiceWorkerContextWrapper::DidDeleteAndStartOver, this));
150 ServiceWorkerContextCore* ServiceWorkerContextWrapper::context() {
151 DCHECK_CURRENTLY_ON(BrowserThread::IO);
152 return context_core_.get();
155 StoragePartitionImpl* ServiceWorkerContextWrapper::storage_partition() const {
156 DCHECK_CURRENTLY_ON(BrowserThread::UI);
157 return storage_partition_;
160 void ServiceWorkerContextWrapper::set_storage_partition(
161 StoragePartitionImpl* storage_partition) {
162 DCHECK_CURRENTLY_ON(BrowserThread::UI);
163 storage_partition_ = storage_partition;
166 static void FinishRegistrationOnIO(
167 const ServiceWorkerContext::ResultCallback& continuation,
168 ServiceWorkerStatusCode status,
169 const std::string& status_message,
170 int64 registration_id) {
171 DCHECK_CURRENTLY_ON(BrowserThread::IO);
172 BrowserThread::PostTask(
173 BrowserThread::UI,
174 FROM_HERE,
175 base::Bind(continuation, status == SERVICE_WORKER_OK));
178 void ServiceWorkerContextWrapper::RegisterServiceWorker(
179 const GURL& pattern,
180 const GURL& script_url,
181 const ResultCallback& continuation) {
182 if (!BrowserThread::CurrentlyOn(BrowserThread::IO)) {
183 BrowserThread::PostTask(
184 BrowserThread::IO,
185 FROM_HERE,
186 base::Bind(&ServiceWorkerContextWrapper::RegisterServiceWorker,
187 this,
188 pattern,
189 script_url,
190 continuation));
191 return;
193 if (!context_core_.get()) {
194 LOG(ERROR) << "ServiceWorkerContextCore is no longer alive.";
195 BrowserThread::PostTask(
196 BrowserThread::IO,
197 FROM_HERE,
198 base::Bind(continuation, false));
199 return;
201 context()->RegisterServiceWorker(
202 pattern,
203 script_url,
204 NULL /* provider_host */,
205 base::Bind(&FinishRegistrationOnIO, continuation));
208 static void FinishUnregistrationOnIO(
209 const ServiceWorkerContext::ResultCallback& continuation,
210 ServiceWorkerStatusCode status) {
211 DCHECK_CURRENTLY_ON(BrowserThread::IO);
212 BrowserThread::PostTask(
213 BrowserThread::UI,
214 FROM_HERE,
215 base::Bind(continuation, status == SERVICE_WORKER_OK));
218 void ServiceWorkerContextWrapper::UnregisterServiceWorker(
219 const GURL& pattern,
220 const ResultCallback& continuation) {
221 if (!BrowserThread::CurrentlyOn(BrowserThread::IO)) {
222 BrowserThread::PostTask(
223 BrowserThread::IO,
224 FROM_HERE,
225 base::Bind(&ServiceWorkerContextWrapper::UnregisterServiceWorker,
226 this,
227 pattern,
228 continuation));
229 return;
231 if (!context_core_.get()) {
232 LOG(ERROR) << "ServiceWorkerContextCore is no longer alive.";
233 BrowserThread::PostTask(
234 BrowserThread::IO,
235 FROM_HERE,
236 base::Bind(continuation, false));
237 return;
240 context()->UnregisterServiceWorker(
241 pattern,
242 base::Bind(&FinishUnregistrationOnIO, continuation));
245 void ServiceWorkerContextWrapper::UpdateRegistration(const GURL& pattern) {
246 if (!BrowserThread::CurrentlyOn(BrowserThread::IO)) {
247 BrowserThread::PostTask(
248 BrowserThread::IO, FROM_HERE,
249 base::Bind(&ServiceWorkerContextWrapper::UpdateRegistration, this,
250 pattern));
251 return;
253 if (!context_core_.get()) {
254 LOG(ERROR) << "ServiceWorkerContextCore is no longer alive.";
255 return;
257 context_core_->storage()->FindRegistrationForPattern(
258 pattern,
259 base::Bind(&ServiceWorkerContextWrapper::DidFindRegistrationForUpdate,
260 this));
263 void ServiceWorkerContextWrapper::StartServiceWorker(
264 const GURL& pattern,
265 const StatusCallback& callback) {
266 if (!BrowserThread::CurrentlyOn(BrowserThread::IO)) {
267 BrowserThread::PostTask(
268 BrowserThread::IO, FROM_HERE,
269 base::Bind(&ServiceWorkerContextWrapper::StartServiceWorker, this,
270 pattern, callback));
271 return;
273 if (!context_core_.get()) {
274 LOG(ERROR) << "ServiceWorkerContextCore is no longer alive.";
275 BrowserThread::PostTask(BrowserThread::UI, FROM_HERE,
276 base::Bind(callback, SERVICE_WORKER_ERROR_ABORT));
277 return;
279 context_core_->storage()->FindRegistrationForPattern(
280 pattern, base::Bind(&StartActiveWorkerOnIO, callback));
283 static void DidFindRegistrationForDocument(
284 const net::CompletionCallback& callback,
285 ServiceWorkerStatusCode status,
286 const scoped_refptr<ServiceWorkerRegistration>& registration) {
287 int rv = registration ? net::OK : net::ERR_CACHE_MISS;
288 // Use RunSoon here because FindRegistrationForDocument can complete
289 // immediately but CanHandleMainResourceOffline must be async.
290 RunSoon(base::Bind(callback, rv));
293 void ServiceWorkerContextWrapper::CanHandleMainResourceOffline(
294 const GURL& url,
295 const GURL& first_party,
296 const net::CompletionCallback& callback) {
297 DCHECK_CURRENTLY_ON(BrowserThread::IO);
298 context()->storage()->FindRegistrationForDocument(
299 url,
300 base::Bind(&DidFindRegistrationForDocument, callback));
303 void ServiceWorkerContextWrapper::GetAllOriginsInfo(
304 const GetUsageInfoCallback& callback) {
305 DCHECK_CURRENTLY_ON(BrowserThread::IO);
306 if (!context_core_.get()) {
307 LOG(ERROR) << "ServiceWorkerContextCore is no longer alive.";
308 BrowserThread::PostTask(
309 BrowserThread::IO,
310 FROM_HERE,
311 base::Bind(callback, std::vector<ServiceWorkerUsageInfo>()));
312 return;
314 context()->storage()->GetAllRegistrations(base::Bind(
315 &ServiceWorkerContextWrapper::DidGetAllRegistrationsForGetAllOrigins,
316 this,
317 callback));
320 void ServiceWorkerContextWrapper::DidGetAllRegistrationsForGetAllOrigins(
321 const GetUsageInfoCallback& callback,
322 const std::vector<ServiceWorkerRegistrationInfo>& registrations) {
323 DCHECK_CURRENTLY_ON(BrowserThread::IO);
324 std::vector<ServiceWorkerUsageInfo> usage_infos;
326 std::map<GURL, ServiceWorkerUsageInfo> origins;
327 for (const auto& registration_info : registrations) {
328 GURL origin = registration_info.pattern.GetOrigin();
330 ServiceWorkerUsageInfo& usage_info = origins[origin];
331 if (usage_info.origin.is_empty())
332 usage_info.origin = origin;
333 usage_info.scopes.push_back(registration_info.pattern);
334 usage_info.total_size_bytes += registration_info.stored_version_size_bytes;
337 for (const auto& origin_info_pair : origins) {
338 usage_infos.push_back(origin_info_pair.second);
340 callback.Run(usage_infos);
343 void ServiceWorkerContextWrapper::DidFindRegistrationForCheckHasServiceWorker(
344 const GURL& other_url,
345 const CheckHasServiceWorkerCallback& callback,
346 ServiceWorkerStatusCode status,
347 const scoped_refptr<ServiceWorkerRegistration>& registration) {
348 DCHECK_CURRENTLY_ON(BrowserThread::IO);
350 if (status != SERVICE_WORKER_OK) {
351 BrowserThread::PostTask(BrowserThread::UI, FROM_HERE,
352 base::Bind(callback, false));
353 return;
356 DCHECK(registration);
357 BrowserThread::PostTask(
358 BrowserThread::UI, FROM_HERE,
359 base::Bind(callback, registration->active_version() &&
360 ServiceWorkerUtils::ScopeMatches(
361 registration->pattern(), other_url)));
364 void ServiceWorkerContextWrapper::DidFindRegistrationForUpdate(
365 ServiceWorkerStatusCode status,
366 const scoped_refptr<ServiceWorkerRegistration>& registration) {
367 DCHECK_CURRENTLY_ON(BrowserThread::IO);
369 if (status != SERVICE_WORKER_OK)
370 return;
371 if (!context_core_.get()) {
372 LOG(ERROR) << "ServiceWorkerContextCore is no longer alive.";
373 return;
375 DCHECK(registration);
376 context_core_->UpdateServiceWorker(registration.get(),
377 true /* force_bypass_cache */);
380 namespace {
381 void StatusCodeToBoolCallbackAdapter(
382 const ServiceWorkerContext::ResultCallback& callback,
383 ServiceWorkerStatusCode code) {
384 callback.Run(code == ServiceWorkerStatusCode::SERVICE_WORKER_OK);
387 void EmptySuccessCallback(bool success) {
389 } // namespace
391 void ServiceWorkerContextWrapper::DeleteForOrigin(
392 const GURL& origin_url,
393 const ResultCallback& result) {
394 DCHECK_CURRENTLY_ON(BrowserThread::IO);
395 if (!context_core_.get()) {
396 LOG(ERROR) << "ServiceWorkerContextCore is no longer alive.";
397 BrowserThread::PostTask(
398 BrowserThread::IO,
399 FROM_HERE,
400 base::Bind(result, false));
401 return;
403 context()->UnregisterServiceWorkers(
404 origin_url, base::Bind(&StatusCodeToBoolCallbackAdapter, result));
407 void ServiceWorkerContextWrapper::DeleteForOrigin(const GURL& origin_url) {
408 DeleteForOrigin(origin_url, base::Bind(&EmptySuccessCallback));
411 void ServiceWorkerContextWrapper::CheckHasServiceWorker(
412 const GURL& url,
413 const GURL& other_url,
414 const CheckHasServiceWorkerCallback& callback) {
415 if (!BrowserThread::CurrentlyOn(BrowserThread::IO)) {
416 BrowserThread::PostTask(
417 BrowserThread::IO, FROM_HERE,
418 base::Bind(&ServiceWorkerContextWrapper::CheckHasServiceWorker, this,
419 url, other_url, callback));
420 return;
422 if (!context_core_.get()) {
423 LOG(ERROR) << "ServiceWorkerContextCore is no longer alive.";
424 BrowserThread::PostTask(BrowserThread::IO, FROM_HERE,
425 base::Bind(callback, false));
426 return;
428 GURL stripped_url = net::SimplifyUrlForRequest(url);
429 context()->storage()->FindRegistrationForDocument(
430 stripped_url, base::Bind(&ServiceWorkerContextWrapper::
431 DidFindRegistrationForCheckHasServiceWorker,
432 this, other_url, callback));
435 void ServiceWorkerContextWrapper::AddObserver(
436 ServiceWorkerContextObserver* observer) {
437 observer_list_->AddObserver(observer);
440 void ServiceWorkerContextWrapper::RemoveObserver(
441 ServiceWorkerContextObserver* observer) {
442 observer_list_->RemoveObserver(observer);
445 void ServiceWorkerContextWrapper::InitInternal(
446 const base::FilePath& user_data_directory,
447 scoped_ptr<ServiceWorkerDatabaseTaskManager> database_task_manager,
448 const scoped_refptr<base::SingleThreadTaskRunner>& disk_cache_thread,
449 storage::QuotaManagerProxy* quota_manager_proxy,
450 storage::SpecialStoragePolicy* special_storage_policy) {
451 if (!BrowserThread::CurrentlyOn(BrowserThread::IO)) {
452 BrowserThread::PostTask(
453 BrowserThread::IO,
454 FROM_HERE,
455 base::Bind(&ServiceWorkerContextWrapper::InitInternal,
456 this,
457 user_data_directory,
458 base::Passed(&database_task_manager),
459 disk_cache_thread,
460 make_scoped_refptr(quota_manager_proxy),
461 make_scoped_refptr(special_storage_policy)));
462 return;
464 // TODO(pkasting): Remove ScopedTracker below once crbug.com/477117 is fixed.
465 tracked_objects::ScopedTracker tracking_profile(
466 FROM_HERE_WITH_EXPLICIT_FUNCTION(
467 "477117 ServiceWorkerContextWrapper::InitInternal"));
468 DCHECK(!context_core_);
469 if (quota_manager_proxy) {
470 quota_manager_proxy->RegisterClient(new ServiceWorkerQuotaClient(this));
472 context_core_.reset(new ServiceWorkerContextCore(user_data_directory,
473 database_task_manager.Pass(),
474 disk_cache_thread,
475 quota_manager_proxy,
476 special_storage_policy,
477 observer_list_.get(),
478 this));
481 void ServiceWorkerContextWrapper::ShutdownOnIO() {
482 DCHECK_CURRENTLY_ON(BrowserThread::IO);
483 context_core_.reset();
486 void ServiceWorkerContextWrapper::DidDeleteAndStartOver(
487 ServiceWorkerStatusCode status) {
488 DCHECK_CURRENTLY_ON(BrowserThread::IO);
489 if (status != SERVICE_WORKER_OK) {
490 context_core_.reset();
491 return;
493 context_core_.reset(new ServiceWorkerContextCore(context_core_.get(), this));
494 DVLOG(1) << "Restarted ServiceWorkerContextCore successfully.";
496 observer_list_->Notify(FROM_HERE,
497 &ServiceWorkerContextObserver::OnStorageWiped);
500 } // namespace content