1021 lines
28 KiB
C++
1021 lines
28 KiB
C++
/* -*- 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);
|
|
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));
|
|
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());
|
|
}
|
|
}
|
|
}
|
|
|
|
#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;
|
|
}
|