• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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:
PluginsUIHTMLSource()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);
GetMimeType(const std::string &) const56   virtual std::string GetMimeType(const std::string&) const {
57     return "text/html";
58   }
59 
60  private:
~PluginsUIHTMLSource()61   ~PluginsUIHTMLSource() {}
62 
63   DISALLOW_COPY_AND_ASSIGN(PluginsUIHTMLSource);
64 };
65 
StartDataRequest(const std::string & path,bool is_incognito,int request_id)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();
~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 
PluginsDOMHandler()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 
Attach(WebUI * web_ui)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 
RegisterMessages()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 
HandleRequestPluginsData(const ListValue * args)229 void PluginsDOMHandler::HandleRequestPluginsData(const ListValue* args) {
230   LoadPlugins();
231 }
232 
HandleEnablePluginMessage(const ListValue * args)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 
HandleShowTermsOfServiceMessage(const ListValue * args)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 
HandleSaveShowDetailsToPrefs(const ListValue * args)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 
HandleGetShowDetails(const ListValue * args)295 void PluginsDOMHandler::HandleGetShowDetails(const ListValue* args) {
296   FundamentalValue show_details(show_details_.GetValue());
297   web_ui_->CallJavascriptFunction("loadShowDetailsFromPrefs", show_details);
298 }
299 
Observe(NotificationType type,const NotificationSource & source,const NotificationDetails & details)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 
LoadPluginsOnFileThread(ListWrapper * wrapper,Task * task)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 
EnsureListDeleted(ListWrapper * wrapper)317 void PluginsDOMHandler::EnsureListDeleted(ListWrapper* wrapper) {
318   delete wrapper->list;
319   delete wrapper;
320 }
321 
LoadPlugins()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 
PluginsLoaded(ListWrapper * wrapper)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 
PluginsUI(TabContents * contents)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
GetFaviconResourceBytes()364 RefCountedMemory* PluginsUI::GetFaviconResourceBytes() {
365   return ResourceBundle::GetSharedInstance().
366       LoadDataResourceBytes(IDR_PLUGIN);
367 }
368 
369 // static
RegisterUserPrefs(PrefService * prefs)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