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
)
36 nsCOMPtr
<nsIObserverService
> obsService
=
37 mozilla::services::GetObserverService();
39 obsService
->AddObserver(this, "plugin-info-updated", true);
43 nsPluginArray::~nsPluginArray()
48 nsPluginArray::GetParentObject() const
55 nsPluginArray::WrapObject(JSContext
* aCx
)
57 return PluginArrayBinding::Wrap(aCx
, this);
60 NS_IMPL_CYCLE_COLLECTING_ADDREF(nsPluginArray
)
61 NS_IMPL_CYCLE_COLLECTING_RELEASE(nsPluginArray
)
62 NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(nsPluginArray
)
63 NS_WRAPPERCACHE_INTERFACE_MAP_ENTRY
64 NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsISupports
, nsIObserver
)
65 NS_INTERFACE_MAP_ENTRY(nsIObserver
)
66 NS_INTERFACE_MAP_ENTRY(nsISupportsWeakReference
)
69 NS_IMPL_CYCLE_COLLECTION_WRAPPERCACHE(nsPluginArray
,
75 GetPluginMimeTypes(const nsTArray
<nsRefPtr
<nsPluginElement
> >& aPlugins
,
76 nsTArray
<nsRefPtr
<nsMimeType
> >& aMimeTypes
)
78 for (uint32_t i
= 0; i
< aPlugins
.Length(); ++i
) {
79 nsPluginElement
*plugin
= aPlugins
[i
];
80 aMimeTypes
.AppendElements(plugin
->MimeTypes());
85 operator<(const nsRefPtr
<nsMimeType
>& lhs
, const nsRefPtr
<nsMimeType
>& rhs
)
87 // Sort MIME types alphabetically by type name.
88 return lhs
->Type() < rhs
->Type();
92 nsPluginArray::GetMimeTypes(nsTArray
<nsRefPtr
<nsMimeType
> >& aMimeTypes
,
93 nsTArray
<nsRefPtr
<nsMimeType
> >& aHiddenMimeTypes
)
96 aHiddenMimeTypes
.Clear();
98 if (!AllowPlugins()) {
104 GetPluginMimeTypes(mPlugins
, aMimeTypes
);
105 GetPluginMimeTypes(mHiddenPlugins
, aHiddenMimeTypes
);
107 // Alphabetize the enumeration order of non-hidden MIME types to reduce
108 // fingerprintable entropy based on plugins' installation file times.
113 nsPluginArray::Item(uint32_t aIndex
)
116 return IndexedGetter(aIndex
, unused
);
120 nsPluginArray::NamedItem(const nsAString
& aName
)
123 return NamedGetter(aName
, unused
);
127 nsPluginArray::Refresh(bool aReloadDocuments
)
129 nsRefPtr
<nsPluginHost
> pluginHost
= nsPluginHost::GetInst();
131 if(!AllowPlugins() || !pluginHost
) {
135 // NS_ERROR_PLUGINS_PLUGINSNOTCHANGED on reloading plugins indicates
136 // that plugins did not change and was not reloaded
137 if (pluginHost
->ReloadPlugins() ==
138 NS_ERROR_PLUGINS_PLUGINSNOTCHANGED
) {
139 nsTArray
<nsRefPtr
<nsPluginTag
> > newPluginTags
;
140 pluginHost
->GetPlugins(newPluginTags
);
142 // Check if the number of plugins we know about are different from
143 // the number of plugin tags the plugin host knows about. If the
144 // lengths are different, we refresh. This is safe because we're
145 // notified for every plugin enabling/disabling event that
146 // happens, and therefore the lengths will be in sync only when
147 // the both arrays contain the same plugin tags (though as
149 uint32_t pluginCount
= mPlugins
.Length() + mHiddenPlugins
.Length();
150 if (newPluginTags
.Length() == pluginCount
) {
156 mHiddenPlugins
.Clear();
158 nsCOMPtr
<nsIDOMNavigator
> navigator
;
159 mWindow
->GetNavigator(getter_AddRefs(navigator
));
165 static_cast<mozilla::dom::Navigator
*>(navigator
.get())->RefreshMIMEArray();
167 nsCOMPtr
<nsIWebNavigation
> webNav
= do_GetInterface(mWindow
);
168 if (aReloadDocuments
&& webNav
) {
169 webNav
->Reload(nsIWebNavigation::LOAD_FLAGS_NONE
);
174 nsPluginArray::IndexedGetter(uint32_t aIndex
, bool &aFound
)
178 if (!AllowPlugins()) {
184 aFound
= aIndex
< mPlugins
.Length();
186 return aFound
? mPlugins
[aIndex
] : nullptr;
190 nsPluginArray::Invalidate()
192 nsCOMPtr
<nsIObserverService
> obsService
=
193 mozilla::services::GetObserverService();
195 obsService
->RemoveObserver(this, "plugin-info-updated");
199 static nsPluginElement
*
200 FindPlugin(const nsTArray
<nsRefPtr
<nsPluginElement
> >& aPlugins
,
201 const nsAString
& aName
)
203 for (uint32_t i
= 0; i
< aPlugins
.Length(); ++i
) {
204 nsAutoString pluginName
;
205 nsPluginElement
* plugin
= aPlugins
[i
];
206 plugin
->GetName(pluginName
);
208 if (pluginName
.Equals(aName
)) {
217 nsPluginArray::NamedGetter(const nsAString
& aName
, bool &aFound
)
221 if (!AllowPlugins()) {
227 nsPluginElement
* plugin
= FindPlugin(mPlugins
, aName
);
229 plugin
= FindPlugin(mHiddenPlugins
, aName
);
232 aFound
= (plugin
!= nullptr);
237 nsPluginArray::NameIsEnumerable(const nsAString
& aName
)
243 nsPluginArray::Length()
245 if (!AllowPlugins()) {
251 return mPlugins
.Length();
255 nsPluginArray::GetSupportedNames(unsigned, nsTArray
<nsString
>& aRetval
)
259 if (!AllowPlugins()) {
263 for (uint32_t i
= 0; i
< mPlugins
.Length(); ++i
) {
264 nsAutoString pluginName
;
265 mPlugins
[i
]->GetName(pluginName
);
267 aRetval
.AppendElement(pluginName
);
272 nsPluginArray::Observe(nsISupports
*aSubject
, const char *aTopic
,
273 const char16_t
*aData
) {
274 if (!nsCRT::strcmp(aTopic
, "plugin-info-updated")) {
282 nsPluginArray::AllowPlugins() const
284 nsCOMPtr
<nsIDocShell
> docShell
= mWindow
? mWindow
->GetDocShell() : nullptr;
286 return docShell
&& docShell
->PluginsAllowedInCurrentDoc();
290 HasStringPrefix(const nsCString
& str
, const nsACString
& prefix
) {
291 return str
.Compare(prefix
.BeginReading(), false, prefix
.Length()) == 0;
295 IsPluginEnumerable(const nsTArray
<nsCString
>& enumerableNames
,
296 const nsPluginTag
* pluginTag
)
298 const nsCString
& pluginName
= pluginTag
->mName
;
300 const uint32_t length
= enumerableNames
.Length();
301 for (uint32_t i
= 0; i
< length
; i
++) {
302 const nsCString
& name
= enumerableNames
[i
];
303 if (HasStringPrefix(pluginName
, name
)) {
304 return true; // don't hide plugin
308 return false; // hide plugin!
312 operator<(const nsRefPtr
<nsPluginElement
>& lhs
,
313 const nsRefPtr
<nsPluginElement
>& rhs
)
315 // Sort plugins alphabetically by name.
316 return lhs
->PluginTag()->mName
< rhs
->PluginTag()->mName
;
320 nsPluginArray::EnsurePlugins()
322 if (!mPlugins
.IsEmpty() || !mHiddenPlugins
.IsEmpty()) {
323 // We already have an array of plugin elements.
327 nsRefPtr
<nsPluginHost
> pluginHost
= nsPluginHost::GetInst();
329 // We have no plugin host.
333 nsTArray
<nsRefPtr
<nsPluginTag
> > pluginTags
;
334 pluginHost
->GetPlugins(pluginTags
);
336 nsTArray
<nsCString
> enumerableNames
;
338 const nsAdoptingCString
& enumerableNamesPref
=
339 Preferences::GetCString("plugins.enumerable_names");
341 bool disablePluginHiding
= !enumerableNamesPref
||
342 enumerableNamesPref
.EqualsLiteral("*");
344 if (!disablePluginHiding
) {
345 nsCCharSeparatedTokenizer
tokens(enumerableNamesPref
, ',');
346 while (tokens
.hasMoreTokens()) {
347 const nsCSubstring
& token
= tokens
.nextToken();
348 if (!token
.IsEmpty()) {
349 enumerableNames
.AppendElement(token
);
354 // need to wrap each of these with a nsPluginElement, which is
356 for (uint32_t i
= 0; i
< pluginTags
.Length(); ++i
) {
357 nsPluginTag
* pluginTag
= pluginTags
[i
];
359 // Add the plugin to the list of hidden plugins or non-hidden plugins?
360 nsTArray
<nsRefPtr
<nsPluginElement
> >& pluginArray
=
361 (disablePluginHiding
|| IsPluginEnumerable(enumerableNames
, pluginTag
))
365 pluginArray
.AppendElement(new nsPluginElement(mWindow
, pluginTag
));
368 // Alphabetize the enumeration order of non-hidden plugins to reduce
369 // fingerprintable entropy based on plugins' installation file times.
373 // nsPluginElement implementation.
375 NS_IMPL_CYCLE_COLLECTING_ADDREF(nsPluginElement
)
376 NS_IMPL_CYCLE_COLLECTING_RELEASE(nsPluginElement
)
377 NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(nsPluginElement
)
378 NS_WRAPPERCACHE_INTERFACE_MAP_ENTRY
379 NS_INTERFACE_MAP_ENTRY(nsISupports
)
382 NS_IMPL_CYCLE_COLLECTION_WRAPPERCACHE(nsPluginElement
, mWindow
, mMimeTypes
)
384 nsPluginElement::nsPluginElement(nsPIDOMWindow
* aWindow
,
385 nsPluginTag
* aPluginTag
)
387 mPluginTag(aPluginTag
)
392 nsPluginElement::~nsPluginElement()
397 nsPluginElement::GetParentObject() const
404 nsPluginElement::WrapObject(JSContext
* aCx
)
406 return PluginBinding::Wrap(aCx
, this);
410 nsPluginElement::GetDescription(nsString
& retval
) const
412 CopyUTF8toUTF16(mPluginTag
->mDescription
, retval
);
416 nsPluginElement::GetFilename(nsString
& retval
) const
418 CopyUTF8toUTF16(mPluginTag
->mFileName
, retval
);
422 nsPluginElement::GetVersion(nsString
& retval
) const
424 CopyUTF8toUTF16(mPluginTag
->mVersion
, retval
);
428 nsPluginElement::GetName(nsString
& retval
) const
430 CopyUTF8toUTF16(mPluginTag
->mName
, retval
);
434 nsPluginElement::Item(uint32_t aIndex
)
436 EnsurePluginMimeTypes();
438 return mMimeTypes
.SafeElementAt(aIndex
);
442 nsPluginElement::NamedItem(const nsAString
& aName
)
445 return NamedGetter(aName
, unused
);
449 nsPluginElement::IndexedGetter(uint32_t aIndex
, bool &aFound
)
451 EnsurePluginMimeTypes();
453 aFound
= aIndex
< mMimeTypes
.Length();
455 return aFound
? mMimeTypes
[aIndex
] : nullptr;
459 nsPluginElement::NamedGetter(const nsAString
& aName
, bool &aFound
)
461 EnsurePluginMimeTypes();
465 for (uint32_t i
= 0; i
< mMimeTypes
.Length(); ++i
) {
466 if (mMimeTypes
[i
]->Type().Equals(aName
)) {
469 return mMimeTypes
[i
];
477 nsPluginElement::NameIsEnumerable(const nsAString
& aName
)
483 nsPluginElement::Length()
485 EnsurePluginMimeTypes();
487 return mMimeTypes
.Length();
491 nsPluginElement::GetSupportedNames(unsigned, nsTArray
<nsString
>& retval
)
493 EnsurePluginMimeTypes();
495 for (uint32_t i
= 0; i
< mMimeTypes
.Length(); ++i
) {
496 retval
.AppendElement(mMimeTypes
[i
]->Type());
500 nsTArray
<nsRefPtr
<nsMimeType
> >&
501 nsPluginElement::MimeTypes()
503 EnsurePluginMimeTypes();
509 nsPluginElement::EnsurePluginMimeTypes()
511 if (!mMimeTypes
.IsEmpty()) {
515 for (uint32_t i
= 0; i
< mPluginTag
->mMimeTypes
.Length(); ++i
) {
516 NS_ConvertUTF8toUTF16
type(mPluginTag
->mMimeTypes
[i
]);
517 mMimeTypes
.AppendElement(new nsMimeType(mWindow
, this, i
, type
));