Home | History | Annotate | Download | only in webui
      1 // Copyright (c) 2011 The Chromium Authors. All rights reserved.
      2 // Use of this source code is governed by a BSD-style license that can be
      3 // found in the LICENSE file.
      4 
      5 #include "chrome/browser/ui/webui/plugins_ui.h"
      6 
      7 #include <algorithm>
      8 #include <string>
      9 #include <vector>
     10 
     11 #include "base/memory/singleton.h"
     12 #include "base/message_loop.h"
     13 #include "base/path_service.h"
     14 #include "base/utf_string_conversions.h"
     15 #include "base/values.h"
     16 #include "chrome/browser/plugin_updater.h"
     17 #include "chrome/browser/prefs/pref_member.h"
     18 #include "chrome/browser/prefs/pref_service.h"
     19 #include "chrome/browser/profiles/profile.h"
     20 #include "chrome/browser/ui/browser.h"
     21 #include "chrome/browser/ui/browser_window.h"
     22 #include "chrome/browser/ui/webui/chrome_url_data_manager.h"
     23 #include "chrome/common/chrome_content_client.h"
     24 #include "chrome/common/chrome_paths.h"
     25 #include "chrome/common/jstemplate_builder.h"
     26 #include "chrome/common/pref_names.h"
     27 #include "chrome/common/url_constants.h"
     28 #include "content/browser/browser_thread.h"
     29 #include "content/browser/tab_contents/tab_contents.h"
     30 #include "content/common/notification_service.h"
     31 #include "grit/browser_resources.h"
     32 #include "grit/generated_resources.h"
     33 #include "grit/theme_resources.h"
     34 #include "ui/base/l10n/l10n_util.h"
     35 #include "ui/base/resource/resource_bundle.h"
     36 #include "webkit/plugins/npapi/plugin_list.h"
     37 
     38 namespace {
     39 
     40 ///////////////////////////////////////////////////////////////////////////////
     41 //
     42 // PluginsHTMLSource
     43 //
     44 ///////////////////////////////////////////////////////////////////////////////
     45 
     46 class PluginsUIHTMLSource : public ChromeURLDataManager::DataSource {
     47  public:
     48   PluginsUIHTMLSource()
     49       : DataSource(chrome::kChromeUIPluginsHost, MessageLoop::current()) {}
     50 
     51   // Called when the network layer has requested a resource underneath
     52   // the path we registered.
     53   virtual void StartDataRequest(const std::string& path,
     54                                 bool is_incognito,
     55                                 int request_id);
     56   virtual std::string GetMimeType(const std::string&) const {
     57     return "text/html";
     58   }
     59 
     60  private:
     61   ~PluginsUIHTMLSource() {}
     62 
     63   DISALLOW_COPY_AND_ASSIGN(PluginsUIHTMLSource);
     64 };
     65 
     66 void PluginsUIHTMLSource::StartDataRequest(const std::string& path,
     67                                            bool is_incognito,
     68                                            int request_id) {
     69   // Strings used in the JsTemplate file.
     70   DictionaryValue localized_strings;
     71   localized_strings.SetString("pluginsTitle",
     72       l10n_util::GetStringUTF16(IDS_PLUGINS_TITLE));
     73   localized_strings.SetString("pluginsDetailsModeLink",
     74       l10n_util::GetStringUTF16(IDS_PLUGINS_DETAILS_MODE_LINK));
     75   localized_strings.SetString("pluginsNoneInstalled",
     76       l10n_util::GetStringUTF16(IDS_PLUGINS_NONE_INSTALLED));
     77   localized_strings.SetString("pluginDisabled",
     78       l10n_util::GetStringUTF16(IDS_PLUGINS_DISABLED_PLUGIN));
     79   localized_strings.SetString("pluginDisabledByPolicy",
     80       l10n_util::GetStringUTF16(IDS_PLUGINS_DISABLED_BY_POLICY_PLUGIN));
     81   localized_strings.SetString("pluginCannotBeEnabledDueToPolicy",
     82       l10n_util::GetStringUTF16(IDS_PLUGINS_CANNOT_ENABLE_DUE_TO_POLICY));
     83   localized_strings.SetString("pluginEnabledByPolicy",
     84       l10n_util::GetStringUTF16(IDS_PLUGINS_ENABLED_BY_POLICY_PLUGIN));
     85   localized_strings.SetString("pluginCannotBeDisabledDueToPolicy",
     86       l10n_util::GetStringUTF16(IDS_PLUGINS_CANNOT_DISABLE_DUE_TO_POLICY));
     87   localized_strings.SetString("pluginDownload",
     88       l10n_util::GetStringUTF16(IDS_PLUGINS_DOWNLOAD));
     89   localized_strings.SetString("pluginName",
     90       l10n_util::GetStringUTF16(IDS_PLUGINS_NAME));
     91   localized_strings.SetString("pluginVersion",
     92       l10n_util::GetStringUTF16(IDS_PLUGINS_VERSION));
     93   localized_strings.SetString("pluginDescription",
     94       l10n_util::GetStringUTF16(IDS_PLUGINS_DESCRIPTION));
     95   localized_strings.SetString("pluginPath",
     96       l10n_util::GetStringUTF16(IDS_PLUGINS_PATH));
     97   localized_strings.SetString("pluginMimeTypes",
     98       l10n_util::GetStringUTF16(IDS_PLUGINS_MIME_TYPES));
     99   localized_strings.SetString("pluginMimeTypesMimeType",
    100       l10n_util::GetStringUTF16(IDS_PLUGINS_MIME_TYPES_MIME_TYPE));
    101   localized_strings.SetString("pluginMimeTypesDescription",
    102       l10n_util::GetStringUTF16(IDS_PLUGINS_MIME_TYPES_DESCRIPTION));
    103   localized_strings.SetString("pluginMimeTypesFileExtensions",
    104       l10n_util::GetStringUTF16(IDS_PLUGINS_MIME_TYPES_FILE_EXTENSIONS));
    105   localized_strings.SetString("disable",
    106       l10n_util::GetStringUTF16(IDS_PLUGINS_DISABLE));
    107   localized_strings.SetString("enable",
    108       l10n_util::GetStringUTF16(IDS_PLUGINS_ENABLE));
    109   localized_strings.SetString("noPlugins",
    110       l10n_util::GetStringUTF16(IDS_PLUGINS_NO_PLUGINS));
    111 
    112   ChromeURLDataManager::DataSource::SetFontAndTextDirection(&localized_strings);
    113 
    114   static const base::StringPiece plugins_html(
    115       ResourceBundle::GetSharedInstance().GetRawDataResource(IDR_PLUGINS_HTML));
    116   std::string full_html(plugins_html.data(), plugins_html.size());
    117   jstemplate_builder::AppendJsonHtml(&localized_strings, &full_html);
    118   jstemplate_builder::AppendI18nTemplateSourceHtml(&full_html);
    119   jstemplate_builder::AppendI18nTemplateProcessHtml(&full_html);
    120   jstemplate_builder::AppendJsTemplateSourceHtml(&full_html);
    121 
    122   scoped_refptr<RefCountedBytes> html_bytes(new RefCountedBytes);
    123   html_bytes->data.resize(full_html.size());
    124   std::copy(full_html.begin(), full_html.end(), html_bytes->data.begin());
    125 
    126   SendResponse(request_id, html_bytes);
    127 }
    128 
    129 ////////////////////////////////////////////////////////////////////////////////
    130 //
    131 // PluginsDOMHandler
    132 //
    133 ////////////////////////////////////////////////////////////////////////////////
    134 
    135 // The handler for Javascript messages for the chrome://plugins/ page.
    136 // TODO(viettrungluu): Make plugin list updates notify, and then observe
    137 // changes; maybe replumb plugin list through plugin service?
    138 // <http://crbug.com/39101>
    139 class PluginsDOMHandler : public WebUIMessageHandler,
    140                           public NotificationObserver {
    141  public:
    142   explicit PluginsDOMHandler();
    143   virtual ~PluginsDOMHandler() {}
    144 
    145   // WebUIMessageHandler implementation.
    146   virtual WebUIMessageHandler* Attach(WebUI* web_ui);
    147   virtual void RegisterMessages();
    148 
    149   // Callback for the "requestPluginsData" message.
    150   void HandleRequestPluginsData(const ListValue* args);
    151 
    152   // Callback for the "enablePlugin" message.
    153   void HandleEnablePluginMessage(const ListValue* args);
    154 
    155   // Callback for the "showTermsOfService" message. This really just opens a new
    156   // window with about:terms. Flash can't link directly to about:terms due to
    157   // the security model.
    158   void HandleShowTermsOfServiceMessage(const ListValue* args);
    159 
    160   // Callback for the "saveShowDetailsToPrefs" message.
    161   void HandleSaveShowDetailsToPrefs(const ListValue* args);
    162 
    163   // Calback for the "getShowDetails" message.
    164   void HandleGetShowDetails(const ListValue* args);
    165 
    166   // NotificationObserver method overrides
    167   void Observe(NotificationType type,
    168                const NotificationSource& source,
    169                const NotificationDetails& details);
    170 
    171  private:
    172   // This extra wrapper is used to ensure we don't leak the ListValue* pointer
    173   // if the PluginsDOMHandler object goes away before the task on the UI thread
    174   // to give it the plugin list runs.
    175   struct ListWrapper {
    176     ListValue* list;
    177   };
    178   // Loads the plugins on the FILE thread.
    179   static void LoadPluginsOnFileThread(ListWrapper* wrapper, Task* task);
    180 
    181   // Used in conjunction with ListWrapper to avoid any memory leaks.
    182   static void EnsureListDeleted(ListWrapper* wrapper);
    183 
    184   // Call this to start getting the plugins on the UI thread.
    185   void LoadPlugins();
    186 
    187   // Called on the UI thread when the plugin information is ready.
    188   void PluginsLoaded(ListWrapper* wrapper);
    189 
    190   NotificationRegistrar registrar_;
    191 
    192   ScopedRunnableMethodFactory<PluginsDOMHandler> get_plugins_factory_;
    193 
    194   // This pref guards the value whether about:plugins is in the details mode or
    195   // not.
    196   BooleanPrefMember show_details_;
    197 
    198   DISALLOW_COPY_AND_ASSIGN(PluginsDOMHandler);
    199 };
    200 
    201 PluginsDOMHandler::PluginsDOMHandler()
    202     : ALLOW_THIS_IN_INITIALIZER_LIST(get_plugins_factory_(this)) {
    203   registrar_.Add(this,
    204                  NotificationType::PLUGIN_ENABLE_STATUS_CHANGED,
    205                  NotificationService::AllSources());
    206 }
    207 
    208 WebUIMessageHandler* PluginsDOMHandler::Attach(WebUI* web_ui) {
    209   PrefService* prefs = web_ui->GetProfile()->GetPrefs();
    210 
    211   show_details_.Init(prefs::kPluginsShowDetails, prefs, this);
    212 
    213   return WebUIMessageHandler::Attach(web_ui);
    214 }
    215 
    216 void PluginsDOMHandler::RegisterMessages() {
    217   web_ui_->RegisterMessageCallback("requestPluginsData",
    218       NewCallback(this, &PluginsDOMHandler::HandleRequestPluginsData));
    219   web_ui_->RegisterMessageCallback("enablePlugin",
    220       NewCallback(this, &PluginsDOMHandler::HandleEnablePluginMessage));
    221   web_ui_->RegisterMessageCallback("showTermsOfService",
    222       NewCallback(this, &PluginsDOMHandler::HandleShowTermsOfServiceMessage));
    223   web_ui_->RegisterMessageCallback("saveShowDetailsToPrefs",
    224       NewCallback(this, &PluginsDOMHandler::HandleSaveShowDetailsToPrefs));
    225   web_ui_->RegisterMessageCallback("getShowDetails",
    226       NewCallback(this, &PluginsDOMHandler::HandleGetShowDetails));
    227 }
    228 
    229 void PluginsDOMHandler::HandleRequestPluginsData(const ListValue* args) {
    230   LoadPlugins();
    231 }
    232 
    233 void PluginsDOMHandler::HandleEnablePluginMessage(const ListValue* args) {
    234   // Be robust in accepting badness since plug-ins display HTML (hence
    235   // JavaScript).
    236   if (args->GetSize() != 3)
    237     return;
    238 
    239   std::string enable_str;
    240   std::string is_group_str;
    241   if (!args->GetString(1, &enable_str) || !args->GetString(2, &is_group_str))
    242     return;
    243   bool enable = enable_str == "true";
    244 
    245   PluginUpdater* plugin_updater = PluginUpdater::GetInstance();
    246   if (is_group_str == "true") {
    247     string16 group_name;
    248     if (!args->GetString(0, &group_name))
    249       return;
    250 
    251     plugin_updater->EnablePluginGroup(enable, group_name);
    252     if (enable) {
    253       // See http://crbug.com/50105 for background.
    254       string16 adobereader = ASCIIToUTF16(
    255           webkit::npapi::PluginGroup::kAdobeReaderGroupName);
    256       string16 internalpdf =
    257           ASCIIToUTF16(chrome::ChromeContentClient::kPDFPluginName);
    258       if (group_name == adobereader) {
    259         plugin_updater->EnablePluginGroup(false, internalpdf);
    260       } else if (group_name == internalpdf) {
    261         plugin_updater->EnablePluginGroup(false, adobereader);
    262       }
    263     }
    264   } else {
    265     FilePath::StringType file_path;
    266     if (!args->GetString(0, &file_path))
    267       return;
    268 
    269     plugin_updater->EnablePlugin(enable, file_path);
    270   }
    271 
    272   // TODO(viettrungluu): We might also want to ensure that the plugins
    273   // list is always written to prefs even when the user hasn't disabled a
    274   // plugin. <http://crbug.com/39101>
    275   plugin_updater->UpdatePreferences(web_ui_->GetProfile(), 0);
    276 }
    277 
    278 void PluginsDOMHandler::HandleShowTermsOfServiceMessage(const ListValue* args) {
    279   // Show it in a new browser window....
    280   Browser* browser = Browser::Create(web_ui_->GetProfile());
    281   browser->OpenURL(GURL(chrome::kAboutTermsURL),
    282                    GURL(), NEW_FOREGROUND_TAB, PageTransition::LINK);
    283   browser->window()->Show();
    284 }
    285 
    286 void PluginsDOMHandler::HandleSaveShowDetailsToPrefs(const ListValue* args) {
    287   std::string details_mode;
    288   if (!args->GetString(0, &details_mode)) {
    289     NOTREACHED();
    290     return;
    291   }
    292   show_details_.SetValue(details_mode == "true");
    293 }
    294 
    295 void PluginsDOMHandler::HandleGetShowDetails(const ListValue* args) {
    296   FundamentalValue show_details(show_details_.GetValue());
    297   web_ui_->CallJavascriptFunction("loadShowDetailsFromPrefs", show_details);
    298 }
    299 
    300 void PluginsDOMHandler::Observe(NotificationType type,
    301                                 const NotificationSource& source,
    302                                 const NotificationDetails& details) {
    303   DCHECK_EQ(NotificationType::PLUGIN_ENABLE_STATUS_CHANGED, type.value);
    304   LoadPlugins();
    305 }
    306 
    307 void PluginsDOMHandler::LoadPluginsOnFileThread(ListWrapper* wrapper,
    308                                                 Task* task) {
    309   wrapper->list = PluginUpdater::GetInstance()->GetPluginGroupsData();
    310   BrowserThread::PostTask(BrowserThread::UI, FROM_HERE, task);
    311   BrowserThread::PostTask(
    312       BrowserThread::UI,
    313       FROM_HERE,
    314       NewRunnableFunction(&PluginsDOMHandler::EnsureListDeleted, wrapper));
    315 }
    316 
    317 void PluginsDOMHandler::EnsureListDeleted(ListWrapper* wrapper) {
    318   delete wrapper->list;
    319   delete wrapper;
    320 }
    321 
    322 void PluginsDOMHandler::LoadPlugins() {
    323   if (!get_plugins_factory_.empty())
    324     return;
    325 
    326   ListWrapper* wrapper = new ListWrapper;
    327   wrapper->list = NULL;
    328   Task* task = get_plugins_factory_.NewRunnableMethod(
    329           &PluginsDOMHandler::PluginsLoaded, wrapper);
    330 
    331   BrowserThread::PostTask(
    332       BrowserThread::FILE,
    333       FROM_HERE,
    334       NewRunnableFunction(
    335           &PluginsDOMHandler::LoadPluginsOnFileThread, wrapper, task));
    336 }
    337 
    338 void PluginsDOMHandler::PluginsLoaded(ListWrapper* wrapper) {
    339   DictionaryValue results;
    340   results.Set("plugins", wrapper->list);
    341   wrapper->list = NULL;  // So it doesn't get deleted.
    342   web_ui_->CallJavascriptFunction("returnPluginsData", results);
    343 }
    344 
    345 }  // namespace
    346 
    347 ///////////////////////////////////////////////////////////////////////////////
    348 //
    349 // PluginsUI
    350 //
    351 ///////////////////////////////////////////////////////////////////////////////
    352 
    353 PluginsUI::PluginsUI(TabContents* contents) : WebUI(contents) {
    354   AddMessageHandler((new PluginsDOMHandler())->Attach(this));
    355 
    356   PluginsUIHTMLSource* html_source = new PluginsUIHTMLSource();
    357 
    358   // Set up the chrome://plugins/ source.
    359   contents->profile()->GetChromeURLDataManager()->AddDataSource(html_source);
    360 }
    361 
    362 
    363 // static
    364 RefCountedMemory* PluginsUI::GetFaviconResourceBytes() {
    365   return ResourceBundle::GetSharedInstance().
    366       LoadDataResourceBytes(IDR_PLUGIN);
    367 }
    368 
    369 // static
    370 void PluginsUI::RegisterUserPrefs(PrefService* prefs) {
    371   FilePath internal_dir;
    372   PathService::Get(chrome::DIR_INTERNAL_PLUGINS, &internal_dir);
    373   prefs->RegisterFilePathPref(prefs::kPluginsLastInternalDirectory,
    374                               internal_dir);
    375 
    376   prefs->RegisterListPref(prefs::kPluginsDisabledPlugins);
    377   prefs->RegisterListPref(prefs::kPluginsDisabledPluginsExceptions);
    378   prefs->RegisterListPref(prefs::kPluginsEnabledPlugins);
    379   prefs->RegisterListPref(prefs::kPluginsPluginsList);
    380   prefs->RegisterBooleanPref(prefs::kPluginsEnabledInternalPDF, false);
    381   prefs->RegisterBooleanPref(prefs::kPluginsShowDetails, false);
    382   prefs->RegisterBooleanPref(prefs::kPluginsShowSetReaderDefaultInfobar, true);
    383 }
    384