Home | History | Annotate | Download | only in browser
      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