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 29namespace { 30 31// PluginInfoBarDelegate ------------------------------------------------------ 32 33class 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 58PluginInfoBarDelegate::PluginInfoBarDelegate(TabContents* tab_contents, 59 const string16& name) 60 : ConfirmInfoBarDelegate(tab_contents), 61 name_(name), 62 tab_contents_(tab_contents) { 63} 64 65PluginInfoBarDelegate::~PluginInfoBarDelegate() { 66} 67 68void PluginInfoBarDelegate::InfoBarClosed() { 69 delete this; 70} 71 72bool PluginInfoBarDelegate::Cancel() { 73 tab_contents_->render_view_host()->LoadBlockedPlugins(); 74 return true; 75} 76 77bool 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 83SkBitmap* PluginInfoBarDelegate::GetIcon() const { 84 return ResourceBundle::GetSharedInstance().GetBitmapNamed( 85 IDR_INFOBAR_PLUGIN_INSTALL); 86} 87 88string16 PluginInfoBarDelegate::GetLinkText() { 89 return l10n_util::GetStringUTF16(IDS_LEARN_MORE); 90} 91 92 93// BlockedPluginInfoBarDelegate ----------------------------------------------- 94 95class 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 116BlockedPluginInfoBarDelegate::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 136BlockedPluginInfoBarDelegate::~BlockedPluginInfoBarDelegate() { 137} 138 139std::string BlockedPluginInfoBarDelegate::GetLearnMoreURL() const { 140 return chrome::kBlockedPluginLearnMoreURL; 141} 142 143string16 BlockedPluginInfoBarDelegate::GetMessageText() const { 144 return l10n_util::GetStringFUTF16(IDS_PLUGIN_NOT_AUTHORIZED, name_); 145} 146 147string16 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 153bool BlockedPluginInfoBarDelegate::Accept() { 154 UserMetrics::RecordAction( 155 UserMetricsAction("BlockedPluginInfobar.AllowThisTime")); 156 return PluginInfoBarDelegate::Cancel(); 157} 158 159bool 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 168void BlockedPluginInfoBarDelegate::InfoBarDismissed() { 169 UserMetrics::RecordAction( 170 UserMetricsAction("BlockedPluginInfobar.Dismissed")); 171} 172 173void BlockedPluginInfoBarDelegate::InfoBarClosed() { 174 UserMetrics::RecordAction(UserMetricsAction("BlockedPluginInfobar.Closed")); 175 PluginInfoBarDelegate::InfoBarClosed(); 176} 177 178bool BlockedPluginInfoBarDelegate::LinkClicked( 179 WindowOpenDisposition disposition) { 180 UserMetrics::RecordAction( 181 UserMetricsAction("BlockedPluginInfobar.LearnMore")); 182 return PluginInfoBarDelegate::LinkClicked(disposition); 183} 184 185// OutdatedPluginInfoBarDelegate ---------------------------------------------- 186 187class 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 211OutdatedPluginInfoBarDelegate::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 239OutdatedPluginInfoBarDelegate::~OutdatedPluginInfoBarDelegate() { 240} 241 242std::string OutdatedPluginInfoBarDelegate::GetLearnMoreURL() const { 243 return chrome::kOutdatedPluginLearnMoreURL; 244} 245 246string16 OutdatedPluginInfoBarDelegate::GetMessageText() const { 247 return l10n_util::GetStringFUTF16(IDS_PLUGIN_OUTDATED_PROMPT, name_); 248} 249 250string16 OutdatedPluginInfoBarDelegate::GetButtonLabel( 251 InfoBarButton button) const { 252 return l10n_util::GetStringUTF16((button == BUTTON_OK) ? 253 IDS_PLUGIN_UPDATE : IDS_PLUGIN_ENABLE_TEMPORARILY); 254} 255 256bool 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 263bool OutdatedPluginInfoBarDelegate::Cancel() { 264 UserMetrics::RecordAction( 265 UserMetricsAction("OutdatedPluginInfobar.AllowThisTime")); 266 return PluginInfoBarDelegate::Cancel(); 267} 268 269void OutdatedPluginInfoBarDelegate::InfoBarDismissed() { 270 UserMetrics::RecordAction( 271 UserMetricsAction("OutdatedPluginInfobar.Dismissed")); 272} 273 274void OutdatedPluginInfoBarDelegate::InfoBarClosed() { 275 UserMetrics::RecordAction(UserMetricsAction("OutdatedPluginInfobar.Closed")); 276 PluginInfoBarDelegate::InfoBarClosed(); 277} 278 279bool 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 291PluginObserver::PluginObserver(TabContents* tab_contents) 292 : TabContentsObserver(tab_contents) { 293} 294 295PluginObserver::~PluginObserver() { 296} 297 298bool 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 310PluginInstallerInfoBarDelegate* PluginObserver::GetPluginInstaller() { 311 if (plugin_installer_ == NULL) 312 plugin_installer_.reset(new PluginInstallerInfoBarDelegate(tab_contents())); 313 return plugin_installer_->AsPluginInstallerInfoBarDelegate(); 314} 315 316void 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 337void 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 362void 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