• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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)
CreateCrashHandlerHost(const std::string & process_type)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 
GetCrashSignalFD(const CommandLine & command_line)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 
Get()119 ShellContentBrowserClient* ShellContentBrowserClient::Get() {
120   return g_browser_client;
121 }
122 
SetSwapProcessesForRedirect(bool swap)123 void ShellContentBrowserClient::SetSwapProcessesForRedirect(bool swap) {
124   g_swap_processes_for_redirect = swap;
125 }
126 
ShellContentBrowserClient()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 
~ShellContentBrowserClient()136 ShellContentBrowserClient::~ShellContentBrowserClient() {
137   g_browser_client = NULL;
138 }
139 
CreateBrowserMainParts(const MainFunctionParams & parameters)140 BrowserMainParts* ShellContentBrowserClient::CreateBrowserMainParts(
141     const MainFunctionParams& parameters) {
142   shell_browser_main_parts_ = new ShellBrowserMainParts(parameters);
143   return shell_browser_main_parts_;
144 }
145 
RenderProcessWillLaunch(RenderProcessHost * host)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 
CreateRequestContext(BrowserContext * content_browser_context,ProtocolHandlerMap * protocol_handlers,URLRequestInterceptorScopedVector request_interceptors)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*
CreateRequestContextForStoragePartition(BrowserContext * content_browser_context,const base::FilePath & partition_path,bool in_memory,ProtocolHandlerMap * protocol_handlers,URLRequestInterceptorScopedVector request_interceptors)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 
IsHandledURL(const GURL & url)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 
AppendExtraCommandLineSwitches(CommandLine * command_line,int child_process_id)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 
OverrideWebkitPrefs(RenderViewHost * render_view_host,const GURL & url,WebPreferences * prefs)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 
ResourceDispatcherHostCreated()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 
GetDefaultDownloadName()258 std::string ShellContentBrowserClient::GetDefaultDownloadName() {
259   return "download";
260 }
261 
GetWebContentsViewDelegate(WebContents * web_contents)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*
CreateQuotaPermissionContext()272 ShellContentBrowserClient::CreateQuotaPermissionContext() {
273   return new ShellQuotaPermissionContext();
274 }
275 
276 SpeechRecognitionManagerDelegate*
GetSpeechRecognitionManagerDelegate()277     ShellContentBrowserClient::GetSpeechRecognitionManagerDelegate() {
278   return new ShellSpeechRecognitionManagerDelegate();
279 }
280 
GetNetLog()281 net::NetLog* ShellContentBrowserClient::GetNetLog() {
282   return shell_browser_main_parts_->net_log();
283 }
284 
ShouldSwapProcessesForRedirect(ResourceContext * resource_context,const GURL & current_url,const GURL & new_url)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)
GetAdditionalMappedFilesForChildProcess(const CommandLine & command_line,int child_process_id,std::vector<FileDescriptorInfo> * mappings)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)
PreSpawnRenderer(sandbox::TargetPolicy * policy,bool * success)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 
browser_context()351 ShellBrowserContext* ShellContentBrowserClient::browser_context() {
352   return shell_browser_main_parts_->browser_context();
353 }
354 
355 ShellBrowserContext*
off_the_record_browser_context()356     ShellContentBrowserClient::off_the_record_browser_context() {
357   return shell_browser_main_parts_->off_the_record_browser_context();
358 }
359 
CreateAccessTokenStore()360 AccessTokenStore* ShellContentBrowserClient::CreateAccessTokenStore() {
361   return new ShellAccessTokenStore(browser_context());
362 }
363 
364 ShellBrowserContext*
ShellBrowserContextForBrowserContext(BrowserContext * content_browser_context)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