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