summaryrefslogtreecommitdiffstats
path: root/dom/plugins/base/nsPluginTags.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'dom/plugins/base/nsPluginTags.cpp')
-rw-r--r--dom/plugins/base/nsPluginTags.cpp1045
1 files changed, 1045 insertions, 0 deletions
diff --git a/dom/plugins/base/nsPluginTags.cpp b/dom/plugins/base/nsPluginTags.cpp
new file mode 100644
index 000000000..ddc3968fd
--- /dev/null
+++ b/dom/plugins/base/nsPluginTags.cpp
@@ -0,0 +1,1045 @@
+/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#include "nsPluginTags.h"
+
+#include "prlink.h"
+#include "plstr.h"
+#include "nsIPluginInstanceOwner.h"
+#include "nsPluginsDir.h"
+#include "nsPluginHost.h"
+#include "nsIBlocklistService.h"
+#include "nsIUnicodeDecoder.h"
+#include "nsIPlatformCharset.h"
+#include "nsPluginLogging.h"
+#include "nsNPAPIPlugin.h"
+#include "nsCharSeparatedTokenizer.h"
+#include "mozilla/Preferences.h"
+#include "mozilla/Unused.h"
+#include "nsNetUtil.h"
+#include <cctype>
+#include "mozilla/dom/EncodingUtils.h"
+#include "mozilla/dom/ContentChild.h"
+#include "mozilla/dom/FakePluginTagInitBinding.h"
+
+using mozilla::dom::EncodingUtils;
+using mozilla::dom::FakePluginTagInit;
+using namespace mozilla;
+
+// These legacy flags are used in the plugin registry. The states are now
+// stored in prefs, but we still need to be able to import them.
+#define NS_PLUGIN_FLAG_ENABLED 0x0001 // is this plugin enabled?
+// no longer used 0x0002 // reuse only if regenerating pluginreg.dat
+#define NS_PLUGIN_FLAG_FROMCACHE 0x0004 // this plugintag info was loaded from cache
+// no longer used 0x0008 // reuse only if regenerating pluginreg.dat
+#define NS_PLUGIN_FLAG_CLICKTOPLAY 0x0020 // this is a click-to-play plugin
+
+static const char kPrefDefaultEnabledState[] = "plugin.default.state";
+static const char kPrefDefaultEnabledStateXpi[] = "plugin.defaultXpi.state";
+
+// check comma delimited extensions
+static bool ExtensionInList(const nsCString& aExtensionList,
+ const nsACString& aExtension)
+{
+ nsCCharSeparatedTokenizer extensions(aExtensionList, ',');
+ while (extensions.hasMoreTokens()) {
+ const nsCSubstring& extension = extensions.nextToken();
+ if (extension.Equals(aExtension, nsCaseInsensitiveCStringComparator())) {
+ return true;
+ }
+ }
+ return false;
+}
+
+// Search for an extension in an extensions array, and return its
+// matching mime type
+static bool SearchExtensions(const nsTArray<nsCString> & aExtensions,
+ const nsTArray<nsCString> & aMimeTypes,
+ const nsACString & aFindExtension,
+ nsACString & aMatchingType)
+{
+ uint32_t mimes = aMimeTypes.Length();
+ MOZ_ASSERT(mimes == aExtensions.Length(),
+ "These arrays should have matching elements");
+
+ aMatchingType.Truncate();
+
+ for (uint32_t i = 0; i < mimes; i++) {
+ if (ExtensionInList(aExtensions[i], aFindExtension)) {
+ aMatchingType = aMimeTypes[i];
+ return true;
+ }
+ }
+
+ return false;
+}
+
+static nsCString
+MakeNiceFileName(const nsCString & aFileName)
+{
+ nsCString niceName = aFileName;
+ int32_t niceNameLength = aFileName.RFind(".");
+ NS_ASSERTION(niceNameLength != kNotFound, "aFileName doesn't have a '.'?");
+ while (niceNameLength > 0) {
+ char chr = aFileName[niceNameLength - 1];
+ if (!std::isalpha(chr))
+ niceNameLength--;
+ else
+ break;
+ }
+
+ // If it turns out that niceNameLength <= 0, we'll fall back and use the
+ // entire aFileName (which we've already taken care of, a few lines back).
+ if (niceNameLength > 0) {
+ niceName.Truncate(niceNameLength);
+ }
+
+ ToLowerCase(niceName);
+ return niceName;
+}
+
+static nsCString
+MakePrefNameForPlugin(const char* const subname, nsIInternalPluginTag* aTag)
+{
+ nsCString pref;
+ nsAutoCString pluginName(aTag->GetNiceFileName());
+
+ if (pluginName.IsEmpty()) {
+ // Use filename if nice name fails
+ pluginName = aTag->FileName();
+ if (pluginName.IsEmpty()) {
+ MOZ_ASSERT_UNREACHABLE("Plugin with no filename or nice name in list");
+ pluginName.AssignLiteral("unknown-plugin-name");
+ }
+ }
+
+ pref.AssignLiteral("plugin.");
+ pref.Append(subname);
+ pref.Append('.');
+ pref.Append(pluginName);
+
+ return pref;
+}
+
+static nsresult
+CStringArrayToXPCArray(nsTArray<nsCString> & aArray,
+ uint32_t* aCount,
+ char16_t*** aResults)
+{
+ uint32_t count = aArray.Length();
+ if (!count) {
+ *aResults = nullptr;
+ *aCount = 0;
+ return NS_OK;
+ }
+
+ *aResults =
+ static_cast<char16_t**>(moz_xmalloc(count * sizeof(**aResults)));
+ *aCount = count;
+
+ for (uint32_t i = 0; i < count; i++) {
+ (*aResults)[i] = ToNewUnicode(NS_ConvertUTF8toUTF16(aArray[i]));
+ }
+
+ return NS_OK;
+}
+
+static nsCString
+GetStatePrefNameForPlugin(nsIInternalPluginTag* aTag)
+{
+ return MakePrefNameForPlugin("state", aTag);
+}
+
+static nsresult
+IsEnabledStateLockedForPlugin(nsIInternalPluginTag* aTag,
+ bool* aIsEnabledStateLocked)
+{
+ *aIsEnabledStateLocked = false;
+ nsCOMPtr<nsIPrefBranch> prefs(do_GetService(NS_PREFSERVICE_CONTRACTID));
+
+ if (NS_WARN_IF(!prefs)) {
+ return NS_ERROR_FAILURE;
+ }
+
+ Unused << prefs->PrefIsLocked(GetStatePrefNameForPlugin(aTag).get(),
+ aIsEnabledStateLocked);
+
+ return NS_OK;
+}
+
+/* nsIInternalPluginTag */
+nsIInternalPluginTag::nsIInternalPluginTag()
+{
+}
+
+nsIInternalPluginTag::nsIInternalPluginTag(const char* aName,
+ const char* aDescription,
+ const char* aFileName,
+ const char* aVersion)
+ : mName(aName)
+ , mDescription(aDescription)
+ , mFileName(aFileName)
+ , mVersion(aVersion)
+{
+}
+
+nsIInternalPluginTag::nsIInternalPluginTag(const char* aName,
+ const char* aDescription,
+ const char* aFileName,
+ const char* aVersion,
+ const nsTArray<nsCString>& aMimeTypes,
+ const nsTArray<nsCString>& aMimeDescriptions,
+ const nsTArray<nsCString>& aExtensions)
+ : mName(aName)
+ , mDescription(aDescription)
+ , mFileName(aFileName)
+ , mVersion(aVersion)
+ , mMimeTypes(aMimeTypes)
+ , mMimeDescriptions(aMimeDescriptions)
+ , mExtensions(aExtensions)
+{
+}
+
+nsIInternalPluginTag::~nsIInternalPluginTag()
+{
+}
+
+bool
+nsIInternalPluginTag::HasExtension(const nsACString& aExtension,
+ nsACString& aMatchingType) const
+{
+ return SearchExtensions(mExtensions, mMimeTypes, aExtension, aMatchingType);
+}
+
+bool
+nsIInternalPluginTag::HasMimeType(const nsACString& aMimeType) const
+{
+ return mMimeTypes.Contains(aMimeType,
+ nsCaseInsensitiveCStringArrayComparator());
+}
+
+/* nsPluginTag */
+
+uint32_t nsPluginTag::sNextId;
+
+nsPluginTag::nsPluginTag(nsPluginInfo* aPluginInfo,
+ int64_t aLastModifiedTime,
+ bool fromExtension)
+ : nsIInternalPluginTag(aPluginInfo->fName, aPluginInfo->fDescription,
+ aPluginInfo->fFileName, aPluginInfo->fVersion),
+ mId(sNextId++),
+ mContentProcessRunningCount(0),
+ mHadLocalInstance(false),
+ mLibrary(nullptr),
+ mIsJavaPlugin(false),
+ mIsFlashPlugin(false),
+ mSupportsAsyncInit(false),
+ mSupportsAsyncRender(false),
+ mFullPath(aPluginInfo->fFullPath),
+ mLastModifiedTime(aLastModifiedTime),
+ mSandboxLevel(0),
+ mCachedBlocklistState(nsIBlocklistService::STATE_NOT_BLOCKED),
+ mCachedBlocklistStateValid(false),
+ mIsFromExtension(fromExtension)
+{
+ InitMime(aPluginInfo->fMimeTypeArray,
+ aPluginInfo->fMimeDescriptionArray,
+ aPluginInfo->fExtensionArray,
+ aPluginInfo->fVariantCount);
+ InitSandboxLevel();
+ EnsureMembersAreUTF8();
+ FixupVersion();
+}
+
+nsPluginTag::nsPluginTag(const char* aName,
+ const char* aDescription,
+ const char* aFileName,
+ const char* aFullPath,
+ const char* aVersion,
+ const char* const* aMimeTypes,
+ const char* const* aMimeDescriptions,
+ const char* const* aExtensions,
+ int32_t aVariants,
+ int64_t aLastModifiedTime,
+ bool fromExtension,
+ bool aArgsAreUTF8)
+ : nsIInternalPluginTag(aName, aDescription, aFileName, aVersion),
+ mId(sNextId++),
+ mContentProcessRunningCount(0),
+ mHadLocalInstance(false),
+ mLibrary(nullptr),
+ mIsJavaPlugin(false),
+ mIsFlashPlugin(false),
+ mSupportsAsyncInit(false),
+ mSupportsAsyncRender(false),
+ mFullPath(aFullPath),
+ mLastModifiedTime(aLastModifiedTime),
+ mSandboxLevel(0),
+ mCachedBlocklistState(nsIBlocklistService::STATE_NOT_BLOCKED),
+ mCachedBlocklistStateValid(false),
+ mIsFromExtension(fromExtension)
+{
+ InitMime(aMimeTypes, aMimeDescriptions, aExtensions,
+ static_cast<uint32_t>(aVariants));
+ InitSandboxLevel();
+ if (!aArgsAreUTF8)
+ EnsureMembersAreUTF8();
+ FixupVersion();
+}
+
+nsPluginTag::nsPluginTag(uint32_t aId,
+ const char* aName,
+ const char* aDescription,
+ const char* aFileName,
+ const char* aFullPath,
+ const char* aVersion,
+ nsTArray<nsCString> aMimeTypes,
+ nsTArray<nsCString> aMimeDescriptions,
+ nsTArray<nsCString> aExtensions,
+ bool aIsJavaPlugin,
+ bool aIsFlashPlugin,
+ bool aSupportsAsyncInit,
+ bool aSupportsAsyncRender,
+ int64_t aLastModifiedTime,
+ bool aFromExtension,
+ int32_t aSandboxLevel)
+ : nsIInternalPluginTag(aName, aDescription, aFileName, aVersion, aMimeTypes,
+ aMimeDescriptions, aExtensions),
+ mId(aId),
+ mContentProcessRunningCount(0),
+ mLibrary(nullptr),
+ mIsJavaPlugin(aIsJavaPlugin),
+ mIsFlashPlugin(aIsFlashPlugin),
+ mSupportsAsyncInit(aSupportsAsyncInit),
+ mSupportsAsyncRender(aSupportsAsyncRender),
+ mLastModifiedTime(aLastModifiedTime),
+ mSandboxLevel(aSandboxLevel),
+ mNiceFileName(),
+ mCachedBlocklistState(nsIBlocklistService::STATE_NOT_BLOCKED),
+ mCachedBlocklistStateValid(false),
+ mIsFromExtension(aFromExtension)
+{
+}
+
+nsPluginTag::~nsPluginTag()
+{
+ NS_ASSERTION(!mNext, "Risk of exhausting the stack space, bug 486349");
+}
+
+NS_IMPL_ISUPPORTS(nsPluginTag, nsPluginTag, nsIInternalPluginTag, nsIPluginTag)
+
+void nsPluginTag::InitMime(const char* const* aMimeTypes,
+ const char* const* aMimeDescriptions,
+ const char* const* aExtensions,
+ uint32_t aVariantCount)
+{
+ if (!aMimeTypes) {
+ return;
+ }
+
+ for (uint32_t i = 0; i < aVariantCount; i++) {
+ if (!aMimeTypes[i]) {
+ continue;
+ }
+
+ nsAutoCString mimeType(aMimeTypes[i]);
+
+ // Convert the MIME type, which is case insensitive, to lowercase in order
+ // to properly handle a mixed-case type.
+ ToLowerCase(mimeType);
+
+ if (!nsPluginHost::IsTypeWhitelisted(mimeType.get())) {
+ continue;
+ }
+
+ // Look for certain special plugins.
+ switch (nsPluginHost::GetSpecialType(mimeType)) {
+ case nsPluginHost::eSpecialType_Java:
+ mIsJavaPlugin = true;
+ mSupportsAsyncInit = true;
+ break;
+ case nsPluginHost::eSpecialType_Flash:
+ // VLC sometimes claims to implement the Flash MIME type, and we want
+ // to allow users to control that separately from Adobe Flash.
+ if (Name().EqualsLiteral("Shockwave Flash")) {
+ mIsFlashPlugin = true;
+ mSupportsAsyncInit = true;
+ }
+ break;
+ case nsPluginHost::eSpecialType_Silverlight:
+ case nsPluginHost::eSpecialType_Unity:
+ case nsPluginHost::eSpecialType_Test:
+ mSupportsAsyncInit = true;
+ break;
+ case nsPluginHost::eSpecialType_None:
+ default:
+#ifndef RELEASE_OR_BETA
+ // Allow async init for all plugins on Nightly and Aurora
+ mSupportsAsyncInit = true;
+#endif
+ break;
+ }
+
+ // Fill in our MIME type array.
+ mMimeTypes.AppendElement(mimeType);
+
+ // Now fill in the MIME descriptions.
+ if (aMimeDescriptions && aMimeDescriptions[i]) {
+ // we should cut off the list of suffixes which the mime
+ // description string may have, see bug 53895
+ // it is usually in form "some description (*.sf1, *.sf2)"
+ // so we can search for the opening round bracket
+ char cur = '\0';
+ char pre = '\0';
+ char * p = PL_strrchr(aMimeDescriptions[i], '(');
+ if (p && (p != aMimeDescriptions[i])) {
+ if ((p - 1) && *(p - 1) == ' ') {
+ pre = *(p - 1);
+ *(p - 1) = '\0';
+ } else {
+ cur = *p;
+ *p = '\0';
+ }
+ }
+ mMimeDescriptions.AppendElement(nsCString(aMimeDescriptions[i]));
+ // restore the original string
+ if (cur != '\0') {
+ *p = cur;
+ }
+ if (pre != '\0') {
+ *(p - 1) = pre;
+ }
+ } else {
+ mMimeDescriptions.AppendElement(nsCString());
+ }
+
+ // Now fill in the extensions.
+ if (aExtensions && aExtensions[i]) {
+ mExtensions.AppendElement(nsCString(aExtensions[i]));
+ } else {
+ mExtensions.AppendElement(nsCString());
+ }
+ }
+}
+
+void
+nsPluginTag::InitSandboxLevel()
+{
+#if defined(XP_WIN) && defined(MOZ_SANDBOX)
+ nsAutoCString sandboxPref("dom.ipc.plugins.sandbox-level.");
+ sandboxPref.Append(GetNiceFileName());
+ if (NS_FAILED(Preferences::GetInt(sandboxPref.get(), &mSandboxLevel))) {
+ mSandboxLevel = Preferences::GetInt("dom.ipc.plugins.sandbox-level.default"
+);
+ }
+
+#if defined(_AMD64_)
+ // As level 2 is now the default NPAPI sandbox level for 64-bit flash, we
+ // don't want to allow a lower setting unless this environment variable is
+ // set. This should be changed if the firefox.js pref file is changed.
+ if (mIsFlashPlugin &&
+ !PR_GetEnv("MOZ_ALLOW_WEAKER_SANDBOX") && mSandboxLevel < 2) {
+ mSandboxLevel = 2;
+ }
+#endif
+#endif
+}
+
+#if !defined(XP_WIN) && !defined(XP_MACOSX)
+static nsresult ConvertToUTF8(nsIUnicodeDecoder *aUnicodeDecoder,
+ nsAFlatCString& aString)
+{
+ int32_t numberOfBytes = aString.Length();
+ int32_t outUnicodeLen;
+ nsAutoString buffer;
+ nsresult rv = aUnicodeDecoder->GetMaxLength(aString.get(), numberOfBytes,
+ &outUnicodeLen);
+ NS_ENSURE_SUCCESS(rv, rv);
+ if (!buffer.SetLength(outUnicodeLen, fallible))
+ return NS_ERROR_OUT_OF_MEMORY;
+ rv = aUnicodeDecoder->Convert(aString.get(), &numberOfBytes,
+ buffer.BeginWriting(), &outUnicodeLen);
+ NS_ENSURE_SUCCESS(rv, rv);
+ buffer.SetLength(outUnicodeLen);
+ CopyUTF16toUTF8(buffer, aString);
+
+ return NS_OK;
+}
+#endif
+
+nsresult nsPluginTag::EnsureMembersAreUTF8()
+{
+#if defined(XP_WIN) || defined(XP_MACOSX)
+ return NS_OK;
+#else
+ nsresult rv;
+
+ nsCOMPtr<nsIPlatformCharset> pcs =
+ do_GetService(NS_PLATFORMCHARSET_CONTRACTID, &rv);
+ NS_ENSURE_SUCCESS(rv, rv);
+ nsCOMPtr<nsIUnicodeDecoder> decoder;
+
+ nsAutoCString charset;
+ rv = pcs->GetCharset(kPlatformCharsetSel_FileName, charset);
+ NS_ENSURE_SUCCESS(rv, rv);
+ if (!charset.LowerCaseEqualsLiteral("utf-8")) {
+ decoder = EncodingUtils::DecoderForEncoding(charset);
+ ConvertToUTF8(decoder, mFileName);
+ ConvertToUTF8(decoder, mFullPath);
+ }
+
+ // The description of the plug-in and the various MIME type descriptions
+ // should be encoded in the standard plain text file encoding for this system.
+ // XXX should we add kPlatformCharsetSel_PluginResource?
+ rv = pcs->GetCharset(kPlatformCharsetSel_PlainTextInFile, charset);
+ NS_ENSURE_SUCCESS(rv, rv);
+ if (!charset.LowerCaseEqualsLiteral("utf-8")) {
+ decoder = EncodingUtils::DecoderForEncoding(charset);
+ ConvertToUTF8(decoder, mName);
+ ConvertToUTF8(decoder, mDescription);
+ for (uint32_t i = 0; i < mMimeDescriptions.Length(); ++i) {
+ ConvertToUTF8(decoder, mMimeDescriptions[i]);
+ }
+ }
+ return NS_OK;
+#endif
+}
+
+void nsPluginTag::FixupVersion()
+{
+#if defined(XP_LINUX)
+ if (mIsFlashPlugin) {
+ mVersion.ReplaceChar(',', '.');
+ }
+#endif
+}
+
+NS_IMETHODIMP
+nsPluginTag::GetDescription(nsACString& aDescription)
+{
+ aDescription = mDescription;
+ return NS_OK;
+}
+
+NS_IMETHODIMP
+nsPluginTag::GetFilename(nsACString& aFileName)
+{
+ aFileName = mFileName;
+ return NS_OK;
+}
+
+NS_IMETHODIMP
+nsPluginTag::GetFullpath(nsACString& aFullPath)
+{
+ aFullPath = mFullPath;
+ return NS_OK;
+}
+
+NS_IMETHODIMP
+nsPluginTag::GetVersion(nsACString& aVersion)
+{
+ aVersion = mVersion;
+ return NS_OK;
+}
+
+NS_IMETHODIMP
+nsPluginTag::GetName(nsACString& aName)
+{
+ aName = mName;
+ return NS_OK;
+}
+
+bool
+nsPluginTag::IsActive()
+{
+ return IsEnabled() && !IsBlocklisted();
+}
+
+NS_IMETHODIMP
+nsPluginTag::GetActive(bool *aResult)
+{
+ *aResult = IsActive();
+ return NS_OK;
+}
+
+bool
+nsPluginTag::IsEnabled()
+{
+ const PluginState state = GetPluginState();
+ return (state == ePluginState_Enabled) || (state == ePluginState_Clicktoplay);
+}
+
+NS_IMETHODIMP
+nsPluginTag::GetDisabled(bool* aDisabled)
+{
+ *aDisabled = !IsEnabled();
+ return NS_OK;
+}
+
+bool
+nsPluginTag::IsBlocklisted()
+{
+ uint32_t blocklistState;
+ nsresult rv = GetBlocklistState(&blocklistState);
+ return NS_FAILED(rv) || blocklistState == nsIBlocklistService::STATE_BLOCKED;
+}
+
+NS_IMETHODIMP
+nsPluginTag::GetBlocklisted(bool* aBlocklisted)
+{
+ *aBlocklisted = IsBlocklisted();
+ return NS_OK;
+}
+
+NS_IMETHODIMP
+nsPluginTag::GetIsEnabledStateLocked(bool* aIsEnabledStateLocked)
+{
+ return IsEnabledStateLockedForPlugin(this, aIsEnabledStateLocked);
+}
+
+bool
+nsPluginTag::IsClicktoplay()
+{
+ const PluginState state = GetPluginState();
+ return (state == ePluginState_Clicktoplay);
+}
+
+NS_IMETHODIMP
+nsPluginTag::GetClicktoplay(bool *aClicktoplay)
+{
+ *aClicktoplay = IsClicktoplay();
+ return NS_OK;
+}
+
+NS_IMETHODIMP
+nsPluginTag::GetEnabledState(uint32_t *aEnabledState)
+{
+ int32_t enabledState;
+ nsresult rv = Preferences::GetInt(GetStatePrefNameForPlugin(this).get(),
+ &enabledState);
+ if (NS_SUCCEEDED(rv) &&
+ enabledState >= nsIPluginTag::STATE_DISABLED &&
+ enabledState <= nsIPluginTag::STATE_ENABLED) {
+ *aEnabledState = (uint32_t)enabledState;
+ return rv;
+ }
+
+ const char* const pref = mIsFromExtension ? kPrefDefaultEnabledStateXpi
+ : kPrefDefaultEnabledState;
+
+ enabledState = Preferences::GetInt(pref, nsIPluginTag::STATE_ENABLED);
+ if (enabledState >= nsIPluginTag::STATE_DISABLED &&
+ enabledState <= nsIPluginTag::STATE_ENABLED) {
+ *aEnabledState = (uint32_t)enabledState;
+ return NS_OK;
+ }
+
+ return NS_ERROR_UNEXPECTED;
+}
+
+NS_IMETHODIMP
+nsPluginTag::SetEnabledState(uint32_t aEnabledState)
+{
+ if (aEnabledState >= ePluginState_MaxValue)
+ return NS_ERROR_ILLEGAL_VALUE;
+ uint32_t oldState = nsIPluginTag::STATE_DISABLED;
+ GetEnabledState(&oldState);
+ if (oldState != aEnabledState) {
+ Preferences::SetInt(GetStatePrefNameForPlugin(this).get(), aEnabledState);
+ if (RefPtr<nsPluginHost> host = nsPluginHost::GetInst()) {
+ host->UpdatePluginInfo(this);
+ }
+ }
+ return NS_OK;
+}
+
+nsPluginTag::PluginState
+nsPluginTag::GetPluginState()
+{
+ uint32_t enabledState = nsIPluginTag::STATE_DISABLED;
+ GetEnabledState(&enabledState);
+ return (PluginState)enabledState;
+}
+
+void
+nsPluginTag::SetPluginState(PluginState state)
+{
+ static_assert((uint32_t)nsPluginTag::ePluginState_Disabled == nsIPluginTag::STATE_DISABLED, "nsPluginTag::ePluginState_Disabled must match nsIPluginTag::STATE_DISABLED");
+ static_assert((uint32_t)nsPluginTag::ePluginState_Clicktoplay == nsIPluginTag::STATE_CLICKTOPLAY, "nsPluginTag::ePluginState_Clicktoplay must match nsIPluginTag::STATE_CLICKTOPLAY");
+ static_assert((uint32_t)nsPluginTag::ePluginState_Enabled == nsIPluginTag::STATE_ENABLED, "nsPluginTag::ePluginState_Enabled must match nsIPluginTag::STATE_ENABLED");
+ SetEnabledState((uint32_t)state);
+}
+
+NS_IMETHODIMP
+nsPluginTag::GetMimeTypes(uint32_t* aCount, char16_t*** aResults)
+{
+ return CStringArrayToXPCArray(mMimeTypes, aCount, aResults);
+}
+
+NS_IMETHODIMP
+nsPluginTag::GetMimeDescriptions(uint32_t* aCount, char16_t*** aResults)
+{
+ return CStringArrayToXPCArray(mMimeDescriptions, aCount, aResults);
+}
+
+NS_IMETHODIMP
+nsPluginTag::GetExtensions(uint32_t* aCount, char16_t*** aResults)
+{
+ return CStringArrayToXPCArray(mExtensions, aCount, aResults);
+}
+
+bool
+nsPluginTag::HasSameNameAndMimes(const nsPluginTag *aPluginTag) const
+{
+ NS_ENSURE_TRUE(aPluginTag, false);
+
+ if ((!mName.Equals(aPluginTag->mName)) ||
+ (mMimeTypes.Length() != aPluginTag->mMimeTypes.Length())) {
+ return false;
+ }
+
+ for (uint32_t i = 0; i < mMimeTypes.Length(); i++) {
+ if (!mMimeTypes[i].Equals(aPluginTag->mMimeTypes[i])) {
+ return false;
+ }
+ }
+
+ return true;
+}
+
+NS_IMETHODIMP
+nsPluginTag::GetLoaded(bool* aIsLoaded)
+{
+ *aIsLoaded = !!mPlugin;
+ return NS_OK;
+}
+
+void nsPluginTag::TryUnloadPlugin(bool inShutdown)
+{
+ // We never want to send NPP_Shutdown to an in-process plugin unless
+ // this process is shutting down.
+ if (!mPlugin) {
+ return;
+ }
+ if (inShutdown || mPlugin->GetLibrary()->IsOOP()) {
+ mPlugin->Shutdown();
+ mPlugin = nullptr;
+ }
+}
+
+const nsCString&
+nsPluginTag::GetNiceFileName()
+{
+ if (!mNiceFileName.IsEmpty()) {
+ return mNiceFileName;
+ }
+
+ if (mIsFlashPlugin) {
+ mNiceFileName.AssignLiteral("flash");
+ return mNiceFileName;
+ }
+
+ if (mIsJavaPlugin) {
+ mNiceFileName.AssignLiteral("java");
+ return mNiceFileName;
+ }
+
+ mNiceFileName = MakeNiceFileName(mFileName);
+ return mNiceFileName;
+}
+
+NS_IMETHODIMP
+nsPluginTag::GetNiceName(nsACString & aResult)
+{
+ aResult = GetNiceFileName();
+ return NS_OK;
+}
+
+NS_IMETHODIMP
+nsPluginTag::GetBlocklistState(uint32_t *aResult)
+{
+#if defined(MOZ_WIDGET_ANDROID)
+ *aResult = nsIBlocklistService::STATE_NOT_BLOCKED;
+ return NS_OK;
+#else
+ if (mCachedBlocklistStateValid) {
+ *aResult = mCachedBlocklistState;
+ return NS_OK;
+ }
+
+ if (!XRE_IsParentProcess()) {
+ *aResult = nsIBlocklistService::STATE_BLOCKED;
+ dom::ContentChild* cp = dom::ContentChild::GetSingleton();
+ if (!cp->SendGetBlocklistState(mId, aResult)) {
+ return NS_OK;
+ }
+ } else {
+ nsCOMPtr<nsIBlocklistService> blocklist =
+ do_GetService("@mozilla.org/extensions/blocklist;1");
+
+ if (!blocklist) {
+ *aResult = nsIBlocklistService::STATE_NOT_BLOCKED;
+ return NS_OK;
+ }
+
+ // The EmptyString()s are so we use the currently running application
+ // and toolkit versions
+ if (NS_FAILED(blocklist->GetPluginBlocklistState(this, EmptyString(),
+ EmptyString(), aResult))) {
+ *aResult = nsIBlocklistService::STATE_NOT_BLOCKED;
+ return NS_OK;
+ }
+ }
+
+ MOZ_ASSERT(*aResult <= UINT16_MAX);
+ mCachedBlocklistState = (uint16_t) *aResult;
+ mCachedBlocklistStateValid = true;
+ return NS_OK;
+#endif // defined(MOZ_WIDGET_ANDROID)
+}
+
+void
+nsPluginTag::InvalidateBlocklistState()
+{
+ mCachedBlocklistStateValid = false;
+}
+
+NS_IMETHODIMP
+nsPluginTag::GetLastModifiedTime(PRTime* aLastModifiedTime)
+{
+ MOZ_ASSERT(aLastModifiedTime);
+ *aLastModifiedTime = mLastModifiedTime;
+ return NS_OK;
+}
+
+bool nsPluginTag::IsFromExtension() const
+{
+ return mIsFromExtension;
+}
+
+/* nsFakePluginTag */
+
+nsFakePluginTag::nsFakePluginTag()
+ : mState(nsPluginTag::ePluginState_Disabled)
+{
+}
+
+nsFakePluginTag::~nsFakePluginTag()
+{
+}
+
+NS_IMPL_ADDREF(nsFakePluginTag)
+NS_IMPL_RELEASE(nsFakePluginTag)
+NS_INTERFACE_TABLE_HEAD(nsFakePluginTag)
+ NS_INTERFACE_TABLE_BEGIN
+ NS_INTERFACE_TABLE_ENTRY_AMBIGUOUS(nsFakePluginTag, nsIPluginTag,
+ nsIInternalPluginTag)
+ NS_INTERFACE_TABLE_ENTRY(nsFakePluginTag, nsIInternalPluginTag)
+ NS_INTERFACE_TABLE_ENTRY_AMBIGUOUS(nsFakePluginTag, nsISupports,
+ nsIInternalPluginTag)
+ NS_INTERFACE_TABLE_ENTRY(nsFakePluginTag, nsIFakePluginTag)
+ NS_INTERFACE_TABLE_END
+NS_INTERFACE_TABLE_TAIL
+
+/* static */
+nsresult
+nsFakePluginTag::Create(const FakePluginTagInit& aInitDictionary,
+ nsFakePluginTag** aPluginTag)
+{
+ NS_ENSURE_TRUE(!aInitDictionary.mMimeEntries.IsEmpty(), NS_ERROR_INVALID_ARG);
+
+ RefPtr<nsFakePluginTag> tag = new nsFakePluginTag();
+ nsresult rv = NS_NewURI(getter_AddRefs(tag->mHandlerURI),
+ aInitDictionary.mHandlerURI);
+ NS_ENSURE_SUCCESS(rv, rv);
+
+ CopyUTF16toUTF8(aInitDictionary.mNiceName, tag->mNiceName);
+ CopyUTF16toUTF8(aInitDictionary.mFullPath, tag->mFullPath);
+ CopyUTF16toUTF8(aInitDictionary.mName, tag->mName);
+ CopyUTF16toUTF8(aInitDictionary.mDescription, tag->mDescription);
+ CopyUTF16toUTF8(aInitDictionary.mFileName, tag->mFileName);
+ CopyUTF16toUTF8(aInitDictionary.mVersion, tag->mVersion);
+
+ for (const FakePluginMimeEntry& mimeEntry : aInitDictionary.mMimeEntries) {
+ CopyUTF16toUTF8(mimeEntry.mType, *tag->mMimeTypes.AppendElement());
+ CopyUTF16toUTF8(mimeEntry.mDescription,
+ *tag->mMimeDescriptions.AppendElement());
+ CopyUTF16toUTF8(mimeEntry.mExtension, *tag->mExtensions.AppendElement());
+ }
+
+ tag.forget(aPluginTag);
+ return NS_OK;
+}
+
+bool
+nsFakePluginTag::HandlerURIMatches(nsIURI* aURI)
+{
+ bool equals = false;
+ return NS_SUCCEEDED(mHandlerURI->Equals(aURI, &equals)) && equals;
+}
+
+NS_IMETHODIMP
+nsFakePluginTag::GetHandlerURI(nsIURI **aResult)
+{
+ NS_IF_ADDREF(*aResult = mHandlerURI);
+ return NS_OK;
+}
+
+NS_IMETHODIMP
+nsFakePluginTag::GetDescription(/* utf-8 */ nsACString& aResult)
+{
+ aResult = mDescription;
+ return NS_OK;
+}
+
+NS_IMETHODIMP
+nsFakePluginTag::GetFilename(/* utf-8 */ nsACString& aResult)
+{
+ aResult = mFileName;
+ return NS_OK;
+}
+
+NS_IMETHODIMP
+nsFakePluginTag::GetFullpath(/* utf-8 */ nsACString& aResult)
+{
+ aResult = mFullPath;
+ return NS_OK;
+}
+
+NS_IMETHODIMP
+nsFakePluginTag::GetVersion(/* utf-8 */ nsACString& aResult)
+{
+ aResult = mVersion;
+ return NS_OK;
+}
+
+NS_IMETHODIMP
+nsFakePluginTag::GetName(/* utf-8 */ nsACString& aResult)
+{
+ aResult = mName;
+ return NS_OK;
+}
+
+const nsCString&
+nsFakePluginTag::GetNiceFileName()
+{
+ // We don't try to mimic the special-cased flash/java names if the fake plugin
+ // claims one of their MIME types, but do allow directly setting niceName if
+ // emulating those is desired.
+ if (mNiceName.IsEmpty() && !mFileName.IsEmpty()) {
+ mNiceName = MakeNiceFileName(mFileName);
+ }
+
+ return mNiceName;
+}
+
+NS_IMETHODIMP
+nsFakePluginTag::GetNiceName(/* utf-8 */ nsACString& aResult)
+{
+ aResult = GetNiceFileName();
+ return NS_OK;
+}
+
+NS_IMETHODIMP
+nsFakePluginTag::GetBlocklistState(uint32_t* aResult)
+{
+ // Fake tags don't currently support blocklisting
+ *aResult = nsIBlocklistService::STATE_NOT_BLOCKED;
+ return NS_OK;
+}
+
+NS_IMETHODIMP
+nsFakePluginTag::GetBlocklisted(bool* aBlocklisted)
+{
+ // Fake tags can't be blocklisted
+ *aBlocklisted = false;
+ return NS_OK;
+}
+
+NS_IMETHODIMP
+nsFakePluginTag::GetIsEnabledStateLocked(bool* aIsEnabledStateLocked)
+{
+ return IsEnabledStateLockedForPlugin(this, aIsEnabledStateLocked);
+}
+
+bool
+nsFakePluginTag::IsEnabled()
+{
+ return mState == nsPluginTag::ePluginState_Enabled ||
+ mState == nsPluginTag::ePluginState_Clicktoplay;
+}
+
+NS_IMETHODIMP
+nsFakePluginTag::GetDisabled(bool* aDisabled)
+{
+ *aDisabled = !IsEnabled();
+ return NS_OK;
+}
+
+NS_IMETHODIMP
+nsFakePluginTag::GetClicktoplay(bool* aClicktoplay)
+{
+ *aClicktoplay = (mState == nsPluginTag::ePluginState_Clicktoplay);
+ return NS_OK;
+}
+
+NS_IMETHODIMP
+nsFakePluginTag::GetEnabledState(uint32_t* aEnabledState)
+{
+ *aEnabledState = (uint32_t)mState;
+ return NS_OK;
+}
+
+NS_IMETHODIMP
+nsFakePluginTag::SetEnabledState(uint32_t aEnabledState)
+{
+ // There are static asserts above enforcing that this enum matches
+ mState = (nsPluginTag::PluginState)aEnabledState;
+ // FIXME-jsplugins update
+ return NS_OK;
+}
+
+NS_IMETHODIMP
+nsFakePluginTag::GetMimeTypes(uint32_t* aCount, char16_t*** aResults)
+{
+ return CStringArrayToXPCArray(mMimeTypes, aCount, aResults);
+}
+
+NS_IMETHODIMP
+nsFakePluginTag::GetMimeDescriptions(uint32_t* aCount, char16_t*** aResults)
+{
+ return CStringArrayToXPCArray(mMimeDescriptions, aCount, aResults);
+}
+
+NS_IMETHODIMP
+nsFakePluginTag::GetExtensions(uint32_t* aCount, char16_t*** aResults)
+{
+ return CStringArrayToXPCArray(mExtensions, aCount, aResults);
+}
+
+NS_IMETHODIMP
+nsFakePluginTag::GetActive(bool *aResult)
+{
+ // Fake plugins can't be blocklisted, so this is just !Disabled
+ *aResult = IsEnabled();
+ return NS_OK;
+}
+
+NS_IMETHODIMP
+nsFakePluginTag::GetLastModifiedTime(PRTime* aLastModifiedTime)
+{
+ // FIXME-jsplugins What should this return, if anything?
+ MOZ_ASSERT(aLastModifiedTime);
+ *aLastModifiedTime = 0;
+ return NS_OK;
+}
+
+// We don't load fake plugins out of a library, so they should always be there.
+NS_IMETHODIMP
+nsFakePluginTag::GetLoaded(bool* ret)
+{
+ *ret = true;
+ return NS_OK;
+}