blob: 451187c1d41f74891b74ab41236f37feb2c93ab1 [file] [log] [blame]
[email protected]d977f9c2011-03-14 16:10:261// Copyright (c) 2011 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 "chrome/browser/chrome_content_browser_client.h"
6
[email protected]b80f68432011-05-02 17:22:307#include "base/command_line.h"
[email protected]25fe7fc52011-05-27 21:48:418#include "base/path_service.h"
9#include "base/string_number_conversions.h"
10#include "base/win/windows_version.h"
[email protected]b80f68432011-05-02 17:22:3011#include "chrome/app/breakpad_mac.h"
12#include "chrome/browser/browser_process.h"
[email protected]763ec4ca2011-04-29 15:48:1213#include "chrome/browser/character_encoding.h"
[email protected]97e6c4c2011-05-18 16:08:5114#include "chrome/browser/chrome_plugin_message_filter.h"
[email protected]5327dfb2011-05-03 17:50:3615#include "chrome/browser/chrome_worker_message_filter.h"
[email protected]a2176792011-05-08 19:30:4916#include "chrome/browser/content_settings/host_content_settings_map.h"
[email protected]8093a542011-05-13 07:29:3217#include "chrome/browser/content_settings/tab_specific_content_settings.h"
[email protected]f364d1392011-04-08 21:03:1018#include "chrome/browser/debugger/devtools_handler.h"
19#include "chrome/browser/desktop_notification_handler.h"
[email protected]f364d1392011-04-08 21:03:1020#include "chrome/browser/extensions/extension_message_handler.h"
[email protected]d977f9c2011-03-14 16:10:2621#include "chrome/browser/extensions/extension_service.h"
[email protected]763ec4ca2011-04-29 15:48:1222#include "chrome/browser/google/google_util.h"
23#include "chrome/browser/prefs/pref_service.h"
[email protected]05fcf982011-04-19 00:44:1424#include "chrome/browser/printing/printing_message_filter.h"
25#include "chrome/browser/profiles/profile.h"
[email protected]8093a542011-05-13 07:29:3226#include "chrome/browser/profiles/profile_io_data.h"
[email protected]05fcf982011-04-19 00:44:1427#include "chrome/browser/renderer_host/chrome_render_message_filter.h"
[email protected]53a0afa2011-04-28 02:09:3328#include "chrome/browser/renderer_host/chrome_render_view_host_observer.h"
[email protected]d4cff272011-05-02 15:46:0129#include "chrome/browser/renderer_host/text_input_client_message_filter.h"
[email protected]05fcf982011-04-19 00:44:1430#include "chrome/browser/search_engines/search_provider_install_state_message_filter.h"
31#include "chrome/browser/spellcheck_message_filter.h"
[email protected]1fd1a502011-03-30 16:55:5632#include "chrome/browser/ui/webui/chrome_web_ui_factory.h"
[email protected]b80f68432011-05-02 17:22:3033#include "chrome/common/child_process_logging.h"
[email protected]25fe7fc52011-05-27 21:48:4134#include "chrome/common/chrome_paths.h"
[email protected]b80f68432011-05-02 17:22:3035#include "chrome/common/chrome_switches.h"
[email protected]c5dbef02011-05-13 05:06:0936#include "chrome/common/extensions/extension_messages.h"
[email protected]763ec4ca2011-04-29 15:48:1237#include "chrome/common/pref_names.h"
[email protected]3e69bc82011-05-26 23:22:3838#include "chrome/common/render_messages.h"
[email protected]c5dbef02011-05-13 05:06:0939#include "chrome/common/url_constants.h"
40#include "content/browser/browsing_instance.h"
41#include "content/browser/child_process_security_policy.h"
[email protected]97e6c4c2011-05-18 16:08:5142#include "content/browser/plugin_process_host.h"
[email protected]05fcf982011-04-19 00:44:1443#include "content/browser/renderer_host/browser_render_process_host.h"
[email protected]d977f9c2011-03-14 16:10:2644#include "content/browser/renderer_host/render_view_host.h"
[email protected]a2176792011-05-08 19:30:4945#include "content/browser/resource_context.h"
[email protected]c5dbef02011-05-13 05:06:0946#include "content/browser/site_instance.h"
[email protected]763ec4ca2011-04-29 15:48:1247#include "content/browser/tab_contents/tab_contents.h"
[email protected]5327dfb2011-05-03 17:50:3648#include "content/browser/worker_host/worker_process_host.h"
[email protected]c5dbef02011-05-13 05:06:0949#include "content/common/bindings_policy.h"
[email protected]ed24fad2011-05-10 22:44:0150#include "net/base/cookie_monster.h"
51#include "net/base/cookie_options.h"
[email protected]d977f9c2011-03-14 16:10:2652
[email protected]b80f68432011-05-02 17:22:3053#if defined(OS_LINUX)
54#include "base/linux_util.h"
55#include "chrome/browser/crash_handler_host_linux.h"
[email protected]1fd5302c2011-05-28 04:06:4356#endif
[email protected]b80f68432011-05-02 17:22:3057
[email protected]25fe7fc52011-05-27 21:48:4158#if defined(OS_WIN)
59#include "chrome/common/sandbox_policy.h"
60#include "sandbox/src/sandbox.h"
61#endif
62
[email protected]c5dbef02011-05-13 05:06:0963namespace {
64
65void InitRenderViewHostForExtensions(RenderViewHost* render_view_host) {
66 // Note that due to GetEffectiveURL(), even hosted apps will have a
67 // chrome-extension:// URL for their site, so we can ignore that wrinkle here.
68 SiteInstance* site_instance = render_view_host->site_instance();
69 const GURL& site = site_instance->site();
70 RenderProcessHost* process = render_view_host->process();
71
72 if (!site.SchemeIs(chrome::kExtensionScheme))
73 return;
74
75 Profile* profile = site_instance->browsing_instance()->profile();
76 ExtensionService* service = profile->GetExtensionService();
77 if (!service)
78 return;
79
80 ExtensionProcessManager* process_manager =
81 profile->GetExtensionProcessManager();
82 CHECK(process_manager);
83
84 // This can happen if somebody typos a chrome-extension:// URL.
85 const Extension* extension = service->GetExtensionByURL(site);
86 if (!extension)
87 return;
88
89 site_instance->GetProcess()->mark_is_extension_process();
90
91 // Register the association between extension and process with
92 // ExtensionProcessManager.
93 process_manager->RegisterExtensionProcess(extension->id(), process->id());
94
95 // Record which, if any, installed app is associated with this process.
96 // TODO(aa): Totally lame to store this state in a global map in extension
97 // service. Can we get it from EPM instead?
98 if (extension->is_app())
99 service->SetInstalledAppForRenderer(process->id(), extension);
100
101 // Some extensions use chrome:// URLs.
102 Extension::Type type = extension->GetType();
103 if (type == Extension::TYPE_EXTENSION ||
104 type == Extension::TYPE_PACKAGED_APP) {
105 ChildProcessSecurityPolicy::GetInstance()->GrantScheme(
106 process->id(), chrome::kChromeUIScheme);
107 }
108
109 // Enable extension bindings for the renderer. Currently only extensions,
110 // packaged apps, and hosted component apps use extension bindings.
111 if (type == Extension::TYPE_EXTENSION ||
[email protected]2333bf22011-05-19 02:16:51112 type == Extension::TYPE_USER_SCRIPT ||
[email protected]c5dbef02011-05-13 05:06:09113 type == Extension::TYPE_PACKAGED_APP ||
114 (type == Extension::TYPE_HOSTED_APP &&
115 extension->location() == Extension::COMPONENT)) {
116 render_view_host->Send(new ExtensionMsg_ActivateExtension(extension->id()));
117 render_view_host->AllowBindings(BindingsPolicy::EXTENSION);
118 }
119}
120
[email protected]25fe7fc52011-05-27 21:48:41121#if defined(OS_WIN)
122// Launches the privileged flash broker, used when flash is sandboxed.
123// The broker is the same flash dll, except that it uses a different
124// entrypoint (BrokerMain) and it is hosted in windows' generic surrogate
125// process rundll32. After launching the broker we need to pass to
126// the flash plugin the process id of the broker via the command line
127// using --flash-broker=pid.
128// More info about rundll32 at http://support.microsoft.com/kb/164787.
129bool LoadFlashBroker(const FilePath& plugin_path, CommandLine* cmd_line) {
130 FilePath rundll;
131 if (!PathService::Get(base::DIR_SYSTEM, &rundll))
132 return false;
133 rundll = rundll.AppendASCII("rundll32.exe");
134 // Rundll32 cannot handle paths with spaces, so we use the short path.
135 wchar_t short_path[MAX_PATH];
136 if (0 == ::GetShortPathNameW(plugin_path.value().c_str(),
137 short_path, arraysize(short_path)))
138 return false;
139 // Here is the kicker, if the user has disabled 8.3 (short path) support
140 // on the volume GetShortPathNameW does not fail but simply returns the
141 // input path. In this case if the path had any spaces then rundll32 will
142 // incorrectly interpret its parameters. So we quote the path, even though
143 // the kb/164787 says you should not.
144 std::wstring cmd_final =
145 base::StringPrintf(L"%ls \"%ls\",BrokerMain browser=chrome",
146 rundll.value().c_str(),
147 short_path);
148 base::ProcessHandle process;
149 if (!base::LaunchApp(cmd_final, false, true, &process))
150 return false;
151
152 cmd_line->AppendSwitchASCII("flash-broker",
153 base::Int64ToString(::GetProcessId(process)));
154
155 // The flash broker, unders some circumstances can linger beyond the lifetime
156 // of the flash player, so we put it in a job object, when the browser
157 // terminates the job object is destroyed (by the OS) and the flash broker
158 // is terminated.
159 HANDLE job = ::CreateJobObjectW(NULL, NULL);
160 JOBOBJECT_EXTENDED_LIMIT_INFORMATION job_limits = {0};
161 job_limits.BasicLimitInformation.LimitFlags =
162 JOB_OBJECT_LIMIT_KILL_ON_JOB_CLOSE;
163 if (::SetInformationJobObject(job, JobObjectExtendedLimitInformation,
164 &job_limits, sizeof(job_limits))) {
165 ::AssignProcessToJobObject(job, process);
166 // Yes, we are leaking the object here. Read comment above.
167 } else {
168 ::CloseHandle(job);
169 return false;
170 }
171
172 ::CloseHandle(process);
173 return true;
174}
175#endif // OS_WIN
176
[email protected]c5dbef02011-05-13 05:06:09177}
178
[email protected]d977f9c2011-03-14 16:10:26179namespace chrome {
180
[email protected]f364d1392011-04-08 21:03:10181void ChromeContentBrowserClient::RenderViewHostCreated(
182 RenderViewHost* render_view_host) {
[email protected]53a0afa2011-04-28 02:09:33183 new ChromeRenderViewHostObserver(render_view_host);
[email protected]f364d1392011-04-08 21:03:10184 new DesktopNotificationHandler(render_view_host);
185 new DevToolsHandler(render_view_host);
186 new ExtensionMessageHandler(render_view_host);
[email protected]f364d1392011-04-08 21:03:10187
[email protected]c5dbef02011-05-13 05:06:09188 InitRenderViewHostForExtensions(render_view_host);
[email protected]d977f9c2011-03-14 16:10:26189}
190
[email protected]05fcf982011-04-19 00:44:14191void ChromeContentBrowserClient::BrowserRenderProcessHostCreated(
192 BrowserRenderProcessHost* host) {
[email protected]c47cfd62011-04-29 21:27:02193 int id = host->id();
194 Profile* profile = host->profile();
[email protected]05fcf982011-04-19 00:44:14195 host->channel()->AddFilter(new ChromeRenderMessageFilter(
[email protected]c47cfd62011-04-29 21:27:02196 id, profile, profile->GetRequestContextForRenderProcess(id)));
[email protected]05fcf982011-04-19 00:44:14197 host->channel()->AddFilter(new PrintingMessageFilter());
198 host->channel()->AddFilter(
[email protected]c47cfd62011-04-29 21:27:02199 new SearchProviderInstallStateMessageFilter(id, profile));
200 host->channel()->AddFilter(new SpellCheckMessageFilter(id));
[email protected]d4cff272011-05-02 15:46:01201#if defined(OS_MACOSX)
202 host->channel()->AddFilter(new TextInputClientMessageFilter(host->id()));
203#endif
[email protected]3e69bc82011-05-26 23:22:38204
205 host->Send(new ViewMsg_SetIsIncognitoProcess(profile->IsOffTheRecord()));
[email protected]05fcf982011-04-19 00:44:14206}
207
[email protected]97e6c4c2011-05-18 16:08:51208void ChromeContentBrowserClient::PluginProcessHostCreated(
209 PluginProcessHost* host) {
210 host->AddFilter(new ChromePluginMessageFilter(host));
211}
212
[email protected]5327dfb2011-05-03 17:50:36213void ChromeContentBrowserClient::WorkerProcessHostCreated(
214 WorkerProcessHost* host) {
215 host->AddFilter(new ChromeWorkerMessageFilter(host));
216}
217
[email protected]1fd1a502011-03-30 16:55:56218content::WebUIFactory* ChromeContentBrowserClient::GetWebUIFactory() {
219 return ChromeWebUIFactory::GetInstance();
220}
221
[email protected]36fb2c7c2011-04-04 15:49:08222GURL ChromeContentBrowserClient::GetEffectiveURL(Profile* profile,
223 const GURL& url) {
224 // Get the effective URL for the given actual URL. If the URL is part of an
225 // installed app, the effective URL is an extension URL with the ID of that
226 // extension as the host. This has the effect of grouping apps together in
227 // a common SiteInstance.
228 if (!profile || !profile->GetExtensionService())
229 return url;
230
231 const Extension* extension =
232 profile->GetExtensionService()->GetExtensionByWebExtent(url);
233 if (!extension)
234 return url;
235
236 // If the URL is part of an extension's web extent, convert it to an
237 // extension URL.
238 return extension->GetResourceURL(url.path());
239}
240
[email protected]0f012df82011-05-19 14:15:29241bool ChromeContentBrowserClient::IsURLSameAsAnySiteInstance(const GURL& url) {
242 return url.spec() == chrome::kAboutKillURL ||
243 url.spec() == chrome::kAboutHangURL ||
244 url.spec() == chrome::kAboutShorthangURL;
245}
246
[email protected]763ec4ca2011-04-29 15:48:12247std::string ChromeContentBrowserClient::GetCanonicalEncodingNameByAliasName(
248 const std::string& alias_name) {
249 return CharacterEncoding::GetCanonicalEncodingNameByAliasName(alias_name);
250}
251
[email protected]b80f68432011-05-02 17:22:30252void ChromeContentBrowserClient::AppendExtraCommandLineSwitches(
253 CommandLine* command_line, int child_process_id) {
254#if defined(USE_LINUX_BREAKPAD)
255 if (IsCrashReporterEnabled()) {
256 command_line->AppendSwitchASCII(switches::kEnableCrashReporter,
257 child_process_logging::GetClientId() + "," + base::GetLinuxDistro());
258 }
259#elif defined(OS_MACOSX)
260 if (IsCrashReporterEnabled()) {
261 command_line->AppendSwitchASCII(switches::kEnableCrashReporter,
262 child_process_logging::GetClientId());
263 }
264#endif // OS_MACOSX
265
266 std::string process_type =
267 command_line->GetSwitchValueASCII(switches::kProcessType);
268 if (process_type == switches::kExtensionProcess ||
269 process_type == switches::kRendererProcess) {
270 const CommandLine& browser_command_line = *CommandLine::ForCurrentProcess();
271 FilePath user_data_dir =
272 browser_command_line.GetSwitchValuePath(switches::kUserDataDir);
273 if (!user_data_dir.empty())
274 command_line->AppendSwitchPath(switches::kUserDataDir, user_data_dir);
275#if defined(OS_CHROMEOS)
276 const std::string& login_profile =
277 browser_command_line.GetSwitchValueASCII(switches::kLoginProfile);
278 if (!login_profile.empty())
279 command_line->AppendSwitchASCII(switches::kLoginProfile, login_profile);
280#endif
281
282 RenderProcessHost* process = RenderProcessHost::FromID(child_process_id);
283
284 PrefService* prefs = process->profile()->GetPrefs();
285 // Currently this pref is only registered if applied via a policy.
286 if (prefs->HasPrefPath(prefs::kDisable3DAPIs) &&
287 prefs->GetBoolean(prefs::kDisable3DAPIs)) {
288 // Turn this policy into a command line switch.
289 command_line->AppendSwitch(switches::kDisable3DAPIs);
290 }
291
292 // Disable client-side phishing detection in the renderer if it is disabled
293 // in the browser process.
294 if (!g_browser_process->safe_browsing_detection_service())
295 command_line->AppendSwitch(switches::kDisableClientSidePhishingDetection);
296 }
297}
298
299std::string ChromeContentBrowserClient::GetApplicationLocale() {
300 return g_browser_process->GetApplicationLocale();
301}
302
[email protected]b5cca982011-05-26 04:42:08303std::string ChromeContentBrowserClient::GetAcceptLangs(const TabContents* tab) {
304 return tab->profile()->GetPrefs()->GetString(prefs::kAcceptLanguages);
305}
306
[email protected]a2176792011-05-08 19:30:49307bool ChromeContentBrowserClient::AllowAppCache(
[email protected]5b52ad42011-05-26 14:26:09308 const GURL& manifest_url,
309 const content::ResourceContext& context) {
[email protected]8093a542011-05-13 07:29:32310 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
311 ProfileIOData* io_data =
312 reinterpret_cast<ProfileIOData*>(context.GetUserData(NULL));
[email protected]5b52ad42011-05-26 14:26:09313 // FIXME(jochen): get the correct top-level origin.
[email protected]efa55212011-05-13 16:19:38314 ContentSetting setting = io_data->GetHostContentSettingsMap()->
[email protected]5b52ad42011-05-26 14:26:09315 GetCookieContentSetting(manifest_url, manifest_url, true);
[email protected]a2176792011-05-08 19:30:49316 DCHECK(setting != CONTENT_SETTING_DEFAULT);
317 return setting != CONTENT_SETTING_BLOCK;
318}
319
[email protected]ed24fad2011-05-10 22:44:01320bool ChromeContentBrowserClient::AllowGetCookie(
321 const GURL& url,
322 const GURL& first_party,
323 const net::CookieList& cookie_list,
324 const content::ResourceContext& context,
325 int render_process_id,
326 int render_view_id) {
327 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
[email protected]8093a542011-05-13 07:29:32328 ProfileIOData* io_data =
329 reinterpret_cast<ProfileIOData*>(context.GetUserData(NULL));
[email protected]5b52ad42011-05-26 14:26:09330 ContentSetting setting = io_data->GetHostContentSettingsMap()->
331 GetCookieContentSetting(url, first_party, false);
332 bool allow = setting == CONTENT_SETTING_ALLOW ||
333 setting == CONTENT_SETTING_SESSION_ONLY;
[email protected]ed24fad2011-05-10 22:44:01334
[email protected]8093a542011-05-13 07:29:32335 BrowserThread::PostTask(
336 BrowserThread::UI, FROM_HERE,
337 NewRunnableFunction(
338 &TabSpecificContentSettings::CookiesRead,
339 render_process_id, render_view_id, url, cookie_list, !allow));
[email protected]ed24fad2011-05-10 22:44:01340 return allow;
341}
342
343bool ChromeContentBrowserClient::AllowSetCookie(
344 const GURL& url,
345 const GURL& first_party,
346 const std::string& cookie_line,
347 const content::ResourceContext& context,
348 int render_process_id,
349 int render_view_id,
350 net::CookieOptions* options) {
351 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
[email protected]8093a542011-05-13 07:29:32352 ProfileIOData* io_data =
353 reinterpret_cast<ProfileIOData*>(context.GetUserData(NULL));
[email protected]5b52ad42011-05-26 14:26:09354 ContentSetting setting = io_data->GetHostContentSettingsMap()->
355 GetCookieContentSetting(url, first_party, true);
[email protected]ed24fad2011-05-10 22:44:01356
[email protected]5b52ad42011-05-26 14:26:09357 if (setting == CONTENT_SETTING_SESSION_ONLY)
358 options->set_force_session();
[email protected]ed24fad2011-05-10 22:44:01359
[email protected]5b52ad42011-05-26 14:26:09360 bool allow = setting == CONTENT_SETTING_ALLOW ||
361 setting == CONTENT_SETTING_SESSION_ONLY;
[email protected]ed24fad2011-05-10 22:44:01362
[email protected]8093a542011-05-13 07:29:32363 BrowserThread::PostTask(
364 BrowserThread::UI, FROM_HERE,
365 NewRunnableFunction(
366 &TabSpecificContentSettings::CookieChanged,
367 render_process_id, render_view_id, url, cookie_line, *options,
368 !allow));
[email protected]ed24fad2011-05-10 22:44:01369 return allow;
370}
371
[email protected]b80f68432011-05-02 17:22:30372#if defined(OS_LINUX)
373int ChromeContentBrowserClient::GetCrashSignalFD(
374 const std::string& process_type) {
375 if (process_type == switches::kRendererProcess)
376 return RendererCrashHandlerHostLinux::GetInstance()->GetDeathSignalSocket();
377
378 if (process_type == switches::kPluginProcess)
379 return PluginCrashHandlerHostLinux::GetInstance()->GetDeathSignalSocket();
380
381 if (process_type == switches::kPpapiPluginProcess)
382 return PpapiCrashHandlerHostLinux::GetInstance()->GetDeathSignalSocket();
383
384 if (process_type == switches::kGpuProcess)
385 return GpuCrashHandlerHostLinux::GetInstance()->GetDeathSignalSocket();
386
387 return -1;
388}
389#endif
390
[email protected]25fe7fc52011-05-27 21:48:41391#if defined(OS_WIN)
392bool ChromeContentBrowserClient::SandboxPlugin(CommandLine* command_line,
393 sandbox::TargetPolicy* policy) {
394 std::wstring plugin_dll = command_line->
395 GetSwitchValueNative(switches::kPluginPath);
396
397 FilePath builtin_flash;
398 if (!PathService::Get(chrome::FILE_FLASH_PLUGIN, &builtin_flash))
399 return false;
400
401 FilePath plugin_path(plugin_dll);
402 if (plugin_path != builtin_flash)
403 return false;
404
405 if (base::win::GetVersion() <= base::win::VERSION_XP ||
406 CommandLine::ForCurrentProcess()->HasSwitch(
407 switches::kDisableFlashSandbox)) {
408 return false;
409 }
410
411 // Add the policy for the pipes.
412 sandbox::ResultCode result = sandbox::SBOX_ALL_OK;
413 result = policy->AddRule(sandbox::TargetPolicy::SUBSYS_NAMED_PIPES,
414 sandbox::TargetPolicy::NAMEDPIPES_ALLOW_ANY,
415 L"\\\\.\\pipe\\chrome.*");
416 if (result != sandbox::SBOX_ALL_OK) {
417 NOTREACHED();
418 return false;
419 }
420
421 // Spawn the flash broker and apply sandbox policy.
422 if (LoadFlashBroker(plugin_path, command_line)) {
423 policy->SetJobLevel(sandbox::JOB_UNPROTECTED, 0);
424 policy->SetTokenLevel(sandbox::USER_RESTRICTED_SAME_ACCESS,
425 sandbox::USER_INTERACTIVE);
426 policy->SetDelayedIntegrityLevel(sandbox::INTEGRITY_LEVEL_LOW);
427 } else {
428 // Could not start the broker, use a very weak policy instead.
429 DLOG(WARNING) << "Failed to start flash broker";
430 policy->SetJobLevel(sandbox::JOB_UNPROTECTED, 0);
431 policy->SetTokenLevel(
432 sandbox::USER_UNPROTECTED, sandbox::USER_UNPROTECTED);
433 }
434
435 return true;
436}
437#endif
438
[email protected]d977f9c2011-03-14 16:10:26439} // namespace chrome