blob: 466f60724c71ab0b1ce40b1d1c708ab3eefb1b4e [file] [log] [blame]
[email protected]c6f3dea2012-01-14 02:23:111// Copyright (c) 2012 The Chromium Authors. All rights reserved.
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
[email protected]cec1b8d2010-03-24 00:21:349#include <algorithm>
10
[email protected]3c0c0bf52010-06-25 06:05:0911#include "base/command_line.h"
[email protected]19537112009-01-21 19:38:1412#include "base/lazy_instance.h"
initial.commitf5b16fe2008-07-27 00:20:5113#include "base/logging.h"
Zhuoyu Qian39a909a2018-10-16 03:48:5214#include "base/stl_util.h"
[email protected]d778e0422013-03-06 18:10:2215#include "base/strings/string_split.h"
[email protected]f63582d2013-06-11 22:52:5416#include "base/strings/string_util.h"
[email protected]13ac53532013-03-30 00:27:0017#include "base/strings/sys_string_conversions.h"
[email protected]906265872013-06-07 22:40:4518#include "base/strings/utf_string_conversions.h"
avia9aa7a82015-12-25 03:06:3119#include "build/build_config.h"
[email protected]1bbbc492013-08-09 00:36:1520#include "content/public/common/content_switches.h"
[email protected]b7344502009-01-12 19:43:4421#include "net/base/mime_util.h"
[email protected]ad677772013-06-29 14:18:3822#include "url/gurl.h"
initial.commitf5b16fe2008-07-27 00:20:5123
[email protected]29e2fb42013-07-19 01:13:4724namespace content {
25
26namespace {
[email protected]0b300172012-09-27 16:11:5227
scottmg5e65e3a2017-03-08 08:48:4628base::LazyInstance<PluginList>::DestructorAtExit g_singleton =
29 LAZY_INSTANCE_INITIALIZER;
[email protected]123a04962011-11-03 15:43:0130
Lei Zhanga2eb18782018-08-15 18:09:2131// Returns true if the plugin supports |mime_type|. |mime_type| should be all
32// lower case.
33bool SupportsType(const WebPluginInfo& plugin,
34 const std::string& mime_type,
35 bool allow_wildcard) {
36 // Webkit will ask for a plugin to handle empty mime types.
37 if (mime_type.empty())
38 return false;
39
Lei Zhang41da87852019-02-07 00:45:3040 for (const WebPluginMimeType& mime_info : plugin.mime_types) {
Lei Zhanga2eb18782018-08-15 18:09:2141 if (net::MatchesMimeType(mime_info.mime_type, mime_type)) {
Lei Zhang41da87852019-02-07 00:45:3042 if (allow_wildcard || mime_info.mime_type != "*")
43 return true;
Lei Zhanga2eb18782018-08-15 18:09:2144 }
45 }
46 return false;
47}
48
49// Returns true if the given plugin supports a given file extension.
50// |extension| should be all lower case. |actual_mime_type| will be set to the
51// MIME type if found. The MIME type which corresponds to the extension is
52// optionally returned back.
53bool SupportsExtension(const WebPluginInfo& plugin,
54 const std::string& extension,
55 std::string* actual_mime_type) {
Lei Zhang41da87852019-02-07 00:45:3056 for (const WebPluginMimeType& mime_type : plugin.mime_types) {
57 for (const std::string& file_extension : mime_type.file_extensions) {
58 if (file_extension == extension) {
Lei Zhanga2eb18782018-08-15 18:09:2159 *actual_mime_type = mime_type.mime_type;
60 return true;
61 }
62 }
63 }
64 return false;
65}
66
[email protected]3b91edbe2012-09-27 22:49:2367} // namespace
[email protected]123a04962011-11-03 15:43:0168
[email protected]19537112009-01-21 19:38:1469// static
initial.commitf5b16fe2008-07-27 00:20:5170PluginList* PluginList::Singleton() {
[email protected]35fa6a22009-08-15 00:04:0171 return g_singleton.Pointer();
initial.commitf5b16fe2008-07-27 00:20:5172}
73
[email protected]4e59e812010-04-06 20:51:1674void PluginList::RefreshPlugins() {
[email protected]20305ec2011-01-21 04:55:5275 base::AutoLock lock(lock_);
[email protected]a33fa9d2012-05-16 14:47:4976 loading_state_ = LOADING_STATE_NEEDS_REFRESH;
[email protected]367230c52009-02-21 01:44:3077}
initial.commitf5b16fe2008-07-27 00:20:5178
[email protected]d7bd3e52013-07-21 04:29:2079void PluginList::RegisterInternalPlugin(const WebPluginInfo& info,
[email protected]c6f3dea2012-01-14 02:23:1180 bool add_at_beginning) {
[email protected]20305ec2011-01-21 04:55:5281 base::AutoLock lock(lock_);
[email protected]8ca37f42011-11-02 16:03:4182
[email protected]fee3a982013-07-18 18:12:4883 internal_plugins_.push_back(info);
[email protected]8ca37f42011-11-02 16:03:4184 if (add_at_beginning) {
85 // Newer registrations go earlier in the list so they can override the MIME
86 // types of older registrations.
[email protected]c6f3dea2012-01-14 02:23:1187 extra_plugin_paths_.insert(extra_plugin_paths_.begin(), info.path);
[email protected]8ca37f42011-11-02 16:03:4188 } else {
[email protected]c6f3dea2012-01-14 02:23:1189 extra_plugin_paths_.push_back(info.path);
[email protected]8ca37f42011-11-02 16:03:4190 }
[email protected]f99c73ad2011-01-11 00:43:4491}
92
[email protected]a3ef4832013-02-02 05:12:3393void PluginList::UnregisterInternalPlugin(const base::FilePath& path) {
[email protected]20305ec2011-01-21 04:55:5294 base::AutoLock lock(lock_);
[email protected]797d9a62013-09-13 23:36:0795 bool found = false;
[email protected]00c39612010-03-06 02:53:2896 for (size_t i = 0; i < internal_plugins_.size(); i++) {
[email protected]fee3a982013-07-18 18:12:4897 if (internal_plugins_[i].path == path) {
[email protected]00c39612010-03-06 02:53:2898 internal_plugins_.erase(internal_plugins_.begin() + i);
[email protected]797d9a62013-09-13 23:36:0799 found = true;
100 break;
[email protected]00c39612010-03-06 02:53:28101 }
102 }
[email protected]797d9a62013-09-13 23:36:07103 DCHECK(found);
104 RemoveExtraPluginPathLocked(path);
[email protected]00c39612010-03-06 02:53:28105}
106
[email protected]d4af1e72011-10-21 17:45:43107void PluginList::GetInternalPlugins(
[email protected]d7bd3e52013-07-21 04:29:20108 std::vector<WebPluginInfo>* internal_plugins) {
[email protected]d4af1e72011-10-21 17:45:43109 base::AutoLock lock(lock_);
110
Lei Zhang41da87852019-02-07 00:45:30111 for (const auto& plugin : internal_plugins_)
112 internal_plugins->push_back(plugin);
[email protected]d4af1e72011-10-21 17:45:43113}
114
[email protected]a3ef4832013-02-02 05:12:33115bool PluginList::ReadPluginInfo(const base::FilePath& filename,
[email protected]d7bd3e52013-07-21 04:29:20116 WebPluginInfo* info) {
pimane8c57ea2016-04-06 01:19:36117 base::AutoLock lock(lock_);
118 for (const auto& plugin : internal_plugins_) {
119 if (filename == plugin.path) {
120 *info = plugin;
121 return true;
[email protected]8ff26092009-01-29 01:53:24122 }
123 }
pimane8c57ea2016-04-06 01:19:36124 return false;
[email protected]8ff26092009-01-29 01:53:24125}
126
Lei Zhangd8c53182019-02-06 22:24:39127PluginList::PluginList() : loading_state_(LOADING_STATE_NEEDS_REFRESH) {}
initial.commitf5b16fe2008-07-27 00:20:51128
[email protected]aa7f8802014-01-27 16:56:32129bool PluginList::PrepareForPluginLoading() {
130 base::AutoLock lock(lock_);
131 if (loading_state_ == LOADING_STATE_UP_TO_DATE)
132 return false;
[email protected]a33fa9d2012-05-16 14:47:49133
[email protected]aa7f8802014-01-27 16:56:32134 loading_state_ = LOADING_STATE_REFRESHING;
135 return true;
136}
137
pimane8c57ea2016-04-06 01:19:36138void PluginList::LoadPlugins() {
[email protected]aa7f8802014-01-27 16:56:32139 if (!PrepareForPluginLoading())
140 return;
[email protected]a466a0c2010-10-02 00:42:39141
[email protected]d7bd3e52013-07-21 04:29:20142 std::vector<WebPluginInfo> new_plugins;
Lei Zhangc213e122019-02-07 00:17:02143 base::OnceClosure will_load_callback;
[email protected]9a60ccb2013-07-19 22:23:36144 {
145 base::AutoLock lock(lock_);
146 will_load_callback = will_load_plugins_callback_;
147 }
Lei Zhangc213e122019-02-07 00:17:02148 if (will_load_callback)
Tommy Nyquist4b749d02018-03-20 21:46:29149 std::move(will_load_callback).Run();
[email protected]9a60ccb2013-07-19 22:23:36150
151 std::vector<base::FilePath> plugin_paths;
pimane8c57ea2016-04-06 01:19:36152 GetPluginPathsToLoad(&plugin_paths);
[email protected]9a60ccb2013-07-19 22:23:36153
Lei Zhang41da87852019-02-07 00:45:30154 for (const base::FilePath& path : plugin_paths) {
[email protected]9a60ccb2013-07-19 22:23:36155 WebPluginInfo plugin_info;
Lei Zhang41da87852019-02-07 00:45:30156 LoadPluginIntoPluginList(path, &new_plugins, &plugin_info);
[email protected]9a60ccb2013-07-19 22:23:36157 }
[email protected]1134a002010-10-08 08:03:14158
[email protected]aa7f8802014-01-27 16:56:32159 SetPlugins(new_plugins);
initial.commitf5b16fe2008-07-27 00:20:51160}
161
Lei Zhangd8c53182019-02-06 22:24:39162bool PluginList::LoadPluginIntoPluginList(const base::FilePath& path,
163 std::vector<WebPluginInfo>* plugins,
164 WebPluginInfo* plugin_info) {
[email protected]fee3a982013-07-18 18:12:48165 if (!ReadPluginInfo(path, plugin_info))
[email protected]68b63bc2012-08-20 22:14:03166 return false;
167
pimane8c57ea2016-04-06 01:19:36168 // TODO(piman): Do we still need this after NPAPI removal?
Lei Zhang41da87852019-02-07 00:45:30169 for (const content::WebPluginMimeType& mime_type : plugin_info->mime_types) {
pimane8c57ea2016-04-06 01:19:36170 // TODO: don't load global handlers for now.
171 // WebKit hands to the Plugin before it tries
172 // to handle mimeTypes on its own.
Lei Zhang41da87852019-02-07 00:45:30173 if (mime_type.mime_type == "*")
pimane8c57ea2016-04-06 01:19:36174 return false;
[email protected]68b63bc2012-08-20 22:14:03175 }
176 plugins->push_back(*plugin_info);
177 return true;
178}
179
pimane8c57ea2016-04-06 01:19:36180void PluginList::GetPluginPathsToLoad(
181 std::vector<base::FilePath>* plugin_paths) {
[email protected]d4af1e72011-10-21 17:45:43182 // Don't want to hold the lock while loading new plugins, so we don't block
183 // other methods if they're called on other threads.
[email protected]a3ef4832013-02-02 05:12:33184 std::vector<base::FilePath> extra_plugin_paths;
[email protected]d4af1e72011-10-21 17:45:43185 {
186 base::AutoLock lock(lock_);
187 extra_plugin_paths = extra_plugin_paths_;
[email protected]49125952011-09-27 18:05:15188 }
[email protected]d4af1e72011-10-21 17:45:43189
Lei Zhang41da87852019-02-07 00:45:30190 for (const base::FilePath& path : extra_plugin_paths) {
Jan Wilken Dörrie531be7ca2019-06-07 10:05:57191 if (base::Contains(*plugin_paths, path))
[email protected]d4af1e72011-10-21 17:45:43192 continue;
[email protected]d4af1e72011-10-21 17:45:43193 plugin_paths->push_back(path);
194 }
[email protected]49125952011-09-27 18:05:15195}
196
[email protected]d7bd3e52013-07-21 04:29:20197void PluginList::SetPlugins(const std::vector<WebPluginInfo>& plugins) {
[email protected]49125952011-09-27 18:05:15198 base::AutoLock lock(lock_);
199
tommyclie86b2982015-03-16 20:16:45200 // If we haven't been invalidated in the mean time, mark the plugin list as
thakis3e861de2016-06-14 14:24:01201 // up to date.
[email protected]aa7f8802014-01-27 16:56:32202 if (loading_state_ != LOADING_STATE_NEEDS_REFRESH)
203 loading_state_ = LOADING_STATE_UP_TO_DATE;
[email protected]49125952011-09-27 18:05:15204
[email protected]aa7f8802014-01-27 16:56:32205 plugins_list_ = plugins;
[email protected]49125952011-09-27 18:05:15206}
207
Lei Zhangc213e122019-02-07 00:17:02208void PluginList::set_will_load_plugins_callback(
209 const base::RepeatingClosure& callback) {
[email protected]49125952011-09-27 18:05:15210 base::AutoLock lock(lock_);
211 will_load_plugins_callback_ = callback;
212}
213
pimane8c57ea2016-04-06 01:19:36214void PluginList::GetPlugins(std::vector<WebPluginInfo>* plugins) {
215 LoadPlugins();
[email protected]20305ec2011-01-21 04:55:52216 base::AutoLock lock(lock_);
[email protected]68b63bc2012-08-20 22:14:03217 plugins->insert(plugins->end(), plugins_list_.begin(), plugins_list_.end());
initial.commitf5b16fe2008-07-27 00:20:51218}
219
[email protected]d7bd3e52013-07-21 04:29:20220bool PluginList::GetPluginsNoRefresh(std::vector<WebPluginInfo>* plugins) {
[email protected]49125952011-09-27 18:05:15221 base::AutoLock lock(lock_);
[email protected]68b63bc2012-08-20 22:14:03222 plugins->insert(plugins->end(), plugins_list_.begin(), plugins_list_.end());
223
[email protected]480c7cc2012-06-29 17:38:44224 return loading_state_ == LOADING_STATE_UP_TO_DATE;
[email protected]49125952011-09-27 18:05:15225}
226
Lei Zhangc923379e2019-02-07 18:13:08227bool PluginList::GetPluginInfoArray(
[email protected]9bcdced72010-12-07 20:51:36228 const GURL& url,
229 const std::string& mime_type,
230 bool allow_wildcard,
[email protected]d7bd3e52013-07-21 04:29:20231 std::vector<WebPluginInfo>* info,
[email protected]9bcdced72010-12-07 20:51:36232 std::vector<std::string>* actual_mime_types) {
brettw8e2106d2015-08-11 19:30:22233 DCHECK(mime_type == base::ToLowerASCII(mime_type));
[email protected]20a793e2010-10-12 06:50:08234 DCHECK(info);
235
[email protected]20305ec2011-01-21 04:55:52236 base::AutoLock lock(lock_);
Lei Zhangc923379e2019-02-07 18:13:08237 bool is_stale = loading_state_ != LOADING_STATE_UP_TO_DATE;
[email protected]f4d43cb2013-10-28 20:53:07238 info->clear();
[email protected]20a793e2010-10-12 06:50:08239 if (actual_mime_types)
240 actual_mime_types->clear();
241
[email protected]a3ef4832013-02-02 05:12:33242 std::set<base::FilePath> visited_plugins;
[email protected]20a793e2010-10-12 06:50:08243
[email protected]dfba8762011-09-02 12:49:54244 // Add in plugins by mime type.
Lei Zhang41da87852019-02-07 00:45:30245 for (const WebPluginInfo& plugin : plugins_list_) {
246 if (SupportsType(plugin, mime_type, allow_wildcard)) {
247 const base::FilePath& path = plugin.path;
[email protected]68b63bc2012-08-20 22:14:03248 if (visited_plugins.insert(path).second) {
Lei Zhang41da87852019-02-07 00:45:30249 info->push_back(plugin);
[email protected]68b63bc2012-08-20 22:14:03250 if (actual_mime_types)
251 actual_mime_types->push_back(mime_type);
[email protected]20a793e2010-10-12 06:50:08252 }
253 }
254 }
255
[email protected]dfba8762011-09-02 12:49:54256 // Add in plugins by url.
tommyclie86b2982015-03-16 20:16:45257 // We do not permit URL-sniff based plugin MIME type overrides aside from
[email protected]cafe0d02013-07-23 15:16:20258 // the case where the "type" was initially missing.
259 // We collected stats to determine this approach isn't a major compat issue,
260 // and we defend against content confusion attacks in various cases, such
tommyclie86b2982015-03-16 20:16:45261 // as when the user doesn't have the Flash plugin enabled.
[email protected]20a793e2010-10-12 06:50:08262 std::string path = url.path();
263 std::string::size_type last_dot = path.rfind('.');
Lei Zhang41da87852019-02-07 00:45:30264 if (last_dot == std::string::npos || !mime_type.empty())
Lei Zhangc923379e2019-02-07 18:13:08265 return is_stale;
Lei Zhang41da87852019-02-07 00:45:30266
267 std::string extension =
268 base::ToLowerASCII(base::StringPiece(path).substr(last_dot + 1));
269 std::string actual_mime_type;
270 for (const WebPluginInfo& plugin : plugins_list_) {
271 if (SupportsExtension(plugin, extension, &actual_mime_type)) {
272 base::FilePath plugin_path = plugin.path;
273 if (visited_plugins.insert(plugin_path).second) {
274 info->push_back(plugin);
275 if (actual_mime_types)
276 actual_mime_types->push_back(actual_mime_type);
[email protected]20a793e2010-10-12 06:50:08277 }
278 }
279 }
Lei Zhangc923379e2019-02-07 18:13:08280 return is_stale;
[email protected]20a793e2010-10-12 06:50:08281}
282
[email protected]797d9a62013-09-13 23:36:07283void PluginList::RemoveExtraPluginPathLocked(
284 const base::FilePath& plugin_path) {
285 lock_.AssertAcquired();
Lei Zhangd8c53182019-02-06 22:24:39286 std::vector<base::FilePath>::iterator it = std::find(
287 extra_plugin_paths_.begin(), extra_plugin_paths_.end(), plugin_path);
[email protected]797d9a62013-09-13 23:36:07288 if (it != extra_plugin_paths_.end())
289 extra_plugin_paths_.erase(it);
290}
291
Lei Zhang41da87852019-02-07 00:45:30292PluginList::~PluginList() = default;
initial.commitf5b16fe2008-07-27 00:20:51293
[email protected]29e2fb42013-07-19 01:13:47294} // namespace content