blob: 421fe846b6766bd324c055bb49f6ac22f8ee970f [file] [log] [blame]
// Copyright 2013 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 "content/shell/browser/shell_content_browser_client.h"
#include <stddef.h>
#include <utility>
#include "base/base_switches.h"
#include "base/command_line.h"
#include "base/files/file.h"
#include "base/files/file_util.h"
#include "base/json/json_reader.h"
#include "base/macros.h"
#include "base/memory/ptr_util.h"
#include "base/path_service.h"
#include "base/strings/pattern.h"
#include "base/strings/utf_string_conversions.h"
#include "build/build_config.h"
#include "content/public/browser/client_certificate_delegate.h"
#include "content/public/browser/page_navigator.h"
#include "content/public/browser/render_process_host.h"
#include "content/public/browser/resource_dispatcher_host.h"
#include "content/public/browser/storage_partition.h"
#include "content/public/common/content_switches.h"
#include "content/public/common/service_names.mojom.h"
#include "content/public/common/url_constants.h"
#include "content/public/common/web_preferences.h"
#include "content/public/test/test_service.h"
#include "content/shell/browser/shell.h"
#include "content/shell/browser/shell_browser_context.h"
#include "content/shell/browser/shell_browser_main_parts.h"
#include "content/shell/browser/shell_devtools_manager_delegate.h"
#include "content/shell/browser/shell_net_log.h"
#include "content/shell/browser/shell_quota_permission_context.h"
#include "content/shell/browser/shell_resource_dispatcher_host_delegate.h"
#include "content/shell/browser/shell_web_contents_view_delegate_creator.h"
#include "content/shell/common/shell_messages.h"
#include "content/shell/common/shell_switches.h"
#include "content/shell/grit/shell_resources.h"
#include "content/test/data/mojo_layouttest_test.mojom.h"
#include "media/mojo/features.h"
#include "mojo/public/cpp/bindings/strong_binding.h"
#include "net/ssl/client_cert_identity.h"
#include "net/url_request/url_request_context_getter.h"
#include "storage/browser/quota/quota_settings.h"
#include "ui/base/resource/resource_bundle.h"
#include "url/gurl.h"
#include "url/origin.h"
#if defined(OS_ANDROID)
#include "base/android/apk_assets.h"
#include "base/android/path_utils.h"
#include "components/crash/content/browser/crash_dump_observer_android.h"
#include "content/shell/android/shell_descriptors.h"
#endif
#if defined(OS_POSIX) && !defined(OS_MACOSX)
#include "base/debug/leak_annotations.h"
#include "components/crash/content/app/breakpad_linux.h"
#include "components/crash/content/browser/crash_handler_host_linux.h"
#include "content/public/common/content_descriptors.h"
#endif
#if defined(OS_WIN)
#include "content/common/sandbox_win.h"
#include "sandbox/win/src/sandbox.h"
#endif
#if BUILDFLAG(ENABLE_MOJO_MEDIA_IN_BROWSER_PROCESS)
#include "media/mojo/interfaces/constants.mojom.h" // nogncheck
#include "media/mojo/services/media_service_factory.h" // nogncheck
#endif
namespace content {
namespace {
ShellContentBrowserClient* g_browser_client;
bool g_swap_processes_for_redirect = false;
#if defined(OS_POSIX) && !defined(OS_MACOSX) && !defined(OS_ANDROID)
breakpad::CrashHandlerHostLinux* CreateCrashHandlerHost(
const std::string& process_type) {
base::FilePath dumps_path =
base::CommandLine::ForCurrentProcess()->GetSwitchValuePath(
switches::kCrashDumpsDir);
{
ANNOTATE_SCOPED_MEMORY_LEAK;
breakpad::CrashHandlerHostLinux* crash_handler =
new breakpad::CrashHandlerHostLinux(
process_type, dumps_path, false);
crash_handler->StartUploaderThread();
return crash_handler;
}
}
int GetCrashSignalFD(const base::CommandLine& command_line) {
if (!breakpad::IsCrashReporterEnabled())
return -1;
std::string process_type =
command_line.GetSwitchValueASCII(switches::kProcessType);
if (process_type == switches::kRendererProcess) {
static breakpad::CrashHandlerHostLinux* crash_handler = NULL;
if (!crash_handler)
crash_handler = CreateCrashHandlerHost(process_type);
return crash_handler->GetDeathSignalSocket();
}
if (process_type == switches::kPpapiPluginProcess) {
static breakpad::CrashHandlerHostLinux* crash_handler = NULL;
if (!crash_handler)
crash_handler = CreateCrashHandlerHost(process_type);
return crash_handler->GetDeathSignalSocket();
}
if (process_type == switches::kGpuProcess) {
static breakpad::CrashHandlerHostLinux* crash_handler = NULL;
if (!crash_handler)
crash_handler = CreateCrashHandlerHost(process_type);
return crash_handler->GetDeathSignalSocket();
}
return -1;
}
#endif // defined(OS_POSIX) && !defined(OS_MACOSX) && !defined(OS_ANDROID)
class MojoLayoutTestHelper : public mojom::MojoLayoutTestHelper {
public:
MojoLayoutTestHelper() {}
~MojoLayoutTestHelper() override {}
// mojom::MojoLayoutTestHelper:
void Reverse(const std::string& message, ReverseCallback callback) override {
std::move(callback).Run(std::string(message.rbegin(), message.rend()));
}
private:
DISALLOW_COPY_AND_ASSIGN(MojoLayoutTestHelper);
};
void BindLayoutTestHelper(mojom::MojoLayoutTestHelperRequest request,
RenderFrameHost* render_frame_host) {
mojo::MakeStrongBinding(base::MakeUnique<MojoLayoutTestHelper>(),
std::move(request));
}
} // namespace
ShellContentBrowserClient* ShellContentBrowserClient::Get() {
return g_browser_client;
}
void ShellContentBrowserClient::SetSwapProcessesForRedirect(bool swap) {
g_swap_processes_for_redirect = swap;
}
ShellContentBrowserClient::ShellContentBrowserClient()
: shell_browser_main_parts_(NULL) {
DCHECK(!g_browser_client);
g_browser_client = this;
frame_interfaces_.AddInterface(base::Bind(&BindLayoutTestHelper));
}
ShellContentBrowserClient::~ShellContentBrowserClient() {
g_browser_client = NULL;
}
BrowserMainParts* ShellContentBrowserClient::CreateBrowserMainParts(
const MainFunctionParams& parameters) {
shell_browser_main_parts_ = new ShellBrowserMainParts(parameters);
return shell_browser_main_parts_;
}
bool ShellContentBrowserClient::DoesSiteRequireDedicatedProcess(
BrowserContext* browser_context,
const GURL& effective_site_url) {
base::CommandLine* command_line = base::CommandLine::ForCurrentProcess();
if (!command_line->HasSwitch(switches::kIsolateSitesForTesting))
return false;
std::string pattern =
command_line->GetSwitchValueASCII(switches::kIsolateSitesForTesting);
url::Origin origin(effective_site_url);
if (!origin.unique()) {
// Schemes like blob or filesystem, which have an embedded origin, should
// already have been canonicalized to the origin site.
CHECK_EQ(origin.scheme(), effective_site_url.scheme())
<< "a site url should have the same scheme as its origin.";
}
// Practically |origin.Serialize()| is the same as
// |effective_site_url.spec()|, except Origin serialization strips the
// trailing "/", which makes for cleaner wildcard patterns.
return base::MatchPattern(origin.Serialize(), pattern);
}
bool ShellContentBrowserClient::IsHandledURL(const GURL& url) {
if (!url.is_valid())
return false;
// Keep in sync with ProtocolHandlers added by
// ShellURLRequestContextGetter::GetURLRequestContext().
static const char* const kProtocolList[] = {
url::kBlobScheme,
url::kFileSystemScheme,
kChromeUIScheme,
kChromeDevToolsScheme,
url::kDataScheme,
url::kFileScheme,
};
for (size_t i = 0; i < arraysize(kProtocolList); ++i) {
if (url.scheme() == kProtocolList[i])
return true;
}
return false;
}
void ShellContentBrowserClient::BindInterfaceRequestFromFrame(
RenderFrameHost* render_frame_host,
const std::string& interface_name,
mojo::ScopedMessagePipeHandle interface_pipe) {
frame_interfaces_.TryBindInterface(interface_name, &interface_pipe,
render_frame_host);
}
void ShellContentBrowserClient::RegisterInProcessServices(
StaticServiceMap* services) {
#if BUILDFLAG(ENABLE_MOJO_MEDIA_IN_BROWSER_PROCESS)
{
service_manager::EmbeddedServiceInfo info;
info.factory = base::Bind(&media::CreateMediaServiceForTesting);
services->insert(std::make_pair(media::mojom::kMediaServiceName, info));
}
#endif
}
void ShellContentBrowserClient::RegisterOutOfProcessServices(
OutOfProcessServiceMap* services) {
(*services)[kTestServiceUrl] = {base::UTF8ToUTF16("Test Service"),
SANDBOX_TYPE_UTILITY};
}
std::unique_ptr<base::Value>
ShellContentBrowserClient::GetServiceManifestOverlay(base::StringPiece name) {
int id = -1;
if (name == content::mojom::kBrowserServiceName)
id = IDR_CONTENT_SHELL_BROWSER_MANIFEST_OVERLAY;
else if (name == content::mojom::kGpuServiceName)
id = IDR_CONTENT_SHELL_GPU_MANIFEST_OVERLAY;
else if (name == content::mojom::kRendererServiceName)
id = IDR_CONTENT_SHELL_RENDERER_MANIFEST_OVERLAY;
else if (name == content::mojom::kUtilityServiceName)
id = IDR_CONTENT_SHELL_UTILITY_MANIFEST_OVERLAY;
if (id == -1)
return nullptr;
base::StringPiece manifest_contents =
ui::ResourceBundle::GetSharedInstance().GetRawDataResourceForScale(
id, ui::ScaleFactor::SCALE_FACTOR_NONE);
return base::JSONReader::Read(manifest_contents);
}
void ShellContentBrowserClient::AppendExtraCommandLineSwitches(
base::CommandLine* command_line,
int child_process_id) {
if (base::CommandLine::ForCurrentProcess()->HasSwitch(
switches::kExposeInternalsForTesting)) {
command_line->AppendSwitch(switches::kExposeInternalsForTesting);
}
if (base::CommandLine::ForCurrentProcess()->HasSwitch(
switches::kEnableCrashReporter)) {
command_line->AppendSwitch(switches::kEnableCrashReporter);
}
if (base::CommandLine::ForCurrentProcess()->HasSwitch(
switches::kCrashDumpsDir)) {
command_line->AppendSwitchPath(
switches::kCrashDumpsDir,
base::CommandLine::ForCurrentProcess()->GetSwitchValuePath(
switches::kCrashDumpsDir));
}
if (base::CommandLine::ForCurrentProcess()->HasSwitch(
switches::kIsolateSitesForTesting)) {
command_line->AppendSwitchASCII(
switches::kIsolateSitesForTesting,
base::CommandLine::ForCurrentProcess()->GetSwitchValueASCII(
switches::kIsolateSitesForTesting));
}
if (base::CommandLine::ForCurrentProcess()->HasSwitch(
switches::kRegisterFontFiles)) {
command_line->AppendSwitchASCII(
switches::kRegisterFontFiles,
base::CommandLine::ForCurrentProcess()->GetSwitchValueASCII(
switches::kRegisterFontFiles));
}
}
void ShellContentBrowserClient::ResourceDispatcherHostCreated() {
resource_dispatcher_host_delegate_.reset(
new ShellResourceDispatcherHostDelegate);
ResourceDispatcherHost::Get()->SetDelegate(
resource_dispatcher_host_delegate_.get());
}
std::string ShellContentBrowserClient::GetDefaultDownloadName() {
return "download";
}
WebContentsViewDelegate* ShellContentBrowserClient::GetWebContentsViewDelegate(
WebContents* web_contents) {
return CreateShellWebContentsViewDelegate(web_contents);
}
QuotaPermissionContext*
ShellContentBrowserClient::CreateQuotaPermissionContext() {
return new ShellQuotaPermissionContext();
}
void ShellContentBrowserClient::GetQuotaSettings(
BrowserContext* context,
StoragePartition* partition,
storage::OptionalQuotaSettingsCallback callback) {
std::move(callback).Run(storage::GetHardCodedSettings(100 * 1024 * 1024));
}
void ShellContentBrowserClient::SelectClientCertificate(
WebContents* web_contents,
net::SSLCertRequestInfo* cert_request_info,
net::ClientCertIdentityList client_certs,
std::unique_ptr<ClientCertificateDelegate> delegate) {
if (!select_client_certificate_callback_.is_null())
select_client_certificate_callback_.Run();
}
SpeechRecognitionManagerDelegate*
ShellContentBrowserClient::CreateSpeechRecognitionManagerDelegate() {
return new ShellSpeechRecognitionManagerDelegate();
}
net::NetLog* ShellContentBrowserClient::GetNetLog() {
return shell_browser_main_parts_->net_log();
}
bool ShellContentBrowserClient::ShouldSwapProcessesForRedirect(
BrowserContext* browser_context,
const GURL& current_url,
const GURL& new_url) {
return g_swap_processes_for_redirect;
}
DevToolsManagerDelegate*
ShellContentBrowserClient::GetDevToolsManagerDelegate() {
return new ShellDevToolsManagerDelegate(browser_context());
}
void ShellContentBrowserClient::OpenURL(
BrowserContext* browser_context,
const OpenURLParams& params,
const base::Callback<void(WebContents*)>& callback) {
callback.Run(Shell::CreateNewWindow(browser_context,
params.url,
nullptr,
gfx::Size())->web_contents());
}
#if defined(OS_POSIX) && !defined(OS_MACOSX)
void ShellContentBrowserClient::GetAdditionalMappedFilesForChildProcess(
const base::CommandLine& command_line,
int child_process_id,
content::PosixFileDescriptorInfo* mappings) {
#if defined(OS_ANDROID)
mappings->ShareWithRegion(
kShellPakDescriptor,
base::GlobalDescriptors::GetInstance()->Get(kShellPakDescriptor),
base::GlobalDescriptors::GetInstance()->GetRegion(kShellPakDescriptor));
breakpad::CrashDumpObserver::GetInstance()->BrowserChildProcessStarted(
child_process_id, mappings);
#else
int crash_signal_fd = GetCrashSignalFD(command_line);
if (crash_signal_fd >= 0) {
mappings->Share(kCrashDumpSignal, crash_signal_fd);
}
#endif // defined(OS_ANDROID)
}
#endif // defined(OS_POSIX) && !defined(OS_MACOSX)
#if defined(OS_WIN)
bool ShellContentBrowserClient::PreSpawnRenderer(
sandbox::TargetPolicy* policy) {
// Add sideloaded font files for testing. See also DIR_WINDOWS_FONTS
// addition in |StartSandboxedProcess|.
std::vector<std::string> font_files = switches::GetSideloadFontFiles();
for (std::vector<std::string>::const_iterator i(font_files.begin());
i != font_files.end();
++i) {
policy->AddRule(sandbox::TargetPolicy::SUBSYS_FILES,
sandbox::TargetPolicy::FILES_ALLOW_READONLY,
base::UTF8ToWide(*i).c_str());
}
return true;
}
#endif // OS_WIN
ShellBrowserContext* ShellContentBrowserClient::browser_context() {
return shell_browser_main_parts_->browser_context();
}
ShellBrowserContext*
ShellContentBrowserClient::off_the_record_browser_context() {
return shell_browser_main_parts_->off_the_record_browser_context();
}
} // namespace content