Popular sites on the NTP: check that experiment group StartsWith (rather than IS...
[chromium-blink-merge.git] / chrome / browser / ui / webui / plugins_ui.cc
blob6826844584b35794a11dd2f16ce58f32faf9be73
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.
5 #include "chrome/browser/ui/webui/plugins_ui.h"
7 #include <algorithm>
8 #include <string>
9 #include <vector>
11 #include "base/bind.h"
12 #include "base/bind_helpers.h"
13 #include "base/files/file_path.h"
14 #include "base/memory/ref_counted_memory.h"
15 #include "base/memory/scoped_ptr.h"
16 #include "base/memory/singleton.h"
17 #include "base/memory/weak_ptr.h"
18 #include "base/message_loop/message_loop.h"
19 #include "base/path_service.h"
20 #include "base/prefs/pref_member.h"
21 #include "base/prefs/pref_service.h"
22 #include "base/prefs/scoped_user_pref_update.h"
23 #include "base/strings/utf_string_conversions.h"
24 #include "base/values.h"
25 #include "chrome/browser/chrome_notification_types.h"
26 #include "chrome/browser/plugins/plugin_finder.h"
27 #include "chrome/browser/plugins/plugin_metadata.h"
28 #include "chrome/browser/plugins/plugin_prefs.h"
29 #include "chrome/browser/profiles/profile.h"
30 #include "chrome/browser/ui/browser.h"
31 #include "chrome/browser/ui/browser_window.h"
32 #include "chrome/common/chrome_content_client.h"
33 #include "chrome/common/chrome_paths.h"
34 #include "chrome/common/pref_names.h"
35 #include "chrome/common/url_constants.h"
36 #include "chrome/grit/generated_resources.h"
37 #include "components/content_settings/core/browser/host_content_settings_map.h"
38 #include "components/pref_registry/pref_registry_syncable.h"
39 #include "content/public/browser/notification_source.h"
40 #include "content/public/browser/plugin_service.h"
41 #include "content/public/browser/web_contents.h"
42 #include "content/public/browser/web_ui.h"
43 #include "content/public/browser/web_ui_data_source.h"
44 #include "content/public/browser/web_ui_message_handler.h"
45 #include "content/public/common/content_constants.h"
46 #include "grit/browser_resources.h"
47 #include "grit/theme_resources.h"
48 #include "ui/base/l10n/l10n_util.h"
49 #include "ui/base/resource/resource_bundle.h"
51 #if defined(OS_CHROMEOS)
52 #include "chrome/browser/ui/webui/chromeos/ui_account_tweaks.h"
53 #endif
55 using content::PluginService;
56 using content::WebContents;
57 using content::WebPluginInfo;
58 using content::WebUIMessageHandler;
60 namespace {
62 // Callback function to process result of EnablePlugin method.
63 void AssertPluginEnabled(bool did_enable) {
64 DCHECK(did_enable);
67 content::WebUIDataSource* CreatePluginsUIHTMLSource(Profile* profile) {
68 content::WebUIDataSource* source =
69 content::WebUIDataSource::Create(chrome::kChromeUIPluginsHost);
71 source->AddLocalizedString("pluginsTitle", IDS_PLUGINS_TITLE);
72 source->AddLocalizedString("pluginsDetailsModeLink",
73 IDS_PLUGINS_DETAILS_MODE_LINK);
74 source->AddLocalizedString("pluginsNoneInstalled",
75 IDS_PLUGINS_NONE_INSTALLED);
76 source->AddLocalizedString("pluginDisabled", IDS_PLUGINS_DISABLED_PLUGIN);
77 source->AddLocalizedString("pluginDisabledByPolicy",
78 IDS_PLUGINS_DISABLED_BY_POLICY_PLUGIN);
79 source->AddLocalizedString("pluginEnabledByPolicy",
80 IDS_PLUGINS_ENABLED_BY_POLICY_PLUGIN);
81 source->AddLocalizedString("pluginGroupManagedByPolicy",
82 IDS_PLUGINS_GROUP_MANAGED_BY_POLICY);
83 source->AddLocalizedString("pluginDownload", IDS_PLUGINS_DOWNLOAD);
84 source->AddLocalizedString("pluginName", IDS_PLUGINS_NAME);
85 source->AddLocalizedString("pluginVersion", IDS_PLUGINS_VERSION);
86 source->AddLocalizedString("pluginDescription", IDS_PLUGINS_DESCRIPTION);
87 source->AddLocalizedString("pluginPath", IDS_PLUGINS_PATH);
88 source->AddLocalizedString("pluginType", IDS_PLUGINS_TYPE);
89 source->AddLocalizedString("pluginMimeTypes", IDS_PLUGINS_MIME_TYPES);
90 source->AddLocalizedString("pluginMimeTypesMimeType",
91 IDS_PLUGINS_MIME_TYPES_MIME_TYPE);
92 source->AddLocalizedString("pluginMimeTypesDescription",
93 IDS_PLUGINS_MIME_TYPES_DESCRIPTION);
94 source->AddLocalizedString("pluginMimeTypesFileExtensions",
95 IDS_PLUGINS_MIME_TYPES_FILE_EXTENSIONS);
96 source->AddLocalizedString("disable", IDS_PLUGINS_DISABLE);
97 source->AddLocalizedString("enable", IDS_PLUGINS_ENABLE);
98 source->AddLocalizedString("alwaysAllowed", IDS_PLUGINS_ALWAYS_ALLOWED);
99 source->AddLocalizedString("noPlugins", IDS_PLUGINS_NO_PLUGINS);
101 source->SetJsonPath("strings.js");
102 source->AddResourcePath("plugins.js", IDR_PLUGINS_JS);
103 source->SetDefaultResource(IDR_PLUGINS_HTML);
104 #if defined(OS_CHROMEOS)
105 chromeos::AddAccountUITweaksLocalizedValues(source, profile);
106 #endif
107 return source;
110 base::string16 PluginTypeToString(int type) {
111 // The type is stored as an |int|, but doing the switch on the right
112 // enumeration type gives us better build-time error checking (if someone adds
113 // a new type).
114 switch (static_cast<WebPluginInfo::PluginType>(type)) {
115 case WebPluginInfo::PLUGIN_TYPE_NPAPI:
116 return l10n_util::GetStringUTF16(IDS_PLUGINS_NPAPI);
117 case WebPluginInfo::PLUGIN_TYPE_PEPPER_IN_PROCESS:
118 return l10n_util::GetStringUTF16(IDS_PLUGINS_PPAPI_IN_PROCESS);
119 case WebPluginInfo::PLUGIN_TYPE_PEPPER_OUT_OF_PROCESS:
120 return l10n_util::GetStringUTF16(IDS_PLUGINS_PPAPI_OUT_OF_PROCESS);
121 case WebPluginInfo::PLUGIN_TYPE_BROWSER_PLUGIN:
122 return l10n_util::GetStringUTF16(IDS_PLUGINS_BROWSER_PLUGIN);
124 NOTREACHED();
125 return base::string16();
128 ////////////////////////////////////////////////////////////////////////////////
130 // PluginsDOMHandler
132 ////////////////////////////////////////////////////////////////////////////////
134 // The handler for Javascript messages for the chrome://plugins/ page.
135 // TODO(viettrungluu): Make plugin list updates notify, and then observe
136 // changes; maybe replumb plugin list through plugin service?
137 // <http://crbug.com/39101>
138 class PluginsDOMHandler : public WebUIMessageHandler,
139 public content::NotificationObserver {
140 public:
141 PluginsDOMHandler();
142 ~PluginsDOMHandler() override {}
144 // WebUIMessageHandler implementation.
145 void RegisterMessages() override;
147 // Callback for the "requestPluginsData" message.
148 void HandleRequestPluginsData(const base::ListValue* args);
150 // Callback for the "enablePlugin" message.
151 void HandleEnablePluginMessage(const base::ListValue* args);
153 // Callback for the "saveShowDetailsToPrefs" message.
154 void HandleSaveShowDetailsToPrefs(const base::ListValue* args);
156 // Calback for the "getShowDetails" message.
157 void HandleGetShowDetails(const base::ListValue* args);
159 // Callback for the "setPluginAlwaysAllowed" message.
160 void HandleSetPluginAlwaysAllowed(const base::ListValue* args);
162 // content::NotificationObserver method overrides
163 void Observe(int type,
164 const content::NotificationSource& source,
165 const content::NotificationDetails& details) override;
167 private:
168 void LoadPlugins();
170 // Called on the UI thread when the plugin information is ready.
171 void PluginsLoaded(const std::vector<WebPluginInfo>& plugins);
173 content::NotificationRegistrar registrar_;
175 // Holds grouped plugins. The key is the group identifier and
176 // the value is the list of plugins belonging to the group.
177 typedef base::hash_map<std::string, std::vector<const WebPluginInfo*> >
178 PluginGroups;
180 // This pref guards the value whether about:plugins is in the details mode or
181 // not.
182 BooleanPrefMember show_details_;
184 base::WeakPtrFactory<PluginsDOMHandler> weak_ptr_factory_;
186 DISALLOW_COPY_AND_ASSIGN(PluginsDOMHandler);
189 PluginsDOMHandler::PluginsDOMHandler()
190 : weak_ptr_factory_(this) {
193 void PluginsDOMHandler::RegisterMessages() {
194 Profile* profile = Profile::FromWebUI(web_ui());
196 PrefService* prefs = profile->GetPrefs();
197 show_details_.Init(prefs::kPluginsShowDetails, prefs);
199 registrar_.Add(this,
200 chrome::NOTIFICATION_PLUGIN_ENABLE_STATUS_CHANGED,
201 content::Source<Profile>(profile));
203 web_ui()->RegisterMessageCallback("requestPluginsData",
204 base::Bind(&PluginsDOMHandler::HandleRequestPluginsData,
205 base::Unretained(this)));
206 web_ui()->RegisterMessageCallback("enablePlugin",
207 base::Bind(&PluginsDOMHandler::HandleEnablePluginMessage,
208 base::Unretained(this)));
209 web_ui()->RegisterMessageCallback("setPluginAlwaysAllowed",
210 base::Bind(&PluginsDOMHandler::HandleSetPluginAlwaysAllowed,
211 base::Unretained(this)));
212 web_ui()->RegisterMessageCallback("saveShowDetailsToPrefs",
213 base::Bind(&PluginsDOMHandler::HandleSaveShowDetailsToPrefs,
214 base::Unretained(this)));
215 web_ui()->RegisterMessageCallback("getShowDetails",
216 base::Bind(&PluginsDOMHandler::HandleGetShowDetails,
217 base::Unretained(this)));
220 void PluginsDOMHandler::HandleRequestPluginsData(const base::ListValue* args) {
221 LoadPlugins();
224 void PluginsDOMHandler::HandleEnablePluginMessage(const base::ListValue* args) {
225 Profile* profile = Profile::FromWebUI(web_ui());
227 // Be robust in accepting badness since plugins display HTML (hence
228 // JavaScript).
229 if (args->GetSize() != 3) {
230 NOTREACHED();
231 return;
234 std::string enable_str;
235 std::string is_group_str;
236 if (!args->GetString(1, &enable_str) || !args->GetString(2, &is_group_str)) {
237 NOTREACHED();
238 return;
240 bool enable = enable_str == "true";
242 PluginPrefs* plugin_prefs = PluginPrefs::GetForProfile(profile).get();
243 if (is_group_str == "true") {
244 base::string16 group_name;
245 if (!args->GetString(0, &group_name)) {
246 NOTREACHED();
247 return;
250 plugin_prefs->EnablePluginGroup(enable, group_name);
251 if (enable) {
252 // See http://crbug.com/50105 for background.
253 base::string16 adobereader = base::ASCIIToUTF16(
254 PluginMetadata::kAdobeReaderGroupName);
255 base::string16 internalpdf =
256 base::ASCIIToUTF16(ChromeContentClient::kPDFPluginName);
257 if (group_name == adobereader)
258 plugin_prefs->EnablePluginGroup(false, internalpdf);
259 else if (group_name == internalpdf)
260 plugin_prefs->EnablePluginGroup(false, adobereader);
262 } else {
263 base::FilePath::StringType file_path;
264 if (!args->GetString(0, &file_path)) {
265 NOTREACHED();
266 return;
269 plugin_prefs->EnablePlugin(enable, base::FilePath(file_path),
270 base::Bind(&AssertPluginEnabled));
274 void PluginsDOMHandler::HandleSaveShowDetailsToPrefs(
275 const base::ListValue* args) {
276 std::string details_mode;
277 if (!args->GetString(0, &details_mode)) {
278 NOTREACHED();
279 return;
281 show_details_.SetValue(details_mode == "true");
284 void PluginsDOMHandler::HandleGetShowDetails(const base::ListValue* args) {
285 base::FundamentalValue show_details(show_details_.GetValue());
286 web_ui()->CallJavascriptFunction("loadShowDetailsFromPrefs", show_details);
289 void PluginsDOMHandler::HandleSetPluginAlwaysAllowed(
290 const base::ListValue* args) {
291 // Be robust in the input parameters, but crash in a Debug build.
292 if (args->GetSize() != 2) {
293 NOTREACHED();
294 return;
297 std::string plugin;
298 bool allowed = false;
299 if (!args->GetString(0, &plugin) || !args->GetBoolean(1, &allowed)) {
300 NOTREACHED();
301 return;
303 Profile* profile = Profile::FromWebUI(web_ui());
304 profile->GetHostContentSettingsMap()->SetContentSetting(
305 ContentSettingsPattern::Wildcard(),
306 ContentSettingsPattern::Wildcard(),
307 CONTENT_SETTINGS_TYPE_PLUGINS,
308 plugin,
309 allowed ? CONTENT_SETTING_ALLOW : CONTENT_SETTING_DEFAULT);
311 // Keep track of the whitelist separately, so that we can distinguish plugins
312 // whitelisted by the user from automatically whitelisted ones.
313 DictionaryPrefUpdate update(profile->GetPrefs(),
314 prefs::kContentSettingsPluginWhitelist);
315 update->SetBoolean(plugin, allowed);
318 void PluginsDOMHandler::Observe(int type,
319 const content::NotificationSource& source,
320 const content::NotificationDetails& details) {
321 DCHECK_EQ(chrome::NOTIFICATION_PLUGIN_ENABLE_STATUS_CHANGED, type);
322 LoadPlugins();
325 void PluginsDOMHandler::LoadPlugins() {
326 if (weak_ptr_factory_.HasWeakPtrs())
327 return;
329 PluginService::GetInstance()->GetPlugins(
330 base::Bind(&PluginsDOMHandler::PluginsLoaded,
331 weak_ptr_factory_.GetWeakPtr()));
334 void PluginsDOMHandler::PluginsLoaded(
335 const std::vector<WebPluginInfo>& plugins) {
336 Profile* profile = Profile::FromWebUI(web_ui());
337 PluginPrefs* plugin_prefs = PluginPrefs::GetForProfile(profile).get();
339 ContentSettingsPattern wildcard = ContentSettingsPattern::Wildcard();
341 PluginFinder* plugin_finder = PluginFinder::GetInstance();
342 // Group plugins by identifier. This is done to be able to display
343 // the plugins in UI in a grouped fashion.
344 PluginGroups groups;
345 for (size_t i = 0; i < plugins.size(); ++i) {
346 scoped_ptr<PluginMetadata> plugin(
347 plugin_finder->GetPluginMetadata(plugins[i]));
348 groups[plugin->identifier()].push_back(&plugins[i]);
351 // Construct DictionaryValues to return to UI.
352 base::ListValue* plugin_groups_data = new base::ListValue();
353 for (PluginGroups::const_iterator it = groups.begin();
354 it != groups.end(); ++it) {
355 const std::vector<const WebPluginInfo*>& group_plugins = it->second;
356 base::ListValue* plugin_files = new base::ListValue();
357 scoped_ptr<PluginMetadata> plugin_metadata(
358 plugin_finder->GetPluginMetadata(*group_plugins[0]));
359 base::string16 group_name = plugin_metadata->name();
360 std::string group_identifier = plugin_metadata->identifier();
361 bool group_enabled = false;
362 bool all_plugins_enabled_by_policy = true;
363 bool all_plugins_disabled_by_policy = true;
364 bool all_plugins_managed_by_policy = true;
365 const WebPluginInfo* active_plugin = NULL;
366 for (size_t j = 0; j < group_plugins.size(); ++j) {
367 const WebPluginInfo& group_plugin = *group_plugins[j];
369 base::DictionaryValue* plugin_file = new base::DictionaryValue();
370 plugin_file->SetString("name", group_plugin.name);
372 // If this plugin is Pepper Flash, and the plugin path is the same as the
373 // path for the Pepper Flash System plugin, then mark this plugin
374 // description as the system plugin to help the user disambiguate the
375 // two plugins.
376 base::string16 desc = group_plugin.desc;
377 if (group_plugin.is_pepper_plugin() &&
378 group_plugin.name == base::ASCIIToUTF16(content::kFlashPluginName)) {
379 base::FilePath system_flash_path;
380 PathService::Get(chrome::FILE_PEPPER_FLASH_SYSTEM_PLUGIN,
381 &system_flash_path);
382 if (base::FilePath::CompareEqualIgnoreCase(group_plugin.path.value(),
383 system_flash_path.value())) {
384 #if defined(GOOGLE_CHROME_BUILD)
385 // Existing documentation for debugging Flash describe this plugin as
386 // "Debug" so preserve this nomenclature here.
387 desc += base::ASCIIToUTF16(" Debug");
388 #else
389 // On Chromium, we can name it what it really is; the system plugin.
390 desc += base::ASCIIToUTF16(" System");
391 #endif
394 plugin_file->SetString("description", desc);
396 plugin_file->SetString("path", group_plugin.path.value());
397 plugin_file->SetString("version", group_plugin.version);
398 plugin_file->SetString("type", PluginTypeToString(group_plugin.type));
400 base::ListValue* mime_types = new base::ListValue();
401 const std::vector<content::WebPluginMimeType>& plugin_mime_types =
402 group_plugin.mime_types;
403 for (size_t k = 0; k < plugin_mime_types.size(); ++k) {
404 base::DictionaryValue* mime_type = new base::DictionaryValue();
405 mime_type->SetString("mimeType", plugin_mime_types[k].mime_type);
406 mime_type->SetString("description", plugin_mime_types[k].description);
408 base::ListValue* file_extensions = new base::ListValue();
409 const std::vector<std::string>& mime_file_extensions =
410 plugin_mime_types[k].file_extensions;
411 for (size_t l = 0; l < mime_file_extensions.size(); ++l) {
412 file_extensions->Append(
413 new base::StringValue(mime_file_extensions[l]));
415 mime_type->Set("fileExtensions", file_extensions);
417 mime_types->Append(mime_type);
419 plugin_file->Set("mimeTypes", mime_types);
421 bool plugin_enabled = plugin_prefs->IsPluginEnabled(group_plugin);
423 if (!active_plugin || (plugin_enabled && !group_enabled))
424 active_plugin = &group_plugin;
425 group_enabled = plugin_enabled || group_enabled;
427 std::string enabled_mode;
428 PluginPrefs::PolicyStatus plugin_status =
429 plugin_prefs->PolicyStatusForPlugin(group_plugin.name);
430 PluginPrefs::PolicyStatus group_status =
431 plugin_prefs->PolicyStatusForPlugin(group_name);
432 if (plugin_status == PluginPrefs::POLICY_ENABLED ||
433 group_status == PluginPrefs::POLICY_ENABLED) {
434 enabled_mode = "enabledByPolicy";
435 all_plugins_disabled_by_policy = false;
436 } else {
437 all_plugins_enabled_by_policy = false;
438 if (plugin_status == PluginPrefs::POLICY_DISABLED ||
439 group_status == PluginPrefs::POLICY_DISABLED) {
440 enabled_mode = "disabledByPolicy";
441 } else {
442 all_plugins_disabled_by_policy = false;
443 all_plugins_managed_by_policy = false;
444 if (plugin_enabled) {
445 enabled_mode = "enabledByUser";
446 } else {
447 enabled_mode = "disabledByUser";
451 plugin_file->SetString("enabledMode", enabled_mode);
453 plugin_files->Append(plugin_file);
455 base::DictionaryValue* group_data = new base::DictionaryValue();
457 group_data->Set("plugin_files", plugin_files);
458 group_data->SetString("name", group_name);
459 group_data->SetString("id", group_identifier);
460 group_data->SetString("description", active_plugin->desc);
461 group_data->SetString("version", active_plugin->version);
463 #if defined(ENABLE_PLUGIN_INSTALLATION)
464 bool out_of_date = plugin_metadata->GetSecurityStatus(*active_plugin) ==
465 PluginMetadata::SECURITY_STATUS_OUT_OF_DATE;
466 group_data->SetBoolean("critical", out_of_date);
467 group_data->SetString("update_url", plugin_metadata->plugin_url().spec());
468 #endif
470 std::string enabled_mode;
471 if (all_plugins_enabled_by_policy) {
472 enabled_mode = "enabledByPolicy";
473 } else if (all_plugins_disabled_by_policy) {
474 enabled_mode = "disabledByPolicy";
475 } else if (all_plugins_managed_by_policy) {
476 enabled_mode = "managedByPolicy";
477 } else if (group_enabled) {
478 enabled_mode = "enabledByUser";
479 } else {
480 enabled_mode = "disabledByUser";
482 group_data->SetString("enabledMode", enabled_mode);
484 bool always_allowed = false;
485 if (group_enabled) {
486 const base::DictionaryValue* whitelist =
487 profile->GetPrefs()->GetDictionary(
488 prefs::kContentSettingsPluginWhitelist);
489 whitelist->GetBoolean(group_identifier, &always_allowed);
491 group_data->SetBoolean("alwaysAllowed", always_allowed);
493 plugin_groups_data->Append(group_data);
495 base::DictionaryValue results;
496 results.Set("plugins", plugin_groups_data);
497 web_ui()->CallJavascriptFunction("returnPluginsData", results);
500 } // namespace
502 ///////////////////////////////////////////////////////////////////////////////
504 // PluginsUI
506 ///////////////////////////////////////////////////////////////////////////////
508 PluginsUI::PluginsUI(content::WebUI* web_ui) : WebUIController(web_ui) {
509 web_ui->AddMessageHandler(new PluginsDOMHandler());
511 // Set up the chrome://plugins/ source.
512 Profile* profile = Profile::FromWebUI(web_ui);
513 content::WebUIDataSource::Add(profile, CreatePluginsUIHTMLSource(profile));
516 // static
517 base::RefCountedMemory* PluginsUI::GetFaviconResourceBytes(
518 ui::ScaleFactor scale_factor) {
519 return ResourceBundle::GetSharedInstance().
520 LoadDataResourceBytesForScale(IDR_PLUGINS_FAVICON, scale_factor);
523 // static
524 void PluginsUI::RegisterProfilePrefs(
525 user_prefs::PrefRegistrySyncable* registry) {
526 registry->RegisterBooleanPref(prefs::kPluginsShowDetails, false);
527 registry->RegisterDictionaryPref(
528 prefs::kContentSettingsPluginWhitelist,
529 user_prefs::PrefRegistrySyncable::SYNCABLE_PREF);