| // 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_updater.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/common/chrome_content_client.h" |
| #include "chrome/common/chrome_paths.h" |
| #include "chrome/common/jstemplate_builder.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 "ui/base/l10n/l10n_util.h" |
| #include "ui/base/resource/resource_bundle.h" |
| #include "webkit/plugins/npapi/plugin_list.h" |
| |
| namespace { |
| |
| /////////////////////////////////////////////////////////////////////////////// |
| // |
| // PluginsHTMLSource |
| // |
| /////////////////////////////////////////////////////////////////////////////// |
| |
| class PluginsUIHTMLSource : public ChromeURLDataManager::DataSource { |
| public: |
| PluginsUIHTMLSource() |
| : DataSource(chrome::kChromeUIPluginsHost, MessageLoop::current()) {} |
| |
| // Called when the network layer has requested a resource underneath |
| // the path we registered. |
| virtual void StartDataRequest(const std::string& path, |
| bool is_incognito, |
| int request_id); |
| virtual std::string GetMimeType(const std::string&) const { |
| return "text/html"; |
| } |
| |
| private: |
| ~PluginsUIHTMLSource() {} |
| |
| DISALLOW_COPY_AND_ASSIGN(PluginsUIHTMLSource); |
| }; |
| |
| void PluginsUIHTMLSource::StartDataRequest(const std::string& path, |
| bool is_incognito, |
| int request_id) { |
| // Strings used in the JsTemplate file. |
| DictionaryValue localized_strings; |
| localized_strings.SetString("pluginsTitle", |
| l10n_util::GetStringUTF16(IDS_PLUGINS_TITLE)); |
| localized_strings.SetString("pluginsDetailsModeLink", |
| l10n_util::GetStringUTF16(IDS_PLUGINS_DETAILS_MODE_LINK)); |
| localized_strings.SetString("pluginsNoneInstalled", |
| l10n_util::GetStringUTF16(IDS_PLUGINS_NONE_INSTALLED)); |
| localized_strings.SetString("pluginDisabled", |
| l10n_util::GetStringUTF16(IDS_PLUGINS_DISABLED_PLUGIN)); |
| localized_strings.SetString("pluginDisabledByPolicy", |
| l10n_util::GetStringUTF16(IDS_PLUGINS_DISABLED_BY_POLICY_PLUGIN)); |
| localized_strings.SetString("pluginCannotBeEnabledDueToPolicy", |
| l10n_util::GetStringUTF16(IDS_PLUGINS_CANNOT_ENABLE_DUE_TO_POLICY)); |
| localized_strings.SetString("pluginEnabledByPolicy", |
| l10n_util::GetStringUTF16(IDS_PLUGINS_ENABLED_BY_POLICY_PLUGIN)); |
| localized_strings.SetString("pluginCannotBeDisabledDueToPolicy", |
| l10n_util::GetStringUTF16(IDS_PLUGINS_CANNOT_DISABLE_DUE_TO_POLICY)); |
| localized_strings.SetString("pluginDownload", |
| l10n_util::GetStringUTF16(IDS_PLUGINS_DOWNLOAD)); |
| localized_strings.SetString("pluginName", |
| l10n_util::GetStringUTF16(IDS_PLUGINS_NAME)); |
| localized_strings.SetString("pluginVersion", |
| l10n_util::GetStringUTF16(IDS_PLUGINS_VERSION)); |
| localized_strings.SetString("pluginDescription", |
| l10n_util::GetStringUTF16(IDS_PLUGINS_DESCRIPTION)); |
| localized_strings.SetString("pluginPath", |
| l10n_util::GetStringUTF16(IDS_PLUGINS_PATH)); |
| localized_strings.SetString("pluginMimeTypes", |
| l10n_util::GetStringUTF16(IDS_PLUGINS_MIME_TYPES)); |
| localized_strings.SetString("pluginMimeTypesMimeType", |
| l10n_util::GetStringUTF16(IDS_PLUGINS_MIME_TYPES_MIME_TYPE)); |
| localized_strings.SetString("pluginMimeTypesDescription", |
| l10n_util::GetStringUTF16(IDS_PLUGINS_MIME_TYPES_DESCRIPTION)); |
| localized_strings.SetString("pluginMimeTypesFileExtensions", |
| l10n_util::GetStringUTF16(IDS_PLUGINS_MIME_TYPES_FILE_EXTENSIONS)); |
| localized_strings.SetString("disable", |
| l10n_util::GetStringUTF16(IDS_PLUGINS_DISABLE)); |
| localized_strings.SetString("enable", |
| l10n_util::GetStringUTF16(IDS_PLUGINS_ENABLE)); |
| localized_strings.SetString("noPlugins", |
| l10n_util::GetStringUTF16(IDS_PLUGINS_NO_PLUGINS)); |
| |
| ChromeURLDataManager::DataSource::SetFontAndTextDirection(&localized_strings); |
| |
| static const base::StringPiece plugins_html( |
| ResourceBundle::GetSharedInstance().GetRawDataResource(IDR_PLUGINS_HTML)); |
| std::string full_html(plugins_html.data(), plugins_html.size()); |
| jstemplate_builder::AppendJsonHtml(&localized_strings, &full_html); |
| jstemplate_builder::AppendI18nTemplateSourceHtml(&full_html); |
| jstemplate_builder::AppendI18nTemplateProcessHtml(&full_html); |
| jstemplate_builder::AppendJsTemplateSourceHtml(&full_html); |
| |
| scoped_refptr<RefCountedBytes> html_bytes(new RefCountedBytes); |
| html_bytes->data.resize(full_html.size()); |
| std::copy(full_html.begin(), full_html.end(), html_bytes->data.begin()); |
| |
| SendResponse(request_id, html_bytes); |
| } |
| |
| //////////////////////////////////////////////////////////////////////////////// |
| // |
| // 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); |
| virtual void RegisterMessages(); |
| |
| // Callback for the "requestPluginsData" message. |
| void HandleRequestPluginsData(const ListValue* args); |
| |
| // Callback for the "enablePlugin" message. |
| void HandleEnablePluginMessage(const ListValue* args); |
| |
| // Callback for the "showTermsOfService" message. This really just opens a new |
| // window with about:terms. Flash can't link directly to about:terms due to |
| // the security model. |
| void HandleShowTermsOfServiceMessage(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 |
| void Observe(NotificationType type, |
| const NotificationSource& source, |
| const NotificationDetails& details); |
| |
| private: |
| // This extra wrapper is used to ensure we don't leak the ListValue* pointer |
| // if the PluginsDOMHandler object goes away before the task on the UI thread |
| // to give it the plugin list runs. |
| struct ListWrapper { |
| ListValue* list; |
| }; |
| // Loads the plugins on the FILE thread. |
| static void LoadPluginsOnFileThread(ListWrapper* wrapper, Task* task); |
| |
| // Used in conjunction with ListWrapper to avoid any memory leaks. |
| static void EnsureListDeleted(ListWrapper* wrapper); |
| |
| // 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(ListWrapper* wrapper); |
| |
| 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, |
| NotificationType::PLUGIN_ENABLE_STATUS_CHANGED, |
| NotificationService::AllSources()); |
| } |
| |
| WebUIMessageHandler* PluginsDOMHandler::Attach(WebUI* web_ui) { |
| PrefService* prefs = web_ui->GetProfile()->GetPrefs(); |
| |
| show_details_.Init(prefs::kPluginsShowDetails, prefs, this); |
| |
| 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("showTermsOfService", |
| NewCallback(this, &PluginsDOMHandler::HandleShowTermsOfServiceMessage)); |
| 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) { |
| // 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"; |
| |
| PluginUpdater* plugin_updater = PluginUpdater::GetInstance(); |
| if (is_group_str == "true") { |
| string16 group_name; |
| if (!args->GetString(0, &group_name)) |
| return; |
| |
| plugin_updater->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_updater->EnablePluginGroup(false, internalpdf); |
| } else if (group_name == internalpdf) { |
| plugin_updater->EnablePluginGroup(false, adobereader); |
| } |
| } |
| } else { |
| FilePath::StringType file_path; |
| if (!args->GetString(0, &file_path)) |
| return; |
| |
| plugin_updater->EnablePlugin(enable, 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_updater->UpdatePreferences(web_ui_->GetProfile(), 0); |
| } |
| |
| void PluginsDOMHandler::HandleShowTermsOfServiceMessage(const ListValue* args) { |
| // Show it in a new browser window.... |
| Browser* browser = Browser::Create(web_ui_->GetProfile()); |
| browser->OpenURL(GURL(chrome::kAboutTermsURL), |
| GURL(), NEW_FOREGROUND_TAB, PageTransition::LINK); |
| browser->window()->Show(); |
| } |
| |
| 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(NotificationType type, |
| const NotificationSource& source, |
| const NotificationDetails& details) { |
| DCHECK_EQ(NotificationType::PLUGIN_ENABLE_STATUS_CHANGED, type.value); |
| LoadPlugins(); |
| } |
| |
| void PluginsDOMHandler::LoadPluginsOnFileThread(ListWrapper* wrapper, |
| Task* task) { |
| wrapper->list = PluginUpdater::GetInstance()->GetPluginGroupsData(); |
| BrowserThread::PostTask(BrowserThread::UI, FROM_HERE, task); |
| BrowserThread::PostTask( |
| BrowserThread::UI, |
| FROM_HERE, |
| NewRunnableFunction(&PluginsDOMHandler::EnsureListDeleted, wrapper)); |
| } |
| |
| void PluginsDOMHandler::EnsureListDeleted(ListWrapper* wrapper) { |
| delete wrapper->list; |
| delete wrapper; |
| } |
| |
| void PluginsDOMHandler::LoadPlugins() { |
| if (!get_plugins_factory_.empty()) |
| return; |
| |
| ListWrapper* wrapper = new ListWrapper; |
| wrapper->list = NULL; |
| Task* task = get_plugins_factory_.NewRunnableMethod( |
| &PluginsDOMHandler::PluginsLoaded, wrapper); |
| |
| BrowserThread::PostTask( |
| BrowserThread::FILE, |
| FROM_HERE, |
| NewRunnableFunction( |
| &PluginsDOMHandler::LoadPluginsOnFileThread, wrapper, task)); |
| } |
| |
| void PluginsDOMHandler::PluginsLoaded(ListWrapper* wrapper) { |
| DictionaryValue results; |
| results.Set("plugins", wrapper->list); |
| wrapper->list = NULL; // So it doesn't get deleted. |
| web_ui_->CallJavascriptFunction("returnPluginsData", results); |
| } |
| |
| } // namespace |
| |
| /////////////////////////////////////////////////////////////////////////////// |
| // |
| // PluginsUI |
| // |
| /////////////////////////////////////////////////////////////////////////////// |
| |
| PluginsUI::PluginsUI(TabContents* contents) : WebUI(contents) { |
| AddMessageHandler((new PluginsDOMHandler())->Attach(this)); |
| |
| PluginsUIHTMLSource* html_source = new PluginsUIHTMLSource(); |
| |
| // Set up the chrome://plugins/ source. |
| contents->profile()->GetChromeURLDataManager()->AddDataSource(html_source); |
| } |
| |
| |
| // static |
| RefCountedMemory* PluginsUI::GetFaviconResourceBytes() { |
| return ResourceBundle::GetSharedInstance(). |
| LoadDataResourceBytes(IDR_PLUGIN); |
| } |
| |
| // static |
| void PluginsUI::RegisterUserPrefs(PrefService* prefs) { |
| FilePath internal_dir; |
| PathService::Get(chrome::DIR_INTERNAL_PLUGINS, &internal_dir); |
| prefs->RegisterFilePathPref(prefs::kPluginsLastInternalDirectory, |
| internal_dir); |
| |
| prefs->RegisterListPref(prefs::kPluginsDisabledPlugins); |
| prefs->RegisterListPref(prefs::kPluginsDisabledPluginsExceptions); |
| prefs->RegisterListPref(prefs::kPluginsEnabledPlugins); |
| prefs->RegisterListPref(prefs::kPluginsPluginsList); |
| prefs->RegisterBooleanPref(prefs::kPluginsEnabledInternalPDF, false); |
| prefs->RegisterBooleanPref(prefs::kPluginsShowDetails, false); |
| prefs->RegisterBooleanPref(prefs::kPluginsShowSetReaderDefaultInfobar, true); |
| } |