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. 4 5 #include "content/shell/browser/shell_content_browser_client.h" 6 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" 36 #include "url/gurl.h" 37 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" 42 #endif 43 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" 49 #endif 50 51 #if defined(OS_WIN) 52 #include "content/common/sandbox_win.h" 53 #include "sandbox/win/src/sandbox.h" 54 #endif 55 56 namespace content { 57 58 namespace { 59 60 ShellContentBrowserClient* g_browser_client; 61 bool g_swap_processes_for_redirect = false; 62 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); 69 { 70 ANNOTATE_SCOPED_MEMORY_LEAK; 71 breakpad::CrashHandlerHostLinux* crash_handler = 72 new breakpad::CrashHandlerHostLinux( 73 process_type, dumps_path, false); 74 crash_handler->StartUploaderThread(); 75 return crash_handler; 76 } 77 } 78 79 int GetCrashSignalFD(const CommandLine& command_line) { 80 if (!breakpad::IsCrashReporterEnabled()) 81 return -1; 82 83 std::string process_type = 84 command_line.GetSwitchValueASCII(switches::kProcessType); 85 86 if (process_type == switches::kRendererProcess) { 87 static breakpad::CrashHandlerHostLinux* crash_handler = NULL; 88 if (!crash_handler) 89 crash_handler = CreateCrashHandlerHost(process_type); 90 return crash_handler->GetDeathSignalSocket(); 91 } 92 93 if (process_type == switches::kPluginProcess) { 94 static breakpad::CrashHandlerHostLinux* crash_handler = NULL; 95 if (!crash_handler) 96 crash_handler = CreateCrashHandlerHost(process_type); 97 return crash_handler->GetDeathSignalSocket(); 98 } 99 100 if (process_type == switches::kPpapiPluginProcess) { 101 static breakpad::CrashHandlerHostLinux* crash_handler = NULL; 102 if (!crash_handler) 103 crash_handler = CreateCrashHandlerHost(process_type); 104 return crash_handler->GetDeathSignalSocket(); 105 } 106 107 if (process_type == switches::kGpuProcess) { 108 static breakpad::CrashHandlerHostLinux* crash_handler = NULL; 109 if (!crash_handler) 110 crash_handler = CreateCrashHandlerHost(process_type); 111 return crash_handler->GetDeathSignalSocket(); 112 } 113 114 return -1; 115 } 116 #endif // defined(OS_POSIX) && !defined(OS_MACOSX) && !defined(OS_ANDROID) 117 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(); 124 if (manager) 125 manager->RequestPermission(source_origin, callback); 126 else 127 callback.Run(blink::WebNotificationPermissionAllowed); 128 } 129 130 } // namespace 131 132 ShellContentBrowserClient* ShellContentBrowserClient::Get() { 133 return g_browser_client; 134 } 135 136 void ShellContentBrowserClient::SetSwapProcessesForRedirect(bool swap) { 137 g_swap_processes_for_redirect = swap; 138 } 139 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)) 145 return; 146 webkit_source_dir_ = GetWebKitRootDirFilePath(); 147 } 148 149 ShellContentBrowserClient::~ShellContentBrowserClient() { 150 g_browser_client = NULL; 151 } 152 153 ShellNotificationManager* 154 ShellContentBrowserClient::GetShellNotificationManager() { 155 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); 156 if (!CommandLine::ForCurrentProcess()->HasSwitch(switches::kDumpRenderTree)) 157 return NULL; 158 159 if (!shell_notification_manager_) 160 shell_notification_manager_.reset(new ShellNotificationManager()); 161 162 return shell_notification_manager_.get(); 163 } 164 165 BrowserMainParts* ShellContentBrowserClient::CreateBrowserMainParts( 166 const MainFunctionParams& parameters) { 167 shell_browser_main_parts_ = new ShellBrowserMainParts(parameters); 168 return shell_browser_main_parts_; 169 } 170 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)) 176 return; 177 host->AddFilter(new ShellMessageFilter( 178 host->GetID(), 179 BrowserContext::GetDefaultStoragePartition(browser_context()) 180 ->GetDatabaseTracker(), 181 BrowserContext::GetDefaultStoragePartition(browser_context()) 182 ->GetQuotaManager(), 183 BrowserContext::GetDefaultStoragePartition(browser_context()) 184 ->GetURLRequestContext())); 185 host->Send(new ShellViewMsg_SetWebKitSourceDir(webkit_source_dir_)); 186 } 187 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()); 196 } 197 198 net::URLRequestContextGetter* 199 ShellContentBrowserClient::CreateRequestContextForStoragePartition( 200 BrowserContext* content_browser_context, 201 const base::FilePath& partition_path, 202 bool in_memory, 203 ProtocolHandlerMap* protocol_handlers, 204 URLRequestInterceptorScopedVector request_interceptors) { 205 ShellBrowserContext* shell_browser_context = 206 ShellBrowserContextForBrowserContext(content_browser_context); 207 return shell_browser_context->CreateRequestContextForStoragePartition( 208 partition_path, 209 in_memory, 210 protocol_handlers, 211 request_interceptors.Pass()); 212 } 213 214 bool ShellContentBrowserClient::IsHandledURL(const GURL& url) { 215 if (!url.is_valid()) 216 return false; 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[] = { 221 url::kBlobScheme, 222 url::kFileSystemScheme, 223 kChromeUIScheme, 224 kChromeDevToolsScheme, 225 url::kDataScheme, 226 url::kFileScheme, 227 }; 228 for (size_t i = 0; i < arraysize(kProtocolList); ++i) { 229 if (url.scheme() == kProtocolList[i]) 230 return true; 231 } 232 return false; 233 } 234 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); 253 } 254 if (CommandLine::ForCurrentProcess()->HasSwitch(switches::kCrashDumpsDir)) { 255 command_line->AppendSwitchPath( 256 switches::kCrashDumpsDir, 257 CommandLine::ForCurrentProcess()->GetSwitchValuePath( 258 switches::kCrashDumpsDir)); 259 } 260 if (CommandLine::ForCurrentProcess()->HasSwitch( 261 switches::kEnableLeakDetection)) { 262 command_line->AppendSwitchASCII( 263 switches::kEnableLeakDetection, 264 CommandLine::ForCurrentProcess()->GetSwitchValueASCII( 265 switches::kEnableLeakDetection)); 266 } 267 if (CommandLine::ForCurrentProcess()->HasSwitch( 268 switches::kRegisterFontFiles)) { 269 command_line->AppendSwitchASCII( 270 switches::kRegisterFontFiles, 271 CommandLine::ForCurrentProcess()->GetSwitchValueASCII( 272 switches::kRegisterFontFiles)); 273 } 274 } 275 276 void ShellContentBrowserClient::OverrideWebkitPrefs( 277 RenderViewHost* render_view_host, 278 const GURL& url, 279 WebPreferences* prefs) { 280 if (!CommandLine::ForCurrentProcess()->HasSwitch(switches::kDumpRenderTree)) 281 return; 282 WebKitTestController::Get()->OverrideWebkitPrefs(prefs); 283 } 284 285 void ShellContentBrowserClient::ResourceDispatcherHostCreated() { 286 resource_dispatcher_host_delegate_.reset( 287 new ShellResourceDispatcherHostDelegate()); 288 ResourceDispatcherHost::Get()->SetDelegate( 289 resource_dispatcher_host_delegate_.get()); 290 } 291 292 std::string ShellContentBrowserClient::GetDefaultDownloadName() { 293 return "download"; 294 } 295 296 WebContentsViewDelegate* ShellContentBrowserClient::GetWebContentsViewDelegate( 297 WebContents* web_contents) { 298 #if !defined(USE_AURA) 299 return CreateShellWebContentsViewDelegate(web_contents); 300 #else 301 return NULL; 302 #endif 303 } 304 305 QuotaPermissionContext* 306 ShellContentBrowserClient::CreateQuotaPermissionContext() { 307 return new ShellQuotaPermissionContext(); 308 } 309 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, 316 FROM_HERE, 317 base::Bind(&RequestDesktopNotificationPermissionOnIO, 318 source_origin, 319 render_frame_host, 320 callback)); 321 } 322 323 blink::WebNotificationPermission 324 ShellContentBrowserClient::CheckDesktopNotificationPermission( 325 const GURL& source_url, 326 ResourceContext* context, 327 int render_process_id) { 328 ShellNotificationManager* manager = GetShellNotificationManager(); 329 if (manager) 330 return manager->CheckPermission(source_url); 331 332 return blink::WebNotificationPermissionAllowed; 333 } 334 335 SpeechRecognitionManagerDelegate* 336 ShellContentBrowserClient::GetSpeechRecognitionManagerDelegate() { 337 return new ShellSpeechRecognitionManagerDelegate(); 338 } 339 340 net::NetLog* ShellContentBrowserClient::GetNetLog() { 341 return shell_browser_main_parts_->net_log(); 342 } 343 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; 349 } 350 351 DevToolsManagerDelegate* 352 ShellContentBrowserClient::GetDevToolsManagerDelegate() { 353 return new ShellDevToolsManagerDelegate(browser_context()); 354 } 355 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); 365 CHECK(r); 366 pak_file = pak_file.Append(FILE_PATH_LITERAL("paks")); 367 pak_file = pak_file.Append(FILE_PATH_LITERAL("content_shell.pak")); 368 369 base::File f(pak_file, flags); 370 if (!f.IsValid()) { 371 NOTREACHED() << "Failed to open file when creating renderer process: " 372 << "content_shell.pak"; 373 } 374 mappings->push_back( 375 FileDescriptorInfo(kShellPakDescriptor, base::FileDescriptor(f.Pass()))); 376 377 if (breakpad::IsCrashReporterEnabled()) { 378 f = breakpad::CrashDumpManager::GetInstance()->CreateMinidumpFile( 379 child_process_id); 380 if (!f.IsValid()) { 381 LOG(ERROR) << "Failed to create file for minidump, crash reporting will " 382 << "be disabled for this process."; 383 } else { 384 mappings->push_back( 385 FileDescriptorInfo(kAndroidMinidumpDescriptor, 386 base::FileDescriptor(f.Pass()))); 387 } 388 } 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))); 394 } 395 #endif // defined(OS_ANDROID) 396 } 397 #endif // defined(OS_POSIX) && !defined(OS_MACOSX) 398 399 #if defined(OS_WIN) 400 void ShellContentBrowserClient::PreSpawnRenderer(sandbox::TargetPolicy* policy, 401 bool* success) { 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(); 407 ++i) { 408 policy->AddRule(sandbox::TargetPolicy::SUBSYS_FILES, 409 sandbox::TargetPolicy::FILES_ALLOW_READONLY, 410 base::UTF8ToWide(*i).c_str()); 411 } 412 } 413 #endif // OS_WIN 414 415 ShellBrowserContext* ShellContentBrowserClient::browser_context() { 416 return shell_browser_main_parts_->browser_context(); 417 } 418 419 ShellBrowserContext* 420 ShellContentBrowserClient::off_the_record_browser_context() { 421 return shell_browser_main_parts_->off_the_record_browser_context(); 422 } 423 424 AccessTokenStore* ShellContentBrowserClient::CreateAccessTokenStore() { 425 return new ShellAccessTokenStore(browser_context()); 426 } 427 428 ShellBrowserContext* 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(); 435 } 436 437 } // namespace content 438