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/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