chrome_content_browser_client.cc revision 5821806d5e7f356e8fa4b058a389a808ea183019
1// Copyright (c) 2012 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
7#include <set>
8#include <utility>
9#include <vector>
10
11#include "base/bind.h"
12#include "base/command_line.h"
13#include "base/path_service.h"
14#include "base/string_tokenizer.h"
15#include "base/utf_string_conversions.h"
16#include "chrome/app/breakpad_mac.h"
17#include "chrome/browser/browser_about_handler.h"
18#include "chrome/browser/browser_process.h"
19#include "chrome/browser/browsing_data/browsing_data_helper.h"
20#include "chrome/browser/browsing_data/browsing_data_remover.h"
21#include "chrome/browser/character_encoding.h"
22#include "chrome/browser/chrome_benchmarking_message_filter.h"
23#include "chrome/browser/chrome_quota_permission_context.h"
24#include "chrome/browser/content_settings/content_settings_utils.h"
25#include "chrome/browser/content_settings/cookie_settings.h"
26#include "chrome/browser/content_settings/host_content_settings_map.h"
27#include "chrome/browser/content_settings/tab_specific_content_settings.h"
28#include "chrome/browser/defaults.h"
29#include "chrome/browser/download/download_util.h"
30#include "chrome/browser/extensions/api/web_request/web_request_api.h"
31#include "chrome/browser/extensions/extension_host.h"
32#include "chrome/browser/extensions/extension_info_map.h"
33#include "chrome/browser/extensions/extension_process_manager.h"
34#include "chrome/browser/extensions/extension_service.h"
35#include "chrome/browser/extensions/extension_system.h"
36#include "chrome/browser/extensions/extension_web_ui.h"
37#include "chrome/browser/extensions/extension_webkit_preferences.h"
38#include "chrome/browser/extensions/message_handler.h"
39#include "chrome/browser/geolocation/chrome_access_token_store.h"
40#include "chrome/browser/google/google_util.h"
41#include "chrome/browser/infobars/infobar_tab_helper.h"
42#include "chrome/browser/media/media_internals.h"
43#include "chrome/browser/nacl_host/nacl_process_host.h"
44#include "chrome/browser/net/chrome_net_log.h"
45#include "chrome/browser/notifications/desktop_notification_service.h"
46#include "chrome/browser/notifications/desktop_notification_service_factory.h"
47#include "chrome/browser/pepper_gtalk_message_filter.h"
48#include "chrome/browser/platform_util.h"
49#include "chrome/browser/prefs/pref_service.h"
50#include "chrome/browser/prefs/scoped_user_pref_update.h"
51#include "chrome/browser/prerender/prerender_manager.h"
52#include "chrome/browser/prerender/prerender_manager_factory.h"
53#include "chrome/browser/prerender/prerender_message_filter.h"
54#include "chrome/browser/prerender/prerender_tracker.h"
55#include "chrome/browser/printing/printing_message_filter.h"
56#include "chrome/browser/profiles/profile.h"
57#include "chrome/browser/profiles/profile_io_data.h"
58#include "chrome/browser/profiles/profile_manager.h"
59#include "chrome/browser/renderer_host/chrome_render_message_filter.h"
60#include "chrome/browser/renderer_host/chrome_render_view_host_observer.h"
61#include "chrome/browser/renderer_host/pepper/chrome_browser_pepper_host_factory.h"
62#include "chrome/browser/renderer_host/plugin_info_message_filter.h"
63#include "chrome/browser/search_engines/search_provider_install_state_message_filter.h"
64#include "chrome/browser/speech/chrome_speech_recognition_manager_delegate.h"
65#include "chrome/browser/spellchecker/spellcheck_message_filter.h"
66#include "chrome/browser/ssl/ssl_add_cert_handler.h"
67#include "chrome/browser/ssl/ssl_blocking_page.h"
68#include "chrome/browser/ssl/ssl_tab_helper.h"
69#include "chrome/browser/tab_contents/tab_util.h"
70#include "chrome/browser/toolkit_extra_parts.h"
71#include "chrome/browser/ui/tab_contents/chrome_web_contents_view_delegate.h"
72#include "chrome/browser/ui/tab_contents/tab_contents.h"
73#include "chrome/browser/ui/webui/chrome_web_ui_controller_factory.h"
74#include "chrome/browser/user_style_sheet_watcher.h"
75#include "chrome/browser/user_style_sheet_watcher_factory.h"
76#include "chrome/browser/view_type_utils.h"
77#include "chrome/common/child_process_logging.h"
78#include "chrome/common/chrome_constants.h"
79#include "chrome/common/chrome_paths.h"
80#include "chrome/common/chrome_switches.h"
81#include "chrome/common/extensions/extension.h"
82#include "chrome/common/extensions/extension_process_policy.h"
83#include "chrome/common/extensions/extension_set.h"
84#include "chrome/common/extensions/permissions/socket_permission.h"
85#include "chrome/common/logging_chrome.h"
86#include "chrome/common/pref_names.h"
87#include "chrome/common/render_messages.h"
88#include "chrome/common/url_constants.h"
89#include "content/public/browser/browser_child_process_host.h"
90#include "content/public/browser/browser_main_parts.h"
91#include "content/public/browser/browser_ppapi_host.h"
92#include "content/public/browser/browser_url_handler.h"
93#include "content/public/browser/child_process_data.h"
94#include "content/public/browser/child_process_security_policy.h"
95#include "content/public/browser/compositor_util.h"
96#include "content/public/browser/render_process_host.h"
97#include "content/public/browser/render_view_host.h"
98#include "content/public/browser/resource_context.h"
99#include "content/public/browser/site_instance.h"
100#include "content/public/browser/web_contents.h"
101#include "content/public/browser/web_contents_view.h"
102#include "content/public/common/child_process_host.h"
103#include "content/public/common/content_descriptors.h"
104#include "grit/generated_resources.h"
105#include "grit/ui_resources.h"
106#include "net/base/escape.h"
107#include "net/base/ssl_cert_request_info.h"
108#include "net/cookies/canonical_cookie.h"
109#include "net/cookies/cookie_options.h"
110#include "ppapi/host/ppapi_host.h"
111#include "ui/base/l10n/l10n_util.h"
112#include "ui/base/resource/resource_bundle.h"
113#include "webkit/glue/webpreferences.h"
114#include "webkit/plugins/plugin_switches.h"
115
116#if defined(OS_WIN)
117#include "chrome/browser/chrome_browser_main_win.h"
118#elif defined(OS_MACOSX)
119#include "chrome/browser/chrome_browser_main_mac.h"
120#include "chrome/browser/spellchecker/spellcheck_message_filter_mac.h"
121#elif defined(OS_CHROMEOS)
122#include "chrome/browser/chromeos/chrome_browser_main_chromeos.h"
123#include "chrome/browser/chromeos/login/user_manager.h"
124#elif defined(OS_LINUX)
125#include "chrome/browser/chrome_browser_main_linux.h"
126#elif defined(OS_ANDROID)
127#include "chrome/browser/android/crash_dump_manager.h"
128#include "chrome/browser/chrome_browser_main_android.h"
129#include "chrome/common/descriptors_android.h"
130#elif defined(OS_POSIX)
131#include "chrome/browser/chrome_browser_main_posix.h"
132#endif
133
134#if defined(OS_LINUX) || defined(OS_OPENBSD) || defined(OS_ANDROID)
135#include "base/linux_util.h"
136#include "chrome/browser/crash_handler_host_linux.h"
137#endif
138
139#if defined(ENABLE_CAPTIVE_PORTAL_DETECTION)
140#include "chrome/browser/captive_portal/captive_portal_tab_helper.h"
141#endif
142
143#if defined(OS_ANDROID)
144#include "ui/base/ui_base_paths.h"
145#endif
146
147#if defined(USE_NSS)
148#include "chrome/browser/ui/crypto_module_password_dialog.h"
149#endif
150
151using base::FileDescriptor;
152using content::AccessTokenStore;
153using content::BrowserChildProcessHostIterator;
154using content::BrowserThread;
155using content::BrowserURLHandler;
156using content::ChildProcessSecurityPolicy;
157using content::FileDescriptorInfo;
158using content::QuotaPermissionContext;
159using content::RenderViewHost;
160using content::SiteInstance;
161using content::WebContents;
162using extensions::APIPermission;
163using extensions::Extension;
164using webkit_glue::WebPreferences;
165
166namespace {
167
168const char* kPredefinedAllowedSocketOrigins[] = {
169  "okddffdblfhhnmhodogpojmfkjmhinfp",  // Test SSH Client
170  "pnhechapfaindjhompbnflcldabbghjo",  // HTerm App (SSH Client)
171  "bglhmjfplikpjnfoegeomebmfnkjomhe",  // see crbug.com/122126
172  "gbchcmhmhahfdphkhkmpfmihenigjmpp",  // Chrome Remote Desktop
173  "kgngmbheleoaphbjbaiobfdepmghbfah",  // Pre-release Chrome Remote Desktop
174  "odkaodonbgfohohmklejpjiejmcipmib",  // Dogfood Chrome Remote Desktop
175  "ojoimpklfciegopdfgeenehpalipignm",  // Chromoting canary
176  "cbkkbcmdlboombapidmoeolnmdacpkch",  // see crbug.com/129089
177  "hhnbmknkdabfoieppbbljkhkfjcmcbjh",  // see crbug.com/134099
178  "mablfbjkhmhkmefkjjacnbaikjkipphg",  // see crbug.com/134099
179  "pdeelgamlgannhelgoegilelnnojegoh",  // see crbug.com/134099
180  "cabapfdbkniadpollkckdnedaanlciaj",  // see crbug.com/134099
181  "mapljbgnjledlpdmlchihnmeclmefbba",  // see crbug.com/134099
182  "ghbfeebgmiidnnmeobbbaiamklmpbpii",  // see crbug.com/134099
183  "jdfhpkjeckflbbleddjlpimecpbjdeep"   // see crbug.com/142514
184};
185
186// Returns a copy of the given url with its host set to given host and path set
187// to given path. Other parts of the url will be the same.
188GURL ReplaceURLHostAndPath(const GURL& url,
189                           const std::string& host,
190                           const std::string& path) {
191  url_canon::Replacements<char> replacements;
192  replacements.SetHost(host.c_str(),
193                       url_parse::Component(0, host.length()));
194  replacements.SetPath(path.c_str(),
195                       url_parse::Component(0, path.length()));
196  return url.ReplaceComponents(replacements);
197}
198
199// Maps "foo://bar/baz/" to "foo://chrome/bar/baz/".
200GURL AddUberHost(const GURL& url) {
201  const std::string uber_host = chrome::kChromeUIUberHost;
202  const std::string new_path = url.host() + url.path();
203
204  return ReplaceURLHostAndPath(url, uber_host, new_path);
205}
206
207// If url->host() is "chrome" and url->path() has characters other than the
208// first slash, changes the url from "foo://chrome/bar/" to "foo://bar/" and
209// returns true. Otherwise returns false.
210bool RemoveUberHost(GURL* url) {
211  if (url->host() != chrome::kChromeUIUberHost)
212    return false;
213
214  if (url->path().empty() || url->path() == "/")
215    return false;
216
217  const std::string old_path = url->path();
218
219  const std::string::size_type separator = old_path.find('/', 1);
220  std::string new_host;
221  std::string new_path;
222  if (separator == std::string::npos) {
223    new_host = old_path.substr(1);
224  } else {
225    new_host = old_path.substr(1, separator - 1);
226    new_path = old_path.substr(separator);
227  }
228
229  *url = ReplaceURLHostAndPath(*url, new_host, new_path);
230
231  return true;
232}
233
234// Handles rewriting Web UI URLs.
235bool HandleWebUI(GURL* url, content::BrowserContext* browser_context) {
236  // Do not handle special URLs such as "about:foo"
237  if (!url->host().empty()) {
238    const GURL chrome_url = AddUberHost(*url);
239
240    // Handle valid "chrome://chrome/foo" URLs so the reverse handler will
241    // be called.
242    if (ChromeWebUIControllerFactory::GetInstance()->UseWebUIForURL(
243            browser_context, chrome_url))
244      return true;
245  }
246
247  if (!ChromeWebUIControllerFactory::GetInstance()->UseWebUIForURL(
248          browser_context, *url))
249    return false;
250
251#if defined(OS_CHROMEOS)
252  // Special case : in ChromeOS in Guest mode bookmarks and history are
253  // disabled for security reasons. New tab page explains the reasons, so
254  // we redirect user to new tab page.
255  if (chromeos::UserManager::Get()->IsLoggedInAsGuest()) {
256    if (url->SchemeIs(chrome::kChromeUIScheme) &&
257        (url->DomainIs(chrome::kChromeUIBookmarksHost) ||
258         url->DomainIs(chrome::kChromeUIHistoryHost))) {
259      // Rewrite with new tab URL
260      *url = GURL(chrome::kChromeUINewTabURL);
261    }
262  }
263#endif
264
265  // Special case the new tab page. In older versions of Chrome, the new tab
266  // page was hosted at chrome-internal:<blah>. This might be in people's saved
267  // sessions or bookmarks, so we say any URL with that scheme triggers the new
268  // tab page.
269  if (url->SchemeIs(chrome::kChromeInternalScheme)) {
270    // Rewrite it with the proper new tab URL.
271    *url = GURL(chrome::kChromeUINewTabURL);
272  }
273
274  return true;
275}
276
277// Reverse URL handler for Web UI. Maps "chrome://chrome/foo/" to
278// "chrome://foo/".
279bool HandleWebUIReverse(GURL* url, content::BrowserContext* browser_context) {
280  if (!url->is_valid() || !url->SchemeIs(chrome::kChromeUIScheme))
281    return false;
282
283  return RemoveUberHost(url);
284}
285
286// Used by the GetPrivilegeRequiredByUrl() and GetProcessPrivilege() functions
287// below.  Extension, and isolated apps require different privileges to be
288// granted to their RenderProcessHosts.  This classification allows us to make
289// sure URLs are served by hosts with the right set of privileges.
290enum RenderProcessHostPrivilege {
291  PRIV_NORMAL,
292  PRIV_HOSTED,
293  PRIV_ISOLATED,
294  PRIV_EXTENSION,
295};
296
297RenderProcessHostPrivilege GetPrivilegeRequiredByUrl(
298    const GURL& url,
299    ExtensionService* service) {
300  // Default to a normal renderer cause it is lower privileged. This should only
301  // occur if the URL on a site instance is either malformed, or uninitialized.
302  // If it is malformed, then there is no need for better privileges anyways.
303  // If it is uninitialized, but eventually settles on being an a scheme other
304  // than normal webrenderer, the navigation logic will correct us out of band
305  // anyways.
306  if (!url.is_valid())
307    return PRIV_NORMAL;
308
309  if (url.SchemeIs(chrome::kExtensionScheme)) {
310    const Extension* extension =
311        service->extensions()->GetByID(url.host());
312    if (extension && extension->is_storage_isolated())
313      return PRIV_ISOLATED;
314    if (extension && extension->is_hosted_app())
315      return PRIV_HOSTED;
316
317    return PRIV_EXTENSION;
318  }
319
320  return PRIV_NORMAL;
321}
322
323RenderProcessHostPrivilege GetProcessPrivilege(
324    content::RenderProcessHost* process_host,
325    extensions::ProcessMap* process_map,
326    ExtensionService* service) {
327  std::set<std::string> extension_ids =
328      process_map->GetExtensionsInProcess(process_host->GetID());
329  if (extension_ids.empty())
330    return PRIV_NORMAL;
331
332  for (std::set<std::string>::iterator iter = extension_ids.begin();
333       iter != extension_ids.end(); ++iter) {
334    const Extension* extension = service->GetExtensionById(*iter, false);
335    if (extension && extension->is_storage_isolated())
336      return PRIV_ISOLATED;
337    if (extension && extension->is_hosted_app())
338      return PRIV_HOSTED;
339  }
340
341  return PRIV_EXTENSION;
342}
343
344bool CertMatchesFilter(const net::X509Certificate& cert,
345                       const base::DictionaryValue& filter) {
346  // TODO(markusheintz): This is the minimal required filter implementation.
347  // Implement a better matcher.
348
349  // An empty filter matches any client certificate since no requirements are
350  // specified at all.
351  if (filter.empty())
352    return true;
353
354  std::string common_name;
355  if (filter.GetString("ISSUER.CN", &common_name) &&
356      (cert.issuer().common_name == common_name)) {
357    return true;
358  }
359  return false;
360}
361
362// Fills |map| with the per-script font prefs under path |map_name|.
363void FillFontFamilyMap(const PrefService* prefs,
364                       const char* map_name,
365                       WebPreferences::ScriptFontFamilyMap* map) {
366  for (size_t i = 0; i < prefs::kWebKitScriptsForFontFamilyMapsLength; ++i) {
367    const char* script = prefs::kWebKitScriptsForFontFamilyMaps[i];
368    std::string pref_name = base::StringPrintf("%s.%s", map_name, script);
369    std::string font_family = prefs->GetString(pref_name.c_str());
370    if (!font_family.empty())
371      (*map)[script] = UTF8ToUTF16(font_family);
372  }
373}
374
375#if defined(OS_POSIX) && !defined(OS_MACOSX)
376int GetCrashSignalFD(const CommandLine& command_line) {
377  if (command_line.HasSwitch(switches::kExtensionProcess)) {
378    ExtensionCrashHandlerHostLinux* crash_handler =
379        ExtensionCrashHandlerHostLinux::GetInstance();
380    return crash_handler->GetDeathSignalSocket();
381  }
382
383  std::string process_type =
384      command_line.GetSwitchValueASCII(switches::kProcessType);
385
386  if (process_type == switches::kRendererProcess)
387    return RendererCrashHandlerHostLinux::GetInstance()->GetDeathSignalSocket();
388
389  if (process_type == switches::kPluginProcess)
390    return PluginCrashHandlerHostLinux::GetInstance()->GetDeathSignalSocket();
391
392  if (process_type == switches::kPpapiPluginProcess)
393    return PpapiCrashHandlerHostLinux::GetInstance()->GetDeathSignalSocket();
394
395  if (process_type == switches::kGpuProcess)
396    return GpuCrashHandlerHostLinux::GetInstance()->GetDeathSignalSocket();
397
398  return -1;
399}
400#endif  // defined(OS_POSIX) && !defined(OS_MACOSX)
401
402}  // namespace
403
404namespace chrome {
405
406ChromeContentBrowserClient::ChromeContentBrowserClient() {
407  for (size_t i = 0; i < arraysize(kPredefinedAllowedSocketOrigins); ++i)
408    allowed_socket_origins_.insert(kPredefinedAllowedSocketOrigins[i]);
409}
410
411ChromeContentBrowserClient::~ChromeContentBrowserClient() {
412}
413
414// static
415void ChromeContentBrowserClient::RegisterUserPrefs(PrefService* prefs) {
416  prefs->RegisterBooleanPref(prefs::kDisable3DAPIs,
417                             false,
418                             PrefService::UNSYNCABLE_PREF);
419  prefs->RegisterBooleanPref(prefs::kEnableHyperlinkAuditing,
420                             true,
421                             PrefService::UNSYNCABLE_PREF);
422  prefs->RegisterBooleanPref(prefs::kEnableMemoryInfo,
423                             false,
424                             PrefService::UNSYNCABLE_PREF);
425}
426
427content::BrowserMainParts* ChromeContentBrowserClient::CreateBrowserMainParts(
428    const content::MainFunctionParams& parameters) {
429  ChromeBrowserMainParts* main_parts;
430  // Construct the Main browser parts based on the OS type.
431#if defined(OS_WIN)
432  main_parts = new ChromeBrowserMainPartsWin(parameters);
433#elif defined(OS_MACOSX)
434  main_parts = new ChromeBrowserMainPartsMac(parameters);
435#elif defined(OS_CHROMEOS)
436  main_parts = new ChromeBrowserMainPartsChromeos(parameters);
437#elif defined(OS_LINUX)
438  main_parts = new ChromeBrowserMainPartsLinux(parameters);
439#elif defined(OS_ANDROID)
440  main_parts = new ChromeBrowserMainPartsAndroid(parameters);
441#elif defined(OS_POSIX)
442  main_parts = new ChromeBrowserMainPartsPosix(parameters);
443#else
444  NOTREACHED();
445  main_parts = new ChromeBrowserMainParts(parameters);
446#endif
447
448  // Construct additional browser parts. Stages are called in the order in
449  // which they are added.
450#if defined(TOOLKIT_GTK)
451  chrome::AddGtkToolkitExtraParts(main_parts);
452#endif
453
454#if defined(TOOLKIT_VIEWS)
455  chrome::AddViewsToolkitExtraParts(main_parts);
456#endif
457
458#if defined(USE_ASH)
459  chrome::AddAshToolkitExtraParts(main_parts);
460#endif
461
462#if defined(USE_AURA)
463  chrome::AddAuraToolkitExtraParts(main_parts);
464#endif
465
466  return main_parts;
467}
468
469content::WebContentsView*
470    ChromeContentBrowserClient::OverrideCreateWebContentsView(
471        WebContents* web_contents,
472        content::RenderViewHostDelegateView** render_view_host_delegate_view) {
473  return NULL;
474}
475
476std::string ChromeContentBrowserClient::GetStoragePartitionIdForSite(
477    content::BrowserContext* browser_context,
478    const GURL& site) {
479  std::string partition_id;
480
481  // The partition ID for webview guest processes is the string value of its
482  // SiteInstance URL - "chrome-guest://app_id/persist?partition".
483  if (site.SchemeIs(chrome::kGuestScheme))
484    partition_id = site.spec();
485
486  DCHECK(IsValidStoragePartitionId(browser_context,partition_id));
487  return partition_id;
488}
489
490bool ChromeContentBrowserClient::IsValidStoragePartitionId(
491    content::BrowserContext* browser_context,
492    const std::string& partition_id) {
493  // The default ID is empty and is always valid.
494  if (partition_id.empty())
495    return true;
496
497  return GURL(partition_id).is_valid();
498}
499
500void ChromeContentBrowserClient::GetStoragePartitionConfigForSite(
501    content::BrowserContext* browser_context,
502    const GURL& site,
503    std::string* partition_domain,
504    std::string* partition_name,
505    bool* in_memory) {
506  // For the webview tag, we create special guest processes, which host the
507  // tag content separately from the main application that embeds the tag.
508  // A webview tag can specify both the partition name and whether the storage
509  // for that partition should be persisted. Each tag gets a SiteInstance with
510  // a specially formatted URL, based on the application it is hosted by and
511  // the partition requested by it. The format for that URL is:
512  // chrome-guest://partition_domain/persist?partition_name
513  if (site.SchemeIs(chrome::kGuestScheme)) {
514    // Since guest URLs are only used for packaged apps, there must be an app
515    // id in the URL.
516    CHECK(site.has_host());
517    *partition_domain = site.host();
518    // Since persistence is optional, the path must either be empty or the
519    // literal string.
520    *in_memory = (site.path() != "/persist");
521    // The partition name is user supplied value, which we have encoded when the
522    // URL was created, so it needs to be decoded.
523    *partition_name = net::UnescapeURLComponent(site.query(),
524                                                net::UnescapeRule::NORMAL);
525    return;
526  }
527
528  const Extension* extension = NULL;
529  Profile* profile = Profile::FromBrowserContext(browser_context);
530  ExtensionService* extension_service =
531      extensions::ExtensionSystem::Get(profile)->extension_service();
532  if (extension_service) {
533    extension = extension_service->extensions()->
534        GetExtensionOrAppByURL(ExtensionURLInfo(site));
535    if (extension && extension->is_storage_isolated()) {
536      // Extensions which have storage isolation enabled (e.g., apps), use
537      // the extension id as the |partition_domain|.
538      *partition_domain = extension->id();
539      partition_name->clear();
540      *in_memory = false;
541      return;
542    }
543  }
544
545  // All other cases use the default, browser-wide, storage partition.
546  partition_domain->clear();
547  partition_name->clear();
548  *in_memory = false;
549}
550
551content::WebContentsViewDelegate*
552    ChromeContentBrowserClient::GetWebContentsViewDelegate(
553        content::WebContents* web_contents) {
554  return chrome::CreateWebContentsViewDelegate(web_contents);
555}
556
557void ChromeContentBrowserClient::RenderViewHostCreated(
558    RenderViewHost* render_view_host) {
559
560  SiteInstance* site_instance = render_view_host->GetSiteInstance();
561  Profile* profile = Profile::FromBrowserContext(
562      site_instance->GetBrowserContext());
563
564  new ChromeRenderViewHostObserver(render_view_host,
565                                   profile->GetNetworkPredictor());
566  new extensions::MessageHandler(render_view_host);
567}
568
569void ChromeContentBrowserClient::RenderProcessHostCreated(
570    content::RenderProcessHost* host) {
571  int id = host->GetID();
572  Profile* profile = Profile::FromBrowserContext(host->GetBrowserContext());
573  host->GetChannel()->AddFilter(new ChromeRenderMessageFilter(
574      id, profile, profile->GetRequestContextForRenderProcess(id)));
575  host->GetChannel()->AddFilter(new PluginInfoMessageFilter(id, profile));
576#if defined(ENABLE_PRINTING)
577  host->GetChannel()->AddFilter(new PrintingMessageFilter(id, profile));
578#endif
579  host->GetChannel()->AddFilter(
580      new SearchProviderInstallStateMessageFilter(id, profile));
581  host->GetChannel()->AddFilter(new SpellCheckMessageFilter(id));
582#if defined(OS_MACOSX)
583  host->GetChannel()->AddFilter(new SpellCheckMessageFilterMac());
584#endif
585  host->GetChannel()->AddFilter(new ChromeBenchmarkingMessageFilter(
586      id, profile, profile->GetRequestContextForRenderProcess(id)));
587  host->GetChannel()->AddFilter(
588      new prerender::PrerenderMessageFilter(id, profile));
589
590  host->Send(new ChromeViewMsg_SetIsIncognitoProcess(
591      profile->IsOffTheRecord()));
592
593  SendExtensionWebRequestStatusToHost(host);
594
595  RendererContentSettingRules rules;
596  GetRendererContentSettingRules(profile->GetHostContentSettingsMap(), &rules);
597  host->Send(new ChromeViewMsg_SetContentSettingRules(rules));
598
599#if defined(OS_ANDROID) && defined(USE_LINUX_BREAKPAD)
600  InitCrashDumpManager();
601#endif
602}
603
604void ChromeContentBrowserClient::BrowserChildProcessHostCreated(
605    content::BrowserChildProcessHost* host) {
606  host->GetHost()->AddFilter(new PepperGtalkMessageFilter());
607}
608
609content::WebUIControllerFactory*
610    ChromeContentBrowserClient::GetWebUIControllerFactory() {
611  return ChromeWebUIControllerFactory::GetInstance();
612}
613
614GURL ChromeContentBrowserClient::GetEffectiveURL(
615    content::BrowserContext* browser_context, const GURL& url) {
616  Profile* profile = Profile::FromBrowserContext(browser_context);
617  // Get the effective URL for the given actual URL. If the URL is part of an
618  // installed app, the effective URL is an extension URL with the ID of that
619  // extension as the host. This has the effect of grouping apps together in
620  // a common SiteInstance.
621  if (!profile || !profile->GetExtensionService())
622    return url;
623
624  const Extension* extension = profile->GetExtensionService()->extensions()->
625      GetHostedAppByURL(ExtensionURLInfo(url));
626  if (!extension)
627    return url;
628
629  // Bookmark apps do not use the hosted app process model, and should be
630  // treated as normal URLs.
631  if (extension->from_bookmark())
632    return url;
633
634  // If the URL is part of an extension's web extent, convert it to an
635  // extension URL.
636  return extension->GetResourceURL(url.path());
637}
638
639bool ChromeContentBrowserClient::ShouldUseProcessPerSite(
640    content::BrowserContext* browser_context, const GURL& effective_url) {
641  // Non-extension URLs should generally use process-per-site-instance.
642  // Because we expect to use the effective URL, URLs for hosted apps (apart
643  // from bookmark apps) should have an extension scheme by now.
644  if (!effective_url.SchemeIs(chrome::kExtensionScheme))
645    return false;
646
647  Profile* profile = Profile::FromBrowserContext(browser_context);
648  if (!profile || !profile->GetExtensionService())
649    return false;
650
651  const Extension* extension = profile->GetExtensionService()->extensions()->
652      GetExtensionOrAppByURL(ExtensionURLInfo(effective_url));
653  if (!extension)
654    return false;
655
656  // If the URL is part of a hosted app that does not have the background
657  // permission, or that does not allow JavaScript access to the background
658  // page, we want to give each instance its own process to improve
659  // responsiveness.
660  if (extension->GetType() == Extension::TYPE_HOSTED_APP) {
661    if (!extension->HasAPIPermission(APIPermission::kBackground) ||
662        !extension->allow_background_js_access()) {
663      return false;
664    }
665  }
666
667  // Hosted apps that have script access to their background page must use
668  // process per site, since all instances can make synchronous calls to the
669  // background window.  Other extensions should use process per site as well.
670  return true;
671}
672
673bool ChromeContentBrowserClient::IsHandledURL(const GURL& url) {
674  return ProfileIOData::IsHandledURL(url);
675}
676
677bool ChromeContentBrowserClient::IsSuitableHost(
678    content::RenderProcessHost* process_host,
679    const GURL& site_url) {
680  Profile* profile =
681      Profile::FromBrowserContext(process_host->GetBrowserContext());
682  ExtensionService* service = profile->GetExtensionService();
683  extensions::ProcessMap* process_map = service->process_map();
684
685  // Don't allow the Task Manager to share a process with anything else.
686  // Otherwise it can affect the renderers it is observing.
687  // Note: we could create another RenderProcessHostPrivilege bucket for
688  // this to allow multiple chrome://tasks instances to share, but that's
689  // a very unlikely case without serious consequences.
690  if (site_url.GetOrigin() == GURL(chrome::kChromeUITaskManagerURL).GetOrigin())
691    return false;
692
693  // These may be NULL during tests. In that case, just assume any site can
694  // share any host.
695  if (!service || !process_map)
696    return true;
697
698  // Experimental:
699  // If --enable-strict-site-isolation is enabled, do not allow non-WebUI pages
700  // to share a renderer process.  (We could allow pages from the same site or
701  // extensions of the same type to share, if we knew what the given process
702  // was dedicated to.  Allowing no sharing is simpler for now.)  This may
703  // cause resource exhaustion issues if too many sites are open at once.
704  const CommandLine& command_line = *CommandLine::ForCurrentProcess();
705  if (command_line.HasSwitch(switches::kEnableStrictSiteIsolation))
706    return false;
707
708  // Otherwise, just make sure the process privilege matches the privilege
709  // required by the site.
710  RenderProcessHostPrivilege privilege_required =
711      GetPrivilegeRequiredByUrl(site_url, service);
712  return GetProcessPrivilege(process_host, process_map, service) ==
713      privilege_required;
714}
715
716// This function is trying to limit the amount of processes used by extensions
717// with background pages. It uses a globally set percentage of processes to
718// run such extensions and if the limit is exceeded, it returns true, to
719// indicate to the content module to group extensions together.
720bool ChromeContentBrowserClient::ShouldTryToUseExistingProcessHost(
721    content::BrowserContext* browser_context, const GURL& url) {
722  // It has to be a valid URL for us to check for an extension.
723  if (!url.is_valid())
724    return false;
725
726  Profile* profile = Profile::FromBrowserContext(browser_context);
727  ExtensionService* service = profile->GetExtensionService();
728  if (!service)
729    return false;
730
731  // We have to have a valid extension with background page to proceed.
732  const Extension* extension =
733      service->extensions()->GetExtensionOrAppByURL(ExtensionURLInfo(url));
734  if (!extension)
735    return false;
736  if (!extension->has_background_page())
737    return false;
738
739  std::set<int> process_ids;
740  size_t max_process_count =
741      content::RenderProcessHost::GetMaxRendererProcessCount();
742
743  // Go through all profiles to ensure we have total count of extension
744  // processes containing background pages, otherwise one profile can
745  // starve the other.
746  std::vector<Profile*> profiles = g_browser_process->profile_manager()->
747      GetLoadedProfiles();
748  for (size_t i = 0; i < profiles.size(); ++i) {
749    ExtensionProcessManager* epm =
750        extensions::ExtensionSystem::Get(profiles[i])->process_manager();
751    for (ExtensionProcessManager::const_iterator iter =
752             epm->background_hosts().begin();
753         iter != epm->background_hosts().end(); ++iter) {
754      const extensions::ExtensionHost* host = *iter;
755      process_ids.insert(host->render_process_host()->GetID());
756    }
757  }
758
759  if (process_ids.size() >
760      (max_process_count * chrome::kMaxShareOfExtensionProcesses)) {
761    return true;
762  }
763
764  return false;
765}
766
767void ChromeContentBrowserClient::SiteInstanceGotProcess(
768    SiteInstance* site_instance) {
769  CHECK(site_instance->HasProcess());
770
771  Profile* profile = Profile::FromBrowserContext(
772      site_instance->GetBrowserContext());
773  ExtensionService* service = profile->GetExtensionService();
774  if (!service)
775    return;
776
777  const Extension* extension =
778      service->extensions()->GetExtensionOrAppByURL(ExtensionURLInfo(
779          site_instance->GetSiteURL()));
780  if (!extension)
781    return;
782
783  service->process_map()->Insert(extension->id(),
784                                 site_instance->GetProcess()->GetID(),
785                                 site_instance->GetId());
786  BrowserThread::PostTask(
787      BrowserThread::IO, FROM_HERE,
788      base::Bind(&ExtensionInfoMap::RegisterExtensionProcess,
789                 extensions::ExtensionSystem::Get(profile)->info_map(),
790                 extension->id(),
791                 site_instance->GetProcess()->GetID(),
792                 site_instance->GetId()));
793}
794
795void ChromeContentBrowserClient::SiteInstanceDeleting(
796    SiteInstance* site_instance) {
797  if (!site_instance->HasProcess())
798    return;
799
800  Profile* profile = Profile::FromBrowserContext(
801      site_instance->GetBrowserContext());
802  ExtensionService* service = profile->GetExtensionService();
803  if (!service)
804    return;
805
806  const Extension* extension =
807      service->extensions()->GetExtensionOrAppByURL(
808          ExtensionURLInfo(site_instance->GetSiteURL()));
809  if (!extension)
810    return;
811
812  service->process_map()->Remove(extension->id(),
813                                 site_instance->GetProcess()->GetID(),
814                                 site_instance->GetId());
815  BrowserThread::PostTask(
816      BrowserThread::IO, FROM_HERE,
817      base::Bind(&ExtensionInfoMap::UnregisterExtensionProcess,
818                 extensions::ExtensionSystem::Get(profile)->info_map(),
819                 extension->id(),
820                 site_instance->GetProcess()->GetID(),
821                 site_instance->GetId()));
822}
823
824bool ChromeContentBrowserClient::ShouldSwapProcessesForNavigation(
825    const GURL& current_url,
826    const GURL& new_url) {
827  if (current_url.is_empty()) {
828    // Always choose a new process when navigating to extension URLs. The
829    // process grouping logic will combine all of a given extension's pages
830    // into the same process.
831    if (new_url.SchemeIs(chrome::kExtensionScheme))
832      return true;
833
834    return false;
835  }
836
837  // Also, we must switch if one is an extension and the other is not the exact
838  // same extension.
839  if (current_url.SchemeIs(chrome::kExtensionScheme) ||
840      new_url.SchemeIs(chrome::kExtensionScheme)) {
841    if (current_url.GetOrigin() != new_url.GetOrigin())
842      return true;
843  }
844
845  return false;
846}
847
848bool ChromeContentBrowserClient::ShouldSwapProcessesForRedirect(
849    content::ResourceContext* resource_context, const GURL& current_url,
850    const GURL& new_url) {
851  ProfileIOData* io_data = ProfileIOData::FromResourceContext(resource_context);
852  return extensions::CrossesExtensionProcessBoundary(
853      io_data->GetExtensionInfoMap()->extensions(),
854      ExtensionURLInfo(current_url), ExtensionURLInfo(new_url), false);
855}
856
857std::string ChromeContentBrowserClient::GetCanonicalEncodingNameByAliasName(
858    const std::string& alias_name) {
859  return CharacterEncoding::GetCanonicalEncodingNameByAliasName(alias_name);
860}
861
862void ChromeContentBrowserClient::AppendExtraCommandLineSwitches(
863    CommandLine* command_line, int child_process_id) {
864#if defined(USE_LINUX_BREAKPAD)
865  if (IsCrashReporterEnabled()) {
866    command_line->AppendSwitchASCII(switches::kEnableCrashReporter,
867        child_process_logging::GetClientId() + "," + base::GetLinuxDistro());
868  }
869#elif defined(OS_MACOSX)
870  if (IsCrashReporterEnabled()) {
871    command_line->AppendSwitchASCII(switches::kEnableCrashReporter,
872                                    child_process_logging::GetClientId());
873  }
874#endif  // OS_MACOSX
875
876  if (logging::DialogsAreSuppressed())
877    command_line->AppendSwitch(switches::kNoErrorDialogs);
878
879  std::string process_type =
880      command_line->GetSwitchValueASCII(switches::kProcessType);
881  const CommandLine& browser_command_line = *CommandLine::ForCurrentProcess();
882  if (process_type == switches::kRendererProcess) {
883    FilePath user_data_dir =
884        browser_command_line.GetSwitchValuePath(switches::kUserDataDir);
885    if (!user_data_dir.empty())
886      command_line->AppendSwitchPath(switches::kUserDataDir, user_data_dir);
887#if defined(OS_CHROMEOS)
888    const std::string& login_profile =
889        browser_command_line.GetSwitchValueASCII(switches::kLoginProfile);
890    if (!login_profile.empty())
891      command_line->AppendSwitchASCII(switches::kLoginProfile, login_profile);
892#endif
893
894    content::RenderProcessHost* process =
895        content::RenderProcessHost::FromID(child_process_id);
896    if (process) {
897      Profile* profile = Profile::FromBrowserContext(
898          process->GetBrowserContext());
899      if (profile->GetExtensionService()) {
900        extensions::ProcessMap* process_map =
901            profile->GetExtensionService()->process_map();
902        if (process_map && process_map->Contains(process->GetID()))
903          command_line->AppendSwitch(switches::kExtensionProcess);
904      }
905
906      PrefService* prefs = profile->GetPrefs();
907      // Currently this pref is only registered if applied via a policy.
908      if (prefs->HasPrefPath(prefs::kDisable3DAPIs) &&
909          prefs->GetBoolean(prefs::kDisable3DAPIs)) {
910        // Turn this policy into a command line switch.
911        command_line->AppendSwitch(switches::kDisable3DAPIs);
912      }
913
914      // Disable client-side phishing detection in the renderer if it is
915      // disabled in the Profile preferences or the browser process.
916      if (!prefs->GetBoolean(prefs::kSafeBrowsingEnabled) ||
917          !g_browser_process->safe_browsing_detection_service()) {
918        command_line->AppendSwitch(
919            switches::kDisableClientSidePhishingDetection);
920      }
921
922      if (!prefs->GetBoolean(prefs::kPrintPreviewDisabled))
923        command_line->AppendSwitch(switches::kRendererPrintPreview);
924    }
925
926    if (content::IsThreadedCompositingEnabled())
927      command_line->AppendSwitch(switches::kEnableThreadedCompositing);
928
929    // Please keep this in alphabetical order.
930    static const char* const kSwitchNames[] = {
931      switches::kAllowHTTPBackgroundPage,
932      switches::kAllowLegacyExtensionManifests,
933      switches::kAllowScriptingGallery,
934      switches::kAppsCheckoutURL,
935      switches::kAppsGalleryURL,
936      switches::kCloudPrintServiceURL,
937      switches::kDebugPrint,
938      switches::kDisableBundledPpapiFlash,
939      switches::kDisableExtensionsResourceWhitelist,
940      switches::kDisableScriptedPrintThrottling,
941      switches::kDumpHistogramsOnExit,
942      switches::kEnableBenchmarking,
943      switches::kEnableBundledPpapiFlash,
944      switches::kEnableChromeStyleDialogs,
945      switches::kEnableCrxlessWebApps,
946      switches::kEnableExperimentalExtensionApis,
947      switches::kEnableIPCFuzzing,
948      switches::kEnableInteractiveAutocomplete,
949      switches::kEnableNaCl,
950      switches::kEnableNaClSRPCProxy,
951      switches::kEnablePasswordGeneration,
952      switches::kEnablePnacl,
953      switches::kEnableWatchdog,
954      switches::kMemoryProfiling,
955      switches::kMessageLoopHistogrammer,
956      switches::kNoJsRandomness,
957      switches::kPerformCrashAnalysis,
958      switches::kPlaybackMode,
959      switches::kPpapiFlashArgs,
960      switches::kPpapiFlashInProcess,
961      switches::kPpapiFlashPath,
962      switches::kPpapiFlashVersion,
963      switches::kProfilingAtStart,
964      switches::kProfilingFile,
965      switches::kProfilingFlush,
966      switches::kRecordMode,
967      switches::kSilentDumpOnDCHECK,
968      switches::kSpdyProxyOrigin,
969      switches::kWhitelistedExtensionID,
970    };
971
972    command_line->CopySwitchesFrom(browser_command_line, kSwitchNames,
973                                   arraysize(kSwitchNames));
974  } else if (process_type == switches::kUtilityProcess) {
975    static const char* const kSwitchNames[] = {
976      switches::kAllowHTTPBackgroundPage,
977      switches::kEnableExperimentalExtensionApis,
978      switches::kWhitelistedExtensionID,
979    };
980
981    command_line->CopySwitchesFrom(browser_command_line, kSwitchNames,
982                                   arraysize(kSwitchNames));
983  } else if (process_type == switches::kPluginProcess) {
984    static const char* const kSwitchNames[] = {
985  #if defined(OS_CHROMEOS)
986      switches::kLoginProfile,
987  #endif
988      switches::kMemoryProfiling,
989      switches::kSilentDumpOnDCHECK,
990      switches::kUserDataDir,
991    };
992
993    command_line->CopySwitchesFrom(browser_command_line, kSwitchNames,
994                                   arraysize(kSwitchNames));
995  } else if (process_type == switches::kZygoteProcess) {
996    static const char* const kSwitchNames[] = {
997      switches::kUserDataDir,  // Make logs go to the right file.
998      // Load (in-process) Pepper plugins in-process in the zygote pre-sandbox.
999      switches::kDisableBundledPpapiFlash,
1000      switches::kEnableBundledPpapiFlash,
1001      switches::kPpapiFlashInProcess,
1002      switches::kPpapiFlashPath,
1003      switches::kPpapiFlashVersion,
1004    };
1005
1006    command_line->CopySwitchesFrom(browser_command_line, kSwitchNames,
1007                                   arraysize(kSwitchNames));
1008  } else if (process_type == switches::kGpuProcess) {
1009    // If --ignore-gpu-blacklist is passed in, don't send in crash reports
1010    // because GPU is expected to be unreliable.
1011    if (browser_command_line.HasSwitch(switches::kIgnoreGpuBlacklist) &&
1012        !command_line->HasSwitch(switches::kDisableBreakpad))
1013      command_line->AppendSwitch(switches::kDisableBreakpad);
1014  }
1015
1016  // The command line switch kEnableBenchmarking needs to be specified along
1017  // with the kEnableStatsTable switch to ensure that the stats table global
1018  // is initialized correctly.
1019  if (command_line->HasSwitch(switches::kEnableBenchmarking))
1020    DCHECK(command_line->HasSwitch(switches::kEnableStatsTable));
1021}
1022
1023std::string ChromeContentBrowserClient::GetApplicationLocale() {
1024  if (BrowserThread::CurrentlyOn(BrowserThread::IO))
1025    return io_thread_application_locale_;
1026  return g_browser_process->GetApplicationLocale();
1027}
1028
1029std::string ChromeContentBrowserClient::GetAcceptLangs(
1030    content::BrowserContext* context) {
1031  Profile* profile = Profile::FromBrowserContext(context);
1032  return profile->GetPrefs()->GetString(prefs::kAcceptLanguages);
1033}
1034
1035gfx::ImageSkia* ChromeContentBrowserClient::GetDefaultFavicon() {
1036  ResourceBundle& rb = ResourceBundle::GetSharedInstance();
1037  return rb.GetImageSkiaNamed(IDR_DEFAULT_FAVICON);
1038}
1039
1040bool ChromeContentBrowserClient::AllowAppCache(
1041    const GURL& manifest_url,
1042    const GURL& first_party,
1043    content::ResourceContext* context) {
1044  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
1045  ProfileIOData* io_data = ProfileIOData::FromResourceContext(context);
1046  return io_data->GetCookieSettings()->
1047      IsSettingCookieAllowed(manifest_url, first_party);
1048}
1049
1050bool ChromeContentBrowserClient::AllowGetCookie(
1051    const GURL& url,
1052    const GURL& first_party,
1053    const net::CookieList& cookie_list,
1054    content::ResourceContext* context,
1055    int render_process_id,
1056    int render_view_id) {
1057  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
1058  ProfileIOData* io_data = ProfileIOData::FromResourceContext(context);
1059  bool allow = io_data->GetCookieSettings()->
1060      IsReadingCookieAllowed(url, first_party);
1061
1062  BrowserThread::PostTask(
1063      BrowserThread::UI, FROM_HERE,
1064      base::Bind(&TabSpecificContentSettings::CookiesRead, render_process_id,
1065                 render_view_id, url, first_party, cookie_list, !allow));
1066  return allow;
1067}
1068
1069bool ChromeContentBrowserClient::AllowSetCookie(
1070    const GURL& url,
1071    const GURL& first_party,
1072    const std::string& cookie_line,
1073    content::ResourceContext* context,
1074    int render_process_id,
1075    int render_view_id,
1076    net::CookieOptions* options) {
1077  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
1078  ProfileIOData* io_data = ProfileIOData::FromResourceContext(context);
1079  CookieSettings* cookie_settings = io_data->GetCookieSettings();
1080  bool allow = cookie_settings->IsSettingCookieAllowed(url, first_party);
1081
1082  BrowserThread::PostTask(
1083      BrowserThread::UI, FROM_HERE,
1084      base::Bind(&TabSpecificContentSettings::CookieChanged, render_process_id,
1085                 render_view_id, url, first_party, cookie_line, *options,
1086                 !allow));
1087  return allow;
1088}
1089
1090bool ChromeContentBrowserClient::AllowPluginLocalDataAccess(
1091    const GURL& document_url,
1092    const GURL& plugin_url,
1093    content::ResourceContext* context) {
1094  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
1095  ProfileIOData* io_data = ProfileIOData::FromResourceContext(context);
1096  return io_data->GetCookieSettings()->IsReadingCookieAllowed(document_url,
1097                                                              plugin_url);
1098}
1099
1100bool ChromeContentBrowserClient::AllowPluginLocalDataSessionOnly(
1101    const GURL& url,
1102    content::ResourceContext* context) {
1103  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
1104  ProfileIOData* io_data = ProfileIOData::FromResourceContext(context);
1105  return io_data->GetCookieSettings()->IsCookieSessionOnly(url);
1106}
1107
1108bool ChromeContentBrowserClient::AllowSaveLocalState(
1109    content::ResourceContext* context) {
1110  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
1111  ProfileIOData* io_data = ProfileIOData::FromResourceContext(context);
1112  CookieSettings* cookie_settings = io_data->GetCookieSettings();
1113  ContentSetting setting = cookie_settings->GetDefaultCookieSetting(NULL);
1114
1115  // TODO(bauerb): Should we also disallow local state if the default is BLOCK?
1116  // Could we even support per-origin settings?
1117  return setting != CONTENT_SETTING_SESSION_ONLY;
1118}
1119
1120bool ChromeContentBrowserClient::AllowWorkerDatabase(
1121    const GURL& url,
1122    const string16& name,
1123    const string16& display_name,
1124    unsigned long estimated_size,
1125    content::ResourceContext* context,
1126    const std::vector<std::pair<int, int> >& render_views) {
1127  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
1128  ProfileIOData* io_data = ProfileIOData::FromResourceContext(context);
1129  CookieSettings* cookie_settings = io_data->GetCookieSettings();
1130  bool allow = cookie_settings->IsSettingCookieAllowed(url, url);
1131
1132  // Record access to database for potential display in UI.
1133  std::vector<std::pair<int, int> >::const_iterator i;
1134  for (i = render_views.begin(); i != render_views.end(); ++i) {
1135    BrowserThread::PostTask(
1136        BrowserThread::UI, FROM_HERE,
1137        base::Bind(&TabSpecificContentSettings::WebDatabaseAccessed,
1138                   i->first, i->second, url, name, display_name, !allow));
1139  }
1140
1141  return allow;
1142}
1143
1144bool ChromeContentBrowserClient::AllowWorkerFileSystem(
1145    const GURL& url,
1146    content::ResourceContext* context,
1147    const std::vector<std::pair<int, int> >& render_views) {
1148  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
1149  ProfileIOData* io_data = ProfileIOData::FromResourceContext(context);
1150  CookieSettings* cookie_settings = io_data->GetCookieSettings();
1151  bool allow = cookie_settings->IsSettingCookieAllowed(url, url);
1152
1153  // Record access to file system for potential display in UI.
1154  std::vector<std::pair<int, int> >::const_iterator i;
1155  for (i = render_views.begin(); i != render_views.end(); ++i) {
1156    BrowserThread::PostTask(
1157        BrowserThread::UI, FROM_HERE,
1158        base::Bind(&TabSpecificContentSettings::FileSystemAccessed,
1159                   i->first, i->second, url, !allow));
1160  }
1161
1162  return allow;
1163}
1164
1165bool ChromeContentBrowserClient::AllowWorkerIndexedDB(
1166    const GURL& url,
1167    const string16& name,
1168    content::ResourceContext* context,
1169    const std::vector<std::pair<int, int> >& render_views) {
1170  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
1171  ProfileIOData* io_data = ProfileIOData::FromResourceContext(context);
1172  CookieSettings* cookie_settings = io_data->GetCookieSettings();
1173  bool allow = cookie_settings->IsSettingCookieAllowed(url, url);
1174
1175  // Record access to IndexedDB for potential display in UI.
1176  std::vector<std::pair<int, int> >::const_iterator i;
1177  for (i = render_views.begin(); i != render_views.end(); ++i) {
1178    BrowserThread::PostTask(
1179        BrowserThread::UI, FROM_HERE,
1180        base::Bind(&TabSpecificContentSettings::IndexedDBAccessed,
1181                   i->first, i->second, url, name, !allow));
1182  }
1183
1184  return allow;
1185}
1186
1187net::URLRequestContext*
1188ChromeContentBrowserClient::OverrideRequestContextForURL(
1189    const GURL& url, content::ResourceContext* context) {
1190  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
1191  if (url.SchemeIs(chrome::kExtensionScheme)) {
1192    ProfileIOData* io_data = ProfileIOData::FromResourceContext(context);
1193    return io_data->extensions_request_context();
1194  }
1195
1196  return NULL;
1197}
1198
1199QuotaPermissionContext*
1200ChromeContentBrowserClient::CreateQuotaPermissionContext() {
1201  return new ChromeQuotaPermissionContext();
1202}
1203
1204void ChromeContentBrowserClient::OpenItem(const FilePath& path) {
1205  platform_util::OpenItem(path);
1206}
1207
1208void ChromeContentBrowserClient::ShowItemInFolder(const FilePath& path) {
1209  platform_util::ShowItemInFolder(path);
1210}
1211
1212void ChromeContentBrowserClient::AllowCertificateError(
1213    int render_process_id,
1214    int render_view_id,
1215    int cert_error,
1216    const net::SSLInfo& ssl_info,
1217    const GURL& request_url,
1218    bool overridable,
1219    bool strict_enforcement,
1220    const base::Callback<void(bool)>& callback,
1221    bool* cancel_request) {
1222  // If the tab is being prerendered, cancel the prerender and the request.
1223  WebContents* tab = tab_util::GetWebContentsByID(
1224      render_process_id, render_view_id);
1225  if (!tab) {
1226    NOTREACHED();
1227    return;
1228  }
1229  prerender::PrerenderManager* prerender_manager =
1230      prerender::PrerenderManagerFactory::GetForProfile(
1231          Profile::FromBrowserContext(tab->GetBrowserContext()));
1232  if (prerender_manager && prerender_manager->IsWebContentsPrerendering(tab,
1233                                                                        NULL)) {
1234    if (prerender_manager->prerender_tracker()->TryCancel(
1235            render_process_id, render_view_id,
1236            prerender::FINAL_STATUS_SSL_ERROR)) {
1237      *cancel_request = true;
1238      return;
1239    }
1240  }
1241
1242#if defined(ENABLE_CAPTIVE_PORTAL_DETECTION)
1243  captive_portal::CaptivePortalTabHelper* captive_portal_tab_helper =
1244      captive_portal::CaptivePortalTabHelper::FromWebContents(tab);
1245  if (captive_portal_tab_helper)
1246    captive_portal_tab_helper->OnSSLCertError(ssl_info);
1247#endif
1248
1249  // Otherwise, display an SSL blocking page.
1250  new SSLBlockingPage(tab, cert_error, ssl_info, request_url, overridable,
1251                      strict_enforcement, callback);
1252}
1253
1254void ChromeContentBrowserClient::SelectClientCertificate(
1255    int render_process_id,
1256    int render_view_id,
1257    const net::HttpNetworkSession* network_session,
1258    net::SSLCertRequestInfo* cert_request_info,
1259    const base::Callback<void(net::X509Certificate*)>& callback) {
1260  WebContents* tab = tab_util::GetWebContentsByID(
1261      render_process_id, render_view_id);
1262  if (!tab) {
1263    NOTREACHED();
1264    return;
1265  }
1266
1267  GURL requesting_url("https://" + cert_request_info->host_and_port);
1268  DCHECK(requesting_url.is_valid()) << "Invalid URL string: https://"
1269                                    << cert_request_info->host_and_port;
1270
1271  Profile* profile = Profile::FromBrowserContext(tab->GetBrowserContext());
1272  scoped_ptr<Value> filter(
1273      profile->GetHostContentSettingsMap()->GetWebsiteSetting(
1274          requesting_url,
1275          requesting_url,
1276          CONTENT_SETTINGS_TYPE_AUTO_SELECT_CERTIFICATE,
1277          std::string(), NULL));
1278
1279  if (filter.get()) {
1280    // Try to automatically select a client certificate.
1281    if (filter->IsType(Value::TYPE_DICTIONARY)) {
1282      DictionaryValue* filter_dict =
1283          static_cast<DictionaryValue*>(filter.get());
1284
1285      const std::vector<scoped_refptr<net::X509Certificate> >&
1286          all_client_certs = cert_request_info->client_certs;
1287      for (size_t i = 0; i < all_client_certs.size(); ++i) {
1288        if (CertMatchesFilter(*all_client_certs[i], *filter_dict)) {
1289          // Use the first certificate that is matched by the filter.
1290          callback.Run(all_client_certs[i]);
1291          return;
1292        }
1293      }
1294    } else {
1295      NOTREACHED();
1296    }
1297  }
1298
1299  SSLTabHelper* ssl_tab_helper = SSLTabHelper::FromWebContents(tab);
1300  if (!ssl_tab_helper) {
1301    // If there is no SSLTabHelper for the given WebContents then we can't
1302    // show the user a dialog to select a client certificate. So we simply
1303    // proceed with no client certificate.
1304    callback.Run(NULL);
1305    return;
1306  }
1307  ssl_tab_helper->ShowClientCertificateRequestDialog(
1308      network_session, cert_request_info, callback);
1309}
1310
1311void ChromeContentBrowserClient::AddNewCertificate(
1312    net::URLRequest* request,
1313    net::X509Certificate* cert,
1314    int render_process_id,
1315    int render_view_id) {
1316  // The handler will run the UI and delete itself when it's finished.
1317  new SSLAddCertHandler(request, cert, render_process_id, render_view_id);
1318}
1319
1320content::MediaObserver* ChromeContentBrowserClient::GetMediaObserver() {
1321  return MediaInternals::GetInstance();
1322}
1323
1324void ChromeContentBrowserClient::RequestDesktopNotificationPermission(
1325    const GURL& source_origin,
1326    int callback_context,
1327    int render_process_id,
1328    int render_view_id) {
1329#if defined(ENABLE_NOTIFICATIONS)
1330  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
1331  WebContents* contents =
1332      tab_util::GetWebContentsByID(render_process_id, render_view_id);
1333  if (!contents) {
1334    NOTREACHED();
1335    return;
1336  }
1337
1338  // Skip showing the infobar if the request comes from an extension, and that
1339  // extension has the 'notify' permission. (If the extension does not have the
1340  // permission, the user will still be prompted.)
1341  Profile* profile = Profile::FromBrowserContext(contents->GetBrowserContext());
1342  ExtensionService* service = profile->GetExtensionService();
1343  const Extension* extension = !service ? NULL :
1344      service->extensions()->GetExtensionOrAppByURL(ExtensionURLInfo(
1345          source_origin));
1346  if (extension &&
1347      extension->HasAPIPermission(APIPermission::kNotification)) {
1348    RenderViewHost* rvh =
1349        RenderViewHost::FromID(render_process_id, render_view_id);
1350    if (rvh)
1351      rvh->DesktopNotificationPermissionRequestDone(callback_context);
1352    return;
1353  }
1354
1355  DesktopNotificationService* notifications =
1356      DesktopNotificationServiceFactory::GetForProfile(profile);
1357  notifications->RequestPermission(source_origin, render_process_id,
1358      render_view_id, callback_context, contents);
1359#else
1360  NOTIMPLEMENTED();
1361#endif
1362}
1363
1364WebKit::WebNotificationPresenter::Permission
1365    ChromeContentBrowserClient::CheckDesktopNotificationPermission(
1366        const GURL& source_origin,
1367        content::ResourceContext* context,
1368        int render_process_id) {
1369#if defined(ENABLE_NOTIFICATIONS)
1370  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
1371  ProfileIOData* io_data = ProfileIOData::FromResourceContext(context);
1372  if (io_data->GetExtensionInfoMap()->SecurityOriginHasAPIPermission(
1373        source_origin, render_process_id,
1374        APIPermission::kNotification))
1375    return WebKit::WebNotificationPresenter::PermissionAllowed;
1376
1377  // Fall back to the regular notification preferences, which works on an
1378  // origin basis.
1379  return io_data->GetNotificationService() ?
1380      io_data->GetNotificationService()->HasPermission(source_origin) :
1381      WebKit::WebNotificationPresenter::PermissionNotAllowed;
1382#else
1383  return WebKit::WebNotificationPresenter::PermissionAllowed;
1384#endif
1385}
1386
1387void ChromeContentBrowserClient::ShowDesktopNotification(
1388    const content::ShowDesktopNotificationHostMsgParams& params,
1389    int render_process_id,
1390    int render_view_id,
1391    bool worker) {
1392#if defined(ENABLE_NOTIFICATIONS)
1393  RenderViewHost* rvh = RenderViewHost::FromID(
1394      render_process_id, render_view_id);
1395  if (!rvh) {
1396    NOTREACHED();
1397    return;
1398  }
1399
1400  content::RenderProcessHost* process = rvh->GetProcess();
1401  Profile* profile = Profile::FromBrowserContext(process->GetBrowserContext());
1402  DesktopNotificationService* service =
1403      DesktopNotificationServiceFactory::GetForProfile(profile);
1404  service->ShowDesktopNotification(
1405    params, render_process_id, render_view_id,
1406    worker ? DesktopNotificationService::WorkerNotification :
1407        DesktopNotificationService::PageNotification);
1408#else
1409  NOTIMPLEMENTED();
1410#endif
1411}
1412
1413void ChromeContentBrowserClient::CancelDesktopNotification(
1414    int render_process_id,
1415    int render_view_id,
1416    int notification_id) {
1417#if defined(ENABLE_NOTIFICATIONS)
1418  RenderViewHost* rvh = RenderViewHost::FromID(
1419      render_process_id, render_view_id);
1420  if (!rvh) {
1421    NOTREACHED();
1422    return;
1423  }
1424
1425  content::RenderProcessHost* process = rvh->GetProcess();
1426  Profile* profile = Profile::FromBrowserContext(process->GetBrowserContext());
1427  DesktopNotificationService* service =
1428      DesktopNotificationServiceFactory::GetForProfile(profile);
1429  service->CancelDesktopNotification(
1430      render_process_id, render_view_id, notification_id);
1431#else
1432  NOTIMPLEMENTED();
1433#endif
1434}
1435
1436bool ChromeContentBrowserClient::CanCreateWindow(
1437    const GURL& opener_url,
1438    const GURL& source_origin,
1439    WindowContainerType container_type,
1440    content::ResourceContext* context,
1441    int render_process_id,
1442    bool* no_javascript_access) {
1443  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
1444
1445  *no_javascript_access = false;
1446
1447  // If the opener is trying to create a background window but doesn't have
1448  // the appropriate permission, fail the attempt.
1449  if (container_type == WINDOW_CONTAINER_TYPE_BACKGROUND) {
1450    ProfileIOData* io_data = ProfileIOData::FromResourceContext(context);
1451    ExtensionInfoMap* map = io_data->GetExtensionInfoMap();
1452
1453    if (!map->SecurityOriginHasAPIPermission(
1454            source_origin,
1455            render_process_id,
1456            APIPermission::kBackground)) {
1457      return false;
1458    }
1459
1460    // Note: this use of GetExtensionOrAppByURL is safe but imperfect.  It may
1461    // return a recently installed Extension even if this CanCreateWindow call
1462    // was made by an old copy of the page in a normal web process.  That's ok,
1463    // because the permission check above would have caused an early return
1464    // already. We must use the full URL to find hosted apps, though, and not
1465    // just the origin.
1466    const Extension* extension = map->extensions().GetExtensionOrAppByURL(
1467        ExtensionURLInfo(opener_url));
1468    if (extension && !extension->allow_background_js_access())
1469      *no_javascript_access = true;
1470  }
1471  return true;
1472}
1473
1474std::string ChromeContentBrowserClient::GetWorkerProcessTitle(
1475    const GURL& url, content::ResourceContext* context) {
1476  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
1477  // Check if it's an extension-created worker, in which case we want to use
1478  // the name of the extension.
1479  ProfileIOData* io_data = ProfileIOData::FromResourceContext(context);
1480  const Extension* extension =
1481      io_data->GetExtensionInfoMap()->extensions().GetByID(url.host());
1482  return extension ? extension->name() : std::string();
1483}
1484
1485void ChromeContentBrowserClient::ResourceDispatcherHostCreated() {
1486  return g_browser_process->ResourceDispatcherHostCreated();
1487}
1488
1489content::SpeechRecognitionManagerDelegate*
1490    ChromeContentBrowserClient::GetSpeechRecognitionManagerDelegate() {
1491#if defined(ENABLE_INPUT_SPEECH)
1492  return new speech::ChromeSpeechRecognitionManagerDelegate();
1493#else
1494  return NULL;
1495#endif
1496}
1497
1498net::NetLog* ChromeContentBrowserClient::GetNetLog() {
1499  return g_browser_process->net_log();
1500}
1501
1502AccessTokenStore* ChromeContentBrowserClient::CreateAccessTokenStore() {
1503  return new ChromeAccessTokenStore();
1504}
1505
1506bool ChromeContentBrowserClient::IsFastShutdownPossible() {
1507  const CommandLine& browser_command_line = *CommandLine::ForCurrentProcess();
1508  return !browser_command_line.HasSwitch(switches::kChromeFrame);
1509}
1510
1511void ChromeContentBrowserClient::OverrideWebkitPrefs(
1512    RenderViewHost* rvh, const GURL& url, WebPreferences* web_prefs) {
1513  Profile* profile = Profile::FromBrowserContext(
1514      rvh->GetProcess()->GetBrowserContext());
1515  PrefService* prefs = profile->GetPrefs();
1516
1517  FillFontFamilyMap(prefs, prefs::kWebKitStandardFontFamilyMap,
1518                    &web_prefs->standard_font_family_map);
1519  FillFontFamilyMap(prefs, prefs::kWebKitFixedFontFamilyMap,
1520                    &web_prefs->fixed_font_family_map);
1521  FillFontFamilyMap(prefs, prefs::kWebKitSerifFontFamilyMap,
1522                    &web_prefs->serif_font_family_map);
1523  FillFontFamilyMap(prefs, prefs::kWebKitSansSerifFontFamilyMap,
1524                    &web_prefs->sans_serif_font_family_map);
1525  FillFontFamilyMap(prefs, prefs::kWebKitCursiveFontFamilyMap,
1526                    &web_prefs->cursive_font_family_map);
1527  FillFontFamilyMap(prefs, prefs::kWebKitFantasyFontFamilyMap,
1528                    &web_prefs->fantasy_font_family_map);
1529  FillFontFamilyMap(prefs, prefs::kWebKitPictographFontFamilyMap,
1530                    &web_prefs->pictograph_font_family_map);
1531
1532  web_prefs->default_font_size =
1533      prefs->GetInteger(prefs::kWebKitDefaultFontSize);
1534  web_prefs->default_fixed_font_size =
1535      prefs->GetInteger(prefs::kWebKitDefaultFixedFontSize);
1536  web_prefs->minimum_font_size =
1537      prefs->GetInteger(prefs::kWebKitMinimumFontSize);
1538  web_prefs->minimum_logical_font_size =
1539      prefs->GetInteger(prefs::kWebKitMinimumLogicalFontSize);
1540
1541  web_prefs->default_encoding = prefs->GetString(prefs::kDefaultCharset);
1542
1543  web_prefs->javascript_can_open_windows_automatically =
1544      prefs->GetBoolean(prefs::kWebKitJavascriptCanOpenWindowsAutomatically);
1545  web_prefs->dom_paste_enabled =
1546      prefs->GetBoolean(prefs::kWebKitDomPasteEnabled);
1547  web_prefs->shrinks_standalone_images_to_fit =
1548      prefs->GetBoolean(prefs::kWebKitShrinksStandaloneImagesToFit);
1549  const DictionaryValue* inspector_settings =
1550      prefs->GetDictionary(prefs::kWebKitInspectorSettings);
1551  if (inspector_settings) {
1552    for (DictionaryValue::key_iterator iter(inspector_settings->begin_keys());
1553         iter != inspector_settings->end_keys(); ++iter) {
1554      std::string value;
1555      if (inspector_settings->GetStringWithoutPathExpansion(*iter, &value))
1556          web_prefs->inspector_settings.push_back(
1557              std::make_pair(*iter, value));
1558    }
1559  }
1560  web_prefs->tabs_to_links = prefs->GetBoolean(prefs::kWebkitTabsToLinks);
1561
1562  if (!prefs->GetBoolean(prefs::kWebKitJavascriptEnabled))
1563    web_prefs->javascript_enabled = false;
1564  if (!prefs->GetBoolean(prefs::kWebKitWebSecurityEnabled))
1565    web_prefs->web_security_enabled = false;
1566  if (!prefs->GetBoolean(prefs::kWebKitPluginsEnabled))
1567    web_prefs->plugins_enabled = false;
1568  if (!prefs->GetBoolean(prefs::kWebKitJavaEnabled))
1569    web_prefs->java_enabled = false;
1570  web_prefs->loads_images_automatically =
1571      prefs->GetBoolean(prefs::kWebKitLoadsImagesAutomatically);
1572
1573  if (prefs->GetBoolean(prefs::kDisable3DAPIs))
1574    web_prefs->experimental_webgl_enabled = false;
1575
1576  web_prefs->memory_info_enabled =
1577      prefs->GetBoolean(prefs::kEnableMemoryInfo);
1578  web_prefs->allow_displaying_insecure_content =
1579      prefs->GetBoolean(prefs::kWebKitAllowDisplayingInsecureContent);
1580  web_prefs->allow_running_insecure_content =
1581      prefs->GetBoolean(prefs::kWebKitAllowRunningInsecureContent);
1582#if defined(OS_ANDROID)
1583  web_prefs->font_scale_factor =
1584      static_cast<float>(prefs->GetDouble(prefs::kWebKitFontScaleFactor));
1585  web_prefs->force_enable_zoom =
1586      prefs->GetBoolean(prefs::kWebKitForceEnableZoom);
1587#endif
1588  web_prefs->password_echo_enabled = browser_defaults::kPasswordEchoEnabled;
1589
1590  // The user stylesheet watcher may not exist in a testing profile.
1591  UserStyleSheetWatcher* user_style_sheet_watcher =
1592      UserStyleSheetWatcherFactory::GetForProfile(profile);
1593  if (user_style_sheet_watcher) {
1594    web_prefs->user_style_sheet_enabled = true;
1595    web_prefs->user_style_sheet_location =
1596        user_style_sheet_watcher->user_style_sheet();
1597  } else {
1598    web_prefs->user_style_sheet_enabled = false;
1599  }
1600
1601  web_prefs->asynchronous_spell_checking_enabled =
1602#if defined(OS_MACOSX)
1603      // TODO(hbono): Bug 107371: Implement asynchronous spellchecking API for
1604      // Mac so it uses NSSpellChecker in the background.
1605      false;
1606#else
1607      !CommandLine::ForCurrentProcess()->
1608          HasSwitch(switches::kForceSyncSpellCheck);
1609#endif
1610  web_prefs->unified_textchecker_enabled =
1611      web_prefs->asynchronous_spell_checking_enabled;
1612
1613  web_prefs->uses_universal_detector =
1614      prefs->GetBoolean(prefs::kWebKitUsesUniversalDetector);
1615  web_prefs->text_areas_are_resizable =
1616      prefs->GetBoolean(prefs::kWebKitTextAreasAreResizable);
1617  web_prefs->hyperlink_auditing_enabled =
1618      prefs->GetBoolean(prefs::kEnableHyperlinkAuditing);
1619
1620  // Make sure we will set the default_encoding with canonical encoding name.
1621  web_prefs->default_encoding =
1622      CharacterEncoding::GetCanonicalEncodingNameByAliasName(
1623          web_prefs->default_encoding);
1624  if (web_prefs->default_encoding.empty()) {
1625    prefs->ClearPref(prefs::kDefaultCharset);
1626    web_prefs->default_encoding = prefs->GetString(prefs::kDefaultCharset);
1627  }
1628  DCHECK(!web_prefs->default_encoding.empty());
1629
1630  WebContents* web_contents = WebContents::FromRenderViewHost(rvh);
1631  chrome::ViewType view_type = chrome::GetViewType(web_contents);
1632  ExtensionService* service = profile->GetExtensionService();
1633  if (service) {
1634    const GURL& url = rvh->GetSiteInstance()->GetSiteURL();
1635    const Extension* extension = service->extensions()->GetByID(url.host());
1636    // Ensure that we are only granting extension preferences to URLs with
1637    // the correct scheme. Without this check, chrome-guest:// schemes used by
1638    // webview tags as well as hosts that happen to match the id of an
1639    // installed extension would get the wrong preferences.
1640    if (url.SchemeIs(chrome::kExtensionScheme)) {
1641      extension_webkit_preferences::SetPreferences(
1642          extension, view_type, web_prefs);
1643    }
1644  }
1645
1646  if (content::IsForceCompositingModeEnabled())
1647    web_prefs->force_compositing_mode = true;
1648
1649  if (view_type == chrome::VIEW_TYPE_NOTIFICATION) {
1650    web_prefs->allow_scripts_to_close_windows = true;
1651  } else if (view_type == chrome::VIEW_TYPE_BACKGROUND_CONTENTS) {
1652    // Disable all kinds of acceleration for background pages.
1653    // See http://crbug.com/96005 and http://crbug.com/96006
1654    web_prefs->force_compositing_mode = false;
1655    web_prefs->accelerated_compositing_enabled = false;
1656    web_prefs->accelerated_2d_canvas_enabled = false;
1657    web_prefs->accelerated_video_enabled = false;
1658    web_prefs->accelerated_painting_enabled = false;
1659    web_prefs->accelerated_plugins_enabled = false;
1660  }
1661
1662#if defined(FILE_MANAGER_EXTENSION)
1663  // Override the default of suppressing HW compositing for WebUI pages for the
1664  // file manager, which is implemented using WebUI but wants HW acceleration
1665  // for video decode & render.
1666  if (url.spec() == chrome::kChromeUIFileManagerURL) {
1667    web_prefs->accelerated_compositing_enabled = true;
1668    web_prefs->accelerated_2d_canvas_enabled = true;
1669  }
1670#endif
1671}
1672
1673void ChromeContentBrowserClient::UpdateInspectorSetting(
1674    RenderViewHost* rvh, const std::string& key, const std::string& value) {
1675  content::BrowserContext* browser_context =
1676      rvh->GetProcess()->GetBrowserContext();
1677  DictionaryPrefUpdate update(
1678      Profile::FromBrowserContext(browser_context)->GetPrefs(),
1679      prefs::kWebKitInspectorSettings);
1680  DictionaryValue* inspector_settings = update.Get();
1681  inspector_settings->SetWithoutPathExpansion(key,
1682                                              Value::CreateStringValue(value));
1683}
1684
1685void ChromeContentBrowserClient::ClearInspectorSettings(RenderViewHost* rvh) {
1686  content::BrowserContext* browser_context =
1687      rvh->GetProcess()->GetBrowserContext();
1688  Profile::FromBrowserContext(browser_context)->GetPrefs()->
1689      ClearPref(prefs::kWebKitInspectorSettings);
1690}
1691
1692void ChromeContentBrowserClient::BrowserURLHandlerCreated(
1693    BrowserURLHandler* handler) {
1694  // Add the default URL handlers.
1695  handler->AddHandlerPair(&ExtensionWebUI::HandleChromeURLOverride,
1696                          BrowserURLHandler::null_handler());
1697  handler->AddHandlerPair(BrowserURLHandler::null_handler(),
1698                          &ExtensionWebUI::HandleChromeURLOverrideReverse);
1699
1700  // about: handler. Must come before chrome: handler, since it will
1701  // rewrite about: urls to chrome: URLs and then expect chrome: to
1702  // actually handle them.
1703  handler->AddHandlerPair(&WillHandleBrowserAboutURL,
1704                          BrowserURLHandler::null_handler());
1705  // chrome: & friends.
1706  handler->AddHandlerPair(&HandleWebUI, &HandleWebUIReverse);
1707}
1708
1709void ChromeContentBrowserClient::ClearCache(RenderViewHost* rvh) {
1710  Profile* profile = Profile::FromBrowserContext(
1711      rvh->GetSiteInstance()->GetProcess()->GetBrowserContext());
1712  BrowsingDataRemover* remover =
1713      BrowsingDataRemover::CreateForUnboundedRange(profile);
1714  remover->Remove(BrowsingDataRemover::REMOVE_CACHE,
1715                  BrowsingDataHelper::UNPROTECTED_WEB);
1716  // BrowsingDataRemover takes care of deleting itself when done.
1717}
1718
1719void ChromeContentBrowserClient::ClearCookies(RenderViewHost* rvh) {
1720  Profile* profile = Profile::FromBrowserContext(
1721      rvh->GetSiteInstance()->GetProcess()->GetBrowserContext());
1722  BrowsingDataRemover* remover =
1723      BrowsingDataRemover::CreateForUnboundedRange(profile);
1724  int remove_mask = BrowsingDataRemover::REMOVE_SITE_DATA;
1725  remover->Remove(remove_mask, BrowsingDataHelper::UNPROTECTED_WEB);
1726  // BrowsingDataRemover takes care of deleting itself when done.
1727}
1728
1729FilePath ChromeContentBrowserClient::GetDefaultDownloadDirectory() {
1730  return download_util::GetDefaultDownloadDirectory();
1731}
1732
1733std::string ChromeContentBrowserClient::GetDefaultDownloadName() {
1734  return l10n_util::GetStringUTF8(IDS_DEFAULT_DOWNLOAD_FILENAME);
1735}
1736
1737void ChromeContentBrowserClient::DidCreatePpapiPlugin(
1738    content::BrowserPpapiHost* browser_host) {
1739  browser_host->GetPpapiHost()->AddHostFactoryFilter(
1740      scoped_ptr<ppapi::host::HostFactory>(
1741          new ChromeBrowserPepperHostFactory(browser_host)));
1742}
1743
1744content::BrowserPpapiHost*
1745    ChromeContentBrowserClient::GetExternalBrowserPpapiHost(
1746        int plugin_process_id) {
1747  BrowserChildProcessHostIterator iter(content::PROCESS_TYPE_NACL_LOADER);
1748  while (!iter.Done()) {
1749    NaClProcessHost* host = static_cast<NaClProcessHost*>(iter.GetDelegate());
1750    if (host->process() &&
1751        host->process()->GetData().id == plugin_process_id) {
1752      // Found the plugin.
1753      return host->browser_ppapi_host();
1754    }
1755    ++iter;
1756  }
1757  return NULL;
1758}
1759
1760bool ChromeContentBrowserClient::AllowPepperSocketAPI(
1761    content::BrowserContext* browser_context,
1762    const GURL& url,
1763    const content::SocketPermissionRequest& params) {
1764  if (!url.is_valid())
1765    return false;
1766
1767  std::string host = url.host();
1768  if (url.SchemeIs(kExtensionScheme) && allowed_socket_origins_.count(host))
1769    return true;
1770
1771  Profile* profile = Profile::FromBrowserContext(browser_context);
1772  const Extension* extension = NULL;
1773  if (profile && profile->GetExtensionService()) {
1774    extension = profile->GetExtensionService()->extensions()->
1775        GetExtensionOrAppByURL(ExtensionURLInfo(url));
1776  }
1777
1778  // Need to check this now and not on construction because otherwise it won't
1779  // work with browser_tests.
1780  const CommandLine& command_line = *CommandLine::ForCurrentProcess();
1781  std::string allowed_list =
1782      command_line.GetSwitchValueASCII(switches::kAllowNaClSocketAPI);
1783  if (allowed_list == "*") {
1784    // The wildcard allows socket API only for packaged and platform apps.
1785    return extension &&
1786        (extension->GetType() == Extension::TYPE_LEGACY_PACKAGED_APP ||
1787         extension->GetType() == Extension::TYPE_PLATFORM_APP);
1788  } else if (!allowed_list.empty()) {
1789    StringTokenizer t(allowed_list, ",");
1790    while (t.GetNext()) {
1791      if (t.token() == host)
1792        return true;
1793    }
1794  }
1795
1796  if (!extension)
1797    return false;
1798
1799  extensions::SocketPermission::CheckParam extension_params(
1800      params.type, params.host, params.port);
1801  if (extension->CheckAPIPermissionWithParam(APIPermission::kSocket,
1802                                             &extension_params))
1803    return true;
1804
1805  return false;
1806}
1807
1808bool ChromeContentBrowserClient::AllowPepperPrivateFileAPI() {
1809  return CommandLine::ForCurrentProcess()->HasSwitch(
1810      switches::kPpapiFlashInProcess);
1811}
1812
1813FilePath ChromeContentBrowserClient::GetHyphenDictionaryDirectory() {
1814  FilePath directory;
1815  PathService::Get(chrome::DIR_APP_DICTIONARIES, &directory);
1816  return directory.Append(FILE_PATH_LITERAL("Hyphen"));
1817}
1818
1819#if defined(OS_POSIX) && !defined(OS_MACOSX)
1820void ChromeContentBrowserClient::GetAdditionalMappedFilesForChildProcess(
1821    const CommandLine& command_line,
1822    int child_process_id,
1823    std::vector<FileDescriptorInfo>* mappings) {
1824#if defined(OS_ANDROID)
1825  FilePath data_path;
1826  PathService::Get(ui::DIR_RESOURCE_PAKS_ANDROID, &data_path);
1827  DCHECK(!data_path.empty());
1828
1829  int flags = base::PLATFORM_FILE_OPEN | base::PLATFORM_FILE_READ;
1830  FilePath chrome_pak = data_path.AppendASCII("chrome.pak");
1831  base::PlatformFile f =
1832      base::CreatePlatformFile(chrome_pak, flags, NULL, NULL);
1833  DCHECK(f != base::kInvalidPlatformFileValue);
1834  mappings->push_back(FileDescriptorInfo(kAndroidChromePakDescriptor,
1835                                         FileDescriptor(f, true)));
1836
1837  FilePath chrome_resources_pak =
1838      data_path.AppendASCII("chrome_100_percent.pak");
1839  f = base::CreatePlatformFile(chrome_resources_pak, flags, NULL, NULL);
1840  DCHECK(f != base::kInvalidPlatformFileValue);
1841  mappings->push_back(FileDescriptorInfo(kAndroidUIResourcesPakDescriptor,
1842                                         FileDescriptor(f, true)));
1843
1844  const std::string locale = GetApplicationLocale();
1845  FilePath locale_pak = ResourceBundle::GetSharedInstance().
1846      GetLocaleFilePath(locale, false);
1847  f = base::CreatePlatformFile(locale_pak, flags, NULL, NULL);
1848  DCHECK(f != base::kInvalidPlatformFileValue);
1849  mappings->push_back(FileDescriptorInfo(kAndroidLocalePakDescriptor,
1850                                         FileDescriptor(f, true)));
1851
1852#if defined(USE_LINUX_BREAKPAD)
1853  f = crash_dump_manager_->CreateMinidumpFile(child_process_id);
1854  if (f == base::kInvalidPlatformFileValue) {
1855    LOG(ERROR) << "Failed to create file for minidump, crash reporting will be "
1856        "disabled for this process.";
1857  } else {
1858    mappings->push_back(FileDescriptorInfo(kAndroidMinidumpDescriptor,
1859                                           FileDescriptor(f, true)));
1860  }
1861#endif  // defined(USE_LINUX_BREAKPAD)
1862
1863#else
1864  int crash_signal_fd = GetCrashSignalFD(command_line);
1865  if (crash_signal_fd >= 0) {
1866    mappings->push_back(FileDescriptorInfo(kCrashDumpSignal,
1867                                           FileDescriptor(crash_signal_fd,
1868                                                          false)));
1869  }
1870#endif  // defined(OS_ANDROID)
1871}
1872#endif  // defined(OS_POSIX) && !defined(OS_MACOSX)
1873
1874#if defined(OS_WIN)
1875const wchar_t* ChromeContentBrowserClient::GetResourceDllName() {
1876  return chrome::kBrowserResourcesDll;
1877}
1878#endif
1879
1880#if defined(OS_ANDROID)
1881void ChromeContentBrowserClient::InitCrashDumpManager() {
1882  if (!crash_dump_manager_.get())
1883    crash_dump_manager_.reset(new CrashDumpManager());
1884}
1885#endif
1886
1887#if defined(USE_NSS)
1888crypto::CryptoModuleBlockingPasswordDelegate*
1889    ChromeContentBrowserClient::GetCryptoPasswordDelegate(
1890        const GURL& url) {
1891  return chrome::NewCryptoModuleBlockingDialogDelegate(
1892      chrome::kCryptoModulePasswordKeygen, url.host());
1893}
1894#endif
1895
1896void ChromeContentBrowserClient::SetApplicationLocale(
1897    const std::string& locale) {
1898  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
1899
1900  // This object is guaranteed to outlive all threads so we don't have to
1901  // worry about the lack of refcounting and can just post as Unretained.
1902  //
1903  // The common case is that this function is called early in Chrome startup
1904  // before any threads are created (it will also be called later if the user
1905  // changes the pref). In this case, there will be no threads created and
1906  // posting will fail. When there are no threads, we can just set the string
1907  // without worrying about threadsafety.
1908  if (!BrowserThread::PostTask(BrowserThread::IO, FROM_HERE,
1909          base::Bind(
1910              &ChromeContentBrowserClient::SetApplicationLocaleOnIOThread,
1911              base::Unretained(this), locale)))
1912    io_thread_application_locale_ = locale;
1913}
1914
1915void ChromeContentBrowserClient::SetApplicationLocaleOnIOThread(
1916    const std::string& locale) {
1917  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
1918  io_thread_application_locale_ = locale;
1919}
1920
1921}  // namespace chrome
1922