blob: 2846737a61ee74b77aa6e6c0a66c759dc8f01e1c [file] [log] [blame]
Avi Drissman4e1b7bc32022-09-15 14:03:501// Copyright 2012 The Chromium Authors
license.botbf09a502008-08-24 00:55:552// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
initial.commitf5b16fe2008-07-27 00:20:514
Lei Zhangd8c53182019-02-06 22:24:395#include "content/browser/plugin_list.h"
initial.commitf5b16fe2008-07-27 00:20:516
avia9aa7a82015-12-25 03:06:317#include <stddef.h>
8
Peter Kasting1557e5f2025-01-28 01:14:089#include <algorithm>
Md Hasibul Hasana963a9342024-04-03 10:15:1410#include <string_view>
11
Hans Wennborg0917de892020-04-28 20:21:1512#include "base/check.h"
[email protected]3c0c0bf52010-06-25 06:05:0913#include "base/command_line.h"
Lei Zhangde197672021-04-29 08:11:2414#include "base/containers/contains.h"
[email protected]19537112009-01-21 19:38:1415#include "base/lazy_instance.h"
[email protected]d778e0422013-03-06 18:10:2216#include "base/strings/string_split.h"
[email protected]f63582d2013-06-11 22:52:5417#include "base/strings/string_util.h"
[email protected]13ac53532013-03-30 00:27:0018#include "base/strings/sys_string_conversions.h"
[email protected]906265872013-06-07 22:40:4519#include "base/strings/utf_string_conversions.h"
avia9aa7a82015-12-25 03:06:3120#include "build/build_config.h"
Lei Zhang8403fa62022-10-12 20:15:2621#include "content/public/browser/browser_thread.h"
[email protected]1bbbc492013-08-09 00:36:1522#include "content/public/common/content_switches.h"
[email protected]b7344502009-01-12 19:43:4423#include "net/base/mime_util.h"
[email protected]ad677772013-06-29 14:18:3824#include "url/gurl.h"
initial.commitf5b16fe2008-07-27 00:20:5125
[email protected]29e2fb42013-07-19 01:13:4726namespace content {
27
28namespace {
[email protected]0b300172012-09-27 16:11:5229
scottmg5e65e3a2017-03-08 08:48:4630base::LazyInstance<PluginList>::DestructorAtExit g_singleton =
31 LAZY_INSTANCE_INITIALIZER;
[email protected]123a04962011-11-03 15:43:0132
Lei Zhanga2eb18782018-08-15 18:09:2133// Returns true if the plugin supports |mime_type|. |mime_type| should be all
34// lower case.
35bool SupportsType(const WebPluginInfo& plugin,
36 const std::string& mime_type,
37 bool allow_wildcard) {
38 // Webkit will ask for a plugin to handle empty mime types.
39 if (mime_type.empty())
40 return false;
41
Lei Zhang41da87852019-02-07 00:45:3042 for (const WebPluginMimeType& mime_info : plugin.mime_types) {
Lei Zhanga2eb18782018-08-15 18:09:2143 if (net::MatchesMimeType(mime_info.mime_type, mime_type)) {
Lei Zhang41da87852019-02-07 00:45:3044 if (allow_wildcard || mime_info.mime_type != "*")
45 return true;
Lei Zhanga2eb18782018-08-15 18:09:2146 }
47 }
48 return false;
49}
50
51// Returns true if the given plugin supports a given file extension.
52// |extension| should be all lower case. |actual_mime_type| will be set to the
53// MIME type if found. The MIME type which corresponds to the extension is
54// optionally returned back.
55bool SupportsExtension(const WebPluginInfo& plugin,
56 const std::string& extension,
57 std::string* actual_mime_type) {
Lei Zhang41da87852019-02-07 00:45:3058 for (const WebPluginMimeType& mime_type : plugin.mime_types) {
59 for (const std::string& file_extension : mime_type.file_extensions) {
60 if (file_extension == extension) {
Lei Zhanga2eb18782018-08-15 18:09:2161 *actual_mime_type = mime_type.mime_type;
62 return true;
63 }
64 }
65 }
66 return false;
67}
68
[email protected]3b91edbe2012-09-27 22:49:2369} // namespace
[email protected]123a04962011-11-03 15:43:0170
[email protected]19537112009-01-21 19:38:1471// static
initial.commitf5b16fe2008-07-27 00:20:5172PluginList* PluginList::Singleton() {
Lei Zhang8403fa62022-10-12 20:15:2673 DCHECK_CURRENTLY_ON(BrowserThread::UI);
[email protected]35fa6a22009-08-15 00:04:0174 return g_singleton.Pointer();
initial.commitf5b16fe2008-07-27 00:20:5175}
76
[email protected]4e59e812010-04-06 20:51:1677void PluginList::RefreshPlugins() {
Lei Zhang8403fa62022-10-12 20:15:2678 DCHECK_CURRENTLY_ON(BrowserThread::UI);
[email protected]a33fa9d2012-05-16 14:47:4979 loading_state_ = LOADING_STATE_NEEDS_REFRESH;
[email protected]367230c52009-02-21 01:44:3080}
initial.commitf5b16fe2008-07-27 00:20:5181
[email protected]d7bd3e52013-07-21 04:29:2082void PluginList::RegisterInternalPlugin(const WebPluginInfo& info,
[email protected]c6f3dea2012-01-14 02:23:1183 bool add_at_beginning) {
Lei Zhang8403fa62022-10-12 20:15:2684 DCHECK_CURRENTLY_ON(BrowserThread::UI);
[email protected]8ca37f42011-11-02 16:03:4185
[email protected]fee3a98b2013-07-18 18:12:4886 internal_plugins_.push_back(info);
[email protected]8ca37f42011-11-02 16:03:4187 if (add_at_beginning) {
88 // Newer registrations go earlier in the list so they can override the MIME
89 // types of older registrations.
[email protected]c6f3dea2012-01-14 02:23:1190 extra_plugin_paths_.insert(extra_plugin_paths_.begin(), info.path);
[email protected]8ca37f42011-11-02 16:03:4191 } else {
[email protected]c6f3dea2012-01-14 02:23:1192 extra_plugin_paths_.push_back(info.path);
[email protected]8ca37f42011-11-02 16:03:4193 }
[email protected]f99c73ad2011-01-11 00:43:4494}
95
[email protected]a3ef4832013-02-02 05:12:3396void PluginList::UnregisterInternalPlugin(const base::FilePath& path) {
Lei Zhang8403fa62022-10-12 20:15:2697 DCHECK_CURRENTLY_ON(BrowserThread::UI);
98
[email protected]797d9a62013-09-13 23:36:0799 bool found = false;
[email protected]00c39612010-03-06 02:53:28100 for (size_t i = 0; i < internal_plugins_.size(); i++) {
[email protected]fee3a98b2013-07-18 18:12:48101 if (internal_plugins_[i].path == path) {
[email protected]00c39612010-03-06 02:53:28102 internal_plugins_.erase(internal_plugins_.begin() + i);
[email protected]797d9a62013-09-13 23:36:07103 found = true;
104 break;
[email protected]00c39612010-03-06 02:53:28105 }
106 }
[email protected]797d9a62013-09-13 23:36:07107 DCHECK(found);
Lei Zhang8403fa62022-10-12 20:15:26108 RemoveExtraPluginPath(path);
[email protected]00c39612010-03-06 02:53:28109}
110
[email protected]d4af1e72011-10-21 17:45:43111void PluginList::GetInternalPlugins(
[email protected]d7bd3e52013-07-21 04:29:20112 std::vector<WebPluginInfo>* internal_plugins) {
Lei Zhang8403fa62022-10-12 20:15:26113 DCHECK_CURRENTLY_ON(BrowserThread::UI);
[email protected]d4af1e72011-10-21 17:45:43114
Lei Zhang41da87852019-02-07 00:45:30115 for (const auto& plugin : internal_plugins_)
116 internal_plugins->push_back(plugin);
[email protected]d4af1e72011-10-21 17:45:43117}
118
[email protected]a3ef4832013-02-02 05:12:33119bool PluginList::ReadPluginInfo(const base::FilePath& filename,
[email protected]d7bd3e52013-07-21 04:29:20120 WebPluginInfo* info) {
Lei Zhang8403fa62022-10-12 20:15:26121 DCHECK_CURRENTLY_ON(BrowserThread::UI);
122
pimane8c57ea2016-04-06 01:19:36123 for (const auto& plugin : internal_plugins_) {
124 if (filename == plugin.path) {
125 *info = plugin;
126 return true;
[email protected]8ff26092009-01-29 01:53:24127 }
128 }
pimane8c57ea2016-04-06 01:19:36129 return false;
[email protected]8ff26092009-01-29 01:53:24130}
131
Lei Zhang8403fa62022-10-12 20:15:26132PluginList::PluginList() {
133 DCHECK_CURRENTLY_ON(BrowserThread::UI);
134}
initial.commitf5b16fe2008-07-27 00:20:51135
[email protected]aa7f8802014-01-27 16:56:32136bool PluginList::PrepareForPluginLoading() {
Lei Zhang8403fa62022-10-12 20:15:26137 DCHECK_CURRENTLY_ON(BrowserThread::UI);
138
[email protected]aa7f8802014-01-27 16:56:32139 if (loading_state_ == LOADING_STATE_UP_TO_DATE)
140 return false;
[email protected]a33fa9d2012-05-16 14:47:49141
[email protected]aa7f8802014-01-27 16:56:32142 loading_state_ = LOADING_STATE_REFRESHING;
143 return true;
144}
145
pimane8c57ea2016-04-06 01:19:36146void PluginList::LoadPlugins() {
Lei Zhang8403fa62022-10-12 20:15:26147 DCHECK_CURRENTLY_ON(BrowserThread::UI);
148
[email protected]aa7f8802014-01-27 16:56:32149 if (!PrepareForPluginLoading())
150 return;
[email protected]a466a0c2010-10-02 00:42:39151
[email protected]d7bd3e52013-07-21 04:29:20152 std::vector<WebPluginInfo> new_plugins;
[email protected]9a60ccb2013-07-19 22:23:36153 std::vector<base::FilePath> plugin_paths;
pimane8c57ea2016-04-06 01:19:36154 GetPluginPathsToLoad(&plugin_paths);
[email protected]9a60ccb2013-07-19 22:23:36155
Lei Zhang41da87852019-02-07 00:45:30156 for (const base::FilePath& path : plugin_paths) {
[email protected]9a60ccb2013-07-19 22:23:36157 WebPluginInfo plugin_info;
Lei Zhang41da87852019-02-07 00:45:30158 LoadPluginIntoPluginList(path, &new_plugins, &plugin_info);
[email protected]9a60ccb2013-07-19 22:23:36159 }
[email protected]1134a002010-10-08 08:03:14160
[email protected]aa7f8802014-01-27 16:56:32161 SetPlugins(new_plugins);
initial.commitf5b16fe2008-07-27 00:20:51162}
163
Lei Zhangd8c53182019-02-06 22:24:39164bool PluginList::LoadPluginIntoPluginList(const base::FilePath& path,
165 std::vector<WebPluginInfo>* plugins,
166 WebPluginInfo* plugin_info) {
Lei Zhang8403fa62022-10-12 20:15:26167 DCHECK_CURRENTLY_ON(BrowserThread::UI);
168
[email protected]fee3a98b2013-07-18 18:12:48169 if (!ReadPluginInfo(path, plugin_info))
[email protected]68b63bc2012-08-20 22:14:03170 return false;
171
pimane8c57ea2016-04-06 01:19:36172 // TODO(piman): Do we still need this after NPAPI removal?
Lei Zhang41da87852019-02-07 00:45:30173 for (const content::WebPluginMimeType& mime_type : plugin_info->mime_types) {
pimane8c57ea2016-04-06 01:19:36174 // TODO: don't load global handlers for now.
175 // WebKit hands to the Plugin before it tries
176 // to handle mimeTypes on its own.
Lei Zhang41da87852019-02-07 00:45:30177 if (mime_type.mime_type == "*")
pimane8c57ea2016-04-06 01:19:36178 return false;
[email protected]68b63bc2012-08-20 22:14:03179 }
180 plugins->push_back(*plugin_info);
181 return true;
182}
183
pimane8c57ea2016-04-06 01:19:36184void PluginList::GetPluginPathsToLoad(
185 std::vector<base::FilePath>* plugin_paths) {
Lei Zhang8403fa62022-10-12 20:15:26186 DCHECK_CURRENTLY_ON(BrowserThread::UI);
[email protected]d4af1e72011-10-21 17:45:43187
Lei Zhang8403fa62022-10-12 20:15:26188 for (const base::FilePath& path : extra_plugin_paths_) {
Jan Wilken Dörrie531be7ca2019-06-07 10:05:57189 if (base::Contains(*plugin_paths, path))
[email protected]d4af1e72011-10-21 17:45:43190 continue;
[email protected]d4af1e72011-10-21 17:45:43191 plugin_paths->push_back(path);
192 }
[email protected]49125952011-09-27 18:05:15193}
194
[email protected]d7bd3e52013-07-21 04:29:20195void PluginList::SetPlugins(const std::vector<WebPluginInfo>& plugins) {
Lei Zhang8403fa62022-10-12 20:15:26196 DCHECK_CURRENTLY_ON(BrowserThread::UI);
[email protected]49125952011-09-27 18:05:15197
tommyclie86b2982015-03-16 20:16:45198 // If we haven't been invalidated in the mean time, mark the plugin list as
thakis3e861de2016-06-14 14:24:01199 // up to date.
[email protected]aa7f8802014-01-27 16:56:32200 if (loading_state_ != LOADING_STATE_NEEDS_REFRESH)
201 loading_state_ = LOADING_STATE_UP_TO_DATE;
[email protected]49125952011-09-27 18:05:15202
[email protected]aa7f8802014-01-27 16:56:32203 plugins_list_ = plugins;
[email protected]49125952011-09-27 18:05:15204}
205
pimane8c57ea2016-04-06 01:19:36206void PluginList::GetPlugins(std::vector<WebPluginInfo>* plugins) {
Lei Zhang8403fa62022-10-12 20:15:26207 DCHECK_CURRENTLY_ON(BrowserThread::UI);
pimane8c57ea2016-04-06 01:19:36208 LoadPlugins();
[email protected]68b63bc2012-08-20 22:14:03209 plugins->insert(plugins->end(), plugins_list_.begin(), plugins_list_.end());
initial.commitf5b16fe2008-07-27 00:20:51210}
211
[email protected]d7bd3e52013-07-21 04:29:20212bool PluginList::GetPluginsNoRefresh(std::vector<WebPluginInfo>* plugins) {
Lei Zhang8403fa62022-10-12 20:15:26213 DCHECK_CURRENTLY_ON(BrowserThread::UI);
[email protected]68b63bc2012-08-20 22:14:03214 plugins->insert(plugins->end(), plugins_list_.begin(), plugins_list_.end());
215
[email protected]480c7cc2012-06-29 17:38:44216 return loading_state_ == LOADING_STATE_UP_TO_DATE;
[email protected]49125952011-09-27 18:05:15217}
218
Lei Zhangc923379e2019-02-07 18:13:08219bool PluginList::GetPluginInfoArray(
[email protected]9bcdced72010-12-07 20:51:36220 const GURL& url,
221 const std::string& mime_type,
222 bool allow_wildcard,
[email protected]d7bd3e52013-07-21 04:29:20223 std::vector<WebPluginInfo>* info,
[email protected]9bcdced72010-12-07 20:51:36224 std::vector<std::string>* actual_mime_types) {
Lei Zhang8403fa62022-10-12 20:15:26225 DCHECK_CURRENTLY_ON(BrowserThread::UI);
brettw8e2106d2015-08-11 19:30:22226 DCHECK(mime_type == base::ToLowerASCII(mime_type));
[email protected]20a793e2010-10-12 06:50:08227 DCHECK(info);
228
Lei Zhangc923379e2019-02-07 18:13:08229 bool is_stale = loading_state_ != LOADING_STATE_UP_TO_DATE;
[email protected]f4d43cb2013-10-28 20:53:07230 info->clear();
[email protected]20a793e2010-10-12 06:50:08231 if (actual_mime_types)
232 actual_mime_types->clear();
233
[email protected]a3ef4832013-02-02 05:12:33234 std::set<base::FilePath> visited_plugins;
[email protected]20a793e2010-10-12 06:50:08235
[email protected]dfba8762011-09-02 12:49:54236 // Add in plugins by mime type.
Lei Zhang41da87852019-02-07 00:45:30237 for (const WebPluginInfo& plugin : plugins_list_) {
238 if (SupportsType(plugin, mime_type, allow_wildcard)) {
239 const base::FilePath& path = plugin.path;
[email protected]68b63bc2012-08-20 22:14:03240 if (visited_plugins.insert(path).second) {
Lei Zhang41da87852019-02-07 00:45:30241 info->push_back(plugin);
[email protected]68b63bc2012-08-20 22:14:03242 if (actual_mime_types)
243 actual_mime_types->push_back(mime_type);
[email protected]20a793e2010-10-12 06:50:08244 }
245 }
246 }
247
[email protected]dfba8762011-09-02 12:49:54248 // Add in plugins by url.
tommyclie86b2982015-03-16 20:16:45249 // We do not permit URL-sniff based plugin MIME type overrides aside from
[email protected]cafe0d02013-07-23 15:16:20250 // the case where the "type" was initially missing.
251 // We collected stats to determine this approach isn't a major compat issue,
252 // and we defend against content confusion attacks in various cases, such
tommyclie86b2982015-03-16 20:16:45253 // as when the user doesn't have the Flash plugin enabled.
[email protected]20a793e2010-10-12 06:50:08254 std::string path = url.path();
255 std::string::size_type last_dot = path.rfind('.');
Lei Zhang41da87852019-02-07 00:45:30256 if (last_dot == std::string::npos || !mime_type.empty())
Lei Zhangc923379e2019-02-07 18:13:08257 return is_stale;
Lei Zhang41da87852019-02-07 00:45:30258
259 std::string extension =
Md Hasibul Hasana963a9342024-04-03 10:15:14260 base::ToLowerASCII(std::string_view(path).substr(last_dot + 1));
Lei Zhang41da87852019-02-07 00:45:30261 std::string actual_mime_type;
262 for (const WebPluginInfo& plugin : plugins_list_) {
263 if (SupportsExtension(plugin, extension, &actual_mime_type)) {
264 base::FilePath plugin_path = plugin.path;
265 if (visited_plugins.insert(plugin_path).second) {
266 info->push_back(plugin);
267 if (actual_mime_types)
268 actual_mime_types->push_back(actual_mime_type);
[email protected]20a793e2010-10-12 06:50:08269 }
270 }
271 }
Lei Zhangc923379e2019-02-07 18:13:08272 return is_stale;
[email protected]20a793e2010-10-12 06:50:08273}
274
Lei Zhang8403fa62022-10-12 20:15:26275void PluginList::RemoveExtraPluginPath(const base::FilePath& plugin_path) {
276 DCHECK_CURRENTLY_ON(BrowserThread::UI);
Peter Kastingff5db6692022-10-06 18:57:24277 std::vector<base::FilePath>::iterator it =
Peter Kasting1557e5f2025-01-28 01:14:08278 std::ranges::find(extra_plugin_paths_, plugin_path);
[email protected]797d9a62013-09-13 23:36:07279 if (it != extra_plugin_paths_.end())
280 extra_plugin_paths_.erase(it);
281}
282
Lei Zhang41da87852019-02-07 00:45:30283PluginList::~PluginList() = default;
initial.commitf5b16fe2008-07-27 00:20:51284
[email protected]29e2fb42013-07-19 01:13:47285} // namespace content