summaryrefslogtreecommitdiffstats
path: root/dom/plugins/base
diff options
context:
space:
mode:
Diffstat (limited to 'dom/plugins/base')
-rw-r--r--dom/plugins/base/moz.build45
-rw-r--r--dom/plugins/base/nsIPluginTag.idl97
-rw-r--r--dom/plugins/base/nsPluginHost.cpp223
-rw-r--r--dom/plugins/base/nsPluginHost.h111
-rw-r--r--dom/plugins/base/nsPluginLogging.h54
-rw-r--r--dom/plugins/base/nsPluginTags.cpp393
-rw-r--r--dom/plugins/base/nsPluginTags.h149
7 files changed, 1072 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..c1a660a3db
--- /dev/null
+++ b/dom/plugins/base/nsPluginTags.cpp
@@ -0,0 +1,393 @@
+/* -*- 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 "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"
+#include "mozilla/StaticPrefs_plugin.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_