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

Side by Side Diff: webkit/glue/plugins/plugin_lib_posix.cc

Issue 6012002: Move the NPAPI files from webkit/glue/plugins to webkit/plugins/npapi and put... (Closed) Base URL: svn://chrome-svn/chrome/trunk/src/
Patch Set: Created 10 years 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 | Annotate | Revision Log
« no previous file with comments | « webkit/glue/plugins/plugin_lib_mac.mm ('k') | webkit/glue/plugins/plugin_lib_unittest.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) 2010 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 "webkit/glue/plugins/plugin_lib.h"
6
7 #include <dlfcn.h>
8 #if defined(OS_OPENBSD)
9 #include <sys/exec_elf.h>
10 #else
11 #include <elf.h>
12 #include <fcntl.h>
13 #endif
14 #include <sys/stat.h>
15 #include <sys/types.h>
16 #include <unistd.h>
17
18 #include "base/eintr_wrapper.h"
19 #include "base/file_util.h"
20 #include "base/string_split.h"
21 #include "base/string_util.h"
22 #include "base/sys_string_conversions.h"
23 #include "base/utf_string_conversions.h"
24 #include "webkit/glue/plugins/plugin_list.h"
25
26 // These headers must be included in this order to make the declaration gods
27 // happy.
28 #include "base/third_party/nspr/prcpucfg_linux.h"
29
30 namespace {
31
32 using NPAPI::PluginList;
33
34 // Copied from nsplugindefs.h instead of including the file since it has a bunch
35 // of dependencies.
36 enum nsPluginVariable {
37 nsPluginVariable_NameString = 1,
38 nsPluginVariable_DescriptionString = 2
39 };
40
41 // Read the ELF header and return true if it is usable on
42 // the current architecture (e.g. 32-bit ELF on 32-bit build).
43 // Returns false on other errors as well.
44 bool ELFMatchesCurrentArchitecture(const FilePath& filename) {
45 // First make sure we can open the file and it is in fact, a regular file.
46 struct stat stat_buf;
47 // Open with O_NONBLOCK so we don't block on pipes.
48 int fd = open(filename.value().c_str(), O_RDONLY|O_NONBLOCK);
49 if (fd < 0)
50 return false;
51 bool ret = (fstat(fd, &stat_buf) >= 0 && S_ISREG(stat_buf.st_mode));
52 if (HANDLE_EINTR(close(fd)) < 0)
53 return false;
54 if (!ret)
55 return false;
56
57 const size_t kELFBufferSize = 5;
58 char buffer[kELFBufferSize];
59 if (!file_util::ReadFile(filename, buffer, kELFBufferSize))
60 return false;
61
62 if (buffer[0] != ELFMAG0 ||
63 buffer[1] != ELFMAG1 ||
64 buffer[2] != ELFMAG2 ||
65 buffer[3] != ELFMAG3) {
66 // Not an ELF file, perhaps?
67 return false;
68 }
69
70 int elf_class = buffer[EI_CLASS];
71 #if defined(ARCH_CPU_32_BITS)
72 if (elf_class == ELFCLASS32)
73 return true;
74 #elif defined(ARCH_CPU_64_BITS)
75 if (elf_class == ELFCLASS64)
76 return true;
77 #endif
78
79 return false;
80 }
81
82 // This structure matches enough of nspluginwrapper's NPW_PluginInfo
83 // for us to extract the real plugin path.
84 struct __attribute__((packed)) NSPluginWrapperInfo {
85 char ident[32]; // NSPluginWrapper magic identifier (includes version).
86 char path[PATH_MAX]; // Path to wrapped plugin.
87 };
88
89 // Test a plugin for whether it's been wrapped by NSPluginWrapper, and
90 // if so attempt to unwrap it. Pass in an opened plugin handle; on
91 // success, |dl| and |unwrapped_path| will be filled in with the newly
92 // opened plugin. On failure, params are left unmodified.
93 void UnwrapNSPluginWrapper(void **dl, FilePath* unwrapped_path) {
94 NSPluginWrapperInfo* info =
95 reinterpret_cast<NSPluginWrapperInfo*>(dlsym(*dl, "NPW_Plugin"));
96 if (!info)
97 return; // Not a NSPW plugin.
98
99 // Here we could check the NSPW ident field for the versioning
100 // information, but the path field is available in all versions
101 // anyway.
102
103 // Grab the path to the wrapped plugin. Just in case the structure
104 // format changes, protect against the path not being null-terminated.
105 char* path_end = static_cast<char*>(memchr(info->path, '\0',
106 sizeof(info->path)));
107 if (!path_end)
108 path_end = info->path + sizeof(info->path);
109 FilePath path = FilePath(std::string(info->path, path_end - info->path));
110
111 if (!ELFMatchesCurrentArchitecture(path)) {
112 LOG(WARNING) << path.value() << " is nspluginwrapper wrapping a "
113 << "plugin for a different architecture; it will "
114 << "work better if you instead use a native plugin.";
115 return;
116 }
117
118 void* newdl = base::LoadNativeLibrary(path);
119 if (!newdl) {
120 // We couldn't load the unwrapped plugin for some reason, despite
121 // being able to load the wrapped one. Just use the wrapped one.
122 LOG_IF(ERROR, PluginList::DebugPluginLoading())
123 << "Could not use unwrapped nspluginwrapper plugin "
124 << unwrapped_path->value() << ", using the wrapped one.";
125 return;
126 }
127
128 // Unload the wrapped plugin, and use the wrapped plugin instead.
129 LOG_IF(ERROR, PluginList::DebugPluginLoading())
130 << "Using unwrapped version " << unwrapped_path->value()
131 << " of nspluginwrapper-wrapped plugin.";
132 base::UnloadNativeLibrary(*dl);
133 *dl = newdl;
134 *unwrapped_path = path;
135 }
136
137 } // anonymous namespace
138
139 namespace NPAPI {
140
141 bool PluginLib::ReadWebPluginInfo(const FilePath& filename,
142 WebPluginInfo* info) {
143 // The file to reference is:
144 // http://mxr.mozilla.org/firefox/source/modules/plugin/base/src/nsPluginsDirU nix.cpp
145
146 // Skip files that aren't appropriate for our architecture.
147 if (!ELFMatchesCurrentArchitecture(filename)) {
148 LOG_IF(ERROR, PluginList::DebugPluginLoading())
149 << "Skipping plugin " << filename.value()
150 << " because it doesn't match the current architecture.";
151 return false;
152 }
153
154 void* dl = base::LoadNativeLibrary(filename);
155 if (!dl) {
156 LOG_IF(ERROR, PluginList::DebugPluginLoading())
157 << "While reading plugin info, unable to load library "
158 << filename.value() << ", skipping.";
159 return false;
160 }
161
162 info->path = filename;
163 info->enabled = true;
164
165 // Attempt to swap in the wrapped plugin if this is nspluginwrapper.
166 UnwrapNSPluginWrapper(&dl, &info->path);
167
168 // See comments in plugin_lib_mac regarding this symbol.
169 typedef const char* (*NP_GetMimeDescriptionType)();
170 NP_GetMimeDescriptionType NP_GetMIMEDescription =
171 reinterpret_cast<NP_GetMimeDescriptionType>(
172 dlsym(dl, "NP_GetMIMEDescription"));
173 const char* mime_description = NULL;
174 if (NP_GetMIMEDescription)
175 mime_description = NP_GetMIMEDescription();
176
177 if (mime_description)
178 ParseMIMEDescription(mime_description, &info->mime_types);
179
180 // The plugin name and description live behind NP_GetValue calls.
181 typedef NPError (*NP_GetValueType)(void* unused,
182 nsPluginVariable variable,
183 void* value_out);
184 NP_GetValueType NP_GetValue =
185 reinterpret_cast<NP_GetValueType>(dlsym(dl, "NP_GetValue"));
186 if (NP_GetValue) {
187 const char* name = NULL;
188 NP_GetValue(NULL, nsPluginVariable_NameString, &name);
189 if (name)
190 info->name = UTF8ToUTF16(name);
191
192 const char* description = NULL;
193 NP_GetValue(NULL, nsPluginVariable_DescriptionString, &description);
194 if (description)
195 info->desc = UTF8ToUTF16(description);
196
197 LOG_IF(ERROR, PluginList::DebugPluginLoading())
198 << "Got info for plugin " << filename.value()
199 << " Name = \"" << UTF16ToUTF8(info->name)
200 << "\", Description = \"" << UTF16ToUTF8(info->desc) << "\".";
201 } else {
202 LOG_IF(ERROR, PluginList::DebugPluginLoading())
203 << "Plugin " << filename.value()
204 << " has no GetValue() and probably won't work.";
205 }
206
207 // Intentionally not unloading the plugin here, it can lead to crashes.
208
209 return true;
210 }
211
212 // static
213 void PluginLib::ParseMIMEDescription(
214 const std::string& description,
215 std::vector<WebPluginMimeType>* mime_types) {
216 // We parse the description here into WebPluginMimeType structures.
217 // Naively from the NPAPI docs you'd think you could use
218 // string-splitting, but the Firefox parser turns out to do something
219 // different: find the first colon, then the second, then a semi.
220 //
221 // See ParsePluginMimeDescription near
222 // http://mxr.mozilla.org/firefox/source/modules/plugin/base/src/nsPluginsDirU tils.h#53
223
224 std::string::size_type ofs = 0;
225 for (;;) {
226 WebPluginMimeType mime_type;
227
228 std::string::size_type end = description.find(':', ofs);
229 if (end == std::string::npos)
230 break;
231 mime_type.mime_type = description.substr(ofs, end - ofs);
232 ofs = end + 1;
233
234 end = description.find(':', ofs);
235 if (end == std::string::npos)
236 break;
237 const std::string extensions = description.substr(ofs, end - ofs);
238 base::SplitString(extensions, ',', &mime_type.file_extensions);
239 ofs = end + 1;
240
241 end = description.find(';', ofs);
242 // It's ok for end to run off the string here. If there's no
243 // trailing semicolon we consume the remainder of the string.
244 if (end != std::string::npos) {
245 mime_type.description = UTF8ToUTF16(description.substr(ofs, end - ofs));
246 } else {
247 mime_type.description = UTF8ToUTF16(description.substr(ofs));
248 }
249 mime_types->push_back(mime_type);
250 if (end == std::string::npos)
251 break;
252 ofs = end + 1;
253 }
254 }
255
256 } // namespace NPAPI
OLDNEW
« no previous file with comments | « webkit/glue/plugins/plugin_lib_mac.mm ('k') | webkit/glue/plugins/plugin_lib_unittest.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698