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/shell/browser/shell_content_browser_client.h"
7 #include "base/base_switches.h"
8 #include "base/command_line.h"
9 #include "base/files/file.h"
10 #include "base/files/file_util.h"
11 #include "base/path_service.h"
12 #include "base/strings/utf_string_conversions.h"
13 #include "content/public/browser/client_certificate_delegate.h"
14 #include "content/public/browser/page_navigator.h"
15 #include "content/public/browser/render_process_host.h"
16 #include "content/public/browser/resource_dispatcher_host.h"
17 #include "content/public/browser/storage_partition.h"
18 #include "content/public/common/content_switches.h"
19 #include "content/public/common/url_constants.h"
20 #include "content/public/common/web_preferences.h"
21 #include "content/shell/browser/ipc_echo_message_filter.h"
22 #include "content/shell/browser/layout_test/layout_test_browser_main_parts.h"
23 #include "content/shell/browser/layout_test/layout_test_resource_dispatcher_host_delegate.h"
24 #include "content/shell/browser/shell.h"
25 #include "content/shell/browser/shell_access_token_store.h"
26 #include "content/shell/browser/shell_browser_context.h"
27 #include "content/shell/browser/shell_browser_main_parts.h"
28 #include "content/shell/browser/shell_devtools_manager_delegate.h"
29 #include "content/shell/browser/shell_net_log.h"
30 #include "content/shell/browser/shell_quota_permission_context.h"
31 #include "content/shell/browser/shell_resource_dispatcher_host_delegate.h"
32 #include "content/shell/browser/shell_web_contents_view_delegate_creator.h"
33 #include "content/shell/browser/webkit_test_controller.h"
34 #include "content/shell/common/shell_messages.h"
35 #include "content/shell/common/shell_switches.h"
36 #include "content/shell/common/webkit_test_helpers.h"
37 #include "gin/v8_initializer.h"
38 #include "net/url_request/url_request_context_getter.h"
41 #if defined(OS_ANDROID)
42 #include "base/android/path_utils.h"
43 #include "components/crash/browser/crash_dump_manager_android.h"
44 #include "content/shell/android/shell_descriptors.h"
47 #if defined(OS_POSIX) && !defined(OS_MACOSX)
48 #include "base/debug/leak_annotations.h"
49 #include "components/crash/app/breakpad_linux.h"
50 #include "components/crash/browser/crash_handler_host_linux.h"
51 #include "content/public/common/content_descriptors.h"
55 #include "content/common/sandbox_win.h"
56 #include "sandbox/win/src/sandbox.h"
63 ShellContentBrowserClient
* g_browser_client
;
64 bool g_swap_processes_for_redirect
= false;
66 #if defined(OS_POSIX) && !defined(OS_MACOSX) && !defined(OS_ANDROID)
67 breakpad::CrashHandlerHostLinux
* CreateCrashHandlerHost(
68 const std::string
& process_type
) {
69 base::FilePath dumps_path
=
70 base::CommandLine::ForCurrentProcess()->GetSwitchValuePath(
71 switches::kCrashDumpsDir
);
73 ANNOTATE_SCOPED_MEMORY_LEAK
;
74 breakpad::CrashHandlerHostLinux
* crash_handler
=
75 new breakpad::CrashHandlerHostLinux(
76 process_type
, dumps_path
, false);
77 crash_handler
->StartUploaderThread();
82 int GetCrashSignalFD(const base::CommandLine
& command_line
) {
83 if (!breakpad::IsCrashReporterEnabled())
86 std::string process_type
=
87 command_line
.GetSwitchValueASCII(switches::kProcessType
);
89 if (process_type
== switches::kRendererProcess
) {
90 static breakpad::CrashHandlerHostLinux
* crash_handler
= NULL
;
92 crash_handler
= CreateCrashHandlerHost(process_type
);
93 return crash_handler
->GetDeathSignalSocket();
96 if (process_type
== switches::kPluginProcess
) {
97 static breakpad::CrashHandlerHostLinux
* crash_handler
= NULL
;
99 crash_handler
= CreateCrashHandlerHost(process_type
);
100 return crash_handler
->GetDeathSignalSocket();
103 if (process_type
== switches::kPpapiPluginProcess
) {
104 static breakpad::CrashHandlerHostLinux
* crash_handler
= NULL
;
106 crash_handler
= CreateCrashHandlerHost(process_type
);
107 return crash_handler
->GetDeathSignalSocket();
110 if (process_type
== switches::kGpuProcess
) {
111 static breakpad::CrashHandlerHostLinux
* crash_handler
= NULL
;
113 crash_handler
= CreateCrashHandlerHost(process_type
);
114 return crash_handler
->GetDeathSignalSocket();
119 #endif // defined(OS_POSIX) && !defined(OS_MACOSX) && !defined(OS_ANDROID)
123 ShellContentBrowserClient
* ShellContentBrowserClient::Get() {
124 return g_browser_client
;
127 void ShellContentBrowserClient::SetSwapProcessesForRedirect(bool swap
) {
128 g_swap_processes_for_redirect
= swap
;
131 ShellContentBrowserClient::ShellContentBrowserClient()
133 #if defined(OS_POSIX) && !defined(OS_MACOSX)
136 #endif // OS_POSIX && !OS_MACOSX
137 shell_browser_main_parts_(NULL
) {
138 DCHECK(!g_browser_client
);
139 g_browser_client
= this;
142 ShellContentBrowserClient::~ShellContentBrowserClient() {
143 g_browser_client
= NULL
;
146 BrowserMainParts
* ShellContentBrowserClient::CreateBrowserMainParts(
147 const MainFunctionParams
& parameters
) {
148 shell_browser_main_parts_
= base::CommandLine::ForCurrentProcess()->HasSwitch(
149 switches::kRunLayoutTest
)
150 ? new LayoutTestBrowserMainParts(parameters
)
151 : new ShellBrowserMainParts(parameters
);
152 return shell_browser_main_parts_
;
155 void ShellContentBrowserClient::RenderProcessWillLaunch(
156 RenderProcessHost
* host
) {
157 if (base::CommandLine::ForCurrentProcess()->HasSwitch(
158 switches::kExposeIpcEcho
))
159 host
->AddFilter(new IPCEchoMessageFilter());
162 net::URLRequestContextGetter
* ShellContentBrowserClient::CreateRequestContext(
163 BrowserContext
* content_browser_context
,
164 ProtocolHandlerMap
* protocol_handlers
,
165 URLRequestInterceptorScopedVector request_interceptors
) {
166 ShellBrowserContext
* shell_browser_context
=
167 ShellBrowserContextForBrowserContext(content_browser_context
);
168 return shell_browser_context
->CreateRequestContext(
169 protocol_handlers
, request_interceptors
.Pass());
172 net::URLRequestContextGetter
*
173 ShellContentBrowserClient::CreateRequestContextForStoragePartition(
174 BrowserContext
* content_browser_context
,
175 const base::FilePath
& partition_path
,
177 ProtocolHandlerMap
* protocol_handlers
,
178 URLRequestInterceptorScopedVector request_interceptors
) {
179 ShellBrowserContext
* shell_browser_context
=
180 ShellBrowserContextForBrowserContext(content_browser_context
);
181 return shell_browser_context
->CreateRequestContextForStoragePartition(
185 request_interceptors
.Pass());
188 bool ShellContentBrowserClient::IsHandledURL(const GURL
& url
) {
191 DCHECK_EQ(url
.scheme(), base::StringToLowerASCII(url
.scheme()));
192 // Keep in sync with ProtocolHandlers added by
193 // ShellURLRequestContextGetter::GetURLRequestContext().
194 static const char* const kProtocolList
[] = {
196 url::kFileSystemScheme
,
198 kChromeDevToolsScheme
,
202 for (size_t i
= 0; i
< arraysize(kProtocolList
); ++i
) {
203 if (url
.scheme() == kProtocolList
[i
])
209 void ShellContentBrowserClient::AppendExtraCommandLineSwitches(
210 base::CommandLine
* command_line
,
211 int child_process_id
) {
212 if (base::CommandLine::ForCurrentProcess()->HasSwitch(
213 switches::kRunLayoutTest
))
214 command_line
->AppendSwitch(switches::kRunLayoutTest
);
215 if (base::CommandLine::ForCurrentProcess()->HasSwitch(
216 switches::kEnableFontAntialiasing
))
217 command_line
->AppendSwitch(switches::kEnableFontAntialiasing
);
218 if (base::CommandLine::ForCurrentProcess()->HasSwitch(
219 switches::kExposeInternalsForTesting
))
220 command_line
->AppendSwitch(switches::kExposeInternalsForTesting
);
221 if (base::CommandLine::ForCurrentProcess()->HasSwitch(
222 switches::kExposeIpcEcho
))
223 command_line
->AppendSwitch(switches::kExposeIpcEcho
);
224 if (base::CommandLine::ForCurrentProcess()->HasSwitch(
225 switches::kStableReleaseMode
))
226 command_line
->AppendSwitch(switches::kStableReleaseMode
);
227 if (base::CommandLine::ForCurrentProcess()->HasSwitch(
228 switches::kEnableCrashReporter
)) {
229 command_line
->AppendSwitch(switches::kEnableCrashReporter
);
231 if (base::CommandLine::ForCurrentProcess()->HasSwitch(
232 switches::kCrashDumpsDir
)) {
233 command_line
->AppendSwitchPath(
234 switches::kCrashDumpsDir
,
235 base::CommandLine::ForCurrentProcess()->GetSwitchValuePath(
236 switches::kCrashDumpsDir
));
238 if (base::CommandLine::ForCurrentProcess()->HasSwitch(
239 switches::kEnableLeakDetection
)) {
240 command_line
->AppendSwitchASCII(
241 switches::kEnableLeakDetection
,
242 base::CommandLine::ForCurrentProcess()->GetSwitchValueASCII(
243 switches::kEnableLeakDetection
));
245 if (base::CommandLine::ForCurrentProcess()->HasSwitch(
246 switches::kRegisterFontFiles
)) {
247 command_line
->AppendSwitchASCII(
248 switches::kRegisterFontFiles
,
249 base::CommandLine::ForCurrentProcess()->GetSwitchValueASCII(
250 switches::kRegisterFontFiles
));
254 void ShellContentBrowserClient::OverrideWebkitPrefs(
255 RenderViewHost
* render_view_host
,
256 WebPreferences
* prefs
) {
257 if (!base::CommandLine::ForCurrentProcess()->HasSwitch(
258 switches::kRunLayoutTest
))
260 WebKitTestController::Get()->OverrideWebkitPrefs(prefs
);
263 void ShellContentBrowserClient::ResourceDispatcherHostCreated() {
264 resource_dispatcher_host_delegate_
.reset(
265 base::CommandLine::ForCurrentProcess()->HasSwitch(
266 switches::kRunLayoutTest
)
267 ? new LayoutTestResourceDispatcherHostDelegate
268 : new ShellResourceDispatcherHostDelegate
);
269 ResourceDispatcherHost::Get()->SetDelegate(
270 resource_dispatcher_host_delegate_
.get());
273 std::string
ShellContentBrowserClient::GetDefaultDownloadName() {
277 WebContentsViewDelegate
* ShellContentBrowserClient::GetWebContentsViewDelegate(
278 WebContents
* web_contents
) {
279 #if !defined(USE_AURA)
280 return CreateShellWebContentsViewDelegate(web_contents
);
286 QuotaPermissionContext
*
287 ShellContentBrowserClient::CreateQuotaPermissionContext() {
288 return new ShellQuotaPermissionContext();
291 void ShellContentBrowserClient::SelectClientCertificate(
292 WebContents
* web_contents
,
293 net::SSLCertRequestInfo
* cert_request_info
,
294 scoped_ptr
<ClientCertificateDelegate
> delegate
) {
295 if (!select_client_certificate_callback_
.is_null())
296 select_client_certificate_callback_
.Run();
299 SpeechRecognitionManagerDelegate
*
300 ShellContentBrowserClient::CreateSpeechRecognitionManagerDelegate() {
301 return new ShellSpeechRecognitionManagerDelegate();
304 net::NetLog
* ShellContentBrowserClient::GetNetLog() {
305 return shell_browser_main_parts_
->net_log();
308 bool ShellContentBrowserClient::ShouldSwapProcessesForRedirect(
309 ResourceContext
* resource_context
,
310 const GURL
& current_url
,
311 const GURL
& new_url
) {
312 return g_swap_processes_for_redirect
;
315 DevToolsManagerDelegate
*
316 ShellContentBrowserClient::GetDevToolsManagerDelegate() {
317 return new ShellDevToolsManagerDelegate(browser_context());
320 void ShellContentBrowserClient::OpenURL(
321 BrowserContext
* browser_context
,
322 const OpenURLParams
& params
,
323 const base::Callback
<void(WebContents
*)>& callback
) {
324 callback
.Run(Shell::CreateNewWindow(browser_context
,
327 gfx::Size())->web_contents());
330 #if defined(OS_POSIX) && !defined(OS_MACOSX)
331 void ShellContentBrowserClient::GetAdditionalMappedFilesForChildProcess(
332 const base::CommandLine
& command_line
,
333 int child_process_id
,
334 FileDescriptorInfo
* mappings
) {
335 #if defined(V8_USE_EXTERNAL_STARTUP_DATA)
336 if (v8_natives_fd_
.get() == -1 || v8_snapshot_fd_
.get() == -1) {
337 int v8_natives_fd
= -1;
338 int v8_snapshot_fd
= -1;
339 if (gin::V8Initializer::OpenV8FilesForChildProcesses(&v8_natives_fd
,
341 v8_natives_fd_
.reset(v8_natives_fd
);
342 v8_snapshot_fd_
.reset(v8_snapshot_fd
);
345 DCHECK(v8_natives_fd_
.get() != -1 && v8_snapshot_fd_
.get() != -1);
346 mappings
->Share(kV8NativesDataDescriptor
, v8_natives_fd_
.get());
347 mappings
->Share(kV8SnapshotDataDescriptor
, v8_snapshot_fd_
.get());
348 #endif // V8_USE_EXTERNAL_STARTUP_DATA
350 #if defined(OS_ANDROID)
351 int flags
= base::File::FLAG_OPEN
| base::File::FLAG_READ
;
352 base::FilePath pak_file
;
353 bool r
= PathService::Get(base::DIR_ANDROID_APP_DATA
, &pak_file
);
355 pak_file
= pak_file
.Append(FILE_PATH_LITERAL("paks"));
356 pak_file
= pak_file
.Append(FILE_PATH_LITERAL("content_shell.pak"));
358 base::File
f(pak_file
, flags
);
360 NOTREACHED() << "Failed to open file when creating renderer process: "
361 << "content_shell.pak";
364 mappings
->Transfer(kShellPakDescriptor
, base::ScopedFD(f
.TakePlatformFile()));
366 if (breakpad::IsCrashReporterEnabled()) {
367 f
= breakpad::CrashDumpManager::GetInstance()->CreateMinidumpFile(
370 LOG(ERROR
) << "Failed to create file for minidump, crash reporting will "
371 << "be disabled for this process.";
373 mappings
->Transfer(kAndroidMinidumpDescriptor
,
374 base::ScopedFD(f
.TakePlatformFile()));
377 #else // !defined(OS_ANDROID)
378 int crash_signal_fd
= GetCrashSignalFD(command_line
);
379 if (crash_signal_fd
>= 0) {
380 mappings
->Share(kCrashDumpSignal
, crash_signal_fd
);
382 #endif // defined(OS_ANDROID)
384 #endif // defined(OS_POSIX) && !defined(OS_MACOSX)
387 void ShellContentBrowserClient::PreSpawnRenderer(sandbox::TargetPolicy
* policy
,
389 // Add sideloaded font files for testing. See also DIR_WINDOWS_FONTS
390 // addition in |StartSandboxedProcess|.
391 std::vector
<std::string
> font_files
= GetSideloadFontFiles();
392 for (std::vector
<std::string
>::const_iterator
i(font_files
.begin());
393 i
!= font_files
.end();
395 policy
->AddRule(sandbox::TargetPolicy::SUBSYS_FILES
,
396 sandbox::TargetPolicy::FILES_ALLOW_READONLY
,
397 base::UTF8ToWide(*i
).c_str());
402 ShellBrowserContext
* ShellContentBrowserClient::browser_context() {
403 return shell_browser_main_parts_
->browser_context();
407 ShellContentBrowserClient::off_the_record_browser_context() {
408 return shell_browser_main_parts_
->off_the_record_browser_context();
411 AccessTokenStore
* ShellContentBrowserClient::CreateAccessTokenStore() {
412 return new ShellAccessTokenStore(browser_context());
416 ShellContentBrowserClient::ShellBrowserContextForBrowserContext(
417 BrowserContext
* content_browser_context
) {
418 if (content_browser_context
== browser_context())
419 return browser_context();
420 DCHECK_EQ(content_browser_context
, off_the_record_browser_context());
421 return off_the_record_browser_context();
424 } // namespace content