Home | History | Annotate | Download | only in browser
      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/plugin_observer.h"
      6 
      7 #include "base/utf_string_conversions.h"
      8 #include "chrome/browser/content_settings/host_content_settings_map.h"
      9 #include "chrome/browser/google/google_util.h"
     10 #include "chrome/browser/metrics/user_metrics.h"
     11 #include "chrome/browser/plugin_installer_infobar_delegate.h"
     12 #include "chrome/browser/profiles/profile.h"
     13 #include "chrome/browser/tab_contents/confirm_infobar_delegate.h"
     14 #include "chrome/browser/tab_contents/simple_alert_infobar_delegate.h"
     15 #include "chrome/common/render_messages.h"
     16 #include "chrome/common/url_constants.h"
     17 #include "content/browser/renderer_host/render_view_host.h"
     18 #include "content/browser/tab_contents/tab_contents.h"
     19 #include "content/common/view_messages.h"
     20 #include "grit/generated_resources.h"
     21 #include "grit/theme_resources.h"
     22 #include "ui/base/l10n/l10n_util.h"
     23 #include "ui/base/resource/resource_bundle.h"
     24 #include "webkit/plugins/npapi/default_plugin_shared.h"
     25 #include "webkit/plugins/npapi/plugin_group.h"
     26 #include "webkit/plugins/npapi/plugin_list.h"
     27 #include "webkit/plugins/npapi/webplugininfo.h"
     28 
     29 namespace {
     30 
     31 // PluginInfoBarDelegate ------------------------------------------------------
     32 
     33 class PluginInfoBarDelegate : public ConfirmInfoBarDelegate {
     34  public:
     35   PluginInfoBarDelegate(TabContents* tab_contents, const string16& name);
     36 
     37  protected:
     38   virtual ~PluginInfoBarDelegate();
     39 
     40   // ConfirmInfoBarDelegate:
     41   virtual void InfoBarClosed();
     42   virtual bool Cancel();
     43   virtual bool LinkClicked(WindowOpenDisposition disposition);
     44 
     45   virtual std::string GetLearnMoreURL() const = 0;
     46 
     47   string16 name_;
     48   TabContents* tab_contents_;
     49 
     50  private:
     51   // ConfirmInfoBarDelegate:
     52   virtual SkBitmap* GetIcon() const;
     53   virtual string16 GetLinkText();
     54 
     55   DISALLOW_COPY_AND_ASSIGN(PluginInfoBarDelegate);
     56 };
     57 
     58 PluginInfoBarDelegate::PluginInfoBarDelegate(TabContents* tab_contents,
     59                                              const string16& name)
     60     : ConfirmInfoBarDelegate(tab_contents),
     61       name_(name),
     62       tab_contents_(tab_contents) {
     63 }
     64 
     65 PluginInfoBarDelegate::~PluginInfoBarDelegate() {
     66 }
     67 
     68 void PluginInfoBarDelegate::InfoBarClosed() {
     69   delete this;
     70 }
     71 
     72 bool PluginInfoBarDelegate::Cancel() {
     73   tab_contents_->render_view_host()->LoadBlockedPlugins();
     74   return true;
     75 }
     76 
     77 bool PluginInfoBarDelegate::LinkClicked(WindowOpenDisposition disposition) {
     78   GURL url = google_util::AppendGoogleLocaleParam(GURL(GetLearnMoreURL()));
     79   tab_contents_->OpenURL(url, GURL(), NEW_FOREGROUND_TAB, PageTransition::LINK);
     80   return false;
     81 }
     82 
     83 SkBitmap* PluginInfoBarDelegate::GetIcon() const {
     84   return ResourceBundle::GetSharedInstance().GetBitmapNamed(
     85       IDR_INFOBAR_PLUGIN_INSTALL);
     86 }
     87 
     88 string16 PluginInfoBarDelegate::GetLinkText() {
     89   return l10n_util::GetStringUTF16(IDS_LEARN_MORE);
     90 }
     91 
     92 
     93 // BlockedPluginInfoBarDelegate -----------------------------------------------
     94 
     95 class BlockedPluginInfoBarDelegate : public PluginInfoBarDelegate {
     96  public:
     97   BlockedPluginInfoBarDelegate(TabContents* tab_contents,
     98                                const string16& name);
     99 
    100  private:
    101   virtual ~BlockedPluginInfoBarDelegate();
    102 
    103   // PluginInfoBarDelegate:
    104   virtual string16 GetMessageText() const;
    105   virtual string16 GetButtonLabel(InfoBarButton button) const;
    106   virtual bool Accept();
    107   virtual bool Cancel();
    108   virtual void InfoBarClosed();
    109   virtual void InfoBarDismissed();
    110   virtual bool LinkClicked(WindowOpenDisposition disposition);
    111   virtual std::string GetLearnMoreURL() const;
    112 
    113   DISALLOW_COPY_AND_ASSIGN(BlockedPluginInfoBarDelegate);
    114 };
    115 
    116 BlockedPluginInfoBarDelegate::BlockedPluginInfoBarDelegate(
    117     TabContents* tab_contents,
    118     const string16& utf16_name)
    119     : PluginInfoBarDelegate(tab_contents, utf16_name) {
    120   UserMetrics::RecordAction(UserMetricsAction("BlockedPluginInfobar.Shown"));
    121   std::string name = UTF16ToUTF8(utf16_name);
    122   if (name == webkit::npapi::PluginGroup::kJavaGroupName)
    123     UserMetrics::RecordAction(
    124         UserMetricsAction("BlockedPluginInfobar.Shown.Java"));
    125   else if (name == webkit::npapi::PluginGroup::kQuickTimeGroupName)
    126     UserMetrics::RecordAction(
    127         UserMetricsAction("BlockedPluginInfobar.Shown.QuickTime"));
    128   else if (name == webkit::npapi::PluginGroup::kShockwaveGroupName)
    129     UserMetrics::RecordAction(
    130         UserMetricsAction("BlockedPluginInfobar.Shown.Shockwave"));
    131   else if (name == webkit::npapi::PluginGroup::kRealPlayerGroupName)
    132     UserMetrics::RecordAction(
    133         UserMetricsAction("BlockedPluginInfobar.Shown.RealPlayer"));
    134 }
    135 
    136 BlockedPluginInfoBarDelegate::~BlockedPluginInfoBarDelegate() {
    137 }
    138 
    139 std::string BlockedPluginInfoBarDelegate::GetLearnMoreURL() const {
    140   return chrome::kBlockedPluginLearnMoreURL;
    141 }
    142 
    143 string16 BlockedPluginInfoBarDelegate::GetMessageText() const {
    144   return l10n_util::GetStringFUTF16(IDS_PLUGIN_NOT_AUTHORIZED, name_);
    145 }
    146 
    147 string16 BlockedPluginInfoBarDelegate::GetButtonLabel(
    148     InfoBarButton button) const {
    149   return l10n_util::GetStringUTF16((button == BUTTON_OK) ?
    150       IDS_PLUGIN_ENABLE_TEMPORARILY : IDS_PLUGIN_ENABLE_ALWAYS);
    151 }
    152 
    153 bool BlockedPluginInfoBarDelegate::Accept() {
    154   UserMetrics::RecordAction(
    155       UserMetricsAction("BlockedPluginInfobar.AllowThisTime"));
    156   return PluginInfoBarDelegate::Cancel();
    157 }
    158 
    159 bool BlockedPluginInfoBarDelegate::Cancel() {
    160   UserMetrics::RecordAction(
    161       UserMetricsAction("BlockedPluginInfobar.AlwaysAllow"));
    162   tab_contents_->profile()->GetHostContentSettingsMap()->AddExceptionForURL(
    163       tab_contents_->GetURL(), CONTENT_SETTINGS_TYPE_PLUGINS, std::string(),
    164       CONTENT_SETTING_ALLOW);
    165   return PluginInfoBarDelegate::Cancel();
    166 }
    167 
    168 void BlockedPluginInfoBarDelegate::InfoBarDismissed() {
    169   UserMetrics::RecordAction(
    170       UserMetricsAction("BlockedPluginInfobar.Dismissed"));
    171 }
    172 
    173 void BlockedPluginInfoBarDelegate::InfoBarClosed() {
    174   UserMetrics::RecordAction(UserMetricsAction("BlockedPluginInfobar.Closed"));
    175   PluginInfoBarDelegate::InfoBarClosed();
    176 }
    177 
    178 bool BlockedPluginInfoBarDelegate::LinkClicked(
    179     WindowOpenDisposition disposition) {
    180   UserMetrics::RecordAction(
    181       UserMetricsAction("BlockedPluginInfobar.LearnMore"));
    182   return PluginInfoBarDelegate::LinkClicked(disposition);
    183 }
    184 
    185 // OutdatedPluginInfoBarDelegate ----------------------------------------------
    186 
    187 class OutdatedPluginInfoBarDelegate : public PluginInfoBarDelegate {
    188  public:
    189   OutdatedPluginInfoBarDelegate(TabContents* tab_contents,
    190                                 const string16& name,
    191                                 const GURL& update_url);
    192 
    193  private:
    194   virtual ~OutdatedPluginInfoBarDelegate();
    195 
    196   // PluginInfoBarDelegate:
    197   virtual string16 GetMessageText() const;
    198   virtual string16 GetButtonLabel(InfoBarButton button) const;
    199   virtual bool Accept();
    200   virtual bool Cancel();
    201   virtual void InfoBarClosed();
    202   virtual void InfoBarDismissed();
    203   virtual bool LinkClicked(WindowOpenDisposition disposition);
    204   virtual std::string GetLearnMoreURL() const;
    205 
    206   GURL update_url_;
    207 
    208   DISALLOW_COPY_AND_ASSIGN(OutdatedPluginInfoBarDelegate);
    209 };
    210 
    211 OutdatedPluginInfoBarDelegate::OutdatedPluginInfoBarDelegate(
    212     TabContents* tab_contents,
    213     const string16& utf16_name,
    214     const GURL& update_url)
    215     : PluginInfoBarDelegate(tab_contents, utf16_name),
    216       update_url_(update_url) {
    217   UserMetrics::RecordAction(UserMetricsAction("OutdatedPluginInfobar.Shown"));
    218   std::string name = UTF16ToUTF8(utf16_name);
    219   if (name == webkit::npapi::PluginGroup::kJavaGroupName)
    220     UserMetrics::RecordAction(
    221         UserMetricsAction("OutdatedPluginInfobar.Shown.Java"));
    222   else if (name == webkit::npapi::PluginGroup::kQuickTimeGroupName)
    223     UserMetrics::RecordAction(
    224         UserMetricsAction("OutdatedPluginInfobar.Shown.QuickTime"));
    225   else if (name == webkit::npapi::PluginGroup::kShockwaveGroupName)
    226     UserMetrics::RecordAction(
    227         UserMetricsAction("OutdatedPluginInfobar.Shown.Shockwave"));
    228   else if (name == webkit::npapi::PluginGroup::kRealPlayerGroupName)
    229     UserMetrics::RecordAction(
    230         UserMetricsAction("OutdatedPluginInfobar.Shown.RealPlayer"));
    231   else if (name == webkit::npapi::PluginGroup::kSilverlightGroupName)
    232     UserMetrics::RecordAction(
    233         UserMetricsAction("OutdatedPluginInfobar.Shown.Silverlight"));
    234   else if (name == webkit::npapi::PluginGroup::kAdobeReaderGroupName)
    235     UserMetrics::RecordAction(
    236         UserMetricsAction("OutdatedPluginInfobar.Shown.Reader"));
    237 }
    238 
    239 OutdatedPluginInfoBarDelegate::~OutdatedPluginInfoBarDelegate() {
    240 }
    241 
    242 std::string OutdatedPluginInfoBarDelegate::GetLearnMoreURL() const {
    243   return chrome::kOutdatedPluginLearnMoreURL;
    244 }
    245 
    246 string16 OutdatedPluginInfoBarDelegate::GetMessageText() const {
    247   return l10n_util::GetStringFUTF16(IDS_PLUGIN_OUTDATED_PROMPT, name_);
    248 }
    249 
    250 string16 OutdatedPluginInfoBarDelegate::GetButtonLabel(
    251     InfoBarButton button) const {
    252   return l10n_util::GetStringUTF16((button == BUTTON_OK) ?
    253       IDS_PLUGIN_UPDATE : IDS_PLUGIN_ENABLE_TEMPORARILY);
    254 }
    255 
    256 bool OutdatedPluginInfoBarDelegate::Accept() {
    257   UserMetrics::RecordAction(UserMetricsAction("OutdatedPluginInfobar.Update"));
    258   tab_contents_->OpenURL(update_url_, GURL(), NEW_FOREGROUND_TAB,
    259                          PageTransition::LINK);
    260   return false;
    261 }
    262 
    263 bool OutdatedPluginInfoBarDelegate::Cancel() {
    264   UserMetrics::RecordAction(
    265       UserMetricsAction("OutdatedPluginInfobar.AllowThisTime"));
    266   return PluginInfoBarDelegate::Cancel();
    267 }
    268 
    269 void OutdatedPluginInfoBarDelegate::InfoBarDismissed() {
    270   UserMetrics::RecordAction(
    271       UserMetricsAction("OutdatedPluginInfobar.Dismissed"));
    272 }
    273 
    274 void OutdatedPluginInfoBarDelegate::InfoBarClosed() {
    275   UserMetrics::RecordAction(UserMetricsAction("OutdatedPluginInfobar.Closed"));
    276   PluginInfoBarDelegate::InfoBarClosed();
    277 }
    278 
    279 bool OutdatedPluginInfoBarDelegate::LinkClicked(
    280     WindowOpenDisposition disposition) {
    281   UserMetrics::RecordAction(
    282       UserMetricsAction("OutdatedPluginInfobar.LearnMore"));
    283   return PluginInfoBarDelegate::LinkClicked(disposition);
    284 }
    285 
    286 }  // namespace
    287 
    288 
    289 // PluginObserver -------------------------------------------------------------
    290 
    291 PluginObserver::PluginObserver(TabContents* tab_contents)
    292     : TabContentsObserver(tab_contents) {
    293 }
    294 
    295 PluginObserver::~PluginObserver() {
    296 }
    297 
    298 bool PluginObserver::OnMessageReceived(const IPC::Message& message) {
    299   IPC_BEGIN_MESSAGE_MAP(PluginObserver, message)
    300     IPC_MESSAGE_HANDLER(ViewHostMsg_MissingPluginStatus, OnMissingPluginStatus)
    301     IPC_MESSAGE_HANDLER(ViewHostMsg_CrashedPlugin, OnCrashedPlugin)
    302     IPC_MESSAGE_HANDLER(ViewHostMsg_BlockedOutdatedPlugin,
    303                         OnBlockedOutdatedPlugin)
    304     IPC_MESSAGE_UNHANDLED(return false)
    305   IPC_END_MESSAGE_MAP()
    306 
    307   return true;
    308 }
    309 
    310 PluginInstallerInfoBarDelegate* PluginObserver::GetPluginInstaller() {
    311   if (plugin_installer_ == NULL)
    312     plugin_installer_.reset(new PluginInstallerInfoBarDelegate(tab_contents()));
    313   return plugin_installer_->AsPluginInstallerInfoBarDelegate();
    314 }
    315 
    316 void PluginObserver::OnMissingPluginStatus(int status) {
    317   // TODO(PORT): pull in when plug-ins work
    318 #if defined(OS_WIN)
    319   if (status == webkit::npapi::default_plugin::MISSING_PLUGIN_AVAILABLE) {
    320     tab_contents()->AddInfoBar(
    321         new PluginInstallerInfoBarDelegate(tab_contents()));
    322     return;
    323   }
    324 
    325   DCHECK_EQ(webkit::npapi::default_plugin::MISSING_PLUGIN_USER_STARTED_DOWNLOAD,
    326             status);
    327   for (size_t i = 0; i < tab_contents()->infobar_count(); ++i) {
    328     InfoBarDelegate* delegate = tab_contents()->GetInfoBarDelegateAt(i);
    329     if (delegate->AsPluginInstallerInfoBarDelegate() != NULL) {
    330       tab_contents()->RemoveInfoBar(delegate);
    331       return;
    332     }
    333   }
    334 #endif
    335 }
    336 
    337 void PluginObserver::OnCrashedPlugin(const FilePath& plugin_path) {
    338   DCHECK(!plugin_path.value().empty());
    339 
    340   string16 plugin_name = plugin_path.LossyDisplayName();
    341   webkit::npapi::WebPluginInfo plugin_info;
    342   if (webkit::npapi::PluginList::Singleton()->GetPluginInfoByPath(
    343           plugin_path, &plugin_info) &&
    344       !plugin_info.name.empty()) {
    345     plugin_name = plugin_info.name;
    346 #if defined(OS_MACOSX)
    347     // Many plugins on the Mac have .plugin in the actual name, which looks
    348     // terrible, so look for that and strip it off if present.
    349     const std::string kPluginExtension = ".plugin";
    350     if (EndsWith(plugin_name, ASCIIToUTF16(kPluginExtension), true))
    351       plugin_name.erase(plugin_name.length() - kPluginExtension.length());
    352 #endif  // OS_MACOSX
    353   }
    354   SkBitmap* crash_icon = ResourceBundle::GetSharedInstance().GetBitmapNamed(
    355       IDR_INFOBAR_PLUGIN_CRASHED);
    356   tab_contents()->AddInfoBar(new SimpleAlertInfoBarDelegate(tab_contents(),
    357       crash_icon,
    358       l10n_util::GetStringFUTF16(IDS_PLUGIN_CRASHED_PROMPT, plugin_name),
    359       true));
    360 }
    361 
    362 void PluginObserver::OnBlockedOutdatedPlugin(const string16& name,
    363                                              const GURL& update_url) {
    364   tab_contents()->AddInfoBar(update_url.is_empty() ?
    365       static_cast<InfoBarDelegate*>(new BlockedPluginInfoBarDelegate(
    366           tab_contents(), name)) :
    367       new OutdatedPluginInfoBarDelegate(tab_contents(), name, update_url));
    368 }
    369 
    370