dom/plugins/base/nsPluginHost.cpp

changeset 0
6474c204b198
     1.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     1.2 +++ b/dom/plugins/base/nsPluginHost.cpp	Wed Dec 31 06:09:35 2014 +0100
     1.3 @@ -0,0 +1,3770 @@
     1.4 +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
     1.5 +/* This Source Code Form is subject to the terms of the Mozilla Public
     1.6 + * License, v. 2.0. If a copy of the MPL was not distributed with this
     1.7 + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
     1.8 +
     1.9 +/* nsPluginHost.cpp - top-level plugin management code */
    1.10 +
    1.11 +#include "nscore.h"
    1.12 +#include "nsPluginHost.h"
    1.13 +
    1.14 +#include <cstdlib>
    1.15 +#include <stdio.h>
    1.16 +#include "prio.h"
    1.17 +#include "prmem.h"
    1.18 +#include "nsNPAPIPlugin.h"
    1.19 +#include "nsNPAPIPluginStreamListener.h"
    1.20 +#include "nsNPAPIPluginInstance.h"
    1.21 +#include "nsPluginInstanceOwner.h"
    1.22 +#include "nsObjectLoadingContent.h"
    1.23 +#include "nsIHTTPHeaderListener.h"
    1.24 +#include "nsIHttpHeaderVisitor.h"
    1.25 +#include "nsIObserverService.h"
    1.26 +#include "nsIHttpProtocolHandler.h"
    1.27 +#include "nsIHttpChannel.h"
    1.28 +#include "nsIUploadChannel.h"
    1.29 +#include "nsIByteRangeRequest.h"
    1.30 +#include "nsIStreamListener.h"
    1.31 +#include "nsIInputStream.h"
    1.32 +#include "nsIOutputStream.h"
    1.33 +#include "nsIURL.h"
    1.34 +#include "nsTArray.h"
    1.35 +#include "nsReadableUtils.h"
    1.36 +#include "nsProtocolProxyService.h"
    1.37 +#include "nsIStreamConverterService.h"
    1.38 +#include "nsIFile.h"
    1.39 +#if defined(XP_MACOSX)
    1.40 +#include "nsILocalFileMac.h"
    1.41 +#endif
    1.42 +#include "nsISeekableStream.h"
    1.43 +#include "nsNetUtil.h"
    1.44 +#include "nsIProgressEventSink.h"
    1.45 +#include "nsIDocument.h"
    1.46 +#include "nsPluginLogging.h"
    1.47 +#include "nsIScriptChannel.h"
    1.48 +#include "nsIBlocklistService.h"
    1.49 +#include "nsVersionComparator.h"
    1.50 +#include "nsIObjectLoadingContent.h"
    1.51 +#include "nsIWritablePropertyBag2.h"
    1.52 +#include "nsICategoryManager.h"
    1.53 +#include "nsPluginStreamListenerPeer.h"
    1.54 +#include "mozilla/Preferences.h"
    1.55 +
    1.56 +#include "nsEnumeratorUtils.h"
    1.57 +#include "nsXPCOM.h"
    1.58 +#include "nsXPCOMCID.h"
    1.59 +#include "nsISupportsPrimitives.h"
    1.60 +
    1.61 +#include "nsXULAppAPI.h"
    1.62 +#include "nsIXULRuntime.h"
    1.63 +
    1.64 +// for the dialog
    1.65 +#include "nsIWindowWatcher.h"
    1.66 +#include "nsIDOMElement.h"
    1.67 +#include "nsIDOMWindow.h"
    1.68 +
    1.69 +#include "nsNetCID.h"
    1.70 +#include "prprf.h"
    1.71 +#include "nsThreadUtils.h"
    1.72 +#include "nsIInputStreamTee.h"
    1.73 +
    1.74 +#include "nsDirectoryServiceDefs.h"
    1.75 +#include "nsAppDirectoryServiceDefs.h"
    1.76 +#include "nsPluginDirServiceProvider.h"
    1.77 +
    1.78 +#include "nsUnicharUtils.h"
    1.79 +#include "nsPluginManifestLineReader.h"
    1.80 +
    1.81 +#include "nsIWeakReferenceUtils.h"
    1.82 +#include "nsIPresShell.h"
    1.83 +#include "nsPluginNativeWindow.h"
    1.84 +#include "nsIScriptSecurityManager.h"
    1.85 +#include "nsIContentPolicy.h"
    1.86 +#include "nsContentPolicyUtils.h"
    1.87 +#include "mozilla/TimeStamp.h"
    1.88 +#include "mozilla/Telemetry.h"
    1.89 +#include "nsIImageLoadingContent.h"
    1.90 +#include "mozilla/Preferences.h"
    1.91 +#include "nsVersionComparator.h"
    1.92 +
    1.93 +#if defined(XP_WIN)
    1.94 +#include "nsIWindowMediator.h"
    1.95 +#include "nsIBaseWindow.h"
    1.96 +#include "windows.h"
    1.97 +#include "winbase.h"
    1.98 +#endif
    1.99 +
   1.100 +#ifdef ANDROID
   1.101 +#include <android/log.h>
   1.102 +#define LOG(args...)  __android_log_print(ANDROID_LOG_INFO, "GeckoPlugins" , ## args)
   1.103 +#endif
   1.104 +
   1.105 +#if MOZ_CRASHREPORTER
   1.106 +#include "nsExceptionHandler.h"
   1.107 +#endif
   1.108 +
   1.109 +using namespace mozilla;
   1.110 +using mozilla::TimeStamp;
   1.111 +
   1.112 +// Null out a strong ref to a linked list iteratively to avoid
   1.113 +// exhausting the stack (bug 486349).
   1.114 +#define NS_ITERATIVE_UNREF_LIST(type_, list_, mNext_)                \
   1.115 +  {                                                                  \
   1.116 +    while (list_) {                                                  \
   1.117 +      type_ temp = list_->mNext_;                                    \
   1.118 +      list_->mNext_ = nullptr;                                        \
   1.119 +      list_ = temp;                                                  \
   1.120 +    }                                                                \
   1.121 +  }
   1.122 +
   1.123 +// this is the name of the directory which will be created
   1.124 +// to cache temporary files.
   1.125 +#define kPluginTmpDirName NS_LITERAL_CSTRING("plugtmp")
   1.126 +
   1.127 +static const char *kPrefWhitelist = "plugin.allowed_types";
   1.128 +static const char *kPrefDisableFullPage = "plugin.disable_full_page_plugin_for_types";
   1.129 +static const char *kPrefJavaMIME = "plugin.java.mime";
   1.130 +
   1.131 +// Version of cached plugin info
   1.132 +// 0.01 first implementation
   1.133 +// 0.02 added caching of CanUnload to fix bug 105935
   1.134 +// 0.03 changed name, description and mime desc from string to bytes, bug 108246
   1.135 +// 0.04 added new mime entry point on Mac, bug 113464
   1.136 +// 0.05 added new entry point check for the default plugin, bug 132430
   1.137 +// 0.06 strip off suffixes in mime description strings, bug 53895
   1.138 +// 0.07 changed nsIRegistry to flat file support for caching plugins info
   1.139 +// 0.08 mime entry point on MachO, bug 137535
   1.140 +// 0.09 the file encoding is changed to UTF-8, bug 420285
   1.141 +// 0.10 added plugin versions on appropriate platforms, bug 427743
   1.142 +// 0.11 file name and full path fields now store expected values on all platforms, bug 488181
   1.143 +// 0.12 force refresh due to quicktime pdf claim fix, bug 611197
   1.144 +// 0.13 add architecture and list of invalid plugins, bug 616271
   1.145 +// 0.14 force refresh due to locale comparison fix, bug 611296
   1.146 +// 0.15 force refresh due to bug in reading Java plist MIME data, bug 638171
   1.147 +// 0.16 version bump to avoid importing the plugin flags in newer versions
   1.148 +// 0.17 added flag on whether plugin is loaded from an XPI
   1.149 +// The current plugin registry version (and the maximum version we know how to read)
   1.150 +static const char *kPluginRegistryVersion = "0.17";
   1.151 +// The minimum registry version we know how to read
   1.152 +static const char *kMinimumRegistryVersion = "0.9";
   1.153 +
   1.154 +static const char kDirectoryServiceContractID[] = "@mozilla.org/file/directory_service;1";
   1.155 +
   1.156 +#define kPluginRegistryFilename NS_LITERAL_CSTRING("pluginreg.dat")
   1.157 +
   1.158 +#ifdef PLUGIN_LOGGING
   1.159 +PRLogModuleInfo* nsPluginLogging::gNPNLog = nullptr;
   1.160 +PRLogModuleInfo* nsPluginLogging::gNPPLog = nullptr;
   1.161 +PRLogModuleInfo* nsPluginLogging::gPluginLog = nullptr;
   1.162 +#endif
   1.163 +
   1.164 +// #defines for plugin cache and prefs
   1.165 +#define NS_PREF_MAX_NUM_CACHED_INSTANCES "browser.plugins.max_num_cached_plugins"
   1.166 +// Raise this from '10' to '50' to work around a bug in Apple's current Java
   1.167 +// plugins on OS X Lion and SnowLeopard.  See bug 705931.
   1.168 +#define DEFAULT_NUMBER_OF_STOPPED_INSTANCES 50
   1.169 +
   1.170 +nsIFile *nsPluginHost::sPluginTempDir;
   1.171 +nsPluginHost *nsPluginHost::sInst;
   1.172 +
   1.173 +NS_IMPL_ISUPPORTS0(nsInvalidPluginTag)
   1.174 +
   1.175 +nsInvalidPluginTag::nsInvalidPluginTag(const char* aFullPath, int64_t aLastModifiedTime)
   1.176 +: mFullPath(aFullPath),
   1.177 +  mLastModifiedTime(aLastModifiedTime),
   1.178 +  mSeen(false)
   1.179 +{}
   1.180 +
   1.181 +nsInvalidPluginTag::~nsInvalidPluginTag()
   1.182 +{}
   1.183 +
   1.184 +// Helper to check for a MIME in a comma-delimited preference
   1.185 +static bool
   1.186 +IsTypeInList(nsCString &aMimeType, nsCString aTypeList)
   1.187 +{
   1.188 +  nsAutoCString searchStr;
   1.189 +  searchStr.Assign(',');
   1.190 +  searchStr.Append(aTypeList);
   1.191 +  searchStr.Append(',');
   1.192 +
   1.193 +  nsACString::const_iterator start, end;
   1.194 +
   1.195 +  searchStr.BeginReading(start);
   1.196 +  searchStr.EndReading(end);
   1.197 +
   1.198 +  nsAutoCString commaSeparated;
   1.199 +  commaSeparated.Assign(',');
   1.200 +  commaSeparated += aMimeType;
   1.201 +  commaSeparated.Append(',');
   1.202 +
   1.203 +  return FindInReadable(commaSeparated, start, end);
   1.204 +}
   1.205 +
   1.206 +// flat file reg funcs
   1.207 +static
   1.208 +bool ReadSectionHeader(nsPluginManifestLineReader& reader, const char *token)
   1.209 +{
   1.210 +  do {
   1.211 +    if (*reader.LinePtr() == '[') {
   1.212 +      char* p = reader.LinePtr() + (reader.LineLength() - 1);
   1.213 +      if (*p != ']')
   1.214 +        break;
   1.215 +      *p = 0;
   1.216 +
   1.217 +      char* values[1];
   1.218 +      if (1 != reader.ParseLine(values, 1))
   1.219 +        break;
   1.220 +      // ignore the leading '['
   1.221 +      if (PL_strcmp(values[0]+1, token)) {
   1.222 +        break; // it's wrong token
   1.223 +      }
   1.224 +      return true;
   1.225 +    }
   1.226 +  } while (reader.NextLine());
   1.227 +  return false;
   1.228 +}
   1.229 +
   1.230 +static bool UnloadPluginsASAP()
   1.231 +{
   1.232 +  return Preferences::GetBool("dom.ipc.plugins.unloadASAP", false);
   1.233 +}
   1.234 +
   1.235 +nsPluginHost::nsPluginHost()
   1.236 +  // No need to initialize members to nullptr, false etc because this class
   1.237 +  // has a zeroing operator new.
   1.238 +{
   1.239 +  // check to see if pref is set at startup to let plugins take over in
   1.240 +  // full page mode for certain image mime types that we handle internally
   1.241 +  mOverrideInternalTypes =
   1.242 +    Preferences::GetBool("plugin.override_internal_types", false);
   1.243 +
   1.244 +  mPluginsDisabled = Preferences::GetBool("plugin.disable", false);
   1.245 +  mPluginsClickToPlay = Preferences::GetBool("plugins.click_to_play", false);
   1.246 +
   1.247 +  Preferences::AddStrongObserver(this, "plugin.disable");
   1.248 +  Preferences::AddStrongObserver(this, "plugins.click_to_play");
   1.249 +
   1.250 +  nsCOMPtr<nsIObserverService> obsService =
   1.251 +    mozilla::services::GetObserverService();
   1.252 +  if (obsService) {
   1.253 +    obsService->AddObserver(this, NS_XPCOM_SHUTDOWN_OBSERVER_ID, false);
   1.254 +    obsService->AddObserver(this, "blocklist-updated", false);
   1.255 +#ifdef MOZ_WIDGET_ANDROID
   1.256 +    obsService->AddObserver(this, "application-foreground", false);
   1.257 +    obsService->AddObserver(this, "application-background", false);
   1.258 +#endif
   1.259 +  }
   1.260 +
   1.261 +#ifdef PLUGIN_LOGGING
   1.262 +  nsPluginLogging::gNPNLog = PR_NewLogModule(NPN_LOG_NAME);
   1.263 +  nsPluginLogging::gNPPLog = PR_NewLogModule(NPP_LOG_NAME);
   1.264 +  nsPluginLogging::gPluginLog = PR_NewLogModule(PLUGIN_LOG_NAME);
   1.265 +
   1.266 +  PR_LOG(nsPluginLogging::gNPNLog, PLUGIN_LOG_ALWAYS,("NPN Logging Active!\n"));
   1.267 +  PR_LOG(nsPluginLogging::gPluginLog, PLUGIN_LOG_ALWAYS,("General Plugin Logging Active! (nsPluginHost::ctor)\n"));
   1.268 +  PR_LOG(nsPluginLogging::gNPPLog, PLUGIN_LOG_ALWAYS,("NPP Logging Active!\n"));
   1.269 +
   1.270 +  PLUGIN_LOG(PLUGIN_LOG_ALWAYS,("nsPluginHost::ctor\n"));
   1.271 +  PR_LogFlush();
   1.272 +#endif
   1.273 +}
   1.274 +
   1.275 +nsPluginHost::~nsPluginHost()
   1.276 +{
   1.277 +  PLUGIN_LOG(PLUGIN_LOG_ALWAYS,("nsPluginHost::dtor\n"));
   1.278 +
   1.279 +  UnloadPlugins();
   1.280 +  sInst = nullptr;
   1.281 +}
   1.282 +
   1.283 +NS_IMPL_ISUPPORTS(nsPluginHost,
   1.284 +                  nsIPluginHost,
   1.285 +                  nsIObserver,
   1.286 +                  nsITimerCallback,
   1.287 +                  nsISupportsWeakReference)
   1.288 +
   1.289 +already_AddRefed<nsPluginHost>
   1.290 +nsPluginHost::GetInst()
   1.291 +{
   1.292 +  if (!sInst) {
   1.293 +    sInst = new nsPluginHost();
   1.294 +    if (!sInst)
   1.295 +      return nullptr;
   1.296 +    NS_ADDREF(sInst);
   1.297 +  }
   1.298 +
   1.299 +  nsRefPtr<nsPluginHost> inst = sInst;
   1.300 +  return inst.forget();
   1.301 +}
   1.302 +
   1.303 +bool nsPluginHost::IsRunningPlugin(nsPluginTag * aPluginTag)
   1.304 +{
   1.305 +  if (!aPluginTag || !aPluginTag->mPlugin) {
   1.306 +    return false;
   1.307 +  }
   1.308 +
   1.309 +  for (uint32_t i = 0; i < mInstances.Length(); i++) {
   1.310 +    nsNPAPIPluginInstance *instance = mInstances[i].get();
   1.311 +    if (instance &&
   1.312 +        instance->GetPlugin() == aPluginTag->mPlugin &&
   1.313 +        instance->IsRunning()) {
   1.314 +      return true;
   1.315 +    }
   1.316 +  }
   1.317 +
   1.318 +  return false;
   1.319 +}
   1.320 +
   1.321 +nsresult nsPluginHost::ReloadPlugins()
   1.322 +{
   1.323 +  PLUGIN_LOG(PLUGIN_LOG_NORMAL,
   1.324 +  ("nsPluginHost::ReloadPlugins Begin\n"));
   1.325 +
   1.326 +  nsresult rv = NS_OK;
   1.327 +
   1.328 +  // this will create the initial plugin list out of cache
   1.329 +  // if it was not created yet
   1.330 +  if (!mPluginsLoaded)
   1.331 +    return LoadPlugins();
   1.332 +
   1.333 +  // we are re-scanning plugins. New plugins may have been added, also some
   1.334 +  // plugins may have been removed, so we should probably shut everything down
   1.335 +  // but don't touch running (active and not stopped) plugins
   1.336 +
   1.337 +  // check if plugins changed, no need to do anything else
   1.338 +  // if no changes to plugins have been made
   1.339 +  // false instructs not to touch the plugin list, just to
   1.340 +  // look for possible changes
   1.341 +  bool pluginschanged = true;
   1.342 +  FindPlugins(false, &pluginschanged);
   1.343 +
   1.344 +  // if no changed detected, return an appropriate error code
   1.345 +  if (!pluginschanged)
   1.346 +    return NS_ERROR_PLUGINS_PLUGINSNOTCHANGED;
   1.347 +
   1.348 +  // shutdown plugins and kill the list if there are no running plugins
   1.349 +  nsRefPtr<nsPluginTag> prev;
   1.350 +  nsRefPtr<nsPluginTag> next;
   1.351 +
   1.352 +  for (nsRefPtr<nsPluginTag> p = mPlugins; p != nullptr;) {
   1.353 +    next = p->mNext;
   1.354 +
   1.355 +    // only remove our plugin from the list if it's not running.
   1.356 +    if (!IsRunningPlugin(p)) {
   1.357 +      if (p == mPlugins)
   1.358 +        mPlugins = next;
   1.359 +      else
   1.360 +        prev->mNext = next;
   1.361 +
   1.362 +      p->mNext = nullptr;
   1.363 +
   1.364 +      // attempt to unload plugins whenever they are removed from the list
   1.365 +      p->TryUnloadPlugin(false);
   1.366 +
   1.367 +      p = next;
   1.368 +      continue;
   1.369 +    }
   1.370 +
   1.371 +    prev = p;
   1.372 +    p = next;
   1.373 +  }
   1.374 +
   1.375 +  // set flags
   1.376 +  mPluginsLoaded = false;
   1.377 +
   1.378 +  // load them again
   1.379 +  rv = LoadPlugins();
   1.380 +
   1.381 +  PLUGIN_LOG(PLUGIN_LOG_NORMAL,
   1.382 +  ("nsPluginHost::ReloadPlugins End\n"));
   1.383 +
   1.384 +  return rv;
   1.385 +}
   1.386 +
   1.387 +#define NS_RETURN_UASTRING_SIZE 128
   1.388 +
   1.389 +nsresult nsPluginHost::UserAgent(const char **retstring)
   1.390 +{
   1.391 +  static char resultString[NS_RETURN_UASTRING_SIZE];
   1.392 +  nsresult res;
   1.393 +
   1.394 +  nsCOMPtr<nsIHttpProtocolHandler> http = do_GetService(NS_NETWORK_PROTOCOL_CONTRACTID_PREFIX "http", &res);
   1.395 +  if (NS_FAILED(res))
   1.396 +    return res;
   1.397 +
   1.398 +  nsAutoCString uaString;
   1.399 +  res = http->GetUserAgent(uaString);
   1.400 +
   1.401 +  if (NS_SUCCEEDED(res)) {
   1.402 +    if (NS_RETURN_UASTRING_SIZE > uaString.Length()) {
   1.403 +      PL_strcpy(resultString, uaString.get());
   1.404 +    } else {
   1.405 +      // Copy as much of UA string as we can (terminate at right-most space).
   1.406 +      PL_strncpy(resultString, uaString.get(), NS_RETURN_UASTRING_SIZE);
   1.407 +      for (int i = NS_RETURN_UASTRING_SIZE - 1; i >= 0; i--) {
   1.408 +        if (i == 0) {
   1.409 +          resultString[NS_RETURN_UASTRING_SIZE - 1] = '\0';
   1.410 +        }
   1.411 +        else if (resultString[i] == ' ') {
   1.412 +          resultString[i] = '\0';
   1.413 +          break;
   1.414 +        }
   1.415 +      }
   1.416 +    }
   1.417 +    *retstring = resultString;
   1.418 +  }
   1.419 +  else {
   1.420 +    *retstring = nullptr;
   1.421 +  }
   1.422 +
   1.423 +  PLUGIN_LOG(PLUGIN_LOG_NORMAL, ("nsPluginHost::UserAgent return=%s\n", *retstring));
   1.424 +
   1.425 +  return res;
   1.426 +}
   1.427 +
   1.428 +nsresult nsPluginHost::GetURL(nsISupports* pluginInst,
   1.429 +                              const char* url,
   1.430 +                              const char* target,
   1.431 +                              nsNPAPIPluginStreamListener* streamListener,
   1.432 +                              const char* altHost,
   1.433 +                              const char* referrer,
   1.434 +                              bool forceJSEnabled)
   1.435 +{
   1.436 +  return GetURLWithHeaders(static_cast<nsNPAPIPluginInstance*>(pluginInst),
   1.437 +                           url, target, streamListener, altHost, referrer,
   1.438 +                           forceJSEnabled, 0, nullptr);
   1.439 +}
   1.440 +
   1.441 +nsresult nsPluginHost::GetURLWithHeaders(nsNPAPIPluginInstance* pluginInst,
   1.442 +                                         const char* url,
   1.443 +                                         const char* target,
   1.444 +                                         nsNPAPIPluginStreamListener* streamListener,
   1.445 +                                         const char* altHost,
   1.446 +                                         const char* referrer,
   1.447 +                                         bool forceJSEnabled,
   1.448 +                                         uint32_t getHeadersLength,
   1.449 +                                         const char* getHeaders)
   1.450 +{
   1.451 +  // we can only send a stream back to the plugin (as specified by a
   1.452 +  // null target) if we also have a nsNPAPIPluginStreamListener to talk to
   1.453 +  if (!target && !streamListener)
   1.454 +    return NS_ERROR_ILLEGAL_VALUE;
   1.455 +
   1.456 +  nsresult rv = DoURLLoadSecurityCheck(pluginInst, url);
   1.457 +  if (NS_FAILED(rv))
   1.458 +    return rv;
   1.459 +
   1.460 +  if (target) {
   1.461 +    nsRefPtr<nsPluginInstanceOwner> owner = pluginInst->GetOwner();
   1.462 +    if (owner) {
   1.463 +      if ((0 == PL_strcmp(target, "newwindow")) ||
   1.464 +          (0 == PL_strcmp(target, "_new")))
   1.465 +        target = "_blank";
   1.466 +      else if (0 == PL_strcmp(target, "_current"))
   1.467 +        target = "_self";
   1.468 +
   1.469 +      rv = owner->GetURL(url, target, nullptr, nullptr, 0);
   1.470 +    }
   1.471 +  }
   1.472 +
   1.473 +  if (streamListener)
   1.474 +    rv = NewPluginURLStream(NS_ConvertUTF8toUTF16(url), pluginInst,
   1.475 +                            streamListener, nullptr,
   1.476 +                            getHeaders, getHeadersLength);
   1.477 +
   1.478 +  return rv;
   1.479 +}
   1.480 +
   1.481 +nsresult nsPluginHost::PostURL(nsISupports* pluginInst,
   1.482 +                                    const char* url,
   1.483 +                                    uint32_t postDataLen,
   1.484 +                                    const char* postData,
   1.485 +                                    bool isFile,
   1.486 +                                    const char* target,
   1.487 +                                    nsNPAPIPluginStreamListener* streamListener,
   1.488 +                                    const char* altHost,
   1.489 +                                    const char* referrer,
   1.490 +                                    bool forceJSEnabled,
   1.491 +                                    uint32_t postHeadersLength,
   1.492 +                                    const char* postHeaders)
   1.493 +{
   1.494 +  nsresult rv;
   1.495 +
   1.496 +  // we can only send a stream back to the plugin (as specified
   1.497 +  // by a null target) if we also have a nsNPAPIPluginStreamListener
   1.498 +  // to talk to also
   1.499 +  if (!target && !streamListener)
   1.500 +    return NS_ERROR_ILLEGAL_VALUE;
   1.501 +
   1.502 +  nsNPAPIPluginInstance* instance = static_cast<nsNPAPIPluginInstance*>(pluginInst);
   1.503 +
   1.504 +  rv = DoURLLoadSecurityCheck(instance, url);
   1.505 +  if (NS_FAILED(rv))
   1.506 +    return rv;
   1.507 +
   1.508 +  nsCOMPtr<nsIInputStream> postStream;
   1.509 +  if (isFile) {
   1.510 +    nsCOMPtr<nsIFile> file;
   1.511 +    rv = CreateTempFileToPost(postData, getter_AddRefs(file));
   1.512 +    if (NS_FAILED(rv))
   1.513 +      return rv;
   1.514 +
   1.515 +    nsCOMPtr<nsIInputStream> fileStream;
   1.516 +    rv = NS_NewLocalFileInputStream(getter_AddRefs(fileStream),
   1.517 +                                    file,
   1.518 +                                    PR_RDONLY,
   1.519 +                                    0600,
   1.520 +                                    nsIFileInputStream::DELETE_ON_CLOSE |
   1.521 +                                    nsIFileInputStream::CLOSE_ON_EOF);
   1.522 +    if (NS_FAILED(rv))
   1.523 +      return rv;
   1.524 +
   1.525 +    rv = NS_NewBufferedInputStream(getter_AddRefs(postStream), fileStream, 8192);
   1.526 +    if (NS_FAILED(rv))
   1.527 +      return rv;
   1.528 +  } else {
   1.529 +    char *dataToPost;
   1.530 +    uint32_t newDataToPostLen;
   1.531 +    ParsePostBufferToFixHeaders(postData, postDataLen, &dataToPost, &newDataToPostLen);
   1.532 +    if (!dataToPost)
   1.533 +      return NS_ERROR_UNEXPECTED;
   1.534 +
   1.535 +    nsCOMPtr<nsIStringInputStream> sis = do_CreateInstance("@mozilla.org/io/string-input-stream;1", &rv);
   1.536 +    if (!sis) {
   1.537 +      NS_Free(dataToPost);
   1.538 +      return rv;
   1.539 +    }
   1.540 +
   1.541 +    // data allocated by ParsePostBufferToFixHeaders() is managed and
   1.542 +    // freed by the string stream.
   1.543 +    postDataLen = newDataToPostLen;
   1.544 +    sis->AdoptData(dataToPost, postDataLen);
   1.545 +    postStream = sis;
   1.546 +  }
   1.547 +
   1.548 +  if (target) {
   1.549 +    nsRefPtr<nsPluginInstanceOwner> owner = instance->GetOwner();
   1.550 +    if (owner) {
   1.551 +      if ((0 == PL_strcmp(target, "newwindow")) ||
   1.552 +          (0 == PL_strcmp(target, "_new"))) {
   1.553 +        target = "_blank";
   1.554 +      } else if (0 == PL_strcmp(target, "_current")) {
   1.555 +        target = "_self";
   1.556 +      }
   1.557 +      rv = owner->GetURL(url, target, postStream,
   1.558 +                         (void*)postHeaders, postHeadersLength);
   1.559 +    }
   1.560 +  }
   1.561 +
   1.562 +  // if we don't have a target, just create a stream.  This does
   1.563 +  // NS_OpenURI()!
   1.564 +  if (streamListener)
   1.565 +    rv = NewPluginURLStream(NS_ConvertUTF8toUTF16(url), instance,
   1.566 +                            streamListener,
   1.567 +                            postStream, postHeaders, postHeadersLength);
   1.568 +
   1.569 +  return rv;
   1.570 +}
   1.571 +
   1.572 +/* This method queries the prefs for proxy information.
   1.573 + * It has been tested and is known to work in the following three cases
   1.574 + * when no proxy host or port is specified
   1.575 + * when only the proxy host is specified
   1.576 + * when only the proxy port is specified
   1.577 + * This method conforms to the return code specified in
   1.578 + * http://developer.netscape.com/docs/manuals/proxy/adminnt/autoconf.htm#1020923
   1.579 + * with the exception that multiple values are not implemented.
   1.580 + */
   1.581 +
   1.582 +nsresult nsPluginHost::FindProxyForURL(const char* url, char* *result)
   1.583 +{
   1.584 +  if (!url || !result) {
   1.585 +    return NS_ERROR_INVALID_ARG;
   1.586 +  }
   1.587 +  nsresult res;
   1.588 +
   1.589 +  nsCOMPtr<nsIProtocolProxyService> proxyService =
   1.590 +    do_GetService(NS_PROTOCOLPROXYSERVICE_CONTRACTID, &res);
   1.591 +  if (NS_FAILED(res) || !proxyService)
   1.592 +    return res;
   1.593 +
   1.594 +  nsRefPtr<nsProtocolProxyService> rawProxyService = do_QueryObject(proxyService);
   1.595 +  if (!rawProxyService)
   1.596 +    return NS_ERROR_FAILURE;
   1.597 +
   1.598 +  nsCOMPtr<nsIIOService> ioService = do_GetService(NS_IOSERVICE_CONTRACTID, &res);
   1.599 +  if (NS_FAILED(res) || !ioService)
   1.600 +    return res;
   1.601 +
   1.602 +  // make a temporary channel from the argument url
   1.603 +  nsCOMPtr<nsIChannel> tempChannel;
   1.604 +  res = ioService->NewChannel(nsDependentCString(url), nullptr, nullptr, getter_AddRefs(tempChannel));
   1.605 +  if (NS_FAILED(res))
   1.606 +    return res;
   1.607 +
   1.608 +  nsCOMPtr<nsIProxyInfo> pi;
   1.609 +
   1.610 +  // Remove this deprecated call in the future (see Bug 778201):
   1.611 +  res = rawProxyService->DeprecatedBlockingResolve(tempChannel, 0, getter_AddRefs(pi));
   1.612 +  if (NS_FAILED(res))
   1.613 +    return res;
   1.614 +
   1.615 +  nsAutoCString host, type;
   1.616 +  int32_t port = -1;
   1.617 +
   1.618 +  // These won't fail, and even if they do... we'll be ok.
   1.619 +  if (pi) {
   1.620 +    pi->GetType(type);
   1.621 +    pi->GetHost(host);
   1.622 +    pi->GetPort(&port);
   1.623 +  }
   1.624 +
   1.625 +  if (!pi || host.IsEmpty() || port <= 0 || host.EqualsLiteral("direct")) {
   1.626 +    *result = PL_strdup("DIRECT");
   1.627 +  } else if (type.EqualsLiteral("http")) {
   1.628 +    *result = PR_smprintf("PROXY %s:%d", host.get(), port);
   1.629 +  } else if (type.EqualsLiteral("socks4")) {
   1.630 +    *result = PR_smprintf("SOCKS %s:%d", host.get(), port);
   1.631 +  } else if (type.EqualsLiteral("socks")) {
   1.632 +    // XXX - this is socks5, but there is no API for us to tell the
   1.633 +    // plugin that fact. SOCKS for now, in case the proxy server
   1.634 +    // speaks SOCKS4 as well. See bug 78176
   1.635 +    // For a long time this was returning an http proxy type, so
   1.636 +    // very little is probably broken by this
   1.637 +    *result = PR_smprintf("SOCKS %s:%d", host.get(), port);
   1.638 +  } else {
   1.639 +    NS_ASSERTION(false, "Unknown proxy type!");
   1.640 +    *result = PL_strdup("DIRECT");
   1.641 +  }
   1.642 +
   1.643 +  if (nullptr == *result)
   1.644 +    res = NS_ERROR_OUT_OF_MEMORY;
   1.645 +
   1.646 +  return res;
   1.647 +}
   1.648 +
   1.649 +nsresult nsPluginHost::Init()
   1.650 +{
   1.651 +  return NS_OK;
   1.652 +}
   1.653 +
   1.654 +nsresult nsPluginHost::UnloadPlugins()
   1.655 +{
   1.656 +  PLUGIN_LOG(PLUGIN_LOG_NORMAL, ("nsPluginHost::UnloadPlugins Called\n"));
   1.657 +
   1.658 +  if (!mPluginsLoaded)
   1.659 +    return NS_OK;
   1.660 +
   1.661 +  // we should call nsIPluginInstance::Stop and nsIPluginInstance::SetWindow
   1.662 +  // for those plugins who want it
   1.663 +  DestroyRunningInstances(nullptr);
   1.664 +
   1.665 +  nsPluginTag *pluginTag;
   1.666 +  for (pluginTag = mPlugins; pluginTag; pluginTag = pluginTag->mNext) {
   1.667 +    pluginTag->TryUnloadPlugin(true);
   1.668 +  }
   1.669 +
   1.670 +  NS_ITERATIVE_UNREF_LIST(nsRefPtr<nsPluginTag>, mPlugins, mNext);
   1.671 +  NS_ITERATIVE_UNREF_LIST(nsRefPtr<nsPluginTag>, mCachedPlugins, mNext);
   1.672 +  NS_ITERATIVE_UNREF_LIST(nsRefPtr<nsInvalidPluginTag>, mInvalidPlugins, mNext);
   1.673 +
   1.674 +  // Lets remove any of the temporary files that we created.
   1.675 +  if (sPluginTempDir) {
   1.676 +    sPluginTempDir->Remove(true);
   1.677 +    NS_RELEASE(sPluginTempDir);
   1.678 +  }
   1.679 +
   1.680 +#ifdef XP_WIN
   1.681 +  if (mPrivateDirServiceProvider) {
   1.682 +    nsCOMPtr<nsIDirectoryService> dirService =
   1.683 +      do_GetService(kDirectoryServiceContractID);
   1.684 +    if (dirService)
   1.685 +      dirService->UnregisterProvider(mPrivateDirServiceProvider);
   1.686 +    mPrivateDirServiceProvider = nullptr;
   1.687 +  }
   1.688 +#endif /* XP_WIN */
   1.689 +
   1.690 +  mPluginsLoaded = false;
   1.691 +
   1.692 +  return NS_OK;
   1.693 +}
   1.694 +
   1.695 +void nsPluginHost::OnPluginInstanceDestroyed(nsPluginTag* aPluginTag)
   1.696 +{
   1.697 +  bool hasInstance = false;
   1.698 +  for (uint32_t i = 0; i < mInstances.Length(); i++) {
   1.699 +    if (TagForPlugin(mInstances[i]->GetPlugin()) == aPluginTag) {
   1.700 +      hasInstance = true;
   1.701 +      break;
   1.702 +    }
   1.703 +  }
   1.704 +
   1.705 +  // We have some options for unloading plugins if they have no instances.
   1.706 +  //
   1.707 +  // Unloading plugins immediately can be bad - some plugins retain state
   1.708 +  // between instances even when there are none. This is largely limited to
   1.709 +  // going from one page to another, so state is retained without an instance
   1.710 +  // for only a very short period of time. In order to allow this to work
   1.711 +  // we don't unload plugins immediately by default. This is supported
   1.712 +  // via a hidden user pref though.
   1.713 +  //
   1.714 +  // Another reason not to unload immediately is that loading is expensive,
   1.715 +  // and it is better to leave popular plugins loaded.
   1.716 +  //
   1.717 +  // Our default behavior is to try to unload a plugin three minutes after
   1.718 +  // its last instance is destroyed. This seems like a reasonable compromise
   1.719 +  // that allows us to reclaim memory while allowing short state retention
   1.720 +  // and avoid perf hits for loading popular plugins.
   1.721 +  if (!hasInstance) {
   1.722 +    if (UnloadPluginsASAP()) {
   1.723 +      aPluginTag->TryUnloadPlugin(false);
   1.724 +    } else {
   1.725 +      if (aPluginTag->mUnloadTimer) {
   1.726 +        aPluginTag->mUnloadTimer->Cancel();
   1.727 +      } else {
   1.728 +        aPluginTag->mUnloadTimer = do_CreateInstance(NS_TIMER_CONTRACTID);
   1.729 +      }
   1.730 +      aPluginTag->mUnloadTimer->InitWithCallback(this, 1000 * 60 * 3, nsITimer::TYPE_ONE_SHOT);
   1.731 +    }
   1.732 +  }
   1.733 +}
   1.734 +
   1.735 +nsresult
   1.736 +nsPluginHost::GetPluginTempDir(nsIFile **aDir)
   1.737 +{
   1.738 +  if (!sPluginTempDir) {
   1.739 +    nsCOMPtr<nsIFile> tmpDir;
   1.740 +    nsresult rv = NS_GetSpecialDirectory(NS_OS_TEMP_DIR,
   1.741 +                                         getter_AddRefs(tmpDir));
   1.742 +    NS_ENSURE_SUCCESS(rv, rv);
   1.743 +
   1.744 +    rv = tmpDir->AppendNative(kPluginTmpDirName);
   1.745 +
   1.746 +    // make it unique, and mode == 0700, not world-readable
   1.747 +    rv = tmpDir->CreateUnique(nsIFile::DIRECTORY_TYPE, 0700);
   1.748 +    NS_ENSURE_SUCCESS(rv, rv);
   1.749 +
   1.750 +    tmpDir.swap(sPluginTempDir);
   1.751 +  }
   1.752 +
   1.753 +  return sPluginTempDir->Clone(aDir);
   1.754 +}
   1.755 +
   1.756 +nsresult
   1.757 +nsPluginHost::InstantiatePluginInstance(const char *aMimeType, nsIURI* aURL,
   1.758 +                                        nsObjectLoadingContent *aContent,
   1.759 +                                        nsPluginInstanceOwner** aOwner)
   1.760 +{
   1.761 +  NS_ENSURE_ARG_POINTER(aOwner);
   1.762 +
   1.763 +#ifdef PLUGIN_LOGGING
   1.764 +  nsAutoCString urlSpec;
   1.765 +  if (aURL)
   1.766 +    aURL->GetAsciiSpec(urlSpec);
   1.767 +
   1.768 +  PR_LOG(nsPluginLogging::gPluginLog, PLUGIN_LOG_NORMAL,
   1.769 +        ("nsPluginHost::InstantiatePlugin Begin mime=%s, url=%s\n",
   1.770 +        aMimeType, urlSpec.get()));
   1.771 +
   1.772 +  PR_LogFlush();
   1.773 +#endif
   1.774 +
   1.775 +  if (!aMimeType) {
   1.776 +    NS_NOTREACHED("Attempting to spawn a plugin with no mime type");
   1.777 +    return NS_ERROR_FAILURE;
   1.778 +  }
   1.779 +
   1.780 +  nsRefPtr<nsPluginInstanceOwner> instanceOwner = new nsPluginInstanceOwner();
   1.781 +  if (!instanceOwner) {
   1.782 +    return NS_ERROR_OUT_OF_MEMORY;
   1.783 +  }
   1.784 +
   1.785 +  nsCOMPtr<nsIContent> ourContent = do_QueryInterface(static_cast<nsIImageLoadingContent*>(aContent));
   1.786 +  nsresult rv = instanceOwner->Init(ourContent);
   1.787 +  if (NS_FAILED(rv)) {
   1.788 +    return rv;
   1.789 +  }
   1.790 +
   1.791 +  nsPluginTagType tagType;
   1.792 +  rv = instanceOwner->GetTagType(&tagType);
   1.793 +  if (NS_FAILED(rv)) {
   1.794 +    return rv;
   1.795 +  }
   1.796 +
   1.797 +  if (tagType != nsPluginTagType_Embed &&
   1.798 +      tagType != nsPluginTagType_Applet &&
   1.799 +      tagType != nsPluginTagType_Object) {
   1.800 +    return NS_ERROR_FAILURE;
   1.801 +  }
   1.802 +
   1.803 +  rv = SetUpPluginInstance(aMimeType, aURL, instanceOwner);
   1.804 +  if (NS_FAILED(rv)) {
   1.805 +    return NS_ERROR_FAILURE;
   1.806 +  }
   1.807 +
   1.808 +  nsRefPtr<nsNPAPIPluginInstance> instance;
   1.809 +  rv = instanceOwner->GetInstance(getter_AddRefs(instance));
   1.810 +  if (NS_FAILED(rv)) {
   1.811 +    return rv;
   1.812 +  }
   1.813 +
   1.814 +  if (instance) {
   1.815 +    instanceOwner->CreateWidget();
   1.816 +
   1.817 +    // If we've got a native window, the let the plugin know about it.
   1.818 +    instanceOwner->CallSetWindow();
   1.819 +  }
   1.820 +
   1.821 +  // At this point we consider instantiation to be successful. Do not return an error.
   1.822 +  instanceOwner.forget(aOwner);
   1.823 +
   1.824 +#ifdef PLUGIN_LOGGING
   1.825 +  nsAutoCString urlSpec2;
   1.826 +  if (aURL != nullptr) aURL->GetAsciiSpec(urlSpec2);
   1.827 +
   1.828 +  PR_LOG(nsPluginLogging::gPluginLog, PLUGIN_LOG_NORMAL,
   1.829 +        ("nsPluginHost::InstantiatePlugin Finished mime=%s, rv=%d, url=%s\n",
   1.830 +        aMimeType, rv, urlSpec2.get()));
   1.831 +
   1.832 +  PR_LogFlush();
   1.833 +#endif
   1.834 +
   1.835 +  return NS_OK;
   1.836 +}
   1.837 +
   1.838 +nsPluginTag*
   1.839 +nsPluginHost::FindTagForLibrary(PRLibrary* aLibrary)
   1.840 +{
   1.841 +  nsPluginTag* pluginTag;
   1.842 +  for (pluginTag = mPlugins; pluginTag; pluginTag = pluginTag->mNext) {
   1.843 +    if (pluginTag->mLibrary == aLibrary) {
   1.844 +      return pluginTag;
   1.845 +    }
   1.846 +  }
   1.847 +  return nullptr;
   1.848 +}
   1.849 +
   1.850 +nsPluginTag*
   1.851 +nsPluginHost::TagForPlugin(nsNPAPIPlugin* aPlugin)
   1.852 +{
   1.853 +  nsPluginTag* pluginTag;
   1.854 +  for (pluginTag = mPlugins; pluginTag; pluginTag = pluginTag->mNext) {
   1.855 +    if (pluginTag->mPlugin == aPlugin) {
   1.856 +      return pluginTag;
   1.857 +    }
   1.858 +  }
   1.859 +  // a plugin should never exist without a corresponding tag
   1.860 +  NS_ERROR("TagForPlugin has failed");
   1.861 +  return nullptr;
   1.862 +}
   1.863 +
   1.864 +nsresult nsPluginHost::SetUpPluginInstance(const char *aMimeType,
   1.865 +                                           nsIURI *aURL,
   1.866 +                                           nsPluginInstanceOwner *aOwner)
   1.867 +{
   1.868 +  NS_ENSURE_ARG_POINTER(aOwner);
   1.869 +
   1.870 +  nsresult rv = TrySetUpPluginInstance(aMimeType, aURL, aOwner);
   1.871 +  if (NS_SUCCEEDED(rv)) {
   1.872 +    return rv;
   1.873 +  }
   1.874 +
   1.875 +  // If we failed to load a plugin instance we'll try again after
   1.876 +  // reloading our plugin list. Only do that once per document to
   1.877 +  // avoid redundant high resource usage on pages with multiple
   1.878 +  // unkown instance types. We'll do that by caching the document.
   1.879 +  nsCOMPtr<nsIDocument> document;
   1.880 +  aOwner->GetDocument(getter_AddRefs(document));
   1.881 +
   1.882 +  nsCOMPtr<nsIDocument> currentdocument = do_QueryReferent(mCurrentDocument);
   1.883 +  if (document == currentdocument) {
   1.884 +    return rv;
   1.885 +  }
   1.886 +
   1.887 +  mCurrentDocument = do_GetWeakReference(document);
   1.888 +
   1.889 +  // Don't try to set up an instance again if nothing changed.
   1.890 +  if (ReloadPlugins() == NS_ERROR_PLUGINS_PLUGINSNOTCHANGED) {
   1.891 +    return rv;
   1.892 +  }
   1.893 +
   1.894 +  return TrySetUpPluginInstance(aMimeType, aURL, aOwner);
   1.895 +}
   1.896 +
   1.897 +nsresult
   1.898 +nsPluginHost::TrySetUpPluginInstance(const char *aMimeType,
   1.899 +                                     nsIURI *aURL,
   1.900 +                                     nsPluginInstanceOwner *aOwner)
   1.901 +{
   1.902 +#ifdef PLUGIN_LOGGING
   1.903 +  nsAutoCString urlSpec;
   1.904 +  if (aURL != nullptr) aURL->GetSpec(urlSpec);
   1.905 +
   1.906 +  PR_LOG(nsPluginLogging::gPluginLog, PLUGIN_LOG_NORMAL,
   1.907 +        ("nsPluginHost::TrySetupPluginInstance Begin mime=%s, owner=%p, url=%s\n",
   1.908 +        aMimeType, aOwner, urlSpec.get()));
   1.909 +
   1.910 +  PR_LogFlush();
   1.911 +#endif
   1.912 +
   1.913 +  nsRefPtr<nsNPAPIPlugin> plugin;
   1.914 +  GetPlugin(aMimeType, getter_AddRefs(plugin));
   1.915 +  if (!plugin) {
   1.916 +    return NS_ERROR_FAILURE;
   1.917 +  }
   1.918 +
   1.919 +  nsPluginTag* pluginTag = FindPluginForType(aMimeType, true);
   1.920 +
   1.921 +  NS_ASSERTION(pluginTag, "Must have plugin tag here!");
   1.922 +
   1.923 +#if defined(MOZ_WIDGET_ANDROID) && defined(MOZ_CRASHREPORTER)
   1.924 +  if (pluginTag->mIsFlashPlugin) {
   1.925 +    CrashReporter::AnnotateCrashReport(NS_LITERAL_CSTRING("FlashVersion"), pluginTag->mVersion);
   1.926 +  }
   1.927 +#endif
   1.928 +
   1.929 +  nsRefPtr<nsNPAPIPluginInstance> instance = new nsNPAPIPluginInstance();
   1.930 +
   1.931 +  // This will create the owning reference. The connection must be made between the
   1.932 +  // instance and the instance owner before initialization. Plugins can call into
   1.933 +  // the browser during initialization.
   1.934 +  aOwner->SetInstance(instance.get());
   1.935 +
   1.936 +  // Add the instance to the instances list before we call NPP_New so that
   1.937 +  // it is "in play" before NPP_New happens. Take it out if NPP_New fails.
   1.938 +  mInstances.AppendElement(instance.get());
   1.939 +
   1.940 +  // this should not addref the instance or owner
   1.941 +  // except in some cases not Java, see bug 140931
   1.942 +  // our COM pointer will free the peer
   1.943 +  nsresult rv = instance->Initialize(plugin.get(), aOwner, aMimeType);
   1.944 +  if (NS_FAILED(rv)) {
   1.945 +    mInstances.RemoveElement(instance.get());
   1.946 +    aOwner->SetInstance(nullptr);
   1.947 +    return rv;
   1.948 +  }
   1.949 +
   1.950 +  // Cancel the plugin unload timer since we are creating
   1.951 +  // an instance for it.
   1.952 +  if (pluginTag->mUnloadTimer) {
   1.953 +    pluginTag->mUnloadTimer->Cancel();
   1.954 +  }
   1.955 +
   1.956 +#ifdef PLUGIN_LOGGING
   1.957 +  nsAutoCString urlSpec2;
   1.958 +  if (aURL)
   1.959 +    aURL->GetSpec(urlSpec2);
   1.960 +
   1.961 +  PR_LOG(nsPluginLogging::gPluginLog, PLUGIN_LOG_BASIC,
   1.962 +        ("nsPluginHost::TrySetupPluginInstance Finished mime=%s, rv=%d, owner=%p, url=%s\n",
   1.963 +        aMimeType, rv, aOwner, urlSpec2.get()));
   1.964 +
   1.965 +  PR_LogFlush();
   1.966 +#endif
   1.967 +
   1.968 +  return rv;
   1.969 +}
   1.970 +
   1.971 +bool
   1.972 +nsPluginHost::PluginExistsForType(const char* aMimeType)
   1.973 +{
   1.974 +  nsPluginTag *plugin = FindPluginForType(aMimeType, false);
   1.975 +  return nullptr != plugin;
   1.976 +}
   1.977 +
   1.978 +NS_IMETHODIMP
   1.979 +nsPluginHost::GetPluginTagForType(const nsACString& aMimeType,
   1.980 +                                  nsIPluginTag** aResult)
   1.981 +{
   1.982 +  nsPluginTag* plugin = FindPluginForType(aMimeType.Data(), true);
   1.983 +  if (!plugin) {
   1.984 +    plugin = FindPluginForType(aMimeType.Data(), false);
   1.985 +  }
   1.986 +  if (!plugin) {
   1.987 +    return NS_ERROR_NOT_AVAILABLE;
   1.988 +  }
   1.989 +  NS_ADDREF(*aResult = plugin);
   1.990 +  return NS_OK;
   1.991 +}
   1.992 +
   1.993 +NS_IMETHODIMP
   1.994 +nsPluginHost::GetStateForType(const nsACString &aMimeType, uint32_t* aResult)
   1.995 +{
   1.996 +  nsPluginTag *plugin = FindPluginForType(aMimeType.Data(), true);
   1.997 +  if (!plugin) {
   1.998 +    plugin = FindPluginForType(aMimeType.Data(), false);
   1.999 +  }
  1.1000 +  if (!plugin) {
  1.1001 +    return NS_ERROR_UNEXPECTED;
  1.1002 +  }
  1.1003 +
  1.1004 +  return plugin->GetEnabledState(aResult);
  1.1005 +}
  1.1006 +
  1.1007 +NS_IMETHODIMP
  1.1008 +nsPluginHost::GetBlocklistStateForType(const char *aMimeType, uint32_t *aState)
  1.1009 +{
  1.1010 +  nsPluginTag *plugin = FindPluginForType(aMimeType, true);
  1.1011 +  if (!plugin) {
  1.1012 +    plugin = FindPluginForType(aMimeType, false);
  1.1013 +  }
  1.1014 +  if (!plugin) {
  1.1015 +    return NS_ERROR_FAILURE;
  1.1016 +  }
  1.1017 +
  1.1018 +  *aState = plugin->GetBlocklistState();
  1.1019 +  return NS_OK;
  1.1020 +}
  1.1021 +
  1.1022 +NS_IMETHODIMP
  1.1023 +nsPluginHost::GetPermissionStringForType(const nsACString &aMimeType, nsACString &aPermissionString)
  1.1024 +{
  1.1025 +  aPermissionString.Truncate();
  1.1026 +  uint32_t blocklistState;
  1.1027 +  nsresult rv = GetBlocklistStateForType(aMimeType.Data(), &blocklistState);
  1.1028 +  NS_ENSURE_SUCCESS(rv, rv);
  1.1029 +  nsPluginTag *tag = FindPluginForType(aMimeType.Data(), true);
  1.1030 +  if (!tag) {
  1.1031 +    tag = FindPluginForType(aMimeType.Data(), false);
  1.1032 +  }
  1.1033 +  if (!tag) {
  1.1034 +    return NS_ERROR_FAILURE;
  1.1035 +  }
  1.1036 +
  1.1037 +  if (blocklistState == nsIBlocklistService::STATE_VULNERABLE_UPDATE_AVAILABLE ||
  1.1038 +      blocklistState == nsIBlocklistService::STATE_VULNERABLE_NO_UPDATE) {
  1.1039 +    aPermissionString.AssignLiteral("plugin-vulnerable:");
  1.1040 +  }
  1.1041 +  else {
  1.1042 +    aPermissionString.AssignLiteral("plugin:");
  1.1043 +  }
  1.1044 +
  1.1045 +  aPermissionString.Append(tag->GetNiceFileName());
  1.1046 +
  1.1047 +  return NS_OK;
  1.1048 +}
  1.1049 +
  1.1050 +// check comma delimitered extensions
  1.1051 +static int CompareExtensions(const char *aExtensionList, const char *aExtension)
  1.1052 +{
  1.1053 +  if (!aExtensionList || !aExtension)
  1.1054 +    return -1;
  1.1055 +
  1.1056 +  const char *pExt = aExtensionList;
  1.1057 +  const char *pComma = strchr(pExt, ',');
  1.1058 +  if (!pComma)
  1.1059 +    return PL_strcasecmp(pExt, aExtension);
  1.1060 +
  1.1061 +  int extlen = strlen(aExtension);
  1.1062 +  while (pComma) {
  1.1063 +    int length = pComma - pExt;
  1.1064 +    if (length == extlen && 0 == PL_strncasecmp(aExtension, pExt, length))
  1.1065 +      return 0;
  1.1066 +    pComma++;
  1.1067 +    pExt = pComma;
  1.1068 +    pComma = strchr(pExt, ',');
  1.1069 +  }
  1.1070 +
  1.1071 +  // the last one
  1.1072 +  return PL_strcasecmp(pExt, aExtension);
  1.1073 +}
  1.1074 +
  1.1075 +nsresult
  1.1076 +nsPluginHost::IsPluginEnabledForExtension(const char* aExtension,
  1.1077 +                                          const char* &aMimeType)
  1.1078 +{
  1.1079 +  nsPluginTag *plugin = FindPluginEnabledForExtension(aExtension, aMimeType);
  1.1080 +  if (plugin)
  1.1081 +    return NS_OK;
  1.1082 +
  1.1083 +  return NS_ERROR_FAILURE;
  1.1084 +}
  1.1085 +
  1.1086 +void
  1.1087 +nsPluginHost::GetPlugins(nsTArray<nsRefPtr<nsPluginTag> >& aPluginArray)
  1.1088 +{
  1.1089 +  aPluginArray.Clear();
  1.1090 +
  1.1091 +  LoadPlugins();
  1.1092 +
  1.1093 +  nsPluginTag* plugin = mPlugins;
  1.1094 +  while (plugin != nullptr) {
  1.1095 +    if (plugin->IsEnabled()) {
  1.1096 +      aPluginArray.AppendElement(plugin);
  1.1097 +    }
  1.1098 +    plugin = plugin->mNext;
  1.1099 +  }
  1.1100 +}
  1.1101 +
  1.1102 +NS_IMETHODIMP
  1.1103 +nsPluginHost::GetPluginTags(uint32_t* aPluginCount, nsIPluginTag*** aResults)
  1.1104 +{
  1.1105 +  LoadPlugins();
  1.1106 +
  1.1107 +  uint32_t count = 0;
  1.1108 +  nsRefPtr<nsPluginTag> plugin = mPlugins;
  1.1109 +  while (plugin != nullptr) {
  1.1110 +    count++;
  1.1111 +    plugin = plugin->mNext;
  1.1112 +  }
  1.1113 +
  1.1114 +  *aResults = static_cast<nsIPluginTag**>
  1.1115 +                         (nsMemory::Alloc(count * sizeof(**aResults)));
  1.1116 +  if (!*aResults)
  1.1117 +    return NS_ERROR_OUT_OF_MEMORY;
  1.1118 +
  1.1119 +  *aPluginCount = count;
  1.1120 +
  1.1121 +  plugin = mPlugins;
  1.1122 +  for (uint32_t i = 0; i < count; i++) {
  1.1123 +    (*aResults)[i] = plugin;
  1.1124 +    NS_ADDREF((*aResults)[i]);
  1.1125 +    plugin = plugin->mNext;
  1.1126 +  }
  1.1127 +
  1.1128 +  return NS_OK;
  1.1129 +}
  1.1130 +
  1.1131 +nsPluginTag*
  1.1132 +nsPluginHost::FindPreferredPlugin(const InfallibleTArray<nsPluginTag*>& matches)
  1.1133 +{
  1.1134 +  // We prefer the plugin with the highest version number.
  1.1135 +  /// XXX(johns): This seems to assume the only time multiple plugins will have
  1.1136 +  ///             the same MIME type is if they're multiple versions of the same
  1.1137 +  ///             plugin -- but since plugin filenames and pretty names can both
  1.1138 +  ///             update, it's probably less arbitrary than just going at it
  1.1139 +  ///             alphabetically.
  1.1140 +
  1.1141 +  if (matches.IsEmpty()) {
  1.1142 +    return nullptr;
  1.1143 +  }
  1.1144 +
  1.1145 +  nsPluginTag *preferredPlugin = matches[0];
  1.1146 +  for (unsigned int i = 1; i < matches.Length(); i++) {
  1.1147 +    if (mozilla::Version(matches[i]->mVersion.get()) > preferredPlugin->mVersion.get()) {
  1.1148 +      preferredPlugin = matches[i];
  1.1149 +    }
  1.1150 +  }
  1.1151 +
  1.1152 +  return preferredPlugin;
  1.1153 +}
  1.1154 +
  1.1155 +nsPluginTag*
  1.1156 +nsPluginHost::FindPluginForType(const char* aMimeType,
  1.1157 +                                bool aCheckEnabled)
  1.1158 +{
  1.1159 +  if (!aMimeType) {
  1.1160 +    return nullptr;
  1.1161 +  }
  1.1162 +
  1.1163 +  LoadPlugins();
  1.1164 +
  1.1165 +  InfallibleTArray<nsPluginTag*> matchingPlugins;
  1.1166 +
  1.1167 +  nsPluginTag *plugin = mPlugins;
  1.1168 +  while (plugin) {
  1.1169 +    if (!aCheckEnabled || plugin->IsActive()) {
  1.1170 +      int32_t mimeCount = plugin->mMimeTypes.Length();
  1.1171 +      for (int32_t i = 0; i < mimeCount; i++) {
  1.1172 +        if (0 == PL_strcasecmp(plugin->mMimeTypes[i].get(), aMimeType)) {
  1.1173 +          matchingPlugins.AppendElement(plugin);
  1.1174 +          break;
  1.1175 +        }
  1.1176 +      }
  1.1177 +    }
  1.1178 +    plugin = plugin->mNext;
  1.1179 +  }
  1.1180 +
  1.1181 +  return FindPreferredPlugin(matchingPlugins);
  1.1182 +}
  1.1183 +
  1.1184 +nsPluginTag*
  1.1185 +nsPluginHost::FindPluginEnabledForExtension(const char* aExtension,
  1.1186 +                                            const char*& aMimeType)
  1.1187 +{
  1.1188 +  if (!aExtension) {
  1.1189 +    return nullptr;
  1.1190 +  }
  1.1191 +
  1.1192 +  LoadPlugins();
  1.1193 +
  1.1194 +  InfallibleTArray<nsPluginTag*> matchingPlugins;
  1.1195 +
  1.1196 +  nsPluginTag *plugin = mPlugins;
  1.1197 +  while (plugin) {
  1.1198 +    if (plugin->IsActive()) {
  1.1199 +      int32_t variants = plugin->mExtensions.Length();
  1.1200 +      for (int32_t i = 0; i < variants; i++) {
  1.1201 +        // mExtensionsArray[cnt] is a list of extensions separated by commas
  1.1202 +        if (0 == CompareExtensions(plugin->mExtensions[i].get(), aExtension)) {
  1.1203 +          matchingPlugins.AppendElement(plugin);
  1.1204 +          break;
  1.1205 +        }
  1.1206 +      }
  1.1207 +    }
  1.1208 +    plugin = plugin->mNext;
  1.1209 +  }
  1.1210 +
  1.1211 +  nsPluginTag *preferredPlugin = FindPreferredPlugin(matchingPlugins);
  1.1212 +  if (!preferredPlugin) {
  1.1213 +    return nullptr;
  1.1214 +  }
  1.1215 +
  1.1216 +  int32_t variants = preferredPlugin->mExtensions.Length();
  1.1217 +  for (int32_t i = 0; i < variants; i++) {
  1.1218 +    // mExtensionsArray[cnt] is a list of extensions separated by commas
  1.1219 +    if (0 == CompareExtensions(preferredPlugin->mExtensions[i].get(), aExtension)) {
  1.1220 +      aMimeType = preferredPlugin->mMimeTypes[i].get();
  1.1221 +      break;
  1.1222 +    }
  1.1223 +  }
  1.1224 +
  1.1225 +  return preferredPlugin;
  1.1226 +}
  1.1227 +
  1.1228 +static nsresult CreateNPAPIPlugin(nsPluginTag *aPluginTag,
  1.1229 +                                  nsNPAPIPlugin **aOutNPAPIPlugin)
  1.1230 +{
  1.1231 +  // If this is an in-process plugin we'll need to load it here if we haven't already.
  1.1232 +  if (!nsNPAPIPlugin::RunPluginOOP(aPluginTag)) {
  1.1233 +    if (aPluginTag->mFullPath.IsEmpty())
  1.1234 +      return NS_ERROR_FAILURE;
  1.1235 +    nsCOMPtr<nsIFile> file = do_CreateInstance("@mozilla.org/file/local;1");
  1.1236 +    file->InitWithPath(NS_ConvertUTF8toUTF16(aPluginTag->mFullPath));
  1.1237 +    nsPluginFile pluginFile(file);
  1.1238 +    PRLibrary* pluginLibrary = nullptr;
  1.1239 +
  1.1240 +    if (NS_FAILED(pluginFile.LoadPlugin(&pluginLibrary)) || !pluginLibrary)
  1.1241 +      return NS_ERROR_FAILURE;
  1.1242 +
  1.1243 +    aPluginTag->mLibrary = pluginLibrary;
  1.1244 +  }
  1.1245 +
  1.1246 +  nsresult rv;
  1.1247 +  rv = nsNPAPIPlugin::CreatePlugin(aPluginTag, aOutNPAPIPlugin);
  1.1248 +
  1.1249 +  return rv;
  1.1250 +}
  1.1251 +
  1.1252 +nsresult nsPluginHost::EnsurePluginLoaded(nsPluginTag* aPluginTag)
  1.1253 +{
  1.1254 +  nsRefPtr<nsNPAPIPlugin> plugin = aPluginTag->mPlugin;
  1.1255 +  if (!plugin) {
  1.1256 +    nsresult rv = CreateNPAPIPlugin(aPluginTag, getter_AddRefs(plugin));
  1.1257 +    if (NS_FAILED(rv)) {
  1.1258 +      return rv;
  1.1259 +    }
  1.1260 +    aPluginTag->mPlugin = plugin;
  1.1261 +  }
  1.1262 +  return NS_OK;
  1.1263 +}
  1.1264 +
  1.1265 +nsresult nsPluginHost::GetPlugin(const char *aMimeType, nsNPAPIPlugin** aPlugin)
  1.1266 +{
  1.1267 +  nsresult rv = NS_ERROR_FAILURE;
  1.1268 +  *aPlugin = nullptr;
  1.1269 +
  1.1270 +  if (!aMimeType)
  1.1271 +    return NS_ERROR_ILLEGAL_VALUE;
  1.1272 +
  1.1273 +  // If plugins haven't been scanned yet, do so now
  1.1274 +  LoadPlugins();
  1.1275 +
  1.1276 +  nsPluginTag* pluginTag = FindPluginForType(aMimeType, true);
  1.1277 +  if (pluginTag) {
  1.1278 +    rv = NS_OK;
  1.1279 +    PLUGIN_LOG(PLUGIN_LOG_BASIC,
  1.1280 +    ("nsPluginHost::GetPlugin Begin mime=%s, plugin=%s\n",
  1.1281 +    aMimeType, pluginTag->mFileName.get()));
  1.1282 +
  1.1283 +#ifdef DEBUG
  1.1284 +    if (aMimeType && !pluginTag->mFileName.IsEmpty())
  1.1285 +      printf("For %s found plugin %s\n", aMimeType, pluginTag->mFileName.get());
  1.1286 +#endif
  1.1287 +
  1.1288 +    rv = EnsurePluginLoaded(pluginTag);
  1.1289 +    if (NS_FAILED(rv)) {
  1.1290 +      return rv;
  1.1291 +    }
  1.1292 +
  1.1293 +    NS_ADDREF(*aPlugin = pluginTag->mPlugin);
  1.1294 +    return NS_OK;
  1.1295 +  }
  1.1296 +
  1.1297 +  PLUGIN_LOG(PLUGIN_LOG_NORMAL,
  1.1298 +  ("nsPluginHost::GetPlugin End mime=%s, rv=%d, plugin=%p name=%s\n",
  1.1299 +  aMimeType, rv, *aPlugin,
  1.1300 +  (pluginTag ? pluginTag->mFileName.get() : "(not found)")));
  1.1301 +
  1.1302 +  return rv;
  1.1303 +}
  1.1304 +
  1.1305 +// Normalize 'host' to ACE.
  1.1306 +nsresult
  1.1307 +nsPluginHost::NormalizeHostname(nsCString& host)
  1.1308 +{
  1.1309 +  if (IsASCII(host)) {
  1.1310 +    ToLowerCase(host);
  1.1311 +    return NS_OK;
  1.1312 +  }
  1.1313 +
  1.1314 +  if (!mIDNService) {
  1.1315 +    nsresult rv;
  1.1316 +    mIDNService = do_GetService(NS_IDNSERVICE_CONTRACTID, &rv);
  1.1317 +    NS_ENSURE_SUCCESS(rv, rv);
  1.1318 +  }
  1.1319 +
  1.1320 +  return mIDNService->ConvertUTF8toACE(host, host);
  1.1321 +}
  1.1322 +
  1.1323 +// Enumerate a 'sites' array returned by GetSitesWithData and determine if
  1.1324 +// any of them have a base domain in common with 'domain'; if so, append them
  1.1325 +// to the 'result' array. If 'firstMatchOnly' is true, return after finding the
  1.1326 +// first match.
  1.1327 +nsresult
  1.1328 +nsPluginHost::EnumerateSiteData(const nsACString& domain,
  1.1329 +                                const InfallibleTArray<nsCString>& sites,
  1.1330 +                                InfallibleTArray<nsCString>& result,
  1.1331 +                                bool firstMatchOnly)
  1.1332 +{
  1.1333 +  NS_ASSERTION(!domain.IsVoid(), "null domain string");
  1.1334 +
  1.1335 +  nsresult rv;
  1.1336 +  if (!mTLDService) {
  1.1337 +    mTLDService = do_GetService(NS_EFFECTIVETLDSERVICE_CONTRACTID, &rv);
  1.1338 +    NS_ENSURE_SUCCESS(rv, rv);
  1.1339 +  }
  1.1340 +
  1.1341 +  // Get the base domain from the domain.
  1.1342 +  nsCString baseDomain;
  1.1343 +  rv = mTLDService->GetBaseDomainFromHost(domain, 0, baseDomain);
  1.1344 +  bool isIP = rv == NS_ERROR_HOST_IS_IP_ADDRESS;
  1.1345 +  if (isIP || rv == NS_ERROR_INSUFFICIENT_DOMAIN_LEVELS) {
  1.1346 +    // The base domain is the site itself. However, we must be careful to
  1.1347 +    // normalize.
  1.1348 +    baseDomain = domain;
  1.1349 +    rv = NormalizeHostname(baseDomain);
  1.1350 +    NS_ENSURE_SUCCESS(rv, rv);
  1.1351 +  } else if (NS_FAILED(rv)) {
  1.1352 +    return rv;
  1.1353 +  }
  1.1354 +
  1.1355 +  // Enumerate the array of sites with data.
  1.1356 +  for (uint32_t i = 0; i < sites.Length(); ++i) {
  1.1357 +    const nsCString& site = sites[i];
  1.1358 +
  1.1359 +    // Check if the site is an IP address.
  1.1360 +    bool siteIsIP =
  1.1361 +      site.Length() >= 2 && site.First() == '[' && site.Last() == ']';
  1.1362 +    if (siteIsIP != isIP)
  1.1363 +      continue;
  1.1364 +
  1.1365 +    nsCString siteBaseDomain;
  1.1366 +    if (siteIsIP) {
  1.1367 +      // Strip the '[]'.
  1.1368 +      siteBaseDomain = Substring(site, 1, site.Length() - 2);
  1.1369 +    } else {
  1.1370 +      // Determine the base domain of the site.
  1.1371 +      rv = mTLDService->GetBaseDomainFromHost(site, 0, siteBaseDomain);
  1.1372 +      if (rv == NS_ERROR_INSUFFICIENT_DOMAIN_LEVELS) {
  1.1373 +        // The base domain is the site itself. However, we must be careful to
  1.1374 +        // normalize.
  1.1375 +        siteBaseDomain = site;
  1.1376 +        rv = NormalizeHostname(siteBaseDomain);
  1.1377 +        NS_ENSURE_SUCCESS(rv, rv);
  1.1378 +      } else if (NS_FAILED(rv)) {
  1.1379 +        return rv;
  1.1380 +      }
  1.1381 +    }
  1.1382 +
  1.1383 +    // At this point, we can do an exact comparison of the two domains.
  1.1384 +    if (baseDomain != siteBaseDomain) {
  1.1385 +      continue;
  1.1386 +    }
  1.1387 +
  1.1388 +    // Append the site to the result array.
  1.1389 +    result.AppendElement(site);
  1.1390 +
  1.1391 +    // If we're supposed to return early, do so.
  1.1392 +    if (firstMatchOnly) {
  1.1393 +      break;
  1.1394 +    }
  1.1395 +  }
  1.1396 +
  1.1397 +  return NS_OK;
  1.1398 +}
  1.1399 +
  1.1400 +NS_IMETHODIMP
  1.1401 +nsPluginHost::RegisterPlayPreviewMimeType(const nsACString& mimeType,
  1.1402 +                                          bool ignoreCTP,
  1.1403 +                                          const nsACString& redirectURL)
  1.1404 +{
  1.1405 +  nsAutoCString mt(mimeType);
  1.1406 +  nsAutoCString url(redirectURL);
  1.1407 +  if (url.Length() == 0) {
  1.1408 +    // using default play preview iframe URL, if redirectURL is not specified
  1.1409 +    url.Assign("data:application/x-moz-playpreview;,");
  1.1410 +    url.Append(mimeType);
  1.1411 +  }
  1.1412 +
  1.1413 +  nsRefPtr<nsPluginPlayPreviewInfo> playPreview =
  1.1414 +    new nsPluginPlayPreviewInfo(mt.get(), ignoreCTP, url.get());
  1.1415 +  mPlayPreviewMimeTypes.AppendElement(playPreview);
  1.1416 +  return NS_OK;
  1.1417 +}
  1.1418 +
  1.1419 +NS_IMETHODIMP
  1.1420 +nsPluginHost::UnregisterPlayPreviewMimeType(const nsACString& mimeType)
  1.1421 +{
  1.1422 +  nsAutoCString mimeTypeToRemove(mimeType);
  1.1423 +  for (uint32_t i = mPlayPreviewMimeTypes.Length(); i > 0; i--) {
  1.1424 +    nsRefPtr<nsPluginPlayPreviewInfo> pp = mPlayPreviewMimeTypes[i - 1];
  1.1425 +    if (PL_strcasecmp(pp.get()->mMimeType.get(), mimeTypeToRemove.get()) == 0) {
  1.1426 +      mPlayPreviewMimeTypes.RemoveElementAt(i - 1);
  1.1427 +      break;
  1.1428 +    }
  1.1429 +  }
  1.1430 +  return NS_OK;
  1.1431 +}
  1.1432 +
  1.1433 +NS_IMETHODIMP
  1.1434 +nsPluginHost::GetPlayPreviewInfo(const nsACString& mimeType,
  1.1435 +                                 nsIPluginPlayPreviewInfo** aResult)
  1.1436 +{
  1.1437 +  nsAutoCString mimeTypeToFind(mimeType);
  1.1438 +  for (uint32_t i = 0; i < mPlayPreviewMimeTypes.Length(); i++) {
  1.1439 +    nsRefPtr<nsPluginPlayPreviewInfo> pp = mPlayPreviewMimeTypes[i];
  1.1440 +    if (PL_strcasecmp(pp.get()->mMimeType.get(), mimeTypeToFind.get()) == 0) {
  1.1441 +      *aResult = new nsPluginPlayPreviewInfo(pp.get());
  1.1442 +      NS_ADDREF(*aResult);
  1.1443 +      return NS_OK;
  1.1444 +    }
  1.1445 +  }
  1.1446 +  *aResult = nullptr;
  1.1447 +  return NS_ERROR_NOT_AVAILABLE;
  1.1448 +}
  1.1449 +
  1.1450 +NS_IMETHODIMP
  1.1451 +nsPluginHost::ClearSiteData(nsIPluginTag* plugin, const nsACString& domain,
  1.1452 +                            uint64_t flags, int64_t maxAge)
  1.1453 +{
  1.1454 +  // maxAge must be either a nonnegative integer or -1.
  1.1455 +  NS_ENSURE_ARG(maxAge >= 0 || maxAge == -1);
  1.1456 +
  1.1457 +  // Caller may give us a tag object that is no longer live.
  1.1458 +  if (!IsLiveTag(plugin)) {
  1.1459 +    return NS_ERROR_NOT_AVAILABLE;
  1.1460 +  }
  1.1461 +
  1.1462 +  nsPluginTag* tag = static_cast<nsPluginTag*>(plugin);
  1.1463 +
  1.1464 +  // We only ensure support for clearing Flash site data for now.
  1.1465 +  // We will also attempt to clear data for any plugin that happens
  1.1466 +  // to be loaded already.
  1.1467 +  if (!tag->mIsFlashPlugin && !tag->mPlugin) {
  1.1468 +    return NS_ERROR_FAILURE;
  1.1469 +  }
  1.1470 +
  1.1471 +  // Make sure the plugin is loaded.
  1.1472 +  nsresult rv = EnsurePluginLoaded(tag);
  1.1473 +  if (NS_FAILED(rv)) {
  1.1474 +    return rv;
  1.1475 +  }
  1.1476 +
  1.1477 +  PluginLibrary* library = tag->mPlugin->GetLibrary();
  1.1478 +
  1.1479 +  // If 'domain' is the null string, clear everything.
  1.1480 +  if (domain.IsVoid()) {
  1.1481 +    return library->NPP_ClearSiteData(nullptr, flags, maxAge);
  1.1482 +  }
  1.1483 +
  1.1484 +  // Get the list of sites from the plugin.
  1.1485 +  InfallibleTArray<nsCString> sites;
  1.1486 +  rv = library->NPP_GetSitesWithData(sites);
  1.1487 +  NS_ENSURE_SUCCESS(rv, rv);
  1.1488 +
  1.1489 +  // Enumerate the sites and build a list of matches.
  1.1490 +  InfallibleTArray<nsCString> matches;
  1.1491 +  rv = EnumerateSiteData(domain, sites, matches, false);
  1.1492 +  NS_ENSURE_SUCCESS(rv, rv);
  1.1493 +
  1.1494 +  // Clear the matches.
  1.1495 +  for (uint32_t i = 0; i < matches.Length(); ++i) {
  1.1496 +    const nsCString& match = matches[i];
  1.1497 +    rv = library->NPP_ClearSiteData(match.get(), flags, maxAge);
  1.1498 +    NS_ENSURE_SUCCESS(rv, rv);
  1.1499 +  }
  1.1500 +
  1.1501 +  return NS_OK;
  1.1502 +}
  1.1503 +
  1.1504 +NS_IMETHODIMP
  1.1505 +nsPluginHost::SiteHasData(nsIPluginTag* plugin, const nsACString& domain,
  1.1506 +                          bool* result)
  1.1507 +{
  1.1508 +  // Caller may give us a tag object that is no longer live.
  1.1509 +  if (!IsLiveTag(plugin)) {
  1.1510 +    return NS_ERROR_NOT_AVAILABLE;
  1.1511 +  }
  1.1512 +
  1.1513 +  nsPluginTag* tag = static_cast<nsPluginTag*>(plugin);
  1.1514 +
  1.1515 +  // We only ensure support for clearing Flash site data for now.
  1.1516 +  // We will also attempt to clear data for any plugin that happens
  1.1517 +  // to be loaded already.
  1.1518 +  if (!tag->mIsFlashPlugin && !tag->mPlugin) {
  1.1519 +    return NS_ERROR_FAILURE;
  1.1520 +  }
  1.1521 +
  1.1522 +  // Make sure the plugin is loaded.
  1.1523 +  nsresult rv = EnsurePluginLoaded(tag);
  1.1524 +  if (NS_FAILED(rv)) {
  1.1525 +    return rv;
  1.1526 +  }
  1.1527 +
  1.1528 +  PluginLibrary* library = tag->mPlugin->GetLibrary();
  1.1529 +
  1.1530 +  // Get the list of sites from the plugin.
  1.1531 +  InfallibleTArray<nsCString> sites;
  1.1532 +  rv = library->NPP_GetSitesWithData(sites);
  1.1533 +  NS_ENSURE_SUCCESS(rv, rv);
  1.1534 +
  1.1535 +  // If there's no data, we're done.
  1.1536 +  if (sites.IsEmpty()) {
  1.1537 +    *result = false;
  1.1538 +    return NS_OK;
  1.1539 +  }
  1.1540 +
  1.1541 +  // If 'domain' is the null string, and there's data for at least one site,
  1.1542 +  // we're done.
  1.1543 +  if (domain.IsVoid()) {
  1.1544 +    *result = true;
  1.1545 +    return NS_OK;
  1.1546 +  }
  1.1547 +
  1.1548 +  // Enumerate the sites and determine if there's a match.
  1.1549 +  InfallibleTArray<nsCString> matches;
  1.1550 +  rv = EnumerateSiteData(domain, sites, matches, true);
  1.1551 +  NS_ENSURE_SUCCESS(rv, rv);
  1.1552 +
  1.1553 +  *result = !matches.IsEmpty();
  1.1554 +  return NS_OK;
  1.1555 +}
  1.1556 +
  1.1557 +bool nsPluginHost::IsJavaMIMEType(const char* aType)
  1.1558 +{
  1.1559 +  // The java mime pref may well not be one of these,
  1.1560 +  // e.g. application/x-java-test used in the test suite
  1.1561 +  nsAdoptingCString javaMIME = Preferences::GetCString(kPrefJavaMIME);
  1.1562 +  return aType &&
  1.1563 +    (javaMIME.EqualsIgnoreCase(aType) ||
  1.1564 +     (0 == PL_strncasecmp(aType, "application/x-java-vm",
  1.1565 +                          sizeof("application/x-java-vm") - 1)) ||
  1.1566 +     (0 == PL_strncasecmp(aType, "application/x-java-applet",
  1.1567 +                          sizeof("application/x-java-applet") - 1)) ||
  1.1568 +     (0 == PL_strncasecmp(aType, "application/x-java-bean",
  1.1569 +                          sizeof("application/x-java-bean") - 1)));
  1.1570 +}
  1.1571 +
  1.1572 +// Check whether or not a tag is a live, valid tag, and that it's loaded.
  1.1573 +bool
  1.1574 +nsPluginHost::IsLiveTag(nsIPluginTag* aPluginTag)
  1.1575 +{
  1.1576 +  nsPluginTag* tag;
  1.1577 +  for (tag = mPlugins; tag; tag = tag->mNext) {
  1.1578 +    if (tag == aPluginTag) {
  1.1579 +      return true;
  1.1580 +    }
  1.1581 +  }
  1.1582 +  return false;
  1.1583 +}
  1.1584 +
  1.1585 +nsPluginTag*
  1.1586 +nsPluginHost::HaveSamePlugin(const nsPluginTag* aPluginTag)
  1.1587 +{
  1.1588 +  for (nsPluginTag* tag = mPlugins; tag; tag = tag->mNext) {
  1.1589 +    if (tag->HasSameNameAndMimes(aPluginTag)) {
  1.1590 +        return tag;
  1.1591 +    }
  1.1592 +  }
  1.1593 +  return nullptr;
  1.1594 +}
  1.1595 +
  1.1596 +nsPluginTag*
  1.1597 +nsPluginHost::FirstPluginWithPath(const nsCString& path)
  1.1598 +{
  1.1599 +  for (nsPluginTag* tag = mPlugins; tag; tag = tag->mNext) {
  1.1600 +    if (tag->mFullPath.Equals(path)) {
  1.1601 +      return tag;
  1.1602 +    }
  1.1603 +  }
  1.1604 +  return nullptr;
  1.1605 +}
  1.1606 +
  1.1607 +namespace {
  1.1608 +
  1.1609 +int64_t GetPluginLastModifiedTime(const nsCOMPtr<nsIFile>& localfile)
  1.1610 +{
  1.1611 +  PRTime fileModTime = 0;
  1.1612 +
  1.1613 +#if defined(XP_MACOSX)
  1.1614 +  // On OS X the date of a bundle's "contents" (i.e. of its Info.plist file)
  1.1615 +  // is a much better guide to when it was last modified than the date of
  1.1616 +  // its package directory.  See bug 313700.
  1.1617 +  nsCOMPtr<nsILocalFileMac> localFileMac = do_QueryInterface(localfile);
  1.1618 +  if (localFileMac) {
  1.1619 +    localFileMac->GetBundleContentsLastModifiedTime(&fileModTime);
  1.1620 +  } else {
  1.1621 +    localfile->GetLastModifiedTime(&fileModTime);
  1.1622 +  }
  1.1623 +#else
  1.1624 +  localfile->GetLastModifiedTime(&fileModTime);
  1.1625 +#endif
  1.1626 +
  1.1627 +  return fileModTime;
  1.1628 +}
  1.1629 +
  1.1630 +bool
  1.1631 +GetPluginIsFromExtension(const nsCOMPtr<nsIFile>& pluginFile,
  1.1632 +                         const nsCOMArray<nsIFile>& extensionDirs)
  1.1633 +{
  1.1634 +  for (uint32_t i = 0; i < extensionDirs.Length(); ++i) {
  1.1635 +    bool contains;
  1.1636 +    if (NS_FAILED(extensionDirs[i]->Contains(pluginFile, true, &contains)) || !contains) {
  1.1637 +      continue;
  1.1638 +    }
  1.1639 +
  1.1640 +    return true;
  1.1641 +  }
  1.1642 +
  1.1643 +  return false;
  1.1644 +}
  1.1645 +
  1.1646 +void
  1.1647 +GetExtensionDirectories(nsCOMArray<nsIFile>& dirs)
  1.1648 +{
  1.1649 +  nsCOMPtr<nsIProperties> dirService = do_GetService(NS_DIRECTORY_SERVICE_CONTRACTID);
  1.1650 +  if (!dirService) {
  1.1651 +    return;
  1.1652 +  }
  1.1653 +
  1.1654 +  nsCOMPtr<nsISimpleEnumerator> list;
  1.1655 +  nsresult rv = dirService->Get(XRE_EXTENSIONS_DIR_LIST,
  1.1656 +                                NS_GET_IID(nsISimpleEnumerator),
  1.1657 +                                getter_AddRefs(list));
  1.1658 +  if (NS_FAILED(rv)) {
  1.1659 +    return;
  1.1660 +  }
  1.1661 +
  1.1662 +  bool more;
  1.1663 +  while (NS_SUCCEEDED(list->HasMoreElements(&more)) && more) {
  1.1664 +    nsCOMPtr<nsISupports> next;
  1.1665 +    if (NS_FAILED(list->GetNext(getter_AddRefs(next)))) {
  1.1666 +      break;
  1.1667 +    }
  1.1668 +    nsCOMPtr<nsIFile> file = do_QueryInterface(next);
  1.1669 +    if (file) {
  1.1670 +      file->Normalize();
  1.1671 +      dirs.AppendElement(file);
  1.1672 +    }
  1.1673 +  }
  1.1674 +}
  1.1675 +
  1.1676 +struct CompareFilesByTime
  1.1677 +{
  1.1678 +  bool
  1.1679 +  LessThan(const nsCOMPtr<nsIFile>& a, const nsCOMPtr<nsIFile>& b) const
  1.1680 +  {
  1.1681 +    return GetPluginLastModifiedTime(a) < GetPluginLastModifiedTime(b);
  1.1682 +  }
  1.1683 +
  1.1684 +  bool
  1.1685 +  Equals(const nsCOMPtr<nsIFile>& a, const nsCOMPtr<nsIFile>& b) const
  1.1686 +  {
  1.1687 +    return GetPluginLastModifiedTime(a) == GetPluginLastModifiedTime(b);
  1.1688 +  }
  1.1689 +};
  1.1690 +
  1.1691 +} // anonymous namespace
  1.1692 +
  1.1693 +PRBool nsPluginHost::GhettoBlacklist(nsIFile *pluginFile)
  1.1694 +{
  1.1695 +    nsCString leaf;
  1.1696 +    const char *leafStr;
  1.1697 +    nsresult rv;
  1.1698 +    
  1.1699 +    rv = pluginFile->GetNativeLeafName(leaf);
  1.1700 +    if (NS_FAILED(rv)) {
  1.1701 +        return PR_TRUE; // fuck 'em. blacklist.
  1.1702 +    }
  1.1703 +
  1.1704 +    leafStr = leaf.get();
  1.1705 +
  1.1706 +    if (!leafStr) {
  1.1707 +        return PR_TRUE; // fuck 'em. blacklist.
  1.1708 +    }
  1.1709 +
  1.1710 +    // libgnashplugin.so, libflashplayer.so, Flash Player-10.4-10.5.plugin,
  1.1711 +    // NPSWF32.dll, NPSWF64.dll
  1.1712 +    if (strstr(leafStr, "libgnashplugin") == leafStr ||
  1.1713 +        strstr(leafStr, "libflashplayer") == leafStr ||
  1.1714 +        strstr(leafStr, "Flash Player") == leafStr ||
  1.1715 +        strstr(leafStr, "NPSWF") == leafStr) {
  1.1716 +        return PR_FALSE;
  1.1717 +    }
  1.1718 +
  1.1719 +    return PR_TRUE; // fuck 'em. blacklist.
  1.1720 +}
  1.1721 +
  1.1722 +typedef NS_NPAPIPLUGIN_CALLBACK(char *, NP_GETMIMEDESCRIPTION)(void);
  1.1723 +
  1.1724 +nsresult nsPluginHost::ScanPluginsDirectory(nsIFile *pluginsDir,
  1.1725 +                                            bool aCreatePluginList,
  1.1726 +                                            bool *aPluginsChanged)
  1.1727 +{
  1.1728 +  NS_ENSURE_ARG_POINTER(aPluginsChanged);
  1.1729 +  nsresult rv;
  1.1730 +
  1.1731 +  *aPluginsChanged = false;
  1.1732 +
  1.1733 +#ifdef PLUGIN_LOGGING
  1.1734 +  nsAutoCString dirPath;
  1.1735 +  pluginsDir->GetNativePath(dirPath);
  1.1736 +  PLUGIN_LOG(PLUGIN_LOG_BASIC,
  1.1737 +  ("nsPluginHost::ScanPluginsDirectory dir=%s\n", dirPath.get()));
  1.1738 +#endif
  1.1739 +
  1.1740 +  nsCOMPtr<nsISimpleEnumerator> iter;
  1.1741 +  rv = pluginsDir->GetDirectoryEntries(getter_AddRefs(iter));
  1.1742 +  if (NS_FAILED(rv))
  1.1743 +    return rv;
  1.1744 +
  1.1745 +  nsAutoTArray<nsCOMPtr<nsIFile>, 6> pluginFiles;
  1.1746 +
  1.1747 +  bool hasMore;
  1.1748 +  while (NS_SUCCEEDED(iter->HasMoreElements(&hasMore)) && hasMore) {
  1.1749 +    nsCOMPtr<nsISupports> supports;
  1.1750 +    rv = iter->GetNext(getter_AddRefs(supports));
  1.1751 +    if (NS_FAILED(rv))
  1.1752 +      continue;
  1.1753 +    nsCOMPtr<nsIFile> dirEntry(do_QueryInterface(supports, &rv));
  1.1754 +    if (NS_FAILED(rv))
  1.1755 +      continue;
  1.1756 +
  1.1757 +    // Sun's JRE 1.3.1 plugin must have symbolic links resolved or else it'll crash.
  1.1758 +    // See bug 197855.
  1.1759 +    dirEntry->Normalize();
  1.1760 +
  1.1761 +    if (nsPluginsDir::IsPluginFile(dirEntry)) {
  1.1762 +      pluginFiles.AppendElement(dirEntry);
  1.1763 +    }
  1.1764 +  }
  1.1765 +
  1.1766 +  pluginFiles.Sort(CompareFilesByTime());
  1.1767 +
  1.1768 +  nsCOMArray<nsIFile> extensionDirs;
  1.1769 +  GetExtensionDirectories(extensionDirs);
  1.1770 +
  1.1771 +  bool warnOutdated = false;
  1.1772 +
  1.1773 +  for (int32_t i = (pluginFiles.Length() - 1); i >= 0; i--) {
  1.1774 +    nsCOMPtr<nsIFile>& localfile = pluginFiles[i];
  1.1775 +
  1.1776 +    nsString utf16FilePath;
  1.1777 +    rv = localfile->GetPath(utf16FilePath);
  1.1778 +    if (NS_FAILED(rv))
  1.1779 +      continue;
  1.1780 +
  1.1781 +    const int64_t fileModTime = GetPluginLastModifiedTime(localfile);
  1.1782 +    const bool fromExtension = GetPluginIsFromExtension(localfile, extensionDirs);
  1.1783 +
  1.1784 +    // Look for it in our cache
  1.1785 +    NS_ConvertUTF16toUTF8 filePath(utf16FilePath);
  1.1786 +    nsRefPtr<nsPluginTag> pluginTag;
  1.1787 +    RemoveCachedPluginsInfo(filePath.get(), getter_AddRefs(pluginTag));
  1.1788 +
  1.1789 +    bool seenBefore = false;
  1.1790 +
  1.1791 +    if (pluginTag) {
  1.1792 +      seenBefore = true;
  1.1793 +      // If plugin changed, delete cachedPluginTag and don't use cache
  1.1794 +      if (fileModTime != pluginTag->mLastModifiedTime) {
  1.1795 +        // Plugins has changed. Don't use cached plugin info.
  1.1796 +        pluginTag = nullptr;
  1.1797 +
  1.1798 +        // plugin file changed, flag this fact
  1.1799 +        *aPluginsChanged = true;
  1.1800 +      }
  1.1801 +
  1.1802 +      // If we're not creating a list and we already know something changed then
  1.1803 +      // we're done.
  1.1804 +      if (!aCreatePluginList) {
  1.1805 +        if (*aPluginsChanged) {
  1.1806 +          return NS_OK;
  1.1807 +        }
  1.1808 +        continue;
  1.1809 +      }
  1.1810 +    }
  1.1811 +
  1.1812 +    bool isKnownInvalidPlugin = false;
  1.1813 +    for (nsRefPtr<nsInvalidPluginTag> invalidPlugins = mInvalidPlugins;
  1.1814 +         invalidPlugins; invalidPlugins = invalidPlugins->mNext) {
  1.1815 +      // If already marked as invalid, ignore it
  1.1816 +      if (invalidPlugins->mFullPath.Equals(filePath.get()) &&
  1.1817 +          invalidPlugins->mLastModifiedTime == fileModTime) {
  1.1818 +        if (aCreatePluginList) {
  1.1819 +          invalidPlugins->mSeen = true;
  1.1820 +        }
  1.1821 +        isKnownInvalidPlugin = true;
  1.1822 +        break;
  1.1823 +      }
  1.1824 +    }
  1.1825 +    if (isKnownInvalidPlugin) {
  1.1826 +      continue;
  1.1827 +    }
  1.1828 +
  1.1829 +    if (GhettoBlacklist(localfile)) {
  1.1830 +        continue;
  1.1831 +    }
  1.1832 +
  1.1833 +    // if it is not found in cache info list or has been changed, create a new one
  1.1834 +    if (!pluginTag) {
  1.1835 +      nsPluginFile pluginFile(localfile);
  1.1836 +
  1.1837 +      // create a tag describing this plugin.
  1.1838 +      PRLibrary *library = nullptr;
  1.1839 +      nsPluginInfo info;
  1.1840 +      memset(&info, 0, sizeof(info));
  1.1841 +      nsresult res;
  1.1842 +      // Opening a block for the telemetry AutoTimer
  1.1843 +      {
  1.1844 +        Telemetry::AutoTimer<Telemetry::PLUGIN_LOAD_METADATA> telemetry;
  1.1845 +        res = pluginFile.GetPluginInfo(info, &library);
  1.1846 +      }
  1.1847 +      // if we don't have mime type don't proceed, this is not a plugin
  1.1848 +      if (NS_FAILED(res) || !info.fMimeTypeArray) {
  1.1849 +        nsRefPtr<nsInvalidPluginTag> invalidTag = new nsInvalidPluginTag(filePath.get(),
  1.1850 +                                                                         fileModTime);
  1.1851 +        pluginFile.FreePluginInfo(info);
  1.1852 +
  1.1853 +        if (aCreatePluginList) {
  1.1854 +          invalidTag->mSeen = true;
  1.1855 +        }
  1.1856 +        invalidTag->mNext = mInvalidPlugins;
  1.1857 +        if (mInvalidPlugins) {
  1.1858 +          mInvalidPlugins->mPrev = invalidTag;
  1.1859 +        }
  1.1860 +        mInvalidPlugins = invalidTag;
  1.1861 +
  1.1862 +        // Mark aPluginsChanged so pluginreg is rewritten
  1.1863 +        *aPluginsChanged = true;
  1.1864 +        continue;
  1.1865 +      }
  1.1866 +
  1.1867 +      pluginTag = new nsPluginTag(&info, fileModTime, fromExtension);
  1.1868 +      pluginFile.FreePluginInfo(info);
  1.1869 +      if (!pluginTag)
  1.1870 +        return NS_ERROR_OUT_OF_MEMORY;
  1.1871 +
  1.1872 +      pluginTag->mLibrary = library;
  1.1873 +      uint32_t state = pluginTag->GetBlocklistState();
  1.1874 +
  1.1875 +      // If the blocklist says it is risky and we have never seen this
  1.1876 +      // plugin before, then disable it.
  1.1877 +      // If the blocklist says this is an outdated plugin, warn about
  1.1878 +      // outdated plugins.
  1.1879 +      if (state == nsIBlocklistService::STATE_SOFTBLOCKED && !seenBefore) {
  1.1880 +        pluginTag->SetEnabledState(nsIPluginTag::STATE_DISABLED);
  1.1881 +      }
  1.1882 +      if (state == nsIBlocklistService::STATE_OUTDATED && !seenBefore) {
  1.1883 +        warnOutdated = true;
  1.1884 +      }
  1.1885 +
  1.1886 +      // Plugin unloading is tag-based. If we created a new tag and loaded
  1.1887 +      // the library in the process then we want to attempt to unload it here.
  1.1888 +      // Only do this if the pref is set for aggressive unloading.
  1.1889 +      if (UnloadPluginsASAP()) {
  1.1890 +        pluginTag->TryUnloadPlugin(false);
  1.1891 +      }
  1.1892 +    }
  1.1893 +
  1.1894 +    // do it if we still want it
  1.1895 +    if (!seenBefore) {
  1.1896 +      // We have a valid new plugin so report that plugins have changed.
  1.1897 +      *aPluginsChanged = true;
  1.1898 +    }
  1.1899 +
  1.1900 +    // Avoid adding different versions of the same plugin if they are running 
  1.1901 +    // in-process, otherwise we risk undefined behaviour.
  1.1902 +    if (!nsNPAPIPlugin::RunPluginOOP(pluginTag)) {
  1.1903 +      if (HaveSamePlugin(pluginTag)) {
  1.1904 +        continue;
  1.1905 +      }
  1.1906 +    }
  1.1907 +
  1.1908 +    // Don't add the same plugin again if it hasn't changed
  1.1909 +    if (nsPluginTag* duplicate = FirstPluginWithPath(pluginTag->mFullPath)) {
  1.1910 +      if (pluginTag->mLastModifiedTime == duplicate->mLastModifiedTime) {
  1.1911 +        continue;
  1.1912 +      }
  1.1913 +    }
  1.1914 +
  1.1915 +    // If we're not creating a plugin list, simply looking for changes,
  1.1916 +    // then we're done.
  1.1917 +    if (!aCreatePluginList) {
  1.1918 +      return NS_OK;
  1.1919 +    }
  1.1920 +
  1.1921 +    // Add plugin tags such that the list is ordered by modification date,
  1.1922 +    // newest to oldest. This is ugly, it'd be easier with just about anything
  1.1923 +    // other than a single-directional linked list.
  1.1924 +    if (mPlugins) {
  1.1925 +      nsPluginTag *prev = nullptr;
  1.1926 +      nsPluginTag *next = mPlugins;
  1.1927 +      while (next) {
  1.1928 +        if (pluginTag->mLastModifiedTime >= next->mLastModifiedTime) {
  1.1929 +          pluginTag->mNext = next;
  1.1930 +          if (prev) {
  1.1931 +            prev->mNext = pluginTag;
  1.1932 +          } else {
  1.1933 +            mPlugins = pluginTag;
  1.1934 +          }
  1.1935 +          break;
  1.1936 +        }
  1.1937 +        prev = next;
  1.1938 +        next = prev->mNext;
  1.1939 +        if (!next) {
  1.1940 +          prev->mNext = pluginTag;
  1.1941 +        }
  1.1942 +      }
  1.1943 +    } else {
  1.1944 +      mPlugins = pluginTag;
  1.1945 +    }
  1.1946 +
  1.1947 +    if (pluginTag->IsActive()) {
  1.1948 +      nsAdoptingCString disableFullPage =
  1.1949 +        Preferences::GetCString(kPrefDisableFullPage);
  1.1950 +      for (uint32_t i = 0; i < pluginTag->mMimeTypes.Length(); i++) {
  1.1951 +        if (!IsTypeInList(pluginTag->mMimeTypes[i], disableFullPage)) {
  1.1952 +          RegisterWithCategoryManager(pluginTag->mMimeTypes[i],
  1.1953 +                                      ePluginRegister);
  1.1954 +        }
  1.1955 +      }
  1.1956 +    }
  1.1957 +  }
  1.1958 +
  1.1959 +  if (warnOutdated) {
  1.1960 +    Preferences::SetBool("plugins.update.notifyUser", true);
  1.1961 +  }
  1.1962 +
  1.1963 +  return NS_OK;
  1.1964 +}
  1.1965 +
  1.1966 +nsresult nsPluginHost::ScanPluginsDirectoryList(nsISimpleEnumerator *dirEnum,
  1.1967 +                                                bool aCreatePluginList,
  1.1968 +                                                bool *aPluginsChanged)
  1.1969 +{
  1.1970 +    bool hasMore;
  1.1971 +    while (NS_SUCCEEDED(dirEnum->HasMoreElements(&hasMore)) && hasMore) {
  1.1972 +      nsCOMPtr<nsISupports> supports;
  1.1973 +      nsresult rv = dirEnum->GetNext(getter_AddRefs(supports));
  1.1974 +      if (NS_FAILED(rv))
  1.1975 +        continue;
  1.1976 +      nsCOMPtr<nsIFile> nextDir(do_QueryInterface(supports, &rv));
  1.1977 +      if (NS_FAILED(rv))
  1.1978 +        continue;
  1.1979 +
  1.1980 +      // don't pass aPluginsChanged directly to prevent it from been reset
  1.1981 +      bool pluginschanged = false;
  1.1982 +      ScanPluginsDirectory(nextDir, aCreatePluginList, &pluginschanged);
  1.1983 +
  1.1984 +      if (pluginschanged)
  1.1985 +        *aPluginsChanged = true;
  1.1986 +
  1.1987 +      // if changes are detected and we are not creating the list, do not proceed
  1.1988 +      if (!aCreatePluginList && *aPluginsChanged)
  1.1989 +        break;
  1.1990 +    }
  1.1991 +    return NS_OK;
  1.1992 +}
  1.1993 +
  1.1994 +nsresult nsPluginHost::LoadPlugins()
  1.1995 +{
  1.1996 +#ifdef ANDROID
  1.1997 +  if (XRE_GetProcessType() == GeckoProcessType_Content) {
  1.1998 +    return NS_OK;
  1.1999 +  }
  1.2000 +#endif
  1.2001 +  // do not do anything if it is already done
  1.2002 +  // use ReloadPlugins() to enforce loading
  1.2003 +  if (mPluginsLoaded)
  1.2004 +    return NS_OK;
  1.2005 +
  1.2006 +  if (mPluginsDisabled)
  1.2007 +    return NS_OK;
  1.2008 +
  1.2009 +  bool pluginschanged;
  1.2010 +  nsresult rv = FindPlugins(true, &pluginschanged);
  1.2011 +  if (NS_FAILED(rv))
  1.2012 +    return rv;
  1.2013 +
  1.2014 +  // only if plugins have changed will we notify plugin-change observers
  1.2015 +  if (pluginschanged) {
  1.2016 +    nsCOMPtr<nsIObserverService> obsService =
  1.2017 +      mozilla::services::GetObserverService();
  1.2018 +    if (obsService)
  1.2019 +      obsService->NotifyObservers(nullptr, "plugins-list-updated", nullptr);
  1.2020 +  }
  1.2021 +
  1.2022 +  return NS_OK;
  1.2023 +}
  1.2024 +
  1.2025 +// if aCreatePluginList is false we will just scan for plugins
  1.2026 +// and see if any changes have been made to the plugins.
  1.2027 +// This is needed in ReloadPlugins to prevent possible recursive reloads
  1.2028 +nsresult nsPluginHost::FindPlugins(bool aCreatePluginList, bool * aPluginsChanged)
  1.2029 +{
  1.2030 +  Telemetry::AutoTimer<Telemetry::FIND_PLUGINS> telemetry;
  1.2031 +
  1.2032 +  NS_ENSURE_ARG_POINTER(aPluginsChanged);
  1.2033 +
  1.2034 +  *aPluginsChanged = false;
  1.2035 +  nsresult rv;
  1.2036 +
  1.2037 +  // Read cached plugins info. If the profile isn't yet available then don't
  1.2038 +  // scan for plugins
  1.2039 +  if (ReadPluginInfo() == NS_ERROR_NOT_AVAILABLE)
  1.2040 +    return NS_OK;
  1.2041 +
  1.2042 +#ifdef XP_WIN
  1.2043 +  // Failure here is not a show-stopper so just warn.
  1.2044 +  rv = EnsurePrivateDirServiceProvider();
  1.2045 +  NS_ASSERTION(NS_SUCCEEDED(rv), "Failed to register dir service provider.");
  1.2046 +#endif /* XP_WIN */
  1.2047 +
  1.2048 +  nsCOMPtr<nsIProperties> dirService(do_GetService(kDirectoryServiceContractID, &rv));
  1.2049 +  if (NS_FAILED(rv))
  1.2050 +    return rv;
  1.2051 +
  1.2052 +  nsCOMPtr<nsISimpleEnumerator> dirList;
  1.2053 +
  1.2054 +  // Scan plugins directories;
  1.2055 +  // don't pass aPluginsChanged directly, to prevent its
  1.2056 +  // possible reset in subsequent ScanPluginsDirectory calls
  1.2057 +  bool pluginschanged = false;
  1.2058 +
  1.2059 +  // Scan the app-defined list of plugin dirs.
  1.2060 +  rv = dirService->Get(NS_APP_PLUGINS_DIR_LIST, NS_GET_IID(nsISimpleEnumerator), getter_AddRefs(dirList));
  1.2061 +  if (NS_SUCCEEDED(rv)) {
  1.2062 +    ScanPluginsDirectoryList(dirList, aCreatePluginList, &pluginschanged);
  1.2063 +
  1.2064 +    if (pluginschanged)
  1.2065 +      *aPluginsChanged = true;
  1.2066 +
  1.2067 +    // if we are just looking for possible changes,
  1.2068 +    // no need to proceed if changes are detected
  1.2069 +    if (!aCreatePluginList && *aPluginsChanged) {
  1.2070 +      NS_ITERATIVE_UNREF_LIST(nsRefPtr<nsPluginTag>, mCachedPlugins, mNext);
  1.2071 +      NS_ITERATIVE_UNREF_LIST(nsRefPtr<nsInvalidPluginTag>, mInvalidPlugins, mNext);
  1.2072 +      return NS_OK;
  1.2073 +    }
  1.2074 +  } else {
  1.2075 +#ifdef ANDROID
  1.2076 +    LOG("getting plugins dir failed");
  1.2077 +#endif
  1.2078 +  }
  1.2079 +
  1.2080 +  mPluginsLoaded = true; // at this point 'some' plugins have been loaded,
  1.2081 +                            // the rest is optional
  1.2082 +
  1.2083 +#ifdef XP_WIN
  1.2084 +  bool bScanPLIDs = Preferences::GetBool("plugin.scan.plid.all", false);
  1.2085 +
  1.2086 +    // Now lets scan any PLID directories
  1.2087 +  if (bScanPLIDs && mPrivateDirServiceProvider) {
  1.2088 +    rv = mPrivateDirServiceProvider->GetPLIDDirectories(getter_AddRefs(dirList));
  1.2089 +    if (NS_SUCCEEDED(rv)) {
  1.2090 +      ScanPluginsDirectoryList(dirList, aCreatePluginList, &pluginschanged);
  1.2091 +
  1.2092 +      if (pluginschanged)
  1.2093 +        *aPluginsChanged = true;
  1.2094 +
  1.2095 +      // if we are just looking for possible changes,
  1.2096 +      // no need to proceed if changes are detected
  1.2097 +      if (!aCreatePluginList && *aPluginsChanged) {
  1.2098 +        NS_ITERATIVE_UNREF_LIST(nsRefPtr<nsPluginTag>, mCachedPlugins, mNext);
  1.2099 +        NS_ITERATIVE_UNREF_LIST(nsRefPtr<nsInvalidPluginTag>, mInvalidPlugins, mNext);
  1.2100 +        return NS_OK;
  1.2101 +      }
  1.2102 +    }
  1.2103 +  }
  1.2104 +
  1.2105 +
  1.2106 +  // Scan the installation paths of our popular plugins if the prefs are enabled
  1.2107 +
  1.2108 +  // This table controls the order of scanning
  1.2109 +  const char* const prefs[] = {NS_WIN_ACROBAT_SCAN_KEY,
  1.2110 +                               NS_WIN_QUICKTIME_SCAN_KEY,
  1.2111 +                               NS_WIN_WMP_SCAN_KEY};
  1.2112 +
  1.2113 +  uint32_t size = sizeof(prefs) / sizeof(prefs[0]);
  1.2114 +
  1.2115 +  for (uint32_t i = 0; i < size; i+=1) {
  1.2116 +    nsCOMPtr<nsIFile> dirToScan;
  1.2117 +    bool bExists;
  1.2118 +    if (NS_SUCCEEDED(dirService->Get(prefs[i], NS_GET_IID(nsIFile), getter_AddRefs(dirToScan))) &&
  1.2119 +        dirToScan &&
  1.2120 +        NS_SUCCEEDED(dirToScan->Exists(&bExists)) &&
  1.2121 +        bExists) {
  1.2122 +
  1.2123 +      ScanPluginsDirectory(dirToScan, aCreatePluginList, &pluginschanged);
  1.2124 +
  1.2125 +      if (pluginschanged)
  1.2126 +        *aPluginsChanged = true;
  1.2127 +
  1.2128 +      // if we are just looking for possible changes,
  1.2129 +      // no need to proceed if changes are detected
  1.2130 +      if (!aCreatePluginList && *aPluginsChanged) {
  1.2131 +        NS_ITERATIVE_UNREF_LIST(nsRefPtr<nsPluginTag>, mCachedPlugins, mNext);
  1.2132 +        NS_ITERATIVE_UNREF_LIST(nsRefPtr<nsInvalidPluginTag>, mInvalidPlugins, mNext);
  1.2133 +        return NS_OK;
  1.2134 +      }
  1.2135 +    }
  1.2136 +  }
  1.2137 +#endif
  1.2138 +
  1.2139 +  // We should also consider plugins to have changed if any plugins have been removed.
  1.2140 +  // We'll know if any were removed if they weren't taken out of the cached plugins list
  1.2141 +  // during our scan, thus we can assume something was removed if the cached plugins list
  1.2142 +  // contains anything.
  1.2143 +  if (!*aPluginsChanged && mCachedPlugins) {
  1.2144 +    *aPluginsChanged = true;
  1.2145 +  }
  1.2146 +
  1.2147 +  // Remove unseen invalid plugins
  1.2148 +  nsRefPtr<nsInvalidPluginTag> invalidPlugins = mInvalidPlugins;
  1.2149 +  while (invalidPlugins) {
  1.2150 +    if (!invalidPlugins->mSeen) {
  1.2151 +      nsRefPtr<nsInvalidPluginTag> invalidPlugin = invalidPlugins;
  1.2152 +
  1.2153 +      if (invalidPlugin->mPrev) {
  1.2154 +        invalidPlugin->mPrev->mNext = invalidPlugin->mNext;
  1.2155 +      }
  1.2156 +      else {
  1.2157 +        mInvalidPlugins = invalidPlugin->mNext;
  1.2158 +      }
  1.2159 +      if (invalidPlugin->mNext) {
  1.2160 +        invalidPlugin->mNext->mPrev = invalidPlugin->mPrev;
  1.2161 +      }
  1.2162 +
  1.2163 +      invalidPlugins = invalidPlugin->mNext;
  1.2164 +
  1.2165 +      invalidPlugin->mPrev = nullptr;
  1.2166 +      invalidPlugin->mNext = nullptr;
  1.2167 +    }
  1.2168 +    else {
  1.2169 +      invalidPlugins->mSeen = false;
  1.2170 +      invalidPlugins = invalidPlugins->mNext;
  1.2171 +    }
  1.2172 +  }
  1.2173 +
  1.2174 +  // if we are not creating the list, there is no need to proceed
  1.2175 +  if (!aCreatePluginList) {
  1.2176 +    NS_ITERATIVE_UNREF_LIST(nsRefPtr<nsPluginTag>, mCachedPlugins, mNext);
  1.2177 +    NS_ITERATIVE_UNREF_LIST(nsRefPtr<nsInvalidPluginTag>, mInvalidPlugins, mNext);
  1.2178 +    return NS_OK;
  1.2179 +  }
  1.2180 +
  1.2181 +  // if we are creating the list, it is already done;
  1.2182 +  // update the plugins info cache if changes are detected
  1.2183 +  if (*aPluginsChanged)
  1.2184 +    WritePluginInfo();
  1.2185 +
  1.2186 +  // No more need for cached plugins. Clear it up.
  1.2187 +  NS_ITERATIVE_UNREF_LIST(nsRefPtr<nsPluginTag>, mCachedPlugins, mNext);
  1.2188 +  NS_ITERATIVE_UNREF_LIST(nsRefPtr<nsInvalidPluginTag>, mInvalidPlugins, mNext);
  1.2189 +
  1.2190 +  return NS_OK;
  1.2191 +}
  1.2192 +
  1.2193 +nsresult
  1.2194 +nsPluginHost::UpdatePluginInfo(nsPluginTag* aPluginTag)
  1.2195 +{
  1.2196 +  ReadPluginInfo();
  1.2197 +  WritePluginInfo();
  1.2198 +  NS_ITERATIVE_UNREF_LIST(nsRefPtr<nsPluginTag>, mCachedPlugins, mNext);
  1.2199 +  NS_ITERATIVE_UNREF_LIST(nsRefPtr<nsInvalidPluginTag>, mInvalidPlugins, mNext);
  1.2200 +
  1.2201 +  if (!aPluginTag) {
  1.2202 +    return NS_OK;
  1.2203 +  }
  1.2204 +
  1.2205 +  // Update types with category manager
  1.2206 +  nsAdoptingCString disableFullPage =
  1.2207 +    Preferences::GetCString(kPrefDisableFullPage);
  1.2208 +  for (uint32_t i = 0; i < aPluginTag->mMimeTypes.Length(); i++) {
  1.2209 +    nsRegisterType shouldRegister;
  1.2210 +
  1.2211 +    if (IsTypeInList(aPluginTag->mMimeTypes[i], disableFullPage)) {
  1.2212 +      shouldRegister = ePluginUnregister;
  1.2213 +    } else {
  1.2214 +      nsPluginTag *plugin = FindPluginForType(aPluginTag->mMimeTypes[i].get(),
  1.2215 +                                              true);
  1.2216 +      shouldRegister = plugin ? ePluginRegister : ePluginUnregister;
  1.2217 +    }
  1.2218 +
  1.2219 +    RegisterWithCategoryManager(aPluginTag->mMimeTypes[i], shouldRegister);
  1.2220 +  }
  1.2221 +
  1.2222 +  nsCOMPtr<nsIObserverService> obsService =
  1.2223 +    mozilla::services::GetObserverService();
  1.2224 +  if (obsService)
  1.2225 +    obsService->NotifyObservers(nullptr, "plugin-info-updated", nullptr);
  1.2226 +
  1.2227 +  // Reload instances if needed
  1.2228 +  if (aPluginTag->IsActive()) {
  1.2229 +    return NS_OK;
  1.2230 +  }
  1.2231 +
  1.2232 +  return NS_OK;
  1.2233 +}
  1.2234 +
  1.2235 +/* static */ bool
  1.2236 +nsPluginHost::IsTypeWhitelisted(const char *aMimeType)
  1.2237 +{
  1.2238 +  nsAdoptingCString whitelist = Preferences::GetCString(kPrefWhitelist);
  1.2239 +  if (!whitelist.Length()) {
  1.2240 +    return true;
  1.2241 +  }
  1.2242 +  nsDependentCString wrap(aMimeType);
  1.2243 +  return IsTypeInList(wrap, whitelist);
  1.2244 +}
  1.2245 +
  1.2246 +void
  1.2247 +nsPluginHost::RegisterWithCategoryManager(nsCString &aMimeType,
  1.2248 +                                          nsRegisterType aType)
  1.2249 +{
  1.2250 +  PLUGIN_LOG(PLUGIN_LOG_NORMAL,
  1.2251 +             ("nsPluginTag::RegisterWithCategoryManager type = %s, removing = %s\n",
  1.2252 +              aMimeType.get(), aType == ePluginUnregister ? "yes" : "no"));
  1.2253 +
  1.2254 +  nsCOMPtr<nsICategoryManager> catMan =
  1.2255 +    do_GetService(NS_CATEGORYMANAGER_CONTRACTID);
  1.2256 +  if (!catMan) {
  1.2257 +    return;
  1.2258 +  }
  1.2259 +
  1.2260 +  const char *contractId =
  1.2261 +    "@mozilla.org/content/plugin/document-loader-factory;1";
  1.2262 +
  1.2263 +  if (aType == ePluginRegister) {
  1.2264 +    catMan->AddCategoryEntry("Gecko-Content-Viewers",
  1.2265 +                             aMimeType.get(),
  1.2266 +                             contractId,
  1.2267 +                             false, /* persist: broken by bug 193031 */
  1.2268 +                             mOverrideInternalTypes,
  1.2269 +                             nullptr);
  1.2270 +  } else {
  1.2271 +    // Only delete the entry if a plugin registered for it
  1.2272 +    nsXPIDLCString value;
  1.2273 +    nsresult rv = catMan->GetCategoryEntry("Gecko-Content-Viewers",
  1.2274 +                                           aMimeType.get(),
  1.2275 +                                           getter_Copies(value));
  1.2276 +    if (NS_SUCCEEDED(rv) && strcmp(value, contractId) == 0) {
  1.2277 +      catMan->DeleteCategoryEntry("Gecko-Content-Viewers",
  1.2278 +                                  aMimeType.get(),
  1.2279 +                                  true);
  1.2280 +    }
  1.2281 +  }
  1.2282 +}
  1.2283 +
  1.2284 +nsresult
  1.2285 +nsPluginHost::WritePluginInfo()
  1.2286 +{
  1.2287 +
  1.2288 +  nsresult rv = NS_OK;
  1.2289 +  nsCOMPtr<nsIProperties> directoryService(do_GetService(NS_DIRECTORY_SERVICE_CONTRACTID,&rv));
  1.2290 +  if (NS_FAILED(rv))
  1.2291 +    return rv;
  1.2292 +
  1.2293 +  directoryService->Get(NS_APP_USER_PROFILE_50_DIR, NS_GET_IID(nsIFile),
  1.2294 +                        getter_AddRefs(mPluginRegFile));
  1.2295 +
  1.2296 +  if (!mPluginRegFile)
  1.2297 +    return NS_ERROR_FAILURE;
  1.2298 +
  1.2299 +  PRFileDesc* fd = nullptr;
  1.2300 +
  1.2301 +  nsCOMPtr<nsIFile> pluginReg;
  1.2302 +
  1.2303 +  rv = mPluginRegFile->Clone(getter_AddRefs(pluginReg));
  1.2304 +  if (NS_FAILED(rv))
  1.2305 +    return rv;
  1.2306 +
  1.2307 +  nsAutoCString filename(kPluginRegistryFilename);
  1.2308 +  filename.Append(".tmp");
  1.2309 +  rv = pluginReg->AppendNative(filename);
  1.2310 +  if (NS_FAILED(rv))
  1.2311 +    return rv;
  1.2312 +
  1.2313 +  rv = pluginReg->OpenNSPRFileDesc(PR_WRONLY | PR_CREATE_FILE | PR_TRUNCATE, 0600, &fd);
  1.2314 +  if (NS_FAILED(rv))
  1.2315 +    return rv;
  1.2316 +
  1.2317 +  nsCOMPtr<nsIXULRuntime> runtime = do_GetService("@mozilla.org/xre/runtime;1");
  1.2318 +  if (!runtime) {
  1.2319 +    return NS_ERROR_FAILURE;
  1.2320 +  }
  1.2321 +
  1.2322 +  nsAutoCString arch;
  1.2323 +  rv = runtime->GetXPCOMABI(arch);
  1.2324 +  if (NS_FAILED(rv)) {
  1.2325 +    return rv;
  1.2326 +  }
  1.2327 +
  1.2328 +  PR_fprintf(fd, "Generated File. Do not edit.\n");
  1.2329 +
  1.2330 +  PR_fprintf(fd, "\n[HEADER]\nVersion%c%s%c%c\nArch%c%s%c%c\n",
  1.2331 +             PLUGIN_REGISTRY_FIELD_DELIMITER,
  1.2332 +             kPluginRegistryVersion,
  1.2333 +             PLUGIN_REGISTRY_FIELD_DELIMITER,
  1.2334 +             PLUGIN_REGISTRY_END_OF_LINE_MARKER,
  1.2335 +             PLUGIN_REGISTRY_FIELD_DELIMITER,
  1.2336 +             arch.get(),
  1.2337 +             PLUGIN_REGISTRY_FIELD_DELIMITER,
  1.2338 +             PLUGIN_REGISTRY_END_OF_LINE_MARKER);
  1.2339 +
  1.2340 +  // Store all plugins in the mPlugins list - all plugins currently in use.
  1.2341 +  PR_fprintf(fd, "\n[PLUGINS]\n");
  1.2342 +
  1.2343 +  for (nsPluginTag *tag = mPlugins; tag; tag = tag->mNext) {
  1.2344 +    // store each plugin info into the registry
  1.2345 +    // filename & fullpath are on separate line
  1.2346 +    // because they can contain field delimiter char
  1.2347 +    PR_fprintf(fd, "%s%c%c\n%s%c%c\n%s%c%c\n",
  1.2348 +      (tag->mFileName.get()),
  1.2349 +      PLUGIN_REGISTRY_FIELD_DELIMITER,
  1.2350 +      PLUGIN_REGISTRY_END_OF_LINE_MARKER,
  1.2351 +      (tag->mFullPath.get()),
  1.2352 +      PLUGIN_REGISTRY_FIELD_DELIMITER,
  1.2353 +      PLUGIN_REGISTRY_END_OF_LINE_MARKER,
  1.2354 +      (tag->mVersion.get()),
  1.2355 +      PLUGIN_REGISTRY_FIELD_DELIMITER,
  1.2356 +      PLUGIN_REGISTRY_END_OF_LINE_MARKER);
  1.2357 +
  1.2358 +    // lastModifiedTimeStamp|canUnload|tag->mFlags|fromExtension
  1.2359 +    PR_fprintf(fd, "%lld%c%d%c%lu%c%d%c%c\n",
  1.2360 +      tag->mLastModifiedTime,
  1.2361 +      PLUGIN_REGISTRY_FIELD_DELIMITER,
  1.2362 +      false, // did store whether or not to unload in-process plugins
  1.2363 +      PLUGIN_REGISTRY_FIELD_DELIMITER,
  1.2364 +      0, // legacy field for flags
  1.2365 +      PLUGIN_REGISTRY_FIELD_DELIMITER,
  1.2366 +      tag->IsFromExtension(),
  1.2367 +      PLUGIN_REGISTRY_FIELD_DELIMITER,
  1.2368 +      PLUGIN_REGISTRY_END_OF_LINE_MARKER);
  1.2369 +
  1.2370 +    //description, name & mtypecount are on separate line
  1.2371 +    PR_fprintf(fd, "%s%c%c\n%s%c%c\n%d\n",
  1.2372 +      (tag->mDescription.get()),
  1.2373 +      PLUGIN_REGISTRY_FIELD_DELIMITER,
  1.2374 +      PLUGIN_REGISTRY_END_OF_LINE_MARKER,
  1.2375 +      (tag->mName.get()),
  1.2376 +      PLUGIN_REGISTRY_FIELD_DELIMITER,
  1.2377 +      PLUGIN_REGISTRY_END_OF_LINE_MARKER,
  1.2378 +      tag->mMimeTypes.Length());
  1.2379 +
  1.2380 +    // Add in each mimetype this plugin supports
  1.2381 +    for (uint32_t i = 0; i < tag->mMimeTypes.Length(); i++) {
  1.2382 +      PR_fprintf(fd, "%d%c%s%c%s%c%s%c%c\n",
  1.2383 +        i,PLUGIN_REGISTRY_FIELD_DELIMITER,
  1.2384 +        (tag->mMimeTypes[i].get()),
  1.2385 +        PLUGIN_REGISTRY_FIELD_DELIMITER,
  1.2386 +        (tag->mMimeDescriptions[i].get()),
  1.2387 +        PLUGIN_REGISTRY_FIELD_DELIMITER,
  1.2388 +        (tag->mExtensions[i].get()),
  1.2389 +        PLUGIN_REGISTRY_FIELD_DELIMITER,
  1.2390 +        PLUGIN_REGISTRY_END_OF_LINE_MARKER);
  1.2391 +    }
  1.2392 +  }
  1.2393 +
  1.2394 +  PR_fprintf(fd, "\n[INVALID]\n");
  1.2395 +
  1.2396 +  nsRefPtr<nsInvalidPluginTag> invalidPlugins = mInvalidPlugins;
  1.2397 +  while (invalidPlugins) {
  1.2398 +    // fullPath
  1.2399 +    PR_fprintf(fd, "%s%c%c\n",
  1.2400 +      (!invalidPlugins->mFullPath.IsEmpty() ? invalidPlugins->mFullPath.get() : ""),
  1.2401 +      PLUGIN_REGISTRY_FIELD_DELIMITER,
  1.2402 +      PLUGIN_REGISTRY_END_OF_LINE_MARKER);
  1.2403 +
  1.2404 +    // lastModifiedTimeStamp
  1.2405 +    PR_fprintf(fd, "%lld%c%c\n",
  1.2406 +      invalidPlugins->mLastModifiedTime,
  1.2407 +      PLUGIN_REGISTRY_FIELD_DELIMITER,
  1.2408 +      PLUGIN_REGISTRY_END_OF_LINE_MARKER);
  1.2409 +
  1.2410 +    invalidPlugins = invalidPlugins->mNext;
  1.2411 +  }
  1.2412 +
  1.2413 +  PRStatus prrc;
  1.2414 +  prrc = PR_Close(fd);
  1.2415 +  if (prrc != PR_SUCCESS) {
  1.2416 +    // we should obtain a refined value based on prrc;
  1.2417 +    rv = NS_ERROR_FAILURE;
  1.2418 +    MOZ_ASSERT(false, "PR_Close() failed.");
  1.2419 +    return rv;
  1.2420 +  }
  1.2421 +  nsCOMPtr<nsIFile> parent;
  1.2422 +  rv = pluginReg->GetParent(getter_AddRefs(parent));
  1.2423 +  NS_ENSURE_SUCCESS(rv, rv);
  1.2424 +  rv = pluginReg->MoveToNative(parent, kPluginRegistryFilename);
  1.2425 +  return rv;
  1.2426 +}
  1.2427 +
  1.2428 +nsresult
  1.2429 +nsPluginHost::ReadPluginInfo()
  1.2430 +{
  1.2431 +  const long PLUGIN_REG_MIMETYPES_ARRAY_SIZE = 12;
  1.2432 +  const long PLUGIN_REG_MAX_MIMETYPES = 1000;
  1.2433 +
  1.2434 +  // we need to import the legacy flags from the plugin registry once
  1.2435 +  const bool pluginStateImported =
  1.2436 +    Preferences::GetDefaultBool("plugin.importedState", false);
  1.2437 +
  1.2438 +  nsresult rv;
  1.2439 +
  1.2440 +  nsCOMPtr<nsIProperties> directoryService(do_GetService(NS_DIRECTORY_SERVICE_CONTRACTID,&rv));
  1.2441 +  if (NS_FAILED(rv))
  1.2442 +    return rv;
  1.2443 +
  1.2444 +  directoryService->Get(NS_APP_USER_PROFILE_50_DIR, NS_GET_IID(nsIFile),
  1.2445 +                        getter_AddRefs(mPluginRegFile));
  1.2446 +
  1.2447 +  if (!mPluginRegFile) {
  1.2448 +    // There is no profile yet, this will tell us if there is going to be one
  1.2449 +    // in the future.
  1.2450 +    directoryService->Get(NS_APP_PROFILE_DIR_STARTUP, NS_GET_IID(nsIFile),
  1.2451 +                          getter_AddRefs(mPluginRegFile));
  1.2452 +    if (!mPluginRegFile)
  1.2453 +      return NS_ERROR_FAILURE;
  1.2454 +    else
  1.2455 +      return NS_ERROR_NOT_AVAILABLE;
  1.2456 +  }
  1.2457 +
  1.2458 +  PRFileDesc* fd = nullptr;
  1.2459 +
  1.2460 +  nsCOMPtr<nsIFile> pluginReg;
  1.2461 +
  1.2462 +  rv = mPluginRegFile->Clone(getter_AddRefs(pluginReg));
  1.2463 +  if (NS_FAILED(rv))
  1.2464 +    return rv;
  1.2465 +
  1.2466 +  rv = pluginReg->AppendNative(kPluginRegistryFilename);
  1.2467 +  if (NS_FAILED(rv))
  1.2468 +    return rv;
  1.2469 +
  1.2470 +  int64_t fileSize;
  1.2471 +  rv = pluginReg->GetFileSize(&fileSize);
  1.2472 +  if (NS_FAILED(rv))
  1.2473 +    return rv;
  1.2474 +
  1.2475 +  if (fileSize > INT32_MAX) {
  1.2476 +    return NS_ERROR_FAILURE;
  1.2477 +  }
  1.2478 +  int32_t flen = int32_t(fileSize);
  1.2479 +  if (flen == 0) {
  1.2480 +    NS_WARNING("Plugins Registry Empty!");
  1.2481 +    return NS_OK; // ERROR CONDITION
  1.2482 +  }
  1.2483 +
  1.2484 +  nsPluginManifestLineReader reader;
  1.2485 +  char* registry = reader.Init(flen);
  1.2486 +  if (!registry)
  1.2487 +    return NS_ERROR_OUT_OF_MEMORY;
  1.2488 +
  1.2489 +  rv = pluginReg->OpenNSPRFileDesc(PR_RDONLY, 0444, &fd);
  1.2490 +  if (NS_FAILED(rv))
  1.2491 +    return rv;
  1.2492 +
  1.2493 +  // set rv to return an error on goto out
  1.2494 +  rv = NS_ERROR_FAILURE;
  1.2495 +
  1.2496 +  int32_t bread = PR_Read(fd, registry, flen);
  1.2497 +
  1.2498 +  PRStatus prrc;
  1.2499 +  prrc = PR_Close(fd);
  1.2500 +  if (prrc != PR_SUCCESS) {
  1.2501 +    // Strange error: this is one of those "Should not happen" error.
  1.2502 +    // we may want to report something more refined than  NS_ERROR_FAILURE.
  1.2503 +    MOZ_ASSERT(false, "PR_Close() failed.");
  1.2504 +    return rv;
  1.2505 +  }
  1.2506 +
  1.2507 +  if (flen > bread)
  1.2508 +    return rv;
  1.2509 +
  1.2510 +  if (!ReadSectionHeader(reader, "HEADER"))
  1.2511 +    return rv;;
  1.2512 +
  1.2513 +  if (!reader.NextLine())
  1.2514 +    return rv;
  1.2515 +
  1.2516 +  char* values[6];
  1.2517 +
  1.2518 +  // VersionLiteral, kPluginRegistryVersion
  1.2519 +  if (2 != reader.ParseLine(values, 2))
  1.2520 +    return rv;
  1.2521 +
  1.2522 +  // VersionLiteral
  1.2523 +  if (PL_strcmp(values[0], "Version"))
  1.2524 +    return rv;
  1.2525 +
  1.2526 +  // kPluginRegistryVersion
  1.2527 +  int32_t vdiff = mozilla::CompareVersions(values[1], kPluginRegistryVersion);
  1.2528 +  mozilla::Version version(values[1]);
  1.2529 +  // If this is a registry from some future version then don't attempt to read it
  1.2530 +  if (vdiff > 0)
  1.2531 +    return rv;
  1.2532 +  // If this is a registry from before the minimum then don't attempt to read it
  1.2533 +  if (version < kMinimumRegistryVersion)
  1.2534 +    return rv;
  1.2535 +
  1.2536 +  // Registry v0.10 and upwards includes the plugin version field
  1.2537 +  bool regHasVersion = (version >= "0.10");
  1.2538 +
  1.2539 +  // Registry v0.13 and upwards includes the architecture
  1.2540 +  if (version >= "0.13") {
  1.2541 +    char* archValues[6];
  1.2542 +
  1.2543 +    if (!reader.NextLine()) {
  1.2544 +      return rv;
  1.2545 +    }
  1.2546 +
  1.2547 +    // ArchLiteral, Architecture
  1.2548 +    if (2 != reader.ParseLine(archValues, 2)) {
  1.2549 +      return rv;
  1.2550 +    }
  1.2551 +
  1.2552 +    // ArchLiteral
  1.2553 +    if (PL_strcmp(archValues[0], "Arch")) {
  1.2554 +      return rv;
  1.2555 +    }
  1.2556 +
  1.2557 +    nsCOMPtr<nsIXULRuntime> runtime = do_GetService("@mozilla.org/xre/runtime;1");
  1.2558 +    if (!runtime) {
  1.2559 +      return rv;
  1.2560 +    }
  1.2561 +
  1.2562 +    nsAutoCString arch;
  1.2563 +    if (NS_FAILED(runtime->GetXPCOMABI(arch))) {
  1.2564 +      return rv;
  1.2565 +    }
  1.2566 +
  1.2567 +    // If this is a registry from a different architecture then don't attempt to read it
  1.2568 +    if (PL_strcmp(archValues[1], arch.get())) {
  1.2569 +      return rv;
  1.2570 +    }
  1.2571 +  }
  1.2572 +
  1.2573 +  // Registry v0.13 and upwards includes the list of invalid plugins
  1.2574 +  const bool hasInvalidPlugins = (version >= "0.13");
  1.2575 +
  1.2576 +  // Registry v0.16 and upwards always have 0 for their plugin flags, prefs are used instead
  1.2577 +  const bool hasValidFlags = (version < "0.16");
  1.2578 +
  1.2579 +  // Registry v0.17 and upwards store whether the plugin comes from an XPI.
  1.2580 +  const bool hasFromExtension = (version >= "0.17");
  1.2581 +
  1.2582 +#if defined(XP_MACOSX)
  1.2583 +  const bool hasFullPathInFileNameField = false;
  1.2584 +#else
  1.2585 +  const bool hasFullPathInFileNameField = (version < "0.11");
  1.2586 +#endif
  1.2587 +
  1.2588 +  if (!ReadSectionHeader(reader, "PLUGINS"))
  1.2589 +    return rv;
  1.2590 +
  1.2591 +  while (reader.NextLine()) {
  1.2592 +    const char *filename;
  1.2593 +    const char *fullpath;
  1.2594 +    nsAutoCString derivedFileName;
  1.2595 +
  1.2596 +    if (hasInvalidPlugins && *reader.LinePtr() == '[') {
  1.2597 +      break;
  1.2598 +    }
  1.2599 +
  1.2600 +    if (hasFullPathInFileNameField) {
  1.2601 +      fullpath = reader.LinePtr();
  1.2602 +      if (!reader.NextLine())
  1.2603 +        return rv;
  1.2604 +      // try to derive a file name from the full path
  1.2605 +      if (fullpath) {
  1.2606 +        nsCOMPtr<nsIFile> file = do_CreateInstance("@mozilla.org/file/local;1");
  1.2607 +        file->InitWithNativePath(nsDependentCString(fullpath));
  1.2608 +        file->GetNativeLeafName(derivedFileName);
  1.2609 +        filename = derivedFileName.get();
  1.2610 +      } else {
  1.2611 +        filename = nullptr;
  1.2612 +      }
  1.2613 +
  1.2614 +      // skip the next line, useless in this version
  1.2615 +      if (!reader.NextLine())
  1.2616 +        return rv;
  1.2617 +    } else {
  1.2618 +      filename = reader.LinePtr();
  1.2619 +      if (!reader.NextLine())
  1.2620 +        return rv;
  1.2621 +
  1.2622 +      fullpath = reader.LinePtr();
  1.2623 +      if (!reader.NextLine())
  1.2624 +        return rv;
  1.2625 +    }
  1.2626 +
  1.2627 +    const char *version;
  1.2628 +    if (regHasVersion) {
  1.2629 +      version = reader.LinePtr();
  1.2630 +      if (!reader.NextLine())
  1.2631 +        return rv;
  1.2632 +    } else {
  1.2633 +      version = "0";
  1.2634 +    }
  1.2635 +
  1.2636 +    // lastModifiedTimeStamp|canUnload|tag.mFlag|fromExtension
  1.2637 +    const int count = hasFromExtension ? 4 : 3;
  1.2638 +    if (reader.ParseLine(values, count) != count)
  1.2639 +      return rv;
  1.2640 +
  1.2641 +    // If this is an old plugin registry mark this plugin tag to be refreshed
  1.2642 +    int64_t lastmod = (vdiff == 0) ? nsCRT::atoll(values[0]) : -1;
  1.2643 +    uint32_t tagflag = atoi(values[2]);
  1.2644 +    bool fromExtension = false;
  1.2645 +    if (hasFromExtension) {
  1.2646 +      fromExtension = atoi(values[3]);
  1.2647 +    }
  1.2648 +    if (!reader.NextLine())
  1.2649 +      return rv;
  1.2650 +
  1.2651 +    char *description = reader.LinePtr();
  1.2652 +    if (!reader.NextLine())
  1.2653 +      return rv;
  1.2654 +
  1.2655 +#if MOZ_WIDGET_ANDROID
  1.2656 +    // Flash on Android does not populate the version field, but it is tacked on to the description.
  1.2657 +    // For example, "Shockwave Flash 11.1 r115"
  1.2658 +    if (PL_strncmp("Shockwave Flash ", description, 16) == 0 && description[16]) {
  1.2659 +      version = &description[16];
  1.2660 +    }
  1.2661 +#endif
  1.2662 +
  1.2663 +    const char *name = reader.LinePtr();
  1.2664 +    if (!reader.NextLine())
  1.2665 +      return rv;
  1.2666 +
  1.2667 +    long mimetypecount = std::strtol(reader.LinePtr(), nullptr, 10);
  1.2668 +    if (mimetypecount == LONG_MAX || mimetypecount == LONG_MIN ||
  1.2669 +        mimetypecount >= PLUGIN_REG_MAX_MIMETYPES || mimetypecount < 0) {
  1.2670 +      return NS_ERROR_FAILURE;
  1.2671 +    }
  1.2672 +
  1.2673 +    char *stackalloced[PLUGIN_REG_MIMETYPES_ARRAY_SIZE * 3];
  1.2674 +    char **mimetypes;
  1.2675 +    char **mimedescriptions;
  1.2676 +    char **extensions;
  1.2677 +    char **heapalloced = 0;
  1.2678 +    if (mimetypecount > PLUGIN_REG_MIMETYPES_ARRAY_SIZE - 1) {
  1.2679 +      heapalloced = new char *[mimetypecount * 3];
  1.2680 +      mimetypes = heapalloced;
  1.2681 +    } else {
  1.2682 +      mimetypes = stackalloced;
  1.2683 +    }
  1.2684 +    mimedescriptions = mimetypes + mimetypecount;
  1.2685 +    extensions = mimedescriptions + mimetypecount;
  1.2686 +
  1.2687 +    int mtr = 0; //mimetype read
  1.2688 +    for (; mtr < mimetypecount; mtr++) {
  1.2689 +      if (!reader.NextLine())
  1.2690 +        break;
  1.2691 +
  1.2692 +      //line number|mimetype|description|extension
  1.2693 +      if (4 != reader.ParseLine(values, 4))
  1.2694 +        break;
  1.2695 +      int line = atoi(values[0]);
  1.2696 +      if (line != mtr)
  1.2697 +        break;
  1.2698 +      mimetypes[mtr] = values[1];
  1.2699 +      mimedescriptions[mtr] = values[2];
  1.2700 +      extensions[mtr] = values[3];
  1.2701 +    }
  1.2702 +
  1.2703 +    if (mtr != mimetypecount) {
  1.2704 +      if (heapalloced) {
  1.2705 +        delete [] heapalloced;
  1.2706 +      }
  1.2707 +      return rv;
  1.2708 +    }
  1.2709 +
  1.2710 +    nsRefPtr<nsPluginTag> tag = new nsPluginTag(name,
  1.2711 +      description,
  1.2712 +      filename,
  1.2713 +      fullpath,
  1.2714 +      version,
  1.2715 +      (const char* const*)mimetypes,
  1.2716 +      (const char* const*)mimedescriptions,
  1.2717 +      (const char* const*)extensions,
  1.2718 +      mimetypecount, lastmod, fromExtension, true);
  1.2719 +    if (heapalloced)
  1.2720 +      delete [] heapalloced;
  1.2721 +
  1.2722 +    // Import flags from registry into prefs for old registry versions
  1.2723 +    if (hasValidFlags && !pluginStateImported) {
  1.2724 +      tag->ImportFlagsToPrefs(tagflag);
  1.2725 +    }
  1.2726 +
  1.2727 +    PR_LOG(nsPluginLogging::gPluginLog, PLUGIN_LOG_BASIC,
  1.2728 +      ("LoadCachedPluginsInfo : Loading Cached plugininfo for %s\n", tag->mFileName.get()));
  1.2729 +    tag->mNext = mCachedPlugins;
  1.2730 +    mCachedPlugins = tag;
  1.2731 +  }
  1.2732 +
  1.2733 +// On Android we always want to try to load a plugin again (Flash). Bug 935676.
  1.2734 +#ifndef MOZ_WIDGET_ANDROID
  1.2735 +  if (hasInvalidPlugins) {
  1.2736 +    if (!ReadSectionHeader(reader, "INVALID")) {
  1.2737 +      return rv;
  1.2738 +    }
  1.2739 +
  1.2740 +    while (reader.NextLine()) {
  1.2741 +      const char *fullpath = reader.LinePtr();
  1.2742 +      if (!reader.NextLine()) {
  1.2743 +        return rv;
  1.2744 +      }
  1.2745 +
  1.2746 +      const char *lastModifiedTimeStamp = reader.LinePtr();
  1.2747 +      int64_t lastmod = (vdiff == 0) ? nsCRT::atoll(lastModifiedTimeStamp) : -1;
  1.2748 +
  1.2749 +      nsRefPtr<nsInvalidPluginTag> invalidTag = new nsInvalidPluginTag(fullpath, lastmod);
  1.2750 +
  1.2751 +      invalidTag->mNext = mInvalidPlugins;
  1.2752 +      if (mInvalidPlugins) {
  1.2753 +        mInvalidPlugins->mPrev = invalidTag;
  1.2754 +      }
  1.2755 +      mInvalidPlugins = invalidTag;
  1.2756 +    }
  1.2757 +  }
  1.2758 +#endif
  1.2759 +
  1.2760 +  // flip the pref so we don't import the legacy flags again
  1.2761 +  Preferences::SetBool("plugin.importedState", true);
  1.2762 +
  1.2763 +  return NS_OK;
  1.2764 +}
  1.2765 +
  1.2766 +void
  1.2767 +nsPluginHost::RemoveCachedPluginsInfo(const char *filePath, nsPluginTag **result)
  1.2768 +{
  1.2769 +  nsRefPtr<nsPluginTag> prev;
  1.2770 +  nsRefPtr<nsPluginTag> tag = mCachedPlugins;
  1.2771 +  while (tag)
  1.2772 +  {
  1.2773 +    if (tag->mFullPath.Equals(filePath)) {
  1.2774 +      // Found it. Remove it from our list
  1.2775 +      if (prev)
  1.2776 +        prev->mNext = tag->mNext;
  1.2777 +      else
  1.2778 +        mCachedPlugins = tag->mNext;
  1.2779 +      tag->mNext = nullptr;
  1.2780 +      *result = tag;
  1.2781 +      NS_ADDREF(*result);
  1.2782 +      break;
  1.2783 +    }
  1.2784 +    prev = tag;
  1.2785 +    tag = tag->mNext;
  1.2786 +  }
  1.2787 +}
  1.2788 +
  1.2789 +#ifdef XP_WIN
  1.2790 +nsresult
  1.2791 +nsPluginHost::EnsurePrivateDirServiceProvider()
  1.2792 +{
  1.2793 +  if (!mPrivateDirServiceProvider) {
  1.2794 +    nsresult rv;
  1.2795 +    mPrivateDirServiceProvider = new nsPluginDirServiceProvider();
  1.2796 +    if (!mPrivateDirServiceProvider)
  1.2797 +      return NS_ERROR_OUT_OF_MEMORY;
  1.2798 +    nsCOMPtr<nsIDirectoryService> dirService(do_GetService(kDirectoryServiceContractID, &rv));
  1.2799 +    if (NS_FAILED(rv))
  1.2800 +      return rv;
  1.2801 +    rv = dirService->RegisterProvider(mPrivateDirServiceProvider);
  1.2802 +    if (NS_FAILED(rv))
  1.2803 +      return rv;
  1.2804 +  }
  1.2805 +  return NS_OK;
  1.2806 +}
  1.2807 +#endif /* XP_WIN */
  1.2808 +
  1.2809 +nsresult nsPluginHost::NewPluginURLStream(const nsString& aURL,
  1.2810 +                                          nsNPAPIPluginInstance *aInstance,
  1.2811 +                                          nsNPAPIPluginStreamListener* aListener,
  1.2812 +                                          nsIInputStream *aPostStream,
  1.2813 +                                          const char *aHeadersData,
  1.2814 +                                          uint32_t aHeadersDataLen)
  1.2815 +{
  1.2816 +  nsCOMPtr<nsIURI> url;
  1.2817 +  nsAutoString absUrl;
  1.2818 +  nsresult rv;
  1.2819 +
  1.2820 +  if (aURL.Length() <= 0)
  1.2821 +    return NS_OK;
  1.2822 +
  1.2823 +  // get the base URI for the plugin to create an absolute url 
  1.2824 +  // in case aURL is relative
  1.2825 +  nsRefPtr<nsPluginInstanceOwner> owner = aInstance->GetOwner();
  1.2826 +  if (owner) {
  1.2827 +    rv = NS_MakeAbsoluteURI(absUrl, aURL, nsCOMPtr<nsIURI>(owner->GetBaseURI()));
  1.2828 +  }
  1.2829 +
  1.2830 +  if (absUrl.IsEmpty())
  1.2831 +    absUrl.Assign(aURL);
  1.2832 +
  1.2833 +  rv = NS_NewURI(getter_AddRefs(url), absUrl);
  1.2834 +  if (NS_FAILED(rv))
  1.2835 +    return rv;
  1.2836 +
  1.2837 +  nsCOMPtr<nsIDOMElement> element;
  1.2838 +  nsCOMPtr<nsIDocument> doc;
  1.2839 +  if (owner) {
  1.2840 +    owner->GetDOMElement(getter_AddRefs(element));
  1.2841 +    owner->GetDocument(getter_AddRefs(doc));
  1.2842 +  }
  1.2843 +
  1.2844 +  int16_t shouldLoad = nsIContentPolicy::ACCEPT;
  1.2845 +  rv = NS_CheckContentLoadPolicy(nsIContentPolicy::TYPE_OBJECT_SUBREQUEST,
  1.2846 +                                 url,
  1.2847 +                                 (doc ? doc->NodePrincipal() : nullptr),
  1.2848 +                                 element,
  1.2849 +                                 EmptyCString(), //mime guess
  1.2850 +                                 nullptr,         //extra
  1.2851 +                                 &shouldLoad);
  1.2852 +  if (NS_FAILED(rv))
  1.2853 +    return rv;
  1.2854 +  if (NS_CP_REJECTED(shouldLoad)) {
  1.2855 +    // Disallowed by content policy
  1.2856 +    return NS_ERROR_CONTENT_BLOCKED;
  1.2857 +  }
  1.2858 +
  1.2859 +  nsRefPtr<nsPluginStreamListenerPeer> listenerPeer = new nsPluginStreamListenerPeer();
  1.2860 +  if (!listenerPeer)
  1.2861 +    return NS_ERROR_OUT_OF_MEMORY;
  1.2862 +
  1.2863 +  rv = listenerPeer->Initialize(url, aInstance, aListener);
  1.2864 +  if (NS_FAILED(rv))
  1.2865 +    return rv;
  1.2866 +
  1.2867 +  nsCOMPtr<nsIChannel> channel;
  1.2868 +  rv = NS_NewChannel(getter_AddRefs(channel), url, nullptr,
  1.2869 +    nullptr, /* do not add this internal plugin's channel
  1.2870 +            on the load group otherwise this channel could be canceled
  1.2871 +            form |nsDocShell::OnLinkClickSync| bug 166613 */
  1.2872 +    listenerPeer);
  1.2873 +  if (NS_FAILED(rv))
  1.2874 +    return rv;
  1.2875 +
  1.2876 +  if (doc) {
  1.2877 +    // Set the owner of channel to the document principal...
  1.2878 +    channel->SetOwner(doc->NodePrincipal());
  1.2879 +
  1.2880 +    // And if it's a script allow it to execute against the
  1.2881 +    // document's script context.
  1.2882 +    nsCOMPtr<nsIScriptChannel> scriptChannel(do_QueryInterface(channel));
  1.2883 +    if (scriptChannel) {
  1.2884 +      scriptChannel->SetExecutionPolicy(nsIScriptChannel::EXECUTE_NORMAL);
  1.2885 +      // Plug-ins seem to depend on javascript: URIs running synchronously
  1.2886 +      scriptChannel->SetExecuteAsync(false);
  1.2887 +    }
  1.2888 +  }
  1.2889 +
  1.2890 +  // deal with headers and post data
  1.2891 +  nsCOMPtr<nsIHttpChannel> httpChannel(do_QueryInterface(channel));
  1.2892 +  if (httpChannel) {
  1.2893 +    if (!aPostStream) {
  1.2894 +      // Only set the Referer header for GET requests because IIS throws
  1.2895 +      // errors about malformed requests if we include it in POSTs. See
  1.2896 +      // bug 724465.
  1.2897 +      nsCOMPtr<nsIURI> referer;
  1.2898 +
  1.2899 +      nsCOMPtr<nsIObjectLoadingContent> olc = do_QueryInterface(element);
  1.2900 +      if (olc)
  1.2901 +        olc->GetSrcURI(getter_AddRefs(referer));
  1.2902 +
  1.2903 +
  1.2904 +      if (!referer) {
  1.2905 +        if (!doc) {
  1.2906 +          return NS_ERROR_FAILURE;
  1.2907 +        }
  1.2908 +        referer = doc->GetDocumentURI();
  1.2909 +      }
  1.2910 +
  1.2911 +      rv = httpChannel->SetReferrer(referer);
  1.2912 +      NS_ENSURE_SUCCESS(rv,rv);
  1.2913 +    }
  1.2914 +
  1.2915 +    if (aPostStream) {
  1.2916 +      // XXX it's a bit of a hack to rewind the postdata stream
  1.2917 +      // here but it has to be done in case the post data is
  1.2918 +      // being reused multiple times.
  1.2919 +      nsCOMPtr<nsISeekableStream>
  1.2920 +      postDataSeekable(do_QueryInterface(aPostStream));
  1.2921 +      if (postDataSeekable)
  1.2922 +        postDataSeekable->Seek(nsISeekableStream::NS_SEEK_SET, 0);
  1.2923 +
  1.2924 +      nsCOMPtr<nsIUploadChannel> uploadChannel(do_QueryInterface(httpChannel));
  1.2925 +      NS_ASSERTION(uploadChannel, "http must support nsIUploadChannel");
  1.2926 +
  1.2927 +      uploadChannel->SetUploadStream(aPostStream, EmptyCString(), -1);
  1.2928 +    }
  1.2929 +
  1.2930 +    if (aHeadersData) {
  1.2931 +      rv = AddHeadersToChannel(aHeadersData, aHeadersDataLen, httpChannel);
  1.2932 +      NS_ENSURE_SUCCESS(rv,rv);
  1.2933 +    }
  1.2934 +  }
  1.2935 +  rv = channel->AsyncOpen(listenerPeer, nullptr);
  1.2936 +  if (NS_SUCCEEDED(rv))
  1.2937 +    listenerPeer->TrackRequest(channel);
  1.2938 +  return rv;
  1.2939 +}
  1.2940 +
  1.2941 +// Called by GetURL and PostURL
  1.2942 +nsresult
  1.2943 +nsPluginHost::DoURLLoadSecurityCheck(nsNPAPIPluginInstance *aInstance,
  1.2944 +                                     const char* aURL)
  1.2945 +{
  1.2946 +  if (!aURL || *aURL == '\0')
  1.2947 +    return NS_OK;
  1.2948 +
  1.2949 +  // get the base URI for the plugin element
  1.2950 +  nsRefPtr<nsPluginInstanceOwner> owner = aInstance->GetOwner();
  1.2951 +  if (!owner)
  1.2952 +    return NS_ERROR_FAILURE;
  1.2953 +
  1.2954 +  nsCOMPtr<nsIURI> baseURI = owner->GetBaseURI();
  1.2955 +  if (!baseURI)
  1.2956 +    return NS_ERROR_FAILURE;
  1.2957 +
  1.2958 +  // Create an absolute URL for the target in case the target is relative
  1.2959 +  nsCOMPtr<nsIURI> targetURL;
  1.2960 +  NS_NewURI(getter_AddRefs(targetURL), aURL, baseURI);
  1.2961 +  if (!targetURL)
  1.2962 +    return NS_ERROR_FAILURE;
  1.2963 +
  1.2964 +  nsCOMPtr<nsIDocument> doc;
  1.2965 +  owner->GetDocument(getter_AddRefs(doc));
  1.2966 +  if (!doc)
  1.2967 +    return NS_ERROR_FAILURE;
  1.2968 +
  1.2969 +  nsresult rv;
  1.2970 +  nsCOMPtr<nsIScriptSecurityManager> secMan(
  1.2971 +    do_GetService(NS_SCRIPTSECURITYMANAGER_CONTRACTID, &rv));
  1.2972 +  if (NS_FAILED(rv))
  1.2973 +    return rv;
  1.2974 +
  1.2975 +  return secMan->CheckLoadURIWithPrincipal(doc->NodePrincipal(), targetURL,
  1.2976 +                                           nsIScriptSecurityManager::STANDARD);
  1.2977 +
  1.2978 +}
  1.2979 +
  1.2980 +nsresult
  1.2981 +nsPluginHost::AddHeadersToChannel(const char *aHeadersData,
  1.2982 +                                  uint32_t aHeadersDataLen,
  1.2983 +                                  nsIChannel *aGenericChannel)
  1.2984 +{
  1.2985 +  nsresult rv = NS_OK;
  1.2986 +
  1.2987 +  nsCOMPtr<nsIHttpChannel> aChannel = do_QueryInterface(aGenericChannel);
  1.2988 +  if (!aChannel) {
  1.2989 +    return NS_ERROR_NULL_POINTER;
  1.2990 +  }
  1.2991 +
  1.2992 +  // used during the manipulation of the String from the aHeadersData
  1.2993 +  nsAutoCString headersString;
  1.2994 +  nsAutoCString oneHeader;
  1.2995 +  nsAutoCString headerName;
  1.2996 +  nsAutoCString headerValue;
  1.2997 +  int32_t crlf = 0;
  1.2998 +  int32_t colon = 0;
  1.2999 +
  1.3000 +  // Turn the char * buffer into an nsString.
  1.3001 +  headersString = aHeadersData;
  1.3002 +
  1.3003 +  // Iterate over the nsString: for each "\r\n" delimited chunk,
  1.3004 +  // add the value as a header to the nsIHTTPChannel
  1.3005 +  while (true) {
  1.3006 +    crlf = headersString.Find("\r\n", true);
  1.3007 +    if (-1 == crlf) {
  1.3008 +      rv = NS_OK;
  1.3009 +      return rv;
  1.3010 +    }
  1.3011 +    headersString.Mid(oneHeader, 0, crlf);
  1.3012 +    headersString.Cut(0, crlf + 2);
  1.3013 +    oneHeader.StripWhitespace();
  1.3014 +    colon = oneHeader.Find(":");
  1.3015 +    if (-1 == colon) {
  1.3016 +      rv = NS_ERROR_NULL_POINTER;
  1.3017 +      return rv;
  1.3018 +    }
  1.3019 +    oneHeader.Left(headerName, colon);
  1.3020 +    colon++;
  1.3021 +    oneHeader.Mid(headerValue, colon, oneHeader.Length() - colon);
  1.3022 +
  1.3023 +    // FINALLY: we can set the header!
  1.3024 +
  1.3025 +    rv = aChannel->SetRequestHeader(headerName, headerValue, true);
  1.3026 +    if (NS_FAILED(rv)) {
  1.3027 +      rv = NS_ERROR_NULL_POINTER;
  1.3028 +      return rv;
  1.3029 +    }
  1.3030 +  }
  1.3031 +  return rv;
  1.3032 +}
  1.3033 +
  1.3034 +nsresult
  1.3035 +nsPluginHost::StopPluginInstance(nsNPAPIPluginInstance* aInstance)
  1.3036 +{
  1.3037 +  if (PluginDestructionGuard::DelayDestroy(aInstance)) {
  1.3038 +    return NS_OK;
  1.3039 +  }
  1.3040 +
  1.3041 +  PLUGIN_LOG(PLUGIN_LOG_NORMAL,
  1.3042 +  ("nsPluginHost::StopPluginInstance called instance=%p\n",aInstance));
  1.3043 +
  1.3044 +  if (aInstance->HasStartedDestroying()) {
  1.3045 +    return NS_OK;
  1.3046 +  }
  1.3047 +
  1.3048 +  Telemetry::AutoTimer<Telemetry::PLUGIN_SHUTDOWN_MS> timer;
  1.3049 +  aInstance->Stop();
  1.3050 +
  1.3051 +  // if the instance does not want to be 'cached' just remove it
  1.3052 +  bool doCache = aInstance->ShouldCache();
  1.3053 +  if (doCache) {
  1.3054 +    // try to get the max cached instances from a pref or use default
  1.3055 +    uint32_t cachedInstanceLimit =
  1.3056 +      Preferences::GetUint(NS_PREF_MAX_NUM_CACHED_INSTANCES,
  1.3057 +                           DEFAULT_NUMBER_OF_STOPPED_INSTANCES);
  1.3058 +    if (StoppedInstanceCount() >= cachedInstanceLimit) {
  1.3059 +      nsNPAPIPluginInstance *oldestInstance = FindOldestStoppedInstance();
  1.3060 +      if (oldestInstance) {
  1.3061 +        nsPluginTag* pluginTag = TagForPlugin(oldestInstance->GetPlugin());
  1.3062 +        oldestInstance->Destroy();
  1.3063 +        mInstances.RemoveElement(oldestInstance);
  1.3064 +        // TODO: Remove this check once bug 752422 was investigated
  1.3065 +        if (pluginTag) {          
  1.3066 +          OnPluginInstanceDestroyed(pluginTag);
  1.3067 +        }
  1.3068 +      }
  1.3069 +    }
  1.3070 +  } else {
  1.3071 +    nsPluginTag* pluginTag = TagForPlugin(aInstance->GetPlugin());
  1.3072 +    aInstance->Destroy();
  1.3073 +    mInstances.RemoveElement(aInstance);
  1.3074 +    // TODO: Remove this check once bug 752422 was investigated
  1.3075 +    if (pluginTag) {      
  1.3076 +      OnPluginInstanceDestroyed(pluginTag);
  1.3077 +    }
  1.3078 +  }
  1.3079 +
  1.3080 +  return NS_OK;
  1.3081 +}
  1.3082 +
  1.3083 +nsresult nsPluginHost::NewPluginStreamListener(nsIURI* aURI,
  1.3084 +                                               nsNPAPIPluginInstance* aInstance,
  1.3085 +                                               nsIStreamListener **aStreamListener)
  1.3086 +{
  1.3087 +  NS_ENSURE_ARG_POINTER(aURI);
  1.3088 +  NS_ENSURE_ARG_POINTER(aStreamListener);
  1.3089 +
  1.3090 +  nsRefPtr<nsPluginStreamListenerPeer> listener = new nsPluginStreamListenerPeer();
  1.3091 +  nsresult rv = listener->Initialize(aURI, aInstance, nullptr);
  1.3092 +  if (NS_FAILED(rv)) {
  1.3093 +    return rv;
  1.3094 +  }
  1.3095 +
  1.3096 +  listener.forget(aStreamListener);
  1.3097 +
  1.3098 +  return NS_OK;
  1.3099 +}
  1.3100 +
  1.3101 +NS_IMETHODIMP nsPluginHost::Observe(nsISupports *aSubject,
  1.3102 +                                    const char *aTopic,
  1.3103 +                                    const char16_t *someData)
  1.3104 +{
  1.3105 +  if (!strcmp(NS_XPCOM_SHUTDOWN_OBSERVER_ID, aTopic)) {
  1.3106 +    OnShutdown();
  1.3107 +    UnloadPlugins();
  1.3108 +    sInst->Release();
  1.3109 +  }
  1.3110 +  if (!strcmp(NS_PREFBRANCH_PREFCHANGE_TOPIC_ID, aTopic)) {
  1.3111 +    mPluginsDisabled = Preferences::GetBool("plugin.disable", false);
  1.3112 +    mPluginsClickToPlay = Preferences::GetBool("plugins.click_to_play", false);
  1.3113 +    // Unload or load plugins as needed
  1.3114 +    if (mPluginsDisabled) {
  1.3115 +      UnloadPlugins();
  1.3116 +    } else {
  1.3117 +      LoadPlugins();
  1.3118 +    }
  1.3119 +  }
  1.3120 +  if (!strcmp("blocklist-updated", aTopic)) {
  1.3121 +    nsPluginTag* plugin = mPlugins;
  1.3122 +    while (plugin) {
  1.3123 +      plugin->InvalidateBlocklistState();
  1.3124 +      plugin = plugin->mNext;
  1.3125 +    }
  1.3126 +  }
  1.3127 +#ifdef MOZ_WIDGET_ANDROID
  1.3128 +  if (!strcmp("application-background", aTopic)) {
  1.3129 +    for(uint32_t i = 0; i < mInstances.Length(); i++) {
  1.3130 +      mInstances[i]->NotifyForeground(false);
  1.3131 +    }
  1.3132 +  }
  1.3133 +  if (!strcmp("application-foreground", aTopic)) {
  1.3134 +    for(uint32_t i = 0; i < mInstances.Length(); i++) {
  1.3135 +      if (mInstances[i]->IsOnScreen())
  1.3136 +        mInstances[i]->NotifyForeground(true);
  1.3137 +    }
  1.3138 +  }
  1.3139 +  if (!strcmp("memory-pressure", aTopic)) {
  1.3140 +    for(uint32_t i = 0; i < mInstances.Length(); i++) {
  1.3141 +      mInstances[i]->MemoryPressure();
  1.3142 +    }
  1.3143 +  }
  1.3144 +#endif
  1.3145 +  return NS_OK;
  1.3146 +}
  1.3147 +
  1.3148 +nsresult
  1.3149 +nsPluginHost::ParsePostBufferToFixHeaders(const char *inPostData, uint32_t inPostDataLen,
  1.3150 +                                          char **outPostData, uint32_t *outPostDataLen)
  1.3151 +{
  1.3152 +  if (!inPostData || !outPostData || !outPostDataLen)
  1.3153 +    return NS_ERROR_NULL_POINTER;
  1.3154 +
  1.3155 +  *outPostData = 0;
  1.3156 +  *outPostDataLen = 0;
  1.3157 +
  1.3158 +  const char CR = '\r';
  1.3159 +  const char LF = '\n';
  1.3160 +  const char CRLFCRLF[] = {CR,LF,CR,LF,'\0'}; // C string"\r\n\r\n"
  1.3161 +  const char ContentLenHeader[] = "Content-length";
  1.3162 +
  1.3163 +  nsAutoTArray<const char*, 8> singleLF;
  1.3164 +  const char *pSCntlh = 0;// pointer to start of ContentLenHeader in inPostData
  1.3165 +  const char *pSod = 0;   // pointer to start of data in inPostData
  1.3166 +  const char *pEoh = 0;   // pointer to end of headers in inPostData
  1.3167 +  const char *pEod = inPostData + inPostDataLen; // pointer to end of inPostData
  1.3168 +  if (*inPostData == LF) {
  1.3169 +    // If no custom headers are required, simply add a blank
  1.3170 +    // line ('\n') to the beginning of the file or buffer.
  1.3171 +    // so *inPostData == '\n' is valid
  1.3172 +    pSod = inPostData + 1;
  1.3173 +  } else {
  1.3174 +    const char *s = inPostData; //tmp pointer to sourse inPostData
  1.3175 +    while (s < pEod) {
  1.3176 +      if (!pSCntlh &&
  1.3177 +          (*s == 'C' || *s == 'c') &&
  1.3178 +          (s + sizeof(ContentLenHeader) - 1 < pEod) &&
  1.3179 +          (!PL_strncasecmp(s, ContentLenHeader, sizeof(ContentLenHeader) - 1)))
  1.3180 +      {
  1.3181 +        // lets assume this is ContentLenHeader for now
  1.3182 +        const char *p = pSCntlh = s;
  1.3183 +        p += sizeof(ContentLenHeader) - 1;
  1.3184 +        // search for first CR or LF == end of ContentLenHeader
  1.3185 +        for (; p < pEod; p++) {
  1.3186 +          if (*p == CR || *p == LF) {
  1.3187 +            // got delimiter,
  1.3188 +            // one more check; if previous char is a digit
  1.3189 +            // most likely pSCntlh points to the start of ContentLenHeader
  1.3190 +            if (*(p-1) >= '0' && *(p-1) <= '9') {
  1.3191 +              s = p;
  1.3192 +            }
  1.3193 +            break; //for loop
  1.3194 +          }
  1.3195 +        }
  1.3196 +        if (pSCntlh == s) { // curret ptr is the same
  1.3197 +          pSCntlh = 0; // that was not ContentLenHeader
  1.3198 +          break; // there is nothing to parse, break *WHILE LOOP* here
  1.3199 +        }
  1.3200 +      }
  1.3201 +
  1.3202 +      if (*s == CR) {
  1.3203 +        if (pSCntlh && // only if ContentLenHeader is found we are looking for end of headers
  1.3204 +            ((s + sizeof(CRLFCRLF)-1) <= pEod) &&
  1.3205 +            !memcmp(s, CRLFCRLF, sizeof(CRLFCRLF)-1))
  1.3206 +        {
  1.3207 +          s += sizeof(CRLFCRLF)-1;
  1.3208 +          pEoh = pSod = s; // data stars here
  1.3209 +          break;
  1.3210 +        }
  1.3211 +      } else if (*s == LF) {
  1.3212 +        if (*(s-1) != CR) {
  1.3213 +          singleLF.AppendElement(s);
  1.3214 +        }
  1.3215 +        if (pSCntlh && (s+1 < pEod) && (*(s+1) == LF)) {
  1.3216 +          s++;
  1.3217 +          singleLF.AppendElement(s);
  1.3218 +          s++;
  1.3219 +          pEoh = pSod = s; // data stars here
  1.3220 +          break;
  1.3221 +        }
  1.3222 +      }
  1.3223 +      s++;
  1.3224 +    }
  1.3225 +  }
  1.3226 +
  1.3227 +  // deal with output buffer
  1.3228 +  if (!pSod) { // lets assume whole buffer is a data
  1.3229 +    pSod = inPostData;
  1.3230 +  }
  1.3231 +
  1.3232 +  uint32_t newBufferLen = 0;
  1.3233 +  uint32_t dataLen = pEod - pSod;
  1.3234 +  uint32_t headersLen = pEoh ? pSod - inPostData : 0;
  1.3235 +
  1.3236 +  char *p; // tmp ptr into new output buf
  1.3237 +  if (headersLen) { // we got a headers
  1.3238 +    // this function does not make any assumption on correctness
  1.3239 +    // of ContentLenHeader value in this case.
  1.3240 +
  1.3241 +    newBufferLen = dataLen + headersLen;
  1.3242 +    // in case there were single LFs in headers
  1.3243 +    // reserve an extra space for CR will be added before each single LF
  1.3244 +    int cntSingleLF = singleLF.Length();
  1.3245 +    newBufferLen += cntSingleLF;
  1.3246 +
  1.3247 +    if (!(*outPostData = p = (char*)nsMemory::Alloc(newBufferLen)))
  1.3248 +      return NS_ERROR_OUT_OF_MEMORY;
  1.3249 +
  1.3250 +    // deal with single LF
  1.3251 +    const char *s = inPostData;
  1.3252 +    if (cntSingleLF) {
  1.3253 +      for (int i=0; i<cntSingleLF; i++) {
  1.3254 +        const char *plf = singleLF.ElementAt(i); // ptr to single LF in headers
  1.3255 +        int n = plf - s; // bytes to copy
  1.3256 +        if (n) { // for '\n\n' there is nothing to memcpy
  1.3257 +          memcpy(p, s, n);
  1.3258 +          p += n;
  1.3259 +        }
  1.3260 +        *p++ = CR;
  1.3261 +        s = plf;
  1.3262 +        *p++ = *s++;
  1.3263 +      }
  1.3264 +    }
  1.3265 +    // are we done with headers?
  1.3266 +    headersLen = pEoh - s;
  1.3267 +    if (headersLen) { // not yet
  1.3268 +      memcpy(p, s, headersLen); // copy the rest
  1.3269 +      p += headersLen;
  1.3270 +    }
  1.3271 +  } else  if (dataLen) { // no ContentLenHeader is found but there is a data
  1.3272 +    // make new output buffer big enough
  1.3273 +    // to keep ContentLenHeader+value followed by data
  1.3274 +    uint32_t l = sizeof(ContentLenHeader) + sizeof(CRLFCRLF) + 32;
  1.3275 +    newBufferLen = dataLen + l;
  1.3276 +    if (!(*outPostData = p = (char*)nsMemory::Alloc(newBufferLen)))
  1.3277 +      return NS_ERROR_OUT_OF_MEMORY;
  1.3278 +    headersLen = PR_snprintf(p, l,"%s: %ld%s", ContentLenHeader, dataLen, CRLFCRLF);
  1.3279 +    if (headersLen == l) { // if PR_snprintf has ate all extra space consider this as an error
  1.3280 +      nsMemory::Free(p);
  1.3281 +      *outPostData = 0;
  1.3282 +      return NS_ERROR_FAILURE;
  1.3283 +    }
  1.3284 +    p += headersLen;
  1.3285 +    newBufferLen = headersLen + dataLen;
  1.3286 +  }
  1.3287 +  // at this point we've done with headers.
  1.3288 +  // there is a possibility that input buffer has only headers info in it
  1.3289 +  // which already parsed and copied into output buffer.
  1.3290 +  // copy the data
  1.3291 +  if (dataLen) {
  1.3292 +    memcpy(p, pSod, dataLen);
  1.3293 +  }
  1.3294 +
  1.3295 +  *outPostDataLen = newBufferLen;
  1.3296 +
  1.3297 +  return NS_OK;
  1.3298 +}
  1.3299 +
  1.3300 +nsresult
  1.3301 +nsPluginHost::CreateTempFileToPost(const char *aPostDataURL, nsIFile **aTmpFile)
  1.3302 +{
  1.3303 +  nsresult rv;
  1.3304 +  int64_t fileSize;
  1.3305 +  nsAutoCString filename;
  1.3306 +
  1.3307 +  // stat file == get size & convert file:///c:/ to c: if needed
  1.3308 +  nsCOMPtr<nsIFile> inFile;
  1.3309 +  rv = NS_GetFileFromURLSpec(nsDependentCString(aPostDataURL),
  1.3310 +                             getter_AddRefs(inFile));
  1.3311 +  if (NS_FAILED(rv)) {
  1.3312 +    nsCOMPtr<nsIFile> localFile;
  1.3313 +    rv = NS_NewNativeLocalFile(nsDependentCString(aPostDataURL), false,
  1.3314 +                               getter_AddRefs(localFile));
  1.3315 +    if (NS_FAILED(rv)) return rv;
  1.3316 +    inFile = localFile;
  1.3317 +  }
  1.3318 +  rv = inFile->GetFileSize(&fileSize);
  1.3319 +  if (NS_FAILED(rv)) return rv;
  1.3320 +  rv = inFile->GetNativePath(filename);
  1.3321 +  if (NS_FAILED(rv)) return rv;
  1.3322 +
  1.3323 +  if (fileSize != 0) {
  1.3324 +    nsCOMPtr<nsIInputStream> inStream;
  1.3325 +    rv = NS_NewLocalFileInputStream(getter_AddRefs(inStream), inFile);
  1.3326 +    if (NS_FAILED(rv)) return rv;
  1.3327 +
  1.3328 +    // Create a temporary file to write the http Content-length:
  1.3329 +    // %ld\r\n\" header and "\r\n" == end of headers for post data to
  1.3330 +
  1.3331 +    nsCOMPtr<nsIFile> tempFile;
  1.3332 +    rv = GetPluginTempDir(getter_AddRefs(tempFile));
  1.3333 +    if (NS_FAILED(rv))
  1.3334 +      return rv;
  1.3335 +
  1.3336 +    nsAutoCString inFileName;
  1.3337 +    inFile->GetNativeLeafName(inFileName);
  1.3338 +    // XXX hack around bug 70083
  1.3339 +    inFileName.Insert(NS_LITERAL_CSTRING("post-"), 0);
  1.3340 +    rv = tempFile->AppendNative(inFileName);
  1.3341 +
  1.3342 +    if (NS_FAILED(rv))
  1.3343 +      return rv;
  1.3344 +
  1.3345 +    // make it unique, and mode == 0600, not world-readable
  1.3346 +    rv = tempFile->CreateUnique(nsIFile::NORMAL_FILE_TYPE, 0600);
  1.3347 +    if (NS_FAILED(rv))
  1.3348 +      return rv;
  1.3349 +
  1.3350 +    nsCOMPtr<nsIOutputStream> outStream;
  1.3351 +    if (NS_SUCCEEDED(rv)) {
  1.3352 +      rv = NS_NewLocalFileOutputStream(getter_AddRefs(outStream),
  1.3353 +        tempFile,
  1.3354 +        (PR_WRONLY | PR_CREATE_FILE | PR_TRUNCATE),
  1.3355 +        0600); // 600 so others can't read our form data
  1.3356 +    }
  1.3357 +    NS_ASSERTION(NS_SUCCEEDED(rv), "Post data file couldn't be created!");
  1.3358 +    if (NS_FAILED(rv))
  1.3359 +      return rv;
  1.3360 +
  1.3361 +    char buf[1024];
  1.3362 +    uint32_t br, bw;
  1.3363 +    bool firstRead = true;
  1.3364 +    while (1) {
  1.3365 +      // Read() mallocs if buffer is null
  1.3366 +      rv = inStream->Read(buf, 1024, &br);
  1.3367 +      if (NS_FAILED(rv) || (int32_t)br <= 0)
  1.3368 +        break;
  1.3369 +      if (firstRead) {
  1.3370 +        //"For protocols in which the headers must be distinguished from the body,
  1.3371 +        // such as HTTP, the buffer or file should contain the headers, followed by
  1.3372 +        // a blank line, then the body. If no custom headers are required, simply
  1.3373 +        // add a blank line ('\n') to the beginning of the file or buffer.
  1.3374 +
  1.3375 +        char *parsedBuf;
  1.3376 +        // assuming first 1K (or what we got) has all headers in,
  1.3377 +        // lets parse it through nsPluginHost::ParsePostBufferToFixHeaders()
  1.3378 +        ParsePostBufferToFixHeaders((const char *)buf, br, &parsedBuf, &bw);
  1.3379 +        rv = outStream->Write(parsedBuf, bw, &br);
  1.3380 +        nsMemory::Free(parsedBuf);
  1.3381 +        if (NS_FAILED(rv) || (bw != br))
  1.3382 +          break;
  1.3383 +
  1.3384 +        firstRead = false;
  1.3385 +        continue;
  1.3386 +      }
  1.3387 +      bw = br;
  1.3388 +      rv = outStream->Write(buf, bw, &br);
  1.3389 +      if (NS_FAILED(rv) || (bw != br))
  1.3390 +        break;
  1.3391 +    }
  1.3392 +
  1.3393 +    inStream->Close();
  1.3394 +    outStream->Close();
  1.3395 +    if (NS_SUCCEEDED(rv))
  1.3396 +      tempFile.forget(aTmpFile);
  1.3397 +  }
  1.3398 +  return rv;
  1.3399 +}
  1.3400 +
  1.3401 +nsresult
  1.3402 +nsPluginHost::NewPluginNativeWindow(nsPluginNativeWindow ** aPluginNativeWindow)
  1.3403 +{
  1.3404 +  return PLUG_NewPluginNativeWindow(aPluginNativeWindow);
  1.3405 +}
  1.3406 +
  1.3407 +nsresult
  1.3408 +nsPluginHost::GetPluginName(nsNPAPIPluginInstance *aPluginInstance,
  1.3409 +                            const char** aPluginName)
  1.3410 +{
  1.3411 +  nsNPAPIPluginInstance *instance = static_cast<nsNPAPIPluginInstance*>(aPluginInstance);
  1.3412 +  if (!instance)
  1.3413 +    return NS_ERROR_FAILURE;
  1.3414 +
  1.3415 +  nsNPAPIPlugin* plugin = instance->GetPlugin();
  1.3416 +  if (!plugin)
  1.3417 +    return NS_ERROR_FAILURE;
  1.3418 +
  1.3419 +  *aPluginName = TagForPlugin(plugin)->mName.get();
  1.3420 +
  1.3421 +  return NS_OK;
  1.3422 +}
  1.3423 +
  1.3424 +nsresult
  1.3425 +nsPluginHost::GetPluginTagForInstance(nsNPAPIPluginInstance *aPluginInstance,
  1.3426 +                                      nsIPluginTag **aPluginTag)
  1.3427 +{
  1.3428 +  NS_ENSURE_ARG_POINTER(aPluginInstance);
  1.3429 +  NS_ENSURE_ARG_POINTER(aPluginTag);
  1.3430 +
  1.3431 +  nsNPAPIPlugin *plugin = aPluginInstance->GetPlugin();
  1.3432 +  if (!plugin)
  1.3433 +    return NS_ERROR_FAILURE;
  1.3434 +
  1.3435 +  *aPluginTag = TagForPlugin(plugin);
  1.3436 +
  1.3437 +  NS_ADDREF(*aPluginTag);
  1.3438 +  return NS_OK;
  1.3439 +}
  1.3440 +
  1.3441 +NS_IMETHODIMP nsPluginHost::Notify(nsITimer* timer)
  1.3442 +{
  1.3443 +  nsRefPtr<nsPluginTag> pluginTag = mPlugins;
  1.3444 +  while (pluginTag) {
  1.3445 +    if (pluginTag->mUnloadTimer == timer) {
  1.3446 +      if (!IsRunningPlugin(pluginTag)) {
  1.3447 +        pluginTag->TryUnloadPlugin(false);
  1.3448 +      }
  1.3449 +      return NS_OK;
  1.3450 +    }
  1.3451 +    pluginTag = pluginTag->mNext;
  1.3452 +  }
  1.3453 +
  1.3454 +  return NS_ERROR_FAILURE;
  1.3455 +}
  1.3456 +
  1.3457 +#ifdef XP_WIN
  1.3458 +// Re-enable any top level browser windows that were disabled by modal dialogs
  1.3459 +// displayed by the crashed plugin.
  1.3460 +static void
  1.3461 +CheckForDisabledWindows()
  1.3462 +{
  1.3463 +  nsCOMPtr<nsIWindowMediator> wm(do_GetService(NS_WINDOWMEDIATOR_CONTRACTID));
  1.3464 +  if (!wm)
  1.3465 +    return;
  1.3466 +
  1.3467 +  nsCOMPtr<nsISimpleEnumerator> windowList;
  1.3468 +  wm->GetXULWindowEnumerator(nullptr, getter_AddRefs(windowList));
  1.3469 +  if (!windowList)
  1.3470 +    return;
  1.3471 +
  1.3472 +  bool haveWindows;
  1.3473 +  do {
  1.3474 +    windowList->HasMoreElements(&haveWindows);
  1.3475 +    if (!haveWindows)
  1.3476 +      return;
  1.3477 +
  1.3478 +    nsCOMPtr<nsISupports> supportsWindow;
  1.3479 +    windowList->GetNext(getter_AddRefs(supportsWindow));
  1.3480 +    nsCOMPtr<nsIBaseWindow> baseWin(do_QueryInterface(supportsWindow));
  1.3481 +    if (baseWin) {
  1.3482 +      nsCOMPtr<nsIWidget> widget;
  1.3483 +      baseWin->GetMainWidget(getter_AddRefs(widget));
  1.3484 +      if (widget && !widget->GetParent() &&
  1.3485 +          widget->IsVisible() &&
  1.3486 +          !widget->IsEnabled()) {
  1.3487 +        nsIWidget* child = widget->GetFirstChild();
  1.3488 +        bool enable = true;
  1.3489 +        while (child)  {
  1.3490 +          if (child->WindowType() == eWindowType_dialog) {
  1.3491 +            enable = false;
  1.3492 +            break;
  1.3493 +          }
  1.3494 +          child = child->GetNextSibling();
  1.3495 +        }
  1.3496 +        if (enable) {
  1.3497 +          widget->Enable(true);
  1.3498 +        }
  1.3499 +      }
  1.3500 +    }
  1.3501 +  } while (haveWindows);
  1.3502 +}
  1.3503 +#endif
  1.3504 +
  1.3505 +void
  1.3506 +nsPluginHost::PluginCrashed(nsNPAPIPlugin* aPlugin,
  1.3507 +                            const nsAString& pluginDumpID,
  1.3508 +                            const nsAString& browserDumpID)
  1.3509 +{
  1.3510 +  nsPluginTag* crashedPluginTag = TagForPlugin(aPlugin);
  1.3511 +
  1.3512 +  // Notify the app's observer that a plugin crashed so it can submit
  1.3513 +  // a crashreport.
  1.3514 +  bool submittedCrashReport = false;
  1.3515 +  nsCOMPtr<nsIObserverService> obsService =
  1.3516 +    mozilla::services::GetObserverService();
  1.3517 +  nsCOMPtr<nsIWritablePropertyBag2> propbag =
  1.3518 +    do_CreateInstance("@mozilla.org/hash-property-bag;1");
  1.3519 +  if (obsService && propbag) {
  1.3520 +    propbag->SetPropertyAsAString(NS_LITERAL_STRING("pluginDumpID"),
  1.3521 +                                  pluginDumpID);
  1.3522 +    propbag->SetPropertyAsAString(NS_LITERAL_STRING("browserDumpID"),
  1.3523 +                                  browserDumpID);
  1.3524 +    propbag->SetPropertyAsBool(NS_LITERAL_STRING("submittedCrashReport"),
  1.3525 +                               submittedCrashReport);
  1.3526 +    obsService->NotifyObservers(propbag, "plugin-crashed", nullptr);
  1.3527 +    // see if an observer submitted a crash report.
  1.3528 +    propbag->GetPropertyAsBool(NS_LITERAL_STRING("submittedCrashReport"),
  1.3529 +                               &submittedCrashReport);
  1.3530 +  }
  1.3531 +
  1.3532 +  // Invalidate each nsPluginInstanceTag for the crashed plugin
  1.3533 +
  1.3534 +  for (uint32_t i = mInstances.Length(); i > 0; i--) {
  1.3535 +    nsNPAPIPluginInstance* instance = mInstances[i - 1];
  1.3536 +    if (instance->GetPlugin() == aPlugin) {
  1.3537 +      // notify the content node (nsIObjectLoadingContent) that the
  1.3538 +      // plugin has crashed
  1.3539 +      nsCOMPtr<nsIDOMElement> domElement;
  1.3540 +      instance->GetDOMElement(getter_AddRefs(domElement));
  1.3541 +      nsCOMPtr<nsIObjectLoadingContent> objectContent(do_QueryInterface(domElement));
  1.3542 +      if (objectContent) {
  1.3543 +        objectContent->PluginCrashed(crashedPluginTag, pluginDumpID, browserDumpID,
  1.3544 +                                     submittedCrashReport);
  1.3545 +      }
  1.3546 +
  1.3547 +      instance->Destroy();
  1.3548 +      mInstances.RemoveElement(instance);
  1.3549 +      OnPluginInstanceDestroyed(crashedPluginTag);
  1.3550 +    }
  1.3551 +  }
  1.3552 +
  1.3553 +  // Only after all instances have been invalidated is it safe to null
  1.3554 +  // out nsPluginTag.mPlugin. The next time we try to create an
  1.3555 +  // instance of this plugin we reload it (launch a new plugin process).
  1.3556 +
  1.3557 +  crashedPluginTag->mPlugin = nullptr;
  1.3558 +
  1.3559 +#ifdef XP_WIN
  1.3560 +  CheckForDisabledWindows();
  1.3561 +#endif
  1.3562 +}
  1.3563 +
  1.3564 +nsNPAPIPluginInstance*
  1.3565 +nsPluginHost::FindInstance(const char *mimetype)
  1.3566 +{
  1.3567 +  for (uint32_t i = 0; i < mInstances.Length(); i++) {
  1.3568 +    nsNPAPIPluginInstance* instance = mInstances[i];
  1.3569 +
  1.3570 +    const char* mt;
  1.3571 +    nsresult rv = instance->GetMIMEType(&mt);
  1.3572 +    if (NS_FAILED(rv))
  1.3573 +      continue;
  1.3574 +
  1.3575 +    if (PL_strcasecmp(mt, mimetype) == 0)
  1.3576 +      return instance;
  1.3577 +  }
  1.3578 +
  1.3579 +  return nullptr;
  1.3580 +}
  1.3581 +
  1.3582 +nsNPAPIPluginInstance*
  1.3583 +nsPluginHost::FindOldestStoppedInstance()
  1.3584 +{
  1.3585 +  nsNPAPIPluginInstance *oldestInstance = nullptr;
  1.3586 +  TimeStamp oldestTime = TimeStamp::Now();
  1.3587 +  for (uint32_t i = 0; i < mInstances.Length(); i++) {
  1.3588 +    nsNPAPIPluginInstance *instance = mInstances[i];
  1.3589 +    if (instance->IsRunning())
  1.3590 +      continue;
  1.3591 +
  1.3592 +    TimeStamp time = instance->StopTime();
  1.3593 +    if (time < oldestTime) {
  1.3594 +      oldestTime = time;
  1.3595 +      oldestInstance = instance;
  1.3596 +    }
  1.3597 +  }
  1.3598 +
  1.3599 +  return oldestInstance;
  1.3600 +}
  1.3601 +
  1.3602 +uint32_t
  1.3603 +nsPluginHost::StoppedInstanceCount()
  1.3604 +{
  1.3605 +  uint32_t stoppedCount = 0;
  1.3606 +  for (uint32_t i = 0; i < mInstances.Length(); i++) {
  1.3607 +    nsNPAPIPluginInstance *instance = mInstances[i];
  1.3608 +    if (!instance->IsRunning())
  1.3609 +      stoppedCount++;
  1.3610 +  }
  1.3611 +  return stoppedCount;
  1.3612 +}
  1.3613 +
  1.3614 +nsTArray< nsRefPtr<nsNPAPIPluginInstance> >*
  1.3615 +nsPluginHost::InstanceArray()
  1.3616 +{
  1.3617 +  return &mInstances;
  1.3618 +}
  1.3619 +
  1.3620 +void 
  1.3621 +nsPluginHost::DestroyRunningInstances(nsPluginTag* aPluginTag)
  1.3622 +{
  1.3623 +  for (int32_t i = mInstances.Length(); i > 0; i--) {
  1.3624 +    nsNPAPIPluginInstance *instance = mInstances[i - 1];
  1.3625 +    if (instance->IsRunning() && (!aPluginTag || aPluginTag == TagForPlugin(instance->GetPlugin()))) {
  1.3626 +      instance->SetWindow(nullptr);
  1.3627 +      instance->Stop();
  1.3628 +
  1.3629 +      // Get rid of all the instances without the possibility of caching.
  1.3630 +      nsPluginTag* pluginTag = TagForPlugin(instance->GetPlugin());
  1.3631 +      instance->SetWindow(nullptr);
  1.3632 +
  1.3633 +      nsCOMPtr<nsIDOMElement> domElement;
  1.3634 +      instance->GetDOMElement(getter_AddRefs(domElement));
  1.3635 +      nsCOMPtr<nsIObjectLoadingContent> objectContent =
  1.3636 +        do_QueryInterface(domElement);
  1.3637 +
  1.3638 +      instance->Destroy();
  1.3639 +
  1.3640 +      mInstances.RemoveElement(instance);
  1.3641 +      OnPluginInstanceDestroyed(pluginTag);
  1.3642 +
  1.3643 +      // Notify owning content that we destroyed its plugin out from under it
  1.3644 +      if (objectContent) {
  1.3645 +        objectContent->PluginDestroyed();
  1.3646 +      }
  1.3647 +    }
  1.3648 +  }
  1.3649 +}
  1.3650 +
  1.3651 +// Runnable that does an async destroy of a plugin.
  1.3652 +
  1.3653 +class nsPluginDestroyRunnable : public nsRunnable,
  1.3654 +                                public PRCList
  1.3655 +{
  1.3656 +public:
  1.3657 +  nsPluginDestroyRunnable(nsNPAPIPluginInstance *aInstance)
  1.3658 +    : mInstance(aInstance)
  1.3659 +  {
  1.3660 +    PR_INIT_CLIST(this);
  1.3661 +    PR_APPEND_LINK(this, &sRunnableListHead);
  1.3662 +  }
  1.3663 +
  1.3664 +  virtual ~nsPluginDestroyRunnable()
  1.3665 +  {
  1.3666 +    PR_REMOVE_LINK(this);
  1.3667 +  }
  1.3668 +
  1.3669 +  NS_IMETHOD Run()
  1.3670 +  {
  1.3671 +    nsRefPtr<nsNPAPIPluginInstance> instance;
  1.3672 +
  1.3673 +    // Null out mInstance to make sure this code in another runnable
  1.3674 +    // will do the right thing even if someone was holding on to this
  1.3675 +    // runnable longer than we expect.
  1.3676 +    instance.swap(mInstance);
  1.3677 +
  1.3678 +    if (PluginDestructionGuard::DelayDestroy(instance)) {
  1.3679 +      // It's still not safe to destroy the plugin, it's now up to the
  1.3680 +      // outermost guard on the stack to take care of the destruction.
  1.3681 +      return NS_OK;
  1.3682 +    }
  1.3683 +
  1.3684 +    nsPluginDestroyRunnable *r =
  1.3685 +      static_cast<nsPluginDestroyRunnable*>(PR_NEXT_LINK(&sRunnableListHead));
  1.3686 +
  1.3687 +    while (r != &sRunnableListHead) {
  1.3688 +      if (r != this && r->mInstance == instance) {
  1.3689 +        // There's another runnable scheduled to tear down
  1.3690 +        // instance. Let it do the job.
  1.3691 +        return NS_OK;
  1.3692 +      }
  1.3693 +      r = static_cast<nsPluginDestroyRunnable*>(PR_NEXT_LINK(r));
  1.3694 +    }
  1.3695 +
  1.3696 +    PLUGIN_LOG(PLUGIN_LOG_NORMAL,
  1.3697 +               ("Doing delayed destroy of instance %p\n", instance.get()));
  1.3698 +
  1.3699 +    nsRefPtr<nsPluginHost> host = nsPluginHost::GetInst();
  1.3700 +    if (host)
  1.3701 +      host->StopPluginInstance(instance);
  1.3702 +
  1.3703 +    PLUGIN_LOG(PLUGIN_LOG_NORMAL,
  1.3704 +               ("Done with delayed destroy of instance %p\n", instance.get()));
  1.3705 +
  1.3706 +    return NS_OK;
  1.3707 +  }
  1.3708 +
  1.3709 +protected:
  1.3710 +  nsRefPtr<nsNPAPIPluginInstance> mInstance;
  1.3711 +
  1.3712 +  static PRCList sRunnableListHead;
  1.3713 +};
  1.3714 +
  1.3715 +PRCList nsPluginDestroyRunnable::sRunnableListHead =
  1.3716 +  PR_INIT_STATIC_CLIST(&nsPluginDestroyRunnable::sRunnableListHead);
  1.3717 +
  1.3718 +PRCList PluginDestructionGuard::sListHead =
  1.3719 +  PR_INIT_STATIC_CLIST(&PluginDestructionGuard::sListHead);
  1.3720 +
  1.3721 +PluginDestructionGuard::PluginDestructionGuard(nsNPAPIPluginInstance *aInstance)
  1.3722 +  : mInstance(aInstance)
  1.3723 +{
  1.3724 +  Init();
  1.3725 +}
  1.3726 +
  1.3727 +PluginDestructionGuard::PluginDestructionGuard(NPP npp)
  1.3728 +  : mInstance(npp ? static_cast<nsNPAPIPluginInstance*>(npp->ndata) : nullptr)
  1.3729 +{
  1.3730 +  Init();
  1.3731 +}
  1.3732 +
  1.3733 +PluginDestructionGuard::~PluginDestructionGuard()
  1.3734 +{
  1.3735 +  NS_ASSERTION(NS_IsMainThread(), "Should be on the main thread");
  1.3736 +
  1.3737 +  PR_REMOVE_LINK(this);
  1.3738 +
  1.3739 +  if (mDelayedDestroy) {
  1.3740 +    // We've attempted to destroy the plugin instance we're holding on
  1.3741 +    // to while we were guarding it. Do the actual destroy now, off of
  1.3742 +    // a runnable.
  1.3743 +    nsRefPtr<nsPluginDestroyRunnable> evt =
  1.3744 +      new nsPluginDestroyRunnable(mInstance);
  1.3745 +
  1.3746 +    NS_DispatchToMainThread(evt);
  1.3747 +  }
  1.3748 +}
  1.3749 +
  1.3750 +// static
  1.3751 +bool
  1.3752 +PluginDestructionGuard::DelayDestroy(nsNPAPIPluginInstance *aInstance)
  1.3753 +{
  1.3754 +  NS_ASSERTION(NS_IsMainThread(), "Should be on the main thread");
  1.3755 +  NS_ASSERTION(aInstance, "Uh, I need an instance!");
  1.3756 +
  1.3757 +  // Find the first guard on the stack and make it do a delayed
  1.3758 +  // destroy upon destruction.
  1.3759 +
  1.3760 +  PluginDestructionGuard *g =
  1.3761 +    static_cast<PluginDestructionGuard*>(PR_LIST_HEAD(&sListHead));
  1.3762 +
  1.3763 +  while (g != &sListHead) {
  1.3764 +    if (g->mInstance == aInstance) {
  1.3765 +      g->mDelayedDestroy = true;
  1.3766 +
  1.3767 +      return true;
  1.3768 +    }
  1.3769 +    g = static_cast<PluginDestructionGuard*>(PR_NEXT_LINK(g));
  1.3770 +  }
  1.3771 +
  1.3772 +  return false;
  1.3773 +}

mercurial