LCOV - code coverage report
Current view: top level - dom/plugins/base - nsPluginHost.cpp (source / functions) Hit Total Coverage
Test: output.info Lines: 156 1763 8.8 %
Date: 2017-07-14 16:53:18 Functions: 20 137 14.6 %
Legend: Lines: hit not hit

          Line data    Source code
       1             : /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
       2             : /* This Source Code Form is subject to the terms of the Mozilla Public
       3             :  * License, v. 2.0. If a copy of the MPL was not distributed with this
       4             :  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
       5             : 
       6             : /* nsPluginHost.cpp - top-level plugin management code */
       7             : 
       8             : #include "nscore.h"
       9             : #include "nsPluginHost.h"
      10             : 
      11             : #include <cstdlib>
      12             : #include <stdio.h>
      13             : #include "prio.h"
      14             : #include "nsNPAPIPlugin.h"
      15             : #include "nsNPAPIPluginStreamListener.h"
      16             : #include "nsNPAPIPluginInstance.h"
      17             : #include "nsPluginInstanceOwner.h"
      18             : #include "nsObjectLoadingContent.h"
      19             : #include "nsIHTTPHeaderListener.h"
      20             : #include "nsIHttpHeaderVisitor.h"
      21             : #include "nsIObserverService.h"
      22             : #include "nsIHttpProtocolHandler.h"
      23             : #include "nsIHttpChannel.h"
      24             : #include "nsIUploadChannel.h"
      25             : #include "nsIByteRangeRequest.h"
      26             : #include "nsIStreamListener.h"
      27             : #include "nsIInputStream.h"
      28             : #include "nsIOutputStream.h"
      29             : #include "nsIURL.h"
      30             : #include "nsTArray.h"
      31             : #include "nsReadableUtils.h"
      32             : #include "nsIStreamConverterService.h"
      33             : #include "nsIFile.h"
      34             : #if defined(XP_MACOSX)
      35             : #include "nsILocalFileMac.h"
      36             : #endif
      37             : #include "nsISeekableStream.h"
      38             : #include "nsNetUtil.h"
      39             : #include "nsIFileStreams.h"
      40             : #include "nsISimpleEnumerator.h"
      41             : #include "nsIStringStream.h"
      42             : #include "nsIProgressEventSink.h"
      43             : #include "nsIDocument.h"
      44             : #include "nsPluginLogging.h"
      45             : #include "nsIScriptChannel.h"
      46             : #include "nsIBlocklistService.h"
      47             : #include "nsVersionComparator.h"
      48             : #include "nsIObjectLoadingContent.h"
      49             : #include "nsIWritablePropertyBag2.h"
      50             : #include "nsICategoryManager.h"
      51             : #include "nsPluginStreamListenerPeer.h"
      52             : #include "mozilla/dom/ContentChild.h"
      53             : #include "mozilla/dom/ContentParent.h"
      54             : #include "mozilla/dom/FakePluginTagInitBinding.h"
      55             : #include "mozilla/LoadInfo.h"
      56             : #include "mozilla/plugins/PluginBridge.h"
      57             : #include "mozilla/plugins/PluginTypes.h"
      58             : #include "mozilla/Preferences.h"
      59             : #include "mozilla/ipc/URIUtils.h"
      60             : 
      61             : #include "nsEnumeratorUtils.h"
      62             : #include "nsXPCOM.h"
      63             : #include "nsXPCOMCID.h"
      64             : #include "nsISupportsPrimitives.h"
      65             : 
      66             : #include "nsXULAppAPI.h"
      67             : #include "nsIXULRuntime.h"
      68             : 
      69             : // for the dialog
      70             : #include "nsIWindowWatcher.h"
      71             : #include "nsIDOMElement.h"
      72             : #include "nsIDOMWindow.h"
      73             : 
      74             : #include "nsNetCID.h"
      75             : #include "mozilla/Sprintf.h"
      76             : #include "nsThreadUtils.h"
      77             : #include "nsIInputStreamTee.h"
      78             : #include "nsQueryObject.h"
      79             : 
      80             : #include "nsDirectoryServiceDefs.h"
      81             : #include "nsAppDirectoryServiceDefs.h"
      82             : #include "nsPluginDirServiceProvider.h"
      83             : 
      84             : #include "nsUnicharUtils.h"
      85             : #include "nsPluginManifestLineReader.h"
      86             : 
      87             : #include "nsIWeakReferenceUtils.h"
      88             : #include "nsIPresShell.h"
      89             : #include "nsPluginNativeWindow.h"
      90             : #include "nsIContentPolicy.h"
      91             : #include "nsContentPolicyUtils.h"
      92             : #include "mozilla/TimeStamp.h"
      93             : #include "mozilla/Telemetry.h"
      94             : #include "nsIImageLoadingContent.h"
      95             : #include "mozilla/Preferences.h"
      96             : #include "nsVersionComparator.h"
      97             : #include "NullPrincipal.h"
      98             : 
      99             : #if defined(XP_WIN)
     100             : #include "nsIWindowMediator.h"
     101             : #include "nsIBaseWindow.h"
     102             : #include "windows.h"
     103             : #include "winbase.h"
     104             : #endif
     105             : 
     106             : #ifdef ANDROID
     107             : #include <android/log.h>
     108             : #define LOG(args...)  __android_log_print(ANDROID_LOG_INFO, "GeckoPlugins" , ## args)
     109             : #endif
     110             : 
     111             : #if MOZ_CRASHREPORTER
     112             : #include "nsExceptionHandler.h"
     113             : #endif
     114             : 
     115             : #include "npapi.h"
     116             : 
     117             : using namespace mozilla;
     118             : using mozilla::TimeStamp;
     119             : using mozilla::plugins::FakePluginTag;
     120             : using mozilla::plugins::PluginTag;
     121             : using mozilla::dom::FakePluginTagInit;
     122             : using mozilla::dom::FakePluginMimeEntry;
     123             : 
     124             : // Null out a strong ref to a linked list iteratively to avoid
     125             : // exhausting the stack (bug 486349).
     126             : #define NS_ITERATIVE_UNREF_LIST(type_, list_, mNext_)                \
     127             :   {                                                                  \
     128             :     while (list_) {                                                  \
     129             :       type_ temp = list_->mNext_;                                    \
     130             :       list_->mNext_ = nullptr;                                       \
     131             :       list_ = temp;                                                  \
     132             :     }                                                                \
     133             :   }
     134             : 
     135             : // this is the name of the directory which will be created
     136             : // to cache temporary files.
     137             : #define kPluginTmpDirName NS_LITERAL_CSTRING("plugtmp")
     138             : 
     139             : static const char *kPrefWhitelist = "plugin.allowed_types";
     140             : static const char *kPrefLoadInParentPrefix = "plugin.load_in_parent_process.";
     141             : static const char *kPrefDisableFullPage = "plugin.disable_full_page_plugin_for_types";
     142             : static const char *kPrefJavaMIME = "plugin.java.mime";
     143             : 
     144             : // How long we wait before unloading an idle plugin process.
     145             : // Defaults to 30 seconds.
     146             : static const char *kPrefUnloadPluginTimeoutSecs = "dom.ipc.plugins.unloadTimeoutSecs";
     147             : static const uint32_t kDefaultPluginUnloadingTimeout = 30;
     148             : 
     149             : static const char *kPluginRegistryVersion = "0.18";
     150             : 
     151             : static const char kDirectoryServiceContractID[] = "@mozilla.org/file/directory_service;1";
     152             : 
     153             : #define kPluginRegistryFilename NS_LITERAL_CSTRING("pluginreg.dat")
     154             : 
     155             : LazyLogModule nsPluginLogging::gNPNLog(NPN_LOG_NAME);
     156             : LazyLogModule nsPluginLogging::gNPPLog(NPP_LOG_NAME);
     157             : LazyLogModule nsPluginLogging::gPluginLog(PLUGIN_LOG_NAME);
     158             : 
     159             : // #defines for plugin cache and prefs
     160             : #define NS_PREF_MAX_NUM_CACHED_INSTANCES "browser.plugins.max_num_cached_plugins"
     161             : // Raise this from '10' to '50' to work around a bug in Apple's current Java
     162             : // plugins on OS X Lion and SnowLeopard.  See bug 705931.
     163             : #define DEFAULT_NUMBER_OF_STOPPED_INSTANCES 50
     164             : 
     165             : nsIFile *nsPluginHost::sPluginTempDir;
     166             : nsPluginHost *nsPluginHost::sInst;
     167             : 
     168             : /* to cope with short read */
     169             : /* we should probably put this into a global library now that this is the second
     170             :    time we need this. */
     171             : static
     172             : int32_t
     173           0 : busy_beaver_PR_Read(PRFileDesc *fd, void * start, int32_t len)
     174             : {
     175             :     int n;
     176           0 :     int32_t remaining = len;
     177             : 
     178           0 :     while (remaining > 0)
     179             :     {
     180           0 :         n = PR_Read(fd, start, remaining);
     181           0 :         if (n < 0)
     182             :         {
     183             :             /* may want to repeat if errno == EINTR */
     184           0 :             if( (len - remaining) == 0 ) // no octet is ever read
     185           0 :                 return -1;
     186           0 :             break;
     187             :         }
     188           0 :         remaining -= n;
     189           0 :         char *cp = (char *) start;
     190           0 :         cp += n;
     191           0 :         start = cp;
     192             :     }
     193           0 :     return len - remaining;
     194             : }
     195             : 
     196           0 : NS_IMPL_ISUPPORTS0(nsInvalidPluginTag)
     197             : 
     198           0 : nsInvalidPluginTag::nsInvalidPluginTag(const char* aFullPath, int64_t aLastModifiedTime)
     199             : : mFullPath(aFullPath),
     200             :   mLastModifiedTime(aLastModifiedTime),
     201           0 :   mSeen(false)
     202           0 : {}
     203             : 
     204             : nsInvalidPluginTag::~nsInvalidPluginTag() = default;
     205             : 
     206             : // Helper to check for a MIME in a comma-delimited preference
     207             : static bool
     208           0 : IsTypeInList(const nsCString& aMimeType, nsCString aTypeList)
     209             : {
     210           0 :   nsAutoCString searchStr;
     211           0 :   searchStr.Assign(',');
     212           0 :   searchStr.Append(aTypeList);
     213           0 :   searchStr.Append(',');
     214             : 
     215           0 :   nsACString::const_iterator start, end;
     216             : 
     217           0 :   searchStr.BeginReading(start);
     218           0 :   searchStr.EndReading(end);
     219             : 
     220           0 :   nsAutoCString commaSeparated;
     221           0 :   commaSeparated.Assign(',');
     222           0 :   commaSeparated += aMimeType;
     223           0 :   commaSeparated.Append(',');
     224             : 
     225             :   // Lower-case the search string and MIME type to properly handle a mixed-case
     226             :   // type, as MIME types are case insensitive.
     227           0 :   ToLowerCase(searchStr);
     228           0 :   ToLowerCase(commaSeparated);
     229             : 
     230           0 :   return FindInReadable(commaSeparated, start, end);
     231             : }
     232             : 
     233             : // flat file reg funcs
     234             : static
     235           0 : bool ReadSectionHeader(nsPluginManifestLineReader& reader, const char *token)
     236             : {
     237           0 :   do {
     238           0 :     if (*reader.LinePtr() == '[') {
     239           0 :       char* p = reader.LinePtr() + (reader.LineLength() - 1);
     240           0 :       if (*p != ']')
     241           0 :         break;
     242           0 :       *p = 0;
     243             : 
     244             :       char* values[1];
     245           0 :       if (1 != reader.ParseLine(values, 1))
     246           0 :         break;
     247             :       // ignore the leading '['
     248           0 :       if (PL_strcmp(values[0]+1, token)) {
     249           0 :         break; // it's wrong token
     250             :       }
     251           0 :       return true;
     252             :     }
     253             :   } while (reader.NextLine());
     254           0 :   return false;
     255             : }
     256             : 
     257           0 : static bool UnloadPluginsASAP()
     258             : {
     259           0 :   return (Preferences::GetUint(kPrefUnloadPluginTimeoutSecs, kDefaultPluginUnloadingTimeout) == 0);
     260             : }
     261             : 
     262           3 : nsPluginHost::nsPluginHost()
     263             :   : mPluginsLoaded(false)
     264             :   , mOverrideInternalTypes(false)
     265             :   , mPluginsDisabled(false)
     266           3 :   , mPluginEpoch(0)
     267             : {
     268             :   // check to see if pref is set at startup to let plugins take over in
     269             :   // full page mode for certain image mime types that we handle internally
     270           3 :   mOverrideInternalTypes =
     271           3 :     Preferences::GetBool("plugin.override_internal_types", false);
     272             : 
     273           3 :   mPluginsDisabled = Preferences::GetBool("plugin.disable", false);
     274             : 
     275           3 :   Preferences::AddStrongObserver(this, "plugin.disable");
     276             : 
     277             :   nsCOMPtr<nsIObserverService> obsService =
     278           6 :     mozilla::services::GetObserverService();
     279           3 :   if (obsService) {
     280           3 :     obsService->AddObserver(this, NS_XPCOM_SHUTDOWN_OBSERVER_ID, false);
     281           3 :     obsService->AddObserver(this, "blocklist-updated", false);
     282             : #ifdef MOZ_WIDGET_ANDROID
     283             :     obsService->AddObserver(this, "application-foreground", false);
     284             :     obsService->AddObserver(this, "application-background", false);
     285             : #endif
     286             :   }
     287             : 
     288             : #ifdef PLUGIN_LOGGING
     289             :   MOZ_LOG(nsPluginLogging::gNPNLog, PLUGIN_LOG_ALWAYS,("NPN Logging Active!\n"));
     290             :   MOZ_LOG(nsPluginLogging::gPluginLog, PLUGIN_LOG_ALWAYS,("General Plugin Logging Active! (nsPluginHost::ctor)\n"));
     291             :   MOZ_LOG(nsPluginLogging::gNPPLog, PLUGIN_LOG_ALWAYS,("NPP Logging Active!\n"));
     292             : 
     293             :   PLUGIN_LOG(PLUGIN_LOG_ALWAYS,("nsPluginHost::ctor\n"));
     294             :   PR_LogFlush();
     295             : #endif
     296             : 
     297             :   // Load plugins on creation, as there's a good chance we'll need to send them
     298             :   // to content processes directly after creation.
     299           3 :   if (XRE_IsParentProcess())
     300             :   {
     301             :     // Always increment the chrome epoch when we bring up the nsPluginHost in
     302             :     // the parent process. If the only plugins we have are cached in
     303             :     // pluginreg.dat, we won't see any plugin changes in LoadPlugins and the
     304             :     // epoch will stay the same between the parent and child process, meaning
     305             :     // plugins will never update in the child process.
     306           1 :     IncrementChromeEpoch();
     307           1 :     LoadPlugins();
     308             :   }
     309           3 : }
     310             : 
     311           0 : nsPluginHost::~nsPluginHost()
     312             : {
     313           0 :   PLUGIN_LOG(PLUGIN_LOG_ALWAYS,("nsPluginHost::dtor\n"));
     314             : 
     315           0 :   UnloadPlugins();
     316           0 :   sInst = nullptr;
     317           0 : }
     318             : 
     319          79 : NS_IMPL_ISUPPORTS(nsPluginHost,
     320             :                   nsIPluginHost,
     321             :                   nsIObserver,
     322             :                   nsITimerCallback,
     323             :                   nsISupportsWeakReference)
     324             : 
     325             : already_AddRefed<nsPluginHost>
     326           6 : nsPluginHost::GetInst()
     327             : {
     328           6 :   if (!sInst) {
     329           3 :     sInst = new nsPluginHost();
     330           3 :     if (!sInst)
     331           0 :       return nullptr;
     332           3 :     NS_ADDREF(sInst);
     333             :   }
     334             : 
     335          12 :   RefPtr<nsPluginHost> inst = sInst;
     336           6 :   return inst.forget();
     337             : }
     338             : 
     339           0 : bool nsPluginHost::IsRunningPlugin(nsPluginTag * aPluginTag)
     340             : {
     341           0 :   if (!aPluginTag || !aPluginTag->mPlugin) {
     342           0 :     return false;
     343             :   }
     344             : 
     345           0 :   if (aPluginTag->mContentProcessRunningCount) {
     346           0 :     return true;
     347             :   }
     348             : 
     349           0 :   for (uint32_t i = 0; i < mInstances.Length(); i++) {
     350           0 :     nsNPAPIPluginInstance *instance = mInstances[i].get();
     351           0 :     if (instance &&
     352           0 :         instance->GetPlugin() == aPluginTag->mPlugin &&
     353           0 :         instance->IsRunning()) {
     354           0 :       return true;
     355             :     }
     356             :   }
     357             : 
     358           0 :   return false;
     359             : }
     360             : 
     361           0 : nsresult nsPluginHost::ReloadPlugins()
     362             : {
     363           0 :   PLUGIN_LOG(PLUGIN_LOG_NORMAL,
     364             :   ("nsPluginHost::ReloadPlugins Begin\n"));
     365             : 
     366             :   // If we're calling this from a content process, forward the reload request to
     367             :   // the parent process. If plugins actually changed, it will notify us
     368             :   // asynchronously later.
     369           0 :   if (XRE_IsContentProcess())
     370             :   {
     371           0 :     Unused << mozilla::dom::ContentChild::GetSingleton()->SendMaybeReloadPlugins();
     372             :     // In content processes, always signal that plugins have not changed. We
     373             :     // will never know if they changed here unless we make slow synchronous
     374             :     // calls. This information will hopefully only be wrong once, as if there
     375             :     // has been a plugin update, we expect to have gotten notification from the
     376             :     // parent process and everything should be updated by the next time this is
     377             :     // called. See Bug 1337058 for more info.
     378           0 :     return NS_ERROR_PLUGINS_PLUGINSNOTCHANGED;
     379             :   }
     380             :   // this will create the initial plugin list out of cache
     381             :   // if it was not created yet
     382           0 :   if (!mPluginsLoaded)
     383           0 :     return LoadPlugins();
     384             : 
     385             :   // we are re-scanning plugins. New plugins may have been added, also some
     386             :   // plugins may have been removed, so we should probably shut everything down
     387             :   // but don't touch running (active and not stopped) plugins
     388             : 
     389             :   // check if plugins changed, no need to do anything else
     390             :   // if no changes to plugins have been made
     391             :   // false instructs not to touch the plugin list, just to
     392             :   // look for possible changes
     393           0 :   bool pluginschanged = true;
     394           0 :   FindPlugins(false, &pluginschanged);
     395             : 
     396             :   // if no changed detected, return an appropriate error code
     397           0 :   if (!pluginschanged)
     398           0 :     return NS_ERROR_PLUGINS_PLUGINSNOTCHANGED;
     399             : 
     400           0 :   return ActuallyReloadPlugins();
     401             : }
     402             : 
     403             : nsresult
     404           2 : nsPluginHost::ActuallyReloadPlugins()
     405             : {
     406           2 :   nsresult rv = NS_OK;
     407             : 
     408             :   // shutdown plugins and kill the list if there are no running plugins
     409           4 :   RefPtr<nsPluginTag> prev;
     410           4 :   RefPtr<nsPluginTag> next;
     411             : 
     412           2 :   for (RefPtr<nsPluginTag> p = mPlugins; p != nullptr;) {
     413           0 :     next = p->mNext;
     414             : 
     415             :     // only remove our plugin from the list if it's not running.
     416           0 :     if (!IsRunningPlugin(p)) {
     417           0 :       if (p == mPlugins)
     418           0 :         mPlugins = next;
     419             :       else
     420           0 :         prev->mNext = next;
     421             : 
     422           0 :       p->mNext = nullptr;
     423             : 
     424             :       // attempt to unload plugins whenever they are removed from the list
     425           0 :       p->TryUnloadPlugin(false);
     426             : 
     427           0 :       p = next;
     428           0 :       continue;
     429             :     }
     430             : 
     431           0 :     prev = p;
     432           0 :     p = next;
     433             :   }
     434             : 
     435             :   // set flags
     436           2 :   mPluginsLoaded = false;
     437             : 
     438             :   // load them again
     439           2 :   rv = LoadPlugins();
     440             : 
     441           2 :   if (XRE_IsParentProcess())
     442             :   {
     443             :     // If the plugin list changed, update content. If the plugin list changed
     444             :     // for the content process, it will also reload plugins.
     445           0 :     SendPluginsToContent();
     446             :   }
     447             : 
     448           2 :   PLUGIN_LOG(PLUGIN_LOG_NORMAL,
     449             :   ("nsPluginHost::ReloadPlugins End\n"));
     450             : 
     451           4 :   return rv;
     452             : }
     453             : 
     454             : #define NS_RETURN_UASTRING_SIZE 128
     455             : 
     456           0 : nsresult nsPluginHost::UserAgent(const char **retstring)
     457             : {
     458             :   static char resultString[NS_RETURN_UASTRING_SIZE];
     459             :   nsresult res;
     460             : 
     461           0 :   nsCOMPtr<nsIHttpProtocolHandler> http = do_GetService(NS_NETWORK_PROTOCOL_CONTRACTID_PREFIX "http", &res);
     462           0 :   if (NS_FAILED(res))
     463           0 :     return res;
     464             : 
     465           0 :   nsAutoCString uaString;
     466           0 :   res = http->GetUserAgent(uaString);
     467             : 
     468           0 :   if (NS_SUCCEEDED(res)) {
     469           0 :     if (NS_RETURN_UASTRING_SIZE > uaString.Length()) {
     470           0 :       PL_strcpy(resultString, uaString.get());
     471             :     } else {
     472             :       // Copy as much of UA string as we can (terminate at right-most space).
     473           0 :       PL_strncpy(resultString, uaString.get(), NS_RETURN_UASTRING_SIZE);
     474           0 :       for (int i = NS_RETURN_UASTRING_SIZE - 1; i >= 0; i--) {
     475           0 :         if (i == 0) {
     476           0 :           resultString[NS_RETURN_UASTRING_SIZE - 1] = '\0';
     477             :         }
     478           0 :         else if (resultString[i] == ' ') {
     479           0 :           resultString[i] = '\0';
     480           0 :           break;
     481             :         }
     482             :       }
     483             :     }
     484           0 :     *retstring = resultString;
     485             :   }
     486             :   else {
     487           0 :     *retstring = nullptr;
     488             :   }
     489             : 
     490           0 :   PLUGIN_LOG(PLUGIN_LOG_NORMAL, ("nsPluginHost::UserAgent return=%s\n", *retstring));
     491             : 
     492           0 :   return res;
     493             : }
     494             : 
     495           0 : nsresult nsPluginHost::GetURL(nsISupports* pluginInst,
     496             :                               const char* url,
     497             :                               const char* target,
     498             :                               nsNPAPIPluginStreamListener* streamListener,
     499             :                               const char* altHost,
     500             :                               const char* referrer,
     501             :                               bool forceJSEnabled)
     502             : {
     503           0 :   return GetURLWithHeaders(static_cast<nsNPAPIPluginInstance*>(pluginInst),
     504             :                            url, target, streamListener, altHost, referrer,
     505           0 :                            forceJSEnabled, 0, nullptr);
     506             : }
     507             : 
     508           0 : nsresult nsPluginHost::GetURLWithHeaders(nsNPAPIPluginInstance* pluginInst,
     509             :                                          const char* url,
     510             :                                          const char* target,
     511             :                                          nsNPAPIPluginStreamListener* streamListener,
     512             :                                          const char* altHost,
     513             :                                          const char* referrer,
     514             :                                          bool forceJSEnabled,
     515             :                                          uint32_t getHeadersLength,
     516             :                                          const char* getHeaders)
     517             : {
     518             :   // we can only send a stream back to the plugin (as specified by a
     519             :   // null target) if we also have a nsNPAPIPluginStreamListener to talk to
     520           0 :   if (!target && !streamListener) {
     521           0 :     return NS_ERROR_ILLEGAL_VALUE;
     522             :   }
     523             : 
     524           0 :   nsresult rv = NS_OK;
     525             : 
     526           0 :   if (target) {
     527           0 :     RefPtr<nsPluginInstanceOwner> owner = pluginInst->GetOwner();
     528           0 :     if (owner) {
     529           0 :       rv = owner->GetURL(url, target, nullptr, nullptr, 0, true);
     530             :     }
     531             :   }
     532             : 
     533           0 :   if (streamListener) {
     534           0 :     rv = NewPluginURLStream(NS_ConvertUTF8toUTF16(url), pluginInst,
     535             :                             streamListener, nullptr,
     536           0 :                             getHeaders, getHeadersLength);
     537             :   }
     538           0 :   return rv;
     539             : }
     540             : 
     541           0 : nsresult nsPluginHost::PostURL(nsISupports* pluginInst,
     542             :                                const char* url,
     543             :                                uint32_t postDataLen,
     544             :                                const char* postData,
     545             :                                const char* target,
     546             :                                nsNPAPIPluginStreamListener* streamListener,
     547             :                                const char* altHost,
     548             :                                const char* referrer,
     549             :                                bool forceJSEnabled,
     550             :                                uint32_t postHeadersLength,
     551             :                                const char* postHeaders)
     552             : {
     553             :   nsresult rv;
     554             : 
     555             :   // we can only send a stream back to the plugin (as specified
     556             :   // by a null target) if we also have a nsNPAPIPluginStreamListener
     557             :   // to talk to also
     558           0 :   if (!target && !streamListener)
     559           0 :     return NS_ERROR_ILLEGAL_VALUE;
     560             : 
     561           0 :   nsNPAPIPluginInstance* instance = static_cast<nsNPAPIPluginInstance*>(pluginInst);
     562             : 
     563           0 :   nsCOMPtr<nsIInputStream> postStream;
     564             :   char *dataToPost;
     565             :   uint32_t newDataToPostLen;
     566           0 :   ParsePostBufferToFixHeaders(postData, postDataLen, &dataToPost, &newDataToPostLen);
     567           0 :   if (!dataToPost)
     568           0 :     return NS_ERROR_UNEXPECTED;
     569             : 
     570           0 :   nsCOMPtr<nsIStringInputStream> sis = do_CreateInstance("@mozilla.org/io/string-input-stream;1", &rv);
     571           0 :   if (!sis) {
     572           0 :     free(dataToPost);
     573           0 :     return rv;
     574             :   }
     575             : 
     576             :   // data allocated by ParsePostBufferToFixHeaders() is managed and
     577             :   // freed by the string stream.
     578           0 :   postDataLen = newDataToPostLen;
     579           0 :   sis->AdoptData(dataToPost, postDataLen);
     580           0 :   postStream = sis;
     581             : 
     582           0 :   if (target) {
     583           0 :     RefPtr<nsPluginInstanceOwner> owner = instance->GetOwner();
     584           0 :     if (owner) {
     585           0 :       rv = owner->GetURL(url, target, postStream,
     586             :                          (void*)postHeaders, postHeadersLength, true);
     587             :     }
     588             :   }
     589             : 
     590             :   // if we don't have a target, just create a stream.
     591           0 :   if (streamListener) {
     592           0 :     rv = NewPluginURLStream(NS_ConvertUTF8toUTF16(url), instance,
     593             :                             streamListener,
     594             :                             postStream, postHeaders, postHeadersLength);
     595             :   }
     596           0 :   return rv;
     597             : }
     598             : 
     599           0 : nsresult nsPluginHost::UnloadPlugins()
     600             : {
     601           0 :   PLUGIN_LOG(PLUGIN_LOG_NORMAL, ("nsPluginHost::UnloadPlugins Called\n"));
     602             : 
     603           0 :   if (!mPluginsLoaded)
     604           0 :     return NS_OK;
     605             : 
     606             :   // we should call nsIPluginInstance::Stop and nsIPluginInstance::SetWindow
     607             :   // for those plugins who want it
     608           0 :   DestroyRunningInstances(nullptr);
     609             : 
     610             :   nsPluginTag *pluginTag;
     611           0 :   for (pluginTag = mPlugins; pluginTag; pluginTag = pluginTag->mNext) {
     612           0 :     pluginTag->TryUnloadPlugin(true);
     613             :   }
     614             : 
     615           0 :   NS_ITERATIVE_UNREF_LIST(RefPtr<nsPluginTag>, mPlugins, mNext);
     616           0 :   NS_ITERATIVE_UNREF_LIST(RefPtr<nsPluginTag>, mCachedPlugins, mNext);
     617           0 :   NS_ITERATIVE_UNREF_LIST(RefPtr<nsInvalidPluginTag>, mInvalidPlugins, mNext);
     618             : 
     619             :   // Lets remove any of the temporary files that we created.
     620           0 :   if (sPluginTempDir) {
     621           0 :     sPluginTempDir->Remove(true);
     622           0 :     NS_RELEASE(sPluginTempDir);
     623             :   }
     624             : 
     625             : #ifdef XP_WIN
     626             :   if (mPrivateDirServiceProvider) {
     627             :     nsCOMPtr<nsIDirectoryService> dirService =
     628             :       do_GetService(kDirectoryServiceContractID);
     629             :     if (dirService)
     630             :       dirService->UnregisterProvider(mPrivateDirServiceProvider);
     631             :     mPrivateDirServiceProvider = nullptr;
     632             :   }
     633             : #endif /* XP_WIN */
     634             : 
     635           0 :   mPluginsLoaded = false;
     636             : 
     637           0 :   return NS_OK;
     638             : }
     639             : 
     640           0 : void nsPluginHost::OnPluginInstanceDestroyed(nsPluginTag* aPluginTag)
     641             : {
     642           0 :   bool hasInstance = false;
     643           0 :   for (uint32_t i = 0; i < mInstances.Length(); i++) {
     644           0 :     if (TagForPlugin(mInstances[i]->GetPlugin()) == aPluginTag) {
     645           0 :       hasInstance = true;
     646           0 :       break;
     647             :     }
     648             :   }
     649             : 
     650             :   // We have some options for unloading plugins if they have no instances.
     651             :   //
     652             :   // Unloading plugins immediately can be bad - some plugins retain state
     653             :   // between instances even when there are none. This is largely limited to
     654             :   // going from one page to another, so state is retained without an instance
     655             :   // for only a very short period of time. In order to allow this to work
     656             :   // we don't unload plugins immediately by default. This is supported
     657             :   // via a hidden user pref though.
     658             :   //
     659             :   // Another reason not to unload immediately is that loading is expensive,
     660             :   // and it is better to leave popular plugins loaded.
     661             :   //
     662             :   // Our default behavior is to try to unload a plugin after a pref-controlled
     663             :   // delay once its last instance is destroyed. This seems like a reasonable
     664             :   // compromise that allows us to reclaim memory while allowing short state
     665             :   // retention and avoid perf hits for loading popular plugins.
     666           0 :   if (!hasInstance) {
     667           0 :     if (UnloadPluginsASAP()) {
     668           0 :       aPluginTag->TryUnloadPlugin(false);
     669             :     } else {
     670           0 :       if (aPluginTag->mUnloadTimer) {
     671           0 :         aPluginTag->mUnloadTimer->Cancel();
     672             :       } else {
     673           0 :         aPluginTag->mUnloadTimer = do_CreateInstance(NS_TIMER_CONTRACTID);
     674             :       }
     675           0 :       uint32_t unloadTimeout = Preferences::GetUint(kPrefUnloadPluginTimeoutSecs,
     676           0 :                                                     kDefaultPluginUnloadingTimeout);
     677           0 :       aPluginTag->mUnloadTimer->InitWithCallback(this,
     678             :                                                  1000 * unloadTimeout,
     679           0 :                                                  nsITimer::TYPE_ONE_SHOT);
     680             :     }
     681             :   }
     682           0 : }
     683             : 
     684             : nsresult
     685           0 : nsPluginHost::GetPluginTempDir(nsIFile **aDir)
     686             : {
     687           0 :   if (!sPluginTempDir) {
     688           0 :     nsCOMPtr<nsIFile> tmpDir;
     689           0 :     nsresult rv = NS_GetSpecialDirectory(NS_OS_TEMP_DIR,
     690           0 :                                          getter_AddRefs(tmpDir));
     691           0 :     NS_ENSURE_SUCCESS(rv, rv);
     692             : 
     693           0 :     rv = tmpDir->AppendNative(kPluginTmpDirName);
     694             : 
     695             :     // make it unique, and mode == 0700, not world-readable
     696           0 :     rv = tmpDir->CreateUnique(nsIFile::DIRECTORY_TYPE, 0700);
     697           0 :     NS_ENSURE_SUCCESS(rv, rv);
     698             : 
     699           0 :     tmpDir.swap(sPluginTempDir);
     700             :   }
     701             : 
     702           0 :   return sPluginTempDir->Clone(aDir);
     703             : }
     704             : 
     705             : nsresult
     706           0 : nsPluginHost::InstantiatePluginInstance(const nsACString& aMimeType, nsIURI* aURL,
     707             :                                         nsObjectLoadingContent *aContent,
     708             :                                         nsPluginInstanceOwner** aOwner)
     709             : {
     710           0 :   NS_ENSURE_ARG_POINTER(aOwner);
     711             : 
     712             : #ifdef PLUGIN_LOGGING
     713             :   nsAutoCString urlSpec;
     714             :   if (aURL)
     715             :     aURL->GetAsciiSpec(urlSpec);
     716             : 
     717             :   MOZ_LOG(nsPluginLogging::gPluginLog, PLUGIN_LOG_NORMAL,
     718             :         ("nsPluginHost::InstantiatePlugin Begin mime=%s, url=%s\n",
     719             :          PromiseFlatCString(aMimeType).get(), urlSpec.get()));
     720             : 
     721             :   PR_LogFlush();
     722             : #endif
     723             : 
     724           0 :   if (aMimeType.IsEmpty()) {
     725           0 :     NS_NOTREACHED("Attempting to spawn a plugin with no mime type");
     726           0 :     return NS_ERROR_FAILURE;
     727             :   }
     728             : 
     729           0 :   RefPtr<nsPluginInstanceOwner> instanceOwner = new nsPluginInstanceOwner();
     730           0 :   if (!instanceOwner) {
     731           0 :     return NS_ERROR_OUT_OF_MEMORY;
     732             :   }
     733             : 
     734           0 :   nsCOMPtr<nsIContent> ourContent = do_QueryInterface(static_cast<nsIImageLoadingContent*>(aContent));
     735           0 :   nsresult rv = instanceOwner->Init(ourContent);
     736           0 :   if (NS_FAILED(rv)) {
     737           0 :     return rv;
     738             :   }
     739             : 
     740             :   nsPluginTagType tagType;
     741           0 :   rv = instanceOwner->GetTagType(&tagType);
     742           0 :   if (NS_FAILED(rv)) {
     743           0 :     instanceOwner->Destroy();
     744           0 :     return rv;
     745             :   }
     746             : 
     747           0 :   if (tagType != nsPluginTagType_Embed &&
     748           0 :       tagType != nsPluginTagType_Applet &&
     749           0 :       tagType != nsPluginTagType_Object) {
     750           0 :     instanceOwner->Destroy();
     751           0 :     return NS_ERROR_FAILURE;
     752             :   }
     753             : 
     754           0 :   rv = SetUpPluginInstance(aMimeType, aURL, instanceOwner);
     755           0 :   if (NS_FAILED(rv)) {
     756           0 :     instanceOwner->Destroy();
     757           0 :     return NS_ERROR_FAILURE;
     758             :   }
     759             : 
     760           0 :   RefPtr<nsNPAPIPluginInstance> instance;
     761           0 :   rv = instanceOwner->GetInstance(getter_AddRefs(instance));
     762           0 :   if (NS_FAILED(rv)) {
     763           0 :     instanceOwner->Destroy();
     764           0 :     return rv;
     765             :   }
     766             : 
     767           0 :   if (instance) {
     768           0 :     CreateWidget(instanceOwner);
     769             :   }
     770             : 
     771             :   // At this point we consider instantiation to be successful. Do not return an error.
     772           0 :   instanceOwner.forget(aOwner);
     773             : 
     774             : #ifdef PLUGIN_LOGGING
     775             :   nsAutoCString urlSpec2;
     776             :   if (aURL != nullptr) aURL->GetAsciiSpec(urlSpec2);
     777             : 
     778             :   MOZ_LOG(nsPluginLogging::gPluginLog, PLUGIN_LOG_NORMAL,
     779             :         ("nsPluginHost::InstantiatePlugin Finished mime=%s, rv=%" PRIu32 ", url=%s\n",
     780             :          PromiseFlatCString(aMimeType).get(), static_cast<uint32_t>(rv), urlSpec2.get()));
     781             : 
     782             :   PR_LogFlush();
     783             : #endif
     784             : 
     785           0 :   return NS_OK;
     786             : }
     787             : 
     788             : nsPluginTag*
     789           0 : nsPluginHost::FindTagForLibrary(PRLibrary* aLibrary)
     790             : {
     791             :   nsPluginTag* pluginTag;
     792           0 :   for (pluginTag = mPlugins; pluginTag; pluginTag = pluginTag->mNext) {
     793           0 :     if (pluginTag->mLibrary == aLibrary) {
     794           0 :       return pluginTag;
     795             :     }
     796             :   }
     797           0 :   return nullptr;
     798             : }
     799             : 
     800             : nsPluginTag*
     801           0 : nsPluginHost::TagForPlugin(nsNPAPIPlugin* aPlugin)
     802             : {
     803             :   nsPluginTag* pluginTag;
     804           0 :   for (pluginTag = mPlugins; pluginTag; pluginTag = pluginTag->mNext) {
     805           0 :     if (pluginTag->mPlugin == aPlugin) {
     806           0 :       return pluginTag;
     807             :     }
     808             :   }
     809             :   // a plugin should never exist without a corresponding tag
     810           0 :   NS_ERROR("TagForPlugin has failed");
     811           0 :   return nullptr;
     812             : }
     813             : 
     814           0 : nsresult nsPluginHost::SetUpPluginInstance(const nsACString &aMimeType,
     815             :                                            nsIURI *aURL,
     816             :                                            nsPluginInstanceOwner *aOwner)
     817             : {
     818           0 :   NS_ENSURE_ARG_POINTER(aOwner);
     819             : 
     820           0 :   nsresult rv = TrySetUpPluginInstance(aMimeType, aURL, aOwner);
     821           0 :   if (NS_SUCCEEDED(rv)) {
     822           0 :     return rv;
     823             :   }
     824             : 
     825             :   // If we failed to load a plugin instance we'll try again after
     826             :   // reloading our plugin list. Only do that once per document to
     827             :   // avoid redundant high resource usage on pages with multiple
     828             :   // unkown instance types. We'll do that by caching the document.
     829           0 :   nsCOMPtr<nsIDocument> document;
     830           0 :   aOwner->GetDocument(getter_AddRefs(document));
     831             : 
     832           0 :   nsCOMPtr<nsIDocument> currentdocument = do_QueryReferent(mCurrentDocument);
     833           0 :   if (document == currentdocument) {
     834           0 :     return rv;
     835             :   }
     836             : 
     837           0 :   mCurrentDocument = do_GetWeakReference(document);
     838             : 
     839             :   // Don't try to set up an instance again if nothing changed.
     840           0 :   if (ReloadPlugins() == NS_ERROR_PLUGINS_PLUGINSNOTCHANGED) {
     841           0 :     return rv;
     842             :   }
     843             : 
     844           0 :   return TrySetUpPluginInstance(aMimeType, aURL, aOwner);
     845             : }
     846             : 
     847             : nsresult
     848           0 : nsPluginHost::TrySetUpPluginInstance(const nsACString &aMimeType,
     849             :                                      nsIURI *aURL,
     850             :                                      nsPluginInstanceOwner *aOwner)
     851             : {
     852             : #ifdef PLUGIN_LOGGING
     853             :   MOZ_LOG(nsPluginLogging::gPluginLog, PLUGIN_LOG_NORMAL,
     854             :           ("nsPluginHost::TrySetupPluginInstance Begin mime=%s, owner=%p, url=%s\n",
     855             :            PromiseFlatCString(aMimeType).get(), aOwner,
     856             :            aURL ? aURL->GetSpecOrDefault().get() : ""));
     857             : 
     858             :   PR_LogFlush();
     859             : #endif
     860             : 
     861             : #ifdef XP_WIN
     862             :   bool changed;
     863             :   if ((mRegKeyHKLM && NS_SUCCEEDED(mRegKeyHKLM->HasChanged(&changed)) && changed) ||
     864             :       (mRegKeyHKCU && NS_SUCCEEDED(mRegKeyHKCU->HasChanged(&changed)) && changed)) {
     865             :     ReloadPlugins();
     866             :   }
     867             : #endif
     868             : 
     869           0 :   RefPtr<nsNPAPIPlugin> plugin;
     870           0 :   GetPlugin(aMimeType, getter_AddRefs(plugin));
     871           0 :   if (!plugin) {
     872           0 :     return NS_ERROR_FAILURE;
     873             :   }
     874             : 
     875           0 :   nsPluginTag* pluginTag = FindNativePluginForType(aMimeType, true);
     876             : 
     877           0 :   NS_ASSERTION(pluginTag, "Must have plugin tag here!");
     878             : 
     879           0 :   plugin->GetLibrary()->SetHasLocalInstance();
     880             : 
     881             : #if defined(MOZ_WIDGET_ANDROID) && defined(MOZ_CRASHREPORTER)
     882             :   if (pluginTag->mIsFlashPlugin) {
     883             :     CrashReporter::AnnotateCrashReport(NS_LITERAL_CSTRING("FlashVersion"), pluginTag->Version());
     884             :   }
     885             : #endif
     886             : 
     887           0 :   RefPtr<nsNPAPIPluginInstance> instance = new nsNPAPIPluginInstance();
     888             : 
     889             :   // This will create the owning reference. The connection must be made between the
     890             :   // instance and the instance owner before initialization. Plugins can call into
     891             :   // the browser during initialization.
     892           0 :   aOwner->SetInstance(instance.get());
     893             : 
     894             :   // Add the instance to the instances list before we call NPP_New so that
     895             :   // it is "in play" before NPP_New happens. Take it out if NPP_New fails.
     896           0 :   mInstances.AppendElement(instance.get());
     897             : 
     898             :   // this should not addref the instance or owner
     899             :   // except in some cases not Java, see bug 140931
     900             :   // our COM pointer will free the peer
     901           0 :   nsresult rv = instance->Initialize(plugin.get(), aOwner, aMimeType);
     902           0 :   if (NS_FAILED(rv)) {
     903           0 :     mInstances.RemoveElement(instance.get());
     904           0 :     aOwner->SetInstance(nullptr);
     905           0 :     return rv;
     906             :   }
     907             : 
     908             :   // Cancel the plugin unload timer since we are creating
     909             :   // an instance for it.
     910           0 :   if (pluginTag->mUnloadTimer) {
     911           0 :     pluginTag->mUnloadTimer->Cancel();
     912             :   }
     913             : 
     914             : #ifdef PLUGIN_LOGGING
     915             :   MOZ_LOG(nsPluginLogging::gPluginLog, PLUGIN_LOG_BASIC,
     916             :         ("nsPluginHost::TrySetupPluginInstance Finished mime=%s, rv=%" PRIu32 ", owner=%p, url=%s\n",
     917             :          PromiseFlatCString(aMimeType).get(), static_cast<uint32_t>(rv), aOwner,
     918             :          aURL ? aURL->GetSpecOrDefault().get() : ""));
     919             : 
     920             :   PR_LogFlush();
     921             : #endif
     922             : 
     923           0 :   return rv;
     924             : }
     925             : 
     926             : bool
     927           0 : nsPluginHost::HavePluginForType(const nsACString & aMimeType,
     928             :                                 PluginFilter aFilter)
     929             : {
     930           0 :   bool checkEnabled = aFilter & eExcludeDisabled;
     931           0 :   bool allowFake = !(aFilter & eExcludeFake);
     932           0 :   return FindPluginForType(aMimeType, allowFake, checkEnabled);
     933             : }
     934             : 
     935             : nsIInternalPluginTag*
     936           0 : nsPluginHost::FindPluginForType(const nsACString& aMimeType,
     937             :                                 bool aIncludeFake, bool aCheckEnabled)
     938             : {
     939           0 :   if (aIncludeFake) {
     940           0 :     nsFakePluginTag* fakeTag = FindFakePluginForType(aMimeType, aCheckEnabled);
     941           0 :     if (fakeTag) {
     942           0 :       return fakeTag;
     943             :     }
     944             :   }
     945             : 
     946           0 :   return FindNativePluginForType(aMimeType, aCheckEnabled);
     947             : }
     948             : 
     949             : NS_IMETHODIMP
     950           0 : nsPluginHost::GetPluginTagForType(const nsACString& aMimeType,
     951             :                                   uint32_t aExcludeFlags,
     952             :                                   nsIPluginTag** aResult)
     953             : {
     954           0 :   bool includeFake = !(aExcludeFlags & eExcludeFake);
     955           0 :   bool includeDisabled = !(aExcludeFlags & eExcludeDisabled);
     956             : 
     957             :   // First look for an enabled plugin.
     958             :   RefPtr<nsIInternalPluginTag> tag = FindPluginForType(aMimeType, includeFake,
     959           0 :                                                          true);
     960           0 :   if (!tag && includeDisabled) {
     961           0 :     tag = FindPluginForType(aMimeType, includeFake, false);
     962             :   }
     963             : 
     964           0 :   if (tag) {
     965           0 :     tag.forget(aResult);
     966           0 :     return NS_OK;
     967             :   }
     968             : 
     969           0 :   return NS_ERROR_NOT_AVAILABLE;
     970             : }
     971             : 
     972             : NS_IMETHODIMP
     973           0 : nsPluginHost::GetStateForType(const nsACString &aMimeType,
     974             :                               uint32_t aExcludeFlags,
     975             :                               uint32_t* aResult)
     976             : {
     977           0 :   nsCOMPtr<nsIPluginTag> tag;
     978           0 :   nsresult rv = GetPluginTagForType(aMimeType, aExcludeFlags,
     979           0 :                                     getter_AddRefs(tag));
     980           0 :   NS_ENSURE_SUCCESS(rv, rv);
     981             : 
     982           0 :   return tag->GetEnabledState(aResult);
     983             : }
     984             : 
     985             : NS_IMETHODIMP
     986           0 : nsPluginHost::GetBlocklistStateForType(const nsACString &aMimeType,
     987             :                                        uint32_t aExcludeFlags,
     988             :                                        uint32_t *aState)
     989             : {
     990           0 :   nsCOMPtr<nsIPluginTag> tag;
     991           0 :   nsresult rv = GetPluginTagForType(aMimeType,
     992             :                                     aExcludeFlags,
     993           0 :                                     getter_AddRefs(tag));
     994           0 :   NS_ENSURE_SUCCESS(rv, rv);
     995           0 :   return tag->GetBlocklistState(aState);
     996             : }
     997             : 
     998             : NS_IMETHODIMP
     999           0 : nsPluginHost::GetPermissionStringForType(const nsACString &aMimeType,
    1000             :                                          uint32_t aExcludeFlags,
    1001             :                                          nsACString &aPermissionString)
    1002             : {
    1003           0 :   nsCOMPtr<nsIPluginTag> tag;
    1004           0 :   nsresult rv = GetPluginTagForType(aMimeType, aExcludeFlags,
    1005           0 :                                     getter_AddRefs(tag));
    1006           0 :   NS_ENSURE_SUCCESS(rv, rv);
    1007           0 :   return GetPermissionStringForTag(tag, aExcludeFlags, aPermissionString);
    1008             : }
    1009             : 
    1010             : NS_IMETHODIMP
    1011           0 : nsPluginHost::GetPermissionStringForTag(nsIPluginTag* aTag,
    1012             :                                         uint32_t aExcludeFlags,
    1013             :                                         nsACString &aPermissionString)
    1014             : {
    1015           0 :   NS_ENSURE_TRUE(aTag, NS_ERROR_FAILURE);
    1016             : 
    1017           0 :   aPermissionString.Truncate();
    1018             :   uint32_t blocklistState;
    1019           0 :   nsresult rv = aTag->GetBlocklistState(&blocklistState);
    1020           0 :   NS_ENSURE_SUCCESS(rv, rv);
    1021             : 
    1022           0 :   if (blocklistState == nsIBlocklistService::STATE_VULNERABLE_UPDATE_AVAILABLE ||
    1023           0 :       blocklistState == nsIBlocklistService::STATE_VULNERABLE_NO_UPDATE) {
    1024           0 :     aPermissionString.AssignLiteral("plugin-vulnerable:");
    1025             :   }
    1026             :   else {
    1027           0 :     aPermissionString.AssignLiteral("plugin:");
    1028             :   }
    1029             : 
    1030           0 :   nsCString niceName;
    1031           0 :   rv = aTag->GetNiceName(niceName);
    1032           0 :   NS_ENSURE_SUCCESS(rv, rv);
    1033           0 :   NS_ENSURE_TRUE(!niceName.IsEmpty(), NS_ERROR_FAILURE);
    1034             : 
    1035           0 :   aPermissionString.Append(niceName);
    1036             : 
    1037           0 :   return NS_OK;
    1038             : }
    1039             : 
    1040             : bool
    1041           0 : nsPluginHost::HavePluginForExtension(const nsACString & aExtension,
    1042             :                                      /* out */ nsACString & aMimeType,
    1043             :                                      PluginFilter aFilter)
    1044             : {
    1045             :   // As of FF 52, we only support flash and test plugins, so if the extension types
    1046             :   // don't match for that, exit before we start loading plugins.
    1047             :   //
    1048             :   // XXX: Remove tst case when bug 1351885 lands.
    1049           0 :   if (!aExtension.LowerCaseEqualsLiteral("swf") &&
    1050           0 :       !aExtension.LowerCaseEqualsLiteral("tst")) {
    1051           0 :     return false;
    1052             :   }
    1053             : 
    1054           0 :   bool checkEnabled = aFilter & eExcludeDisabled;
    1055           0 :   bool allowFake = !(aFilter & eExcludeFake);
    1056           0 :   return FindNativePluginForExtension(aExtension, aMimeType, checkEnabled) ||
    1057           0 :     (allowFake &&
    1058           0 :      FindFakePluginForExtension(aExtension, aMimeType, checkEnabled));
    1059             : }
    1060             : 
    1061             : void
    1062           2 : nsPluginHost::GetPlugins(nsTArray<nsCOMPtr<nsIInternalPluginTag>>& aPluginArray,
    1063             :                          bool aIncludeDisabled)
    1064             : {
    1065           2 :   aPluginArray.Clear();
    1066             : 
    1067           2 :   LoadPlugins();
    1068             : 
    1069             :   // Append fake plugins, then normal plugins.
    1070             : 
    1071           2 :   uint32_t numFake = mFakePlugins.Length();
    1072           2 :   for (uint32_t i = 0; i < numFake; i++) {
    1073           0 :     aPluginArray.AppendElement(mFakePlugins[i]);
    1074             :   }
    1075             : 
    1076             :   // Regular plugins
    1077           2 :   nsPluginTag* plugin = mPlugins;
    1078           2 :   while (plugin != nullptr) {
    1079           0 :     if (plugin->IsEnabled() || aIncludeDisabled) {
    1080           0 :       aPluginArray.AppendElement(plugin);
    1081             :     }
    1082           0 :     plugin = plugin->mNext;
    1083             :   }
    1084           2 : }
    1085             : 
    1086             : // FIXME-jsplugins Check users for order of fake v non-fake
    1087             : NS_IMETHODIMP
    1088           2 : nsPluginHost::GetPluginTags(uint32_t* aPluginCount, nsIPluginTag*** aResults)
    1089             : {
    1090           2 :   LoadPlugins();
    1091             : 
    1092           2 :   uint32_t count = 0;
    1093           2 :   uint32_t fakeCount = mFakePlugins.Length();
    1094           4 :   RefPtr<nsPluginTag> plugin = mPlugins;
    1095           2 :   while (plugin != nullptr) {
    1096           0 :     count++;
    1097           0 :     plugin = plugin->mNext;
    1098             :   }
    1099             : 
    1100           2 :   *aResults = static_cast<nsIPluginTag**>
    1101           2 :                          (moz_xmalloc((fakeCount + count) * sizeof(**aResults)));
    1102           2 :   if (!*aResults)
    1103           0 :     return NS_ERROR_OUT_OF_MEMORY;
    1104             : 
    1105           2 :   *aPluginCount = count + fakeCount;
    1106             : 
    1107           2 :   plugin = mPlugins;
    1108           2 :   for (uint32_t i = 0; i < count; i++) {
    1109           0 :     (*aResults)[i] = plugin;
    1110           0 :     NS_ADDREF((*aResults)[i]);
    1111           0 :     plugin = plugin->mNext;
    1112             :   }
    1113             : 
    1114           2 :   for (uint32_t i = 0; i < fakeCount; i++) {
    1115           0 :     (*aResults)[i + count] = static_cast<nsIInternalPluginTag*>(mFakePlugins[i]);
    1116           0 :     NS_ADDREF((*aResults)[i + count]);
    1117             :   }
    1118             : 
    1119           2 :   return NS_OK;
    1120             : }
    1121             : 
    1122             : nsPluginTag*
    1123           0 : nsPluginHost::FindPreferredPlugin(const InfallibleTArray<nsPluginTag*>& matches)
    1124             : {
    1125             :   // We prefer the plugin with the highest version number.
    1126             :   /// XXX(johns): This seems to assume the only time multiple plugins will have
    1127             :   ///             the same MIME type is if they're multiple versions of the same
    1128             :   ///             plugin -- but since plugin filenames and pretty names can both
    1129             :   ///             update, it's probably less arbitrary than just going at it
    1130             :   ///             alphabetically.
    1131             : 
    1132           0 :   if (matches.IsEmpty()) {
    1133           0 :     return nullptr;
    1134             :   }
    1135             : 
    1136           0 :   nsPluginTag *preferredPlugin = matches[0];
    1137           0 :   for (unsigned int i = 1; i < matches.Length(); i++) {
    1138           0 :     if (mozilla::Version(matches[i]->Version().get()) > preferredPlugin->Version().get()) {
    1139           0 :       preferredPlugin = matches[i];
    1140             :     }
    1141             :   }
    1142             : 
    1143           0 :   return preferredPlugin;
    1144             : }
    1145             : 
    1146             : nsFakePluginTag*
    1147           0 : nsPluginHost::FindFakePluginForExtension(const nsACString & aExtension,
    1148             :                                          /* out */ nsACString & aMimeType,
    1149             :                                          bool aCheckEnabled)
    1150             : {
    1151           0 :   if (aExtension.IsEmpty()) {
    1152           0 :     return nullptr;
    1153             :   }
    1154             : 
    1155           0 :   int32_t numFakePlugins = mFakePlugins.Length();
    1156           0 :   for (int32_t i = 0; i < numFakePlugins; i++) {
    1157           0 :     nsFakePluginTag *plugin = mFakePlugins[i];
    1158             :     bool active;
    1159           0 :     if ((!aCheckEnabled ||
    1160           0 :          (NS_SUCCEEDED(plugin->GetActive(&active)) && active)) &&
    1161           0 :         plugin->HasExtension(aExtension, aMimeType)) {
    1162           0 :       return plugin;
    1163             :     }
    1164             :   }
    1165             : 
    1166           0 :   return nullptr;
    1167             : }
    1168             : 
    1169             : nsFakePluginTag*
    1170           0 : nsPluginHost::FindFakePluginForType(const nsACString & aMimeType,
    1171             :                                     bool aCheckEnabled)
    1172             : {
    1173           0 :   int32_t numFakePlugins = mFakePlugins.Length();
    1174           0 :   for (int32_t i = 0; i < numFakePlugins; i++) {
    1175           0 :     nsFakePluginTag *plugin = mFakePlugins[i];
    1176             :     bool active;
    1177           0 :     if ((!aCheckEnabled ||
    1178           0 :          (NS_SUCCEEDED(plugin->GetActive(&active)) && active)) &&
    1179           0 :         plugin->HasMimeType(aMimeType)) {
    1180           0 :       return plugin;
    1181             :     }
    1182             :   }
    1183             : 
    1184           0 :   return nullptr;
    1185             : }
    1186             : 
    1187             : nsPluginTag*
    1188           0 : nsPluginHost::FindNativePluginForType(const nsACString & aMimeType,
    1189             :                                       bool aCheckEnabled)
    1190             : {
    1191           0 :   if (aMimeType.IsEmpty()) {
    1192           0 :     return nullptr;
    1193             :   }
    1194             : 
    1195             :   // As of FF 52, we only support flash and test plugins, so if the mime types
    1196             :   // don't match for that, exit before we start loading plugins.
    1197           0 :   if (!nsPluginHost::CanUsePluginForMIMEType(aMimeType)) {
    1198           0 :     return nullptr;
    1199             :   }
    1200             : 
    1201           0 :   LoadPlugins();
    1202             : 
    1203           0 :   InfallibleTArray<nsPluginTag*> matchingPlugins;
    1204             : 
    1205           0 :   nsPluginTag *plugin = mPlugins;
    1206           0 :   while (plugin) {
    1207           0 :     if ((!aCheckEnabled || plugin->IsActive()) &&
    1208           0 :         plugin->HasMimeType(aMimeType)) {
    1209           0 :       matchingPlugins.AppendElement(plugin);
    1210             :     }
    1211           0 :     plugin = plugin->mNext;
    1212             :   }
    1213             : 
    1214           0 :   return FindPreferredPlugin(matchingPlugins);
    1215             : }
    1216             : 
    1217             : nsPluginTag*
    1218           0 : nsPluginHost::FindNativePluginForExtension(const nsACString & aExtension,
    1219             :                                            /* out */ nsACString & aMimeType,
    1220             :                                            bool aCheckEnabled)
    1221             : {
    1222           0 :   if (aExtension.IsEmpty()) {
    1223           0 :     return nullptr;
    1224             :   }
    1225             : 
    1226           0 :   LoadPlugins();
    1227             : 
    1228           0 :   InfallibleTArray<nsPluginTag*> matchingPlugins;
    1229           0 :   nsCString matchingMime; // Don't mutate aMimeType unless returning a match
    1230           0 :   nsPluginTag *plugin = mPlugins;
    1231             : 
    1232           0 :   while (plugin) {
    1233           0 :     if (!aCheckEnabled || plugin->IsActive()) {
    1234           0 :       if (plugin->HasExtension(aExtension, matchingMime)) {
    1235           0 :         matchingPlugins.AppendElement(plugin);
    1236             :       }
    1237             :     }
    1238           0 :     plugin = plugin->mNext;
    1239             :   }
    1240             : 
    1241           0 :   nsPluginTag *preferredPlugin = FindPreferredPlugin(matchingPlugins);
    1242           0 :   if (!preferredPlugin) {
    1243           0 :     return nullptr;
    1244             :   }
    1245             : 
    1246             :   // Re-fetch the matching type because of how FindPreferredPlugin works...
    1247           0 :   preferredPlugin->HasExtension(aExtension, aMimeType);
    1248           0 :   return preferredPlugin;
    1249             : }
    1250             : 
    1251           0 : static nsresult CreateNPAPIPlugin(nsPluginTag *aPluginTag,
    1252             :                                   nsNPAPIPlugin **aOutNPAPIPlugin)
    1253             : {
    1254             :   // If this is an in-process plugin we'll need to load it here if we haven't already.
    1255           0 :   if (!nsNPAPIPlugin::RunPluginOOP(aPluginTag)) {
    1256           0 :     if (aPluginTag->mFullPath.IsEmpty())
    1257           0 :       return NS_ERROR_FAILURE;
    1258           0 :     nsCOMPtr<nsIFile> file = do_CreateInstance("@mozilla.org/file/local;1");
    1259           0 :     file->InitWithPath(NS_ConvertUTF8toUTF16(aPluginTag->mFullPath));
    1260           0 :     nsPluginFile pluginFile(file);
    1261           0 :     PRLibrary* pluginLibrary = nullptr;
    1262             : 
    1263           0 :     if (NS_FAILED(pluginFile.LoadPlugin(&pluginLibrary)) || !pluginLibrary)
    1264           0 :       return NS_ERROR_FAILURE;
    1265             : 
    1266           0 :     aPluginTag->mLibrary = pluginLibrary;
    1267             :   }
    1268             : 
    1269             :   nsresult rv;
    1270           0 :   rv = nsNPAPIPlugin::CreatePlugin(aPluginTag, aOutNPAPIPlugin);
    1271             : 
    1272           0 :   return rv;
    1273             : }
    1274             : 
    1275           0 : nsresult nsPluginHost::EnsurePluginLoaded(nsPluginTag* aPluginTag)
    1276             : {
    1277           0 :   RefPtr<nsNPAPIPlugin> plugin = aPluginTag->mPlugin;
    1278           0 :   if (!plugin) {
    1279           0 :     nsresult rv = CreateNPAPIPlugin(aPluginTag, getter_AddRefs(plugin));
    1280           0 :     if (NS_FAILED(rv)) {
    1281           0 :       return rv;
    1282             :     }
    1283           0 :     aPluginTag->mPlugin = plugin;
    1284             :   }
    1285           0 :   return NS_OK;
    1286             : }
    1287             : 
    1288             : nsresult
    1289           0 : nsPluginHost::GetPluginForContentProcess(uint32_t aPluginId, nsNPAPIPlugin** aPlugin)
    1290             : {
    1291           0 :   AUTO_PROFILER_LABEL("nsPluginHost::GetPluginForContentProcess", OTHER);
    1292           0 :   MOZ_ASSERT(XRE_IsParentProcess());
    1293             : 
    1294             :   // If plugins haven't been scanned yet, do so now
    1295           0 :   LoadPlugins();
    1296             : 
    1297           0 :   nsPluginTag* pluginTag = PluginWithId(aPluginId);
    1298           0 :   if (pluginTag) {
    1299             :     // When setting up a bridge, double check with chrome to see if this plugin
    1300             :     // is blocked hard. Note this does not protect against vulnerable plugins
    1301             :     // that the user has explicitly allowed. :(
    1302           0 :     if (pluginTag->IsBlocklisted()) {
    1303           0 :       return NS_ERROR_PLUGIN_BLOCKLISTED;
    1304             :     }
    1305             : 
    1306           0 :     nsresult rv = EnsurePluginLoaded(pluginTag);
    1307           0 :     if (NS_FAILED(rv)) {
    1308           0 :       return rv;
    1309             :     }
    1310             : 
    1311             :     // We only get here if a content process doesn't have a PluginModuleParent
    1312             :     // for the given plugin already. Therefore, this counter is counting the
    1313             :     // number of outstanding PluginModuleParents for the plugin, excluding the
    1314             :     // one from the chrome process.
    1315           0 :     pluginTag->mContentProcessRunningCount++;
    1316           0 :     NS_ADDREF(*aPlugin = pluginTag->mPlugin);
    1317           0 :     return NS_OK;
    1318             :   }
    1319             : 
    1320           0 :   return NS_ERROR_FAILURE;
    1321             : }
    1322             : 
    1323           0 : class nsPluginUnloadRunnable : public Runnable
    1324             : {
    1325             : public:
    1326           0 :   explicit nsPluginUnloadRunnable(uint32_t aPluginId) :
    1327             :     Runnable("nsPluginUnloadRunnable"),
    1328           0 :     mPluginId(aPluginId)
    1329           0 :   {}
    1330             : 
    1331           0 :   NS_IMETHOD Run() override
    1332             :   {
    1333           0 :     RefPtr<nsPluginHost> host = nsPluginHost::GetInst();
    1334           0 :     if (!host) {
    1335           0 :       return NS_OK;
    1336             :     }
    1337           0 :     nsPluginTag* pluginTag = host->PluginWithId(mPluginId);
    1338           0 :     if (!pluginTag) {
    1339           0 :       return NS_OK;
    1340             :     }
    1341             : 
    1342           0 :     MOZ_ASSERT(pluginTag->mContentProcessRunningCount > 0);
    1343           0 :     pluginTag->mContentProcessRunningCount--;
    1344             : 
    1345           0 :     if (!pluginTag->mContentProcessRunningCount) {
    1346           0 :       if (!host->IsRunningPlugin(pluginTag)) {
    1347           0 :         pluginTag->TryUnloadPlugin(false);
    1348             :       }
    1349             :     }
    1350           0 :     return NS_OK;
    1351             :   }
    1352             : 
    1353             : protected:
    1354             :   uint32_t mPluginId;
    1355             : };
    1356             : 
    1357             : void
    1358           0 : nsPluginHost::NotifyContentModuleDestroyed(uint32_t aPluginId)
    1359             : {
    1360           0 :   MOZ_ASSERT(XRE_IsParentProcess());
    1361             : 
    1362             :   // This is called in response to a message from the plugin. Don't unload the
    1363             :   // plugin until the message handler is off the stack.
    1364             :   RefPtr<nsPluginUnloadRunnable> runnable =
    1365           0 :     new nsPluginUnloadRunnable(aPluginId);
    1366           0 :   NS_DispatchToMainThread(runnable);
    1367           0 : }
    1368             : 
    1369           0 : nsresult nsPluginHost::GetPlugin(const nsACString &aMimeType,
    1370             :                                  nsNPAPIPlugin** aPlugin)
    1371             : {
    1372           0 :   nsresult rv = NS_ERROR_FAILURE;
    1373           0 :   *aPlugin = nullptr;
    1374             : 
    1375             :   // If plugins haven't been scanned yet, do so now
    1376           0 :   LoadPlugins();
    1377             : 
    1378           0 :   nsPluginTag* pluginTag = FindNativePluginForType(aMimeType, true);
    1379           0 :   if (pluginTag) {
    1380           0 :     rv = NS_OK;
    1381           0 :     PLUGIN_LOG(PLUGIN_LOG_BASIC,
    1382             :     ("nsPluginHost::GetPlugin Begin mime=%s, plugin=%s\n",
    1383             :      PromiseFlatCString(aMimeType).get(), pluginTag->FileName().get()));
    1384             : 
    1385             : #ifdef DEBUG
    1386           0 :     if (!pluginTag->FileName().IsEmpty())
    1387           0 :       printf("For %s found plugin %s\n",
    1388           0 :              PromiseFlatCString(aMimeType).get(), pluginTag->FileName().get());
    1389             : #endif
    1390             : 
    1391           0 :     rv = EnsurePluginLoaded(pluginTag);
    1392           0 :     if (NS_FAILED(rv)) {
    1393           0 :       return rv;
    1394             :     }
    1395             : 
    1396           0 :     NS_ADDREF(*aPlugin = pluginTag->mPlugin);
    1397           0 :     return NS_OK;
    1398             :   }
    1399             : 
    1400           0 :   PLUGIN_LOG(PLUGIN_LOG_NORMAL,
    1401             :   ("nsPluginHost::GetPlugin End mime=%s, rv=%" PRIu32 ", plugin=%p name=%s\n",
    1402             :    PromiseFlatCString(aMimeType).get(), static_cast<uint32_t>(rv), *aPlugin,
    1403             :    (pluginTag ? pluginTag->FileName().get() : "(not found)")));
    1404             : 
    1405           0 :   return rv;
    1406             : }
    1407             : 
    1408             : // Normalize 'host' to ACE.
    1409             : nsresult
    1410           0 : nsPluginHost::NormalizeHostname(nsCString& host)
    1411             : {
    1412           0 :   if (IsASCII(host)) {
    1413           0 :     ToLowerCase(host);
    1414           0 :     return NS_OK;
    1415             :   }
    1416             : 
    1417           0 :   if (!mIDNService) {
    1418             :     nsresult rv;
    1419           0 :     mIDNService = do_GetService(NS_IDNSERVICE_CONTRACTID, &rv);
    1420           0 :     NS_ENSURE_SUCCESS(rv, rv);
    1421             :   }
    1422             : 
    1423           0 :   return mIDNService->ConvertUTF8toACE(host, host);
    1424             : }
    1425             : 
    1426             : // Enumerate a 'sites' array returned by GetSitesWithData and determine if
    1427             : // any of them have a base domain in common with 'domain'; if so, append them
    1428             : // to the 'result' array. If 'firstMatchOnly' is true, return after finding the
    1429             : // first match.
    1430             : nsresult
    1431           0 : nsPluginHost::EnumerateSiteData(const nsACString& domain,
    1432             :                                 const InfallibleTArray<nsCString>& sites,
    1433             :                                 InfallibleTArray<nsCString>& result,
    1434             :                                 bool firstMatchOnly)
    1435             : {
    1436           0 :   NS_ASSERTION(!domain.IsVoid(), "null domain string");
    1437             : 
    1438             :   nsresult rv;
    1439           0 :   if (!mTLDService) {
    1440           0 :     mTLDService = do_GetService(NS_EFFECTIVETLDSERVICE_CONTRACTID, &rv);
    1441           0 :     NS_ENSURE_SUCCESS(rv, rv);
    1442             :   }
    1443             : 
    1444             :   // Get the base domain from the domain.
    1445           0 :   nsCString baseDomain;
    1446           0 :   rv = mTLDService->GetBaseDomainFromHost(domain, 0, baseDomain);
    1447           0 :   bool isIP = rv == NS_ERROR_HOST_IS_IP_ADDRESS;
    1448           0 :   if (isIP || rv == NS_ERROR_INSUFFICIENT_DOMAIN_LEVELS) {
    1449             :     // The base domain is the site itself. However, we must be careful to
    1450             :     // normalize.
    1451           0 :     baseDomain = domain;
    1452           0 :     rv = NormalizeHostname(baseDomain);
    1453           0 :     NS_ENSURE_SUCCESS(rv, rv);
    1454           0 :   } else if (NS_FAILED(rv)) {
    1455           0 :     return rv;
    1456             :   }
    1457             : 
    1458             :   // Enumerate the array of sites with data.
    1459           0 :   for (uint32_t i = 0; i < sites.Length(); ++i) {
    1460           0 :     const nsCString& site = sites[i];
    1461             : 
    1462             :     // Check if the site is an IP address.
    1463             :     bool siteIsIP =
    1464           0 :       site.Length() >= 2 && site.First() == '[' && site.Last() == ']';
    1465           0 :     if (siteIsIP != isIP)
    1466           0 :       continue;
    1467             : 
    1468           0 :     nsCString siteBaseDomain;
    1469           0 :     if (siteIsIP) {
    1470             :       // Strip the '[]'.
    1471           0 :       siteBaseDomain = Substring(site, 1, site.Length() - 2);
    1472             :     } else {
    1473             :       // Determine the base domain of the site.
    1474           0 :       rv = mTLDService->GetBaseDomainFromHost(site, 0, siteBaseDomain);
    1475           0 :       if (rv == NS_ERROR_INSUFFICIENT_DOMAIN_LEVELS) {
    1476             :         // The base domain is the site itself. However, we must be careful to
    1477             :         // normalize.
    1478           0 :         siteBaseDomain = site;
    1479           0 :         rv = NormalizeHostname(siteBaseDomain);
    1480           0 :         NS_ENSURE_SUCCESS(rv, rv);
    1481           0 :       } else if (NS_FAILED(rv)) {
    1482           0 :         return rv;
    1483             :       }
    1484             :     }
    1485             : 
    1486             :     // At this point, we can do an exact comparison of the two domains.
    1487           0 :     if (baseDomain != siteBaseDomain) {
    1488           0 :       continue;
    1489             :     }
    1490             : 
    1491             :     // Append the site to the result array.
    1492           0 :     result.AppendElement(site);
    1493             : 
    1494             :     // If we're supposed to return early, do so.
    1495           0 :     if (firstMatchOnly) {
    1496           0 :       break;
    1497             :     }
    1498             :   }
    1499             : 
    1500           0 :   return NS_OK;
    1501             : }
    1502             : 
    1503             : static bool
    1504           0 : MimeTypeIsAllowedForFakePlugin(const nsString& aMimeType)
    1505             : {
    1506             :   static const char* const allowedFakePlugins[] = {
    1507             :     // Flash
    1508             :     "application/x-shockwave-flash",
    1509             :     // PDF
    1510             :     "application/pdf",
    1511             :     "application/vnd.adobe.pdf",
    1512             :     "application/vnd.adobe.pdfxml",
    1513             :     "application/vnd.adobe.x-mars",
    1514             :     "application/vnd.adobe.xdp+xml",
    1515             :     "application/vnd.adobe.xfdf",
    1516             :     "application/vnd.adobe.xfd+xml",
    1517             :     "application/vnd.fdf",
    1518             :   };
    1519             : 
    1520           0 :   for (const auto allowed : allowedFakePlugins) {
    1521           0 :     if (aMimeType.EqualsASCII(allowed)) {
    1522           0 :       return true;
    1523             :     }
    1524             :   }
    1525           0 :   return false;
    1526             : }
    1527             : 
    1528             : NS_IMETHODIMP
    1529           0 : nsPluginHost::RegisterFakePlugin(JS::Handle<JS::Value> aInitDictionary,
    1530             :                                  JSContext* aCx,
    1531             :                                  nsIFakePluginTag **aResult)
    1532             : {
    1533           0 :   FakePluginTagInit initDictionary;
    1534           0 :   if (!initDictionary.Init(aCx, aInitDictionary)) {
    1535           0 :     return NS_ERROR_FAILURE;
    1536             :   }
    1537             : 
    1538           0 :   for (const FakePluginMimeEntry& mimeEntry : initDictionary.mMimeEntries) {
    1539           0 :     if (!MimeTypeIsAllowedForFakePlugin(mimeEntry.mType)) {
    1540           0 :       return NS_ERROR_FAILURE;
    1541             :     }
    1542             :   }
    1543             : 
    1544           0 :   RefPtr<nsFakePluginTag> newTag;
    1545           0 :   nsresult rv = nsFakePluginTag::Create(initDictionary, getter_AddRefs(newTag));
    1546           0 :   NS_ENSURE_SUCCESS(rv, rv);
    1547             : 
    1548           0 :   for (const auto& existingTag : mFakePlugins) {
    1549           0 :     if (newTag->HandlerURIMatches(existingTag->HandlerURI())) {
    1550           0 :       return NS_ERROR_UNEXPECTED;
    1551             :     }
    1552             :   }
    1553             : 
    1554           0 :   mFakePlugins.AppendElement(newTag);
    1555             : 
    1556             :   nsAdoptingCString disableFullPage =
    1557           0 :     Preferences::GetCString(kPrefDisableFullPage);
    1558           0 :   for (uint32_t i = 0; i < newTag->MimeTypes().Length(); i++) {
    1559           0 :     if (!IsTypeInList(newTag->MimeTypes()[i], disableFullPage)) {
    1560           0 :       RegisterWithCategoryManager(newTag->MimeTypes()[i],
    1561           0 :                                   ePluginRegister);
    1562             :     }
    1563             :   }
    1564             : 
    1565           0 :   newTag.forget(aResult);
    1566           0 :   return NS_OK;
    1567             : }
    1568             : 
    1569             : NS_IMETHODIMP
    1570           0 : nsPluginHost::UnregisterFakePlugin(const nsACString& aHandlerURI)
    1571             : {
    1572           0 :   nsCOMPtr<nsIURI> handlerURI;
    1573           0 :   nsresult rv = NS_NewURI(getter_AddRefs(handlerURI), aHandlerURI);
    1574           0 :   NS_ENSURE_SUCCESS(rv, rv);
    1575             : 
    1576           0 :   for (uint32_t i = 0; i < mFakePlugins.Length(); ++i) {
    1577           0 :     if (mFakePlugins[i]->HandlerURIMatches(handlerURI)) {
    1578           0 :       mFakePlugins.RemoveElementAt(i);
    1579           0 :       return NS_OK;
    1580             :     }
    1581             :   }
    1582             : 
    1583           0 :   return NS_OK;
    1584             : }
    1585             : 
    1586             : // FIXME-jsplugins Is this method actually needed?
    1587             : NS_IMETHODIMP
    1588           0 : nsPluginHost::GetFakePlugin(const nsACString & aMimeType,
    1589             :                             nsIFakePluginTag** aResult)
    1590             : {
    1591           0 :   RefPtr<nsFakePluginTag> result = FindFakePluginForType(aMimeType, false);
    1592           0 :   if (result) {
    1593           0 :     result.forget(aResult);
    1594           0 :     return NS_OK;
    1595             :   }
    1596             : 
    1597           0 :   *aResult = nullptr;
    1598           0 :   return NS_ERROR_NOT_AVAILABLE;
    1599             : }
    1600             : 
    1601             : #define ClearDataFromSitesClosure_CID {0x9fb21761, 0x2403, 0x41ad, {0x9e, 0xfd, 0x36, 0x7e, 0xc4, 0x4f, 0xa4, 0x5e}}
    1602             : 
    1603             : 
    1604             : // Class to hold all the data we need need for IterateMatchesAndClear and ClearDataFromSites
    1605             : class ClearDataFromSitesClosure : public nsIClearSiteDataCallback, public nsIGetSitesWithDataCallback {
    1606             : public:
    1607           0 :   ClearDataFromSitesClosure(nsIPluginTag* plugin, const nsACString& domain, uint64_t flags,
    1608             :                             int64_t maxAge, nsCOMPtr<nsIClearSiteDataCallback> callback,
    1609           0 :                             nsPluginHost* host) :
    1610           0 :     domain(domain), callback(callback), tag(plugin), flags(flags), maxAge(maxAge), host(host) {}
    1611             :   NS_DECL_ISUPPORTS
    1612             : 
    1613             :   // Callback from NPP_ClearSiteData, continue to iterate the matches and clear
    1614           0 :   NS_IMETHOD Callback(nsresult rv) override {
    1615           0 :     if (NS_FAILED(rv)) {
    1616           0 :       callback->Callback(rv);
    1617           0 :       return NS_OK;
    1618             :     }
    1619           0 :     if (!matches.Length()) {
    1620           0 :       callback->Callback(NS_OK);
    1621           0 :       return NS_OK;
    1622             :     }
    1623             : 
    1624           0 :     const nsCString match(matches[0]);
    1625           0 :     matches.RemoveElement(match);
    1626           0 :     PluginLibrary* library = static_cast<nsPluginTag*>(tag)->mPlugin->GetLibrary();
    1627           0 :     rv = library->NPP_ClearSiteData(match.get(), flags, maxAge, this);
    1628           0 :     if (NS_FAILED(rv)) {
    1629           0 :       callback->Callback(rv);
    1630           0 :       return NS_OK;
    1631             :     }
    1632           0 :     return NS_OK;
    1633             :   }
    1634             : 
    1635             :   // Callback from NPP_GetSitesWithData, kick the iteration off to clear the data
    1636           0 :   NS_IMETHOD SitesWithData(InfallibleTArray<nsCString>& sites) override
    1637             :   {
    1638             :     // Enumerate the sites and build a list of matches.
    1639           0 :     nsresult rv = host->EnumerateSiteData(domain, sites, matches, false);
    1640           0 :     Callback(rv);
    1641           0 :     return NS_OK;
    1642             :   }
    1643             : 
    1644             :   nsCString domain;
    1645             :   nsCOMPtr<nsIClearSiteDataCallback> callback;
    1646             :   InfallibleTArray<nsCString> matches;
    1647             :   nsIPluginTag* tag;
    1648             :   uint64_t flags;
    1649             :   int64_t maxAge;
    1650             :   nsPluginHost* host;
    1651             :   NS_DECLARE_STATIC_IID_ACCESSOR(ClearDataFromSitesClosure_CID)
    1652             :   private:
    1653           0 :   virtual ~ClearDataFromSitesClosure() = default;
    1654             : };
    1655             : 
    1656             : NS_DEFINE_STATIC_IID_ACCESSOR(ClearDataFromSitesClosure, ClearDataFromSitesClosure_CID)
    1657             : 
    1658           0 : NS_IMPL_ADDREF(ClearDataFromSitesClosure)
    1659           0 : NS_IMPL_RELEASE(ClearDataFromSitesClosure)
    1660             : 
    1661           0 : NS_INTERFACE_MAP_BEGIN(ClearDataFromSitesClosure)
    1662           0 :   NS_INTERFACE_MAP_ENTRY(nsIClearSiteDataCallback)
    1663           0 :   NS_INTERFACE_MAP_ENTRY(nsIGetSitesWithDataCallback)
    1664           0 :   NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsISupports, nsIClearSiteDataCallback)
    1665           0 : NS_INTERFACE_MAP_END
    1666             : 
    1667             : // FIXME-jsplugins what should this do for fake plugins?
    1668             : NS_IMETHODIMP
    1669           0 : nsPluginHost::ClearSiteData(nsIPluginTag* plugin, const nsACString& domain,
    1670             :                             uint64_t flags, int64_t maxAge, nsIClearSiteDataCallback* callbackFunc)
    1671             : {
    1672           0 :   nsCOMPtr<nsIClearSiteDataCallback> callback(callbackFunc);
    1673             :   // maxAge must be either a nonnegative integer or -1.
    1674           0 :   NS_ENSURE_ARG(maxAge >= 0 || maxAge == -1);
    1675             : 
    1676             :   // Caller may give us a tag object that is no longer live.
    1677           0 :   if (!IsLiveTag(plugin)) {
    1678           0 :     return NS_ERROR_NOT_AVAILABLE;
    1679             :   }
    1680             : 
    1681           0 :   nsPluginTag* tag = static_cast<nsPluginTag*>(plugin);
    1682             : 
    1683           0 :   if (!tag->IsEnabled()) {
    1684           0 :     return NS_ERROR_NOT_AVAILABLE;
    1685             :   }
    1686             : 
    1687             :   // We only ensure support for clearing Flash site data for now.
    1688             :   // We will also attempt to clear data for any plugin that happens
    1689             :   // to be loaded already.
    1690           0 :   if (!tag->mIsFlashPlugin && !tag->mPlugin) {
    1691           0 :     return NS_ERROR_FAILURE;
    1692             :   }
    1693             : 
    1694             :   // Make sure the plugin is loaded.
    1695           0 :   nsresult rv = EnsurePluginLoaded(tag);
    1696           0 :   if (NS_FAILED(rv)) {
    1697           0 :     return rv;
    1698             :   }
    1699             : 
    1700           0 :   PluginLibrary* library = tag->mPlugin->GetLibrary();
    1701             : 
    1702             :   // If 'domain' is the null string, clear everything.
    1703           0 :   if (domain.IsVoid()) {
    1704           0 :     return library->NPP_ClearSiteData(nullptr, flags, maxAge, callback);
    1705             :   }
    1706           0 :   nsCOMPtr<nsIGetSitesWithDataCallback> closure(new ClearDataFromSitesClosure(plugin, domain, flags,
    1707           0 :                                                                               maxAge, callback, this));
    1708           0 :   rv = library->NPP_GetSitesWithData(closure);
    1709           0 :   NS_ENSURE_SUCCESS(rv, rv);
    1710           0 :   return NS_OK;
    1711             : }
    1712             : 
    1713             : #define GetSitesClosure_CID {0x4c9268ac, 0x2fd1, 0x4f2a, {0x9a, 0x10, 0x7a, 0x09, 0xf1, 0xb7, 0x60, 0x3a}}
    1714             : 
    1715             : // Closure to contain the data needed to handle the callback from NPP_GetSitesWithData
    1716             : class GetSitesClosure : public nsIGetSitesWithDataCallback {
    1717             : public:
    1718             :   NS_DECL_ISUPPORTS
    1719           0 :   GetSitesClosure(const nsACString& domain, nsPluginHost* host)
    1720           0 :   : domain(domain), host(host), keepWaiting(true)
    1721             :   {
    1722           0 :   }
    1723           0 :   NS_IMETHOD SitesWithData(InfallibleTArray<nsCString>& sites) override {
    1724           0 :     retVal = HandleGetSites(sites);
    1725           0 :     keepWaiting = false;
    1726           0 :     return NS_OK;
    1727             :   }
    1728             : 
    1729           0 :   nsresult HandleGetSites(InfallibleTArray<nsCString>& sites) {
    1730             :     // If there's no data, we're done.
    1731           0 :     if (sites.IsEmpty()) {
    1732           0 :       result = false;
    1733           0 :       return NS_OK;
    1734             :     }
    1735             : 
    1736             :     // If 'domain' is the null string, and there's data for at least one site,
    1737             :     // we're done.
    1738           0 :     if (domain.IsVoid()) {
    1739           0 :       result = true;
    1740           0 :       return NS_OK;
    1741             :     }
    1742             : 
    1743             :     // Enumerate the sites and determine if there's a match.
    1744           0 :     InfallibleTArray<nsCString> matches;
    1745           0 :     nsresult rv = host->EnumerateSiteData(domain, sites, matches, true);
    1746           0 :     NS_ENSURE_SUCCESS(rv, rv);
    1747             : 
    1748           0 :     result = !matches.IsEmpty();
    1749           0 :     return NS_OK;
    1750             :   }
    1751             : 
    1752             :   nsCString domain;
    1753             :   RefPtr<nsPluginHost> host;
    1754             :   bool result;
    1755             :   bool keepWaiting;
    1756             :   nsresult retVal;
    1757             :   NS_DECLARE_STATIC_IID_ACCESSOR(GetSitesClosure_CID)
    1758             :   private:
    1759           0 :   virtual ~GetSitesClosure() = default;
    1760             : };
    1761             : 
    1762             : NS_DEFINE_STATIC_IID_ACCESSOR(GetSitesClosure, GetSitesClosure_CID)
    1763             : 
    1764           0 : NS_IMPL_ISUPPORTS(GetSitesClosure, GetSitesClosure, nsIGetSitesWithDataCallback)
    1765             : 
    1766             : // This will spin the event loop while waiting on an async
    1767             : // call to GetSitesWithData
    1768             : NS_IMETHODIMP
    1769           0 : nsPluginHost::SiteHasData(nsIPluginTag* plugin, const nsACString& domain,
    1770             :                           bool* result)
    1771             : {
    1772             :   // Caller may give us a tag object that is no longer live.
    1773           0 :   if (!IsLiveTag(plugin)) {
    1774           0 :     return NS_ERROR_NOT_AVAILABLE;
    1775             :   }
    1776             : 
    1777             :   // FIXME-jsplugins audit casts
    1778           0 :   nsPluginTag* tag = static_cast<nsPluginTag*>(plugin);
    1779             : 
    1780             :   // We only ensure support for clearing Flash site data for now.
    1781             :   // We will also attempt to clear data for any plugin that happens
    1782             :   // to be loaded already.
    1783           0 :   if (!tag->mIsFlashPlugin && !tag->mPlugin) {
    1784           0 :     return NS_ERROR_FAILURE;
    1785             :   }
    1786             : 
    1787             :   // Make sure the plugin is loaded.
    1788           0 :   nsresult rv = EnsurePluginLoaded(tag);
    1789           0 :   if (NS_FAILED(rv)) {
    1790           0 :     return rv;
    1791             :   }
    1792             : 
    1793           0 :   PluginLibrary* library = tag->mPlugin->GetLibrary();
    1794             : 
    1795             :   // Get the list of sites from the plugin
    1796           0 :   nsCOMPtr<GetSitesClosure> closure(new GetSitesClosure(domain, this));
    1797           0 :   rv = library->NPP_GetSitesWithData(nsCOMPtr<nsIGetSitesWithDataCallback>(do_QueryInterface(closure)));
    1798           0 :   NS_ENSURE_SUCCESS(rv, rv);
    1799             :   // Spin the event loop while we wait for the async call to GetSitesWithData
    1800           0 :   SpinEventLoopUntil([&]() { return !closure->keepWaiting; });
    1801           0 :   *result = closure->result;
    1802           0 :   return closure->retVal;
    1803             : }
    1804             : 
    1805             : nsPluginHost::SpecialType
    1806           0 : nsPluginHost::GetSpecialType(const nsACString & aMIMEType)
    1807             : {
    1808           0 :   if (aMIMEType.LowerCaseEqualsASCII("application/x-test")) {
    1809           0 :     return eSpecialType_Test;
    1810             :   }
    1811             : 
    1812           0 :   if (aMIMEType.LowerCaseEqualsASCII("application/x-shockwave-flash") ||
    1813           0 :       aMIMEType.LowerCaseEqualsASCII("application/futuresplash") ||
    1814           0 :       aMIMEType.LowerCaseEqualsASCII("application/x-shockwave-flash-test")) {
    1815           0 :     return eSpecialType_Flash;
    1816             :   }
    1817             : 
    1818             :   // Java registers variants of its MIME with parameters, e.g.
    1819             :   // application/x-java-vm;version=1.3
    1820           0 :   const nsACString &noParam = Substring(aMIMEType, 0, aMIMEType.FindChar(';'));
    1821             : 
    1822             :   // The java mime pref may well not be one of these,
    1823             :   // e.g. application/x-java-test used in the test suite
    1824           0 :   nsAdoptingCString javaMIME = Preferences::GetCString(kPrefJavaMIME);
    1825           0 :   if ((!javaMIME.IsEmpty() && noParam.LowerCaseEqualsASCII(javaMIME)) ||
    1826           0 :       noParam.LowerCaseEqualsASCII("application/x-java-vm") ||
    1827           0 :       noParam.LowerCaseEqualsASCII("application/x-java-applet") ||
    1828           0 :       noParam.LowerCaseEqualsASCII("application/x-java-bean")) {
    1829           0 :     return eSpecialType_Java;
    1830             :   }
    1831             : 
    1832           0 :   return eSpecialType_None;
    1833             : }
    1834             : 
    1835             : // Check whether or not a tag is a live, valid tag, and that it's loaded.
    1836             : bool
    1837           0 : nsPluginHost::IsLiveTag(nsIPluginTag* aPluginTag)
    1838             : {
    1839           0 :   nsCOMPtr<nsIInternalPluginTag> internalTag(do_QueryInterface(aPluginTag));
    1840           0 :   uint32_t fakeCount = mFakePlugins.Length();
    1841           0 :   for (uint32_t i = 0; i < fakeCount; i++) {
    1842           0 :     if (mFakePlugins[i] == internalTag) {
    1843           0 :       return true;
    1844             :     }
    1845             :   }
    1846             : 
    1847             :   nsPluginTag* tag;
    1848           0 :   for (tag = mPlugins; tag; tag = tag->mNext) {
    1849           0 :     if (tag == internalTag) {
    1850           0 :       return true;
    1851             :     }
    1852             :   }
    1853           0 :   return false;
    1854             : }
    1855             : 
    1856             : // FIXME-jsplugins what should happen with jsplugins here, if anything?
    1857             : nsPluginTag*
    1858           0 : nsPluginHost::HaveSamePlugin(const nsPluginTag* aPluginTag)
    1859             : {
    1860           0 :   for (nsPluginTag* tag = mPlugins; tag; tag = tag->mNext) {
    1861           0 :     if (tag->HasSameNameAndMimes(aPluginTag)) {
    1862           0 :         return tag;
    1863             :     }
    1864             :   }
    1865           0 :   return nullptr;
    1866             : }
    1867             : 
    1868             : // Don't have to worry about fake plugins here, since this is only used during
    1869             : // the plugin directory scan, which doesn't pick up fake plugins.
    1870             : nsPluginTag*
    1871           0 : nsPluginHost::FirstPluginWithPath(const nsCString& path)
    1872             : {
    1873           0 :   for (nsPluginTag* tag = mPlugins; tag; tag = tag->mNext) {
    1874           0 :     if (tag->mFullPath.Equals(path)) {
    1875           0 :       return tag;
    1876             :     }
    1877             :   }
    1878           0 :   return nullptr;
    1879             : }
    1880             : 
    1881             : nsPluginTag*
    1882           0 : nsPluginHost::PluginWithId(uint32_t aId)
    1883             : {
    1884           0 :   for (nsPluginTag* tag = mPlugins; tag; tag = tag->mNext) {
    1885           0 :     if (tag->mId == aId) {
    1886           0 :       return tag;
    1887             :     }
    1888             :   }
    1889           0 :   return nullptr;
    1890             : }
    1891             : 
    1892             : namespace {
    1893             : 
    1894           0 : int64_t GetPluginLastModifiedTime(const nsCOMPtr<nsIFile>& localfile)
    1895             : {
    1896           0 :   PRTime fileModTime = 0;
    1897             : 
    1898             : #if defined(XP_MACOSX)
    1899             :   // On OS X the date of a bundle's "contents" (i.e. of its Info.plist file)
    1900             :   // is a much better guide to when it was last modified than the date of
    1901             :   // its package directory.  See bug 313700.
    1902             :   nsCOMPtr<nsILocalFileMac> localFileMac = do_QueryInterface(localfile);
    1903             :   if (localFileMac) {
    1904             :     localFileMac->GetBundleContentsLastModifiedTime(&fileModTime);
    1905             :   } else {
    1906             :     localfile->GetLastModifiedTime(&fileModTime);
    1907             :   }
    1908             : #else
    1909           0 :   localfile->GetLastModifiedTime(&fileModTime);
    1910             : #endif
    1911             : 
    1912           0 :   return fileModTime;
    1913             : }
    1914             : 
    1915             : bool
    1916           0 : GetPluginIsFromExtension(const nsCOMPtr<nsIFile>& pluginFile,
    1917             :                          const nsCOMArray<nsIFile>& extensionDirs)
    1918             : {
    1919           0 :   for (uint32_t i = 0; i < extensionDirs.Length(); ++i) {
    1920             :     bool contains;
    1921           0 :     if (NS_FAILED(extensionDirs[i]->Contains(pluginFile, &contains)) || !contains) {
    1922           0 :       continue;
    1923             :     }
    1924             : 
    1925           0 :     return true;
    1926             :   }
    1927             : 
    1928           0 :   return false;
    1929             : }
    1930             : 
    1931             : void
    1932           0 : GetExtensionDirectories(nsCOMArray<nsIFile>& dirs)
    1933             : {
    1934           0 :   nsCOMPtr<nsIProperties> dirService = do_GetService(NS_DIRECTORY_SERVICE_CONTRACTID);
    1935           0 :   if (!dirService) {
    1936           0 :     return;
    1937             :   }
    1938             : 
    1939           0 :   nsCOMPtr<nsISimpleEnumerator> list;
    1940           0 :   nsresult rv = dirService->Get(XRE_EXTENSIONS_DIR_LIST,
    1941             :                                 NS_GET_IID(nsISimpleEnumerator),
    1942           0 :                                 getter_AddRefs(list));
    1943           0 :   if (NS_FAILED(rv)) {
    1944           0 :     return;
    1945             :   }
    1946             : 
    1947             :   bool more;
    1948           0 :   while (NS_SUCCEEDED(list->HasMoreElements(&more)) && more) {
    1949           0 :     nsCOMPtr<nsISupports> next;
    1950           0 :     if (NS_FAILED(list->GetNext(getter_AddRefs(next)))) {
    1951           0 :       break;
    1952             :     }
    1953           0 :     nsCOMPtr<nsIFile> file = do_QueryInterface(next);
    1954           0 :     if (file) {
    1955           0 :       file->Normalize();
    1956           0 :       dirs.AppendElement(file.forget());
    1957             :     }
    1958             :   }
    1959             : }
    1960             : 
    1961             : struct CompareFilesByTime
    1962             : {
    1963             :   bool
    1964           0 :   LessThan(const nsCOMPtr<nsIFile>& a, const nsCOMPtr<nsIFile>& b) const
    1965             :   {
    1966           0 :     return GetPluginLastModifiedTime(a) < GetPluginLastModifiedTime(b);
    1967             :   }
    1968             : 
    1969             :   bool
    1970           0 :   Equals(const nsCOMPtr<nsIFile>& a, const nsCOMPtr<nsIFile>& b) const
    1971             :   {
    1972           0 :     return GetPluginLastModifiedTime(a) == GetPluginLastModifiedTime(b);
    1973             :   }
    1974             : };
    1975             : 
    1976             : } // namespace
    1977             : 
    1978             : static
    1979             : bool
    1980           0 : ShouldAddPlugin(const nsPluginInfo& info, bool flashOnly)
    1981             : {
    1982           0 :   if (!info.fName || (strcmp(info.fName, "Shockwave Flash") != 0 && flashOnly)) {
    1983           0 :     return false;
    1984             :   }
    1985           0 :   for (uint32_t i = 0; i < info.fVariantCount; ++i) {
    1986           0 :     if (info.fMimeTypeArray[i] &&
    1987           0 :         (!strcmp(info.fMimeTypeArray[i], "application/x-shockwave-flash") ||
    1988           0 :          !strcmp(info.fMimeTypeArray[i], "application/x-shockwave-flash-test"))) {
    1989           0 :       return true;
    1990             :     }
    1991           0 :     if (flashOnly) {
    1992           0 :       continue;
    1993             :     }
    1994           0 :     if (info.fMimeTypeArray[i] &&
    1995           0 :         (!strcmp(info.fMimeTypeArray[i], "application/x-test") ||
    1996           0 :          !strcmp(info.fMimeTypeArray[i], "application/x-Second-Test") ||
    1997           0 :          !strcmp(info.fMimeTypeArray[i], "application/x-java-test"))) {
    1998           0 :       return true;
    1999             :     }
    2000             :   }
    2001             : #ifdef PLUGIN_LOGGING
    2002             :   PLUGIN_LOG(PLUGIN_LOG_NORMAL,
    2003             :              ("ShouldAddPlugin : Ignoring non-flash plugin library %s\n", aPluginTag->FileName().get()));
    2004             : #endif // PLUGIN_LOGGING
    2005           0 :   return false;
    2006             : }
    2007             : 
    2008             : void
    2009           0 : nsPluginHost::AddPluginTag(nsPluginTag* aPluginTag)
    2010             : {
    2011           0 :   aPluginTag->mNext = mPlugins;
    2012           0 :   mPlugins = aPluginTag;
    2013             : 
    2014           0 :   if (aPluginTag->IsActive()) {
    2015             :     nsAdoptingCString disableFullPage =
    2016           0 :       Preferences::GetCString(kPrefDisableFullPage);
    2017           0 :     for (uint32_t i = 0; i < aPluginTag->MimeTypes().Length(); i++) {
    2018           0 :       if (!IsTypeInList(aPluginTag->MimeTypes()[i], disableFullPage)) {
    2019           0 :         RegisterWithCategoryManager(aPluginTag->MimeTypes()[i],
    2020           0 :                                     ePluginRegister);
    2021             :       }
    2022             :     }
    2023             :   }
    2024           0 : }
    2025             : 
    2026             : typedef NS_NPAPIPLUGIN_CALLBACK(char *, NP_GETMIMEDESCRIPTION)(void);
    2027             : 
    2028           0 : nsresult nsPluginHost::ScanPluginsDirectory(nsIFile *pluginsDir,
    2029             :                                             bool aCreatePluginList,
    2030             :                                             bool *aPluginsChanged)
    2031             : {
    2032           0 :   MOZ_ASSERT(XRE_IsParentProcess());
    2033             : 
    2034           0 :   NS_ENSURE_ARG_POINTER(aPluginsChanged);
    2035             :   nsresult rv;
    2036             : 
    2037           0 :   *aPluginsChanged = false;
    2038             : 
    2039             : #ifdef PLUGIN_LOGGING
    2040             :   nsAutoCString dirPath;
    2041             :   pluginsDir->GetNativePath(dirPath);
    2042             :   PLUGIN_LOG(PLUGIN_LOG_BASIC,
    2043             :   ("nsPluginHost::ScanPluginsDirectory dir=%s\n", dirPath.get()));
    2044             : #endif
    2045             : 
    2046           0 :   bool flashOnly = Preferences::GetBool("plugin.load_flash_only", true);
    2047             : 
    2048           0 :   nsCOMPtr<nsISimpleEnumerator> iter;
    2049           0 :   rv = pluginsDir->GetDirectoryEntries(getter_AddRefs(iter));
    2050           0 :   if (NS_FAILED(rv))
    2051           0 :     return rv;
    2052             : 
    2053           0 :   AutoTArray<nsCOMPtr<nsIFile>, 6> pluginFiles;
    2054             : 
    2055             :   bool hasMore;
    2056           0 :   while (NS_SUCCEEDED(iter->HasMoreElements(&hasMore)) && hasMore) {
    2057           0 :     nsCOMPtr<nsISupports> supports;
    2058           0 :     rv = iter->GetNext(getter_AddRefs(supports));
    2059           0 :     if (NS_FAILED(rv))
    2060           0 :       continue;
    2061           0 :     nsCOMPtr<nsIFile> dirEntry(do_QueryInterface(supports, &rv));
    2062           0 :     if (NS_FAILED(rv))
    2063           0 :       continue;
    2064             : 
    2065             :     // Sun's JRE 1.3.1 plugin must have symbolic links resolved or else it'll crash.
    2066             :     // See bug 197855.
    2067           0 :     dirEntry->Normalize();
    2068             : 
    2069           0 :     if (nsPluginsDir::IsPluginFile(dirEntry)) {
    2070           0 :       pluginFiles.AppendElement(dirEntry);
    2071             :     }
    2072             :   }
    2073             : 
    2074           0 :   pluginFiles.Sort(CompareFilesByTime());
    2075             : 
    2076           0 :   nsCOMArray<nsIFile> extensionDirs;
    2077           0 :   GetExtensionDirectories(extensionDirs);
    2078             : 
    2079           0 :   for (int32_t i = (pluginFiles.Length() - 1); i >= 0; i--) {
    2080           0 :     nsCOMPtr<nsIFile>& localfile = pluginFiles[i];
    2081             : 
    2082           0 :     nsString utf16FilePath;
    2083           0 :     rv = localfile->GetPath(utf16FilePath);
    2084           0 :     if (NS_FAILED(rv))
    2085           0 :       continue;
    2086             : 
    2087           0 :     const int64_t fileModTime = GetPluginLastModifiedTime(localfile);
    2088           0 :     const bool fromExtension = GetPluginIsFromExtension(localfile, extensionDirs);
    2089             : 
    2090             :     // Look for it in our cache
    2091           0 :     NS_ConvertUTF16toUTF8 filePath(utf16FilePath);
    2092           0 :     RefPtr<nsPluginTag> pluginTag;
    2093           0 :     RemoveCachedPluginsInfo(filePath.get(), getter_AddRefs(pluginTag));
    2094             : 
    2095           0 :     bool seenBefore = false;
    2096             : 
    2097           0 :     if (pluginTag) {
    2098           0 :       seenBefore = true;
    2099             :       // If plugin changed, delete cachedPluginTag and don't use cache
    2100           0 :       if (fileModTime != pluginTag->mLastModifiedTime) {
    2101             :         // Plugins has changed. Don't use cached plugin info.
    2102           0 :         pluginTag = nullptr;
    2103             : 
    2104             :         // plugin file changed, flag this fact
    2105           0 :         *aPluginsChanged = true;
    2106             :       }
    2107             : 
    2108             :       // If we're not creating a list and we already know something changed then
    2109             :       // we're done.
    2110           0 :       if (!aCreatePluginList) {
    2111           0 :         if (*aPluginsChanged) {
    2112           0 :           return NS_OK;
    2113             :         }
    2114           0 :         continue;
    2115             :       }
    2116             :     }
    2117             : 
    2118           0 :     bool isKnownInvalidPlugin = false;
    2119           0 :     for (RefPtr<nsInvalidPluginTag> invalidPlugins = mInvalidPlugins;
    2120           0 :          invalidPlugins; invalidPlugins = invalidPlugins->mNext) {
    2121             :       // If already marked as invalid, ignore it
    2122           0 :       if (invalidPlugins->mFullPath.Equals(filePath.get()) &&
    2123           0 :           invalidPlugins->mLastModifiedTime == fileModTime) {
    2124           0 :         if (aCreatePluginList) {
    2125           0 :           invalidPlugins->mSeen = true;
    2126             :         }
    2127           0 :         isKnownInvalidPlugin = true;
    2128           0 :         break;
    2129             :       }
    2130             :     }
    2131           0 :     if (isKnownInvalidPlugin) {
    2132           0 :       continue;
    2133             :     }
    2134             : 
    2135             :     // if it is not found in cache info list or has been changed, create a new one
    2136           0 :     if (!pluginTag) {
    2137           0 :       nsPluginFile pluginFile(localfile);
    2138             : 
    2139             :       // create a tag describing this plugin.
    2140           0 :       PRLibrary *library = nullptr;
    2141             :       nsPluginInfo info;
    2142           0 :       memset(&info, 0, sizeof(info));
    2143             :       nsresult res;
    2144             :       // Opening a block for the telemetry AutoTimer
    2145             :       {
    2146           0 :         Telemetry::AutoTimer<Telemetry::PLUGIN_LOAD_METADATA> telemetry;
    2147           0 :         res = pluginFile.GetPluginInfo(info, &library);
    2148             :       }
    2149             :       // if we don't have mime type don't proceed, this is not a plugin
    2150           0 :       if (NS_FAILED(res) || !info.fMimeTypeArray ||
    2151           0 :           (!ShouldAddPlugin(info, flashOnly))) {
    2152           0 :         RefPtr<nsInvalidPluginTag> invalidTag = new nsInvalidPluginTag(filePath.get(),
    2153           0 :                                                                          fileModTime);
    2154           0 :         pluginFile.FreePluginInfo(info);
    2155             : 
    2156           0 :         if (aCreatePluginList) {
    2157           0 :           invalidTag->mSeen = true;
    2158             :         }
    2159           0 :         invalidTag->mNext = mInvalidPlugins;
    2160           0 :         if (mInvalidPlugins) {
    2161           0 :           mInvalidPlugins->mPrev = invalidTag;
    2162             :         }
    2163           0 :         mInvalidPlugins = invalidTag;
    2164             : 
    2165             :         // Mark aPluginsChanged so pluginreg is rewritten
    2166           0 :         *aPluginsChanged = true;
    2167           0 :         continue;
    2168             :       }
    2169             : 
    2170           0 :       pluginTag = new nsPluginTag(&info, fileModTime, fromExtension);
    2171           0 :       pluginFile.FreePluginInfo(info);
    2172           0 :       pluginTag->mLibrary = library;
    2173             :       uint32_t state;
    2174           0 :       rv = pluginTag->GetBlocklistState(&state);
    2175           0 :       NS_ENSURE_SUCCESS(rv, rv);
    2176             : 
    2177             :       // If the blocklist says it is risky and we have never seen this
    2178             :       // plugin before, then disable it.
    2179           0 :       if (state == nsIBlocklistService::STATE_SOFTBLOCKED && !seenBefore) {
    2180           0 :         pluginTag->SetEnabledState(nsIPluginTag::STATE_DISABLED);
    2181             :       }
    2182             : 
    2183             :       // Plugin unloading is tag-based. If we created a new tag and loaded
    2184             :       // the library in the process then we want to attempt to unload it here.
    2185             :       // Only do this if the pref is set for aggressive unloading.
    2186           0 :       if (UnloadPluginsASAP()) {
    2187           0 :         pluginTag->TryUnloadPlugin(false);
    2188             :       }
    2189             :     }
    2190             : 
    2191             :     // do it if we still want it
    2192           0 :     if (!seenBefore) {
    2193             :       // We have a valid new plugin so report that plugins have changed.
    2194           0 :       *aPluginsChanged = true;
    2195             :     }
    2196             : 
    2197             :     // Avoid adding different versions of the same plugin if they are running
    2198             :     // in-process, otherwise we risk undefined behaviour.
    2199           0 :     if (!nsNPAPIPlugin::RunPluginOOP(pluginTag)) {
    2200           0 :       if (HaveSamePlugin(pluginTag)) {
    2201           0 :         continue;
    2202             :       }
    2203             :     }
    2204             : 
    2205             :     // Don't add the same plugin again if it hasn't changed
    2206           0 :     if (nsPluginTag* duplicate = FirstPluginWithPath(pluginTag->mFullPath)) {
    2207           0 :       if (pluginTag->mLastModifiedTime == duplicate->mLastModifiedTime) {
    2208           0 :         continue;
    2209             :       }
    2210             :     }
    2211             : 
    2212             :     // If we're not creating a plugin list, simply looking for changes,
    2213             :     // then we're done.
    2214           0 :     if (!aCreatePluginList) {
    2215           0 :       return NS_OK;
    2216             :     }
    2217             : 
    2218           0 :     AddPluginTag(pluginTag);
    2219             :   }
    2220             : 
    2221           0 :   return NS_OK;
    2222             : }
    2223             : 
    2224           1 : nsresult nsPluginHost::ScanPluginsDirectoryList(nsISimpleEnumerator *dirEnum,
    2225             :                                                 bool aCreatePluginList,
    2226             :                                                 bool *aPluginsChanged)
    2227             : {
    2228           1 :   MOZ_ASSERT(XRE_IsParentProcess());
    2229             : 
    2230             :     bool hasMore;
    2231           1 :     while (NS_SUCCEEDED(dirEnum->HasMoreElements(&hasMore)) && hasMore) {
    2232           0 :       nsCOMPtr<nsISupports> supports;
    2233           0 :       nsresult rv = dirEnum->GetNext(getter_AddRefs(supports));
    2234           0 :       if (NS_FAILED(rv))
    2235           0 :         continue;
    2236           0 :       nsCOMPtr<nsIFile> nextDir(do_QueryInterface(supports, &rv));
    2237           0 :       if (NS_FAILED(rv))
    2238           0 :         continue;
    2239             : 
    2240             :       // don't pass aPluginsChanged directly to prevent it from been reset
    2241           0 :       bool pluginschanged = false;
    2242           0 :       ScanPluginsDirectory(nextDir, aCreatePluginList, &pluginschanged);
    2243             : 
    2244           0 :       if (pluginschanged)
    2245           0 :         *aPluginsChanged = true;
    2246             : 
    2247             :       // if changes are detected and we are not creating the list, do not proceed
    2248           0 :       if (!aCreatePluginList && *aPluginsChanged)
    2249           0 :         break;
    2250             :     }
    2251           1 :     return NS_OK;
    2252             : }
    2253             : 
    2254             : void
    2255           1 : nsPluginHost::IncrementChromeEpoch()
    2256             : {
    2257           1 :   MOZ_ASSERT(XRE_IsParentProcess());
    2258           1 :   mPluginEpoch++;
    2259           1 : }
    2260             : 
    2261             : uint32_t
    2262           2 : nsPluginHost::ChromeEpoch()
    2263             : {
    2264           2 :   MOZ_ASSERT(XRE_IsParentProcess());
    2265           2 :   return mPluginEpoch;
    2266             : }
    2267             : 
    2268             : uint32_t
    2269           3 : nsPluginHost::ChromeEpochForContent()
    2270             : {
    2271           3 :   MOZ_ASSERT(XRE_IsContentProcess());
    2272           3 :   return mPluginEpoch;
    2273             : }
    2274             : 
    2275             : void
    2276           2 : nsPluginHost::SetChromeEpochForContent(uint32_t aEpoch)
    2277             : {
    2278           2 :   MOZ_ASSERT(XRE_IsContentProcess());
    2279           2 :   mPluginEpoch = aEpoch;
    2280           2 : }
    2281             : 
    2282             : #ifdef XP_WIN
    2283             : static void
    2284             : WatchRegKey(uint32_t aRoot, nsCOMPtr<nsIWindowsRegKey>& aKey)
    2285             : {
    2286             :   if (aKey) {
    2287             :     return;
    2288             :   }
    2289             : 
    2290             :   aKey = do_CreateInstance("@mozilla.org/windows-registry-key;1");
    2291             :   if (!aKey) {
    2292             :     return;
    2293             :   }
    2294             :   nsresult rv = aKey->Open(aRoot,
    2295             :                            NS_LITERAL_STRING("Software\\MozillaPlugins"),
    2296             :                            nsIWindowsRegKey::ACCESS_READ | nsIWindowsRegKey::ACCESS_NOTIFY);
    2297             :   if (NS_FAILED(rv)) {
    2298             :     aKey = nullptr;
    2299             :     return;
    2300             :   }
    2301             :   aKey->StartWatching(true);
    2302             : }
    2303             : #endif
    2304             : 
    2305           9 : nsresult nsPluginHost::LoadPlugins()
    2306             : {
    2307             :   // This should only be run in the parent process. On plugin list change, we'll
    2308             :   // update observers in the content process as part of SetPluginsInContent
    2309           9 :   if (XRE_IsContentProcess()) {
    2310           2 :     return NS_OK;
    2311             :   }
    2312             :   // do not do anything if it is already done
    2313             :   // use ReloadPlugins() to enforce loading
    2314           7 :   if (mPluginsLoaded)
    2315           6 :     return NS_OK;
    2316             : 
    2317           1 :   if (mPluginsDisabled)
    2318           0 :     return NS_OK;
    2319             : 
    2320             : #ifdef XP_WIN
    2321             :   WatchRegKey(nsIWindowsRegKey::ROOT_KEY_LOCAL_MACHINE, mRegKeyHKLM);
    2322             :   WatchRegKey(nsIWindowsRegKey::ROOT_KEY_CURRENT_USER, mRegKeyHKCU);
    2323             : #endif
    2324             : 
    2325             :   bool pluginschanged;
    2326           1 :   nsresult rv = FindPlugins(true, &pluginschanged);
    2327           1 :   if (NS_FAILED(rv))
    2328           0 :     return rv;
    2329             : 
    2330             :   // only if plugins have changed will we notify plugin-change observers
    2331           1 :   if (pluginschanged) {
    2332           0 :     if (XRE_IsParentProcess()) {
    2333           0 :       IncrementChromeEpoch();
    2334             :     }
    2335             : 
    2336             :     nsCOMPtr<nsIObserverService> obsService =
    2337           0 :       mozilla::services::GetObserverService();
    2338           0 :     if (obsService)
    2339           0 :       obsService->NotifyObservers(nullptr, "plugins-list-updated", nullptr);
    2340             :   }
    2341             : 
    2342           1 :   return NS_OK;
    2343             : }
    2344             : 
    2345             : nsresult
    2346           3 : nsPluginHost::SetPluginsInContent(uint32_t aPluginEpoch,
    2347             :                                   nsTArray<mozilla::plugins::PluginTag>& aPlugins,
    2348             :                                   nsTArray<mozilla::plugins::FakePluginTag>& aFakePlugins)
    2349             : {
    2350           3 :   MOZ_ASSERT(XRE_IsContentProcess());
    2351             : 
    2352           6 :   nsTArray<PluginTag> plugins;
    2353             : 
    2354           6 :   nsTArray<FakePluginTag> fakePlugins;
    2355             : 
    2356           3 :   if (aPluginEpoch != ChromeEpochForContent()) {
    2357             :     // Since we know we're going to be repopulating the lists anyways, trigger a
    2358             :     // reload now to clear out all old entries.
    2359           2 :     ActuallyReloadPlugins();
    2360             : 
    2361           2 :     SetChromeEpochForContent(aPluginEpoch);
    2362             : 
    2363           2 :     for (auto tag : aPlugins) {
    2364             : 
    2365             :       // Don't add the same plugin again.
    2366           0 :       if (nsPluginTag* existing = PluginWithId(tag.id())) {
    2367           0 :         UpdateInMemoryPluginInfo(existing);
    2368           0 :         continue;
    2369             :       }
    2370             : 
    2371           0 :       nsPluginTag *pluginTag = new nsPluginTag(tag.id(),
    2372           0 :                                                tag.name().get(),
    2373           0 :                                                tag.description().get(),
    2374           0 :                                                tag.filename().get(),
    2375             :                                                "", // aFullPath
    2376           0 :                                                tag.version().get(),
    2377           0 :                                                nsTArray<nsCString>(tag.mimeTypes()),
    2378           0 :                                                nsTArray<nsCString>(tag.mimeDescriptions()),
    2379           0 :                                                nsTArray<nsCString>(tag.extensions()),
    2380           0 :                                                tag.isJavaPlugin(),
    2381           0 :                                                tag.isFlashPlugin(),
    2382           0 :                                                tag.supportsAsyncRender(),
    2383           0 :                                                tag.lastModifiedTime(),
    2384           0 :                                                tag.isFromExtension(),
    2385           0 :                                                tag.sandboxLevel());
    2386           0 :       AddPluginTag(pluginTag);
    2387             :     }
    2388             : 
    2389           2 :     for (const auto& tag : aFakePlugins) {
    2390             :       // Don't add the same plugin again.
    2391           0 :       for (const auto& existingTag : mFakePlugins) {
    2392           0 :         if (existingTag->Id() == tag.id()) {
    2393           0 :           continue;
    2394             :         }
    2395             :       }
    2396             : 
    2397             :       RefPtr<nsFakePluginTag> pluginTag =
    2398           0 :       *mFakePlugins.AppendElement(new nsFakePluginTag(tag.id(),
    2399           0 :                                                       mozilla::ipc::DeserializeURI(tag.handlerURI()),
    2400           0 :                                                       tag.name().get(),
    2401           0 :                                                       tag.description().get(),
    2402             :                                                       tag.mimeTypes(),
    2403             :                                                       tag.mimeDescriptions(),
    2404             :                                                       tag.extensions(),
    2405             :                                                       tag.niceName(),
    2406           0 :                                                       tag.sandboxScript()));
    2407             :       nsAdoptingCString disableFullPage =
    2408           0 :         Preferences::GetCString(kPrefDisableFullPage);
    2409           0 :       for (uint32_t i = 0; i < pluginTag->MimeTypes().Length(); i++) {
    2410           0 :         if (!IsTypeInList(pluginTag->MimeTypes()[i], disableFullPage)) {
    2411           0 :           RegisterWithCategoryManager(pluginTag->MimeTypes()[i],
    2412           0 :                                       ePluginRegister);
    2413             :         }
    2414             :       }
    2415             :     }
    2416             : 
    2417             :     nsCOMPtr<nsIObserverService> obsService =
    2418           4 :       mozilla::services::GetObserverService();
    2419           2 :     if (obsService) {
    2420           2 :       obsService->NotifyObservers(nullptr, "plugins-list-updated", nullptr);
    2421             :     }
    2422             :   }
    2423             : 
    2424           3 :   mPluginsLoaded = true;
    2425           6 :   return NS_OK;
    2426             : }
    2427             : 
    2428             : // if aCreatePluginList is false we will just scan for plugins
    2429             : // and see if any changes have been made to the plugins.
    2430             : // This is needed in ReloadPlugins to prevent possible recursive reloads
    2431           1 : nsresult nsPluginHost::FindPlugins(bool aCreatePluginList, bool * aPluginsChanged)
    2432             : {
    2433           2 :   Telemetry::AutoTimer<Telemetry::FIND_PLUGINS> telemetry;
    2434             : 
    2435           1 :   NS_ENSURE_ARG_POINTER(aPluginsChanged);
    2436             : 
    2437           1 :   *aPluginsChanged = false;
    2438             : 
    2439             :   // If plugins are found or change, the content process will be notified by the
    2440             :   // parent process. Bail out early if this is called from the content process.
    2441           1 :   if (XRE_IsContentProcess()) {
    2442           0 :     return NS_OK;
    2443             :   }
    2444             : 
    2445             :   nsresult rv;
    2446             : 
    2447             :   // Read cached plugins info. If the profile isn't yet available then don't
    2448             :   // scan for plugins
    2449           1 :   if (ReadPluginInfo() == NS_ERROR_NOT_AVAILABLE)
    2450           0 :     return NS_OK;
    2451             : 
    2452             : #ifdef XP_WIN
    2453             :   // Failure here is not a show-stopper so just warn.
    2454             :   rv = EnsurePrivateDirServiceProvider();
    2455             :   NS_ASSERTION(NS_SUCCEEDED(rv), "Failed to register dir service provider.");
    2456             : #endif /* XP_WIN */
    2457             : 
    2458           2 :   nsCOMPtr<nsIProperties> dirService(do_GetService(kDirectoryServiceContractID, &rv));
    2459           1 :   if (NS_FAILED(rv))
    2460           0 :     return rv;
    2461             : 
    2462           2 :   nsCOMPtr<nsISimpleEnumerator> dirList;
    2463             : 
    2464             :   // Scan plugins directories;
    2465             :   // don't pass aPluginsChanged directly, to prevent its
    2466             :   // possible reset in subsequent ScanPluginsDirectory calls
    2467           1 :   bool pluginschanged = false;
    2468             : 
    2469             :   // Scan the app-defined list of plugin dirs.
    2470           1 :   rv = dirService->Get(NS_APP_PLUGINS_DIR_LIST, NS_GET_IID(nsISimpleEnumerator), getter_AddRefs(dirList));
    2471           1 :   if (NS_SUCCEEDED(rv)) {
    2472           1 :     ScanPluginsDirectoryList(dirList, aCreatePluginList, &pluginschanged);
    2473             : 
    2474           1 :     if (pluginschanged)
    2475           0 :       *aPluginsChanged = true;
    2476             : 
    2477             :     // if we are just looking for possible changes,
    2478             :     // no need to proceed if changes are detected
    2479           1 :     if (!aCreatePluginList && *aPluginsChanged) {
    2480           0 :       NS_ITERATIVE_UNREF_LIST(RefPtr<nsPluginTag>, mCachedPlugins, mNext);
    2481           0 :       NS_ITERATIVE_UNREF_LIST(RefPtr<nsInvalidPluginTag>, mInvalidPlugins, mNext);
    2482           0 :       return NS_OK;
    2483             :     }
    2484             :   } else {
    2485             : #ifdef ANDROID
    2486             :     LOG("getting plugins dir failed");
    2487             : #endif
    2488             :   }
    2489             : 
    2490           1 :   mPluginsLoaded = true; // at this point 'some' plugins have been loaded,
    2491             :                             // the rest is optional
    2492             : 
    2493             : #ifdef XP_WIN
    2494             :   bool bScanPLIDs = Preferences::GetBool("plugin.scan.plid.all", false);
    2495             : 
    2496             :     // Now lets scan any PLID directories
    2497             :   if (bScanPLIDs && mPrivateDirServiceProvider) {
    2498             :     rv = mPrivateDirServiceProvider->GetPLIDDirectories(getter_AddRefs(dirList));
    2499             :     if (NS_SUCCEEDED(rv)) {
    2500             :       ScanPluginsDirectoryList(dirList, aCreatePluginList, &pluginschanged);
    2501             : 
    2502             :       if (pluginschanged)
    2503             :         *aPluginsChanged = true;
    2504             : 
    2505             :       // if we are just looking for possible changes,
    2506             :       // no need to proceed if changes are detected
    2507             :       if (!aCreatePluginList && *aPluginsChanged) {
    2508             :         NS_ITERATIVE_UNREF_LIST(RefPtr<nsPluginTag>, mCachedPlugins, mNext);
    2509             :         NS_ITERATIVE_UNREF_LIST(RefPtr<nsInvalidPluginTag>, mInvalidPlugins, mNext);
    2510             :         return NS_OK;
    2511             :       }
    2512             :     }
    2513             :   }
    2514             : #endif
    2515             : 
    2516             :   // We should also consider plugins to have changed if any plugins have been removed.
    2517             :   // We'll know if any were removed if they weren't taken out of the cached plugins list
    2518             :   // during our scan, thus we can assume something was removed if the cached plugins list
    2519             :   // contains anything.
    2520           1 :   if (!*aPluginsChanged && mCachedPlugins) {
    2521           0 :     *aPluginsChanged = true;
    2522             :   }
    2523             : 
    2524             :   // Remove unseen invalid plugins
    2525           2 :   RefPtr<nsInvalidPluginTag> invalidPlugins = mInvalidPlugins;
    2526           1 :   while (invalidPlugins) {
    2527           0 :     if (!invalidPlugins->mSeen) {
    2528           0 :       RefPtr<nsInvalidPluginTag> invalidPlugin = invalidPlugins;
    2529             : 
    2530           0 :       if (invalidPlugin->mPrev) {
    2531           0 :         invalidPlugin->mPrev->mNext = invalidPlugin->mNext;
    2532             :       }
    2533             :       else {
    2534           0 :         mInvalidPlugins = invalidPlugin->mNext;
    2535             :       }
    2536           0 :       if (invalidPlugin->mNext) {
    2537           0 :         invalidPlugin->mNext->mPrev = invalidPlugin->mPrev;
    2538             :       }
    2539             : 
    2540           0 :       invalidPlugins = invalidPlugin->mNext;
    2541             : 
    2542           0 :       invalidPlugin->mPrev = nullptr;
    2543           0 :       invalidPlugin->mNext = nullptr;
    2544             :     }
    2545             :     else {
    2546           0 :       invalidPlugins->mSeen = false;
    2547           0 :       invalidPlugins = invalidPlugins->mNext;
    2548             :     }
    2549             :   }
    2550             : 
    2551             :   // if we are not creating the list, there is no need to proceed
    2552           1 :   if (!aCreatePluginList) {
    2553           0 :     NS_ITERATIVE_UNREF_LIST(RefPtr<nsPluginTag>, mCachedPlugins, mNext);
    2554           0 :     NS_ITERATIVE_UNREF_LIST(RefPtr<nsInvalidPluginTag>, mInvalidPlugins, mNext);
    2555           0 :     return NS_OK;
    2556             :   }
    2557             : 
    2558             :   // if we are creating the list, it is already done;
    2559             :   // update the plugins info cache if changes are detected
    2560           1 :   if (*aPluginsChanged)
    2561           0 :     WritePluginInfo();
    2562             : 
    2563             :   // No more need for cached plugins. Clear it up.
    2564           1 :   NS_ITERATIVE_UNREF_LIST(RefPtr<nsPluginTag>, mCachedPlugins, mNext);
    2565           1 :   NS_ITERATIVE_UNREF_LIST(RefPtr<nsInvalidPluginTag>, mInvalidPlugins, mNext);
    2566             : 
    2567           1 :   return NS_OK;
    2568             : }
    2569             : 
    2570             : nsresult
    2571           2 : nsPluginHost::SendPluginsToContent()
    2572             : {
    2573           2 :   MOZ_ASSERT(XRE_IsParentProcess());
    2574             : 
    2575           4 :   nsTArray<PluginTag> pluginTags;
    2576           4 :   nsTArray<FakePluginTag> fakePluginTags;
    2577             :   // Load plugins so that the epoch is correct.
    2578           2 :   nsresult rv = LoadPlugins();
    2579           2 :   if (NS_FAILED(rv)) {
    2580           0 :     return rv;
    2581             :   }
    2582             : 
    2583           2 :   uint32_t newPluginEpoch = ChromeEpoch();
    2584             : 
    2585           4 :   nsTArray<nsCOMPtr<nsIInternalPluginTag>> plugins;
    2586           2 :   GetPlugins(plugins, true);
    2587             : 
    2588           2 :   for (size_t i = 0; i < plugins.Length(); i++) {
    2589           0 :     nsCOMPtr<nsIInternalPluginTag> basetag = plugins[i];
    2590             : 
    2591           0 :     nsCOMPtr<nsIFakePluginTag> faketag = do_QueryInterface(basetag);
    2592           0 :     if (faketag) {
    2593             :       /// FIXME-jsplugins - We need to add a nsIInternalPluginTag->AsNative() to
    2594             :       /// avoid this hacky static cast
    2595           0 :       nsFakePluginTag* tag = static_cast<nsFakePluginTag*>(basetag.get());
    2596           0 :       mozilla::ipc::URIParams handlerURI;
    2597           0 :       SerializeURI(tag->HandlerURI(), handlerURI);
    2598           0 :       fakePluginTags.AppendElement(FakePluginTag(tag->Id(),
    2599             :                                                  handlerURI,
    2600             :                                                  tag->Name(),
    2601             :                                                  tag->Description(),
    2602             :                                                  tag->MimeTypes(),
    2603             :                                                  tag->MimeDescriptions(),
    2604             :                                                  tag->Extensions(),
    2605           0 :                                                  tag->GetNiceFileName(),
    2606           0 :                                                  tag->SandboxScript()));
    2607           0 :       continue;
    2608             :     }
    2609             : 
    2610             :     /// FIXME-jsplugins - We need to cleanup the various plugintag classes
    2611             :     /// to be more sane and avoid this dance
    2612           0 :     nsPluginTag *tag = static_cast<nsPluginTag *>(basetag.get());
    2613             : 
    2614           0 :     pluginTags.AppendElement(PluginTag(tag->mId,
    2615             :                                        tag->Name(),
    2616             :                                        tag->Description(),
    2617             :                                        tag->MimeTypes(),
    2618             :                                        tag->MimeDescriptions(),
    2619             :                                        tag->Extensions(),
    2620             :                                        tag->mIsJavaPlugin,
    2621             :                                        tag->mIsFlashPlugin,
    2622             :                                        tag->mSupportsAsyncRender,
    2623             :                                        tag->FileName(),
    2624             :                                        tag->Version(),
    2625             :                                        tag->mLastModifiedTime,
    2626           0 :                                        tag->IsFromExtension(),
    2627           0 :                                        tag->mSandboxLevel));
    2628             :   }
    2629           4 :   nsTArray<dom::ContentParent*> parents;
    2630           2 :   dom::ContentParent::GetAll(parents);
    2631           5 :   for (auto p : parents)
    2632             :   {
    2633           3 :     Unused << p->SendSetPluginList(newPluginEpoch, pluginTags, fakePluginTags);
    2634             :   }
    2635           2 :   return NS_OK;
    2636             : }
    2637             : 
    2638             : void
    2639           0 : nsPluginHost::UpdateInMemoryPluginInfo(nsPluginTag* aPluginTag)
    2640             : {
    2641           0 :   NS_ITERATIVE_UNREF_LIST(RefPtr<nsPluginTag>, mCachedPlugins, mNext);
    2642           0 :   NS_ITERATIVE_UNREF_LIST(RefPtr<nsInvalidPluginTag>, mInvalidPlugins, mNext);
    2643             : 
    2644           0 :   if (!aPluginTag) {
    2645           0 :     return;
    2646             :   }
    2647             : 
    2648             :   // Update types with category manager
    2649             :   nsAdoptingCString disableFullPage =
    2650           0 :     Preferences::GetCString(kPrefDisableFullPage);
    2651           0 :   for (uint32_t i = 0; i < aPluginTag->MimeTypes().Length(); i++) {
    2652             :     nsRegisterType shouldRegister;
    2653             : 
    2654           0 :     if (IsTypeInList(aPluginTag->MimeTypes()[i], disableFullPage)) {
    2655           0 :       shouldRegister = ePluginUnregister;
    2656             :     } else {
    2657           0 :       nsPluginTag *plugin = FindNativePluginForType(aPluginTag->MimeTypes()[i],
    2658           0 :                                                     true);
    2659           0 :       shouldRegister = plugin ? ePluginRegister : ePluginUnregister;
    2660             :     }
    2661             : 
    2662           0 :     RegisterWithCategoryManager(aPluginTag->MimeTypes()[i], shouldRegister);
    2663             :   }
    2664             : 
    2665             :   nsCOMPtr<nsIObserverService> obsService =
    2666           0 :     mozilla::services::GetObserverService();
    2667           0 :   if (obsService)
    2668           0 :     obsService->NotifyObservers(nullptr, "plugin-info-updated", nullptr);
    2669             : }
    2670             : 
    2671             : // This function is not relevant for fake plugins.
    2672             : void
    2673           0 : nsPluginHost::UpdatePluginInfo(nsPluginTag* aPluginTag)
    2674             : {
    2675           0 :   MOZ_ASSERT(XRE_IsParentProcess());
    2676             : 
    2677           0 :   ReadPluginInfo();
    2678           0 :   WritePluginInfo();
    2679             : 
    2680           0 :   IncrementChromeEpoch();
    2681             : 
    2682           0 :   UpdateInMemoryPluginInfo(aPluginTag);
    2683           0 : }
    2684             : 
    2685             : /* static */ bool
    2686           0 : nsPluginHost::IsTypeWhitelisted(const char *aMimeType)
    2687             : {
    2688           0 :   nsAdoptingCString whitelist = Preferences::GetCString(kPrefWhitelist);
    2689           0 :   if (!whitelist.Length()) {
    2690           0 :     return true;
    2691             :   }
    2692           0 :   nsDependentCString wrap(aMimeType);
    2693           0 :   return IsTypeInList(wrap, whitelist);
    2694             : }
    2695             : 
    2696             : /* static */ bool
    2697           0 : nsPluginHost::ShouldLoadTypeInParent(const nsACString& aMimeType)
    2698             : {
    2699           0 :   nsCString prefName(kPrefLoadInParentPrefix);
    2700           0 :   prefName += aMimeType;
    2701           0 :   return Preferences::GetBool(prefName.get(), false);
    2702             : }
    2703             : 
    2704             : void
    2705           0 : nsPluginHost::RegisterWithCategoryManager(const nsCString& aMimeType,
    2706             :                                           nsRegisterType aType)
    2707             : {
    2708           0 :   PLUGIN_LOG(PLUGIN_LOG_NORMAL,
    2709             :              ("nsPluginTag::RegisterWithCategoryManager type = %s, removing = %s\n",
    2710             :               aMimeType.get(), aType == ePluginUnregister ? "yes" : "no"));
    2711             : 
    2712             :   nsCOMPtr<nsICategoryManager> catMan =
    2713           0 :     do_GetService(NS_CATEGORYMANAGER_CONTRACTID);
    2714           0 :   if (!catMan) {
    2715           0 :     return;
    2716             :   }
    2717             : 
    2718             :   const char *contractId =
    2719           0 :     "@mozilla.org/content/plugin/document-loader-factory;1";
    2720             : 
    2721           0 :   if (aType == ePluginRegister) {
    2722           0 :     catMan->AddCategoryEntry("Gecko-Content-Viewers",
    2723             :                              aMimeType.get(),
    2724             :                              contractId,
    2725             :                              false, /* persist: broken by bug 193031 */
    2726           0 :                              mOverrideInternalTypes,
    2727           0 :                              nullptr);
    2728             :   } else {
    2729           0 :     if (aType == ePluginMaybeUnregister) {
    2730             :       // Bail out if this type is still used by an enabled plugin
    2731           0 :       if (HavePluginForType(aMimeType)) {
    2732           0 :         return;
    2733             :       }
    2734             :     } else {
    2735           0 :       MOZ_ASSERT(aType == ePluginUnregister, "Unknown nsRegisterType");
    2736             :     }
    2737             : 
    2738             :     // Only delete the entry if a plugin registered for it
    2739           0 :     nsXPIDLCString value;
    2740           0 :     nsresult rv = catMan->GetCategoryEntry("Gecko-Content-Viewers",
    2741             :                                            aMimeType.get(),
    2742           0 :                                            getter_Copies(value));
    2743           0 :     if (NS_SUCCEEDED(rv) && strcmp(value, contractId) == 0) {
    2744           0 :       catMan->DeleteCategoryEntry("Gecko-Content-Viewers",
    2745             :                                   aMimeType.get(),
    2746           0 :                                   true);
    2747             :     }
    2748             :   }
    2749             : }
    2750             : 
    2751             : nsresult
    2752           0 : nsPluginHost::WritePluginInfo()
    2753             : {
    2754           0 :   MOZ_ASSERT(XRE_IsParentProcess());
    2755             : 
    2756           0 :   nsresult rv = NS_OK;
    2757           0 :   nsCOMPtr<nsIProperties> directoryService(do_GetService(NS_DIRECTORY_SERVICE_CONTRACTID,&rv));
    2758           0 :   if (NS_FAILED(rv))
    2759           0 :     return rv;
    2760             : 
    2761           0 :   directoryService->Get(NS_APP_USER_PROFILE_50_DIR, NS_GET_IID(nsIFile),
    2762           0 :                         getter_AddRefs(mPluginRegFile));
    2763             : 
    2764           0 :   if (!mPluginRegFile)
    2765           0 :     return NS_ERROR_FAILURE;
    2766             : 
    2767           0 :   PRFileDesc* fd = nullptr;
    2768             : 
    2769           0 :   nsCOMPtr<nsIFile> pluginReg;
    2770             : 
    2771           0 :   rv = mPluginRegFile->Clone(getter_AddRefs(pluginReg));
    2772           0 :   if (NS_FAILED(rv))
    2773           0 :     return rv;
    2774             : 
    2775           0 :   nsAutoCString filename(kPluginRegistryFilename);
    2776           0 :   filename.AppendLiteral(".tmp");
    2777           0 :   rv = pluginReg->AppendNative(filename);
    2778           0 :   if (NS_FAILED(rv))
    2779           0 :     return rv;
    2780             : 
    2781           0 :   rv = pluginReg->OpenNSPRFileDesc(PR_WRONLY | PR_CREATE_FILE | PR_TRUNCATE, 0600, &fd);
    2782           0 :   if (NS_FAILED(rv))
    2783           0 :     return rv;
    2784             : 
    2785           0 :   nsCOMPtr<nsIXULRuntime> runtime = do_GetService("@mozilla.org/xre/runtime;1");
    2786           0 :   if (!runtime) {
    2787           0 :     return NS_ERROR_FAILURE;
    2788             :   }
    2789             : 
    2790           0 :   nsAutoCString arch;
    2791           0 :   rv = runtime->GetXPCOMABI(arch);
    2792           0 :   if (NS_FAILED(rv)) {
    2793           0 :     return rv;
    2794             :   }
    2795             : 
    2796           0 :   bool flashOnly = Preferences::GetBool("plugin.load_flash_only", true);
    2797             : 
    2798           0 :   PR_fprintf(fd, "Generated File. Do not edit.\n");
    2799             : 
    2800           0 :   PR_fprintf(fd, "\n[HEADER]\nVersion%c%s%c%c%c\nArch%c%s%c%c\n",
    2801             :              PLUGIN_REGISTRY_FIELD_DELIMITER,
    2802             :              kPluginRegistryVersion,
    2803             :              flashOnly ? 't' : 'f',
    2804             :              PLUGIN_REGISTRY_FIELD_DELIMITER,
    2805             :              PLUGIN_REGISTRY_END_OF_LINE_MARKER,
    2806             :              PLUGIN_REGISTRY_FIELD_DELIMITER,
    2807             :              arch.get(),
    2808             :              PLUGIN_REGISTRY_FIELD_DELIMITER,
    2809           0 :              PLUGIN_REGISTRY_END_OF_LINE_MARKER);
    2810             : 
    2811             :   // Store all plugins in the mPlugins list - all plugins currently in use.
    2812           0 :   PR_fprintf(fd, "\n[PLUGINS]\n");
    2813             : 
    2814           0 :   for (nsPluginTag *tag = mPlugins; tag; tag = tag->mNext) {
    2815             :     // store each plugin info into the registry
    2816             :     // filename & fullpath are on separate line
    2817             :     // because they can contain field delimiter char
    2818           0 :     PR_fprintf(fd, "%s%c%c\n%s%c%c\n%s%c%c\n",
    2819           0 :       (tag->FileName().get()),
    2820             :       PLUGIN_REGISTRY_FIELD_DELIMITER,
    2821             :       PLUGIN_REGISTRY_END_OF_LINE_MARKER,
    2822             :       (tag->mFullPath.get()),
    2823             :       PLUGIN_REGISTRY_FIELD_DELIMITER,
    2824             :       PLUGIN_REGISTRY_END_OF_LINE_MARKER,
    2825           0 :       (tag->Version().get()),
    2826             :       PLUGIN_REGISTRY_FIELD_DELIMITER,
    2827           0 :       PLUGIN_REGISTRY_END_OF_LINE_MARKER);
    2828             : 
    2829             :     // lastModifiedTimeStamp|canUnload|tag->mFlags|fromExtension
    2830           0 :     PR_fprintf(fd, "%lld%c%d%c%lu%c%d%c%c\n",
    2831             :       tag->mLastModifiedTime,
    2832             :       PLUGIN_REGISTRY_FIELD_DELIMITER,
    2833             :       false, // did store whether or not to unload in-process plugins
    2834             :       PLUGIN_REGISTRY_FIELD_DELIMITER,
    2835             :       0, // legacy field for flags
    2836             :       PLUGIN_REGISTRY_FIELD_DELIMITER,
    2837           0 :       tag->IsFromExtension(),
    2838             :       PLUGIN_REGISTRY_FIELD_DELIMITER,
    2839           0 :       PLUGIN_REGISTRY_END_OF_LINE_MARKER);
    2840             : 
    2841             :     //description, name & mtypecount are on separate line
    2842           0 :     PR_fprintf(fd, "%s%c%c\n%s%c%c\n%d\n",
    2843           0 :       (tag->Description().get()),
    2844             :       PLUGIN_REGISTRY_FIELD_DELIMITER,
    2845             :       PLUGIN_REGISTRY_END_OF_LINE_MARKER,
    2846           0 :       (tag->Name().get()),
    2847             :       PLUGIN_REGISTRY_FIELD_DELIMITER,
    2848             :       PLUGIN_REGISTRY_END_OF_LINE_MARKER,
    2849           0 :       tag->MimeTypes().Length());
    2850             : 
    2851             :     // Add in each mimetype this plugin supports
    2852           0 :     for (uint32_t i = 0; i < tag->MimeTypes().Length(); i++) {
    2853           0 :       PR_fprintf(fd, "%d%c%s%c%s%c%s%c%c\n",
    2854             :         i,PLUGIN_REGISTRY_FIELD_DELIMITER,
    2855           0 :         (tag->MimeTypes()[i].get()),
    2856             :         PLUGIN_REGISTRY_FIELD_DELIMITER,
    2857           0 :         (tag->MimeDescriptions()[i].get()),
    2858             :         PLUGIN_REGISTRY_FIELD_DELIMITER,
    2859           0 :         (tag->Extensions()[i].get()),
    2860             :         PLUGIN_REGISTRY_FIELD_DELIMITER,
    2861           0 :         PLUGIN_REGISTRY_END_OF_LINE_MARKER);
    2862             :     }
    2863             :   }
    2864             : 
    2865           0 :   PR_fprintf(fd, "\n[INVALID]\n");
    2866             : 
    2867           0 :   RefPtr<nsInvalidPluginTag> invalidPlugins = mInvalidPlugins;
    2868           0 :   while (invalidPlugins) {
    2869             :     // fullPath
    2870           0 :     PR_fprintf(fd, "%s%c%c\n",
    2871           0 :       (!invalidPlugins->mFullPath.IsEmpty() ? invalidPlugins->mFullPath.get() : ""),
    2872             :       PLUGIN_REGISTRY_FIELD_DELIMITER,
    2873           0 :       PLUGIN_REGISTRY_END_OF_LINE_MARKER);
    2874             : 
    2875             :     // lastModifiedTimeStamp
    2876           0 :     PR_fprintf(fd, "%lld%c%c\n",
    2877           0 :       invalidPlugins->mLastModifiedTime,
    2878             :       PLUGIN_REGISTRY_FIELD_DELIMITER,
    2879           0 :       PLUGIN_REGISTRY_END_OF_LINE_MARKER);
    2880             : 
    2881           0 :     invalidPlugins = invalidPlugins->mNext;
    2882             :   }
    2883             : 
    2884             :   PRStatus prrc;
    2885           0 :   prrc = PR_Close(fd);
    2886           0 :   if (prrc != PR_SUCCESS) {
    2887             :     // we should obtain a refined value based on prrc;
    2888           0 :     rv = NS_ERROR_FAILURE;
    2889           0 :     MOZ_ASSERT(false, "PR_Close() failed.");
    2890             :     return rv;
    2891             :   }
    2892           0 :   nsCOMPtr<nsIFile> parent;
    2893           0 :   rv = pluginReg->GetParent(getter_AddRefs(parent));
    2894           0 :   NS_ENSURE_SUCCESS(rv, rv);
    2895           0 :   rv = pluginReg->MoveToNative(parent, kPluginRegistryFilename);
    2896           0 :   return rv;
    2897             : }
    2898             : 
    2899             : nsresult
    2900           1 : nsPluginHost::ReadPluginInfo()
    2901             : {
    2902           1 :   MOZ_ASSERT(XRE_IsParentProcess());
    2903             : 
    2904           1 :   const long PLUGIN_REG_MIMETYPES_ARRAY_SIZE = 12;
    2905           1 :   const long PLUGIN_REG_MAX_MIMETYPES = 1000;
    2906             : 
    2907             :   nsresult rv;
    2908             : 
    2909           2 :   nsCOMPtr<nsIProperties> directoryService(do_GetService(NS_DIRECTORY_SERVICE_CONTRACTID,&rv));
    2910           1 :   if (NS_FAILED(rv))
    2911           0 :     return rv;
    2912             : 
    2913           2 :   directoryService->Get(NS_APP_USER_PROFILE_50_DIR, NS_GET_IID(nsIFile),
    2914           2 :                         getter_AddRefs(mPluginRegFile));
    2915             : 
    2916           1 :   if (!mPluginRegFile) {
    2917             :     // There is no profile yet, this will tell us if there is going to be one
    2918             :     // in the future.
    2919           0 :     directoryService->Get(NS_APP_PROFILE_DIR_STARTUP, NS_GET_IID(nsIFile),
    2920           0 :                           getter_AddRefs(mPluginRegFile));
    2921           0 :     if (!mPluginRegFile)
    2922           0 :       return NS_ERROR_FAILURE;
    2923             : 
    2924           0 :     return NS_ERROR_NOT_AVAILABLE;
    2925             :   }
    2926             : 
    2927           1 :   PRFileDesc* fd = nullptr;
    2928             : 
    2929           2 :   nsCOMPtr<nsIFile> pluginReg;
    2930             : 
    2931           1 :   rv = mPluginRegFile->Clone(getter_AddRefs(pluginReg));
    2932           1 :   if (NS_FAILED(rv))
    2933           0 :     return rv;
    2934             : 
    2935           1 :   rv = pluginReg->AppendNative(kPluginRegistryFilename);
    2936           1 :   if (NS_FAILED(rv))
    2937           0 :     return rv;
    2938             : 
    2939             :   int64_t fileSize;
    2940           1 :   rv = pluginReg->GetFileSize(&fileSize);
    2941           1 :   if (NS_FAILED(rv))
    2942           1 :     return rv;
    2943             : 
    2944           0 :   if (fileSize > INT32_MAX) {
    2945           0 :     return NS_ERROR_FAILURE;
    2946             :   }
    2947           0 :   int32_t flen = int32_t(fileSize);
    2948           0 :   if (flen == 0) {
    2949           0 :     NS_WARNING("Plugins Registry Empty!");
    2950           0 :     return NS_OK; // ERROR CONDITION
    2951             :   }
    2952             : 
    2953           0 :   nsPluginManifestLineReader reader;
    2954           0 :   char* registry = reader.Init(flen);
    2955           0 :   if (!registry)
    2956           0 :     return NS_ERROR_OUT_OF_MEMORY;
    2957             : 
    2958           0 :   rv = pluginReg->OpenNSPRFileDesc(PR_RDONLY, 0444, &fd);
    2959           0 :   if (NS_FAILED(rv))
    2960           0 :     return rv;
    2961             : 
    2962             :   // set rv to return an error on goto out
    2963           0 :   rv = NS_ERROR_FAILURE;
    2964             : 
    2965             :   // We know how many octes we are supposed to read.
    2966             :   // So let use the busy_beaver_PR_Read version.
    2967           0 :   int32_t bread = busy_beaver_PR_Read(fd, registry, flen);
    2968             : 
    2969             :   PRStatus prrc;
    2970           0 :   prrc = PR_Close(fd);
    2971           0 :   if (prrc != PR_SUCCESS) {
    2972             :     // Strange error: this is one of those "Should not happen" error.
    2973             :     // we may want to report something more refined than  NS_ERROR_FAILURE.
    2974           0 :     MOZ_ASSERT(false, "PR_Close() failed.");
    2975             :     return rv;
    2976             :   }
    2977             : 
    2978             :   // short read error, so to speak.
    2979           0 :   if (flen > bread)
    2980           0 :     return rv;
    2981             : 
    2982           0 :   if (!ReadSectionHeader(reader, "HEADER"))
    2983           0 :     return rv;;
    2984             : 
    2985           0 :   if (!reader.NextLine())
    2986           0 :     return rv;
    2987             : 
    2988             :   char* values[6];
    2989             : 
    2990             :   // VersionLiteral, kPluginRegistryVersion
    2991           0 :   if (2 != reader.ParseLine(values, 2))
    2992           0 :     return rv;
    2993             : 
    2994             :   // VersionLiteral
    2995           0 :   if (PL_strcmp(values[0], "Version"))
    2996           0 :     return rv;
    2997             : 
    2998             :   // If we're reading an old registry, ignore it
    2999             :   // If we flipped the flash-only pref, ignore it
    3000           0 :   bool flashOnly = Preferences::GetBool("plugin.load_flash_only", true);
    3001           0 :   nsAutoCString expectedVersion(kPluginRegistryVersion);
    3002           0 :   expectedVersion.Append(flashOnly ? 't' : 'f');
    3003             : 
    3004           0 :   if (!expectedVersion.Equals(values[1])) {
    3005           0 :     return rv;
    3006             :   }
    3007             : 
    3008             :   char* archValues[6];
    3009           0 :   if (!reader.NextLine()) {
    3010           0 :     return rv;
    3011             :   }
    3012             : 
    3013             :   // ArchLiteral, Architecture
    3014           0 :   if (2 != reader.ParseLine(archValues, 2)) {
    3015           0 :     return rv;
    3016             :   }
    3017             : 
    3018             :   // ArchLiteral
    3019           0 :   if (PL_strcmp(archValues[0], "Arch")) {
    3020           0 :     return rv;
    3021             :   }
    3022             : 
    3023           0 :   nsCOMPtr<nsIXULRuntime> runtime = do_GetService("@mozilla.org/xre/runtime;1");
    3024           0 :   if (!runtime) {
    3025           0 :     return rv;
    3026             :   }
    3027             : 
    3028           0 :   nsAutoCString arch;
    3029           0 :   if (NS_FAILED(runtime->GetXPCOMABI(arch))) {
    3030           0 :     return rv;
    3031             :   }
    3032             : 
    3033             :   // If this is a registry from a different architecture then don't attempt to read it
    3034           0 :   if (PL_strcmp(archValues[1], arch.get())) {
    3035           0 :     return rv;
    3036             :   }
    3037             : 
    3038           0 :   if (!ReadSectionHeader(reader, "PLUGINS"))
    3039           0 :     return rv;
    3040             : 
    3041           0 :   while (reader.NextLine()) {
    3042           0 :     if (*reader.LinePtr() == '[') {
    3043           0 :       break;
    3044             :     }
    3045             : 
    3046           0 :     const char* filename = reader.LinePtr();
    3047           0 :     if (!reader.NextLine())
    3048           0 :       return rv;
    3049             : 
    3050           0 :     const char* fullpath = reader.LinePtr();
    3051           0 :     if (!reader.NextLine())
    3052           0 :       return rv;
    3053             : 
    3054             :     const char *version;
    3055           0 :     version = reader.LinePtr();
    3056           0 :     if (!reader.NextLine())
    3057           0 :       return rv;
    3058             : 
    3059             :     // lastModifiedTimeStamp|canUnload|tag.mFlag|fromExtension
    3060           0 :     if (4 != reader.ParseLine(values, 4))
    3061           0 :       return rv;
    3062             : 
    3063           0 :     int64_t lastmod = nsCRT::atoll(values[0]);
    3064           0 :     bool fromExtension = atoi(values[3]);
    3065           0 :     if (!reader.NextLine())
    3066           0 :       return rv;
    3067             : 
    3068           0 :     char *description = reader.LinePtr();
    3069           0 :     if (!reader.NextLine())
    3070           0 :       return rv;
    3071             : 
    3072             : #if MOZ_WIDGET_ANDROID
    3073             :     // Flash on Android does not populate the version field, but it is tacked on to the description.
    3074             :     // For example, "Shockwave Flash 11.1 r115"
    3075             :     if (PL_strncmp("Shockwave Flash ", description, 16) == 0 && description[16]) {
    3076             :       version = &description[16];
    3077             :     }
    3078             : #endif
    3079             : 
    3080           0 :     const char *name = reader.LinePtr();
    3081           0 :     if (!reader.NextLine())
    3082           0 :       return rv;
    3083             : 
    3084           0 :     long mimetypecount = std::strtol(reader.LinePtr(), nullptr, 10);
    3085           0 :     if (mimetypecount == LONG_MAX || mimetypecount == LONG_MIN ||
    3086           0 :         mimetypecount >= PLUGIN_REG_MAX_MIMETYPES || mimetypecount < 0) {
    3087           0 :       return NS_ERROR_FAILURE;
    3088             :     }
    3089             : 
    3090             :     char *stackalloced[PLUGIN_REG_MIMETYPES_ARRAY_SIZE * 3];
    3091             :     char **mimetypes;
    3092             :     char **mimedescriptions;
    3093             :     char **extensions;
    3094           0 :     char **heapalloced = 0;
    3095           0 :     if (mimetypecount > PLUGIN_REG_MIMETYPES_ARRAY_SIZE - 1) {
    3096           0 :       heapalloced = new char *[mimetypecount * 3];
    3097           0 :       mimetypes = heapalloced;
    3098             :     } else {
    3099           0 :       mimetypes = stackalloced;
    3100             :     }
    3101           0 :     mimedescriptions = mimetypes + mimetypecount;
    3102           0 :     extensions = mimedescriptions + mimetypecount;
    3103             : 
    3104           0 :     int mtr = 0; //mimetype read
    3105           0 :     for (; mtr < mimetypecount; mtr++) {
    3106           0 :       if (!reader.NextLine())
    3107           0 :         break;
    3108             : 
    3109             :       //line number|mimetype|description|extension
    3110           0 :       if (4 != reader.ParseLine(values, 4))
    3111           0 :         break;
    3112           0 :       int line = atoi(values[0]);
    3113           0 :       if (line != mtr)
    3114           0 :         break;
    3115           0 :       mimetypes[mtr] = values[1];
    3116           0 :       mimedescriptions[mtr] = values[2];
    3117           0 :       extensions[mtr] = values[3];
    3118             :     }
    3119             : 
    3120           0 :     if (mtr != mimetypecount) {
    3121           0 :       delete [] heapalloced;
    3122           0 :       return rv;
    3123             :     }
    3124             : 
    3125             :     RefPtr<nsPluginTag> tag = new nsPluginTag(name,
    3126             :       description,
    3127             :       filename,
    3128             :       fullpath,
    3129             :       version,
    3130             :       (const char* const*)mimetypes,
    3131             :       (const char* const*)mimedescriptions,
    3132             :       (const char* const*)extensions,
    3133           0 :       mimetypecount, lastmod, fromExtension, true);
    3134             : 
    3135           0 :     delete [] heapalloced;
    3136             : 
    3137             :     // Import flags from registry into prefs for old registry versions
    3138           0 :     MOZ_LOG(nsPluginLogging::gPluginLog, PLUGIN_LOG_BASIC,
    3139             :       ("LoadCachedPluginsInfo : Loading Cached plugininfo for %s\n", tag->FileName().get()));
    3140             : 
    3141           0 :     tag->mNext = mCachedPlugins;
    3142           0 :     mCachedPlugins = tag;
    3143             :   }
    3144             : 
    3145             : // On Android we always want to try to load a plugin again (Flash). Bug 935676.
    3146             : #ifndef MOZ_WIDGET_ANDROID
    3147           0 :   if (!ReadSectionHeader(reader, "INVALID")) {
    3148           0 :     return rv;
    3149             :   }
    3150             : 
    3151           0 :   while (reader.NextLine()) {
    3152           0 :     const char *fullpath = reader.LinePtr();
    3153           0 :     if (!reader.NextLine()) {
    3154           0 :       return rv;
    3155             :     }
    3156             : 
    3157           0 :     const char *lastModifiedTimeStamp = reader.LinePtr();
    3158           0 :     int64_t lastmod = nsCRT::atoll(lastModifiedTimeStamp);
    3159             : 
    3160           0 :     RefPtr<nsInvalidPluginTag> invalidTag = new nsInvalidPluginTag(fullpath, lastmod);
    3161             : 
    3162           0 :     invalidTag->mNext = mInvalidPlugins;
    3163           0 :     if (mInvalidPlugins) {
    3164           0 :       mInvalidPlugins->mPrev = invalidTag;
    3165             :     }
    3166           0 :     mInvalidPlugins = invalidTag;
    3167             :   }
    3168             : #endif
    3169             : 
    3170           0 :   return NS_OK;
    3171             : }
    3172             : 
    3173             : void
    3174           0 : nsPluginHost::RemoveCachedPluginsInfo(const char *filePath, nsPluginTag **result)
    3175             : {
    3176           0 :   RefPtr<nsPluginTag> prev;
    3177           0 :   RefPtr<nsPluginTag> tag = mCachedPlugins;
    3178           0 :   while (tag)
    3179             :   {
    3180           0 :     if (tag->mFullPath.Equals(filePath)) {
    3181             :       // Found it. Remove it from our list
    3182           0 :       if (prev)
    3183           0 :         prev->mNext = tag->mNext;
    3184             :       else
    3185           0 :         mCachedPlugins = tag->mNext;
    3186           0 :       tag->mNext = nullptr;
    3187           0 :       *result = tag;
    3188           0 :       NS_ADDREF(*result);
    3189           0 :       break;
    3190             :     }
    3191           0 :     prev = tag;
    3192           0 :     tag = tag->mNext;
    3193             :   }
    3194           0 : }
    3195             : 
    3196             : #ifdef XP_WIN
    3197             : nsresult
    3198             : nsPluginHost::EnsurePrivateDirServiceProvider()
    3199             : {
    3200             :   if (!mPrivateDirServiceProvider) {
    3201             :     nsresult rv;
    3202             :     mPrivateDirServiceProvider = new nsPluginDirServiceProvider();
    3203             :     nsCOMPtr<nsIDirectoryService> dirService(do_GetService(kDirectoryServiceContractID, &rv));
    3204             :     if (NS_FAILED(rv))
    3205             :       return rv;
    3206             :     rv = dirService->RegisterProvider(mPrivateDirServiceProvider);
    3207             :     if (NS_FAILED(rv))
    3208             :       return rv;
    3209             :   }
    3210             :   return NS_OK;
    3211             : }
    3212             : #endif /* XP_WIN */
    3213             : 
    3214           0 : nsresult nsPluginHost::NewPluginURLStream(const nsString& aURL,
    3215             :                                           nsNPAPIPluginInstance *aInstance,
    3216             :                                           nsNPAPIPluginStreamListener* aListener,
    3217             :                                           nsIInputStream *aPostStream,
    3218             :                                           const char *aHeadersData,
    3219             :                                           uint32_t aHeadersDataLen)
    3220             : {
    3221           0 :   nsCOMPtr<nsIURI> url;
    3222           0 :   nsAutoString absUrl;
    3223             :   nsresult rv;
    3224             : 
    3225           0 :   if (aURL.Length() <= 0)
    3226           0 :     return NS_OK;
    3227             : 
    3228             :   // get the base URI for the plugin to create an absolute url
    3229             :   // in case aURL is relative
    3230           0 :   RefPtr<nsPluginInstanceOwner> owner = aInstance->GetOwner();
    3231           0 :   if (owner) {
    3232           0 :     nsCOMPtr<nsIURI> baseURI = owner->GetBaseURI();
    3233           0 :     rv = NS_MakeAbsoluteURI(absUrl, aURL, baseURI);
    3234             :   }
    3235             : 
    3236           0 :   if (absUrl.IsEmpty())
    3237           0 :     absUrl.Assign(aURL);
    3238             : 
    3239           0 :   rv = NS_NewURI(getter_AddRefs(url), absUrl);
    3240           0 :   NS_ENSURE_SUCCESS(rv, rv);
    3241             : 
    3242           0 :   RefPtr<nsPluginStreamListenerPeer> listenerPeer = new nsPluginStreamListenerPeer();
    3243           0 :   NS_ENSURE_TRUE(listenerPeer, NS_ERROR_OUT_OF_MEMORY);
    3244             : 
    3245           0 :   rv = listenerPeer->Initialize(url, aInstance, aListener);
    3246           0 :   NS_ENSURE_SUCCESS(rv, rv);
    3247             : 
    3248           0 :   nsCOMPtr<nsIDOMElement> element;
    3249           0 :   nsCOMPtr<nsIDocument> doc;
    3250           0 :   if (owner) {
    3251           0 :     owner->GetDOMElement(getter_AddRefs(element));
    3252           0 :     owner->GetDocument(getter_AddRefs(doc));
    3253             :   }
    3254             : 
    3255           0 :   nsCOMPtr<nsINode> requestingNode(do_QueryInterface(element));
    3256           0 :   NS_ENSURE_TRUE(requestingNode, NS_ERROR_FAILURE);
    3257             : 
    3258           0 :   nsCOMPtr<nsIChannel> channel;
    3259             :   // @arg loadgroup:
    3260             :   // do not add this internal plugin's channel on the
    3261             :   // load group otherwise this channel could be canceled
    3262             :   // form |nsDocShell::OnLinkClickSync| bug 166613
    3263           0 :   rv = NS_NewChannel(getter_AddRefs(channel),
    3264             :                      url,
    3265             :                      requestingNode,
    3266             :                      nsILoadInfo::SEC_ALLOW_CROSS_ORIGIN_DATA_INHERITS |
    3267             :                      nsILoadInfo::SEC_FORCE_INHERIT_PRINCIPAL,
    3268             :                      nsIContentPolicy::TYPE_OBJECT_SUBREQUEST,
    3269             :                      nullptr,  // aLoadGroup
    3270             :                      listenerPeer,
    3271             :                      nsIRequest::LOAD_NORMAL | nsIChannel::LOAD_CLASSIFY_URI |
    3272           0 :                      nsIChannel::LOAD_BYPASS_SERVICE_WORKER);
    3273           0 :   NS_ENSURE_SUCCESS(rv, rv);
    3274             : 
    3275           0 :   if (doc) {
    3276             :     // And if it's a script allow it to execute against the
    3277             :     // document's script context.
    3278           0 :     nsCOMPtr<nsIScriptChannel> scriptChannel(do_QueryInterface(channel));
    3279           0 :     if (scriptChannel) {
    3280           0 :       scriptChannel->SetExecutionPolicy(nsIScriptChannel::EXECUTE_NORMAL);
    3281             :       // Plug-ins seem to depend on javascript: URIs running synchronously
    3282           0 :       scriptChannel->SetExecuteAsync(false);
    3283             :     }
    3284             :   }
    3285             : 
    3286             :   // deal with headers and post data
    3287           0 :   nsCOMPtr<nsIHttpChannel> httpChannel(do_QueryInterface(channel));
    3288           0 :   if (httpChannel) {
    3289           0 :     if (!aPostStream) {
    3290             :       // Only set the Referer header for GET requests because IIS throws
    3291             :       // errors about malformed requests if we include it in POSTs. See
    3292             :       // bug 724465.
    3293           0 :       nsCOMPtr<nsIURI> referer;
    3294           0 :       net::ReferrerPolicy referrerPolicy = net::RP_Unset;
    3295             : 
    3296           0 :       nsCOMPtr<nsIObjectLoadingContent> olc = do_QueryInterface(element);
    3297           0 :       if (olc)
    3298           0 :         olc->GetSrcURI(getter_AddRefs(referer));
    3299             : 
    3300             : 
    3301           0 :       if (!referer) {
    3302           0 :         if (!doc) {
    3303           0 :           return NS_ERROR_FAILURE;
    3304             :         }
    3305           0 :         referer = doc->GetDocumentURI();
    3306           0 :         referrerPolicy = doc->GetReferrerPolicy();
    3307             :       }
    3308             : 
    3309           0 :       rv = httpChannel->SetReferrerWithPolicy(referer, referrerPolicy);
    3310           0 :       NS_ENSURE_SUCCESS(rv,rv);
    3311             :     }
    3312             : 
    3313           0 :     if (aPostStream) {
    3314             :       // XXX it's a bit of a hack to rewind the postdata stream
    3315             :       // here but it has to be done in case the post data is
    3316             :       // being reused multiple times.
    3317             :       nsCOMPtr<nsISeekableStream>
    3318           0 :       postDataSeekable(do_QueryInterface(aPostStream));
    3319           0 :       if (postDataSeekable)
    3320           0 :         postDataSeekable->Seek(nsISeekableStream::NS_SEEK_SET, 0);
    3321             : 
    3322           0 :       nsCOMPtr<nsIUploadChannel> uploadChannel(do_QueryInterface(httpChannel));
    3323           0 :       NS_ASSERTION(uploadChannel, "http must support nsIUploadChannel");
    3324             : 
    3325           0 :       uploadChannel->SetUploadStream(aPostStream, EmptyCString(), -1);
    3326             :     }
    3327             : 
    3328           0 :     if (aHeadersData) {
    3329           0 :       rv = AddHeadersToChannel(aHeadersData, aHeadersDataLen, httpChannel);
    3330           0 :       NS_ENSURE_SUCCESS(rv,rv);
    3331             :     }
    3332             :   }
    3333           0 :   rv = channel->AsyncOpen2(listenerPeer);
    3334           0 :   if (NS_SUCCEEDED(rv))
    3335           0 :     listenerPeer->TrackRequest(channel);
    3336           0 :   return rv;
    3337             : }
    3338             : 
    3339             : nsresult
    3340           0 : nsPluginHost::AddHeadersToChannel(const char *aHeadersData,
    3341             :                                   uint32_t aHeadersDataLen,
    3342             :                                   nsIChannel *aGenericChannel)
    3343             : {
    3344           0 :   nsresult rv = NS_OK;
    3345             : 
    3346           0 :   nsCOMPtr<nsIHttpChannel> aChannel = do_QueryInterface(aGenericChannel);
    3347           0 :   if (!aChannel) {
    3348           0 :     return NS_ERROR_NULL_POINTER;
    3349             :   }
    3350             : 
    3351             :   // used during the manipulation of the String from the aHeadersData
    3352           0 :   nsAutoCString headersString;
    3353           0 :   nsAutoCString oneHeader;
    3354           0 :   nsAutoCString headerName;
    3355           0 :   nsAutoCString headerValue;
    3356           0 :   int32_t crlf = 0;
    3357           0 :   int32_t colon = 0;
    3358             : 
    3359             :   // Turn the char * buffer into an nsString.
    3360           0 :   headersString = aHeadersData;
    3361             : 
    3362             :   // Iterate over the nsString: for each "\r\n" delimited chunk,
    3363             :   // add the value as a header to the nsIHTTPChannel
    3364             :   while (true) {
    3365           0 :     crlf = headersString.Find("\r\n", true);
    3366           0 :     if (-1 == crlf) {
    3367           0 :       rv = NS_OK;
    3368           0 :       return rv;
    3369             :     }
    3370           0 :     headersString.Mid(oneHeader, 0, crlf);
    3371           0 :     headersString.Cut(0, crlf + 2);
    3372           0 :     oneHeader.StripWhitespace();
    3373           0 :     colon = oneHeader.Find(":");
    3374           0 :     if (-1 == colon) {
    3375           0 :       rv = NS_ERROR_NULL_POINTER;
    3376           0 :       return rv;
    3377             :     }
    3378           0 :     oneHeader.Left(headerName, colon);
    3379           0 :     colon++;
    3380           0 :     oneHeader.Mid(headerValue, colon, oneHeader.Length() - colon);
    3381             : 
    3382             :     // FINALLY: we can set the header!
    3383             : 
    3384           0 :     rv = aChannel->SetRequestHeader(headerName, headerValue, true);
    3385           0 :     if (NS_FAILED(rv)) {
    3386           0 :       rv = NS_ERROR_NULL_POINTER;
    3387           0 :       return rv;
    3388             :     }
    3389             :   }
    3390             : }
    3391             : 
    3392             : nsresult
    3393           0 : nsPluginHost::StopPluginInstance(nsNPAPIPluginInstance* aInstance)
    3394             : {
    3395           0 :   AUTO_PROFILER_LABEL("nsPluginHost::StopPluginInstance", OTHER);
    3396           0 :   if (PluginDestructionGuard::DelayDestroy(aInstance)) {
    3397           0 :     return NS_OK;
    3398             :   }
    3399             : 
    3400           0 :   PLUGIN_LOG(PLUGIN_LOG_NORMAL,
    3401             :   ("nsPluginHost::StopPluginInstance called instance=%p\n",aInstance));
    3402             : 
    3403           0 :   if (aInstance->HasStartedDestroying()) {
    3404           0 :     return NS_OK;
    3405             :   }
    3406             : 
    3407           0 :   Telemetry::AutoTimer<Telemetry::PLUGIN_SHUTDOWN_MS> timer;
    3408           0 :   aInstance->Stop();
    3409             : 
    3410             :   // if the instance does not want to be 'cached' just remove it
    3411           0 :   bool doCache = aInstance->ShouldCache();
    3412           0 :   if (doCache) {
    3413             :     // try to get the max cached instances from a pref or use default
    3414             :     uint32_t cachedInstanceLimit =
    3415             :       Preferences::GetUint(NS_PREF_MAX_NUM_CACHED_INSTANCES,
    3416           0 :                            DEFAULT_NUMBER_OF_STOPPED_INSTANCES);
    3417           0 :     if (StoppedInstanceCount() >= cachedInstanceLimit) {
    3418           0 :       nsNPAPIPluginInstance *oldestInstance = FindOldestStoppedInstance();
    3419           0 :       if (oldestInstance) {
    3420           0 :         nsPluginTag* pluginTag = TagForPlugin(oldestInstance->GetPlugin());
    3421           0 :         oldestInstance->Destroy();
    3422           0 :         mInstances.RemoveElement(oldestInstance);
    3423             :         // TODO: Remove this check once bug 752422 was investigated
    3424           0 :         if (pluginTag) {
    3425           0 :           OnPluginInstanceDestroyed(pluginTag);
    3426             :         }
    3427             :       }
    3428             :     }
    3429             :   } else {
    3430           0 :     nsPluginTag* pluginTag = TagForPlugin(aInstance->GetPlugin());
    3431           0 :     aInstance->Destroy();
    3432           0 :     mInstances.RemoveElement(aInstance);
    3433             :     // TODO: Remove this check once bug 752422 was investigated
    3434           0 :     if (pluginTag) {
    3435           0 :       OnPluginInstanceDestroyed(pluginTag);
    3436             :     }
    3437             :   }
    3438             : 
    3439           0 :   return NS_OK;
    3440             : }
    3441             : 
    3442           0 : nsresult nsPluginHost::NewPluginStreamListener(nsIURI* aURI,
    3443             :                                                nsNPAPIPluginInstance* aInstance,
    3444             :                                                nsIStreamListener **aStreamListener)
    3445             : {
    3446           0 :   NS_ENSURE_ARG_POINTER(aURI);
    3447           0 :   NS_ENSURE_ARG_POINTER(aStreamListener);
    3448             : 
    3449           0 :   RefPtr<nsPluginStreamListenerPeer> listener = new nsPluginStreamListenerPeer();
    3450           0 :   nsresult rv = listener->Initialize(aURI, aInstance, nullptr);
    3451           0 :   if (NS_FAILED(rv)) {
    3452           0 :     return rv;
    3453             :   }
    3454             : 
    3455           0 :   listener.forget(aStreamListener);
    3456             : 
    3457           0 :   return NS_OK;
    3458             : }
    3459             : 
    3460           0 : void nsPluginHost::CreateWidget(nsPluginInstanceOwner* aOwner)
    3461             : {
    3462           0 :   aOwner->CreateWidget();
    3463             : 
    3464             :   // If we've got a native window, the let the plugin know about it.
    3465           0 :   aOwner->CallSetWindow();
    3466           0 : }
    3467             : 
    3468           0 : NS_IMETHODIMP nsPluginHost::Observe(nsISupports *aSubject,
    3469             :                                     const char *aTopic,
    3470             :                                     const char16_t *someData)
    3471             : {
    3472           0 :   if (!strcmp(NS_XPCOM_SHUTDOWN_OBSERVER_ID, aTopic)) {
    3473           0 :     OnShutdown();
    3474           0 :     UnloadPlugins();
    3475           0 :     sInst->Release();
    3476             :   }
    3477           0 :   if (!strcmp(NS_PREFBRANCH_PREFCHANGE_TOPIC_ID, aTopic)) {
    3478           0 :     mPluginsDisabled = Preferences::GetBool("plugin.disable", false);
    3479             :     // Unload or load plugins as needed
    3480           0 :     if (mPluginsDisabled) {
    3481           0 :       UnloadPlugins();
    3482             :     } else {
    3483           0 :       LoadPlugins();
    3484             :     }
    3485             :   }
    3486           0 :   if (!strcmp("blocklist-updated", aTopic)) {
    3487           0 :     nsPluginTag* plugin = mPlugins;
    3488           0 :     while (plugin) {
    3489           0 :       plugin->InvalidateBlocklistState();
    3490           0 :       plugin = plugin->mNext;
    3491             :     }
    3492             :   }
    3493             : #ifdef MOZ_WIDGET_ANDROID
    3494             :   if (!strcmp("application-background", aTopic)) {
    3495             :     for(uint32_t i = 0; i < mInstances.Length(); i++) {
    3496             :       mInstances[i]->NotifyForeground(false);
    3497             :     }
    3498             :   }
    3499             :   if (!strcmp("application-foreground", aTopic)) {
    3500             :     for(uint32_t i = 0; i < mInstances.Length(); i++) {
    3501             :       if (mInstances[i]->IsOnScreen())
    3502             :         mInstances[i]->NotifyForeground(true);
    3503             :     }
    3504             :   }
    3505             :   if (!strcmp("memory-pressure", aTopic)) {
    3506             :     for(uint32_t i = 0; i < mInstances.Length(); i++) {
    3507             :       mInstances[i]->MemoryPressure();
    3508             :     }
    3509             :   }
    3510             : #endif
    3511           0 :   return NS_OK;
    3512             : }
    3513             : 
    3514             : nsresult
    3515           0 : nsPluginHost::ParsePostBufferToFixHeaders(const char *inPostData, uint32_t inPostDataLen,
    3516             :                                           char **outPostData, uint32_t *outPostDataLen)
    3517             : {
    3518           0 :   if (!inPostData || !outPostData || !outPostDataLen)
    3519           0 :     return NS_ERROR_NULL_POINTER;
    3520             : 
    3521           0 :   *outPostData = 0;
    3522           0 :   *outPostDataLen = 0;
    3523             : 
    3524           0 :   const char CR = '\r';
    3525           0 :   const char LF = '\n';
    3526           0 :   const char CRLFCRLF[] = {CR,LF,CR,LF,'\0'}; // C string"\r\n\r\n"
    3527           0 :   const char ContentLenHeader[] = "Content-length";
    3528             : 
    3529           0 :   AutoTArray<const char*, 8> singleLF;
    3530           0 :   const char *pSCntlh = 0;// pointer to start of ContentLenHeader in inPostData
    3531           0 :   const char *pSod = 0;   // pointer to start of data in inPostData
    3532           0 :   const char *pEoh = 0;   // pointer to end of headers in inPostData
    3533           0 :   const char *pEod = inPostData + inPostDataLen; // pointer to end of inPostData
    3534           0 :   if (*inPostData == LF) {
    3535             :     // If no custom headers are required, simply add a blank
    3536             :     // line ('\n') to the beginning of the file or buffer.
    3537             :     // so *inPostData == '\n' is valid
    3538           0 :     pSod = inPostData + 1;
    3539             :   } else {
    3540           0 :     const char *s = inPostData; //tmp pointer to sourse inPostData
    3541           0 :     while (s < pEod) {
    3542           0 :       if (!pSCntlh &&
    3543           0 :           (*s == 'C' || *s == 'c') &&
    3544           0 :           (s + sizeof(ContentLenHeader) - 1 < pEod) &&
    3545           0 :           (!PL_strncasecmp(s, ContentLenHeader, sizeof(ContentLenHeader) - 1)))
    3546             :       {
    3547             :         // lets assume this is ContentLenHeader for now
    3548           0 :         const char *p = pSCntlh = s;
    3549           0 :         p += sizeof(ContentLenHeader) - 1;
    3550             :         // search for first CR or LF == end of ContentLenHeader
    3551           0 :         for (; p < pEod; p++) {
    3552           0 :           if (*p == CR || *p == LF) {
    3553             :             // got delimiter,
    3554             :             // one more check; if previous char is a digit
    3555             :             // most likely pSCntlh points to the start of ContentLenHeader
    3556           0 :             if (*(p-1) >= '0' && *(p-1) <= '9') {
    3557           0 :               s = p;
    3558             :             }
    3559           0 :             break; //for loop
    3560             :           }
    3561             :         }
    3562           0 :         if (pSCntlh == s) { // curret ptr is the same
    3563           0 :           pSCntlh = 0; // that was not ContentLenHeader
    3564           0 :           break; // there is nothing to parse, break *WHILE LOOP* here
    3565             :         }
    3566             :       }
    3567             : 
    3568           0 :       if (*s == CR) {
    3569           0 :         if (pSCntlh && // only if ContentLenHeader is found we are looking for end of headers
    3570           0 :             ((s + sizeof(CRLFCRLF)-1) <= pEod) &&
    3571           0 :             !memcmp(s, CRLFCRLF, sizeof(CRLFCRLF)-1))
    3572             :         {
    3573           0 :           s += sizeof(CRLFCRLF)-1;
    3574           0 :           pEoh = pSod = s; // data stars here
    3575           0 :           break;
    3576             :         }
    3577           0 :       } else if (*s == LF) {
    3578           0 :         if (*(s-1) != CR) {
    3579           0 :           singleLF.AppendElement(s);
    3580             :         }
    3581           0 :         if (pSCntlh && (s+1 < pEod) && (*(s+1) == LF)) {
    3582           0 :           s++;
    3583           0 :           singleLF.AppendElement(s);
    3584           0 :           s++;
    3585           0 :           pEoh = pSod = s; // data stars here
    3586           0 :           break;
    3587             :         }
    3588             :       }
    3589           0 :       s++;
    3590             :     }
    3591             :   }
    3592             : 
    3593             :   // deal with output buffer
    3594           0 :   if (!pSod) { // lets assume whole buffer is a data
    3595           0 :     pSod = inPostData;
    3596             :   }
    3597             : 
    3598           0 :   uint32_t newBufferLen = 0;
    3599           0 :   uint32_t dataLen = pEod - pSod;
    3600           0 :   uint32_t headersLen = pEoh ? pSod - inPostData : 0;
    3601             : 
    3602             :   char *p; // tmp ptr into new output buf
    3603           0 :   if (headersLen) { // we got a headers
    3604             :     // this function does not make any assumption on correctness
    3605             :     // of ContentLenHeader value in this case.
    3606             : 
    3607           0 :     newBufferLen = dataLen + headersLen;
    3608             :     // in case there were single LFs in headers
    3609             :     // reserve an extra space for CR will be added before each single LF
    3610           0 :     int cntSingleLF = singleLF.Length();
    3611           0 :     newBufferLen += cntSingleLF;
    3612             : 
    3613           0 :     if (!(*outPostData = p = (char*)moz_xmalloc(newBufferLen)))
    3614           0 :       return NS_ERROR_OUT_OF_MEMORY;
    3615             : 
    3616             :     // deal with single LF
    3617           0 :     const char *s = inPostData;
    3618           0 :     if (cntSingleLF) {
    3619           0 :       for (int i=0; i<cntSingleLF; i++) {
    3620           0 :         const char *plf = singleLF.ElementAt(i); // ptr to single LF in headers
    3621           0 :         int n = plf - s; // bytes to copy
    3622           0 :         if (n) { // for '\n\n' there is nothing to memcpy
    3623           0 :           memcpy(p, s, n);
    3624           0 :           p += n;
    3625             :         }
    3626           0 :         *p++ = CR;
    3627           0 :         s = plf;
    3628           0 :         *p++ = *s++;
    3629             :       }
    3630             :     }
    3631             :     // are we done with headers?
    3632           0 :     headersLen = pEoh - s;
    3633           0 :     if (headersLen) { // not yet
    3634           0 :       memcpy(p, s, headersLen); // copy the rest
    3635           0 :       p += headersLen;
    3636             :     }
    3637           0 :   } else  if (dataLen) { // no ContentLenHeader is found but there is a data
    3638             :     // make new output buffer big enough
    3639             :     // to keep ContentLenHeader+value followed by data
    3640           0 :     uint32_t l = sizeof(ContentLenHeader) + sizeof(CRLFCRLF) + 32;
    3641           0 :     newBufferLen = dataLen + l;
    3642           0 :     if (!(*outPostData = p = (char*)moz_xmalloc(newBufferLen)))
    3643           0 :       return NS_ERROR_OUT_OF_MEMORY;
    3644           0 :     headersLen = snprintf(p, l,"%s: %u%s", ContentLenHeader, dataLen, CRLFCRLF);
    3645           0 :     if (headersLen == l) { // if snprintf has ate all extra space consider this as an error
    3646           0 :       free(p);
    3647           0 :       *outPostData = 0;
    3648           0 :       return NS_ERROR_FAILURE;
    3649             :     }
    3650           0 :     p += headersLen;
    3651           0 :     newBufferLen = headersLen + dataLen;
    3652             :   }
    3653             :   // at this point we've done with headers.
    3654             :   // there is a possibility that input buffer has only headers info in it
    3655             :   // which already parsed and copied into output buffer.
    3656             :   // copy the data
    3657           0 :   if (dataLen) {
    3658           0 :     memcpy(p, pSod, dataLen);
    3659             :   }
    3660             : 
    3661           0 :   *outPostDataLen = newBufferLen;
    3662             : 
    3663           0 :   return NS_OK;
    3664             : }
    3665             : 
    3666             : nsresult
    3667           0 : nsPluginHost::NewPluginNativeWindow(nsPluginNativeWindow ** aPluginNativeWindow)
    3668             : {
    3669           0 :   return PLUG_NewPluginNativeWindow(aPluginNativeWindow);
    3670             : }
    3671             : 
    3672             : nsresult
    3673           0 : nsPluginHost::GetPluginName(nsNPAPIPluginInstance *aPluginInstance,
    3674             :                             const char** aPluginName)
    3675             : {
    3676           0 :   nsNPAPIPluginInstance *instance = static_cast<nsNPAPIPluginInstance*>(aPluginInstance);
    3677           0 :   if (!instance)
    3678           0 :     return NS_ERROR_FAILURE;
    3679             : 
    3680           0 :   nsNPAPIPlugin* plugin = instance->GetPlugin();
    3681           0 :   if (!plugin)
    3682           0 :     return NS_ERROR_FAILURE;
    3683             : 
    3684           0 :   *aPluginName = TagForPlugin(plugin)->Name().get();
    3685             : 
    3686           0 :   return NS_OK;
    3687             : }
    3688             : 
    3689             : nsresult
    3690           0 : nsPluginHost::GetPluginTagForInstance(nsNPAPIPluginInstance *aPluginInstance,
    3691             :                                       nsIPluginTag **aPluginTag)
    3692             : {
    3693           0 :   NS_ENSURE_ARG_POINTER(aPluginInstance);
    3694           0 :   NS_ENSURE_ARG_POINTER(aPluginTag);
    3695             : 
    3696           0 :   nsNPAPIPlugin *plugin = aPluginInstance->GetPlugin();
    3697           0 :   if (!plugin)
    3698           0 :     return NS_ERROR_FAILURE;
    3699             : 
    3700           0 :   *aPluginTag = TagForPlugin(plugin);
    3701             : 
    3702           0 :   NS_ADDREF(*aPluginTag);
    3703           0 :   return NS_OK;
    3704             : }
    3705             : 
    3706           0 : NS_IMETHODIMP nsPluginHost::Notify(nsITimer* timer)
    3707             : {
    3708           0 :   RefPtr<nsPluginTag> pluginTag = mPlugins;
    3709           0 :   while (pluginTag) {
    3710           0 :     if (pluginTag->mUnloadTimer == timer) {
    3711           0 :       if (!IsRunningPlugin(pluginTag)) {
    3712           0 :         pluginTag->TryUnloadPlugin(false);
    3713             :       }
    3714           0 :       return NS_OK;
    3715             :     }
    3716           0 :     pluginTag = pluginTag->mNext;
    3717             :   }
    3718             : 
    3719           0 :   return NS_ERROR_FAILURE;
    3720             : }
    3721             : 
    3722             : #ifdef XP_WIN
    3723             : // Re-enable any top level browser windows that were disabled by modal dialogs
    3724             : // displayed by the crashed plugin.
    3725             : static void
    3726             : CheckForDisabledWindows()
    3727             : {
    3728             :   nsCOMPtr<nsIWindowMediator> wm(do_GetService(NS_WINDOWMEDIATOR_CONTRACTID));
    3729             :   if (!wm)
    3730             :     return;
    3731             : 
    3732             :   nsCOMPtr<nsISimpleEnumerator> windowList;
    3733             :   wm->GetXULWindowEnumerator(nullptr, getter_AddRefs(windowList));
    3734             :   if (!windowList)
    3735             :     return;
    3736             : 
    3737             :   bool haveWindows;
    3738             :   do {
    3739             :     windowList->HasMoreElements(&haveWindows);
    3740             :     if (!haveWindows)
    3741             :       return;
    3742             : 
    3743             :     nsCOMPtr<nsISupports> supportsWindow;
    3744             :     windowList->GetNext(getter_AddRefs(supportsWindow));
    3745             :     nsCOMPtr<nsIBaseWindow> baseWin(do_QueryInterface(supportsWindow));
    3746             :     if (baseWin) {
    3747             :       nsCOMPtr<nsIWidget> widget;
    3748             :       baseWin->GetMainWidget(getter_AddRefs(widget));
    3749             :       if (widget && !widget->GetParent() &&
    3750             :           widget->IsVisible() &&
    3751             :           !widget->IsEnabled()) {
    3752             :         nsIWidget* child = widget->GetFirstChild();
    3753             :         bool enable = true;
    3754             :         while (child)  {
    3755             :           if (child->WindowType() == eWindowType_dialog) {
    3756             :             enable = false;
    3757             :             break;
    3758             :           }
    3759             :           child = child->GetNextSibling();
    3760             :         }
    3761             :         if (enable) {
    3762             :           widget->Enable(true);
    3763             :         }
    3764             :       }
    3765             :     }
    3766             :   } while (haveWindows);
    3767             : }
    3768             : #endif
    3769             : 
    3770             : void
    3771           0 : nsPluginHost::PluginCrashed(nsNPAPIPlugin* aPlugin,
    3772             :                             const nsAString& pluginDumpID,
    3773             :                             const nsAString& browserDumpID)
    3774             : {
    3775           0 :   nsPluginTag* crashedPluginTag = TagForPlugin(aPlugin);
    3776           0 :   MOZ_ASSERT(crashedPluginTag);
    3777             : 
    3778             :   // Notify the app's observer that a plugin crashed so it can submit
    3779             :   // a crashreport.
    3780           0 :   bool submittedCrashReport = false;
    3781             :   nsCOMPtr<nsIObserverService> obsService =
    3782           0 :     mozilla::services::GetObserverService();
    3783             :   nsCOMPtr<nsIWritablePropertyBag2> propbag =
    3784           0 :     do_CreateInstance("@mozilla.org/hash-property-bag;1");
    3785           0 :   if (obsService && propbag) {
    3786           0 :     uint32_t runID = 0;
    3787           0 :     PluginLibrary* library = aPlugin->GetLibrary();
    3788             : 
    3789           0 :     if (!NS_WARN_IF(!library)) {
    3790           0 :       library->GetRunID(&runID);
    3791             :     }
    3792           0 :     propbag->SetPropertyAsUint32(NS_LITERAL_STRING("runID"), runID);
    3793             : 
    3794           0 :     nsCString pluginName;
    3795           0 :     crashedPluginTag->GetName(pluginName);
    3796           0 :     propbag->SetPropertyAsAString(NS_LITERAL_STRING("pluginName"),
    3797           0 :                                    NS_ConvertUTF8toUTF16(pluginName));
    3798           0 :     propbag->SetPropertyAsAString(NS_LITERAL_STRING("pluginDumpID"),
    3799           0 :                                   pluginDumpID);
    3800           0 :     propbag->SetPropertyAsAString(NS_LITERAL_STRING("browserDumpID"),
    3801           0 :                                   browserDumpID);
    3802           0 :     propbag->SetPropertyAsBool(NS_LITERAL_STRING("submittedCrashReport"),
    3803           0 :                                submittedCrashReport);
    3804           0 :     obsService->NotifyObservers(propbag, "plugin-crashed", nullptr);
    3805             :     // see if an observer submitted a crash report.
    3806           0 :     propbag->GetPropertyAsBool(NS_LITERAL_STRING("submittedCrashReport"),
    3807           0 :                                &submittedCrashReport);
    3808             :   }
    3809             : 
    3810             :   // Invalidate each nsPluginInstanceTag for the crashed plugin
    3811             : 
    3812           0 :   for (uint32_t i = mInstances.Length(); i > 0; i--) {
    3813           0 :     nsNPAPIPluginInstance* instance = mInstances[i - 1];
    3814           0 :     if (instance->GetPlugin() == aPlugin) {
    3815             :       // notify the content node (nsIObjectLoadingContent) that the
    3816             :       // plugin has crashed
    3817           0 :       nsCOMPtr<nsIDOMElement> domElement;
    3818           0 :       instance->GetDOMElement(getter_AddRefs(domElement));
    3819           0 :       nsCOMPtr<nsIObjectLoadingContent> objectContent(do_QueryInterface(domElement));
    3820           0 :       if (objectContent) {
    3821           0 :         objectContent->PluginCrashed(crashedPluginTag, pluginDumpID, browserDumpID,
    3822           0 :                                      submittedCrashReport);
    3823             :       }
    3824             : 
    3825           0 :       instance->Destroy();
    3826           0 :       mInstances.RemoveElement(instance);
    3827           0 :       OnPluginInstanceDestroyed(crashedPluginTag);
    3828             :     }
    3829             :   }
    3830             : 
    3831             :   // Only after all instances have been invalidated is it safe to null
    3832             :   // out nsPluginTag.mPlugin. The next time we try to create an
    3833             :   // instance of this plugin we reload it (launch a new plugin process).
    3834             : 
    3835           0 :   crashedPluginTag->mPlugin = nullptr;
    3836           0 :   crashedPluginTag->mContentProcessRunningCount = 0;
    3837             : 
    3838             : #ifdef XP_WIN
    3839             :   CheckForDisabledWindows();
    3840             : #endif
    3841           0 : }
    3842             : 
    3843             : nsNPAPIPluginInstance*
    3844           0 : nsPluginHost::FindInstance(const char *mimetype)
    3845             : {
    3846           0 :   for (uint32_t i = 0; i < mInstances.Length(); i++) {
    3847           0 :     nsNPAPIPluginInstance* instance = mInstances[i];
    3848             : 
    3849             :     const char* mt;
    3850           0 :     nsresult rv = instance->GetMIMEType(&mt);
    3851           0 :     if (NS_FAILED(rv))
    3852           0 :       continue;
    3853             : 
    3854           0 :     if (PL_strcasecmp(mt, mimetype) == 0)
    3855           0 :       return instance;
    3856             :   }
    3857             : 
    3858           0 :   return nullptr;
    3859             : }
    3860             : 
    3861             : nsNPAPIPluginInstance*
    3862           0 : nsPluginHost::FindOldestStoppedInstance()
    3863             : {
    3864           0 :   nsNPAPIPluginInstance *oldestInstance = nullptr;
    3865           0 :   TimeStamp oldestTime = TimeStamp::Now();
    3866           0 :   for (uint32_t i = 0; i < mInstances.Length(); i++) {
    3867           0 :     nsNPAPIPluginInstance *instance = mInstances[i];
    3868           0 :     if (instance->IsRunning())
    3869           0 :       continue;
    3870             : 
    3871           0 :     TimeStamp time = instance->StopTime();
    3872           0 :     if (time < oldestTime) {
    3873           0 :       oldestTime = time;
    3874           0 :       oldestInstance = instance;
    3875             :     }
    3876             :   }
    3877             : 
    3878           0 :   return oldestInstance;
    3879             : }
    3880             : 
    3881             : uint32_t
    3882           0 : nsPluginHost::StoppedInstanceCount()
    3883             : {
    3884           0 :   uint32_t stoppedCount = 0;
    3885           0 :   for (uint32_t i = 0; i < mInstances.Length(); i++) {
    3886           0 :     nsNPAPIPluginInstance *instance = mInstances[i];
    3887           0 :     if (!instance->IsRunning())
    3888           0 :       stoppedCount++;
    3889             :   }
    3890           0 :   return stoppedCount;
    3891             : }
    3892             : 
    3893             : nsTArray< RefPtr<nsNPAPIPluginInstance> >*
    3894           0 : nsPluginHost::InstanceArray()
    3895             : {
    3896           0 :   return &mInstances;
    3897             : }
    3898             : 
    3899             : void
    3900           0 : nsPluginHost::DestroyRunningInstances(nsPluginTag* aPluginTag)
    3901             : {
    3902           0 :   for (int32_t i = mInstances.Length(); i > 0; i--) {
    3903           0 :     nsNPAPIPluginInstance *instance = mInstances[i - 1];
    3904           0 :     if (instance->IsRunning() && (!aPluginTag || aPluginTag == TagForPlugin(instance->GetPlugin()))) {
    3905           0 :       instance->SetWindow(nullptr);
    3906           0 :       instance->Stop();
    3907             : 
    3908             :       // Get rid of all the instances without the possibility of caching.
    3909           0 :       nsPluginTag* pluginTag = TagForPlugin(instance->GetPlugin());
    3910           0 :       instance->SetWindow(nullptr);
    3911             : 
    3912           0 :       nsCOMPtr<nsIDOMElement> domElement;
    3913           0 :       instance->GetDOMElement(getter_AddRefs(domElement));
    3914             :       nsCOMPtr<nsIObjectLoadingContent> objectContent =
    3915           0 :         do_QueryInterface(domElement);
    3916             : 
    3917           0 :       instance->Destroy();
    3918             : 
    3919           0 :       mInstances.RemoveElement(instance);
    3920           0 :       OnPluginInstanceDestroyed(pluginTag);
    3921             : 
    3922             :       // Notify owning content that we destroyed its plugin out from under it
    3923           0 :       if (objectContent) {
    3924           0 :         objectContent->PluginDestroyed();
    3925             :       }
    3926             :     }
    3927             :   }
    3928           0 : }
    3929             : 
    3930             : /* static */
    3931             : bool
    3932           0 : nsPluginHost::CanUsePluginForMIMEType(const nsACString& aMIMEType)
    3933             : {
    3934             :   // We only support flash as a plugin, so if the mime types don't match for
    3935             :   // those, exit before we start loading plugins.
    3936             :   //
    3937             :   // XXX: Remove test/java cases when bug 1351885 lands.
    3938           0 :   if (nsPluginHost::GetSpecialType(aMIMEType) == nsPluginHost::eSpecialType_Flash ||
    3939           0 :       MimeTypeIsAllowedForFakePlugin(NS_ConvertUTF8toUTF16(aMIMEType)) ||
    3940           0 :       aMIMEType.LowerCaseEqualsLiteral("application/x-test") ||
    3941           0 :       aMIMEType.LowerCaseEqualsLiteral("application/x-second-test") ||
    3942           0 :       aMIMEType.LowerCaseEqualsLiteral("application/x-third-test") ||
    3943           0 :       aMIMEType.LowerCaseEqualsLiteral("application/x-java-test")) {
    3944           0 :     return true;
    3945             :   }
    3946             : 
    3947           0 :   return false;
    3948             : }
    3949             : 
    3950             : // Runnable that does an async destroy of a plugin.
    3951             : 
    3952             : class nsPluginDestroyRunnable : public Runnable,
    3953             :                                 public mozilla::LinkedListElement<nsPluginDestroyRunnable>
    3954             : {
    3955             : public:
    3956           0 :   explicit nsPluginDestroyRunnable(nsNPAPIPluginInstance *aInstance)
    3957           0 :     : Runnable("nsPluginDestroyRunnable"),
    3958           0 :       mInstance(aInstance)
    3959             :   {
    3960           0 :     sRunnableList.insertBack(this);
    3961           0 :   }
    3962             : 
    3963           0 :   ~nsPluginDestroyRunnable() override
    3964           0 :   {
    3965           0 :     this->remove();
    3966           0 :   }
    3967             : 
    3968           0 :   NS_IMETHOD Run() override
    3969             :   {
    3970           0 :     RefPtr<nsNPAPIPluginInstance> instance;
    3971             : 
    3972             :     // Null out mInstance to make sure this code in another runnable
    3973             :     // will do the right thing even if someone was holding on to this
    3974             :     // runnable longer than we expect.
    3975           0 :     instance.swap(mInstance);
    3976             : 
    3977           0 :     if (PluginDestructionGuard::DelayDestroy(instance)) {
    3978             :       // It's still not safe to destroy the plugin, it's now up to the
    3979             :       // outermost guard on the stack to take care of the destruction.
    3980           0 :       return NS_OK;
    3981             :     }
    3982             : 
    3983           0 :     for (auto r : sRunnableList) {
    3984           0 :       if (r != this && r->mInstance == instance) {
    3985             :         // There's another runnable scheduled to tear down
    3986             :         // instance. Let it do the job.
    3987           0 :         return NS_OK;
    3988             :       }
    3989             :     }
    3990             : 
    3991           0 :     PLUGIN_LOG(PLUGIN_LOG_NORMAL,
    3992             :                ("Doing delayed destroy of instance %p\n", instance.get()));
    3993             : 
    3994           0 :     RefPtr<nsPluginHost> host = nsPluginHost::GetInst();
    3995           0 :     if (host)
    3996           0 :       host->StopPluginInstance(instance);
    3997             : 
    3998           0 :     PLUGIN_LOG(PLUGIN_LOG_NORMAL,
    3999             :                ("Done with delayed destroy of instance %p\n", instance.get()));
    4000             : 
    4001           0 :     return NS_OK;
    4002             :   }
    4003             : 
    4004             : protected:
    4005             :   RefPtr<nsNPAPIPluginInstance> mInstance;
    4006             : 
    4007             :   static mozilla::LinkedList<nsPluginDestroyRunnable> sRunnableList;
    4008             : };
    4009             : 
    4010           3 : mozilla::LinkedList<nsPluginDestroyRunnable> nsPluginDestroyRunnable::sRunnableList;
    4011             : 
    4012           3 : mozilla::LinkedList<PluginDestructionGuard> PluginDestructionGuard::sList;
    4013             : 
    4014           0 : PluginDestructionGuard::PluginDestructionGuard(nsNPAPIPluginInstance *aInstance)
    4015           0 :   : mInstance(aInstance)
    4016             : {
    4017           0 :   Init();
    4018           0 : }
    4019             : 
    4020           0 : PluginDestructionGuard::PluginDestructionGuard(NPP npp)
    4021           0 :   : mInstance(npp ? static_cast<nsNPAPIPluginInstance*>(npp->ndata) : nullptr)
    4022             : {
    4023           0 :   Init();
    4024           0 : }
    4025             : 
    4026           0 : PluginDestructionGuard::~PluginDestructionGuard()
    4027             : {
    4028           0 :   NS_ASSERTION(NS_IsMainThread(), "Should be on the main thread");
    4029             : 
    4030           0 :   this->remove();
    4031             : 
    4032           0 :   if (mDelayedDestroy) {
    4033             :     // We've attempted to destroy the plugin instance we're holding on
    4034             :     // to while we were guarding it. Do the actual destroy now, off of
    4035             :     // a runnable.
    4036             :     RefPtr<nsPluginDestroyRunnable> evt =
    4037           0 :       new nsPluginDestroyRunnable(mInstance);
    4038             : 
    4039           0 :     NS_DispatchToMainThread(evt);
    4040             :   }
    4041           0 : }
    4042             : 
    4043             : // static
    4044             : bool
    4045           0 : PluginDestructionGuard::DelayDestroy(nsNPAPIPluginInstance *aInstance)
    4046             : {
    4047           0 :   NS_ASSERTION(NS_IsMainThread(), "Should be on the main thread");
    4048           0 :   NS_ASSERTION(aInstance, "Uh, I need an instance!");
    4049             : 
    4050             :   // Find the first guard on the stack and make it do a delayed
    4051             :   // destroy upon destruction.
    4052             : 
    4053           0 :   for (auto g : sList) {
    4054           0 :     if (g->mInstance == aInstance) {
    4055           0 :       g->mDelayedDestroy = true;
    4056             : 
    4057           0 :       return true;
    4058             :     }
    4059             :   }
    4060             : 
    4061           0 :   return false;
    4062           9 : }

Generated by: LCOV version 1.13