blob: 6ded70eb1063112187dc5a5d72f029966b9eb00f [file] [log] [blame]
// Copyright 2015 The Chromium Authors. All rights reserved.
// 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/guid.h"
#include "base/path_service.h"
#include "base/task/post_task.h"
#include "content/public/browser/browser_task_traits.h"
#include "content/public/browser/browser_thread.h"
#include "content/public/browser/storage_partition.h"
#include "headless/grit/headless_lib_resources.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_permission_manager.h"
#include "headless/lib/browser/headless_web_contents_impl.h"
#include "net/url_request/url_request_context.h"
#include "ui/base/resource/resource_bundle.h"
namespace headless {
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>(this)) {
InitWhileIOAllowed();
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);
}
HeadlessBrowserContextImpl::~HeadlessBrowserContextImpl() {
DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
NotifyWillBeDestroyed(this);
// Destroy all web contents before shutting down storage partitions.
web_contents_map_.clear();
if (request_context_manager_) {
content::BrowserThread::DeleteSoon(content::BrowserThread::IO, FROM_HERE,
request_context_manager_.release());
}
ShutdownStoragePartitions();
}
// 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(
HeadlessBrowserContext::Builder* builder) {
return base::WrapUnique(new HeadlessBrowserContextImpl(
builder->browser_, std::move(builder->options_)));
}
HeadlessWebContents::Builder
HeadlessBrowserContextImpl::CreateWebContentsBuilder() {
DCHECK(browser_->BrowserMainThread()->BelongsToCurrentThread());
return HeadlessWebContents::Builder(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::SetDevToolsFrameToken(
int render_process_id,
int render_frame_routing_id,
const base::UnguessableToken& devtools_frame_token,
int frame_tree_node_id) {
base::AutoLock lock(devtools_frame_token_map_lock_);
devtools_frame_token_map_[content::GlobalFrameRoutingId(
render_process_id, render_frame_routing_id)] = devtools_frame_token;
frame_tree_node_id_to_devtools_frame_token_map_[frame_tree_node_id] =
devtools_frame_token;
}
void HeadlessBrowserContextImpl::RemoveDevToolsFrameToken(
int render_process_id,
int render_frame_routing_id,
int frame_tree_node_id) {
base::AutoLock lock(devtools_frame_token_map_lock_);
devtools_frame_token_map_.erase(content::GlobalFrameRoutingId(
render_process_id, render_frame_routing_id));
frame_tree_node_id_to_devtools_frame_token_map_.erase(frame_tree_node_id);
}
const base::UnguessableToken* HeadlessBrowserContextImpl::GetDevToolsFrameToken(
int render_process_id,
int render_frame_id) const {
base::AutoLock lock(devtools_frame_token_map_lock_);
const auto& find_it = devtools_frame_token_map_.find(
content::GlobalFrameRoutingId(render_process_id, render_frame_id));
if (find_it == devtools_frame_token_map_.end())
return nullptr;
return &find_it->second;
}
const base::UnguessableToken*
HeadlessBrowserContextImpl::GetDevToolsFrameTokenForFrameTreeNodeId(
int frame_tree_node_id) const {
base::AutoLock lock(devtools_frame_token_map_lock_);
const auto& find_it =
frame_tree_node_id_to_devtools_frame_token_map_.find(frame_tree_node_id);
if (find_it == frame_tree_node_id_to_devtools_frame_token_map_.end())
return nullptr;
return &find_it->second;
}
void HeadlessBrowserContextImpl::Close() {
DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
browser_->DestroyBrowserContext(this);
}
void HeadlessBrowserContextImpl::InitWhileIOAllowed() {
if (!context_options_->user_data_dir().empty()) {
path_ = context_options_->user_data_dir().Append(kDefaultProfileName);
} else {
base::PathService::Get(base::DIR_EXE, &path_);
}
BrowserContext::Initialize(this, path_);
}
std::unique_ptr<content::ZoomLevelDelegate>
HeadlessBrowserContextImpl::CreateZoomLevelDelegate(
const base::FilePath& partition_path) {
return std::unique_ptr<content::ZoomLevelDelegate>();
}
base::FilePath HeadlessBrowserContextImpl::GetPath() const {
return path_;
}
base::FilePath HeadlessBrowserContextImpl::GetCachePath() const {
return path_;
}
bool HeadlessBrowserContextImpl::IsOffTheRecord() const {
return context_options_->incognito_mode();
}
content::ResourceContext* HeadlessBrowserContextImpl::GetResourceContext() {
return request_context_manager_->GetResourceContext();
}
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::PushMessagingService*
HeadlessBrowserContextImpl::GetPushMessagingService() {
return nullptr;
}
content::SSLHostStateDelegate*
HeadlessBrowserContextImpl::GetSSLHostStateDelegate() {
return nullptr;
}
content::PermissionControllerDelegate*
HeadlessBrowserContextImpl::GetPermissionControllerDelegate() {
return permission_controller_delegate_.get();
}
content::BackgroundFetchDelegate*
HeadlessBrowserContextImpl::GetBackgroundFetchDelegate() {
return nullptr;
}
content::BackgroundSyncController*
HeadlessBrowserContextImpl::GetBackgroundSyncController() {
return nullptr;
}
content::BrowsingDataRemoverDelegate*
HeadlessBrowserContextImpl::GetBrowsingDataRemoverDelegate() {
return nullptr;
}
net::URLRequestContextGetter* HeadlessBrowserContextImpl::CreateRequestContext(
content::ProtocolHandlerMap* protocol_handlers,
content::URLRequestInterceptorScopedVector request_interceptors) {
return request_context_manager_->CreateRequestContext(
protocol_handlers, std::move(request_interceptors));
}
net::URLRequestContextGetter*
HeadlessBrowserContextImpl::CreateRequestContextForStoragePartition(
const base::FilePath& partition_path,
bool in_memory,
content::ProtocolHandlerMap* protocol_handlers,
content::URLRequestInterceptorScopedVector request_interceptors) {
return nullptr;
}
net::URLRequestContextGetter*
HeadlessBrowserContextImpl::CreateMediaRequestContext() {
return request_context_manager_->url_request_context_getter();
}
net::URLRequestContextGetter*
HeadlessBrowserContextImpl::CreateMediaRequestContextForStoragePartition(
const base::FilePath& partition_path,
bool in_memory) {
return nullptr;
}
HeadlessWebContents* HeadlessBrowserContextImpl::CreateWebContents(
HeadlessWebContents::Builder* builder) {
DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
std::unique_ptr<HeadlessWebContentsImpl> headless_web_contents =
HeadlessWebContentsImpl::Create(builder);
if (!headless_web_contents) {
return nullptr;
}
HeadlessWebContents* result = headless_web_contents.get();
RegisterWebContents(std::move(headless_web_contents));
return result;
}
void HeadlessBrowserContextImpl::RegisterWebContents(
std::unique_ptr<HeadlessWebContentsImpl> web_contents) {
DCHECK(web_contents);
web_contents_map_[web_contents->GetDevToolsAgentHostId()] =
std::move(web_contents);
}
void HeadlessBrowserContextImpl::DestroyWebContents(
HeadlessWebContentsImpl* web_contents) {
auto it = web_contents_map_.find(web_contents->GetDevToolsAgentHostId());
DCHECK(it != web_contents_map_.end());
web_contents_map_.erase(it);
}
HeadlessWebContents*
HeadlessBrowserContextImpl::GetWebContentsForDevToolsAgentHostId(
const std::string& devtools_agent_host_id) {
auto find_it = web_contents_map_.find(devtools_agent_host_id);
if (find_it == web_contents_map_.end())
return nullptr;
return find_it->second.get();
}
HeadlessBrowserImpl* HeadlessBrowserContextImpl::browser() const {
return browser_;
}
const HeadlessBrowserContextOptions* HeadlessBrowserContextImpl::options()
const {
return context_options_.get();
}
const std::string& HeadlessBrowserContextImpl::Id() const {
return UniqueId();
}
::network::mojom::NetworkContextPtr
HeadlessBrowserContextImpl::CreateNetworkContext(
bool in_memory,
const base::FilePath& relative_partition_path) {
return request_context_manager_->CreateNetworkContext(
in_memory, relative_partition_path);
}
HeadlessBrowserContext::Builder::Builder(HeadlessBrowserImpl* browser)
: browser_(browser),
options_(new HeadlessBrowserContextOptions(browser->options())) {}
HeadlessBrowserContext::Builder::~Builder() = default;
HeadlessBrowserContext::Builder::Builder(Builder&&) = default;
HeadlessBrowserContext::Builder&
HeadlessBrowserContext::Builder::SetProtocolHandlers(
ProtocolHandlerMap protocol_handlers) {
options_->protocol_handlers_ = std::move(protocol_handlers);
return *this;
}
HeadlessBrowserContext::Builder&
HeadlessBrowserContext::Builder::SetProductNameAndVersion(
const std::string& product_name_and_version) {
options_->product_name_and_version_ = product_name_and_version;
return *this;
}
HeadlessBrowserContext::Builder& HeadlessBrowserContext::Builder::SetUserAgent(
const std::string& user_agent) {
options_->user_agent_ = user_agent;
return *this;
}
HeadlessBrowserContext::Builder&
HeadlessBrowserContext::Builder::SetAcceptLanguage(
const std::string& accept_language) {
options_->accept_language_ = accept_language;
return *this;
}
HeadlessBrowserContext::Builder&
HeadlessBrowserContext::Builder::SetProxyConfig(
std::unique_ptr<net::ProxyConfig> proxy_config) {
options_->proxy_config_ = std::move(proxy_config);
return *this;
}
HeadlessBrowserContext::Builder& HeadlessBrowserContext::Builder::SetWindowSize(
const gfx::Size& window_size) {
options_->window_size_ = window_size;
return *this;
}
HeadlessBrowserContext::Builder&
HeadlessBrowserContext::Builder::SetUserDataDir(
const base::FilePath& user_data_dir) {
options_->user_data_dir_ = user_data_dir;
return *this;
}
HeadlessBrowserContext::Builder&
HeadlessBrowserContext::Builder::SetIncognitoMode(bool incognito_mode) {
options_->incognito_mode_ = incognito_mode;
return *this;
}
HeadlessBrowserContext::Builder&
HeadlessBrowserContext::Builder::SetSitePerProcess(bool site_per_process) {
options_->site_per_process_ = site_per_process;
return *this;
}
HeadlessBrowserContext::Builder&
HeadlessBrowserContext::Builder::SetBlockNewWebContents(
bool block_new_web_contents) {
options_->block_new_web_contents_ = block_new_web_contents;
return *this;
}
HeadlessBrowserContext::Builder&
HeadlessBrowserContext::Builder::SetOverrideWebPreferencesCallback(
base::RepeatingCallback<void(WebPreferences*)> callback) {
options_->override_web_preferences_callback_ = std::move(callback);
return *this;
}
HeadlessBrowserContext* HeadlessBrowserContext::Builder::Build() {
return browser_->CreateBrowserContext(this);
}
HeadlessBrowserContext::Builder::MojoBindings::MojoBindings() = default;
HeadlessBrowserContext::Builder::MojoBindings::MojoBindings(
const std::string& mojom_name,
const std::string& js_bindings)
: mojom_name(mojom_name), js_bindings(js_bindings) {}
HeadlessBrowserContext::Builder::MojoBindings::~MojoBindings() = default;
} // namespace headless