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