Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(573)

Side by Side Diff: content/common/plugin_list_mac.mm

Issue 1862513003: Remove NPAPI from browser and utility (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: rebase Created 4 years, 8 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
« no previous file with comments | « content/common/plugin_list.cc ('k') | content/common/plugin_list_posix.cc » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
(Empty)
1 // Copyright (c) 2012 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 "content/common/plugin_list.h"
6
7 #import <Carbon/Carbon.h>
8 #import <Foundation/Foundation.h>
9
10 #include "base/files/file_enumerator.h"
11 #include "base/files/file_util.h"
12 #include "base/mac/foundation_util.h"
13 #include "base/mac/scoped_cftyperef.h"
14 #include "base/memory/scoped_ptr.h"
15 #include "base/native_library.h"
16 #include "base/strings/string_number_conversions.h"
17 #include "base/strings/string_split.h"
18 #include "base/strings/string_util.h"
19 #include "base/strings/sys_string_conversions.h"
20 #include "base/strings/utf_string_conversions.h"
21
22 using base::ScopedCFTypeRef;
23
24 namespace content {
25
26 namespace {
27
28 void GetPluginCommonDirectories(std::vector<base::FilePath>* plugin_dirs) {
29 // This once used ::FSFindFolder() and kInternetPlugInFolderType, which is
30 // deprecated since 10.8. There is no NSSearchPathDirectory replacement for
31 // kInternetPlugInFolderType, so append a hard-coded value to [~]/Library.
32 // Interestingly, Safari also hard-codes the location (see
33 // WebKit/WebKit/mac/Plugins/WebPluginDatabase.mm's +_defaultPlugInPaths).
34 const char kInternetPluginFolderName[] = "Internet Plug-Ins";
35
36 NSSearchPathDomainMask mask = NSUserDomainMask | NSLocalDomainMask;
37 // Note the returned urls are ordered according to the order of the domain
38 // mask constants: paths under $HOME come first, which take precedence.
39 NSArray* library_urls =
40 [[NSFileManager defaultManager] URLsForDirectory:NSLibraryDirectory
41 inDomains:mask];
42 for (NSURL* url in library_urls) {
43 DCHECK([url isFileURL]);
44 base::FilePath path = base::mac::NSStringToFilePath([url path])
45 .AppendASCII(kInternetPluginFolderName);
46 if (base::PathExists(path))
47 plugin_dirs->push_back(path);
48 }
49 }
50
51 // Returns true if the plugin should be prevented from loading.
52 bool IsBlacklistedPlugin(const WebPluginInfo& info) {
53 // We blacklist Gears by included MIME type, since that is more stable than
54 // its name. Be careful about adding any more plugins to this list though,
55 // since it's easy to accidentally blacklist plugins that support lots of
56 // MIME types.
57 for (const WebPluginMimeType& mime : info.mime_types) {
58 // The Gears plugin is Safari-specific, so don't load it.
59 if (mime.mime_type == "application/x-googlegears")
60 return true;
61 }
62
63 // Versions of Flip4Mac 2.3 before 2.3.6 often hang the renderer, so don't
64 // load them.
65 if (base::StartsWith(info.name,
66 base::ASCIIToUTF16("Flip4Mac Windows Media"),
67 base::CompareCase::INSENSITIVE_ASCII) &&
68 base::StartsWith(info.version, base::ASCIIToUTF16("2.3"),
69 base::CompareCase::SENSITIVE)) {
70 std::vector<base::StringPiece16> components = base::SplitStringPiece(
71 info.version, base::ASCIIToUTF16("."), base::TRIM_WHITESPACE,
72 base::SPLIT_WANT_ALL);
73 int bugfix_version = 0;
74 return (components.size() >= 3 &&
75 base::StringToInt(components[2], &bugfix_version) &&
76 bugfix_version < 6);
77 }
78
79 return false;
80 }
81
82 NSDictionary* GetMIMETypes(CFBundleRef bundle) {
83 NSString* mime_filename =
84 (NSString*)CFBundleGetValueForInfoDictionaryKey(bundle,
85 CFSTR("WebPluginMIMETypesFilename"));
86
87 if (mime_filename) {
88
89 // get the file
90
91 NSString* mime_path =
92 [NSString stringWithFormat:@"%@/Library/Preferences/%@",
93 NSHomeDirectory(), mime_filename];
94 NSDictionary* mime_file_dict =
95 [NSDictionary dictionaryWithContentsOfFile:mime_path];
96
97 // is it valid?
98
99 bool valid_file = false;
100 if (mime_file_dict) {
101 NSString* l10n_name =
102 [mime_file_dict objectForKey:@"WebPluginLocalizationName"];
103 NSString* preferred_l10n = [[NSLocale currentLocale] localeIdentifier];
104 if ([l10n_name isEqualToString:preferred_l10n])
105 valid_file = true;
106 }
107
108 if (valid_file)
109 return [mime_file_dict objectForKey:@"WebPluginMIMETypes"];
110
111 // dammit, I didn't want to have to do this
112
113 typedef void (*CreateMIMETypesPrefsPtr)(void);
114 CreateMIMETypesPrefsPtr create_prefs_file =
115 (CreateMIMETypesPrefsPtr)CFBundleGetFunctionPointerForName(
116 bundle, CFSTR("BP_CreatePluginMIMETypesPreferences"));
117 if (!create_prefs_file)
118 return nil;
119 create_prefs_file();
120
121 // one more time
122
123 mime_file_dict = [NSDictionary dictionaryWithContentsOfFile:mime_path];
124 if (mime_file_dict)
125 return [mime_file_dict objectForKey:@"WebPluginMIMETypes"];
126 else
127 return nil;
128
129 } else {
130 return (NSDictionary*)CFBundleGetValueForInfoDictionaryKey(bundle,
131 CFSTR("WebPluginMIMETypes"));
132 }
133 }
134
135 bool ReadPlistPluginInfo(const base::FilePath& filename, CFBundleRef bundle,
136 WebPluginInfo* info) {
137 NSDictionary* mime_types = GetMIMETypes(bundle);
138 if (!mime_types)
139 return false; // no type info here; try elsewhere
140
141 for (NSString* mime_type in [mime_types allKeys]) {
142 NSDictionary* mime_dict = [mime_types objectForKey:mime_type];
143 NSNumber* type_enabled = [mime_dict objectForKey:@"WebPluginTypeEnabled"];
144 NSString* mime_desc = [mime_dict objectForKey:@"WebPluginTypeDescription"];
145 NSArray* mime_exts = [mime_dict objectForKey:@"WebPluginExtensions"];
146
147 // Skip any disabled types.
148 if (type_enabled && ![type_enabled boolValue])
149 continue;
150
151 WebPluginMimeType mime;
152 mime.mime_type = base::SysNSStringToUTF8([mime_type lowercaseString]);
153 // Remove PDF from the list of types handled by QuickTime, since it provides
154 // a worse experience than just downloading the PDF.
155 if (mime.mime_type == "application/pdf" &&
156 base::StartsWith(filename.BaseName().value(), "QuickTime",
157 base::CompareCase::INSENSITIVE_ASCII)) {
158 continue;
159 }
160
161 if (mime_desc)
162 mime.description = base::SysNSStringToUTF16(mime_desc);
163 for (NSString* ext in mime_exts)
164 mime.file_extensions.push_back(
165 base::SysNSStringToUTF8([ext lowercaseString]));
166
167 info->mime_types.push_back(mime);
168 }
169
170 NSString* plugin_name =
171 (NSString*)CFBundleGetValueForInfoDictionaryKey(bundle,
172 CFSTR("WebPluginName"));
173 NSString* plugin_vers =
174 (NSString*)CFBundleGetValueForInfoDictionaryKey(bundle,
175 CFSTR("CFBundleShortVersionString"));
176 NSString* plugin_desc =
177 (NSString*)CFBundleGetValueForInfoDictionaryKey(bundle,
178 CFSTR("WebPluginDescription"));
179
180 if (plugin_name)
181 info->name = base::SysNSStringToUTF16(plugin_name);
182 else
183 info->name = base::UTF8ToUTF16(filename.BaseName().value());
184 info->path = filename;
185 if (plugin_vers)
186 info->version = base::SysNSStringToUTF16(plugin_vers);
187 if (plugin_desc)
188 info->desc = base::SysNSStringToUTF16(plugin_desc);
189 else
190 info->desc = base::UTF8ToUTF16(filename.BaseName().value());
191
192 return true;
193 }
194
195 } // namespace
196
197 bool PluginList::ReadWebPluginInfo(const base::FilePath &filename,
198 WebPluginInfo* info) {
199 // There are three ways to get information about plugin capabilities:
200 // 1) a set of Info.plist keys, documented at
201 // http://developer.apple.com/documentation/InternetWeb/Conceptual/WebKit_Plug inProgTopic/Concepts/AboutPlugins.html .
202 // 2) a set of STR# resources, documented at
203 // https://developer.mozilla.org/En/Gecko_Plugin_API_Reference/Plug-in_Develop ment_Overview .
204 // 3) a NP_GetMIMEDescription() entry point, documented at
205 // https://developer.mozilla.org/en/NP_GetMIMEDescription
206 //
207 // Mozilla supported (3), but WebKit never has, so no plugins rely on it. Most
208 // browsers supported (2) and then added support for (1); Chromium originally
209 // supported (2) and (1), but now supports only (1) as (2) is deprecated.
210 //
211 // For the Info.plist version, the data is formatted as follows (in text plist
212 // format):
213 // {
214 // ... the usual plist keys ...
215 // WebPluginDescription = <<plugindescription>>;
216 // WebPluginMIMETypes = {
217 // <<type0mimetype>> = {
218 // WebPluginExtensions = (
219 // <<type0fileextension0>>,
220 // ...
221 // <<type0fileextensionk>>,
222 // );
223 // WebPluginTypeDescription = <<type0description>>;
224 // };
225 // <<type1mimetype>> = { ... };
226 // ...
227 // <<typenmimetype>> = { ... };
228 // };
229 // WebPluginName = <<pluginname>>;
230 // }
231 //
232 // Alternatively (and this is undocumented), rather than a WebPluginMIMETypes
233 // key, there may be a WebPluginMIMETypesFilename key. If it is present, then
234 // it is the name of a file in the user's preferences folder in which to find
235 // the WebPluginMIMETypes key. If the key is present but the file doesn't
236 // exist, we must load the plugin and call a specific function to have the
237 // plugin create the file.
238
239 ScopedCFTypeRef<CFURLRef> bundle_url(CFURLCreateFromFileSystemRepresentation(
240 kCFAllocatorDefault, (const UInt8*)filename.value().c_str(),
241 filename.value().length(), true));
242 if (!bundle_url) {
243 LOG_IF(ERROR, PluginList::DebugPluginLoading())
244 << "PluginLib::ReadWebPluginInfo could not create bundle URL";
245 return false;
246 }
247 ScopedCFTypeRef<CFBundleRef> bundle(CFBundleCreate(kCFAllocatorDefault,
248 bundle_url.get()));
249 if (!bundle) {
250 LOG_IF(ERROR, PluginList::DebugPluginLoading())
251 << "PluginLib::ReadWebPluginInfo could not create CFBundleRef";
252 return false;
253 }
254
255 // preflight
256
257 OSType type = 0;
258 CFBundleGetPackageInfo(bundle.get(), &type, NULL);
259 if (type != FOUR_CHAR_CODE('BRPL')) {
260 LOG_IF(ERROR, PluginList::DebugPluginLoading())
261 << "PluginLib::ReadWebPluginInfo bundle is not BRPL, is " << type;
262 return false;
263 }
264
265 CFErrorRef error;
266 Boolean would_load = CFBundlePreflightExecutable(bundle.get(), &error);
267 if (!would_load) {
268 ScopedCFTypeRef<CFStringRef> error_string(CFErrorCopyDescription(error));
269 LOG_IF(ERROR, PluginList::DebugPluginLoading())
270 << "PluginLib::ReadWebPluginInfo bundle failed preflight: "
271 << base::SysCFStringRefToUTF8(error_string);
272 return false;
273 }
274
275 // get the info
276
277 if (ReadPlistPluginInfo(filename, bundle.get(), info))
278 return true;
279
280 // ... or not
281
282 return false;
283 }
284
285 void PluginList::GetPluginDirectories(
286 std::vector<base::FilePath>* plugin_dirs) {
287 if (PluginList::plugins_discovery_disabled_)
288 return;
289
290 GetPluginCommonDirectories(plugin_dirs);
291 }
292
293 void PluginList::GetPluginsInDir(
294 const base::FilePath& path, std::vector<base::FilePath>* plugins) {
295 base::FileEnumerator enumerator(path,
296 false, // not recursive
297 base::FileEnumerator::DIRECTORIES);
298 for (base::FilePath path = enumerator.Next(); !path.value().empty();
299 path = enumerator.Next()) {
300 plugins->push_back(path);
301 }
302 }
303
304 bool PluginList::ShouldLoadPluginUsingPluginList(
305 const WebPluginInfo& info,
306 std::vector<WebPluginInfo>* plugins) {
307 return !IsBlacklistedPlugin(info);
308 }
309
310 } // namespace content
OLDNEW
« no previous file with comments | « content/common/plugin_list.cc ('k') | content/common/plugin_list_posix.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698