blob: 015e8ead6bde64f0d252bab81d027f6d19202090 [file] [log] [blame]
// Copyright (c) 2011 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "chrome/browser/ui/webui/plugins_ui.h"
#include <algorithm>
#include <string>
#include <vector>
#include "base/memory/singleton.h"
#include "base/message_loop.h"
#include "base/path_service.h"
#include "base/utf_string_conversions.h"
#include "base/values.h"
#include "chrome/browser/plugin_prefs.h"
#include "chrome/browser/prefs/pref_member.h"
#include "chrome/browser/prefs/pref_service.h"
#include "chrome/browser/profiles/profile.h"
#include "chrome/browser/ui/browser.h"
#include "chrome/browser/ui/browser_window.h"
#include "chrome/browser/ui/webui/chrome_url_data_manager.h"
#include "chrome/browser/ui/webui/chrome_web_ui_data_source.h"
#include "chrome/common/chrome_content_client.h"
#include "chrome/common/chrome_paths.h"
#include "chrome/common/pref_names.h"
#include "chrome/common/url_constants.h"
#include "content/browser/browser_thread.h"
#include "content/browser/tab_contents/tab_contents.h"
#include "content/common/notification_service.h"
#include "grit/browser_resources.h"
#include "grit/generated_resources.h"
#include "grit/theme_resources.h"
#include "grit/theme_resources_standard.h"
#include "ui/base/resource/resource_bundle.h"
#include "webkit/plugins/npapi/plugin_list.h"
namespace {
ChromeWebUIDataSource* CreatePluginsUIHTMLSource(bool enable_controls) {
ChromeWebUIDataSource* source =
new ChromeWebUIDataSource(chrome::kChromeUIPluginsHost);
source->AddLocalizedString("pluginsTitle", IDS_PLUGINS_TITLE);
source->AddLocalizedString("pluginsDetailsModeLink",
IDS_PLUGINS_DETAILS_MODE_LINK);
source->AddLocalizedString("pluginsNoneInstalled",
IDS_PLUGINS_NONE_INSTALLED);
source->AddLocalizedString("pluginDisabled", IDS_PLUGINS_DISABLED_PLUGIN);
source->AddLocalizedString("pluginDisabledByPolicy",
IDS_PLUGINS_DISABLED_BY_POLICY_PLUGIN);
source->AddLocalizedString("pluginCannotBeEnabledDueToPolicy",
IDS_PLUGINS_CANNOT_ENABLE_DUE_TO_POLICY);
source->AddLocalizedString("pluginEnabledByPolicy",
IDS_PLUGINS_ENABLED_BY_POLICY_PLUGIN);
source->AddLocalizedString("pluginCannotBeDisabledDueToPolicy",
IDS_PLUGINS_CANNOT_DISABLE_DUE_TO_POLICY);
source->AddLocalizedString("pluginDownload", IDS_PLUGINS_DOWNLOAD);
source->AddLocalizedString("pluginName", IDS_PLUGINS_NAME);
source->AddLocalizedString("pluginVersion", IDS_PLUGINS_VERSION);
source->AddLocalizedString("pluginDescription", IDS_PLUGINS_DESCRIPTION);
source->AddLocalizedString("pluginPath", IDS_PLUGINS_PATH);
source->AddLocalizedString("pluginMimeTypes", IDS_PLUGINS_MIME_TYPES);
source->AddLocalizedString("pluginMimeTypesMimeType",
IDS_PLUGINS_MIME_TYPES_MIME_TYPE);
source->AddLocalizedString("pluginMimeTypesDescription",
IDS_PLUGINS_MIME_TYPES_DESCRIPTION);
source->AddLocalizedString("pluginMimeTypesFileExtensions",
IDS_PLUGINS_MIME_TYPES_FILE_EXTENSIONS);
source->AddLocalizedString("disable", IDS_PLUGINS_DISABLE);
source->AddLocalizedString("enable", IDS_PLUGINS_ENABLE);
source->AddLocalizedString("noPlugins", IDS_PLUGINS_NO_PLUGINS);
if (!enable_controls) {
source->AddLocalizedString("pluginsDisabledHeader",
IDS_PLUGINS_DISABLED_HEADER);
source->AddLocalizedString("pluginsDisabledText",
IDS_PLUGINS_DISABLED_TEXT);
}
source->set_json_path("strings.js");
source->add_resource_path("plugins.js", IDR_PLUGINS_JS);
source->set_default_resource(IDR_PLUGINS_HTML);
return source;
}
////////////////////////////////////////////////////////////////////////////////
//
// PluginsDOMHandler
//
////////////////////////////////////////////////////////////////////////////////
// The handler for Javascript messages for the chrome://plugins/ page.
// TODO(viettrungluu): Make plugin list updates notify, and then observe
// changes; maybe replumb plugin list through plugin service?
// <http://crbug.com/39101>
class PluginsDOMHandler : public WebUIMessageHandler,
public NotificationObserver {
public:
explicit PluginsDOMHandler();
virtual ~PluginsDOMHandler() {}
// WebUIMessageHandler implementation.
virtual WebUIMessageHandler* Attach(WebUI* web_ui) OVERRIDE;
virtual void RegisterMessages() OVERRIDE;
// Callback for the "requestPluginsData" message.
void HandleRequestPluginsData(const ListValue* args);
// Callback for the "enablePlugin" message.
void HandleEnablePluginMessage(const ListValue* args);
// Callback for the "saveShowDetailsToPrefs" message.
void HandleSaveShowDetailsToPrefs(const ListValue* args);
// Calback for the "getShowDetails" message.
void HandleGetShowDetails(const ListValue* args);
// NotificationObserver method overrides
virtual void Observe(int type,
const NotificationSource& source,
const NotificationDetails& details) OVERRIDE;
private:
// Loads the plugins on the FILE thread.
static void LoadPluginsOnFileThread(
std::vector<webkit::npapi::PluginGroup>* groups, Task* task);
// Used in conjunction with ListWrapper to avoid any memory leaks.
static void EnsurePluginGroupsDeleted(
std::vector<webkit::npapi::PluginGroup>* groups);
// Call this to start getting the plugins on the UI thread.
void LoadPlugins();
// Called on the UI thread when the plugin information is ready.
void PluginsLoaded(const std::vector<webkit::npapi::PluginGroup>* groups);
NotificationRegistrar registrar_;
ScopedRunnableMethodFactory<PluginsDOMHandler> get_plugins_factory_;
// This pref guards the value whether about:plugins is in the details mode or
// not.
BooleanPrefMember show_details_;
DISALLOW_COPY_AND_ASSIGN(PluginsDOMHandler);
};
PluginsDOMHandler::PluginsDOMHandler()
: ALLOW_THIS_IN_INITIALIZER_LIST(get_plugins_factory_(this)) {
registrar_.Add(this,
content::NOTIFICATION_PLUGIN_ENABLE_STATUS_CHANGED,
NotificationService::AllSources());
}
WebUIMessageHandler* PluginsDOMHandler::Attach(WebUI* web_ui) {
PrefService* prefs = web_ui->GetProfile()->GetPrefs();
show_details_.Init(prefs::kPluginsShowDetails, prefs, NULL);
return WebUIMessageHandler::Attach(web_ui);
}
void PluginsDOMHandler::RegisterMessages() {
web_ui_->RegisterMessageCallback("requestPluginsData",
NewCallback(this, &PluginsDOMHandler::HandleRequestPluginsData));
web_ui_->RegisterMessageCallback("enablePlugin",
NewCallback(this, &PluginsDOMHandler::HandleEnablePluginMessage));
web_ui_->RegisterMessageCallback("saveShowDetailsToPrefs",
NewCallback(this, &PluginsDOMHandler::HandleSaveShowDetailsToPrefs));
web_ui_->RegisterMessageCallback("getShowDetails",
NewCallback(this, &PluginsDOMHandler::HandleGetShowDetails));
}
void PluginsDOMHandler::HandleRequestPluginsData(const ListValue* args) {
LoadPlugins();
}
void PluginsDOMHandler::HandleEnablePluginMessage(const ListValue* args) {
// If a non-first-profile user tries to trigger these methods sneakily,
// forbid it.
#if !defined(OS_CHROMEOS)
if (!web_ui_->GetProfile()->GetOriginalProfile()->first_launched())
return;
#endif
// Be robust in accepting badness since plug-ins display HTML (hence
// JavaScript).
if (args->GetSize() != 3)
return;
std::string enable_str;
std::string is_group_str;
if (!args->GetString(1, &enable_str) || !args->GetString(2, &is_group_str))
return;
bool enable = enable_str == "true";
PluginPrefs* plugin_prefs = PluginPrefs::GetForProfile(web_ui_->GetProfile());
if (is_group_str == "true") {
string16 group_name;
if (!args->GetString(0, &group_name))
return;
plugin_prefs->EnablePluginGroup(enable, group_name);
if (enable) {
// See http://crbug.com/50105 for background.
string16 adobereader = ASCIIToUTF16(
webkit::npapi::PluginGroup::kAdobeReaderGroupName);
string16 internalpdf =
ASCIIToUTF16(chrome::ChromeContentClient::kPDFPluginName);
if (group_name == adobereader) {
plugin_prefs->EnablePluginGroup(false, internalpdf);
} else if (group_name == internalpdf) {
plugin_prefs->EnablePluginGroup(false, adobereader);
}
}
} else {
FilePath::StringType file_path;
if (!args->GetString(0, &file_path))
return;
plugin_prefs->EnablePlugin(enable, FilePath(file_path));
}
// TODO(viettrungluu): We might also want to ensure that the plugins
// list is always written to prefs even when the user hasn't disabled a
// plugin. <http://crbug.com/39101>
plugin_prefs->UpdatePreferences(0);
}
void PluginsDOMHandler::HandleSaveShowDetailsToPrefs(const ListValue* args) {
std::string details_mode;
if (!args->GetString(0, &details_mode)) {
NOTREACHED();
return;
}
show_details_.SetValue(details_mode == "true");
}
void PluginsDOMHandler::HandleGetShowDetails(const ListValue* args) {
FundamentalValue show_details(show_details_.GetValue());
web_ui_->CallJavascriptFunction("loadShowDetailsFromPrefs", show_details);
}
void PluginsDOMHandler::Observe(int type,
const NotificationSource& source,
const NotificationDetails& details) {
DCHECK_EQ(content::NOTIFICATION_PLUGIN_ENABLE_STATUS_CHANGED, type);
LoadPlugins();
}
void PluginsDOMHandler::LoadPluginsOnFileThread(
std::vector<webkit::npapi::PluginGroup>* groups,
Task* task) {
webkit::npapi::PluginList::Singleton()->GetPluginGroups(true, groups);
BrowserThread::PostTask(BrowserThread::UI, FROM_HERE, task);
BrowserThread::PostTask(
BrowserThread::UI,
FROM_HERE,
NewRunnableFunction(&PluginsDOMHandler::EnsurePluginGroupsDeleted,
groups));
}
void PluginsDOMHandler::EnsurePluginGroupsDeleted(
std::vector<webkit::npapi::PluginGroup>* groups) {
delete groups;
}
void PluginsDOMHandler::LoadPlugins() {
if (!get_plugins_factory_.empty())
return;
std::vector<webkit::npapi::PluginGroup>* groups =
new std::vector<webkit::npapi::PluginGroup>;
Task* task = get_plugins_factory_.NewRunnableMethod(
&PluginsDOMHandler::PluginsLoaded, groups);
BrowserThread::PostTask(
BrowserThread::FILE,
FROM_HERE,
NewRunnableFunction(
&PluginsDOMHandler::LoadPluginsOnFileThread, groups, task));
}
void PluginsDOMHandler::PluginsLoaded(
const std::vector<webkit::npapi::PluginGroup>* groups) {
// Construct DictionaryValues to return to the UI
ListValue* plugin_groups_data = new ListValue();
for (size_t i = 0; i < groups->size(); ++i) {
plugin_groups_data->Append((*groups)[i].GetDataForUI());
// TODO(bauerb): Fetch plugin enabled state from PluginPrefs.
}
DictionaryValue results;
results.Set("plugins", plugin_groups_data);
web_ui_->CallJavascriptFunction("returnPluginsData", results);
}
} // namespace
///////////////////////////////////////////////////////////////////////////////
//
// PluginsUI
//
///////////////////////////////////////////////////////////////////////////////
PluginsUI::PluginsUI(TabContents* contents) : ChromeWebUI(contents) {
AddMessageHandler((new PluginsDOMHandler())->Attach(this));
// Set up the chrome://plugins/ source.
bool enable_controls = true;
Profile* profile = Profile::FromBrowserContext(contents->browser_context());
#if !defined(OS_CHROMEOS)
enable_controls = profile->GetOriginalProfile()->first_launched();
#endif
profile->GetChromeURLDataManager()->AddDataSource(
CreatePluginsUIHTMLSource(enable_controls));
}
// static
RefCountedMemory* PluginsUI::GetFaviconResourceBytes() {
return ResourceBundle::GetSharedInstance().
LoadDataResourceBytes(IDR_PLUGIN);
}
// static
void PluginsUI::RegisterUserPrefs(PrefService* prefs) {
prefs->RegisterListPref(prefs::kPluginsPluginsList,
PrefService::UNSYNCABLE_PREF);
prefs->RegisterBooleanPref(prefs::kPluginsEnabledInternalPDF,
false,
PrefService::UNSYNCABLE_PREF);
prefs->RegisterBooleanPref(prefs::kPluginsShowDetails,
false,
PrefService::UNSYNCABLE_PREF);
prefs->RegisterBooleanPref(prefs::kPluginsShowSetReaderDefaultInfobar,
true,
PrefService::UNSYNCABLE_PREF);
}