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