WebCore/plugins/PluginDatabase.cpp
changeset 2 303757a437d3
parent 0 4f2f89ce4247
equal deleted inserted replaced
0:4f2f89ce4247 2:303757a437d3
    28 #include "PluginDatabase.h"
    28 #include "PluginDatabase.h"
    29 
    29 
    30 #include "Frame.h"
    30 #include "Frame.h"
    31 #include "KURL.h"
    31 #include "KURL.h"
    32 #include "PluginPackage.h"
    32 #include "PluginPackage.h"
       
    33 #if ENABLE(NETSCAPE_PLUGIN_METADATA_CACHE)
       
    34 #include "FileSystem.h"
       
    35 #endif
    33 #include <stdlib.h>
    36 #include <stdlib.h>
    34 
    37 
    35 namespace WebCore {
    38 namespace WebCore {
    36 
    39 
    37 typedef HashMap<String, RefPtr<PluginPackage> > PluginPackageByNameMap;
    40 typedef HashMap<String, RefPtr<PluginPackage> > PluginPackageByNameMap;
    38 
    41 
       
    42 #if ENABLE(NETSCAPE_PLUGIN_METADATA_CACHE)
       
    43 static const size_t maximumPersistentPluginMetadataCacheSize = 32768;
       
    44 
       
    45 static bool gPersistentPluginMetadataCacheIsEnabled;
       
    46 
       
    47 String& persistentPluginMetadataCachePath()
       
    48 {
       
    49     DEFINE_STATIC_LOCAL(String, cachePath, ());
       
    50     return cachePath;
       
    51 }
       
    52 #endif
       
    53 
    39 PluginDatabase::PluginDatabase()
    54 PluginDatabase::PluginDatabase()
       
    55 #if ENABLE(NETSCAPE_PLUGIN_METADATA_CACHE)
       
    56     : m_persistentMetadataCacheIsLoaded(false)
       
    57 #endif
    40 {
    58 {
    41 }
    59 }
    42 
    60 
    43 PluginDatabase* PluginDatabase::installedPlugins(bool populate)
    61 PluginDatabase* PluginDatabase::installedPlugins(bool populate)
    44 {
    62 {
    72     refresh();
    90     refresh();
    73 }
    91 }
    74 
    92 
    75 bool PluginDatabase::refresh()
    93 bool PluginDatabase::refresh()
    76 {
    94 {
       
    95 #if ENABLE(NETSCAPE_PLUGIN_METADATA_CACHE)
       
    96     if (!m_persistentMetadataCacheIsLoaded)
       
    97         loadPersistentMetadataCache();
       
    98 #endif
    77     bool pluginSetChanged = false;
    99     bool pluginSetChanged = false;
    78 
   100 
    79     if (!m_plugins.isEmpty()) {
   101     if (!m_plugins.isEmpty()) {
    80         PluginSet pluginsToUnload;
   102         PluginSet pluginsToUnload;
    81         getDeletedPlugins(pluginsToUnload);
   103         getDeletedPlugins(pluginsToUnload);
   123     // Cache all the paths we found with their timestamps for next time.
   145     // Cache all the paths we found with their timestamps for next time.
   124     pathsWithTimes.swap(m_pluginPathsWithTimes);
   146     pathsWithTimes.swap(m_pluginPathsWithTimes);
   125 
   147 
   126     if (!pluginSetChanged)
   148     if (!pluginSetChanged)
   127         return false;
   149         return false;
       
   150 
       
   151 #if ENABLE(NETSCAPE_PLUGIN_METADATA_CACHE)
       
   152     updatePersistentMetadataCache();
       
   153 #endif
   128 
   154 
   129     m_registeredMIMETypes.clear();
   155     m_registeredMIMETypes.clear();
   130 
   156 
   131     // Register plug-in MIME types
   157     // Register plug-in MIME types
   132     PluginSet::const_iterator end = m_plugins.end();
   158     PluginSet::const_iterator end = m_plugins.end();
   180         PluginPackage* plugin = (*it).get();
   206         PluginPackage* plugin = (*it).get();
   181 
   207 
   182         if (!plugin->isEnabled())
   208         if (!plugin->isEnabled())
   183             continue;
   209             continue;
   184 
   210 
   185         if (plugin->mimeToDescriptions().contains(key))
   211         if (plugin->mimeToDescriptions().contains(key)) {
       
   212 #if ENABLE(NETSCAPE_PLUGIN_METADATA_CACHE)
       
   213             if (!plugin->ensurePluginLoaded())
       
   214                 continue;
       
   215 #endif
   186             pluginChoices.append(plugin);
   216             pluginChoices.append(plugin);
       
   217         }
   187     }
   218     }
   188 
   219 
   189     if (pluginChoices.isEmpty())
   220     if (pluginChoices.isEmpty())
   190         return 0;
   221         return 0;
   191 
   222 
   220                     PluginPackage* plugin = (*it).get();
   251                     PluginPackage* plugin = (*it).get();
   221 
   252 
   222                     if (preferredPlugin && PluginPackage::equal(*plugin, *preferredPlugin))
   253                     if (preferredPlugin && PluginPackage::equal(*plugin, *preferredPlugin))
   223                         return mimeType;
   254                         return mimeType;
   224 
   255 
       
   256 #if ENABLE(NETSCAPE_PLUGIN_METADATA_CACHE)
       
   257                     if (!plugin->ensurePluginLoaded())
       
   258                         continue;
       
   259 #endif
   225                     pluginChoices.append(plugin);
   260                     pluginChoices.append(plugin);
   226                     mimeTypeForPlugin.add(plugin, mimeType);
   261                     mimeTypeForPlugin.add(plugin, mimeType);
   227                     foundMapping = true;
   262                     foundMapping = true;
   228                     break;
   263                     break;
   229                 }
   264                 }
   313     m_plugins.clear();
   348     m_plugins.clear();
   314     m_pluginsByPath.clear();
   349     m_pluginsByPath.clear();
   315     m_pluginPathsWithTimes.clear();
   350     m_pluginPathsWithTimes.clear();
   316     m_registeredMIMETypes.clear();
   351     m_registeredMIMETypes.clear();
   317     m_preferredPlugins.clear();
   352     m_preferredPlugins.clear();
       
   353 #if ENABLE(NETSCAPE_PLUGIN_METADATA_CACHE)
       
   354     m_persistentMetadataCacheIsLoaded = false;
       
   355 #endif
   318 }
   356 }
   319 
   357 
   320 #if (!OS(WINCE)) && (!OS(SYMBIAN)) && (!OS(WINDOWS) || !ENABLE(NETSCAPE_PLUGIN_API))
   358 #if (!OS(WINCE)) && (!OS(SYMBIAN)) && (!OS(WINDOWS) || !ENABLE(NETSCAPE_PLUGIN_API))
   321 // For Safari/Win the following three methods are implemented
   359 // For Safari/Win the following three methods are implemented
   322 // in PluginDatabaseWin.cpp, but if we can use WebCore constructs
   360 // in PluginDatabaseWin.cpp, but if we can use WebCore constructs
   425     }
   463     }
   426 }
   464 }
   427 
   465 
   428 #endif // !OS(SYMBIAN) && !OS(WINDOWS)
   466 #endif // !OS(SYMBIAN) && !OS(WINDOWS)
   429 
   467 
   430 }
   468 #if ENABLE(NETSCAPE_PLUGIN_METADATA_CACHE)
       
   469 
       
   470 static void fillBufferWithContentsOfFile(PlatformFileHandle file, Vector<char>& buffer)
       
   471 {
       
   472     size_t bufferSize = 0;
       
   473     size_t bufferCapacity = 1024;
       
   474     buffer.resize(bufferCapacity);
       
   475 
       
   476     do {
       
   477         bufferSize += readFromFile(file, buffer.data() + bufferSize, bufferCapacity - bufferSize);
       
   478         if (bufferSize == bufferCapacity) {
       
   479             if (bufferCapacity < maximumPersistentPluginMetadataCacheSize) {
       
   480                 bufferCapacity *= 2;
       
   481                 buffer.resize(bufferCapacity);
       
   482             } else {
       
   483                 buffer.clear();
       
   484                 return;
       
   485             }
       
   486         } else
       
   487             break;
       
   488     } while (true);
       
   489 
       
   490     buffer.shrink(bufferSize);
       
   491 }
       
   492 
       
   493 static bool readUTF8String(String& resultString, char*& start, const char* end)
       
   494 {
       
   495     if (start >= end)
       
   496         return false;
       
   497 
       
   498     int len = strlen(start);
       
   499     resultString = String::fromUTF8(start, len);
       
   500     start += len + 1;
       
   501 
       
   502     return true;
       
   503 }
       
   504 
       
   505 static bool readTime(time_t& resultTime, char*& start, const char* end)
       
   506 {
       
   507     if (start + sizeof(time_t) >= end)
       
   508         return false;
       
   509 
       
   510     resultTime = *reinterpret_cast<time_t*>(start);
       
   511     start += sizeof(time_t);
       
   512 
       
   513     return true;
       
   514 }
       
   515 
       
   516 static const char schemaVersion = '1';
       
   517 static const char persistentPluginMetadataCacheFilename[] = "PluginMetadataCache.bin";
       
   518 
       
   519 void PluginDatabase::loadPersistentMetadataCache()
       
   520 {
       
   521     if (!isPersistentMetadataCacheEnabled() || persistentMetadataCachePath().isEmpty())
       
   522         return;
       
   523 
       
   524     PlatformFileHandle file;
       
   525     String absoluteCachePath = pathByAppendingComponent(persistentMetadataCachePath(), persistentPluginMetadataCacheFilename);
       
   526     file = openFile(absoluteCachePath, OpenForRead);
       
   527 
       
   528     if (!isHandleValid(file))
       
   529         return;
       
   530 
       
   531     // Mark cache as loaded regardless of success or failure. If
       
   532     // there's error in the cache, we won't try to load it anymore.
       
   533     m_persistentMetadataCacheIsLoaded = true;
       
   534 
       
   535     Vector<char> fileContents;
       
   536     fillBufferWithContentsOfFile(file, fileContents);
       
   537     closeFile(file);
       
   538 
       
   539     if (fileContents.size() < 2 || fileContents.first() != schemaVersion || fileContents.last() != '\0') {
       
   540         LOG_ERROR("Unable to read plugin metadata cache: corrupt schema");
       
   541         deleteFile(absoluteCachePath);
       
   542         return;
       
   543     }
       
   544 
       
   545     char* bufferPos = fileContents.data() + 1;
       
   546     char* end = fileContents.data() + fileContents.size();
       
   547 
       
   548     PluginSet cachedPlugins;
       
   549     HashMap<String, time_t> cachedPluginPathsWithTimes;
       
   550     HashMap<String, RefPtr<PluginPackage> > cachedPluginsByPath;
       
   551 
       
   552     while (bufferPos < end) {
       
   553         String path;
       
   554         time_t lastModified;
       
   555         String name;
       
   556         String desc;
       
   557         String mimeDesc;
       
   558         if (!(readUTF8String(path, bufferPos, end)
       
   559               && readTime(lastModified, bufferPos, end)
       
   560               && readUTF8String(name, bufferPos, end)
       
   561               && readUTF8String(desc, bufferPos, end)
       
   562               && readUTF8String(mimeDesc, bufferPos, end))) {
       
   563             LOG_ERROR("Unable to read plugin metadata cache: corrupt data");
       
   564             deleteFile(absoluteCachePath);
       
   565             return;
       
   566         }
       
   567 
       
   568         // Skip metadata that points to plugins from directories that
       
   569         // are not part of plugin directory list anymore.
       
   570         String pluginDirectoryName = directoryName(path);
       
   571         if (m_pluginDirectories.find(pluginDirectoryName) == WTF::notFound)
       
   572             continue;
       
   573 
       
   574         RefPtr<PluginPackage> package = PluginPackage::createPackageFromCache(path, lastModified, name, desc, mimeDesc);
       
   575 
       
   576         if (package && cachedPlugins.add(package).second) {
       
   577             cachedPluginPathsWithTimes.add(package->path(), package->lastModified());
       
   578             cachedPluginsByPath.add(package->path(), package);
       
   579         }
       
   580     }
       
   581 
       
   582     m_plugins.swap(cachedPlugins);
       
   583     m_pluginsByPath.swap(cachedPluginsByPath);
       
   584     m_pluginPathsWithTimes.swap(cachedPluginPathsWithTimes);
       
   585 }
       
   586 
       
   587 static bool writeUTF8String(PlatformFileHandle file, const String& string)
       
   588 {
       
   589     CString utf8String = string.utf8();
       
   590     int length = utf8String.length() + 1;
       
   591     return writeToFile(file, utf8String.data(), length) == length;
       
   592 }
       
   593 
       
   594 static bool writeTime(PlatformFileHandle file, const time_t& time)
       
   595 {
       
   596     return writeToFile(file, reinterpret_cast<const char*>(&time), sizeof(time_t)) == sizeof(time_t);
       
   597 }
       
   598 
       
   599 void PluginDatabase::updatePersistentMetadataCache()
       
   600 {
       
   601     if (!isPersistentMetadataCacheEnabled() || persistentMetadataCachePath().isEmpty())
       
   602         return;
       
   603 
       
   604     makeAllDirectories(persistentMetadataCachePath());
       
   605     String absoluteCachePath = pathByAppendingComponent(persistentMetadataCachePath(), persistentPluginMetadataCacheFilename);
       
   606     deleteFile(absoluteCachePath);
       
   607 
       
   608     if (m_plugins.isEmpty())
       
   609         return;
       
   610 
       
   611     PlatformFileHandle file;
       
   612     file = openFile(absoluteCachePath, OpenForWrite);
       
   613 
       
   614     if (!isHandleValid(file)) {
       
   615         LOG_ERROR("Unable to open plugin metadata cache for saving");
       
   616         return;
       
   617     }
       
   618 
       
   619     char localSchemaVersion = schemaVersion;
       
   620     if (writeToFile(file, &localSchemaVersion, 1) != 1) {
       
   621         LOG_ERROR("Unable to write plugin metadata cache schema");
       
   622         closeFile(file);
       
   623         deleteFile(absoluteCachePath);
       
   624         return;
       
   625     }
       
   626 
       
   627     PluginSet::const_iterator end = m_plugins.end();
       
   628     for (PluginSet::const_iterator it = m_plugins.begin(); it != end; ++it) {
       
   629         if (!(writeUTF8String(file, (*it)->path())
       
   630               && writeTime(file, (*it)->lastModified())
       
   631               && writeUTF8String(file, (*it)->name())
       
   632               && writeUTF8String(file, (*it)->description())
       
   633               && writeUTF8String(file, (*it)->fullMIMEDescription()))) {
       
   634             LOG_ERROR("Unable to write plugin metadata to cache");
       
   635             closeFile(file);
       
   636             deleteFile(absoluteCachePath);
       
   637             return;
       
   638         }
       
   639     }
       
   640 
       
   641     closeFile(file);
       
   642 }
       
   643 
       
   644 bool PluginDatabase::isPersistentMetadataCacheEnabled()
       
   645 {
       
   646     return gPersistentPluginMetadataCacheIsEnabled;
       
   647 }
       
   648 
       
   649 void PluginDatabase::setPersistentMetadataCacheEnabled(bool isEnabled)
       
   650 {
       
   651     gPersistentPluginMetadataCacheIsEnabled = isEnabled;
       
   652 }
       
   653 
       
   654 String PluginDatabase::persistentMetadataCachePath()
       
   655 {
       
   656     return WebCore::persistentPluginMetadataCachePath();
       
   657 }
       
   658 
       
   659 void PluginDatabase::setPersistentMetadataCachePath(const String& persistentMetadataCachePath)
       
   660 {
       
   661     WebCore::persistentPluginMetadataCachePath() = persistentMetadataCachePath;
       
   662 }
       
   663 #endif
       
   664 }