diff options
Diffstat (limited to 'dom/plugins/base')
-rw-r--r-- | dom/plugins/base/moz.build | 45 | ||||
-rw-r--r-- | dom/plugins/base/nsIPluginTag.idl | 97 | ||||
-rw-r--r-- | dom/plugins/base/nsPluginHost.cpp | 223 | ||||
-rw-r--r-- | dom/plugins/base/nsPluginHost.h | 111 | ||||
-rw-r--r-- | dom/plugins/base/nsPluginLogging.h | 54 | ||||
-rw-r--r-- | dom/plugins/base/nsPluginTags.cpp | 391 | ||||
-rw-r--r-- | dom/plugins/base/nsPluginTags.h | 149 |
7 files changed, 1070 insertions, 0 deletions
diff --git a/dom/plugins/base/moz.build b/dom/plugins/base/moz.build new file mode 100644 index 0000000000..1e13483336 --- /dev/null +++ b/dom/plugins/base/moz.build @@ -0,0 +1,45 @@ +# -*- Mode: python; indent-tabs-mode: nil; tab-width: 40 -*- +# vim: set filetype=python: +# 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/. + +XPIDL_SOURCES += [ + "nsIPluginTag.idl", +] + +XPIDL_MODULE = "plugin" + +EXPORTS += [ + "nsPluginHost.h", + "nsPluginLogging.h", + "nsPluginTags.h", +] + +UNIFIED_SOURCES += [ + "nsPluginHost.cpp", + "nsPluginTags.cpp", +] + +LOCAL_INCLUDES += [ + "/dom/base", + "/gfx/cairo/cairo/src", + "/layout/generic", + "/layout/xul", + "/netwerk/base", + "/widget", + "/widget/cocoa", + "/xpcom/base", +] + +if CONFIG["OS_ARCH"] == "WINNT": + LOCAL_INCLUDES += [ + "/xpcom/base", + ] + +include("/ipc/chromium/chromium-config.mozbuild") + +FINAL_LIBRARY = "xul" + +if CONFIG["MOZ_WIDGET_TOOLKIT"] == "gtk": + CXXFLAGS += CONFIG["MOZ_GTK3_CFLAGS"] diff --git a/dom/plugins/base/nsIPluginTag.idl b/dom/plugins/base/nsIPluginTag.idl new file mode 100644 index 0000000000..68f8da1dc8 --- /dev/null +++ b/dom/plugins/base/nsIPluginTag.idl @@ -0,0 +1,97 @@ +/* -*- Mode: IDL; 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 "nsISupports.idl" + +interface nsIURI; + +[builtinclass, scriptable, uuid(5daa99d5-265a-4397-b429-c943803e2619)] +interface nsIPluginTag : nsISupports +{ + // enabledState is stored as one of the following as an integer in prefs, + // so if new states are added, they must not renumber the existing states. + const unsigned long STATE_DISABLED = 0; + const unsigned long STATE_CLICKTOPLAY = 1; + const unsigned long STATE_ENABLED = 2; + + readonly attribute AUTF8String description; + readonly attribute AUTF8String filename; + readonly attribute AUTF8String fullpath; + readonly attribute AUTF8String version; + readonly attribute AUTF8String name; + + // The 'nice' name of this plugin, e.g. 'flash' 'java' + readonly attribute AUTF8String niceName; + + /** + * true only if this plugin is "hardblocked" and cannot be enabled. + */ + // FIXME-jsplugins QI to fakePluginTag possible + // FIXME-jsplugins implement missing + tests (whatever that means) + [infallible] + readonly attribute boolean blocklisted; + + /** + * true if the state is non-default and locked, false otherwise. + */ + [infallible] + readonly attribute boolean isEnabledStateLocked; + + // If this plugin is capable of being used (not disabled, blocklisted, etc) + [infallible] + readonly attribute boolean active; + + // Get a specific nsIBlocklistService::STATE_* + [infallible] + readonly attribute unsigned long blocklistState; + + [infallible] + readonly attribute boolean disabled; + [infallible] + readonly attribute boolean clicktoplay; + [infallible] + readonly attribute boolean loaded; + // See the STATE_* values above. + attribute unsigned long enabledState; + + readonly attribute PRTime lastModifiedTime; + + readonly attribute boolean isFlashPlugin; + + Array<AUTF8String> getMimeTypes(); + Array<AUTF8String> getMimeDescriptions(); + Array<AUTF8String> getExtensions(); + + /** + * An id for this plugin. 0 is a valid id. + */ + readonly attribute unsigned long id; +}; + +/** + * An interface representing a "fake" plugin: one implemented in JavaScript, not + * as a NPAPI plug-in. See nsIPluginHost.registerFakePlugin and the + * documentation for the FakePluginTagInit dictionary. + */ +[builtinclass, scriptable, uuid(6d22c968-226d-4156-b230-da6ad6bbf6e8)] +interface nsIFakePluginTag : nsIPluginTag +{ + /** + * The URI that should be loaded into the tag (as a frame) to handle the + * plugin. Note that the original data/src value for the plugin is not loaded + * and will need to be requested by the handler via XHR or similar if desired. + */ + readonly attribute nsIURI handlerURI; + + /** + * Optional script to run in a sandbox when instantiating a plugin. If this + * value is an empty string then no such script will be run. + * The script runs in a sandbox with system principal in the process that + * contains the element that instantiates the plugin (ie the EMBED or OBJECT + * element). The sandbox global has a 'pluginElement' property that the script + * can use to access the element that instantiates the plugin. + */ + readonly attribute AString sandboxScript; +}; diff --git a/dom/plugins/base/nsPluginHost.cpp b/dom/plugins/base/nsPluginHost.cpp new file mode 100644 index 0000000000..1c94e60002 --- /dev/null +++ b/dom/plugins/base/nsPluginHost.cpp @@ -0,0 +1,223 @@ +/* -*- 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/. */ + +/* nsPluginHost.cpp - top-level plugin management code */ + +#include "nsPluginHost.h" + +#include "nscore.h" + +#include <cstdlib> +#include <stdio.h> +#include "nsPluginLogging.h" +#include "mozilla/Preferences.h" +#include "mozilla/ProfilerLabels.h" +#include "nsIBlocklistService.h" +#include "mozilla/ClearOnShutdown.h" +#include "nsXULAppAPI.h" + +using namespace mozilla; + +LazyLogModule nsPluginLogging::gNPNLog(NPN_LOG_NAME); +LazyLogModule nsPluginLogging::gNPPLog(NPP_LOG_NAME); +LazyLogModule nsPluginLogging::gPluginLog(PLUGIN_LOG_NAME); + +StaticRefPtr<nsPluginHost> nsPluginHost::sInst; + +nsPluginHost::nsPluginHost() : mPluginEpoch(0) { +#ifdef PLUGIN_LOGGING + MOZ_LOG(nsPluginLogging::gNPNLog, PLUGIN_LOG_ALWAYS, + ("NPN Logging Active!\n")); + MOZ_LOG(nsPluginLogging::gPluginLog, PLUGIN_LOG_ALWAYS, + ("General Plugin Logging Active! (nsPluginHost::ctor)\n")); + MOZ_LOG(nsPluginLogging::gNPPLog, PLUGIN_LOG_ALWAYS, + ("NPP Logging Active!\n")); + + PLUGIN_LOG(PLUGIN_LOG_ALWAYS, ("nsPluginHost::ctor\n")); + PR_LogFlush(); +#endif + + // Load plugins on creation, as there's a good chance we'll need to send them + // to content processes directly after creation. + if (XRE_IsParentProcess()) { + // Always increment the chrome epoch when we bring up the nsPluginHost in + // the parent process. + IncrementChromeEpoch(); + } +} + +nsPluginHost::~nsPluginHost() { + PLUGIN_LOG(PLUGIN_LOG_ALWAYS, ("nsPluginHost::dtor\n")); +} + +NS_IMPL_ISUPPORTS(nsPluginHost, nsISupportsWeakReference) + +already_AddRefed<nsPluginHost> nsPluginHost::GetInst() { + if (!sInst) { + sInst = new nsPluginHost(); + ClearOnShutdown(&sInst); + } + + return do_AddRef(sInst); +} + +bool nsPluginHost::HavePluginForType(const nsACString& aMimeType, + PluginFilter aFilter) { + bool checkEnabled = aFilter & eExcludeDisabled; + bool allowFake = !(aFilter & eExcludeFake); + return FindPluginForType(aMimeType, allowFake, checkEnabled); +} + +nsIInternalPluginTag* nsPluginHost::FindPluginForType( + const nsACString& aMimeType, bool aIncludeFake, bool aCheckEnabled) { + if (aIncludeFake) { + return FindFakePluginForType(aMimeType, aCheckEnabled); + } + + return nullptr; +} + +NS_IMETHODIMP +nsPluginHost::GetPluginTagForType(const nsACString& aMimeType, + uint32_t aExcludeFlags, + nsIPluginTag** aResult) { + bool includeFake = !(aExcludeFlags & eExcludeFake); + bool includeDisabled = !(aExcludeFlags & eExcludeDisabled); + + // First look for an enabled plugin. + RefPtr<nsIInternalPluginTag> tag = + FindPluginForType(aMimeType, includeFake, true); + if (!tag && includeDisabled) { + tag = FindPluginForType(aMimeType, includeFake, false); + } + + if (tag) { + tag.forget(aResult); + return NS_OK; + } + + return NS_ERROR_NOT_AVAILABLE; +} + +NS_IMETHODIMP +nsPluginHost::GetPermissionStringForTag(nsIPluginTag* aTag, + uint32_t aExcludeFlags, + nsACString& aPermissionString) { + NS_ENSURE_TRUE(aTag, NS_ERROR_FAILURE); + + aPermissionString.Truncate(); + uint32_t blocklistState; + nsresult rv = aTag->GetBlocklistState(&blocklistState); + NS_ENSURE_SUCCESS(rv, rv); + + aPermissionString.AssignLiteral("plugin:"); + + nsCString niceName; + rv = aTag->GetNiceName(niceName); + NS_ENSURE_SUCCESS(rv, rv); + NS_ENSURE_TRUE(!niceName.IsEmpty(), NS_ERROR_FAILURE); + + aPermissionString.Append(niceName); + + return NS_OK; +} + +nsFakePluginTag* nsPluginHost::FindFakePluginForType( + const nsACString& aMimeType, bool aCheckEnabled) { + int32_t numFakePlugins = mFakePlugins.Length(); + for (int32_t i = 0; i < numFakePlugins; i++) { + nsFakePluginTag* plugin = mFakePlugins[i]; + bool active; + if ((!aCheckEnabled || + (NS_SUCCEEDED(plugin->GetActive(&active)) && active)) && + plugin->HasMimeType(aMimeType)) { + return plugin; + } + } + + return nullptr; +} + +static bool MimeTypeIsAllowedForFakePlugin(const nsString& aMimeType) { + static const char* const allowedFakePlugins[] = { + // PDF + "application/pdf", + "application/vnd.adobe.pdf", + "application/vnd.adobe.pdfxml", + "application/vnd.adobe.x-mars", + "application/vnd.adobe.xdp+xml", + "application/vnd.adobe.xfdf", + "application/vnd.adobe.xfd+xml", + "application/vnd.fdf", + }; + + for (const auto allowed : allowedFakePlugins) { + if (aMimeType.EqualsASCII(allowed)) { + return true; + } + } + return false; +} + +nsPluginHost::SpecialType nsPluginHost::GetSpecialType( + const nsACString& aMIMEType) { + if (aMIMEType.LowerCaseEqualsASCII("application/x-test")) { + return eSpecialType_Test; + } + + if (aMIMEType.LowerCaseEqualsASCII("application/x-shockwave-flash") || + aMIMEType.LowerCaseEqualsASCII("application/futuresplash") || + aMIMEType.LowerCaseEqualsASCII("application/x-shockwave-flash-test")) { + return eSpecialType_Flash; + } + + return eSpecialType_None; +} + +// Check whether or not a tag is a live, valid tag, and that it's loaded. +bool nsPluginHost::IsLiveTag(nsIPluginTag* aPluginTag) { + nsCOMPtr<nsIInternalPluginTag> internalTag(do_QueryInterface(aPluginTag)); + uint32_t fakeCount = mFakePlugins.Length(); + for (uint32_t i = 0; i < fakeCount; i++) { + if (mFakePlugins[i] == internalTag) { + return true; + } + } + return false; +} + +void nsPluginHost::IncrementChromeEpoch() { + MOZ_ASSERT(XRE_IsParentProcess()); + mPluginEpoch++; +} + +uint32_t nsPluginHost::ChromeEpoch() { + MOZ_ASSERT(XRE_IsParentProcess()); + return mPluginEpoch; +} + +uint32_t nsPluginHost::ChromeEpochForContent() { + MOZ_ASSERT(XRE_IsContentProcess()); + return mPluginEpoch; +} + +void nsPluginHost::SetChromeEpochForContent(uint32_t aEpoch) { + MOZ_ASSERT(XRE_IsContentProcess()); + mPluginEpoch = aEpoch; +} + +/* static */ +bool nsPluginHost::CanUsePluginForMIMEType(const nsACString& aMIMEType) { + // We "support" these in the sense that we show a special transparent + // fallback element in their place. + if (nsPluginHost::GetSpecialType(aMIMEType) == + nsPluginHost::eSpecialType_Flash || + MimeTypeIsAllowedForFakePlugin(NS_ConvertUTF8toUTF16(aMIMEType)) || + aMIMEType.LowerCaseEqualsLiteral("application/x-test")) { + return true; + } + + return false; +} diff --git a/dom/plugins/base/nsPluginHost.h b/dom/plugins/base/nsPluginHost.h new file mode 100644 index 0000000000..6566e979f3 --- /dev/null +++ b/dom/plugins/base/nsPluginHost.h @@ -0,0 +1,111 @@ +/* -*- 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/. */ + +#ifndef nsPluginHost_h_ +#define nsPluginHost_h_ + +#include "mozilla/StaticPtr.h" + +#include "nsCOMPtr.h" +#include "prlink.h" +#include "nsIPluginTag.h" +#include "nsWeakReference.h" +#include "nsTArray.h" +#include "nsPluginTags.h" + +class nsIFile; + +class nsPluginHost final : public nsSupportsWeakReference { + friend class nsFakePluginTag; + virtual ~nsPluginHost(); + + public: + nsPluginHost(); + + static already_AddRefed<nsPluginHost> GetInst(); + + NS_DECL_ISUPPORTS + + // Acts like a bitfield + enum PluginFilter { eExcludeNone, eExcludeDisabled, eExcludeFake }; + + NS_IMETHOD GetPluginTagForType(const nsACString& aMimeType, + uint32_t aExcludeFlags, + nsIPluginTag** aResult); + NS_IMETHOD GetPermissionStringForTag(nsIPluginTag* aTag, + uint32_t aExcludeFlags, + nsACString& aPermissionString); + + // FIXME-jsplugins comment about fake + bool HavePluginForType(const nsACString& aMimeType, + PluginFilter aFilter = eExcludeDisabled); + + void GetPlugins(nsTArray<nsCOMPtr<nsIInternalPluginTag>>& aPluginArray, + bool aIncludeDisabled = false); + + /** + * Returns true if a plugin can be used to load the requested MIME type. Used + * for short circuiting before sending things to plugin code. + */ + static bool CanUsePluginForMIMEType(const nsACString& aMIMEType); + + // checks whether aType is a type we recognize for potential special handling + enum SpecialType { + eSpecialType_None, + // Needed to whitelist for async init support + eSpecialType_Test, + // Informs some decisions about OOP and quirks + eSpecialType_Flash + }; + static SpecialType GetSpecialType(const nsACString& aMIMEType); + + private: + // Find a plugin for the given type. If aIncludeFake is true a fake plugin + // will be preferred if one exists; otherwise a fake plugin will never be + // returned. If aCheckEnabled is false, disabled plugins can be returned. + nsIInternalPluginTag* FindPluginForType(const nsACString& aMimeType, + bool aIncludeFake, + bool aCheckEnabled); + + // Find specifically a fake plugin for the given type. If aCheckEnabled is + // false, disabled plugins can be returned. + nsFakePluginTag* FindFakePluginForType(const nsACString& aMimeType, + bool aCheckEnabled); + + // Find specifically a fake plugin for the given extension. If aCheckEnabled + // is false, disabled plugins can be returned. aMimeType will be filled in + // with the MIME type the plugin is registered for. + nsFakePluginTag* FindFakePluginForExtension(const nsACString& aExtension, + /* out */ nsACString& aMimeType, + bool aCheckEnabled); + + // Checks to see if a tag object is in our list of live tags. + bool IsLiveTag(nsIPluginTag* tag); + + // To be used by the chrome process whenever the set of plugins changes. + void IncrementChromeEpoch(); + + // To be used by the chrome process; returns the current epoch. + uint32_t ChromeEpoch(); + + // To be used by the content process to get/set the last observed epoch value + // from the chrome process. + uint32_t ChromeEpochForContent(); + void SetChromeEpochForContent(uint32_t aEpoch); + + nsTArray<RefPtr<nsFakePluginTag>> mFakePlugins; + + // This epoch increases each time we load the list of plugins from disk. + // In the chrome process, this stores the actual epoch. + // In the content process, this stores the last epoch value observed + // when reading plugins from chrome. + uint32_t mPluginEpoch; + + // We need to hold a global ptr to ourselves because we register for + // two different CIDs for some reason... + static mozilla::StaticRefPtr<nsPluginHost> sInst; +}; + +#endif // nsPluginHost_h_ diff --git a/dom/plugins/base/nsPluginLogging.h b/dom/plugins/base/nsPluginLogging.h new file mode 100644 index 0000000000..029a073308 --- /dev/null +++ b/dom/plugins/base/nsPluginLogging.h @@ -0,0 +1,54 @@ +/* -*- Mode: C++; tab-width: 4; 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/. */ + +/* Plugin Module Logging usage instructions and includes */ +//////////////////////////////////////////////////////////////////////////////// +#ifndef nsPluginLogging_h__ +#define nsPluginLogging_h__ + +#include "mozilla/Logging.h" + +//////////////////////////////////////////////////////////////////////////////// +// Basic Plugin Logging Usage Instructions +// +// 1. Set this environment variable: MOZ_LOG=<name>:<level> + +// Choose the <name> and <level> from this list (no quotes): + +// Log Names <name> +#define NPN_LOG_NAME "PluginNPN" +#define NPP_LOG_NAME "PluginNPP" +#define PLUGIN_LOG_NAME "Plugin" + +// Levels <level> +#define PLUGIN_LOG_ALWAYS mozilla::LogLevel::Error +#define PLUGIN_LOG_BASIC mozilla::LogLevel::Info +#define PLUGIN_LOG_NORMAL mozilla::LogLevel::Debug +#define PLUGIN_LOG_NOISY mozilla::LogLevel::Verbose + +// 2. You can combine logs and levels by separating them with a comma: +// My favorite Win32 Example: SET MOZ_LOG=Plugin:5,PluginNPP:5,PluginNPN:5 + +// 3. Instead of output going to the console, you can log to a file. +// Additionally, set the MOZ_LOG_FILE environment variable to point to the +// full path of a file. +// My favorite Win32 Example: SET MOZ_LOG_FILE=c:\temp\pluginLog.txt + +// 4. For complete information see the Gecko Developer guide: +// https://firefox-source-docs.mozilla.org/xpcom/logging.html + +class nsPluginLogging { + public: + static mozilla::LazyLogModule gNPNLog; // 4.x NP API, calls into navigator + static mozilla::LazyLogModule gNPPLog; // 4.x NP API, calls into plugin + static mozilla::LazyLogModule gPluginLog; // general plugin log +}; + +// Quick-use macros +#define NPN_PLUGIN_LOG(a, b) MOZ_LOG(nsPluginLogging::gNPNLog, a, b) +#define NPP_PLUGIN_LOG(a, b) MOZ_LOG(nsPluginLogging::gNPPLog, a, b) +#define PLUGIN_LOG(a, b) MOZ_LOG(nsPluginLogging::gPluginLog, a, b) + +#endif // nsPluginLogging_h__ diff --git a/dom/plugins/base/nsPluginTags.cpp b/dom/plugins/base/nsPluginTags.cpp new file mode 100644 index 0000000000..37e9f742ac --- /dev/null +++ b/dom/plugins/base/nsPluginTags.cpp @@ -0,0 +1,391 @@ +/* -*- 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 "prenv.h" +#include "nsPluginHost.h" +#include "nsIBlocklistService.h" +#include "nsPluginLogging.h" +#include "nsCharSeparatedTokenizer.h" +#include "mozilla/Preferences.h" +#include "mozilla/Unused.h" +#include "nsNetUtil.h" +#include <cctype> +#include "mozilla/Encoding.h" +#include "mozilla/dom/FakePluginTagInitBinding.h" + +using mozilla::dom::FakePluginTagInit; +using namespace mozilla; + +// check comma delimited extensions +static bool ExtensionInList(const nsCString& aExtensionList, + const nsACString& aExtension) { + for (const nsACString& extension : + nsCCharSeparatedTokenizer(aExtensionList, ',').ToRange()) { + 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 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 */ + +uint32_t nsIInternalPluginTag::sNextId; + +nsIInternalPluginTag::nsIInternalPluginTag() = default; + +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.Clone()), + mMimeDescriptions(aMimeDescriptions.Clone()), + mExtensions(aExtensions.Clone()) {} + +nsIInternalPluginTag::~nsIInternalPluginTag() = default; + +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()); +} + +/* nsFakePluginTag */ + +nsFakePluginTag::nsFakePluginTag() + : mId(sNextId++), mState(ePluginState_Disabled) {} + +nsFakePluginTag::nsFakePluginTag(uint32_t aId, + already_AddRefed<nsIURI>&& aHandlerURI, + const char* aName, const char* aDescription, + const nsTArray<nsCString>& aMimeTypes, + const nsTArray<nsCString>& aMimeDescriptions, + const nsTArray<nsCString>& aExtensions, + const nsCString& aNiceName, + const nsString& aSandboxScript) + : nsIInternalPluginTag(aName, aDescription, nullptr, nullptr, aMimeTypes, + aMimeDescriptions, aExtensions), + mId(aId), + mHandlerURI(aHandlerURI), + mNiceName(aNiceName), + mSandboxScript(aSandboxScript), + mState(ePluginState_Enabled) {} + +nsFakePluginTag::~nsFakePluginTag() = default; + +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(sNextId <= PR_INT32_MAX, NS_ERROR_OUT_OF_MEMORY); + 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); + tag->mSandboxScript = aInitDictionary.mSandboxScript; + + for (const mozilla::dom::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::GetSandboxScript(nsAString& aSandboxScript) { + aSandboxScript = mSandboxScript; + return NS_OK; +} + +NS_IMETHODIMP +nsFakePluginTag::GetDescription(/* utf-8 */ nsACString& aResult) { + aResult = mDescription; + return NS_OK; +} + +NS_IMETHODIMP +nsFakePluginTag::GetIsFlashPlugin(bool* aIsFlash) { + *aIsFlash = false; + 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 == ePluginState_Enabled || mState == ePluginState_Clicktoplay; +} + +NS_IMETHODIMP +nsFakePluginTag::GetDisabled(bool* aDisabled) { + *aDisabled = !IsEnabled(); + return NS_OK; +} + +NS_IMETHODIMP +nsFakePluginTag::GetClicktoplay(bool* aClicktoplay) { + *aClicktoplay = (mState == 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 = (PluginState)aEnabledState; + // FIXME-jsplugins update + return NS_OK; +} + +NS_IMETHODIMP +nsFakePluginTag::GetMimeTypes(nsTArray<nsCString>& aResults) { + aResults = mMimeTypes.Clone(); + return NS_OK; +} + +NS_IMETHODIMP +nsFakePluginTag::GetMimeDescriptions(nsTArray<nsCString>& aResults) { + aResults = mMimeDescriptions.Clone(); + return NS_OK; +} + +NS_IMETHODIMP +nsFakePluginTag::GetExtensions(nsTArray<nsCString>& aResults) { + aResults = mExtensions.Clone(); + return NS_OK; +} + +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; +} + +NS_IMETHODIMP +nsFakePluginTag::GetId(uint32_t* aId) { + *aId = mId; + return NS_OK; +} diff --git a/dom/plugins/base/nsPluginTags.h b/dom/plugins/base/nsPluginTags.h new file mode 100644 index 0000000000..2219112d26 --- /dev/null +++ b/dom/plugins/base/nsPluginTags.h @@ -0,0 +1,149 @@ +/* -*- 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/. */ + +#ifndef nsPluginTags_h_ +#define nsPluginTags_h_ + +#include "mozilla/Attributes.h" +#include "nscore.h" +#include "nsCOMPtr.h" +#include "nsCOMArray.h" +#include "nsIPluginTag.h" +#include "nsITimer.h" +#include "nsString.h" + +class nsIURI; + +namespace mozilla::dom { +struct FakePluginTagInit; +} // namespace mozilla::dom + +// An interface representing plugin tags internally. +#define NS_IINTERNALPLUGINTAG_IID \ + { \ + 0xe8fdd227, 0x27da, 0x46ee, { \ + 0xbe, 0xf3, 0x1a, 0xef, 0x5a, 0x8f, 0xc5, 0xb4 \ + } \ + } + +class nsIInternalPluginTag : public nsIPluginTag { + public: + NS_DECLARE_STATIC_IID_ACCESSOR(NS_IINTERNALPLUGINTAG_IID) + + nsIInternalPluginTag(); + nsIInternalPluginTag(const char* aName, const char* aDescription, + const char* aFileName, const char* aVersion); + 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); + + virtual bool IsEnabled() = 0; + virtual const nsCString& GetNiceFileName() = 0; + + const nsCString& Name() const { return mName; } + const nsCString& Description() const { return mDescription; } + + const nsTArray<nsCString>& MimeTypes() const { return mMimeTypes; } + + const nsTArray<nsCString>& MimeDescriptions() const { + return mMimeDescriptions; + } + + const nsTArray<nsCString>& Extensions() const { return mExtensions; } + + const nsCString& FileName() const { return mFileName; } + + const nsCString& Version() const { return mVersion; } + + // Returns true if this plugin claims it supports this MIME type. The + // comparison is done ASCII-case-insensitively. + bool HasMimeType(const nsACString& aMimeType) const; + + // Returns true if this plugin claims it supports the given extension. In + // that case, aMatchingType is set to the MIME type the plugin claims + // corresponds to this extension. The match on aExtension is done + // ASCII-case-insensitively. + bool HasExtension(const nsACString& aExtension, + /* out */ nsACString& aMatchingType) const; + + // These must match the STATE_* values in nsIPluginTag.idl + enum PluginState { + ePluginState_Disabled = 0, + ePluginState_Clicktoplay = 1, + ePluginState_Enabled = 2, + ePluginState_MaxValue = 3, + }; + + protected: + ~nsIInternalPluginTag(); + + nsCString mName; // UTF-8 + nsCString mDescription; // UTF-8 + nsCString mFileName; // UTF-8 + nsCString mVersion; // UTF-8 + nsTArray<nsCString> mMimeTypes; // UTF-8 + nsTArray<nsCString> mMimeDescriptions; // UTF-8 + nsTArray<nsCString> mExtensions; // UTF-8 + + static uint32_t sNextId; +}; +NS_DEFINE_STATIC_IID_ACCESSOR(nsIInternalPluginTag, NS_IINTERNALPLUGINTAG_IID) + +// A class representing "fake" plugin tags for Javascript-based plugins. +// There are currently no other types of supported plugins. +class nsFakePluginTag : public nsIInternalPluginTag, public nsIFakePluginTag { + public: + NS_DECL_ISUPPORTS + NS_DECL_NSIPLUGINTAG + NS_DECL_NSIFAKEPLUGINTAG + + static nsresult Create(const mozilla::dom::FakePluginTagInit& aInitDictionary, + nsFakePluginTag** aPluginTag); + nsFakePluginTag(uint32_t aId, already_AddRefed<nsIURI>&& aHandlerURI, + const char* aName, const char* aDescription, + const nsTArray<nsCString>& aMimeTypes, + const nsTArray<nsCString>& aMimeDescriptions, + const nsTArray<nsCString>& aExtensions, + const nsCString& aNiceName, const nsString& aSandboxScript); + + bool IsEnabled() override; + const nsCString& GetNiceFileName() override; + + bool HandlerURIMatches(nsIURI* aURI); + + nsIURI* HandlerURI() const { return mHandlerURI; } + + uint32_t Id() const { return mId; } + + const nsString& SandboxScript() const { return mSandboxScript; } + + static const int32_t NOT_JSPLUGIN = -1; + + private: + nsFakePluginTag(); + virtual ~nsFakePluginTag(); + + // A unique id for this JS-implemented plugin. Registering a plugin through + // nsPluginHost::RegisterFakePlugin assigns a new id. The id is transferred + // through IPC when getting the list of JS-implemented plugins from child + // processes, so it should be consistent across processes. + // 0 is a valid id. + uint32_t mId; + + // The URI of the handler for our fake plugin. + // FIXME-jsplugins do we need to sanity check these? + nsCOMPtr<nsIURI> mHandlerURI; + + nsCString mFullPath; + nsCString mNiceName; + + nsString mSandboxScript; + + PluginState mState; +}; + +#endif // nsPluginTags_h_ |