Supervised user whitelists: Cleanup
[chromium-blink-merge.git] / content / browser / service_worker / service_worker_context_wrapper.cc
blobdb7262236633fd80ad3489a9217ff3a4a778b386
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 StoragePartitionImpl* ServiceWorkerContextWrapper::storage_partition() const {
151 DCHECK_CURRENTLY_ON(BrowserThread::UI);
152 return storage_partition_;
155 void ServiceWorkerContextWrapper::set_storage_partition(
156 StoragePartitionImpl* storage_partition) {
157 DCHECK_CURRENTLY_ON(BrowserThread::UI);
158 storage_partition_ = storage_partition;
161 static void FinishRegistrationOnIO(
162 const ServiceWorkerContext::ResultCallback& continuation,
163 ServiceWorkerStatusCode status,
164 const std::string& status_message,
165 int64 registration_id) {
166 DCHECK_CURRENTLY_ON(BrowserThread::IO);
167 BrowserThread::PostTask(
168 BrowserThread::UI,
169 FROM_HERE,
170 base::Bind(continuation, status == SERVICE_WORKER_OK));
173 void ServiceWorkerContextWrapper::RegisterServiceWorker(
174 const GURL& pattern,
175 const GURL& script_url,
176 const ResultCallback& continuation) {
177 if (!BrowserThread::CurrentlyOn(BrowserThread::IO)) {
178 BrowserThread::PostTask(
179 BrowserThread::IO,
180 FROM_HERE,
181 base::Bind(&ServiceWorkerContextWrapper::RegisterServiceWorker,
182 this,
183 pattern,
184 script_url,
185 continuation));
186 return;
188 if (!context_core_.get()) {
189 LOG(ERROR) << "ServiceWorkerContextCore is no longer alive.";
190 BrowserThread::PostTask(
191 BrowserThread::IO,
192 FROM_HERE,
193 base::Bind(continuation, false));
194 return;
196 context()->RegisterServiceWorker(
197 pattern,
198 script_url,
199 NULL /* provider_host */,
200 base::Bind(&FinishRegistrationOnIO, continuation));
203 static void FinishUnregistrationOnIO(
204 const ServiceWorkerContext::ResultCallback& continuation,
205 ServiceWorkerStatusCode status) {
206 DCHECK_CURRENTLY_ON(BrowserThread::IO);
207 BrowserThread::PostTask(
208 BrowserThread::UI,
209 FROM_HERE,
210 base::Bind(continuation, status == SERVICE_WORKER_OK));
213 void ServiceWorkerContextWrapper::UnregisterServiceWorker(
214 const GURL& pattern,
215 const ResultCallback& continuation) {
216 if (!BrowserThread::CurrentlyOn(BrowserThread::IO)) {
217 BrowserThread::PostTask(
218 BrowserThread::IO,
219 FROM_HERE,
220 base::Bind(&ServiceWorkerContextWrapper::UnregisterServiceWorker,
221 this,
222 pattern,
223 continuation));
224 return;
226 if (!context_core_.get()) {
227 LOG(ERROR) << "ServiceWorkerContextCore is no longer alive.";
228 BrowserThread::PostTask(
229 BrowserThread::IO,
230 FROM_HERE,
231 base::Bind(continuation, false));
232 return;
235 context()->UnregisterServiceWorker(
236 pattern,
237 base::Bind(&FinishUnregistrationOnIO, continuation));
240 void ServiceWorkerContextWrapper::UpdateRegistration(const GURL& pattern) {
241 if (!BrowserThread::CurrentlyOn(BrowserThread::IO)) {
242 BrowserThread::PostTask(
243 BrowserThread::IO, FROM_HERE,
244 base::Bind(&ServiceWorkerContextWrapper::UpdateRegistration, this,
245 pattern));
246 return;
248 if (!context_core_.get()) {
249 LOG(ERROR) << "ServiceWorkerContextCore is no longer alive.";
250 return;
252 context_core_->storage()->FindRegistrationForPattern(
253 pattern,
254 base::Bind(&ServiceWorkerContextWrapper::DidFindRegistrationForUpdate,
255 this));
258 void ServiceWorkerContextWrapper::StartServiceWorker(
259 const GURL& pattern,
260 const StatusCallback& callback) {
261 if (!BrowserThread::CurrentlyOn(BrowserThread::IO)) {
262 BrowserThread::PostTask(
263 BrowserThread::IO, FROM_HERE,
264 base::Bind(&ServiceWorkerContextWrapper::StartServiceWorker, this,
265 pattern, callback));
266 return;
268 if (!context_core_.get()) {
269 LOG(ERROR) << "ServiceWorkerContextCore is no longer alive.";
270 BrowserThread::PostTask(BrowserThread::UI, FROM_HERE,
271 base::Bind(callback, SERVICE_WORKER_ERROR_ABORT));
272 return;
274 context_core_->storage()->FindRegistrationForPattern(
275 pattern, base::Bind(&StartActiveWorkerOnIO, callback));
278 static void DidFindRegistrationForDocument(
279 const net::CompletionCallback& callback,
280 ServiceWorkerStatusCode status,
281 const scoped_refptr<ServiceWorkerRegistration>& registration) {
282 int rv = registration ? net::OK : net::ERR_CACHE_MISS;
283 // Use RunSoon here because FindRegistrationForDocument can complete
284 // immediately but CanHandleMainResourceOffline must be async.
285 RunSoon(base::Bind(callback, rv));
288 void ServiceWorkerContextWrapper::CanHandleMainResourceOffline(
289 const GURL& url,
290 const GURL& first_party,
291 const net::CompletionCallback& callback) {
292 DCHECK_CURRENTLY_ON(BrowserThread::IO);
293 context()->storage()->FindRegistrationForDocument(
294 url,
295 base::Bind(&DidFindRegistrationForDocument, callback));
298 void ServiceWorkerContextWrapper::GetAllOriginsInfo(
299 const GetUsageInfoCallback& callback) {
300 DCHECK_CURRENTLY_ON(BrowserThread::IO);
301 if (!context_core_.get()) {
302 LOG(ERROR) << "ServiceWorkerContextCore is no longer alive.";
303 BrowserThread::PostTask(
304 BrowserThread::IO,
305 FROM_HERE,
306 base::Bind(callback, std::vector<ServiceWorkerUsageInfo>()));
307 return;
309 context()->storage()->GetAllRegistrations(base::Bind(
310 &ServiceWorkerContextWrapper::DidGetAllRegistrationsForGetAllOrigins,
311 this,
312 callback));
315 void ServiceWorkerContextWrapper::DidGetAllRegistrationsForGetAllOrigins(
316 const GetUsageInfoCallback& callback,
317 const std::vector<ServiceWorkerRegistrationInfo>& registrations) {
318 DCHECK_CURRENTLY_ON(BrowserThread::IO);
319 std::vector<ServiceWorkerUsageInfo> usage_infos;
321 std::map<GURL, ServiceWorkerUsageInfo> origins;
322 for (const auto& registration_info : registrations) {
323 GURL origin = registration_info.pattern.GetOrigin();
325 ServiceWorkerUsageInfo& usage_info = origins[origin];
326 if (usage_info.origin.is_empty())
327 usage_info.origin = origin;
328 usage_info.scopes.push_back(registration_info.pattern);
329 usage_info.total_size_bytes += registration_info.stored_version_size_bytes;
332 for (const auto& origin_info_pair : origins) {
333 usage_infos.push_back(origin_info_pair.second);
335 callback.Run(usage_infos);
338 void ServiceWorkerContextWrapper::DidFindRegistrationForCheckHasServiceWorker(
339 const GURL& other_url,
340 const CheckHasServiceWorkerCallback& callback,
341 ServiceWorkerStatusCode status,
342 const scoped_refptr<ServiceWorkerRegistration>& registration) {
343 DCHECK_CURRENTLY_ON(BrowserThread::IO);
345 if (status != SERVICE_WORKER_OK) {
346 BrowserThread::PostTask(BrowserThread::UI, FROM_HERE,
347 base::Bind(callback, false));
348 return;
351 DCHECK(registration);
352 BrowserThread::PostTask(
353 BrowserThread::UI, FROM_HERE,
354 base::Bind(callback, registration->active_version() &&
355 ServiceWorkerUtils::ScopeMatches(
356 registration->pattern(), other_url)));
359 void ServiceWorkerContextWrapper::DidFindRegistrationForUpdate(
360 ServiceWorkerStatusCode status,
361 const scoped_refptr<ServiceWorkerRegistration>& registration) {
362 DCHECK_CURRENTLY_ON(BrowserThread::IO);
364 if (status != SERVICE_WORKER_OK)
365 return;
366 if (!context_core_.get()) {
367 LOG(ERROR) << "ServiceWorkerContextCore is no longer alive.";
368 return;
370 DCHECK(registration);
371 context_core_->UpdateServiceWorker(registration.get(),
372 true /* force_bypass_cache */);
375 namespace {
376 void StatusCodeToBoolCallbackAdapter(
377 const ServiceWorkerContext::ResultCallback& callback,
378 ServiceWorkerStatusCode code) {
379 callback.Run(code == ServiceWorkerStatusCode::SERVICE_WORKER_OK);
382 void EmptySuccessCallback(bool success) {
384 } // namespace
386 void ServiceWorkerContextWrapper::DeleteForOrigin(
387 const GURL& origin_url,
388 const ResultCallback& result) {
389 DCHECK_CURRENTLY_ON(BrowserThread::IO);
390 if (!context_core_.get()) {
391 LOG(ERROR) << "ServiceWorkerContextCore is no longer alive.";
392 BrowserThread::PostTask(
393 BrowserThread::IO,
394 FROM_HERE,
395 base::Bind(result, false));
396 return;
398 context()->UnregisterServiceWorkers(
399 origin_url, base::Bind(&StatusCodeToBoolCallbackAdapter, result));
402 void ServiceWorkerContextWrapper::DeleteForOrigin(const GURL& origin_url) {
403 DeleteForOrigin(origin_url, base::Bind(&EmptySuccessCallback));
406 void ServiceWorkerContextWrapper::CheckHasServiceWorker(
407 const GURL& url,
408 const GURL& other_url,
409 const CheckHasServiceWorkerCallback& callback) {
410 if (!BrowserThread::CurrentlyOn(BrowserThread::IO)) {
411 BrowserThread::PostTask(
412 BrowserThread::IO, FROM_HERE,
413 base::Bind(&ServiceWorkerContextWrapper::CheckHasServiceWorker, this,
414 url, other_url, callback));
415 return;
417 if (!context_core_.get()) {
418 LOG(ERROR) << "ServiceWorkerContextCore is no longer alive.";
419 BrowserThread::PostTask(BrowserThread::IO, FROM_HERE,
420 base::Bind(callback, false));
421 return;
423 GURL stripped_url = net::SimplifyUrlForRequest(url);
424 context()->storage()->FindRegistrationForDocument(
425 stripped_url, base::Bind(&ServiceWorkerContextWrapper::
426 DidFindRegistrationForCheckHasServiceWorker,
427 this, other_url, callback));
430 ServiceWorkerRegistration* ServiceWorkerContextWrapper::GetLiveRegistration(
431 int64_t registration_id) {
432 DCHECK_CURRENTLY_ON(BrowserThread::IO);
433 if (!context_core_)
434 return nullptr;
435 return context_core_->GetLiveRegistration(registration_id);
438 ServiceWorkerVersion* ServiceWorkerContextWrapper::GetLiveVersion(
439 int64_t version_id) {
440 DCHECK_CURRENTLY_ON(BrowserThread::IO);
441 if (!context_core_)
442 return nullptr;
443 return context_core_->GetLiveVersion(version_id);
446 std::vector<ServiceWorkerRegistrationInfo>
447 ServiceWorkerContextWrapper::GetAllLiveRegistrationInfo() {
448 DCHECK_CURRENTLY_ON(BrowserThread::IO);
449 if (!context_core_)
450 return std::vector<ServiceWorkerRegistrationInfo>();
451 return context_core_->GetAllLiveRegistrationInfo();
454 std::vector<ServiceWorkerVersionInfo>
455 ServiceWorkerContextWrapper::GetAllLiveVersionInfo() {
456 DCHECK_CURRENTLY_ON(BrowserThread::IO);
457 if (!context_core_)
458 return std::vector<ServiceWorkerVersionInfo>();
459 return context_core_->GetAllLiveVersionInfo();
462 void ServiceWorkerContextWrapper::FindRegistrationForDocument(
463 const GURL& document_url,
464 const FindRegistrationCallback& callback) {
465 DCHECK_CURRENTLY_ON(BrowserThread::IO);
466 if (!context_core_) {
467 // FindRegistrationForDocument() can run the callback synchronously.
468 callback.Run(SERVICE_WORKER_ERROR_ABORT, nullptr);
469 return;
471 context_core_->storage()->FindRegistrationForDocument(document_url, callback);
474 void ServiceWorkerContextWrapper::FindRegistrationForId(
475 int64_t registration_id,
476 const GURL& origin,
477 const FindRegistrationCallback& callback) {
478 DCHECK_CURRENTLY_ON(BrowserThread::IO);
479 if (!context_core_) {
480 // FindRegistrationForId() can run the callback synchronously.
481 callback.Run(SERVICE_WORKER_ERROR_ABORT, nullptr);
482 return;
484 context_core_->storage()->FindRegistrationForId(registration_id, origin,
485 callback);
488 void ServiceWorkerContextWrapper::GetAllRegistrations(
489 const GetRegistrationsInfosCallback& callback) {
490 DCHECK_CURRENTLY_ON(BrowserThread::IO);
491 if (!context_core_) {
492 RunSoon(base::Bind(callback, std::vector<ServiceWorkerRegistrationInfo>()));
493 return;
495 context_core_->storage()->GetAllRegistrations(callback);
498 void ServiceWorkerContextWrapper::GetRegistrationUserData(
499 int64_t registration_id,
500 const std::string& key,
501 const GetUserDataCallback& callback) {
502 DCHECK_CURRENTLY_ON(BrowserThread::IO);
503 if (!context_core_) {
504 RunSoon(base::Bind(callback, std::string(), SERVICE_WORKER_ERROR_ABORT));
505 return;
507 context_core_->storage()->GetUserData(registration_id, key, callback);
510 void ServiceWorkerContextWrapper::StoreRegistrationUserData(
511 int64_t registration_id,
512 const GURL& origin,
513 const std::string& key,
514 const std::string& data,
515 const StatusCallback& callback) {
516 DCHECK_CURRENTLY_ON(BrowserThread::IO);
517 if (!context_core_) {
518 RunSoon(base::Bind(callback, SERVICE_WORKER_ERROR_ABORT));
519 return;
521 context_core_->storage()->StoreUserData(registration_id, origin, key, data,
522 callback);
525 void ServiceWorkerContextWrapper::ClearRegistrationUserData(
526 int64_t registration_id,
527 const std::string& key,
528 const StatusCallback& callback) {
529 DCHECK_CURRENTLY_ON(BrowserThread::IO);
530 if (!context_core_) {
531 RunSoon(base::Bind(callback, SERVICE_WORKER_ERROR_ABORT));
532 return;
534 context_core_->storage()->ClearUserData(registration_id, key, callback);
537 void ServiceWorkerContextWrapper::GetUserDataForAllRegistrations(
538 const std::string& key,
539 const GetUserDataForAllRegistrationsCallback& callback) {
540 DCHECK_CURRENTLY_ON(BrowserThread::IO);
541 if (!context_core_) {
542 RunSoon(base::Bind(callback, std::vector<std::pair<int64_t, std::string>>(),
543 SERVICE_WORKER_ERROR_ABORT));
544 return;
546 context_core_->storage()->GetUserDataForAllRegistrations(key, callback);
549 void ServiceWorkerContextWrapper::AddObserver(
550 ServiceWorkerContextObserver* observer) {
551 observer_list_->AddObserver(observer);
554 void ServiceWorkerContextWrapper::RemoveObserver(
555 ServiceWorkerContextObserver* observer) {
556 observer_list_->RemoveObserver(observer);
559 void ServiceWorkerContextWrapper::InitInternal(
560 const base::FilePath& user_data_directory,
561 scoped_ptr<ServiceWorkerDatabaseTaskManager> database_task_manager,
562 const scoped_refptr<base::SingleThreadTaskRunner>& disk_cache_thread,
563 storage::QuotaManagerProxy* quota_manager_proxy,
564 storage::SpecialStoragePolicy* special_storage_policy) {
565 if (!BrowserThread::CurrentlyOn(BrowserThread::IO)) {
566 BrowserThread::PostTask(
567 BrowserThread::IO,
568 FROM_HERE,
569 base::Bind(&ServiceWorkerContextWrapper::InitInternal,
570 this,
571 user_data_directory,
572 base::Passed(&database_task_manager),
573 disk_cache_thread,
574 make_scoped_refptr(quota_manager_proxy),
575 make_scoped_refptr(special_storage_policy)));
576 return;
578 // TODO(pkasting): Remove ScopedTracker below once crbug.com/477117 is fixed.
579 tracked_objects::ScopedTracker tracking_profile(
580 FROM_HERE_WITH_EXPLICIT_FUNCTION(
581 "477117 ServiceWorkerContextWrapper::InitInternal"));
582 DCHECK(!context_core_);
583 if (quota_manager_proxy) {
584 quota_manager_proxy->RegisterClient(new ServiceWorkerQuotaClient(this));
586 context_core_.reset(new ServiceWorkerContextCore(user_data_directory,
587 database_task_manager.Pass(),
588 disk_cache_thread,
589 quota_manager_proxy,
590 special_storage_policy,
591 observer_list_.get(),
592 this));
595 void ServiceWorkerContextWrapper::ShutdownOnIO() {
596 DCHECK_CURRENTLY_ON(BrowserThread::IO);
597 context_core_.reset();
600 void ServiceWorkerContextWrapper::DidDeleteAndStartOver(
601 ServiceWorkerStatusCode status) {
602 DCHECK_CURRENTLY_ON(BrowserThread::IO);
603 if (status != SERVICE_WORKER_OK) {
604 context_core_.reset();
605 return;
607 context_core_.reset(new ServiceWorkerContextCore(context_core_.get(), this));
608 DVLOG(1) << "Restarted ServiceWorkerContextCore successfully.";
610 observer_list_->Notify(FROM_HERE,
611 &ServiceWorkerContextObserver::OnStorageWiped);
614 ServiceWorkerContextCore* ServiceWorkerContextWrapper::context() {
615 DCHECK_CURRENTLY_ON(BrowserThread::IO);
616 return context_core_.get();
619 } // namespace content