blob: 1f7dff613bb3b27c48cdd61ced3bbb4db17708c8 [file]
// Copyright 2015 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "headless/lib/browser/headless_browser_context_impl.h"
#include <memory>
#include <string>
#include <utility>
#include <vector>
#include "base/not_fatal_until.h"
#include "base/path_service.h"
#include "components/keyed_service/content/browser_context_dependency_manager.h"
#include "components/keyed_service/core/simple_key_map.h"
#include "components/origin_trials/browser/leveldb_persistence_provider.h"
#include "components/origin_trials/browser/origin_trials.h"
#include "components/profile_metrics/browser_profile_type.h"
#include "content/public/browser/browser_task_traits.h"
#include "content/public/browser/browser_thread.h"
#include "content/public/browser/render_process_host.h"
#include "content/public/browser/storage_partition.h"
#include "headless/lib/browser/headless_browser_context_options.h"
#include "headless/lib/browser/headless_browser_impl.h"
#include "headless/lib/browser/headless_browser_main_parts.h"
#include "headless/lib/browser/headless_client_hints_controller_delegate.h"
#include "headless/lib/browser/headless_permission_manager.h"
#include "headless/lib/browser/headless_web_contents_impl.h"
#include "third_party/blink/public/common/origin_trials/trial_token_validator.h"
#include "ui/base/resource/resource_bundle.h"
namespace headless {
namespace {
base::FilePath MakeAbsolutePath(const base::FilePath& path) {
#if BUILDFLAG(IS_WIN)
// On Windows it's common to omit drive specification assuming the current
// drive, which makes the path specification not absolute, but relative to
// the current drive. Handle this case by prepending the current drive to
// the "\path" specification.
std::vector<base::FilePath::StringType> components = path.GetComponents();
if (components.size() > 0 && components[0].length() == 1 &&
base::FilePath::IsSeparator(components[0].front())) {
components =
base::PathService::CheckedGet(base::DIR_CURRENT).GetComponents();
return base::FilePath(components[0]).Append(path);
}
#endif // BUILDFLAG(IS_WIN)
return base::PathService::CheckedGet(base::DIR_CURRENT).Append(path);
}
} // namespace
HeadlessBrowserContextImpl::HeadlessBrowserContextImpl(
HeadlessBrowserImpl* browser,
std::unique_ptr<HeadlessBrowserContextOptions> context_options)
: browser_(browser),
context_options_(std::move(context_options)),
permission_controller_delegate_(
std::make_unique<HeadlessPermissionManager>()),
hints_delegate_(
std::make_unique<HeadlessClientHintsControllerDelegate>()) {
BrowserContextDependencyManager::GetInstance()->MarkBrowserContextLive(this);
InitWhileIOAllowed();
simple_factory_key_ =
std::make_unique<SimpleFactoryKey>(GetPath(), IsOffTheRecord());
SimpleKeyMap::GetInstance()->Associate(this, simple_factory_key_.get());
base::FilePath user_data_path =
IsOffTheRecord() || context_options_->user_data_dir().empty()
? base::FilePath()
: path_;
request_context_manager_ = std::make_unique<HeadlessRequestContextManager>(
context_options_.get(), user_data_path, browser->os_crypt_async());
profile_metrics::SetBrowserProfileType(
this, IsOffTheRecord() ? profile_metrics::BrowserProfileType::kIncognito
: profile_metrics::BrowserProfileType::kRegular);
// Ensure the delegate is initialized early to give it time to load its
// persistence.
GetOriginTrialsControllerDelegate();
}
HeadlessBrowserContextImpl::~HeadlessBrowserContextImpl() {
DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
SimpleKeyMap::GetInstance()->Dissociate(this);
NotifyWillBeDestroyed();
// Destroy all web contents before shutting down in process renderer and
// storage partitions. Note that web_contents_ container can't be "just"
// cleared as deleting one element may lead to other elements being deleted.
while (!web_contents_map_.empty()) {
web_contents_map_.erase(web_contents_map_.begin());
}
// In single process mode we can only have one browser context, so it's
// safe to shutdown the in-process renderer here.
if (content::RenderProcessHost::run_renderer_in_process())
content::RenderProcessHost::ShutDownInProcessRenderer();
ShutdownStoragePartitions();
BrowserContextDependencyManager::GetInstance()->DestroyBrowserContextServices(
this);
}
// static
HeadlessBrowserContextImpl* HeadlessBrowserContextImpl::From(
HeadlessBrowserContext* browser_context) {
return static_cast<HeadlessBrowserContextImpl*>(browser_context);
}
// static
HeadlessBrowserContextImpl* HeadlessBrowserContextImpl::From(
content::BrowserContext* browser_context) {
return static_cast<HeadlessBrowserContextImpl*>(browser_context);
}
// static
std::unique_ptr<HeadlessBrowserContextImpl> HeadlessBrowserContextImpl::Create(
HeadlessBrowserImpl* browser,
HeadlessBrowserContext::CreateParams params) {
return std::make_unique<HeadlessBrowserContextImpl>(
browser, std::make_unique<HeadlessBrowserContextOptions>(
browser->options(), std::move(params)));
}
HeadlessWebContents* HeadlessBrowserContextImpl::CreateWebContents(
const HeadlessWebContents::CreateParams& params) {
DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
std::unique_ptr<HeadlessWebContentsImpl> headless_web_contents =
HeadlessWebContentsImpl::Create(params);
if (!headless_web_contents) {
return nullptr;
}
HeadlessWebContents* result = headless_web_contents.get();
RegisterWebContents(std::move(headless_web_contents));
return result;
}
HeadlessWebContents* HeadlessBrowserContextImpl::CreateWebContents(
const GURL& initial_url) {
return CreateWebContents(
HeadlessWebContents::CreateParams(this, initial_url));
}
HeadlessWebContents* HeadlessBrowserContextImpl::CreateWebContents() {
return CreateWebContents(HeadlessWebContents::CreateParams(this));
}
std::vector<HeadlessWebContents*>
HeadlessBrowserContextImpl::GetAllWebContents() {
DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
std::vector<HeadlessWebContents*> result;
result.reserve(web_contents_map_.size());
for (const auto& web_contents_pair : web_contents_map_) {
result.push_back(web_contents_pair.second.get());
}
return result;
}
void HeadlessBrowserContextImpl::Close() {
while (!web_contents_map_.empty()) {
auto it = web_contents_map_.begin();
it->second->Close();
}
DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
browser_->DestroyBrowserContext(this);
}
void HeadlessBrowserContextImpl::InitWhileIOAllowed() {
if (!context_options_->user_data_dir().empty()) {
base::FilePath path =
context_options_->user_data_dir().Append(kDefaultProfileName);
if (!path.IsAbsolute())
path = MakeAbsolutePath(path);
path_ = std::move(path);
} else {
base::PathService::Get(base::DIR_EXE, &path_);
}
DCHECK(path_.IsAbsolute());
}
std::unique_ptr<content::ZoomLevelDelegate>
HeadlessBrowserContextImpl::CreateZoomLevelDelegate(
const base::FilePath& partition_path) {
return nullptr;
}
base::FilePath HeadlessBrowserContextImpl::GetPath() const {
return path_;
}
bool HeadlessBrowserContextImpl::IsOffTheRecord() {
return context_options_->incognito_mode();
}
content::DownloadManagerDelegate*
HeadlessBrowserContextImpl::GetDownloadManagerDelegate() {
return nullptr;
}
content::BrowserPluginGuestManager*
HeadlessBrowserContextImpl::GetGuestManager() {
// TODO(altimin): Should be non-null? (is null in content/shell).
return nullptr;
}
storage::SpecialStoragePolicy*
HeadlessBrowserContextImpl::GetSpecialStoragePolicy() {
return nullptr;
}
content::PlatformNotificationService*
HeadlessBrowserContextImpl::GetPlatformNotificationService() {
return nullptr;
}
content::PushMessagingService*
HeadlessBrowserContextImpl::GetPushMessagingService() {
return nullptr;
}
content::StorageNotificationService*
HeadlessBrowserContextImpl::GetStorageNotificationService() {
return nullptr;
}
content::SSLHostStateDelegate*
HeadlessBrowserContextImpl::GetSSLHostStateDelegate() {
return nullptr;
}
content::PermissionControllerDelegate*
HeadlessBrowserContextImpl::GetPermissionControllerDelegate() {
return permission_controller_delegate_.get();
}
content::ClientHintsControllerDelegate*
HeadlessBrowserContextImpl::GetClientHintsControllerDelegate() {
return hints_delegate_.get();
}
content::BackgroundFetchDelegate*
HeadlessBrowserContextImpl::GetBackgroundFetchDelegate() {
return nullptr;
}
content::BackgroundSyncController*
HeadlessBrowserContextImpl::GetBackgroundSyncController() {
return nullptr;
}
content::BrowsingDataRemoverDelegate*
HeadlessBrowserContextImpl::GetBrowsingDataRemoverDelegate() {
return nullptr;
}
content::ReduceAcceptLanguageControllerDelegate*
HeadlessBrowserContextImpl::GetReduceAcceptLanguageControllerDelegate() {
return nullptr;
}
content::OriginTrialsControllerDelegate*
HeadlessBrowserContextImpl::GetOriginTrialsControllerDelegate() {
if (!origin_trials_controller_delegate_) {
origin_trials_controller_delegate_ =
std::make_unique<origin_trials::OriginTrials>(
std::make_unique<origin_trials::LevelDbPersistenceProvider>(
GetPath(),
GetDefaultStoragePartition()->GetProtoDatabaseProvider()),
std::make_unique<blink::TrialTokenValidator>());
}
return origin_trials_controller_delegate_.get();
}
void HeadlessBrowserContextImpl::RegisterWebContents(
std::unique_ptr<HeadlessWebContentsImpl> web_contents) {
CHECK(web_contents);
const uintptr_t key =
reinterpret_cast<uintptr_t>(web_contents->web_contents());
CHECK(key);
const bool inserted =
web_contents_map_.insert({key, std::move(web_contents)}).second;
CHECK(inserted);
}
void HeadlessBrowserContextImpl::DestroyWebContents(
HeadlessWebContentsImpl* web_contents) {
CHECK(web_contents);
const uintptr_t key =
reinterpret_cast<uintptr_t>(web_contents->web_contents());
CHECK(key);
size_t erased = web_contents_map_.erase(key);
CHECK(erased);
}
HeadlessWebContentsImpl* HeadlessBrowserContextImpl::GetHeadlessWebContents(
const content::WebContents* web_contents) {
const uintptr_t key = reinterpret_cast<uintptr_t>(web_contents);
auto find_it = web_contents_map_.find(key);
return find_it == web_contents_map_.end() ? nullptr : find_it->second.get();
}
HeadlessBrowserImpl* HeadlessBrowserContextImpl::browser() const {
return browser_;
}
const HeadlessBrowserContextOptions* HeadlessBrowserContextImpl::options()
const {
return context_options_.get();
}
const std::string& HeadlessBrowserContextImpl::Id() {
return UniqueId();
}
void HeadlessBrowserContextImpl::ConfigureNetworkContextParams(
bool in_memory,
const base::FilePath& relative_partition_path,
::network::mojom::NetworkContextParams* network_context_params,
::cert_verifier::mojom::CertVerifierCreationParams*
cert_verifier_creation_params) {
request_context_manager_->ConfigureNetworkContextParams(
in_memory, relative_partition_path, network_context_params,
cert_verifier_creation_params);
}
HeadlessBrowserContext::CreateParams::CreateParams() = default;
HeadlessBrowserContext::CreateParams::~CreateParams() = default;
HeadlessBrowserContext::CreateParams::CreateParams(CreateParams&&) = default;
HeadlessBrowserContext::CreateParams&
HeadlessBrowserContext::CreateParams::operator=(CreateParams&&) = default;
} // namespace headless