1 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2 /* This Source Code Form is subject to the terms of the Mozilla Public
3 * License, v. 2.0. If a copy of the MPL was not distributed with this
4 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
6 #include "nsPluginArray.h"
8 #include "mozilla/Preferences.h"
9 #include "mozilla/dom/PluginArrayBinding.h"
10 #include "mozilla/dom/PluginBinding.h"
12 #include "nsCharSeparatedTokenizer.h"
13 #include "nsMimeTypeArray.h"
14 #include "Navigator.h"
15 #include "nsIDocShell.h"
16 #include "nsIWebNavigation.h"
17 #include "nsPluginHost.h"
18 #include "nsPluginTags.h"
19 #include "nsIObserverService.h"
20 #include "nsIWeakReference.h"
21 #include "mozilla/Services.h"
22 #include "nsIInterfaceRequestorUtils.h"
24 using namespace mozilla
;
25 using namespace mozilla::dom
;
27 nsPluginArray::nsPluginArray(nsPIDOMWindow
* aWindow
)
35 nsCOMPtr
<nsIObserverService
> obsService
=
36 mozilla::services::GetObserverService();
38 obsService
->AddObserver(this, "plugin-info-updated", true);
42 nsPluginArray::~nsPluginArray()
47 nsPluginArray::GetParentObject() const
54 nsPluginArray::WrapObject(JSContext
* aCx
)
56 return PluginArrayBinding::Wrap(aCx
, this);
59 NS_IMPL_CYCLE_COLLECTING_ADDREF(nsPluginArray
)
60 NS_IMPL_CYCLE_COLLECTING_RELEASE(nsPluginArray
)
61 NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(nsPluginArray
)
62 NS_WRAPPERCACHE_INTERFACE_MAP_ENTRY
63 NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsISupports
, nsIObserver
)
64 NS_INTERFACE_MAP_ENTRY(nsIObserver
)
65 NS_INTERFACE_MAP_ENTRY(nsISupportsWeakReference
)
68 NS_IMPL_CYCLE_COLLECTION_WRAPPERCACHE(nsPluginArray
,
74 GetPluginMimeTypes(const nsTArray
<nsRefPtr
<nsPluginElement
> >& aPlugins
,
75 nsTArray
<nsRefPtr
<nsMimeType
> >& aMimeTypes
)
77 for (uint32_t i
= 0; i
< aPlugins
.Length(); ++i
) {
78 nsPluginElement
*plugin
= aPlugins
[i
];
79 aMimeTypes
.AppendElements(plugin
->MimeTypes());
84 operator<(const nsRefPtr
<nsMimeType
>& lhs
, const nsRefPtr
<nsMimeType
>& rhs
)
86 // Sort MIME types alphabetically by type name.
87 return lhs
->Type() < rhs
->Type();
91 nsPluginArray::GetMimeTypes(nsTArray
<nsRefPtr
<nsMimeType
> >& aMimeTypes
,
92 nsTArray
<nsRefPtr
<nsMimeType
> >& aHiddenMimeTypes
)
95 aHiddenMimeTypes
.Clear();
97 if (!AllowPlugins()) {
103 GetPluginMimeTypes(mPlugins
, aMimeTypes
);
104 GetPluginMimeTypes(mHiddenPlugins
, aHiddenMimeTypes
);
106 // Alphabetize the enumeration order of non-hidden MIME types to reduce
107 // fingerprintable entropy based on plugins' installation file times.
112 nsPluginArray::Item(uint32_t aIndex
)
115 return IndexedGetter(aIndex
, unused
);
119 nsPluginArray::NamedItem(const nsAString
& aName
)
122 return NamedGetter(aName
, unused
);
126 nsPluginArray::Refresh(bool aReloadDocuments
)
128 nsRefPtr
<nsPluginHost
> pluginHost
= nsPluginHost::GetInst();
130 if(!AllowPlugins() || !pluginHost
) {
134 // NS_ERROR_PLUGINS_PLUGINSNOTCHANGED on reloading plugins indicates
135 // that plugins did not change and was not reloaded
136 if (pluginHost
->ReloadPlugins() ==
137 NS_ERROR_PLUGINS_PLUGINSNOTCHANGED
) {
138 nsTArray
<nsRefPtr
<nsPluginTag
> > newPluginTags
;
139 pluginHost
->GetPlugins(newPluginTags
);
141 // Check if the number of plugins we know about are different from
142 // the number of plugin tags the plugin host knows about. If the
143 // lengths are different, we refresh. This is safe because we're
144 // notified for every plugin enabling/disabling event that
145 // happens, and therefore the lengths will be in sync only when
146 // the both arrays contain the same plugin tags (though as
148 uint32_t pluginCount
= mPlugins
.Length() + mHiddenPlugins
.Length();
149 if (newPluginTags
.Length() == pluginCount
) {
155 mHiddenPlugins
.Clear();
157 nsCOMPtr
<nsIDOMNavigator
> navigator
;
158 mWindow
->GetNavigator(getter_AddRefs(navigator
));
164 static_cast<mozilla::dom::Navigator
*>(navigator
.get())->RefreshMIMEArray();
166 nsCOMPtr
<nsIWebNavigation
> webNav
= do_GetInterface(mWindow
);
167 if (aReloadDocuments
&& webNav
) {
168 webNav
->Reload(nsIWebNavigation::LOAD_FLAGS_NONE
);
173 nsPluginArray::IndexedGetter(uint32_t aIndex
, bool &aFound
)
177 if (!AllowPlugins()) {
183 aFound
= aIndex
< mPlugins
.Length();
185 return aFound
? mPlugins
[aIndex
] : nullptr;
189 nsPluginArray::Invalidate()
191 nsCOMPtr
<nsIObserverService
> obsService
=
192 mozilla::services::GetObserverService();
194 obsService
->RemoveObserver(this, "plugin-info-updated");
198 static nsPluginElement
*
199 FindPlugin(const nsTArray
<nsRefPtr
<nsPluginElement
> >& aPlugins
,
200 const nsAString
& aName
)
202 for (uint32_t i
= 0; i
< aPlugins
.Length(); ++i
) {
203 nsAutoString pluginName
;
204 nsPluginElement
* plugin
= aPlugins
[i
];
205 plugin
->GetName(pluginName
);
207 if (pluginName
.Equals(aName
)) {
216 nsPluginArray::NamedGetter(const nsAString
& aName
, bool &aFound
)
220 if (!AllowPlugins()) {
226 nsPluginElement
* plugin
= FindPlugin(mPlugins
, aName
);
228 plugin
= FindPlugin(mHiddenPlugins
, aName
);
231 aFound
= (plugin
!= nullptr);
236 nsPluginArray::NameIsEnumerable(const nsAString
& aName
)
242 nsPluginArray::Length()
244 if (!AllowPlugins()) {
250 return mPlugins
.Length();
254 nsPluginArray::GetSupportedNames(unsigned, nsTArray
<nsString
>& aRetval
)
258 if (!AllowPlugins()) {
262 for (uint32_t i
= 0; i
< mPlugins
.Length(); ++i
) {
263 nsAutoString pluginName
;
264 mPlugins
[i
]->GetName(pluginName
);
266 aRetval
.AppendElement(pluginName
);
271 nsPluginArray::Observe(nsISupports
*aSubject
, const char *aTopic
,
272 const char16_t
*aData
) {
273 if (!nsCRT::strcmp(aTopic
, "plugin-info-updated")) {
281 nsPluginArray::AllowPlugins() const
283 nsCOMPtr
<nsIDocShell
> docShell
= mWindow
? mWindow
->GetDocShell() : nullptr;
285 return docShell
&& docShell
->PluginsAllowedInCurrentDoc();
289 HasStringPrefix(const nsCString
& str
, const nsACString
& prefix
) {
290 return str
.Compare(prefix
.BeginReading(), false, prefix
.Length()) == 0;
294 IsPluginEnumerable(const nsTArray
<nsCString
>& enumerableNames
,
295 const nsPluginTag
* pluginTag
)
297 const nsCString
& pluginName
= pluginTag
->mName
;
299 const uint32_t length
= enumerableNames
.Length();
300 for (uint32_t i
= 0; i
< length
; i
++) {
301 const nsCString
& name
= enumerableNames
[i
];
302 if (HasStringPrefix(pluginName
, name
)) {
303 return true; // don't hide plugin
307 return false; // hide plugin!
311 operator<(const nsRefPtr
<nsPluginElement
>& lhs
,
312 const nsRefPtr
<nsPluginElement
>& rhs
)
314 // Sort plugins alphabetically by name.
315 return lhs
->PluginTag()->mName
< rhs
->PluginTag()->mName
;
319 nsPluginArray::EnsurePlugins()
321 if (!mPlugins
.IsEmpty() || !mHiddenPlugins
.IsEmpty()) {
322 // We already have an array of plugin elements.
326 nsRefPtr
<nsPluginHost
> pluginHost
= nsPluginHost::GetInst();
328 // We have no plugin host.
332 nsTArray
<nsRefPtr
<nsPluginTag
> > pluginTags
;
333 pluginHost
->GetPlugins(pluginTags
);
335 nsTArray
<nsCString
> enumerableNames
;
337 const nsAdoptingCString
& enumerableNamesPref
=
338 Preferences::GetCString("plugins.enumerable_names");
340 bool disablePluginHiding
= !enumerableNamesPref
||
341 enumerableNamesPref
.EqualsLiteral("*");
343 if (!disablePluginHiding
) {
344 nsCCharSeparatedTokenizer
tokens(enumerableNamesPref
, ',');
345 while (tokens
.hasMoreTokens()) {
346 const nsCSubstring
& token
= tokens
.nextToken();
347 if (!token
.IsEmpty()) {
348 enumerableNames
.AppendElement(token
);
353 // need to wrap each of these with a nsPluginElement, which is
355 for (uint32_t i
= 0; i
< pluginTags
.Length(); ++i
) {
356 nsPluginTag
* pluginTag
= pluginTags
[i
];
358 // Add the plugin to the list of hidden plugins or non-hidden plugins?
359 nsTArray
<nsRefPtr
<nsPluginElement
> >& pluginArray
=
360 (disablePluginHiding
|| IsPluginEnumerable(enumerableNames
, pluginTag
))
364 pluginArray
.AppendElement(new nsPluginElement(mWindow
, pluginTag
));
367 // Alphabetize the enumeration order of non-hidden plugins to reduce
368 // fingerprintable entropy based on plugins' installation file times.
372 // nsPluginElement implementation.
374 NS_IMPL_CYCLE_COLLECTING_ADDREF(nsPluginElement
)
375 NS_IMPL_CYCLE_COLLECTING_RELEASE(nsPluginElement
)
376 NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(nsPluginElement
)
377 NS_WRAPPERCACHE_INTERFACE_MAP_ENTRY
378 NS_INTERFACE_MAP_ENTRY(nsISupports
)
381 NS_IMPL_CYCLE_COLLECTION_WRAPPERCACHE(nsPluginElement
, mWindow
, mMimeTypes
)
383 nsPluginElement::nsPluginElement(nsPIDOMWindow
* aWindow
,
384 nsPluginTag
* aPluginTag
)
386 mPluginTag(aPluginTag
)
390 nsPluginElement::~nsPluginElement()
395 nsPluginElement::GetParentObject() const
402 nsPluginElement::WrapObject(JSContext
* aCx
)
404 return PluginBinding::Wrap(aCx
, this);
408 nsPluginElement::GetDescription(nsString
& retval
) const
410 CopyUTF8toUTF16(mPluginTag
->mDescription
, retval
);
414 nsPluginElement::GetFilename(nsString
& retval
) const
416 CopyUTF8toUTF16(mPluginTag
->mFileName
, retval
);
420 nsPluginElement::GetVersion(nsString
& retval
) const
422 CopyUTF8toUTF16(mPluginTag
->mVersion
, retval
);
426 nsPluginElement::GetName(nsString
& retval
) const
428 CopyUTF8toUTF16(mPluginTag
->mName
, retval
);
432 nsPluginElement::Item(uint32_t aIndex
)
434 EnsurePluginMimeTypes();
436 return mMimeTypes
.SafeElementAt(aIndex
);
440 nsPluginElement::NamedItem(const nsAString
& aName
)
443 return NamedGetter(aName
, unused
);
447 nsPluginElement::IndexedGetter(uint32_t aIndex
, bool &aFound
)
449 EnsurePluginMimeTypes();
451 aFound
= aIndex
< mMimeTypes
.Length();
453 return aFound
? mMimeTypes
[aIndex
] : nullptr;
457 nsPluginElement::NamedGetter(const nsAString
& aName
, bool &aFound
)
459 EnsurePluginMimeTypes();
463 for (uint32_t i
= 0; i
< mMimeTypes
.Length(); ++i
) {
464 if (mMimeTypes
[i
]->Type().Equals(aName
)) {
467 return mMimeTypes
[i
];
475 nsPluginElement::NameIsEnumerable(const nsAString
& aName
)
481 nsPluginElement::Length()
483 EnsurePluginMimeTypes();
485 return mMimeTypes
.Length();
489 nsPluginElement::GetSupportedNames(unsigned, nsTArray
<nsString
>& retval
)
491 EnsurePluginMimeTypes();
493 for (uint32_t i
= 0; i
< mMimeTypes
.Length(); ++i
) {
494 retval
.AppendElement(mMimeTypes
[i
]->Type());
498 nsTArray
<nsRefPtr
<nsMimeType
> >&
499 nsPluginElement::MimeTypes()
501 EnsurePluginMimeTypes();
507 nsPluginElement::EnsurePluginMimeTypes()
509 if (!mMimeTypes
.IsEmpty()) {
513 for (uint32_t i
= 0; i
< mPluginTag
->mMimeTypes
.Length(); ++i
) {
514 NS_ConvertUTF8toUTF16
type(mPluginTag
->mMimeTypes
[i
]);
515 mMimeTypes
.AppendElement(new nsMimeType(mWindow
, this, i
, type
));