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/render_process_host.h"
14 #include "content/public/browser/resource_dispatcher_host.h"
15 #include "content/public/browser/storage_partition.h"
16 #include "content/public/common/content_switches.h"
17 #include "content/public/common/url_constants.h"
18 #include "content/public/common/web_preferences.h"
19 #include "content/shell/browser/ipc_echo_message_filter.h"
20 #include "content/shell/browser/shell.h"
21 #include "content/shell/browser/shell_browser_context.h"
22 #include "content/shell/browser/shell_browser_main_parts.h"
23 #include "content/shell/browser/shell_devtools_delegate.h"
24 #include "content/shell/browser/shell_message_filter.h"
25 #include "content/shell/browser/shell_net_log.h"
26 #include "content/shell/browser/shell_notification_manager.h"
27 #include "content/shell/browser/shell_quota_permission_context.h"
28 #include "content/shell/browser/shell_resource_dispatcher_host_delegate.h"
29 #include "content/shell/browser/shell_web_contents_view_delegate_creator.h"
30 #include "content/shell/browser/webkit_test_controller.h"
31 #include "content/shell/common/shell_messages.h"
32 #include "content/shell/common/shell_switches.h"
33 #include "content/shell/common/webkit_test_helpers.h"
34 #include "content/shell/geolocation/shell_access_token_store.h"
35 #include "net/url_request/url_request_context_getter.h"
38 #if defined(OS_ANDROID)
39 #include "base/android/path_utils.h"
40 #include "components/crash/browser/crash_dump_manager_android.h"
41 #include "content/shell/android/shell_descriptors.h"
44 #if defined(OS_POSIX) && !defined(OS_MACOSX)
45 #include "base/debug/leak_annotations.h"
46 #include "components/crash/app/breakpad_linux.h"
47 #include "components/crash/browser/crash_handler_host_linux.h"
48 #include "content/public/common/content_descriptors.h"
52 #include "content/common/sandbox_win.h"
53 #include "sandbox/win/src/sandbox.h"
60 ShellContentBrowserClient* g_browser_client;
61 bool g_swap_processes_for_redirect = false;
63 #if defined(OS_POSIX) && !defined(OS_MACOSX) && !defined(OS_ANDROID)
64 breakpad::CrashHandlerHostLinux* CreateCrashHandlerHost(
65 const std::string& process_type) {
66 base::FilePath dumps_path =
67 CommandLine::ForCurrentProcess()->GetSwitchValuePath(
68 switches::kCrashDumpsDir);
70 ANNOTATE_SCOPED_MEMORY_LEAK;
71 breakpad::CrashHandlerHostLinux* crash_handler =
72 new breakpad::CrashHandlerHostLinux(
73 process_type, dumps_path, false);
74 crash_handler->StartUploaderThread();
79 int GetCrashSignalFD(const CommandLine& command_line) {
80 if (!breakpad::IsCrashReporterEnabled())
83 std::string process_type =
84 command_line.GetSwitchValueASCII(switches::kProcessType);
86 if (process_type == switches::kRendererProcess) {
87 static breakpad::CrashHandlerHostLinux* crash_handler = NULL;
89 crash_handler = CreateCrashHandlerHost(process_type);
90 return crash_handler->GetDeathSignalSocket();
93 if (process_type == switches::kPluginProcess) {
94 static breakpad::CrashHandlerHostLinux* crash_handler = NULL;
96 crash_handler = CreateCrashHandlerHost(process_type);
97 return crash_handler->GetDeathSignalSocket();
100 if (process_type == switches::kPpapiPluginProcess) {
101 static breakpad::CrashHandlerHostLinux* crash_handler = NULL;
103 crash_handler = CreateCrashHandlerHost(process_type);
104 return crash_handler->GetDeathSignalSocket();
107 if (process_type == switches::kGpuProcess) {
108 static breakpad::CrashHandlerHostLinux* crash_handler = NULL;
110 crash_handler = CreateCrashHandlerHost(process_type);
111 return crash_handler->GetDeathSignalSocket();
116 #endif // defined(OS_POSIX) && !defined(OS_MACOSX) && !defined(OS_ANDROID)
118 void RequestDesktopNotificationPermissionOnIO(
119 const GURL& source_origin,
120 RenderFrameHost* render_frame_host,
121 const base::Callback<void(blink::WebNotificationPermission)>& callback) {
122 ShellNotificationManager* manager =
123 ShellContentBrowserClient::Get()->GetShellNotificationManager();
125 manager->RequestPermission(source_origin, callback);
127 callback.Run(blink::WebNotificationPermissionAllowed);
132 ShellContentBrowserClient* ShellContentBrowserClient::Get() {
133 return g_browser_client;
136 void ShellContentBrowserClient::SetSwapProcessesForRedirect(bool swap) {
137 g_swap_processes_for_redirect = swap;
140 ShellContentBrowserClient::ShellContentBrowserClient()
141 : shell_browser_main_parts_(NULL) {
142 DCHECK(!g_browser_client);
143 g_browser_client = this;
144 if (!CommandLine::ForCurrentProcess()->HasSwitch(switches::kDumpRenderTree))
146 webkit_source_dir_ = GetWebKitRootDirFilePath();
149 ShellContentBrowserClient::~ShellContentBrowserClient() {
150 g_browser_client = NULL;
153 ShellNotificationManager*
154 ShellContentBrowserClient::GetShellNotificationManager() {
155 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
156 if (!CommandLine::ForCurrentProcess()->HasSwitch(switches::kDumpRenderTree))
159 if (!shell_notification_manager_)
160 shell_notification_manager_.reset(new ShellNotificationManager());
162 return shell_notification_manager_.get();
165 BrowserMainParts* ShellContentBrowserClient::CreateBrowserMainParts(
166 const MainFunctionParams& parameters) {
167 shell_browser_main_parts_ = new ShellBrowserMainParts(parameters);
168 return shell_browser_main_parts_;
171 void ShellContentBrowserClient::RenderProcessWillLaunch(
172 RenderProcessHost* host) {
173 if (CommandLine::ForCurrentProcess()->HasSwitch(switches::kExposeIpcEcho))
174 host->AddFilter(new IPCEchoMessageFilter());
175 if (!CommandLine::ForCurrentProcess()->HasSwitch(switches::kDumpRenderTree))
177 host->AddFilter(new ShellMessageFilter(
179 BrowserContext::GetDefaultStoragePartition(browser_context())
180 ->GetDatabaseTracker(),
181 BrowserContext::GetDefaultStoragePartition(browser_context())
183 BrowserContext::GetDefaultStoragePartition(browser_context())
184 ->GetURLRequestContext()));
185 host->Send(new ShellViewMsg_SetWebKitSourceDir(webkit_source_dir_));
188 net::URLRequestContextGetter* ShellContentBrowserClient::CreateRequestContext(
189 BrowserContext* content_browser_context,
190 ProtocolHandlerMap* protocol_handlers,
191 URLRequestInterceptorScopedVector request_interceptors) {
192 ShellBrowserContext* shell_browser_context =
193 ShellBrowserContextForBrowserContext(content_browser_context);
194 return shell_browser_context->CreateRequestContext(
195 protocol_handlers, request_interceptors.Pass());
198 net::URLRequestContextGetter*
199 ShellContentBrowserClient::CreateRequestContextForStoragePartition(
200 BrowserContext* content_browser_context,
201 const base::FilePath& partition_path,
203 ProtocolHandlerMap* protocol_handlers,
204 URLRequestInterceptorScopedVector request_interceptors) {
205 ShellBrowserContext* shell_browser_context =
206 ShellBrowserContextForBrowserContext(content_browser_context);
207 return shell_browser_context->CreateRequestContextForStoragePartition(
211 request_interceptors.Pass());
214 bool ShellContentBrowserClient::IsHandledURL(const GURL& url) {
217 DCHECK_EQ(url.scheme(), base::StringToLowerASCII(url.scheme()));
218 // Keep in sync with ProtocolHandlers added by
219 // ShellURLRequestContextGetter::GetURLRequestContext().
220 static const char* const kProtocolList[] = {
222 url::kFileSystemScheme,
224 kChromeDevToolsScheme,
228 for (size_t i = 0; i < arraysize(kProtocolList); ++i) {
229 if (url.scheme() == kProtocolList[i])
235 void ShellContentBrowserClient::AppendExtraCommandLineSwitches(
236 CommandLine* command_line, int child_process_id) {
237 if (CommandLine::ForCurrentProcess()->HasSwitch(switches::kDumpRenderTree))
238 command_line->AppendSwitch(switches::kDumpRenderTree);
239 if (CommandLine::ForCurrentProcess()->HasSwitch(
240 switches::kEnableFontAntialiasing))
241 command_line->AppendSwitch(switches::kEnableFontAntialiasing);
242 if (CommandLine::ForCurrentProcess()->HasSwitch(
243 switches::kExposeInternalsForTesting))
244 command_line->AppendSwitch(switches::kExposeInternalsForTesting);
245 if (CommandLine::ForCurrentProcess()->HasSwitch(
246 switches::kExposeIpcEcho))
247 command_line->AppendSwitch(switches::kExposeIpcEcho);
248 if (CommandLine::ForCurrentProcess()->HasSwitch(switches::kStableReleaseMode))
249 command_line->AppendSwitch(switches::kStableReleaseMode);
250 if (CommandLine::ForCurrentProcess()->HasSwitch(
251 switches::kEnableCrashReporter)) {
252 command_line->AppendSwitch(switches::kEnableCrashReporter);
254 if (CommandLine::ForCurrentProcess()->HasSwitch(switches::kCrashDumpsDir)) {
255 command_line->AppendSwitchPath(
256 switches::kCrashDumpsDir,
257 CommandLine::ForCurrentProcess()->GetSwitchValuePath(
258 switches::kCrashDumpsDir));
260 if (CommandLine::ForCurrentProcess()->HasSwitch(
261 switches::kEnableLeakDetection)) {
262 command_line->AppendSwitchASCII(
263 switches::kEnableLeakDetection,
264 CommandLine::ForCurrentProcess()->GetSwitchValueASCII(
265 switches::kEnableLeakDetection));
267 if (CommandLine::ForCurrentProcess()->HasSwitch(
268 switches::kRegisterFontFiles)) {
269 command_line->AppendSwitchASCII(
270 switches::kRegisterFontFiles,
271 CommandLine::ForCurrentProcess()->GetSwitchValueASCII(
272 switches::kRegisterFontFiles));
276 void ShellContentBrowserClient::OverrideWebkitPrefs(
277 RenderViewHost* render_view_host,
279 WebPreferences* prefs) {
280 if (!CommandLine::ForCurrentProcess()->HasSwitch(switches::kDumpRenderTree))
282 WebKitTestController::Get()->OverrideWebkitPrefs(prefs);
285 void ShellContentBrowserClient::ResourceDispatcherHostCreated() {
286 resource_dispatcher_host_delegate_.reset(
287 new ShellResourceDispatcherHostDelegate());
288 ResourceDispatcherHost::Get()->SetDelegate(
289 resource_dispatcher_host_delegate_.get());
292 std::string ShellContentBrowserClient::GetDefaultDownloadName() {
296 WebContentsViewDelegate* ShellContentBrowserClient::GetWebContentsViewDelegate(
297 WebContents* web_contents) {
298 #if !defined(USE_AURA)
299 return CreateShellWebContentsViewDelegate(web_contents);
305 QuotaPermissionContext*
306 ShellContentBrowserClient::CreateQuotaPermissionContext() {
307 return new ShellQuotaPermissionContext();
310 void ShellContentBrowserClient::RequestDesktopNotificationPermission(
311 const GURL& source_origin,
312 RenderFrameHost* render_frame_host,
313 const base::Callback<void(blink::WebNotificationPermission)>& callback) {
314 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
315 BrowserThread::PostTask(BrowserThread::IO,
317 base::Bind(&RequestDesktopNotificationPermissionOnIO,
323 blink::WebNotificationPermission
324 ShellContentBrowserClient::CheckDesktopNotificationPermission(
325 const GURL& source_url,
326 ResourceContext* context,
327 int render_process_id) {
328 ShellNotificationManager* manager = GetShellNotificationManager();
330 return manager->CheckPermission(source_url);
332 return blink::WebNotificationPermissionAllowed;
335 SpeechRecognitionManagerDelegate*
336 ShellContentBrowserClient::GetSpeechRecognitionManagerDelegate() {
337 return new ShellSpeechRecognitionManagerDelegate();
340 net::NetLog* ShellContentBrowserClient::GetNetLog() {
341 return shell_browser_main_parts_->net_log();
344 bool ShellContentBrowserClient::ShouldSwapProcessesForRedirect(
345 ResourceContext* resource_context,
346 const GURL& current_url,
347 const GURL& new_url) {
348 return g_swap_processes_for_redirect;
351 DevToolsManagerDelegate*
352 ShellContentBrowserClient::GetDevToolsManagerDelegate() {
353 return new ShellDevToolsManagerDelegate(browser_context());
356 #if defined(OS_POSIX) && !defined(OS_MACOSX)
357 void ShellContentBrowserClient::GetAdditionalMappedFilesForChildProcess(
358 const CommandLine& command_line,
359 int child_process_id,
360 std::vector<FileDescriptorInfo>* mappings) {
361 #if defined(OS_ANDROID)
362 int flags = base::File::FLAG_OPEN | base::File::FLAG_READ;
363 base::FilePath pak_file;
364 bool r = PathService::Get(base::DIR_ANDROID_APP_DATA, &pak_file);
366 pak_file = pak_file.Append(FILE_PATH_LITERAL("paks"));
367 pak_file = pak_file.Append(FILE_PATH_LITERAL("content_shell.pak"));
369 base::File f(pak_file, flags);
371 NOTREACHED() << "Failed to open file when creating renderer process: "
372 << "content_shell.pak";
375 FileDescriptorInfo(kShellPakDescriptor, base::FileDescriptor(f.Pass())));
377 if (breakpad::IsCrashReporterEnabled()) {
378 f = breakpad::CrashDumpManager::GetInstance()->CreateMinidumpFile(
381 LOG(ERROR) << "Failed to create file for minidump, crash reporting will "
382 << "be disabled for this process.";
385 FileDescriptorInfo(kAndroidMinidumpDescriptor,
386 base::FileDescriptor(f.Pass())));
389 #else // !defined(OS_ANDROID)
390 int crash_signal_fd = GetCrashSignalFD(command_line);
391 if (crash_signal_fd >= 0) {
392 mappings->push_back(FileDescriptorInfo(
393 kCrashDumpSignal, base::FileDescriptor(crash_signal_fd, false)));
395 #endif // defined(OS_ANDROID)
397 #endif // defined(OS_POSIX) && !defined(OS_MACOSX)
400 void ShellContentBrowserClient::PreSpawnRenderer(sandbox::TargetPolicy* policy,
402 // Add sideloaded font files for testing. See also DIR_WINDOWS_FONTS
403 // addition in |StartSandboxedProcess|.
404 std::vector<std::string> font_files = GetSideloadFontFiles();
405 for (std::vector<std::string>::const_iterator i(font_files.begin());
406 i != font_files.end();
408 policy->AddRule(sandbox::TargetPolicy::SUBSYS_FILES,
409 sandbox::TargetPolicy::FILES_ALLOW_READONLY,
410 base::UTF8ToWide(*i).c_str());
415 ShellBrowserContext* ShellContentBrowserClient::browser_context() {
416 return shell_browser_main_parts_->browser_context();
420 ShellContentBrowserClient::off_the_record_browser_context() {
421 return shell_browser_main_parts_->off_the_record_browser_context();
424 AccessTokenStore* ShellContentBrowserClient::CreateAccessTokenStore() {
425 return new ShellAccessTokenStore(browser_context());
429 ShellContentBrowserClient::ShellBrowserContextForBrowserContext(
430 BrowserContext* content_browser_context) {
431 if (content_browser_context == browser_context())
432 return browser_context();
433 DCHECK_EQ(content_browser_context, off_the_record_browser_context());
434 return off_the_record_browser_context();
437 } // namespace content