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/file_util.h" 10 #include "base/files/file.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/shell/browser/shell.h" 19 #include "content/shell/browser/shell_browser_context.h" 20 #include "content/shell/browser/shell_browser_main_parts.h" 21 #include "content/shell/browser/shell_devtools_delegate.h" 22 #include "content/shell/browser/shell_message_filter.h" 23 #include "content/shell/browser/shell_net_log.h" 24 #include "content/shell/browser/shell_quota_permission_context.h" 25 #include "content/shell/browser/shell_resource_dispatcher_host_delegate.h" 26 #include "content/shell/browser/shell_web_contents_view_delegate_creator.h" 27 #include "content/shell/browser/webkit_test_controller.h" 28 #include "content/shell/common/shell_messages.h" 29 #include "content/shell/common/shell_switches.h" 30 #include "content/shell/common/webkit_test_helpers.h" 31 #include "content/shell/geolocation/shell_access_token_store.h" 32 #include "net/url_request/url_request_context_getter.h" 33 #include "url/gurl.h" 34 #include "webkit/common/webpreferences.h" 35 36 #if defined(OS_ANDROID) 37 #include "base/android/path_utils.h" 38 #include "base/path_service.h" 39 #include "components/breakpad/browser/crash_dump_manager_android.h" 40 #include "content/shell/android/shell_descriptors.h" 41 #endif 42 43 #if defined(OS_POSIX) && !defined(OS_MACOSX) 44 #include "base/debug/leak_annotations.h" 45 #include "components/breakpad/app/breakpad_linux.h" 46 #include "components/breakpad/browser/crash_handler_host_linux.h" 47 #include "content/public/common/content_descriptors.h" 48 #endif 49 50 #if defined(OS_WIN) 51 #include "content/common/sandbox_win.h" 52 #include "sandbox/win/src/sandbox.h" 53 #endif 54 55 namespace content { 56 57 namespace { 58 59 ShellContentBrowserClient* g_browser_client; 60 bool g_swap_processes_for_redirect = false; 61 62 #if defined(OS_POSIX) && !defined(OS_MACOSX) && !defined(OS_ANDROID) 63 breakpad::CrashHandlerHostLinux* CreateCrashHandlerHost( 64 const std::string& process_type) { 65 base::FilePath dumps_path = 66 CommandLine::ForCurrentProcess()->GetSwitchValuePath( 67 switches::kCrashDumpsDir); 68 { 69 ANNOTATE_SCOPED_MEMORY_LEAK; 70 breakpad::CrashHandlerHostLinux* crash_handler = 71 new breakpad::CrashHandlerHostLinux( 72 process_type, dumps_path, false); 73 crash_handler->StartUploaderThread(); 74 return crash_handler; 75 } 76 } 77 78 int GetCrashSignalFD(const CommandLine& command_line) { 79 if (!breakpad::IsCrashReporterEnabled()) 80 return -1; 81 82 std::string process_type = 83 command_line.GetSwitchValueASCII(switches::kProcessType); 84 85 if (process_type == switches::kRendererProcess) { 86 static breakpad::CrashHandlerHostLinux* crash_handler = NULL; 87 if (!crash_handler) 88 crash_handler = CreateCrashHandlerHost(process_type); 89 return crash_handler->GetDeathSignalSocket(); 90 } 91 92 if (process_type == switches::kPluginProcess) { 93 static breakpad::CrashHandlerHostLinux* crash_handler = NULL; 94 if (!crash_handler) 95 crash_handler = CreateCrashHandlerHost(process_type); 96 return crash_handler->GetDeathSignalSocket(); 97 } 98 99 if (process_type == switches::kPpapiPluginProcess) { 100 static breakpad::CrashHandlerHostLinux* crash_handler = NULL; 101 if (!crash_handler) 102 crash_handler = CreateCrashHandlerHost(process_type); 103 return crash_handler->GetDeathSignalSocket(); 104 } 105 106 if (process_type == switches::kGpuProcess) { 107 static breakpad::CrashHandlerHostLinux* crash_handler = NULL; 108 if (!crash_handler) 109 crash_handler = CreateCrashHandlerHost(process_type); 110 return crash_handler->GetDeathSignalSocket(); 111 } 112 113 return -1; 114 } 115 #endif // defined(OS_POSIX) && !defined(OS_MACOSX) && !defined(OS_ANDROID) 116 117 } // namespace 118 119 ShellContentBrowserClient* ShellContentBrowserClient::Get() { 120 return g_browser_client; 121 } 122 123 void ShellContentBrowserClient::SetSwapProcessesForRedirect(bool swap) { 124 g_swap_processes_for_redirect = swap; 125 } 126 127 ShellContentBrowserClient::ShellContentBrowserClient() 128 : shell_browser_main_parts_(NULL) { 129 DCHECK(!g_browser_client); 130 g_browser_client = this; 131 if (!CommandLine::ForCurrentProcess()->HasSwitch(switches::kDumpRenderTree)) 132 return; 133 webkit_source_dir_ = GetWebKitRootDirFilePath(); 134 } 135 136 ShellContentBrowserClient::~ShellContentBrowserClient() { 137 g_browser_client = NULL; 138 } 139 140 BrowserMainParts* ShellContentBrowserClient::CreateBrowserMainParts( 141 const MainFunctionParams& parameters) { 142 shell_browser_main_parts_ = new ShellBrowserMainParts(parameters); 143 return shell_browser_main_parts_; 144 } 145 146 void ShellContentBrowserClient::RenderProcessWillLaunch( 147 RenderProcessHost* host) { 148 if (!CommandLine::ForCurrentProcess()->HasSwitch(switches::kDumpRenderTree)) 149 return; 150 host->AddFilter(new ShellMessageFilter( 151 host->GetID(), 152 BrowserContext::GetDefaultStoragePartition(browser_context()) 153 ->GetDatabaseTracker(), 154 BrowserContext::GetDefaultStoragePartition(browser_context()) 155 ->GetQuotaManager(), 156 BrowserContext::GetDefaultStoragePartition(browser_context()) 157 ->GetURLRequestContext())); 158 host->Send(new ShellViewMsg_SetWebKitSourceDir(webkit_source_dir_)); 159 } 160 161 net::URLRequestContextGetter* ShellContentBrowserClient::CreateRequestContext( 162 BrowserContext* content_browser_context, 163 ProtocolHandlerMap* protocol_handlers, 164 URLRequestInterceptorScopedVector request_interceptors) { 165 ShellBrowserContext* shell_browser_context = 166 ShellBrowserContextForBrowserContext(content_browser_context); 167 return shell_browser_context->CreateRequestContext( 168 protocol_handlers, request_interceptors.Pass()); 169 } 170 171 net::URLRequestContextGetter* 172 ShellContentBrowserClient::CreateRequestContextForStoragePartition( 173 BrowserContext* content_browser_context, 174 const base::FilePath& partition_path, 175 bool in_memory, 176 ProtocolHandlerMap* protocol_handlers, 177 URLRequestInterceptorScopedVector request_interceptors) { 178 ShellBrowserContext* shell_browser_context = 179 ShellBrowserContextForBrowserContext(content_browser_context); 180 return shell_browser_context->CreateRequestContextForStoragePartition( 181 partition_path, 182 in_memory, 183 protocol_handlers, 184 request_interceptors.Pass()); 185 } 186 187 bool ShellContentBrowserClient::IsHandledURL(const GURL& url) { 188 if (!url.is_valid()) 189 return false; 190 DCHECK_EQ(url.scheme(), StringToLowerASCII(url.scheme())); 191 // Keep in sync with ProtocolHandlers added by 192 // ShellURLRequestContextGetter::GetURLRequestContext(). 193 static const char* const kProtocolList[] = { 194 url::kBlobScheme, 195 url::kFileSystemScheme, 196 kChromeUIScheme, 197 kChromeDevToolsScheme, 198 url::kDataScheme, 199 url::kFileScheme, 200 }; 201 for (size_t i = 0; i < arraysize(kProtocolList); ++i) { 202 if (url.scheme() == kProtocolList[i]) 203 return true; 204 } 205 return false; 206 } 207 208 void ShellContentBrowserClient::AppendExtraCommandLineSwitches( 209 CommandLine* command_line, int child_process_id) { 210 if (CommandLine::ForCurrentProcess()->HasSwitch(switches::kDumpRenderTree)) 211 command_line->AppendSwitch(switches::kDumpRenderTree); 212 if (CommandLine::ForCurrentProcess()->HasSwitch( 213 switches::kEnableFontAntialiasing)) 214 command_line->AppendSwitch(switches::kEnableFontAntialiasing); 215 if (CommandLine::ForCurrentProcess()->HasSwitch( 216 switches::kExposeInternalsForTesting)) 217 command_line->AppendSwitch(switches::kExposeInternalsForTesting); 218 if (CommandLine::ForCurrentProcess()->HasSwitch(switches::kStableReleaseMode)) 219 command_line->AppendSwitch(switches::kStableReleaseMode); 220 if (CommandLine::ForCurrentProcess()->HasSwitch( 221 switches::kEnableCrashReporter)) { 222 command_line->AppendSwitch(switches::kEnableCrashReporter); 223 } 224 if (CommandLine::ForCurrentProcess()->HasSwitch(switches::kCrashDumpsDir)) { 225 command_line->AppendSwitchPath( 226 switches::kCrashDumpsDir, 227 CommandLine::ForCurrentProcess()->GetSwitchValuePath( 228 switches::kCrashDumpsDir)); 229 } 230 if (CommandLine::ForCurrentProcess()->HasSwitch( 231 switches::kEnableLeakDetection)) 232 command_line->AppendSwitch(switches::kEnableLeakDetection); 233 if (CommandLine::ForCurrentProcess()->HasSwitch( 234 switches::kRegisterFontFiles)) { 235 command_line->AppendSwitchASCII( 236 switches::kRegisterFontFiles, 237 CommandLine::ForCurrentProcess()->GetSwitchValueASCII( 238 switches::kRegisterFontFiles)); 239 } 240 } 241 242 void ShellContentBrowserClient::OverrideWebkitPrefs( 243 RenderViewHost* render_view_host, 244 const GURL& url, 245 WebPreferences* prefs) { 246 if (!CommandLine::ForCurrentProcess()->HasSwitch(switches::kDumpRenderTree)) 247 return; 248 WebKitTestController::Get()->OverrideWebkitPrefs(prefs); 249 } 250 251 void ShellContentBrowserClient::ResourceDispatcherHostCreated() { 252 resource_dispatcher_host_delegate_.reset( 253 new ShellResourceDispatcherHostDelegate()); 254 ResourceDispatcherHost::Get()->SetDelegate( 255 resource_dispatcher_host_delegate_.get()); 256 } 257 258 std::string ShellContentBrowserClient::GetDefaultDownloadName() { 259 return "download"; 260 } 261 262 WebContentsViewDelegate* ShellContentBrowserClient::GetWebContentsViewDelegate( 263 WebContents* web_contents) { 264 #if !defined(USE_AURA) 265 return CreateShellWebContentsViewDelegate(web_contents); 266 #else 267 return NULL; 268 #endif 269 } 270 271 QuotaPermissionContext* 272 ShellContentBrowserClient::CreateQuotaPermissionContext() { 273 return new ShellQuotaPermissionContext(); 274 } 275 276 SpeechRecognitionManagerDelegate* 277 ShellContentBrowserClient::GetSpeechRecognitionManagerDelegate() { 278 return new ShellSpeechRecognitionManagerDelegate(); 279 } 280 281 net::NetLog* ShellContentBrowserClient::GetNetLog() { 282 return shell_browser_main_parts_->net_log(); 283 } 284 285 bool ShellContentBrowserClient::ShouldSwapProcessesForRedirect( 286 ResourceContext* resource_context, 287 const GURL& current_url, 288 const GURL& new_url) { 289 return g_swap_processes_for_redirect; 290 } 291 292 #if defined(OS_POSIX) && !defined(OS_MACOSX) 293 void ShellContentBrowserClient::GetAdditionalMappedFilesForChildProcess( 294 const CommandLine& command_line, 295 int child_process_id, 296 std::vector<FileDescriptorInfo>* mappings) { 297 #if defined(OS_ANDROID) 298 int flags = base::File::FLAG_OPEN | base::File::FLAG_READ; 299 base::FilePath pak_file; 300 bool r = PathService::Get(base::DIR_ANDROID_APP_DATA, &pak_file); 301 CHECK(r); 302 pak_file = pak_file.Append(FILE_PATH_LITERAL("paks")); 303 pak_file = pak_file.Append(FILE_PATH_LITERAL("content_shell.pak")); 304 305 base::File f(pak_file, flags); 306 if (!f.IsValid()) { 307 NOTREACHED() << "Failed to open file when creating renderer process: " 308 << "content_shell.pak"; 309 } 310 mappings->push_back( 311 FileDescriptorInfo(kShellPakDescriptor, base::FileDescriptor(f.Pass()))); 312 313 if (breakpad::IsCrashReporterEnabled()) { 314 f = breakpad::CrashDumpManager::GetInstance()->CreateMinidumpFile( 315 child_process_id); 316 if (!f.IsValid()) { 317 LOG(ERROR) << "Failed to create file for minidump, crash reporting will " 318 << "be disabled for this process."; 319 } else { 320 mappings->push_back( 321 FileDescriptorInfo(kAndroidMinidumpDescriptor, 322 base::FileDescriptor(f.Pass()))); 323 } 324 } 325 #else // !defined(OS_ANDROID) 326 int crash_signal_fd = GetCrashSignalFD(command_line); 327 if (crash_signal_fd >= 0) { 328 mappings->push_back(FileDescriptorInfo( 329 kCrashDumpSignal, base::FileDescriptor(crash_signal_fd, false))); 330 } 331 #endif // defined(OS_ANDROID) 332 } 333 #endif // defined(OS_POSIX) && !defined(OS_MACOSX) 334 335 #if defined(OS_WIN) 336 void ShellContentBrowserClient::PreSpawnRenderer(sandbox::TargetPolicy* policy, 337 bool* success) { 338 // Add sideloaded font files for testing. See also DIR_WINDOWS_FONTS 339 // addition in |StartSandboxedProcess|. 340 std::vector<std::string> font_files = GetSideloadFontFiles(); 341 for (std::vector<std::string>::const_iterator i(font_files.begin()); 342 i != font_files.end(); 343 ++i) { 344 policy->AddRule(sandbox::TargetPolicy::SUBSYS_FILES, 345 sandbox::TargetPolicy::FILES_ALLOW_READONLY, 346 base::UTF8ToWide(*i).c_str()); 347 } 348 } 349 #endif // OS_WIN 350 351 ShellBrowserContext* ShellContentBrowserClient::browser_context() { 352 return shell_browser_main_parts_->browser_context(); 353 } 354 355 ShellBrowserContext* 356 ShellContentBrowserClient::off_the_record_browser_context() { 357 return shell_browser_main_parts_->off_the_record_browser_context(); 358 } 359 360 AccessTokenStore* ShellContentBrowserClient::CreateAccessTokenStore() { 361 return new ShellAccessTokenStore(browser_context()); 362 } 363 364 ShellBrowserContext* 365 ShellContentBrowserClient::ShellBrowserContextForBrowserContext( 366 BrowserContext* content_browser_context) { 367 if (content_browser_context == browser_context()) 368 return browser_context(); 369 DCHECK_EQ(content_browser_context, off_the_record_browser_context()); 370 return off_the_record_browser_context(); 371 } 372 373 } // namespace content 374