1/*
2 * Copyright (C) 2010 Apple Inc. All rights reserved.
3 *
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions
6 * are met:
7 * 1. Redistributions of source code must retain the above copyright
8 * notice, this list of conditions and the following disclaimer.
9 * 2. Redistributions in binary form must reproduce the above copyright
10 * notice, this list of conditions and the following disclaimer in the
11 * documentation and/or other materials provided with the distribution.
12 *
13 * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS''
14 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
15 * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
16 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS
17 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
18 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
19 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
20 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
21 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
22 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
23 * THE POSSIBILITY OF SUCH DAMAGE.
24 */
25
26#include "config.h"
27#include "NetscapePluginModule.h"
28
29#if PLUGIN_ARCHITECTURE(UNIX) && ENABLE(NETSCAPE_PLUGIN_API)
30
31#include "NetscapeBrowserFuncs.h"
32#include "PluginProcessProxy.h"
33#include <errno.h>
34#include <fcntl.h>
35#include <sys/stat.h>
36#include <sys/types.h>
37#include <unistd.h>
38#include <wtf/FileSystem.h>
39#include <wtf/text/StringBuilder.h>
40
41namespace WebKit {
42using namespace WebCore;
43
44class StdoutDevNullRedirector {
45public:
46 StdoutDevNullRedirector();
47 ~StdoutDevNullRedirector();
48
49private:
50 int m_savedStdout;
51};
52
53StdoutDevNullRedirector::StdoutDevNullRedirector()
54 : m_savedStdout(-1)
55{
56 int newStdout = open("/dev/null", O_WRONLY);
57 if (newStdout == -1)
58 return;
59 m_savedStdout = dup(STDOUT_FILENO);
60 dup2(newStdout, STDOUT_FILENO);
61 close(newStdout);
62}
63
64StdoutDevNullRedirector::~StdoutDevNullRedirector()
65{
66 if (m_savedStdout != -1) {
67 dup2(m_savedStdout, STDOUT_FILENO);
68 close(m_savedStdout);
69 }
70}
71
72
73void NetscapePluginModule::parseMIMEDescription(const String& mimeDescription, Vector<MimeClassInfo>& result)
74{
75 ASSERT_ARG(result, result.isEmpty());
76
77 Vector<String> types = mimeDescription.convertToASCIILowercase().split(';');
78 result.reserveInitialCapacity(types.size());
79
80 size_t mimeInfoCount = 0;
81 for (size_t i = 0; i < types.size(); ++i) {
82 Vector<String> mimeTypeParts = types[i].splitAllowingEmptyEntries(':');
83 if (mimeTypeParts.size() <= 0)
84 continue;
85
86 result.uncheckedAppend(MimeClassInfo());
87 MimeClassInfo& mimeInfo = result[mimeInfoCount++];
88 mimeInfo.type = mimeTypeParts[0];
89
90 if (mimeTypeParts.size() > 1)
91 mimeInfo.extensions = mimeTypeParts[1].split(',');
92
93 if (mimeTypeParts.size() > 2)
94 mimeInfo.desc = mimeTypeParts[2];
95 }
96}
97
98String NetscapePluginModule::buildMIMEDescription(const Vector<MimeClassInfo>& mimeDescription)
99{
100 StringBuilder builder;
101
102 size_t mimeInfoCount = mimeDescription.size();
103 for (size_t i = 0; i < mimeInfoCount; ++i) {
104 const MimeClassInfo& mimeInfo = mimeDescription[i];
105 builder.append(mimeInfo.type);
106 builder.append(':');
107
108 size_t extensionsCount = mimeInfo.extensions.size();
109 for (size_t j = 0; j < extensionsCount; ++j) {
110 builder.append(mimeInfo.extensions[j]);
111 if (j != extensionsCount - 1)
112 builder.append(',');
113 }
114 builder.append(':');
115
116 builder.append(mimeInfo.desc);
117 if (i != mimeInfoCount - 1)
118 builder.append(';');
119 }
120
121 return builder.toString();
122}
123
124bool NetscapePluginModule::getPluginInfoForLoadedPlugin(RawPluginMetaData& metaData)
125{
126 ASSERT(m_isInitialized);
127
128 Module* module = m_module.get();
129 NPP_GetValueProcPtr NPP_GetValue = module->functionPointer<NPP_GetValueProcPtr>("NP_GetValue");
130 if (!NPP_GetValue)
131 return false;
132
133 NP_GetMIMEDescriptionFuncPtr NP_GetMIMEDescription = module->functionPointer<NP_GetMIMEDescriptionFuncPtr>("NP_GetMIMEDescription");
134 if (!NP_GetMIMEDescription)
135 return false;
136
137 char* buffer;
138 NPError error = NPP_GetValue(0, NPPVpluginNameString, &buffer);
139 if (error == NPERR_NO_ERROR)
140 metaData.name = String::fromUTF8(buffer);
141
142 error = NPP_GetValue(0, NPPVpluginDescriptionString, &buffer);
143 if (error == NPERR_NO_ERROR)
144 metaData.description = String::fromUTF8(buffer);
145
146 String mimeDescription = String::fromUTF8(NP_GetMIMEDescription());
147 if (mimeDescription.isNull())
148 return false;
149
150 metaData.mimeDescription = mimeDescription;
151
152 return true;
153}
154
155bool NetscapePluginModule::getPluginInfo(const String& pluginPath, PluginModuleInfo& plugin)
156{
157 RawPluginMetaData metaData;
158 if (!PluginProcessProxy::scanPlugin(pluginPath, metaData))
159 return false;
160
161 plugin.path = pluginPath;
162 plugin.info.file = FileSystem::pathGetFileName(pluginPath);
163 plugin.info.name = metaData.name;
164 plugin.info.desc = metaData.description;
165 parseMIMEDescription(metaData.mimeDescription, plugin.info.mimes);
166#if PLATFORM(GTK)
167 plugin.requiresGtk2 = metaData.requiresGtk2;
168#endif
169
170 return true;
171}
172
173void NetscapePluginModule::determineQuirks()
174{
175 RawPluginMetaData metaData;
176 if (!getPluginInfoForLoadedPlugin(metaData))
177 return;
178
179 Vector<MimeClassInfo> mimeTypes;
180 parseMIMEDescription(metaData.mimeDescription, mimeTypes);
181
182#if PLATFORM(X11)
183 for (size_t i = 0; i < mimeTypes.size(); ++i) {
184 if (mimeTypes[i].type == "application/x-shockwave-flash") {
185#if CPU(X86_64)
186 m_pluginQuirks.add(PluginQuirks::IgnoreRightClickInWindowlessMode);
187#endif
188 m_pluginQuirks.add(PluginQuirks::DoNotCancelSrcStreamInWindowedMode);
189 break;
190 }
191 }
192#endif // PLATFORM(X11)
193}
194
195static void writeCharacter(char byte)
196{
197 int result;
198 while ((result = fputc(byte, stdout)) == EOF && errno == EINTR) { }
199 ASSERT(result != EOF);
200}
201
202static void writeLine(const String& line)
203{
204 CString utf8String = line.utf8();
205 const char* utf8Data = utf8String.data();
206
207 for (unsigned i = 0; i < utf8String.length(); i++) {
208 char character = utf8Data[i];
209 if (character != '\n')
210 writeCharacter(character);
211 }
212 writeCharacter('\n');
213}
214
215bool NetscapePluginModule::scanPlugin(const String& pluginPath)
216{
217 RawPluginMetaData metaData;
218
219 {
220 // Don't allow the plugin to pollute the standard output.
221 StdoutDevNullRedirector stdOutRedirector;
222
223 // We are loading the plugin here since it does not seem to be a standardized way to
224 // get the needed informations from a UNIX plugin without loading it.
225 RefPtr<NetscapePluginModule> pluginModule = NetscapePluginModule::getOrCreate(pluginPath);
226 if (!pluginModule)
227 return false;
228
229 pluginModule->incrementLoadCount();
230 bool success = pluginModule->getPluginInfoForLoadedPlugin(metaData);
231 pluginModule->decrementLoadCount();
232
233 if (!success)
234 return false;
235 }
236
237 // Write data to standard output for the UI process.
238 writeLine(metaData.name);
239 writeLine(metaData.description);
240 writeLine(metaData.mimeDescription);
241
242 fflush(stdout);
243
244 return true;
245}
246
247} // namespace WebKit
248
249#endif // PLUGIN_ARCHITECTURE(UNIX) && ENABLE(NETSCAPE_PLUGIN_API)
250