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#if PLUGIN_ARCHITECTURE(X11) && ENABLE(NETSCAPE_PLUGIN_API) 28 29#include "NetscapePluginModule.h" 30 31#include "PluginProcessProxy.h" 32#include "NetscapeBrowserFuncs.h" 33#include <WebCore/FileSystem.h> 34#include <errno.h> 35#include <fcntl.h> 36#include <sys/stat.h> 37#include <sys/types.h> 38#include <unistd.h> 39 40using namespace WebCore; 41 42namespace WebKit { 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} 62 63StdoutDevNullRedirector::~StdoutDevNullRedirector() 64{ 65 if (m_savedStdout != -1) 66 dup2(m_savedStdout, STDOUT_FILENO); 67} 68 69 70static void parseMIMEDescription(const String& mimeDescription, Vector<MimeClassInfo>& result) 71{ 72 ASSERT_ARG(result, result.isEmpty()); 73 74 Vector<String> types; 75 mimeDescription.lower().split(UChar(';'), false, types); 76 result.reserveInitialCapacity(types.size()); 77 78 size_t mimeInfoCount = 0; 79 for (size_t i = 0; i < types.size(); ++i) { 80 Vector<String> mimeTypeParts; 81 types[i].split(UChar(':'), true, mimeTypeParts); 82 if (mimeTypeParts.size() <= 0) 83 continue; 84 85 result.uncheckedAppend(MimeClassInfo()); 86 MimeClassInfo& mimeInfo = result[mimeInfoCount++]; 87 mimeInfo.type = mimeTypeParts[0]; 88 89 if (mimeTypeParts.size() > 1) 90 mimeTypeParts[1].split(UChar(','), false, mimeInfo.extensions); 91 92 if (mimeTypeParts.size() > 2) 93 mimeInfo.desc = mimeTypeParts[2]; 94 } 95} 96 97bool NetscapePluginModule::getPluginInfoForLoadedPlugin(RawPluginMetaData& metaData) 98{ 99 ASSERT(m_isInitialized); 100 101 Module* module = m_module.get(); 102 NPP_GetValueProcPtr NPP_GetValue = module->functionPointer<NPP_GetValueProcPtr>("NP_GetValue"); 103 if (!NPP_GetValue) 104 return false; 105 106 NP_GetMIMEDescriptionFuncPtr NP_GetMIMEDescription = module->functionPointer<NP_GetMIMEDescriptionFuncPtr>("NP_GetMIMEDescription"); 107 if (!NP_GetMIMEDescription) 108 return false; 109 110 char* buffer; 111 NPError error = NPP_GetValue(0, NPPVpluginNameString, &buffer); 112 if (error == NPERR_NO_ERROR) 113 metaData.name = String::fromUTF8(buffer); 114 115 error = NPP_GetValue(0, NPPVpluginDescriptionString, &buffer); 116 if (error == NPERR_NO_ERROR) 117 metaData.description = String::fromUTF8(buffer); 118 119 String mimeDescription = String::fromUTF8(NP_GetMIMEDescription()); 120 if (mimeDescription.isNull()) 121 return false; 122 123 metaData.mimeDescription = mimeDescription; 124 125 return true; 126} 127 128bool NetscapePluginModule::getPluginInfo(const String& pluginPath, PluginModuleInfo& plugin) 129{ 130 RawPluginMetaData metaData; 131 if (!PluginProcessProxy::scanPlugin(pluginPath, metaData)) 132 return false; 133 134 plugin.path = pluginPath; 135 plugin.info.file = pathGetFileName(pluginPath); 136 plugin.info.name = metaData.name; 137 plugin.info.desc = metaData.description; 138 parseMIMEDescription(metaData.mimeDescription, plugin.info.mimes); 139 140 return true; 141} 142 143void NetscapePluginModule::determineQuirks() 144{ 145#if CPU(X86_64) 146 RawPluginMetaData metaData; 147 if (!getPluginInfoForLoadedPlugin(metaData)) 148 return; 149 150 Vector<MimeClassInfo> mimeTypes; 151 parseMIMEDescription(metaData.mimeDescription, mimeTypes); 152 for (size_t i = 0; i < mimeTypes.size(); ++i) { 153 if (mimeTypes[i].type == "application/x-shockwave-flash") { 154 m_pluginQuirks.add(PluginQuirks::IgnoreRightClickInWindowlessMode); 155 break; 156 } 157 } 158#endif 159} 160 161static String truncateToSingleLine(const String& string) 162{ 163 unsigned oldLength = string.length(); 164 UChar* buffer; 165 String stringBuffer(StringImpl::createUninitialized(oldLength + 1, buffer)); 166 167 unsigned newLength = 0; 168 const UChar* start = string.characters(); 169 for (const UChar* c = start; c < start + oldLength; ++c) { 170 if (*c != UChar('\n')) 171 buffer[newLength++] = *c; 172 } 173 buffer[newLength++] = UChar('\n'); 174 175 String result = (newLength == oldLength + 1) ? stringBuffer : String(stringBuffer.characters16(), newLength); 176 ASSERT(result.endsWith(UChar('\n'))); 177 return result; 178} 179 180bool NetscapePluginModule::scanPlugin(const String& pluginPath) 181{ 182 RawPluginMetaData metaData; 183 184 { 185 // Don't allow the plugin to pollute the standard output. 186 StdoutDevNullRedirector stdOutRedirector; 187 188 // We are loading the plugin here since it does not seem to be a standardized way to 189 // get the needed informations from a UNIX plugin without loading it. 190 RefPtr<NetscapePluginModule> pluginModule = NetscapePluginModule::getOrCreate(pluginPath); 191 if (!pluginModule) 192 return false; 193 194 pluginModule->incrementLoadCount(); 195 bool success = pluginModule->getPluginInfoForLoadedPlugin(metaData); 196 pluginModule->decrementLoadCount(); 197 198 if (!success) 199 return false; 200 } 201 202 // Write data to standard output for the UI process. 203 String output[3] = { 204 truncateToSingleLine(metaData.name), 205 truncateToSingleLine(metaData.description), 206 truncateToSingleLine(metaData.mimeDescription) 207 }; 208 for (unsigned i = 0; i < 3; ++i) { 209 const String& line = output[i]; 210 const char* current = reinterpret_cast<const char*>(line.characters16()); 211 const char* end = reinterpret_cast<const char*>(line.characters16()) + (line.length() * sizeof(UChar)); 212 while (current < end) { 213 int result; 214 while ((result = fputc(*current, stdout)) == EOF && errno == EINTR) { } 215 ASSERT(result != EOF); 216 ++current; 217 } 218 } 219 220 fflush(stdout); 221 222 return true; 223} 224 225} // namespace WebKit 226 227#endif // PLUGIN_ARCHITECTURE(X11) && ENABLE(NETSCAPE_PLUGIN_API) 228