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 /* nsPluginHost.cpp - top-level plugin management code */
9 #include "nsPluginHost.h"
15 #include "nsNPAPIPlugin.h"
16 #include "nsNPAPIPluginStreamListener.h"
17 #include "nsNPAPIPluginInstance.h"
18 #include "nsPluginInstanceOwner.h"
19 #include "nsObjectLoadingContent.h"
20 #include "nsIHTTPHeaderListener.h"
21 #include "nsIHttpHeaderVisitor.h"
22 #include "nsIObserverService.h"
23 #include "nsIHttpProtocolHandler.h"
24 #include "nsIHttpChannel.h"
25 #include "nsIUploadChannel.h"
26 #include "nsIByteRangeRequest.h"
27 #include "nsIStreamListener.h"
28 #include "nsIInputStream.h"
29 #include "nsIOutputStream.h"
32 #include "nsReadableUtils.h"
33 #include "nsIProtocolProxyService2.h"
34 #include "nsIStreamConverterService.h"
36 #if defined(XP_MACOSX)
37 #include "nsILocalFileMac.h"
39 #include "nsISeekableStream.h"
40 #include "nsNetUtil.h"
41 #include "nsIProgressEventSink.h"
42 #include "nsIDocument.h"
43 #include "nsPluginLogging.h"
44 #include "nsIScriptChannel.h"
45 #include "nsIBlocklistService.h"
46 #include "nsVersionComparator.h"
47 #include "nsIObjectLoadingContent.h"
48 #include "nsIWritablePropertyBag2.h"
49 #include "nsICategoryManager.h"
50 #include "nsPluginStreamListenerPeer.h"
51 #include "mozilla/dom/ContentChild.h"
52 #include "mozilla/LoadInfo.h"
53 #include "mozilla/plugins/PluginAsyncSurrogate.h"
54 #include "mozilla/plugins/PluginBridge.h"
55 #include "mozilla/plugins/PluginTypes.h"
56 #include "mozilla/Preferences.h"
58 #include "nsEnumeratorUtils.h"
60 #include "nsXPCOMCID.h"
61 #include "nsISupportsPrimitives.h"
63 #include "nsXULAppAPI.h"
64 #include "nsIXULRuntime.h"
67 #include "nsIWindowWatcher.h"
68 #include "nsIDOMElement.h"
69 #include "nsIDOMWindow.h"
73 #include "nsThreadUtils.h"
74 #include "nsIInputStreamTee.h"
76 #include "nsDirectoryServiceDefs.h"
77 #include "nsAppDirectoryServiceDefs.h"
78 #include "nsPluginDirServiceProvider.h"
80 #include "nsUnicharUtils.h"
81 #include "nsPluginManifestLineReader.h"
83 #include "nsIWeakReferenceUtils.h"
84 #include "nsIPresShell.h"
85 #include "nsPluginNativeWindow.h"
86 #include "nsIScriptSecurityManager.h"
87 #include "nsIContentPolicy.h"
88 #include "nsContentPolicyUtils.h"
89 #include "mozilla/TimeStamp.h"
90 #include "mozilla/Telemetry.h"
91 #include "nsIImageLoadingContent.h"
92 #include "mozilla/Preferences.h"
93 #include "nsVersionComparator.h"
96 #include "nsIWindowMediator.h"
97 #include "nsIBaseWindow.h"
103 #include <android/log.h>
104 #define LOG(args...) __android_log_print(ANDROID_LOG_INFO, "GeckoPlugins" , ## args)
107 #if MOZ_CRASHREPORTER
108 #include "nsExceptionHandler.h"
111 using namespace mozilla
;
112 using mozilla::TimeStamp
;
113 using mozilla::plugins::PluginTag
;
114 using mozilla::plugins::PluginAsyncSurrogate
;
116 // Null out a strong ref to a linked list iteratively to avoid
117 // exhausting the stack (bug 486349).
118 #define NS_ITERATIVE_UNREF_LIST(type_, list_, mNext_) \
121 type_ temp = list_->mNext_; \
122 list_->mNext_ = nullptr; \
127 // this is the name of the directory which will be created
128 // to cache temporary files.
129 #define kPluginTmpDirName NS_LITERAL_CSTRING("plugtmp")
131 static const char *kPrefWhitelist
= "plugin.allowed_types";
132 static const char *kPrefDisableFullPage
= "plugin.disable_full_page_plugin_for_types";
133 static const char *kPrefJavaMIME
= "plugin.java.mime";
135 // How long we wait before unloading an idle plugin process.
136 // Defaults to 30 seconds.
137 static const char *kPrefUnloadPluginTimeoutSecs
= "dom.ipc.plugins.unloadTimeoutSecs";
138 static const uint32_t kDefaultPluginUnloadingTimeout
= 30;
140 // Version of cached plugin info
141 // 0.01 first implementation
142 // 0.02 added caching of CanUnload to fix bug 105935
143 // 0.03 changed name, description and mime desc from string to bytes, bug 108246
144 // 0.04 added new mime entry point on Mac, bug 113464
145 // 0.05 added new entry point check for the default plugin, bug 132430
146 // 0.06 strip off suffixes in mime description strings, bug 53895
147 // 0.07 changed nsIRegistry to flat file support for caching plugins info
148 // 0.08 mime entry point on MachO, bug 137535
149 // 0.09 the file encoding is changed to UTF-8, bug 420285
150 // 0.10 added plugin versions on appropriate platforms, bug 427743
151 // 0.11 file name and full path fields now store expected values on all platforms, bug 488181
152 // 0.12 force refresh due to quicktime pdf claim fix, bug 611197
153 // 0.13 add architecture and list of invalid plugins, bug 616271
154 // 0.14 force refresh due to locale comparison fix, bug 611296
155 // 0.15 force refresh due to bug in reading Java plist MIME data, bug 638171
156 // 0.16 version bump to avoid importing the plugin flags in newer versions
157 // 0.17 added flag on whether plugin is loaded from an XPI
158 // The current plugin registry version (and the maximum version we know how to read)
159 static const char *kPluginRegistryVersion
= "0.17";
160 // The minimum registry version we know how to read
161 static const char *kMinimumRegistryVersion
= "0.9";
163 static const char kDirectoryServiceContractID
[] = "@mozilla.org/file/directory_service;1";
165 #define kPluginRegistryFilename NS_LITERAL_CSTRING("pluginreg.dat")
167 #ifdef PLUGIN_LOGGING
168 PRLogModuleInfo
* nsPluginLogging::gNPNLog
= nullptr;
169 PRLogModuleInfo
* nsPluginLogging::gNPPLog
= nullptr;
170 PRLogModuleInfo
* nsPluginLogging::gPluginLog
= nullptr;
173 // #defines for plugin cache and prefs
174 #define NS_PREF_MAX_NUM_CACHED_INSTANCES "browser.plugins.max_num_cached_plugins"
175 // Raise this from '10' to '50' to work around a bug in Apple's current Java
176 // plugins on OS X Lion and SnowLeopard. See bug 705931.
177 #define DEFAULT_NUMBER_OF_STOPPED_INSTANCES 50
179 nsIFile
*nsPluginHost::sPluginTempDir
;
180 nsPluginHost
*nsPluginHost::sInst
;
182 NS_IMPL_ISUPPORTS0(nsInvalidPluginTag
)
184 nsInvalidPluginTag::nsInvalidPluginTag(const char* aFullPath
, int64_t aLastModifiedTime
)
185 : mFullPath(aFullPath
),
186 mLastModifiedTime(aLastModifiedTime
),
190 nsInvalidPluginTag::~nsInvalidPluginTag()
193 // Helper to check for a MIME in a comma-delimited preference
195 IsTypeInList(nsCString
&aMimeType
, nsCString aTypeList
)
197 nsAutoCString searchStr
;
198 searchStr
.Assign(',');
199 searchStr
.Append(aTypeList
);
200 searchStr
.Append(',');
202 nsACString::const_iterator start
, end
;
204 searchStr
.BeginReading(start
);
205 searchStr
.EndReading(end
);
207 nsAutoCString commaSeparated
;
208 commaSeparated
.Assign(',');
209 commaSeparated
+= aMimeType
;
210 commaSeparated
.Append(',');
212 return FindInReadable(commaSeparated
, start
, end
);
215 // flat file reg funcs
217 bool ReadSectionHeader(nsPluginManifestLineReader
& reader
, const char *token
)
220 if (*reader
.LinePtr() == '[') {
221 char* p
= reader
.LinePtr() + (reader
.LineLength() - 1);
227 if (1 != reader
.ParseLine(values
, 1))
229 // ignore the leading '['
230 if (PL_strcmp(values
[0]+1, token
)) {
231 break; // it's wrong token
235 } while (reader
.NextLine());
239 static bool UnloadPluginsASAP()
241 return (Preferences::GetUint(kPrefUnloadPluginTimeoutSecs
, kDefaultPluginUnloadingTimeout
) == 0);
244 nsPluginHost::nsPluginHost()
245 // No need to initialize members to nullptr, false etc because this class
246 // has a zeroing operator new.
248 // Bump the pluginchanged epoch on startup. This insures content gets a
249 // good plugin list the first time it requests it. Normally we'd just
250 // init this to 1, but due to the unique nature of our ctor we need to do
252 if (XRE_GetProcessType() == GeckoProcessType_Default
) {
253 IncrementChromeEpoch();
256 // check to see if pref is set at startup to let plugins take over in
257 // full page mode for certain image mime types that we handle internally
258 mOverrideInternalTypes
=
259 Preferences::GetBool("plugin.override_internal_types", false);
261 mPluginsDisabled
= Preferences::GetBool("plugin.disable", false);
262 mPluginsClickToPlay
= Preferences::GetBool("plugins.click_to_play", false);
264 Preferences::AddStrongObserver(this, "plugin.disable");
265 Preferences::AddStrongObserver(this, "plugins.click_to_play");
267 nsCOMPtr
<nsIObserverService
> obsService
=
268 mozilla::services::GetObserverService();
270 obsService
->AddObserver(this, NS_XPCOM_SHUTDOWN_OBSERVER_ID
, false);
271 obsService
->AddObserver(this, "blocklist-updated", false);
272 #ifdef MOZ_WIDGET_ANDROID
273 obsService
->AddObserver(this, "application-foreground", false);
274 obsService
->AddObserver(this, "application-background", false);
278 #ifdef PLUGIN_LOGGING
279 nsPluginLogging::gNPNLog
= PR_NewLogModule(NPN_LOG_NAME
);
280 nsPluginLogging::gNPPLog
= PR_NewLogModule(NPP_LOG_NAME
);
281 nsPluginLogging::gPluginLog
= PR_NewLogModule(PLUGIN_LOG_NAME
);
283 PR_LOG(nsPluginLogging::gNPNLog
, PLUGIN_LOG_ALWAYS
,("NPN Logging Active!\n"));
284 PR_LOG(nsPluginLogging::gPluginLog
, PLUGIN_LOG_ALWAYS
,("General Plugin Logging Active! (nsPluginHost::ctor)\n"));
285 PR_LOG(nsPluginLogging::gNPPLog
, PLUGIN_LOG_ALWAYS
,("NPP Logging Active!\n"));
287 PLUGIN_LOG(PLUGIN_LOG_ALWAYS
,("nsPluginHost::ctor\n"));
292 nsPluginHost::~nsPluginHost()
294 PLUGIN_LOG(PLUGIN_LOG_ALWAYS
,("nsPluginHost::dtor\n"));
300 NS_IMPL_ISUPPORTS(nsPluginHost
,
304 nsISupportsWeakReference
)
306 already_AddRefed
<nsPluginHost
>
307 nsPluginHost::GetInst()
310 sInst
= new nsPluginHost();
316 nsRefPtr
<nsPluginHost
> inst
= sInst
;
317 return inst
.forget();
320 bool nsPluginHost::IsRunningPlugin(nsPluginTag
* aPluginTag
)
322 if (!aPluginTag
|| !aPluginTag
->mPlugin
) {
326 if (aPluginTag
->mContentProcessRunningCount
) {
330 for (uint32_t i
= 0; i
< mInstances
.Length(); i
++) {
331 nsNPAPIPluginInstance
*instance
= mInstances
[i
].get();
333 instance
->GetPlugin() == aPluginTag
->mPlugin
&&
334 instance
->IsRunning()) {
342 nsresult
nsPluginHost::ReloadPlugins()
344 PLUGIN_LOG(PLUGIN_LOG_NORMAL
,
345 ("nsPluginHost::ReloadPlugins Begin\n"));
349 // this will create the initial plugin list out of cache
350 // if it was not created yet
352 return LoadPlugins();
354 // we are re-scanning plugins. New plugins may have been added, also some
355 // plugins may have been removed, so we should probably shut everything down
356 // but don't touch running (active and not stopped) plugins
358 // check if plugins changed, no need to do anything else
359 // if no changes to plugins have been made
360 // false instructs not to touch the plugin list, just to
361 // look for possible changes
362 bool pluginschanged
= true;
363 FindPlugins(false, &pluginschanged
);
365 // if no changed detected, return an appropriate error code
367 return NS_ERROR_PLUGINS_PLUGINSNOTCHANGED
;
369 // shutdown plugins and kill the list if there are no running plugins
370 nsRefPtr
<nsPluginTag
> prev
;
371 nsRefPtr
<nsPluginTag
> next
;
373 for (nsRefPtr
<nsPluginTag
> p
= mPlugins
; p
!= nullptr;) {
376 // only remove our plugin from the list if it's not running.
377 if (!IsRunningPlugin(p
)) {
385 // attempt to unload plugins whenever they are removed from the list
386 p
->TryUnloadPlugin(false);
397 mPluginsLoaded
= false;
402 PLUGIN_LOG(PLUGIN_LOG_NORMAL
,
403 ("nsPluginHost::ReloadPlugins End\n"));
408 #define NS_RETURN_UASTRING_SIZE 128
410 nsresult
nsPluginHost::UserAgent(const char **retstring
)
412 static char resultString
[NS_RETURN_UASTRING_SIZE
];
415 nsCOMPtr
<nsIHttpProtocolHandler
> http
= do_GetService(NS_NETWORK_PROTOCOL_CONTRACTID_PREFIX
"http", &res
);
419 nsAutoCString uaString
;
420 res
= http
->GetUserAgent(uaString
);
422 if (NS_SUCCEEDED(res
)) {
423 if (NS_RETURN_UASTRING_SIZE
> uaString
.Length()) {
424 PL_strcpy(resultString
, uaString
.get());
426 // Copy as much of UA string as we can (terminate at right-most space).
427 PL_strncpy(resultString
, uaString
.get(), NS_RETURN_UASTRING_SIZE
);
428 for (int i
= NS_RETURN_UASTRING_SIZE
- 1; i
>= 0; i
--) {
430 resultString
[NS_RETURN_UASTRING_SIZE
- 1] = '\0';
432 else if (resultString
[i
] == ' ') {
433 resultString
[i
] = '\0';
438 *retstring
= resultString
;
441 *retstring
= nullptr;
444 PLUGIN_LOG(PLUGIN_LOG_NORMAL
, ("nsPluginHost::UserAgent return=%s\n", *retstring
));
449 nsresult
nsPluginHost::GetURL(nsISupports
* pluginInst
,
452 nsNPAPIPluginStreamListener
* streamListener
,
454 const char* referrer
,
457 return GetURLWithHeaders(static_cast<nsNPAPIPluginInstance
*>(pluginInst
),
458 url
, target
, streamListener
, altHost
, referrer
,
459 forceJSEnabled
, 0, nullptr);
462 nsresult
nsPluginHost::GetURLWithHeaders(nsNPAPIPluginInstance
* pluginInst
,
465 nsNPAPIPluginStreamListener
* streamListener
,
467 const char* referrer
,
469 uint32_t getHeadersLength
,
470 const char* getHeaders
)
472 // we can only send a stream back to the plugin (as specified by a
473 // null target) if we also have a nsNPAPIPluginStreamListener to talk to
474 if (!target
&& !streamListener
)
475 return NS_ERROR_ILLEGAL_VALUE
;
477 nsresult rv
= DoURLLoadSecurityCheck(pluginInst
, url
);
482 nsRefPtr
<nsPluginInstanceOwner
> owner
= pluginInst
->GetOwner();
484 if ((0 == PL_strcmp(target
, "newwindow")) ||
485 (0 == PL_strcmp(target
, "_new")))
487 else if (0 == PL_strcmp(target
, "_current"))
490 rv
= owner
->GetURL(url
, target
, nullptr, nullptr, 0);
495 rv
= NewPluginURLStream(NS_ConvertUTF8toUTF16(url
), pluginInst
,
496 streamListener
, nullptr,
497 getHeaders
, getHeadersLength
);
502 nsresult
nsPluginHost::PostURL(nsISupports
* pluginInst
,
504 uint32_t postDataLen
,
505 const char* postData
,
508 nsNPAPIPluginStreamListener
* streamListener
,
510 const char* referrer
,
512 uint32_t postHeadersLength
,
513 const char* postHeaders
)
517 // we can only send a stream back to the plugin (as specified
518 // by a null target) if we also have a nsNPAPIPluginStreamListener
520 if (!target
&& !streamListener
)
521 return NS_ERROR_ILLEGAL_VALUE
;
523 nsNPAPIPluginInstance
* instance
= static_cast<nsNPAPIPluginInstance
*>(pluginInst
);
525 rv
= DoURLLoadSecurityCheck(instance
, url
);
529 nsCOMPtr
<nsIInputStream
> postStream
;
531 nsCOMPtr
<nsIFile
> file
;
532 rv
= CreateTempFileToPost(postData
, getter_AddRefs(file
));
536 nsCOMPtr
<nsIInputStream
> fileStream
;
537 rv
= NS_NewLocalFileInputStream(getter_AddRefs(fileStream
),
541 nsIFileInputStream::DELETE_ON_CLOSE
|
542 nsIFileInputStream::CLOSE_ON_EOF
);
546 rv
= NS_NewBufferedInputStream(getter_AddRefs(postStream
), fileStream
, 8192);
551 uint32_t newDataToPostLen
;
552 ParsePostBufferToFixHeaders(postData
, postDataLen
, &dataToPost
, &newDataToPostLen
);
554 return NS_ERROR_UNEXPECTED
;
556 nsCOMPtr
<nsIStringInputStream
> sis
= do_CreateInstance("@mozilla.org/io/string-input-stream;1", &rv
);
562 // data allocated by ParsePostBufferToFixHeaders() is managed and
563 // freed by the string stream.
564 postDataLen
= newDataToPostLen
;
565 sis
->AdoptData(dataToPost
, postDataLen
);
570 nsRefPtr
<nsPluginInstanceOwner
> owner
= instance
->GetOwner();
572 if ((0 == PL_strcmp(target
, "newwindow")) ||
573 (0 == PL_strcmp(target
, "_new"))) {
575 } else if (0 == PL_strcmp(target
, "_current")) {
578 rv
= owner
->GetURL(url
, target
, postStream
,
579 (void*)postHeaders
, postHeadersLength
);
583 // if we don't have a target, just create a stream.
585 rv
= NewPluginURLStream(NS_ConvertUTF8toUTF16(url
), instance
,
587 postStream
, postHeaders
, postHeadersLength
);
592 /* This method queries the prefs for proxy information.
593 * It has been tested and is known to work in the following three cases
594 * when no proxy host or port is specified
595 * when only the proxy host is specified
596 * when only the proxy port is specified
597 * This method conforms to the return code specified in
598 * http://developer.netscape.com/docs/manuals/proxy/adminnt/autoconf.htm#1020923
599 * with the exception that multiple values are not implemented.
602 nsresult
nsPluginHost::FindProxyForURL(const char* url
, char* *result
)
604 if (!url
|| !result
) {
605 return NS_ERROR_INVALID_ARG
;
609 nsCOMPtr
<nsIURI
> uriIn
;
610 nsCOMPtr
<nsIProtocolProxyService
> proxyService
;
611 nsCOMPtr
<nsIProtocolProxyService2
> proxyService2
;
612 nsCOMPtr
<nsIIOService
> ioService
;
614 proxyService
= do_GetService(NS_PROTOCOLPROXYSERVICE_CONTRACTID
, &res
);
615 if (NS_FAILED(res
) || !proxyService
)
618 proxyService2
= do_QueryInterface(proxyService
, &res
);
619 if (NS_FAILED(res
) || !proxyService2
)
622 ioService
= do_GetService(NS_IOSERVICE_CONTRACTID
, &res
);
623 if (NS_FAILED(res
) || !ioService
)
626 // make an nsURI from the argument url
627 res
= ioService
->NewURI(nsDependentCString(url
), nullptr, nullptr, getter_AddRefs(uriIn
));
631 nsCOMPtr
<nsIProxyInfo
> pi
;
633 // Remove this with bug 778201
634 res
= proxyService2
->DeprecatedBlockingResolve(uriIn
, 0, getter_AddRefs(pi
));
638 nsAutoCString host
, type
;
641 // These won't fail, and even if they do... we'll be ok.
648 if (!pi
|| host
.IsEmpty() || port
<= 0 || host
.EqualsLiteral("direct")) {
649 *result
= PL_strdup("DIRECT");
650 } else if (type
.EqualsLiteral("http")) {
651 *result
= PR_smprintf("PROXY %s:%d", host
.get(), port
);
652 } else if (type
.EqualsLiteral("socks4")) {
653 *result
= PR_smprintf("SOCKS %s:%d", host
.get(), port
);
654 } else if (type
.EqualsLiteral("socks")) {
655 // XXX - this is socks5, but there is no API for us to tell the
656 // plugin that fact. SOCKS for now, in case the proxy server
657 // speaks SOCKS4 as well. See bug 78176
658 // For a long time this was returning an http proxy type, so
659 // very little is probably broken by this
660 *result
= PR_smprintf("SOCKS %s:%d", host
.get(), port
);
662 NS_ASSERTION(false, "Unknown proxy type!");
663 *result
= PL_strdup("DIRECT");
666 if (nullptr == *result
)
667 res
= NS_ERROR_OUT_OF_MEMORY
;
672 nsresult
nsPluginHost::Init()
677 nsresult
nsPluginHost::UnloadPlugins()
679 PLUGIN_LOG(PLUGIN_LOG_NORMAL
, ("nsPluginHost::UnloadPlugins Called\n"));
684 // we should call nsIPluginInstance::Stop and nsIPluginInstance::SetWindow
685 // for those plugins who want it
686 DestroyRunningInstances(nullptr);
688 nsPluginTag
*pluginTag
;
689 for (pluginTag
= mPlugins
; pluginTag
; pluginTag
= pluginTag
->mNext
) {
690 pluginTag
->TryUnloadPlugin(true);
693 NS_ITERATIVE_UNREF_LIST(nsRefPtr
<nsPluginTag
>, mPlugins
, mNext
);
694 NS_ITERATIVE_UNREF_LIST(nsRefPtr
<nsPluginTag
>, mCachedPlugins
, mNext
);
695 NS_ITERATIVE_UNREF_LIST(nsRefPtr
<nsInvalidPluginTag
>, mInvalidPlugins
, mNext
);
697 // Lets remove any of the temporary files that we created.
698 if (sPluginTempDir
) {
699 sPluginTempDir
->Remove(true);
700 NS_RELEASE(sPluginTempDir
);
704 if (mPrivateDirServiceProvider
) {
705 nsCOMPtr
<nsIDirectoryService
> dirService
=
706 do_GetService(kDirectoryServiceContractID
);
708 dirService
->UnregisterProvider(mPrivateDirServiceProvider
);
709 mPrivateDirServiceProvider
= nullptr;
713 mPluginsLoaded
= false;
718 void nsPluginHost::OnPluginInstanceDestroyed(nsPluginTag
* aPluginTag
)
720 bool hasInstance
= false;
721 for (uint32_t i
= 0; i
< mInstances
.Length(); i
++) {
722 if (TagForPlugin(mInstances
[i
]->GetPlugin()) == aPluginTag
) {
728 // We have some options for unloading plugins if they have no instances.
730 // Unloading plugins immediately can be bad - some plugins retain state
731 // between instances even when there are none. This is largely limited to
732 // going from one page to another, so state is retained without an instance
733 // for only a very short period of time. In order to allow this to work
734 // we don't unload plugins immediately by default. This is supported
735 // via a hidden user pref though.
737 // Another reason not to unload immediately is that loading is expensive,
738 // and it is better to leave popular plugins loaded.
740 // Our default behavior is to try to unload a plugin after a pref-controlled
741 // delay once its last instance is destroyed. This seems like a reasonable
742 // compromise that allows us to reclaim memory while allowing short state
743 // retention and avoid perf hits for loading popular plugins.
745 if (UnloadPluginsASAP()) {
746 aPluginTag
->TryUnloadPlugin(false);
748 if (aPluginTag
->mUnloadTimer
) {
749 aPluginTag
->mUnloadTimer
->Cancel();
751 aPluginTag
->mUnloadTimer
= do_CreateInstance(NS_TIMER_CONTRACTID
);
753 uint32_t unloadTimeout
= Preferences::GetUint(kPrefUnloadPluginTimeoutSecs
,
754 kDefaultPluginUnloadingTimeout
);
755 aPluginTag
->mUnloadTimer
->InitWithCallback(this,
756 1000 * unloadTimeout
,
757 nsITimer::TYPE_ONE_SHOT
);
763 nsPluginHost::GetPluginTempDir(nsIFile
**aDir
)
765 if (!sPluginTempDir
) {
766 nsCOMPtr
<nsIFile
> tmpDir
;
767 nsresult rv
= NS_GetSpecialDirectory(NS_OS_TEMP_DIR
,
768 getter_AddRefs(tmpDir
));
769 NS_ENSURE_SUCCESS(rv
, rv
);
771 rv
= tmpDir
->AppendNative(kPluginTmpDirName
);
773 // make it unique, and mode == 0700, not world-readable
774 rv
= tmpDir
->CreateUnique(nsIFile::DIRECTORY_TYPE
, 0700);
775 NS_ENSURE_SUCCESS(rv
, rv
);
777 tmpDir
.swap(sPluginTempDir
);
780 return sPluginTempDir
->Clone(aDir
);
784 nsPluginHost::InstantiatePluginInstance(const char *aMimeType
, nsIURI
* aURL
,
785 nsObjectLoadingContent
*aContent
,
786 nsPluginInstanceOwner
** aOwner
)
788 NS_ENSURE_ARG_POINTER(aOwner
);
790 #ifdef PLUGIN_LOGGING
791 nsAutoCString urlSpec
;
793 aURL
->GetAsciiSpec(urlSpec
);
795 PR_LOG(nsPluginLogging::gPluginLog
, PLUGIN_LOG_NORMAL
,
796 ("nsPluginHost::InstantiatePlugin Begin mime=%s, url=%s\n",
797 aMimeType
, urlSpec
.get()));
803 NS_NOTREACHED("Attempting to spawn a plugin with no mime type");
804 return NS_ERROR_FAILURE
;
807 nsRefPtr
<nsPluginInstanceOwner
> instanceOwner
= new nsPluginInstanceOwner();
808 if (!instanceOwner
) {
809 return NS_ERROR_OUT_OF_MEMORY
;
812 nsCOMPtr
<nsIContent
> ourContent
= do_QueryInterface(static_cast<nsIImageLoadingContent
*>(aContent
));
813 nsresult rv
= instanceOwner
->Init(ourContent
);
818 nsPluginTagType tagType
;
819 rv
= instanceOwner
->GetTagType(&tagType
);
821 instanceOwner
->Destroy();
825 if (tagType
!= nsPluginTagType_Embed
&&
826 tagType
!= nsPluginTagType_Applet
&&
827 tagType
!= nsPluginTagType_Object
) {
828 instanceOwner
->Destroy();
829 return NS_ERROR_FAILURE
;
832 rv
= SetUpPluginInstance(aMimeType
, aURL
, instanceOwner
);
834 instanceOwner
->Destroy();
835 return NS_ERROR_FAILURE
;
837 const bool isAsyncInit
= (rv
== NS_PLUGIN_INIT_PENDING
);
839 nsRefPtr
<nsNPAPIPluginInstance
> instance
;
840 rv
= instanceOwner
->GetInstance(getter_AddRefs(instance
));
842 instanceOwner
->Destroy();
846 // Async init plugins will initiate their own widget creation.
847 if (!isAsyncInit
&& instance
) {
848 CreateWidget(instanceOwner
);
851 // At this point we consider instantiation to be successful. Do not return an error.
852 instanceOwner
.forget(aOwner
);
854 #ifdef PLUGIN_LOGGING
855 nsAutoCString urlSpec2
;
856 if (aURL
!= nullptr) aURL
->GetAsciiSpec(urlSpec2
);
858 PR_LOG(nsPluginLogging::gPluginLog
, PLUGIN_LOG_NORMAL
,
859 ("nsPluginHost::InstantiatePlugin Finished mime=%s, rv=%d, url=%s\n",
860 aMimeType
, rv
, urlSpec2
.get()));
869 nsPluginHost::FindTagForLibrary(PRLibrary
* aLibrary
)
871 nsPluginTag
* pluginTag
;
872 for (pluginTag
= mPlugins
; pluginTag
; pluginTag
= pluginTag
->mNext
) {
873 if (pluginTag
->mLibrary
== aLibrary
) {
881 nsPluginHost::TagForPlugin(nsNPAPIPlugin
* aPlugin
)
883 nsPluginTag
* pluginTag
;
884 for (pluginTag
= mPlugins
; pluginTag
; pluginTag
= pluginTag
->mNext
) {
885 if (pluginTag
->mPlugin
== aPlugin
) {
889 // a plugin should never exist without a corresponding tag
890 NS_ERROR("TagForPlugin has failed");
894 nsresult
nsPluginHost::SetUpPluginInstance(const char *aMimeType
,
896 nsPluginInstanceOwner
*aOwner
)
898 NS_ENSURE_ARG_POINTER(aOwner
);
900 nsresult rv
= TrySetUpPluginInstance(aMimeType
, aURL
, aOwner
);
901 if (NS_SUCCEEDED(rv
)) {
905 // If we failed to load a plugin instance we'll try again after
906 // reloading our plugin list. Only do that once per document to
907 // avoid redundant high resource usage on pages with multiple
908 // unkown instance types. We'll do that by caching the document.
909 nsCOMPtr
<nsIDocument
> document
;
910 aOwner
->GetDocument(getter_AddRefs(document
));
912 nsCOMPtr
<nsIDocument
> currentdocument
= do_QueryReferent(mCurrentDocument
);
913 if (document
== currentdocument
) {
917 mCurrentDocument
= do_GetWeakReference(document
);
919 // Don't try to set up an instance again if nothing changed.
920 if (ReloadPlugins() == NS_ERROR_PLUGINS_PLUGINSNOTCHANGED
) {
924 return TrySetUpPluginInstance(aMimeType
, aURL
, aOwner
);
928 nsPluginHost::TrySetUpPluginInstance(const char *aMimeType
,
930 nsPluginInstanceOwner
*aOwner
)
932 #ifdef PLUGIN_LOGGING
933 nsAutoCString urlSpec
;
934 if (aURL
!= nullptr) aURL
->GetSpec(urlSpec
);
936 PR_LOG(nsPluginLogging::gPluginLog
, PLUGIN_LOG_NORMAL
,
937 ("nsPluginHost::TrySetupPluginInstance Begin mime=%s, owner=%p, url=%s\n",
938 aMimeType
, aOwner
, urlSpec
.get()));
943 nsRefPtr
<nsNPAPIPlugin
> plugin
;
944 GetPlugin(aMimeType
, getter_AddRefs(plugin
));
946 return NS_ERROR_FAILURE
;
949 nsPluginTag
* pluginTag
= FindPluginForType(aMimeType
, true);
951 NS_ASSERTION(pluginTag
, "Must have plugin tag here!");
953 #if defined(MOZ_WIDGET_ANDROID) && defined(MOZ_CRASHREPORTER)
954 if (pluginTag
->mIsFlashPlugin
) {
955 CrashReporter::AnnotateCrashReport(NS_LITERAL_CSTRING("FlashVersion"), pluginTag
->mVersion
);
959 nsRefPtr
<nsNPAPIPluginInstance
> instance
= new nsNPAPIPluginInstance();
961 // This will create the owning reference. The connection must be made between the
962 // instance and the instance owner before initialization. Plugins can call into
963 // the browser during initialization.
964 aOwner
->SetInstance(instance
.get());
966 // Add the instance to the instances list before we call NPP_New so that
967 // it is "in play" before NPP_New happens. Take it out if NPP_New fails.
968 mInstances
.AppendElement(instance
.get());
970 // this should not addref the instance or owner
971 // except in some cases not Java, see bug 140931
972 // our COM pointer will free the peer
973 nsresult rv
= instance
->Initialize(plugin
.get(), aOwner
, aMimeType
);
975 mInstances
.RemoveElement(instance
.get());
976 aOwner
->SetInstance(nullptr);
980 // Cancel the plugin unload timer since we are creating
981 // an instance for it.
982 if (pluginTag
->mUnloadTimer
) {
983 pluginTag
->mUnloadTimer
->Cancel();
986 #ifdef PLUGIN_LOGGING
987 nsAutoCString urlSpec2
;
989 aURL
->GetSpec(urlSpec2
);
991 PR_LOG(nsPluginLogging::gPluginLog
, PLUGIN_LOG_BASIC
,
992 ("nsPluginHost::TrySetupPluginInstance Finished mime=%s, rv=%d, owner=%p, url=%s\n",
993 aMimeType
, rv
, aOwner
, urlSpec2
.get()));
1002 nsPluginHost::PluginExistsForType(const char* aMimeType
)
1004 nsPluginTag
*plugin
= FindPluginForType(aMimeType
, false);
1005 return nullptr != plugin
;
1009 nsPluginHost::GetPluginTagForType(const nsACString
& aMimeType
,
1010 nsIPluginTag
** aResult
)
1012 nsPluginTag
* plugin
= FindPluginForType(aMimeType
.Data(), true);
1014 plugin
= FindPluginForType(aMimeType
.Data(), false);
1017 return NS_ERROR_NOT_AVAILABLE
;
1019 NS_ADDREF(*aResult
= plugin
);
1024 nsPluginHost::GetStateForType(const nsACString
&aMimeType
, uint32_t* aResult
)
1026 nsPluginTag
*plugin
= FindPluginForType(aMimeType
.Data(), true);
1028 plugin
= FindPluginForType(aMimeType
.Data(), false);
1031 return NS_ERROR_UNEXPECTED
;
1034 return plugin
->GetEnabledState(aResult
);
1038 nsPluginHost::GetBlocklistStateForType(const char *aMimeType
, uint32_t *aState
)
1040 nsPluginTag
*plugin
= FindPluginForType(aMimeType
, true);
1042 plugin
= FindPluginForType(aMimeType
, false);
1045 return NS_ERROR_FAILURE
;
1048 *aState
= plugin
->GetBlocklistState();
1053 nsPluginHost::GetPermissionStringForType(const nsACString
&aMimeType
, nsACString
&aPermissionString
)
1055 aPermissionString
.Truncate();
1056 uint32_t blocklistState
;
1057 nsresult rv
= GetBlocklistStateForType(aMimeType
.Data(), &blocklistState
);
1058 NS_ENSURE_SUCCESS(rv
, rv
);
1059 nsPluginTag
*tag
= FindPluginForType(aMimeType
.Data(), true);
1061 tag
= FindPluginForType(aMimeType
.Data(), false);
1064 return NS_ERROR_FAILURE
;
1067 if (blocklistState
== nsIBlocklistService::STATE_VULNERABLE_UPDATE_AVAILABLE
||
1068 blocklistState
== nsIBlocklistService::STATE_VULNERABLE_NO_UPDATE
) {
1069 aPermissionString
.AssignLiteral("plugin-vulnerable:");
1072 aPermissionString
.AssignLiteral("plugin:");
1075 aPermissionString
.Append(tag
->GetNiceFileName());
1080 // check comma delimitered extensions
1081 static int CompareExtensions(const char *aExtensionList
, const char *aExtension
)
1083 if (!aExtensionList
|| !aExtension
)
1086 const char *pExt
= aExtensionList
;
1087 const char *pComma
= strchr(pExt
, ',');
1089 return PL_strcasecmp(pExt
, aExtension
);
1091 int extlen
= strlen(aExtension
);
1093 int length
= pComma
- pExt
;
1094 if (length
== extlen
&& 0 == PL_strncasecmp(aExtension
, pExt
, length
))
1098 pComma
= strchr(pExt
, ',');
1102 return PL_strcasecmp(pExt
, aExtension
);
1106 nsPluginHost::IsPluginEnabledForExtension(const char* aExtension
,
1107 const char* &aMimeType
)
1109 nsPluginTag
*plugin
= FindPluginEnabledForExtension(aExtension
, aMimeType
);
1113 return NS_ERROR_FAILURE
;
1117 nsPluginHost::GetPlugins(nsTArray
<nsRefPtr
<nsPluginTag
> >& aPluginArray
)
1119 aPluginArray
.Clear();
1123 nsPluginTag
* plugin
= mPlugins
;
1124 while (plugin
!= nullptr) {
1125 if (plugin
->IsEnabled()) {
1126 aPluginArray
.AppendElement(plugin
);
1128 plugin
= plugin
->mNext
;
1133 nsPluginHost::GetPluginTags(uint32_t* aPluginCount
, nsIPluginTag
*** aResults
)
1138 nsRefPtr
<nsPluginTag
> plugin
= mPlugins
;
1139 while (plugin
!= nullptr) {
1141 plugin
= plugin
->mNext
;
1144 *aResults
= static_cast<nsIPluginTag
**>
1145 (nsMemory::Alloc(count
* sizeof(**aResults
)));
1147 return NS_ERROR_OUT_OF_MEMORY
;
1149 *aPluginCount
= count
;
1152 for (uint32_t i
= 0; i
< count
; i
++) {
1153 (*aResults
)[i
] = plugin
;
1154 NS_ADDREF((*aResults
)[i
]);
1155 plugin
= plugin
->mNext
;
1162 nsPluginHost::FindPreferredPlugin(const InfallibleTArray
<nsPluginTag
*>& matches
)
1164 // We prefer the plugin with the highest version number.
1165 /// XXX(johns): This seems to assume the only time multiple plugins will have
1166 /// the same MIME type is if they're multiple versions of the same
1167 /// plugin -- but since plugin filenames and pretty names can both
1168 /// update, it's probably less arbitrary than just going at it
1171 if (matches
.IsEmpty()) {
1175 nsPluginTag
*preferredPlugin
= matches
[0];
1176 for (unsigned int i
= 1; i
< matches
.Length(); i
++) {
1177 if (mozilla::Version(matches
[i
]->mVersion
.get()) > preferredPlugin
->mVersion
.get()) {
1178 preferredPlugin
= matches
[i
];
1182 return preferredPlugin
;
1186 nsPluginHost::FindPluginForType(const char* aMimeType
,
1195 InfallibleTArray
<nsPluginTag
*> matchingPlugins
;
1197 nsPluginTag
*plugin
= mPlugins
;
1199 if (!aCheckEnabled
|| plugin
->IsActive()) {
1200 int32_t mimeCount
= plugin
->mMimeTypes
.Length();
1201 for (int32_t i
= 0; i
< mimeCount
; i
++) {
1202 if (0 == PL_strcasecmp(plugin
->mMimeTypes
[i
].get(), aMimeType
)) {
1203 matchingPlugins
.AppendElement(plugin
);
1208 plugin
= plugin
->mNext
;
1211 return FindPreferredPlugin(matchingPlugins
);
1215 nsPluginHost::FindPluginEnabledForExtension(const char* aExtension
,
1216 const char*& aMimeType
)
1224 InfallibleTArray
<nsPluginTag
*> matchingPlugins
;
1226 nsPluginTag
*plugin
= mPlugins
;
1228 if (plugin
->IsActive()) {
1229 int32_t variants
= plugin
->mExtensions
.Length();
1230 for (int32_t i
= 0; i
< variants
; i
++) {
1231 // mExtensionsArray[cnt] is a list of extensions separated by commas
1232 if (0 == CompareExtensions(plugin
->mExtensions
[i
].get(), aExtension
)) {
1233 matchingPlugins
.AppendElement(plugin
);
1238 plugin
= plugin
->mNext
;
1241 nsPluginTag
*preferredPlugin
= FindPreferredPlugin(matchingPlugins
);
1242 if (!preferredPlugin
) {
1246 int32_t variants
= preferredPlugin
->mExtensions
.Length();
1247 for (int32_t i
= 0; i
< variants
; i
++) {
1248 // mExtensionsArray[cnt] is a list of extensions separated by commas
1249 if (0 == CompareExtensions(preferredPlugin
->mExtensions
[i
].get(), aExtension
)) {
1250 aMimeType
= preferredPlugin
->mMimeTypes
[i
].get();
1255 return preferredPlugin
;
1258 static nsresult
CreateNPAPIPlugin(nsPluginTag
*aPluginTag
,
1259 nsNPAPIPlugin
**aOutNPAPIPlugin
)
1261 // If this is an in-process plugin we'll need to load it here if we haven't already.
1262 if (!nsNPAPIPlugin::RunPluginOOP(aPluginTag
)) {
1263 if (aPluginTag
->mFullPath
.IsEmpty())
1264 return NS_ERROR_FAILURE
;
1265 nsCOMPtr
<nsIFile
> file
= do_CreateInstance("@mozilla.org/file/local;1");
1266 file
->InitWithPath(NS_ConvertUTF8toUTF16(aPluginTag
->mFullPath
));
1267 nsPluginFile
pluginFile(file
);
1268 PRLibrary
* pluginLibrary
= nullptr;
1270 if (NS_FAILED(pluginFile
.LoadPlugin(&pluginLibrary
)) || !pluginLibrary
)
1271 return NS_ERROR_FAILURE
;
1273 aPluginTag
->mLibrary
= pluginLibrary
;
1277 rv
= nsNPAPIPlugin::CreatePlugin(aPluginTag
, aOutNPAPIPlugin
);
1282 nsresult
nsPluginHost::EnsurePluginLoaded(nsPluginTag
* aPluginTag
)
1284 nsRefPtr
<nsNPAPIPlugin
> plugin
= aPluginTag
->mPlugin
;
1286 nsresult rv
= CreateNPAPIPlugin(aPluginTag
, getter_AddRefs(plugin
));
1287 if (NS_FAILED(rv
)) {
1290 aPluginTag
->mPlugin
= plugin
;
1296 nsPluginHost::GetPluginForContentProcess(uint32_t aPluginId
, nsNPAPIPlugin
** aPlugin
)
1298 MOZ_ASSERT(XRE_GetProcessType() == GeckoProcessType_Default
);
1300 // If plugins haven't been scanned yet, do so now
1303 nsPluginTag
* pluginTag
= PluginWithId(aPluginId
);
1305 nsresult rv
= EnsurePluginLoaded(pluginTag
);
1306 if (NS_FAILED(rv
)) {
1310 // We only get here if a content process doesn't have a PluginModuleParent
1311 // for the given plugin already. Therefore, this counter is counting the
1312 // number of outstanding PluginModuleParents for the plugin, excluding the
1313 // one from the chrome process.
1314 pluginTag
->mContentProcessRunningCount
++;
1315 NS_ADDREF(*aPlugin
= pluginTag
->mPlugin
);
1319 return NS_ERROR_FAILURE
;
1322 class nsPluginUnloadRunnable
: public nsRunnable
1325 explicit nsPluginUnloadRunnable(uint32_t aPluginId
) : mPluginId(aPluginId
) {}
1329 nsRefPtr
<nsPluginHost
> host
= nsPluginHost::GetInst();
1333 nsPluginTag
* pluginTag
= host
->PluginWithId(mPluginId
);
1338 MOZ_ASSERT(pluginTag
->mContentProcessRunningCount
> 0);
1339 pluginTag
->mContentProcessRunningCount
--;
1341 if (!pluginTag
->mContentProcessRunningCount
) {
1342 if (!host
->IsRunningPlugin(pluginTag
)) {
1343 pluginTag
->TryUnloadPlugin(false);
1354 nsPluginHost::NotifyContentModuleDestroyed(uint32_t aPluginId
)
1356 MOZ_ASSERT(XRE_GetProcessType() == GeckoProcessType_Default
);
1358 // This is called in response to a message from the plugin. Don't unload the
1359 // plugin until the message handler is off the stack.
1360 nsRefPtr
<nsPluginUnloadRunnable
> runnable
=
1361 new nsPluginUnloadRunnable(aPluginId
);
1362 NS_DispatchToMainThread(runnable
);
1365 nsresult
nsPluginHost::GetPlugin(const char *aMimeType
, nsNPAPIPlugin
** aPlugin
)
1367 nsresult rv
= NS_ERROR_FAILURE
;
1371 return NS_ERROR_ILLEGAL_VALUE
;
1373 // If plugins haven't been scanned yet, do so now
1376 nsPluginTag
* pluginTag
= FindPluginForType(aMimeType
, true);
1379 PLUGIN_LOG(PLUGIN_LOG_BASIC
,
1380 ("nsPluginHost::GetPlugin Begin mime=%s, plugin=%s\n",
1381 aMimeType
, pluginTag
->mFileName
.get()));
1384 if (aMimeType
&& !pluginTag
->mFileName
.IsEmpty())
1385 printf("For %s found plugin %s\n", aMimeType
, pluginTag
->mFileName
.get());
1388 rv
= EnsurePluginLoaded(pluginTag
);
1389 if (NS_FAILED(rv
)) {
1393 NS_ADDREF(*aPlugin
= pluginTag
->mPlugin
);
1397 PLUGIN_LOG(PLUGIN_LOG_NORMAL
,
1398 ("nsPluginHost::GetPlugin End mime=%s, rv=%d, plugin=%p name=%s\n",
1399 aMimeType
, rv
, *aPlugin
,
1400 (pluginTag
? pluginTag
->mFileName
.get() : "(not found)")));
1405 // Normalize 'host' to ACE.
1407 nsPluginHost::NormalizeHostname(nsCString
& host
)
1409 if (IsASCII(host
)) {
1416 mIDNService
= do_GetService(NS_IDNSERVICE_CONTRACTID
, &rv
);
1417 NS_ENSURE_SUCCESS(rv
, rv
);
1420 return mIDNService
->ConvertUTF8toACE(host
, host
);
1423 // Enumerate a 'sites' array returned by GetSitesWithData and determine if
1424 // any of them have a base domain in common with 'domain'; if so, append them
1425 // to the 'result' array. If 'firstMatchOnly' is true, return after finding the
1428 nsPluginHost::EnumerateSiteData(const nsACString
& domain
,
1429 const InfallibleTArray
<nsCString
>& sites
,
1430 InfallibleTArray
<nsCString
>& result
,
1431 bool firstMatchOnly
)
1433 NS_ASSERTION(!domain
.IsVoid(), "null domain string");
1437 mTLDService
= do_GetService(NS_EFFECTIVETLDSERVICE_CONTRACTID
, &rv
);
1438 NS_ENSURE_SUCCESS(rv
, rv
);
1441 // Get the base domain from the domain.
1442 nsCString baseDomain
;
1443 rv
= mTLDService
->GetBaseDomainFromHost(domain
, 0, baseDomain
);
1444 bool isIP
= rv
== NS_ERROR_HOST_IS_IP_ADDRESS
;
1445 if (isIP
|| rv
== NS_ERROR_INSUFFICIENT_DOMAIN_LEVELS
) {
1446 // The base domain is the site itself. However, we must be careful to
1448 baseDomain
= domain
;
1449 rv
= NormalizeHostname(baseDomain
);
1450 NS_ENSURE_SUCCESS(rv
, rv
);
1451 } else if (NS_FAILED(rv
)) {
1455 // Enumerate the array of sites with data.
1456 for (uint32_t i
= 0; i
< sites
.Length(); ++i
) {
1457 const nsCString
& site
= sites
[i
];
1459 // Check if the site is an IP address.
1461 site
.Length() >= 2 && site
.First() == '[' && site
.Last() == ']';
1462 if (siteIsIP
!= isIP
)
1465 nsCString siteBaseDomain
;
1468 siteBaseDomain
= Substring(site
, 1, site
.Length() - 2);
1470 // Determine the base domain of the site.
1471 rv
= mTLDService
->GetBaseDomainFromHost(site
, 0, siteBaseDomain
);
1472 if (rv
== NS_ERROR_INSUFFICIENT_DOMAIN_LEVELS
) {
1473 // The base domain is the site itself. However, we must be careful to
1475 siteBaseDomain
= site
;
1476 rv
= NormalizeHostname(siteBaseDomain
);
1477 NS_ENSURE_SUCCESS(rv
, rv
);
1478 } else if (NS_FAILED(rv
)) {
1483 // At this point, we can do an exact comparison of the two domains.
1484 if (baseDomain
!= siteBaseDomain
) {
1488 // Append the site to the result array.
1489 result
.AppendElement(site
);
1491 // If we're supposed to return early, do so.
1492 if (firstMatchOnly
) {
1501 nsPluginHost::RegisterPlayPreviewMimeType(const nsACString
& mimeType
,
1503 const nsACString
& redirectURL
)
1505 nsAutoCString
mt(mimeType
);
1506 nsAutoCString
url(redirectURL
);
1507 if (url
.Length() == 0) {
1508 // using default play preview iframe URL, if redirectURL is not specified
1509 url
.AssignLiteral("data:application/x-moz-playpreview;,");
1510 url
.Append(mimeType
);
1513 nsRefPtr
<nsPluginPlayPreviewInfo
> playPreview
=
1514 new nsPluginPlayPreviewInfo(mt
.get(), ignoreCTP
, url
.get());
1515 mPlayPreviewMimeTypes
.AppendElement(playPreview
);
1520 nsPluginHost::UnregisterPlayPreviewMimeType(const nsACString
& mimeType
)
1522 nsAutoCString
mimeTypeToRemove(mimeType
);
1523 for (uint32_t i
= mPlayPreviewMimeTypes
.Length(); i
> 0; i
--) {
1524 nsRefPtr
<nsPluginPlayPreviewInfo
> pp
= mPlayPreviewMimeTypes
[i
- 1];
1525 if (PL_strcasecmp(pp
.get()->mMimeType
.get(), mimeTypeToRemove
.get()) == 0) {
1526 mPlayPreviewMimeTypes
.RemoveElementAt(i
- 1);
1534 nsPluginHost::GetPlayPreviewInfo(const nsACString
& mimeType
,
1535 nsIPluginPlayPreviewInfo
** aResult
)
1537 nsAutoCString
mimeTypeToFind(mimeType
);
1538 for (uint32_t i
= 0; i
< mPlayPreviewMimeTypes
.Length(); i
++) {
1539 nsRefPtr
<nsPluginPlayPreviewInfo
> pp
= mPlayPreviewMimeTypes
[i
];
1540 if (PL_strcasecmp(pp
.get()->mMimeType
.get(), mimeTypeToFind
.get()) == 0) {
1541 *aResult
= new nsPluginPlayPreviewInfo(pp
.get());
1542 NS_ADDREF(*aResult
);
1547 return NS_ERROR_NOT_AVAILABLE
;
1551 nsPluginHost::ClearSiteData(nsIPluginTag
* plugin
, const nsACString
& domain
,
1552 uint64_t flags
, int64_t maxAge
)
1554 // maxAge must be either a nonnegative integer or -1.
1555 NS_ENSURE_ARG(maxAge
>= 0 || maxAge
== -1);
1557 // Caller may give us a tag object that is no longer live.
1558 if (!IsLiveTag(plugin
)) {
1559 return NS_ERROR_NOT_AVAILABLE
;
1562 nsPluginTag
* tag
= static_cast<nsPluginTag
*>(plugin
);
1564 // We only ensure support for clearing Flash site data for now.
1565 // We will also attempt to clear data for any plugin that happens
1566 // to be loaded already.
1567 if (!tag
->mIsFlashPlugin
&& !tag
->mPlugin
) {
1568 return NS_ERROR_FAILURE
;
1571 // Make sure the plugin is loaded.
1572 nsresult rv
= EnsurePluginLoaded(tag
);
1573 if (NS_FAILED(rv
)) {
1577 PluginLibrary
* library
= tag
->mPlugin
->GetLibrary();
1579 // If 'domain' is the null string, clear everything.
1580 if (domain
.IsVoid()) {
1581 return library
->NPP_ClearSiteData(nullptr, flags
, maxAge
);
1584 // Get the list of sites from the plugin.
1585 InfallibleTArray
<nsCString
> sites
;
1586 rv
= library
->NPP_GetSitesWithData(sites
);
1587 NS_ENSURE_SUCCESS(rv
, rv
);
1589 // Enumerate the sites and build a list of matches.
1590 InfallibleTArray
<nsCString
> matches
;
1591 rv
= EnumerateSiteData(domain
, sites
, matches
, false);
1592 NS_ENSURE_SUCCESS(rv
, rv
);
1594 // Clear the matches.
1595 for (uint32_t i
= 0; i
< matches
.Length(); ++i
) {
1596 const nsCString
& match
= matches
[i
];
1597 rv
= library
->NPP_ClearSiteData(match
.get(), flags
, maxAge
);
1598 NS_ENSURE_SUCCESS(rv
, rv
);
1605 nsPluginHost::SiteHasData(nsIPluginTag
* plugin
, const nsACString
& domain
,
1608 // Caller may give us a tag object that is no longer live.
1609 if (!IsLiveTag(plugin
)) {
1610 return NS_ERROR_NOT_AVAILABLE
;
1613 nsPluginTag
* tag
= static_cast<nsPluginTag
*>(plugin
);
1615 // We only ensure support for clearing Flash site data for now.
1616 // We will also attempt to clear data for any plugin that happens
1617 // to be loaded already.
1618 if (!tag
->mIsFlashPlugin
&& !tag
->mPlugin
) {
1619 return NS_ERROR_FAILURE
;
1622 // Make sure the plugin is loaded.
1623 nsresult rv
= EnsurePluginLoaded(tag
);
1624 if (NS_FAILED(rv
)) {
1628 PluginLibrary
* library
= tag
->mPlugin
->GetLibrary();
1630 // Get the list of sites from the plugin.
1631 InfallibleTArray
<nsCString
> sites
;
1632 rv
= library
->NPP_GetSitesWithData(sites
);
1633 NS_ENSURE_SUCCESS(rv
, rv
);
1635 // If there's no data, we're done.
1636 if (sites
.IsEmpty()) {
1641 // If 'domain' is the null string, and there's data for at least one site,
1643 if (domain
.IsVoid()) {
1648 // Enumerate the sites and determine if there's a match.
1649 InfallibleTArray
<nsCString
> matches
;
1650 rv
= EnumerateSiteData(domain
, sites
, matches
, true);
1651 NS_ENSURE_SUCCESS(rv
, rv
);
1653 *result
= !matches
.IsEmpty();
1657 bool nsPluginHost::IsJavaMIMEType(const char* aType
)
1659 // The java mime pref may well not be one of these,
1660 // e.g. application/x-java-test used in the test suite
1661 nsAdoptingCString javaMIME
= Preferences::GetCString(kPrefJavaMIME
);
1663 (javaMIME
.EqualsIgnoreCase(aType
) ||
1664 (0 == PL_strncasecmp(aType
, "application/x-java-vm",
1665 sizeof("application/x-java-vm") - 1)) ||
1666 (0 == PL_strncasecmp(aType
, "application/x-java-applet",
1667 sizeof("application/x-java-applet") - 1)) ||
1668 (0 == PL_strncasecmp(aType
, "application/x-java-bean",
1669 sizeof("application/x-java-bean") - 1)));
1672 // Check whether or not a tag is a live, valid tag, and that it's loaded.
1674 nsPluginHost::IsLiveTag(nsIPluginTag
* aPluginTag
)
1677 for (tag
= mPlugins
; tag
; tag
= tag
->mNext
) {
1678 if (tag
== aPluginTag
) {
1686 nsPluginHost::HaveSamePlugin(const nsPluginTag
* aPluginTag
)
1688 for (nsPluginTag
* tag
= mPlugins
; tag
; tag
= tag
->mNext
) {
1689 if (tag
->HasSameNameAndMimes(aPluginTag
)) {
1697 nsPluginHost::FirstPluginWithPath(const nsCString
& path
)
1699 for (nsPluginTag
* tag
= mPlugins
; tag
; tag
= tag
->mNext
) {
1700 if (tag
->mFullPath
.Equals(path
)) {
1708 nsPluginHost::PluginWithId(uint32_t aId
)
1710 for (nsPluginTag
* tag
= mPlugins
; tag
; tag
= tag
->mNext
) {
1711 if (tag
->mId
== aId
) {
1720 int64_t GetPluginLastModifiedTime(const nsCOMPtr
<nsIFile
>& localfile
)
1722 PRTime fileModTime
= 0;
1724 #if defined(XP_MACOSX)
1725 // On OS X the date of a bundle's "contents" (i.e. of its Info.plist file)
1726 // is a much better guide to when it was last modified than the date of
1727 // its package directory. See bug 313700.
1728 nsCOMPtr
<nsILocalFileMac
> localFileMac
= do_QueryInterface(localfile
);
1730 localFileMac
->GetBundleContentsLastModifiedTime(&fileModTime
);
1732 localfile
->GetLastModifiedTime(&fileModTime
);
1735 localfile
->GetLastModifiedTime(&fileModTime
);
1742 GetPluginIsFromExtension(const nsCOMPtr
<nsIFile
>& pluginFile
,
1743 const nsCOMArray
<nsIFile
>& extensionDirs
)
1745 for (uint32_t i
= 0; i
< extensionDirs
.Length(); ++i
) {
1747 if (NS_FAILED(extensionDirs
[i
]->Contains(pluginFile
, &contains
)) || !contains
) {
1758 GetExtensionDirectories(nsCOMArray
<nsIFile
>& dirs
)
1760 nsCOMPtr
<nsIProperties
> dirService
= do_GetService(NS_DIRECTORY_SERVICE_CONTRACTID
);
1765 nsCOMPtr
<nsISimpleEnumerator
> list
;
1766 nsresult rv
= dirService
->Get(XRE_EXTENSIONS_DIR_LIST
,
1767 NS_GET_IID(nsISimpleEnumerator
),
1768 getter_AddRefs(list
));
1769 if (NS_FAILED(rv
)) {
1774 while (NS_SUCCEEDED(list
->HasMoreElements(&more
)) && more
) {
1775 nsCOMPtr
<nsISupports
> next
;
1776 if (NS_FAILED(list
->GetNext(getter_AddRefs(next
)))) {
1779 nsCOMPtr
<nsIFile
> file
= do_QueryInterface(next
);
1782 dirs
.AppendElement(file
);
1787 struct CompareFilesByTime
1790 LessThan(const nsCOMPtr
<nsIFile
>& a
, const nsCOMPtr
<nsIFile
>& b
) const
1792 return GetPluginLastModifiedTime(a
) < GetPluginLastModifiedTime(b
);
1796 Equals(const nsCOMPtr
<nsIFile
>& a
, const nsCOMPtr
<nsIFile
>& b
) const
1798 return GetPluginLastModifiedTime(a
) == GetPluginLastModifiedTime(b
);
1802 } // anonymous namespace
1805 nsPluginHost::AddPluginTag(nsPluginTag
* aPluginTag
)
1807 aPluginTag
->mNext
= mPlugins
;
1808 mPlugins
= aPluginTag
;
1810 if (aPluginTag
->IsActive()) {
1811 nsAdoptingCString disableFullPage
=
1812 Preferences::GetCString(kPrefDisableFullPage
);
1813 for (uint32_t i
= 0; i
< aPluginTag
->mMimeTypes
.Length(); i
++) {
1814 if (!IsTypeInList(aPluginTag
->mMimeTypes
[i
], disableFullPage
)) {
1815 RegisterWithCategoryManager(aPluginTag
->mMimeTypes
[i
],
1822 typedef NS_NPAPIPLUGIN_CALLBACK(char *, NP_GETMIMEDESCRIPTION
)(void);
1824 nsresult
nsPluginHost::ScanPluginsDirectory(nsIFile
*pluginsDir
,
1825 bool aCreatePluginList
,
1826 bool *aPluginsChanged
)
1828 MOZ_ASSERT(XRE_GetProcessType() == GeckoProcessType_Default
);
1830 NS_ENSURE_ARG_POINTER(aPluginsChanged
);
1833 *aPluginsChanged
= false;
1835 #ifdef PLUGIN_LOGGING
1836 nsAutoCString dirPath
;
1837 pluginsDir
->GetNativePath(dirPath
);
1838 PLUGIN_LOG(PLUGIN_LOG_BASIC
,
1839 ("nsPluginHost::ScanPluginsDirectory dir=%s\n", dirPath
.get()));
1842 nsCOMPtr
<nsISimpleEnumerator
> iter
;
1843 rv
= pluginsDir
->GetDirectoryEntries(getter_AddRefs(iter
));
1847 nsAutoTArray
<nsCOMPtr
<nsIFile
>, 6> pluginFiles
;
1850 while (NS_SUCCEEDED(iter
->HasMoreElements(&hasMore
)) && hasMore
) {
1851 nsCOMPtr
<nsISupports
> supports
;
1852 rv
= iter
->GetNext(getter_AddRefs(supports
));
1855 nsCOMPtr
<nsIFile
> dirEntry(do_QueryInterface(supports
, &rv
));
1859 // Sun's JRE 1.3.1 plugin must have symbolic links resolved or else it'll crash.
1861 dirEntry
->Normalize();
1863 if (nsPluginsDir::IsPluginFile(dirEntry
)) {
1864 pluginFiles
.AppendElement(dirEntry
);
1868 pluginFiles
.Sort(CompareFilesByTime());
1870 nsCOMArray
<nsIFile
> extensionDirs
;
1871 GetExtensionDirectories(extensionDirs
);
1873 bool warnOutdated
= false;
1875 for (int32_t i
= (pluginFiles
.Length() - 1); i
>= 0; i
--) {
1876 nsCOMPtr
<nsIFile
>& localfile
= pluginFiles
[i
];
1878 nsString utf16FilePath
;
1879 rv
= localfile
->GetPath(utf16FilePath
);
1883 const int64_t fileModTime
= GetPluginLastModifiedTime(localfile
);
1884 const bool fromExtension
= GetPluginIsFromExtension(localfile
, extensionDirs
);
1886 // Look for it in our cache
1887 NS_ConvertUTF16toUTF8
filePath(utf16FilePath
);
1888 nsRefPtr
<nsPluginTag
> pluginTag
;
1889 RemoveCachedPluginsInfo(filePath
.get(), getter_AddRefs(pluginTag
));
1891 bool seenBefore
= false;
1895 // If plugin changed, delete cachedPluginTag and don't use cache
1896 if (fileModTime
!= pluginTag
->mLastModifiedTime
) {
1897 // Plugins has changed. Don't use cached plugin info.
1898 pluginTag
= nullptr;
1900 // plugin file changed, flag this fact
1901 *aPluginsChanged
= true;
1904 // If we're not creating a list and we already know something changed then
1906 if (!aCreatePluginList
) {
1907 if (*aPluginsChanged
) {
1914 bool isKnownInvalidPlugin
= false;
1915 for (nsRefPtr
<nsInvalidPluginTag
> invalidPlugins
= mInvalidPlugins
;
1916 invalidPlugins
; invalidPlugins
= invalidPlugins
->mNext
) {
1917 // If already marked as invalid, ignore it
1918 if (invalidPlugins
->mFullPath
.Equals(filePath
.get()) &&
1919 invalidPlugins
->mLastModifiedTime
== fileModTime
) {
1920 if (aCreatePluginList
) {
1921 invalidPlugins
->mSeen
= true;
1923 isKnownInvalidPlugin
= true;
1927 if (isKnownInvalidPlugin
) {
1931 // if it is not found in cache info list or has been changed, create a new one
1933 nsPluginFile
pluginFile(localfile
);
1935 // create a tag describing this plugin.
1936 PRLibrary
*library
= nullptr;
1938 memset(&info
, 0, sizeof(info
));
1940 // Opening a block for the telemetry AutoTimer
1942 Telemetry::AutoTimer
<Telemetry::PLUGIN_LOAD_METADATA
> telemetry
;
1943 res
= pluginFile
.GetPluginInfo(info
, &library
);
1945 // if we don't have mime type don't proceed, this is not a plugin
1946 if (NS_FAILED(res
) || !info
.fMimeTypeArray
) {
1947 nsRefPtr
<nsInvalidPluginTag
> invalidTag
= new nsInvalidPluginTag(filePath
.get(),
1949 pluginFile
.FreePluginInfo(info
);
1951 if (aCreatePluginList
) {
1952 invalidTag
->mSeen
= true;
1954 invalidTag
->mNext
= mInvalidPlugins
;
1955 if (mInvalidPlugins
) {
1956 mInvalidPlugins
->mPrev
= invalidTag
;
1958 mInvalidPlugins
= invalidTag
;
1960 // Mark aPluginsChanged so pluginreg is rewritten
1961 *aPluginsChanged
= true;
1965 pluginTag
= new nsPluginTag(&info
, fileModTime
, fromExtension
);
1966 pluginFile
.FreePluginInfo(info
);
1968 return NS_ERROR_OUT_OF_MEMORY
;
1970 pluginTag
->mLibrary
= library
;
1971 uint32_t state
= pluginTag
->GetBlocklistState();
1973 // If the blocklist says it is risky and we have never seen this
1974 // plugin before, then disable it.
1975 // If the blocklist says this is an outdated plugin, warn about
1976 // outdated plugins.
1977 if (state
== nsIBlocklistService::STATE_SOFTBLOCKED
&& !seenBefore
) {
1978 pluginTag
->SetEnabledState(nsIPluginTag::STATE_DISABLED
);
1980 if (state
== nsIBlocklistService::STATE_OUTDATED
&& !seenBefore
) {
1981 warnOutdated
= true;
1984 // Plugin unloading is tag-based. If we created a new tag and loaded
1985 // the library in the process then we want to attempt to unload it here.
1986 // Only do this if the pref is set for aggressive unloading.
1987 if (UnloadPluginsASAP()) {
1988 pluginTag
->TryUnloadPlugin(false);
1992 // do it if we still want it
1994 // We have a valid new plugin so report that plugins have changed.
1995 *aPluginsChanged
= true;
1998 // Avoid adding different versions of the same plugin if they are running
1999 // in-process, otherwise we risk undefined behaviour.
2000 if (!nsNPAPIPlugin::RunPluginOOP(pluginTag
)) {
2001 if (HaveSamePlugin(pluginTag
)) {
2006 // Don't add the same plugin again if it hasn't changed
2007 if (nsPluginTag
* duplicate
= FirstPluginWithPath(pluginTag
->mFullPath
)) {
2008 if (pluginTag
->mLastModifiedTime
== duplicate
->mLastModifiedTime
) {
2013 // If we're not creating a plugin list, simply looking for changes,
2015 if (!aCreatePluginList
) {
2019 AddPluginTag(pluginTag
);
2023 Preferences::SetBool("plugins.update.notifyUser", true);
2029 nsresult
nsPluginHost::ScanPluginsDirectoryList(nsISimpleEnumerator
*dirEnum
,
2030 bool aCreatePluginList
,
2031 bool *aPluginsChanged
)
2033 MOZ_ASSERT(XRE_GetProcessType() == GeckoProcessType_Default
);
2036 while (NS_SUCCEEDED(dirEnum
->HasMoreElements(&hasMore
)) && hasMore
) {
2037 nsCOMPtr
<nsISupports
> supports
;
2038 nsresult rv
= dirEnum
->GetNext(getter_AddRefs(supports
));
2041 nsCOMPtr
<nsIFile
> nextDir(do_QueryInterface(supports
, &rv
));
2045 // don't pass aPluginsChanged directly to prevent it from been reset
2046 bool pluginschanged
= false;
2047 ScanPluginsDirectory(nextDir
, aCreatePluginList
, &pluginschanged
);
2050 *aPluginsChanged
= true;
2052 // if changes are detected and we are not creating the list, do not proceed
2053 if (!aCreatePluginList
&& *aPluginsChanged
)
2060 nsPluginHost::IncrementChromeEpoch()
2062 MOZ_ASSERT(XRE_GetProcessType() == GeckoProcessType_Default
);
2067 nsPluginHost::ChromeEpoch()
2069 MOZ_ASSERT(XRE_GetProcessType() == GeckoProcessType_Default
);
2070 return mPluginEpoch
;
2074 nsPluginHost::ChromeEpochForContent()
2076 MOZ_ASSERT(XRE_GetProcessType() == GeckoProcessType_Content
);
2077 return mPluginEpoch
;
2081 nsPluginHost::SetChromeEpochForContent(uint32_t aEpoch
)
2083 MOZ_ASSERT(XRE_GetProcessType() == GeckoProcessType_Content
);
2084 mPluginEpoch
= aEpoch
;
2087 nsresult
nsPluginHost::LoadPlugins()
2090 if (XRE_GetProcessType() == GeckoProcessType_Content
) {
2094 // do not do anything if it is already done
2095 // use ReloadPlugins() to enforce loading
2099 if (mPluginsDisabled
)
2102 bool pluginschanged
;
2103 nsresult rv
= FindPlugins(true, &pluginschanged
);
2107 // only if plugins have changed will we notify plugin-change observers
2108 if (pluginschanged
) {
2109 if (XRE_GetProcessType() == GeckoProcessType_Default
) {
2110 IncrementChromeEpoch();
2113 nsCOMPtr
<nsIObserverService
> obsService
=
2114 mozilla::services::GetObserverService();
2116 obsService
->NotifyObservers(nullptr, "plugins-list-updated", nullptr);
2123 nsPluginHost::FindPluginsInContent(bool aCreatePluginList
, bool* aPluginsChanged
)
2125 MOZ_ASSERT(XRE_GetProcessType() == GeckoProcessType_Content
);
2127 dom::ContentChild
* cp
= dom::ContentChild::GetSingleton();
2128 nsTArray
<PluginTag
> plugins
;
2129 uint32_t parentEpoch
;
2130 if (!cp
->SendFindPlugins(ChromeEpochForContent(), &plugins
, &parentEpoch
)) {
2131 return NS_ERROR_NOT_AVAILABLE
;
2134 if (parentEpoch
!= ChromeEpochForContent()) {
2135 SetChromeEpochForContent(parentEpoch
);
2136 *aPluginsChanged
= true;
2137 if (!aCreatePluginList
) {
2141 for (size_t i
= 0; i
< plugins
.Length(); i
++) {
2142 PluginTag
& tag
= plugins
[i
];
2144 // Don't add the same plugin again.
2145 if (PluginWithId(tag
.id())) {
2149 nsPluginTag
*pluginTag
= new nsPluginTag(tag
.id(),
2151 tag
.description().get(),
2152 tag
.filename().get(),
2154 tag
.version().get(),
2155 nsTArray
<nsCString
>(tag
.mimeTypes()),
2156 nsTArray
<nsCString
>(tag
.mimeDescriptions()),
2157 nsTArray
<nsCString
>(tag
.extensions()),
2159 tag
.isFlashPlugin(),
2160 tag
.lastModifiedTime(),
2161 tag
.isFromExtension());
2162 AddPluginTag(pluginTag
);
2166 mPluginsLoaded
= true;
2170 // if aCreatePluginList is false we will just scan for plugins
2171 // and see if any changes have been made to the plugins.
2172 // This is needed in ReloadPlugins to prevent possible recursive reloads
2173 nsresult
nsPluginHost::FindPlugins(bool aCreatePluginList
, bool * aPluginsChanged
)
2175 Telemetry::AutoTimer
<Telemetry::FIND_PLUGINS
> telemetry
;
2177 NS_ENSURE_ARG_POINTER(aPluginsChanged
);
2179 *aPluginsChanged
= false;
2181 if (XRE_GetProcessType() == GeckoProcessType_Content
) {
2182 return FindPluginsInContent(aCreatePluginList
, aPluginsChanged
);
2187 // Read cached plugins info. If the profile isn't yet available then don't
2189 if (ReadPluginInfo() == NS_ERROR_NOT_AVAILABLE
)
2193 // Failure here is not a show-stopper so just warn.
2194 rv
= EnsurePrivateDirServiceProvider();
2195 NS_ASSERTION(NS_SUCCEEDED(rv
), "Failed to register dir service provider.");
2198 nsCOMPtr
<nsIProperties
> dirService(do_GetService(kDirectoryServiceContractID
, &rv
));
2202 nsCOMPtr
<nsISimpleEnumerator
> dirList
;
2204 // Scan plugins directories;
2205 // don't pass aPluginsChanged directly, to prevent its
2206 // possible reset in subsequent ScanPluginsDirectory calls
2207 bool pluginschanged
= false;
2209 // Scan the app-defined list of plugin dirs.
2210 rv
= dirService
->Get(NS_APP_PLUGINS_DIR_LIST
, NS_GET_IID(nsISimpleEnumerator
), getter_AddRefs(dirList
));
2211 if (NS_SUCCEEDED(rv
)) {
2212 ScanPluginsDirectoryList(dirList
, aCreatePluginList
, &pluginschanged
);
2215 *aPluginsChanged
= true;
2217 // if we are just looking for possible changes,
2218 // no need to proceed if changes are detected
2219 if (!aCreatePluginList
&& *aPluginsChanged
) {
2220 NS_ITERATIVE_UNREF_LIST(nsRefPtr
<nsPluginTag
>, mCachedPlugins
, mNext
);
2221 NS_ITERATIVE_UNREF_LIST(nsRefPtr
<nsInvalidPluginTag
>, mInvalidPlugins
, mNext
);
2226 LOG("getting plugins dir failed");
2230 mPluginsLoaded
= true; // at this point 'some' plugins have been loaded,
2231 // the rest is optional
2234 bool bScanPLIDs
= Preferences::GetBool("plugin.scan.plid.all", false);
2236 // Now lets scan any PLID directories
2237 if (bScanPLIDs
&& mPrivateDirServiceProvider
) {
2238 rv
= mPrivateDirServiceProvider
->GetPLIDDirectories(getter_AddRefs(dirList
));
2239 if (NS_SUCCEEDED(rv
)) {
2240 ScanPluginsDirectoryList(dirList
, aCreatePluginList
, &pluginschanged
);
2243 *aPluginsChanged
= true;
2245 // if we are just looking for possible changes,
2246 // no need to proceed if changes are detected
2247 if (!aCreatePluginList
&& *aPluginsChanged
) {
2248 NS_ITERATIVE_UNREF_LIST(nsRefPtr
<nsPluginTag
>, mCachedPlugins
, mNext
);
2249 NS_ITERATIVE_UNREF_LIST(nsRefPtr
<nsInvalidPluginTag
>, mInvalidPlugins
, mNext
);
2256 // Scan the installation paths of our popular plugins if the prefs are enabled
2258 // This table controls the order of scanning
2259 const char* const prefs
[] = {NS_WIN_ACROBAT_SCAN_KEY
,
2260 NS_WIN_QUICKTIME_SCAN_KEY
,
2261 NS_WIN_WMP_SCAN_KEY
};
2263 uint32_t size
= sizeof(prefs
) / sizeof(prefs
[0]);
2265 for (uint32_t i
= 0; i
< size
; i
+=1) {
2266 nsCOMPtr
<nsIFile
> dirToScan
;
2268 if (NS_SUCCEEDED(dirService
->Get(prefs
[i
], NS_GET_IID(nsIFile
), getter_AddRefs(dirToScan
))) &&
2270 NS_SUCCEEDED(dirToScan
->Exists(&bExists
)) &&
2273 ScanPluginsDirectory(dirToScan
, aCreatePluginList
, &pluginschanged
);
2276 *aPluginsChanged
= true;
2278 // if we are just looking for possible changes,
2279 // no need to proceed if changes are detected
2280 if (!aCreatePluginList
&& *aPluginsChanged
) {
2281 NS_ITERATIVE_UNREF_LIST(nsRefPtr
<nsPluginTag
>, mCachedPlugins
, mNext
);
2282 NS_ITERATIVE_UNREF_LIST(nsRefPtr
<nsInvalidPluginTag
>, mInvalidPlugins
, mNext
);
2289 // We should also consider plugins to have changed if any plugins have been removed.
2290 // We'll know if any were removed if they weren't taken out of the cached plugins list
2291 // during our scan, thus we can assume something was removed if the cached plugins list
2292 // contains anything.
2293 if (!*aPluginsChanged
&& mCachedPlugins
) {
2294 *aPluginsChanged
= true;
2297 // Remove unseen invalid plugins
2298 nsRefPtr
<nsInvalidPluginTag
> invalidPlugins
= mInvalidPlugins
;
2299 while (invalidPlugins
) {
2300 if (!invalidPlugins
->mSeen
) {
2301 nsRefPtr
<nsInvalidPluginTag
> invalidPlugin
= invalidPlugins
;
2303 if (invalidPlugin
->mPrev
) {
2304 invalidPlugin
->mPrev
->mNext
= invalidPlugin
->mNext
;
2307 mInvalidPlugins
= invalidPlugin
->mNext
;
2309 if (invalidPlugin
->mNext
) {
2310 invalidPlugin
->mNext
->mPrev
= invalidPlugin
->mPrev
;
2313 invalidPlugins
= invalidPlugin
->mNext
;
2315 invalidPlugin
->mPrev
= nullptr;
2316 invalidPlugin
->mNext
= nullptr;
2319 invalidPlugins
->mSeen
= false;
2320 invalidPlugins
= invalidPlugins
->mNext
;
2324 // if we are not creating the list, there is no need to proceed
2325 if (!aCreatePluginList
) {
2326 NS_ITERATIVE_UNREF_LIST(nsRefPtr
<nsPluginTag
>, mCachedPlugins
, mNext
);
2327 NS_ITERATIVE_UNREF_LIST(nsRefPtr
<nsInvalidPluginTag
>, mInvalidPlugins
, mNext
);
2331 // if we are creating the list, it is already done;
2332 // update the plugins info cache if changes are detected
2333 if (*aPluginsChanged
)
2336 // No more need for cached plugins. Clear it up.
2337 NS_ITERATIVE_UNREF_LIST(nsRefPtr
<nsPluginTag
>, mCachedPlugins
, mNext
);
2338 NS_ITERATIVE_UNREF_LIST(nsRefPtr
<nsInvalidPluginTag
>, mInvalidPlugins
, mNext
);
2344 mozilla::plugins::FindPluginsForContent(uint32_t aPluginEpoch
,
2345 nsTArray
<PluginTag
>* aPlugins
,
2346 uint32_t* aNewPluginEpoch
)
2348 MOZ_ASSERT(XRE_GetProcessType() == GeckoProcessType_Default
);
2350 nsRefPtr
<nsPluginHost
> host
= nsPluginHost::GetInst();
2351 host
->FindPluginsForContent(aPluginEpoch
, aPlugins
, aNewPluginEpoch
);
2356 nsPluginHost::FindPluginsForContent(uint32_t aPluginEpoch
,
2357 nsTArray
<PluginTag
>* aPlugins
,
2358 uint32_t* aNewPluginEpoch
)
2360 MOZ_ASSERT(XRE_GetProcessType() == GeckoProcessType_Default
);
2362 // Load plugins so that the epoch is correct.
2365 *aNewPluginEpoch
= ChromeEpoch();
2366 if (aPluginEpoch
== ChromeEpoch()) {
2370 nsTArray
<nsRefPtr
<nsPluginTag
>> plugins
;
2371 GetPlugins(plugins
);
2373 for (size_t i
= 0; i
< plugins
.Length(); i
++) {
2374 nsRefPtr
<nsPluginTag
> tag
= plugins
[i
];
2376 if (!nsNPAPIPlugin::RunPluginOOP(tag
)) {
2377 // Don't expose non-OOP plugins to content processes since we have no way
2378 // to bridge them over.
2382 aPlugins
->AppendElement(PluginTag(tag
->mId
,
2386 tag
->mMimeDescriptions
,
2389 tag
->mIsFlashPlugin
,
2392 tag
->mLastModifiedTime
,
2393 tag
->IsFromExtension()));
2398 nsPluginHost::UpdatePluginInfo(nsPluginTag
* aPluginTag
)
2400 MOZ_ASSERT(XRE_GetProcessType() == GeckoProcessType_Default
);
2404 NS_ITERATIVE_UNREF_LIST(nsRefPtr
<nsPluginTag
>, mCachedPlugins
, mNext
);
2405 NS_ITERATIVE_UNREF_LIST(nsRefPtr
<nsInvalidPluginTag
>, mInvalidPlugins
, mNext
);
2411 // Update types with category manager
2412 nsAdoptingCString disableFullPage
=
2413 Preferences::GetCString(kPrefDisableFullPage
);
2414 for (uint32_t i
= 0; i
< aPluginTag
->mMimeTypes
.Length(); i
++) {
2415 nsRegisterType shouldRegister
;
2417 if (IsTypeInList(aPluginTag
->mMimeTypes
[i
], disableFullPage
)) {
2418 shouldRegister
= ePluginUnregister
;
2420 nsPluginTag
*plugin
= FindPluginForType(aPluginTag
->mMimeTypes
[i
].get(),
2422 shouldRegister
= plugin
? ePluginRegister
: ePluginUnregister
;
2425 RegisterWithCategoryManager(aPluginTag
->mMimeTypes
[i
], shouldRegister
);
2428 nsCOMPtr
<nsIObserverService
> obsService
=
2429 mozilla::services::GetObserverService();
2431 obsService
->NotifyObservers(nullptr, "plugin-info-updated", nullptr);
2433 // Reload instances if needed
2434 if (aPluginTag
->IsActive()) {
2442 nsPluginHost::IsTypeWhitelisted(const char *aMimeType
)
2444 nsAdoptingCString whitelist
= Preferences::GetCString(kPrefWhitelist
);
2445 if (!whitelist
.Length()) {
2448 nsDependentCString
wrap(aMimeType
);
2449 return IsTypeInList(wrap
, whitelist
);
2453 nsPluginHost::RegisterWithCategoryManager(nsCString
&aMimeType
,
2454 nsRegisterType aType
)
2456 PLUGIN_LOG(PLUGIN_LOG_NORMAL
,
2457 ("nsPluginTag::RegisterWithCategoryManager type = %s, removing = %s\n",
2458 aMimeType
.get(), aType
== ePluginUnregister
? "yes" : "no"));
2460 nsCOMPtr
<nsICategoryManager
> catMan
=
2461 do_GetService(NS_CATEGORYMANAGER_CONTRACTID
);
2466 const char *contractId
=
2467 "@mozilla.org/content/plugin/document-loader-factory;1";
2469 if (aType
== ePluginRegister
) {
2470 catMan
->AddCategoryEntry("Gecko-Content-Viewers",
2473 false, /* persist: broken by bug 193031 */
2474 mOverrideInternalTypes
,
2477 // Only delete the entry if a plugin registered for it
2478 nsXPIDLCString value
;
2479 nsresult rv
= catMan
->GetCategoryEntry("Gecko-Content-Viewers",
2481 getter_Copies(value
));
2482 if (NS_SUCCEEDED(rv
) && strcmp(value
, contractId
) == 0) {
2483 catMan
->DeleteCategoryEntry("Gecko-Content-Viewers",
2491 nsPluginHost::WritePluginInfo()
2493 MOZ_ASSERT(XRE_GetProcessType() == GeckoProcessType_Default
);
2495 nsresult rv
= NS_OK
;
2496 nsCOMPtr
<nsIProperties
> directoryService(do_GetService(NS_DIRECTORY_SERVICE_CONTRACTID
,&rv
));
2500 directoryService
->Get(NS_APP_USER_PROFILE_50_DIR
, NS_GET_IID(nsIFile
),
2501 getter_AddRefs(mPluginRegFile
));
2503 if (!mPluginRegFile
)
2504 return NS_ERROR_FAILURE
;
2506 PRFileDesc
* fd
= nullptr;
2508 nsCOMPtr
<nsIFile
> pluginReg
;
2510 rv
= mPluginRegFile
->Clone(getter_AddRefs(pluginReg
));
2514 nsAutoCString
filename(kPluginRegistryFilename
);
2515 filename
.AppendLiteral(".tmp");
2516 rv
= pluginReg
->AppendNative(filename
);
2520 rv
= pluginReg
->OpenNSPRFileDesc(PR_WRONLY
| PR_CREATE_FILE
| PR_TRUNCATE
, 0600, &fd
);
2524 nsCOMPtr
<nsIXULRuntime
> runtime
= do_GetService("@mozilla.org/xre/runtime;1");
2526 return NS_ERROR_FAILURE
;
2530 rv
= runtime
->GetXPCOMABI(arch
);
2531 if (NS_FAILED(rv
)) {
2535 PR_fprintf(fd
, "Generated File. Do not edit.\n");
2537 PR_fprintf(fd
, "\n[HEADER]\nVersion%c%s%c%c\nArch%c%s%c%c\n",
2538 PLUGIN_REGISTRY_FIELD_DELIMITER
,
2539 kPluginRegistryVersion
,
2540 PLUGIN_REGISTRY_FIELD_DELIMITER
,
2541 PLUGIN_REGISTRY_END_OF_LINE_MARKER
,
2542 PLUGIN_REGISTRY_FIELD_DELIMITER
,
2544 PLUGIN_REGISTRY_FIELD_DELIMITER
,
2545 PLUGIN_REGISTRY_END_OF_LINE_MARKER
);
2547 // Store all plugins in the mPlugins list - all plugins currently in use.
2548 PR_fprintf(fd
, "\n[PLUGINS]\n");
2550 for (nsPluginTag
*tag
= mPlugins
; tag
; tag
= tag
->mNext
) {
2551 // store each plugin info into the registry
2552 // filename & fullpath are on separate line
2553 // because they can contain field delimiter char
2554 PR_fprintf(fd
, "%s%c%c\n%s%c%c\n%s%c%c\n",
2555 (tag
->mFileName
.get()),
2556 PLUGIN_REGISTRY_FIELD_DELIMITER
,
2557 PLUGIN_REGISTRY_END_OF_LINE_MARKER
,
2558 (tag
->mFullPath
.get()),
2559 PLUGIN_REGISTRY_FIELD_DELIMITER
,
2560 PLUGIN_REGISTRY_END_OF_LINE_MARKER
,
2561 (tag
->mVersion
.get()),
2562 PLUGIN_REGISTRY_FIELD_DELIMITER
,
2563 PLUGIN_REGISTRY_END_OF_LINE_MARKER
);
2565 // lastModifiedTimeStamp|canUnload|tag->mFlags|fromExtension
2566 PR_fprintf(fd
, "%lld%c%d%c%lu%c%d%c%c\n",
2567 tag
->mLastModifiedTime
,
2568 PLUGIN_REGISTRY_FIELD_DELIMITER
,
2569 false, // did store whether or not to unload in-process plugins
2570 PLUGIN_REGISTRY_FIELD_DELIMITER
,
2571 0, // legacy field for flags
2572 PLUGIN_REGISTRY_FIELD_DELIMITER
,
2573 tag
->IsFromExtension(),
2574 PLUGIN_REGISTRY_FIELD_DELIMITER
,
2575 PLUGIN_REGISTRY_END_OF_LINE_MARKER
);
2577 //description, name & mtypecount are on separate line
2578 PR_fprintf(fd
, "%s%c%c\n%s%c%c\n%d\n",
2579 (tag
->mDescription
.get()),
2580 PLUGIN_REGISTRY_FIELD_DELIMITER
,
2581 PLUGIN_REGISTRY_END_OF_LINE_MARKER
,
2583 PLUGIN_REGISTRY_FIELD_DELIMITER
,
2584 PLUGIN_REGISTRY_END_OF_LINE_MARKER
,
2585 tag
->mMimeTypes
.Length());
2587 // Add in each mimetype this plugin supports
2588 for (uint32_t i
= 0; i
< tag
->mMimeTypes
.Length(); i
++) {
2589 PR_fprintf(fd
, "%d%c%s%c%s%c%s%c%c\n",
2590 i
,PLUGIN_REGISTRY_FIELD_DELIMITER
,
2591 (tag
->mMimeTypes
[i
].get()),
2592 PLUGIN_REGISTRY_FIELD_DELIMITER
,
2593 (tag
->mMimeDescriptions
[i
].get()),
2594 PLUGIN_REGISTRY_FIELD_DELIMITER
,
2595 (tag
->mExtensions
[i
].get()),
2596 PLUGIN_REGISTRY_FIELD_DELIMITER
,
2597 PLUGIN_REGISTRY_END_OF_LINE_MARKER
);
2601 PR_fprintf(fd
, "\n[INVALID]\n");
2603 nsRefPtr
<nsInvalidPluginTag
> invalidPlugins
= mInvalidPlugins
;
2604 while (invalidPlugins
) {
2606 PR_fprintf(fd
, "%s%c%c\n",
2607 (!invalidPlugins
->mFullPath
.IsEmpty() ? invalidPlugins
->mFullPath
.get() : ""),
2608 PLUGIN_REGISTRY_FIELD_DELIMITER
,
2609 PLUGIN_REGISTRY_END_OF_LINE_MARKER
);
2611 // lastModifiedTimeStamp
2612 PR_fprintf(fd
, "%lld%c%c\n",
2613 invalidPlugins
->mLastModifiedTime
,
2614 PLUGIN_REGISTRY_FIELD_DELIMITER
,
2615 PLUGIN_REGISTRY_END_OF_LINE_MARKER
);
2617 invalidPlugins
= invalidPlugins
->mNext
;
2621 prrc
= PR_Close(fd
);
2622 if (prrc
!= PR_SUCCESS
) {
2623 // we should obtain a refined value based on prrc;
2624 rv
= NS_ERROR_FAILURE
;
2625 MOZ_ASSERT(false, "PR_Close() failed.");
2628 nsCOMPtr
<nsIFile
> parent
;
2629 rv
= pluginReg
->GetParent(getter_AddRefs(parent
));
2630 NS_ENSURE_SUCCESS(rv
, rv
);
2631 rv
= pluginReg
->MoveToNative(parent
, kPluginRegistryFilename
);
2636 nsPluginHost::ReadPluginInfo()
2638 MOZ_ASSERT(XRE_GetProcessType() == GeckoProcessType_Default
);
2640 const long PLUGIN_REG_MIMETYPES_ARRAY_SIZE
= 12;
2641 const long PLUGIN_REG_MAX_MIMETYPES
= 1000;
2643 // we need to import the legacy flags from the plugin registry once
2644 const bool pluginStateImported
=
2645 Preferences::GetDefaultBool("plugin.importedState", false);
2649 nsCOMPtr
<nsIProperties
> directoryService(do_GetService(NS_DIRECTORY_SERVICE_CONTRACTID
,&rv
));
2653 directoryService
->Get(NS_APP_USER_PROFILE_50_DIR
, NS_GET_IID(nsIFile
),
2654 getter_AddRefs(mPluginRegFile
));
2656 if (!mPluginRegFile
) {
2657 // There is no profile yet, this will tell us if there is going to be one
2659 directoryService
->Get(NS_APP_PROFILE_DIR_STARTUP
, NS_GET_IID(nsIFile
),
2660 getter_AddRefs(mPluginRegFile
));
2661 if (!mPluginRegFile
)
2662 return NS_ERROR_FAILURE
;
2664 return NS_ERROR_NOT_AVAILABLE
;
2667 PRFileDesc
* fd
= nullptr;
2669 nsCOMPtr
<nsIFile
> pluginReg
;
2671 rv
= mPluginRegFile
->Clone(getter_AddRefs(pluginReg
));
2675 rv
= pluginReg
->AppendNative(kPluginRegistryFilename
);
2680 rv
= pluginReg
->GetFileSize(&fileSize
);
2684 if (fileSize
> INT32_MAX
) {
2685 return NS_ERROR_FAILURE
;
2687 int32_t flen
= int32_t(fileSize
);
2689 NS_WARNING("Plugins Registry Empty!");
2690 return NS_OK
; // ERROR CONDITION
2693 nsPluginManifestLineReader reader
;
2694 char* registry
= reader
.Init(flen
);
2696 return NS_ERROR_OUT_OF_MEMORY
;
2698 rv
= pluginReg
->OpenNSPRFileDesc(PR_RDONLY
, 0444, &fd
);
2702 // set rv to return an error on goto out
2703 rv
= NS_ERROR_FAILURE
;
2705 int32_t bread
= PR_Read(fd
, registry
, flen
);
2708 prrc
= PR_Close(fd
);
2709 if (prrc
!= PR_SUCCESS
) {
2710 // Strange error: this is one of those "Should not happen" error.
2711 // we may want to report something more refined than NS_ERROR_FAILURE.
2712 MOZ_ASSERT(false, "PR_Close() failed.");
2719 if (!ReadSectionHeader(reader
, "HEADER"))
2722 if (!reader
.NextLine())
2727 // VersionLiteral, kPluginRegistryVersion
2728 if (2 != reader
.ParseLine(values
, 2))
2732 if (PL_strcmp(values
[0], "Version"))
2735 // kPluginRegistryVersion
2736 int32_t vdiff
= mozilla::CompareVersions(values
[1], kPluginRegistryVersion
);
2737 mozilla::Version
version(values
[1]);
2738 // If this is a registry from some future version then don't attempt to read it
2741 // If this is a registry from before the minimum then don't attempt to read it
2742 if (version
< kMinimumRegistryVersion
)
2745 // Registry v0.10 and upwards includes the plugin version field
2746 bool regHasVersion
= (version
>= "0.10");
2748 // Registry v0.13 and upwards includes the architecture
2749 if (version
>= "0.13") {
2750 char* archValues
[6];
2752 if (!reader
.NextLine()) {
2756 // ArchLiteral, Architecture
2757 if (2 != reader
.ParseLine(archValues
, 2)) {
2762 if (PL_strcmp(archValues
[0], "Arch")) {
2766 nsCOMPtr
<nsIXULRuntime
> runtime
= do_GetService("@mozilla.org/xre/runtime;1");
2772 if (NS_FAILED(runtime
->GetXPCOMABI(arch
))) {
2776 // If this is a registry from a different architecture then don't attempt to read it
2777 if (PL_strcmp(archValues
[1], arch
.get())) {
2782 // Registry v0.13 and upwards includes the list of invalid plugins
2783 const bool hasInvalidPlugins
= (version
>= "0.13");
2785 // Registry v0.16 and upwards always have 0 for their plugin flags, prefs are used instead
2786 const bool hasValidFlags
= (version
< "0.16");
2788 // Registry v0.17 and upwards store whether the plugin comes from an XPI.
2789 const bool hasFromExtension
= (version
>= "0.17");
2791 #if defined(XP_MACOSX)
2792 const bool hasFullPathInFileNameField
= false;
2794 const bool hasFullPathInFileNameField
= (version
< "0.11");
2797 if (!ReadSectionHeader(reader
, "PLUGINS"))
2800 while (reader
.NextLine()) {
2801 const char *filename
;
2802 const char *fullpath
;
2803 nsAutoCString derivedFileName
;
2805 if (hasInvalidPlugins
&& *reader
.LinePtr() == '[') {
2809 if (hasFullPathInFileNameField
) {
2810 fullpath
= reader
.LinePtr();
2811 if (!reader
.NextLine())
2813 // try to derive a file name from the full path
2815 nsCOMPtr
<nsIFile
> file
= do_CreateInstance("@mozilla.org/file/local;1");
2816 file
->InitWithNativePath(nsDependentCString(fullpath
));
2817 file
->GetNativeLeafName(derivedFileName
);
2818 filename
= derivedFileName
.get();
2823 // skip the next line, useless in this version
2824 if (!reader
.NextLine())
2827 filename
= reader
.LinePtr();
2828 if (!reader
.NextLine())
2831 fullpath
= reader
.LinePtr();
2832 if (!reader
.NextLine())
2836 const char *version
;
2837 if (regHasVersion
) {
2838 version
= reader
.LinePtr();
2839 if (!reader
.NextLine())
2845 // lastModifiedTimeStamp|canUnload|tag.mFlag|fromExtension
2846 const int count
= hasFromExtension
? 4 : 3;
2847 if (reader
.ParseLine(values
, count
) != count
)
2850 // If this is an old plugin registry mark this plugin tag to be refreshed
2851 int64_t lastmod
= (vdiff
== 0) ? nsCRT::atoll(values
[0]) : -1;
2852 uint32_t tagflag
= atoi(values
[2]);
2853 bool fromExtension
= false;
2854 if (hasFromExtension
) {
2855 fromExtension
= atoi(values
[3]);
2857 if (!reader
.NextLine())
2860 char *description
= reader
.LinePtr();
2861 if (!reader
.NextLine())
2864 #if MOZ_WIDGET_ANDROID
2865 // Flash on Android does not populate the version field, but it is tacked on to the description.
2866 // For example, "Shockwave Flash 11.1 r115"
2867 if (PL_strncmp("Shockwave Flash ", description
, 16) == 0 && description
[16]) {
2868 version
= &description
[16];
2872 const char *name
= reader
.LinePtr();
2873 if (!reader
.NextLine())
2876 long mimetypecount
= std::strtol(reader
.LinePtr(), nullptr, 10);
2877 if (mimetypecount
== LONG_MAX
|| mimetypecount
== LONG_MIN
||
2878 mimetypecount
>= PLUGIN_REG_MAX_MIMETYPES
|| mimetypecount
< 0) {
2879 return NS_ERROR_FAILURE
;
2882 char *stackalloced
[PLUGIN_REG_MIMETYPES_ARRAY_SIZE
* 3];
2884 char **mimedescriptions
;
2886 char **heapalloced
= 0;
2887 if (mimetypecount
> PLUGIN_REG_MIMETYPES_ARRAY_SIZE
- 1) {
2888 heapalloced
= new char *[mimetypecount
* 3];
2889 mimetypes
= heapalloced
;
2891 mimetypes
= stackalloced
;
2893 mimedescriptions
= mimetypes
+ mimetypecount
;
2894 extensions
= mimedescriptions
+ mimetypecount
;
2896 int mtr
= 0; //mimetype read
2897 for (; mtr
< mimetypecount
; mtr
++) {
2898 if (!reader
.NextLine())
2901 //line number|mimetype|description|extension
2902 if (4 != reader
.ParseLine(values
, 4))
2904 int line
= atoi(values
[0]);
2907 mimetypes
[mtr
] = values
[1];
2908 mimedescriptions
[mtr
] = values
[2];
2909 extensions
[mtr
] = values
[3];
2912 if (mtr
!= mimetypecount
) {
2914 delete [] heapalloced
;
2919 nsRefPtr
<nsPluginTag
> tag
= new nsPluginTag(name
,
2924 (const char* const*)mimetypes
,
2925 (const char* const*)mimedescriptions
,
2926 (const char* const*)extensions
,
2927 mimetypecount
, lastmod
, fromExtension
, true);
2929 delete [] heapalloced
;
2931 // Import flags from registry into prefs for old registry versions
2932 if (hasValidFlags
&& !pluginStateImported
) {
2933 tag
->ImportFlagsToPrefs(tagflag
);
2936 PR_LOG(nsPluginLogging::gPluginLog
, PLUGIN_LOG_BASIC
,
2937 ("LoadCachedPluginsInfo : Loading Cached plugininfo for %s\n", tag
->mFileName
.get()));
2938 tag
->mNext
= mCachedPlugins
;
2939 mCachedPlugins
= tag
;
2942 // On Android we always want to try to load a plugin again (Flash). Bug 935676.
2943 #ifndef MOZ_WIDGET_ANDROID
2944 if (hasInvalidPlugins
) {
2945 if (!ReadSectionHeader(reader
, "INVALID")) {
2949 while (reader
.NextLine()) {
2950 const char *fullpath
= reader
.LinePtr();
2951 if (!reader
.NextLine()) {
2955 const char *lastModifiedTimeStamp
= reader
.LinePtr();
2956 int64_t lastmod
= (vdiff
== 0) ? nsCRT::atoll(lastModifiedTimeStamp
) : -1;
2958 nsRefPtr
<nsInvalidPluginTag
> invalidTag
= new nsInvalidPluginTag(fullpath
, lastmod
);
2960 invalidTag
->mNext
= mInvalidPlugins
;
2961 if (mInvalidPlugins
) {
2962 mInvalidPlugins
->mPrev
= invalidTag
;
2964 mInvalidPlugins
= invalidTag
;
2969 // flip the pref so we don't import the legacy flags again
2970 Preferences::SetBool("plugin.importedState", true);
2976 nsPluginHost::RemoveCachedPluginsInfo(const char *filePath
, nsPluginTag
**result
)
2978 nsRefPtr
<nsPluginTag
> prev
;
2979 nsRefPtr
<nsPluginTag
> tag
= mCachedPlugins
;
2982 if (tag
->mFullPath
.Equals(filePath
)) {
2983 // Found it. Remove it from our list
2985 prev
->mNext
= tag
->mNext
;
2987 mCachedPlugins
= tag
->mNext
;
2988 tag
->mNext
= nullptr;
3000 nsPluginHost::EnsurePrivateDirServiceProvider()
3002 if (!mPrivateDirServiceProvider
) {
3004 mPrivateDirServiceProvider
= new nsPluginDirServiceProvider();
3005 if (!mPrivateDirServiceProvider
)
3006 return NS_ERROR_OUT_OF_MEMORY
;
3007 nsCOMPtr
<nsIDirectoryService
> dirService(do_GetService(kDirectoryServiceContractID
, &rv
));
3010 rv
= dirService
->RegisterProvider(mPrivateDirServiceProvider
);
3018 nsresult
nsPluginHost::NewPluginURLStream(const nsString
& aURL
,
3019 nsNPAPIPluginInstance
*aInstance
,
3020 nsNPAPIPluginStreamListener
* aListener
,
3021 nsIInputStream
*aPostStream
,
3022 const char *aHeadersData
,
3023 uint32_t aHeadersDataLen
)
3025 nsCOMPtr
<nsIURI
> url
;
3026 nsAutoString absUrl
;
3029 if (aURL
.Length() <= 0)
3032 // get the base URI for the plugin to create an absolute url
3033 // in case aURL is relative
3034 nsRefPtr
<nsPluginInstanceOwner
> owner
= aInstance
->GetOwner();
3036 rv
= NS_MakeAbsoluteURI(absUrl
, aURL
, nsCOMPtr
<nsIURI
>(owner
->GetBaseURI()));
3039 if (absUrl
.IsEmpty())
3040 absUrl
.Assign(aURL
);
3042 rv
= NS_NewURI(getter_AddRefs(url
), absUrl
);
3046 nsCOMPtr
<nsIDOMElement
> element
;
3047 nsCOMPtr
<nsIDocument
> doc
;
3049 owner
->GetDOMElement(getter_AddRefs(element
));
3050 owner
->GetDocument(getter_AddRefs(doc
));
3052 nsCOMPtr
<nsIPrincipal
> principal
= doc
? doc
->NodePrincipal() : nullptr;
3054 int16_t shouldLoad
= nsIContentPolicy::ACCEPT
;
3055 rv
= NS_CheckContentLoadPolicy(nsIContentPolicy::TYPE_OBJECT_SUBREQUEST
,
3059 EmptyCString(), //mime guess
3064 if (NS_CP_REJECTED(shouldLoad
)) {
3065 // Disallowed by content policy
3066 return NS_ERROR_CONTENT_BLOCKED
;
3069 nsRefPtr
<nsPluginStreamListenerPeer
> listenerPeer
= new nsPluginStreamListenerPeer();
3071 return NS_ERROR_OUT_OF_MEMORY
;
3073 rv
= listenerPeer
->Initialize(url
, aInstance
, aListener
);
3078 // do not add this internal plugin's channel on the
3079 // load group otherwise this channel could be canceled
3080 // form |nsDocShell::OnLinkClickSync| bug 166613
3081 nsCOMPtr
<nsIChannel
> channel
;
3082 nsCOMPtr
<nsINode
> requestingNode(do_QueryInterface(element
));
3083 if (requestingNode
) {
3084 rv
= NS_NewChannel(getter_AddRefs(channel
),
3087 nsILoadInfo::SEC_FORCE_INHERIT_PRINCIPAL
,
3088 nsIContentPolicy::TYPE_OBJECT_SUBREQUEST
,
3089 nullptr, // aLoadGroup
3093 // in this else branch we really don't know where the load is coming
3094 // from and in fact should use something better than just using
3095 // a nullPrincipal as the loadingPrincipal.
3096 principal
= do_CreateInstance("@mozilla.org/nullprincipal;1", &rv
);
3097 NS_ENSURE_SUCCESS(rv
, rv
);
3098 rv
= NS_NewChannel(getter_AddRefs(channel
),
3101 nsILoadInfo::SEC_FORCE_INHERIT_PRINCIPAL
,
3102 nsIContentPolicy::TYPE_OBJECT_SUBREQUEST
,
3103 nullptr, // aLoadGroup
3111 // And if it's a script allow it to execute against the
3112 // document's script context.
3113 nsCOMPtr
<nsIScriptChannel
> scriptChannel(do_QueryInterface(channel
));
3114 if (scriptChannel
) {
3115 scriptChannel
->SetExecutionPolicy(nsIScriptChannel::EXECUTE_NORMAL
);
3116 // Plug-ins seem to depend on javascript: URIs running synchronously
3117 scriptChannel
->SetExecuteAsync(false);
3121 // deal with headers and post data
3122 nsCOMPtr
<nsIHttpChannel
> httpChannel(do_QueryInterface(channel
));
3125 // Only set the Referer header for GET requests because IIS throws
3126 // errors about malformed requests if we include it in POSTs. See
3128 nsCOMPtr
<nsIURI
> referer
;
3129 net::ReferrerPolicy referrerPolicy
= net::RP_Default
;
3131 nsCOMPtr
<nsIObjectLoadingContent
> olc
= do_QueryInterface(element
);
3133 olc
->GetSrcURI(getter_AddRefs(referer
));
3138 return NS_ERROR_FAILURE
;
3140 referer
= doc
->GetDocumentURI();
3141 referrerPolicy
= doc
->GetReferrerPolicy();
3144 rv
= httpChannel
->SetReferrerWithPolicy(referer
, referrerPolicy
);
3145 NS_ENSURE_SUCCESS(rv
,rv
);
3149 // XXX it's a bit of a hack to rewind the postdata stream
3150 // here but it has to be done in case the post data is
3151 // being reused multiple times.
3152 nsCOMPtr
<nsISeekableStream
>
3153 postDataSeekable(do_QueryInterface(aPostStream
));
3154 if (postDataSeekable
)
3155 postDataSeekable
->Seek(nsISeekableStream::NS_SEEK_SET
, 0);
3157 nsCOMPtr
<nsIUploadChannel
> uploadChannel(do_QueryInterface(httpChannel
));
3158 NS_ASSERTION(uploadChannel
, "http must support nsIUploadChannel");
3160 uploadChannel
->SetUploadStream(aPostStream
, EmptyCString(), -1);
3164 rv
= AddHeadersToChannel(aHeadersData
, aHeadersDataLen
, httpChannel
);
3165 NS_ENSURE_SUCCESS(rv
,rv
);
3168 rv
= channel
->AsyncOpen(listenerPeer
, nullptr);
3169 if (NS_SUCCEEDED(rv
))
3170 listenerPeer
->TrackRequest(channel
);
3174 // Called by GetURL and PostURL
3176 nsPluginHost::DoURLLoadSecurityCheck(nsNPAPIPluginInstance
*aInstance
,
3179 if (!aURL
|| *aURL
== '\0')
3182 // get the base URI for the plugin element
3183 nsRefPtr
<nsPluginInstanceOwner
> owner
= aInstance
->GetOwner();
3185 return NS_ERROR_FAILURE
;
3187 nsCOMPtr
<nsIURI
> baseURI
= owner
->GetBaseURI();
3189 return NS_ERROR_FAILURE
;
3191 // Create an absolute URL for the target in case the target is relative
3192 nsCOMPtr
<nsIURI
> targetURL
;
3193 NS_NewURI(getter_AddRefs(targetURL
), aURL
, baseURI
);
3195 return NS_ERROR_FAILURE
;
3197 nsCOMPtr
<nsIDocument
> doc
;
3198 owner
->GetDocument(getter_AddRefs(doc
));
3200 return NS_ERROR_FAILURE
;
3203 nsCOMPtr
<nsIScriptSecurityManager
> secMan(
3204 do_GetService(NS_SCRIPTSECURITYMANAGER_CONTRACTID
, &rv
));
3208 return secMan
->CheckLoadURIWithPrincipal(doc
->NodePrincipal(), targetURL
,
3209 nsIScriptSecurityManager::STANDARD
);
3214 nsPluginHost::AddHeadersToChannel(const char *aHeadersData
,
3215 uint32_t aHeadersDataLen
,
3216 nsIChannel
*aGenericChannel
)
3218 nsresult rv
= NS_OK
;
3220 nsCOMPtr
<nsIHttpChannel
> aChannel
= do_QueryInterface(aGenericChannel
);
3222 return NS_ERROR_NULL_POINTER
;
3225 // used during the manipulation of the String from the aHeadersData
3226 nsAutoCString headersString
;
3227 nsAutoCString oneHeader
;
3228 nsAutoCString headerName
;
3229 nsAutoCString headerValue
;
3233 // Turn the char * buffer into an nsString.
3234 headersString
= aHeadersData
;
3236 // Iterate over the nsString: for each "\r\n" delimited chunk,
3237 // add the value as a header to the nsIHTTPChannel
3239 crlf
= headersString
.Find("\r\n", true);
3244 headersString
.Mid(oneHeader
, 0, crlf
);
3245 headersString
.Cut(0, crlf
+ 2);
3246 oneHeader
.StripWhitespace();
3247 colon
= oneHeader
.Find(":");
3249 rv
= NS_ERROR_NULL_POINTER
;
3252 oneHeader
.Left(headerName
, colon
);
3254 oneHeader
.Mid(headerValue
, colon
, oneHeader
.Length() - colon
);
3256 // FINALLY: we can set the header!
3258 rv
= aChannel
->SetRequestHeader(headerName
, headerValue
, true);
3259 if (NS_FAILED(rv
)) {
3260 rv
= NS_ERROR_NULL_POINTER
;
3268 nsPluginHost::StopPluginInstance(nsNPAPIPluginInstance
* aInstance
)
3270 if (PluginDestructionGuard::DelayDestroy(aInstance
)) {
3274 PLUGIN_LOG(PLUGIN_LOG_NORMAL
,
3275 ("nsPluginHost::StopPluginInstance called instance=%p\n",aInstance
));
3277 if (aInstance
->HasStartedDestroying()) {
3281 Telemetry::AutoTimer
<Telemetry::PLUGIN_SHUTDOWN_MS
> timer
;
3284 // if the instance does not want to be 'cached' just remove it
3285 bool doCache
= aInstance
->ShouldCache();
3287 // try to get the max cached instances from a pref or use default
3288 uint32_t cachedInstanceLimit
=
3289 Preferences::GetUint(NS_PREF_MAX_NUM_CACHED_INSTANCES
,
3290 DEFAULT_NUMBER_OF_STOPPED_INSTANCES
);
3291 if (StoppedInstanceCount() >= cachedInstanceLimit
) {
3292 nsNPAPIPluginInstance
*oldestInstance
= FindOldestStoppedInstance();
3293 if (oldestInstance
) {
3294 nsPluginTag
* pluginTag
= TagForPlugin(oldestInstance
->GetPlugin());
3295 oldestInstance
->Destroy();
3296 mInstances
.RemoveElement(oldestInstance
);
3297 // TODO: Remove this check once bug 752422 was investigated
3299 OnPluginInstanceDestroyed(pluginTag
);
3304 nsPluginTag
* pluginTag
= TagForPlugin(aInstance
->GetPlugin());
3305 aInstance
->Destroy();
3306 mInstances
.RemoveElement(aInstance
);
3307 // TODO: Remove this check once bug 752422 was investigated
3309 OnPluginInstanceDestroyed(pluginTag
);
3316 nsresult
nsPluginHost::NewPluginStreamListener(nsIURI
* aURI
,
3317 nsNPAPIPluginInstance
* aInstance
,
3318 nsIStreamListener
**aStreamListener
)
3320 NS_ENSURE_ARG_POINTER(aURI
);
3321 NS_ENSURE_ARG_POINTER(aStreamListener
);
3323 nsRefPtr
<nsPluginStreamListenerPeer
> listener
= new nsPluginStreamListenerPeer();
3324 nsresult rv
= listener
->Initialize(aURI
, aInstance
, nullptr);
3325 if (NS_FAILED(rv
)) {
3329 listener
.forget(aStreamListener
);
3334 void nsPluginHost::CreateWidget(nsPluginInstanceOwner
* aOwner
)
3336 aOwner
->CreateWidget();
3338 // If we've got a native window, the let the plugin know about it.
3339 aOwner
->CallSetWindow();
3342 NS_IMETHODIMP
nsPluginHost::Observe(nsISupports
*aSubject
,
3344 const char16_t
*someData
)
3346 if (!strcmp(NS_XPCOM_SHUTDOWN_OBSERVER_ID
, aTopic
)) {
3351 if (!strcmp(NS_PREFBRANCH_PREFCHANGE_TOPIC_ID
, aTopic
)) {
3352 mPluginsDisabled
= Preferences::GetBool("plugin.disable", false);
3353 mPluginsClickToPlay
= Preferences::GetBool("plugins.click_to_play", false);
3354 // Unload or load plugins as needed
3355 if (mPluginsDisabled
) {
3361 if (!strcmp("blocklist-updated", aTopic
)) {
3362 nsPluginTag
* plugin
= mPlugins
;
3364 plugin
->InvalidateBlocklistState();
3365 plugin
= plugin
->mNext
;
3368 #ifdef MOZ_WIDGET_ANDROID
3369 if (!strcmp("application-background", aTopic
)) {
3370 for(uint32_t i
= 0; i
< mInstances
.Length(); i
++) {
3371 mInstances
[i
]->NotifyForeground(false);
3374 if (!strcmp("application-foreground", aTopic
)) {
3375 for(uint32_t i
= 0; i
< mInstances
.Length(); i
++) {
3376 if (mInstances
[i
]->IsOnScreen())
3377 mInstances
[i
]->NotifyForeground(true);
3380 if (!strcmp("memory-pressure", aTopic
)) {
3381 for(uint32_t i
= 0; i
< mInstances
.Length(); i
++) {
3382 mInstances
[i
]->MemoryPressure();
3390 nsPluginHost::ParsePostBufferToFixHeaders(const char *inPostData
, uint32_t inPostDataLen
,
3391 char **outPostData
, uint32_t *outPostDataLen
)
3393 if (!inPostData
|| !outPostData
|| !outPostDataLen
)
3394 return NS_ERROR_NULL_POINTER
;
3397 *outPostDataLen
= 0;
3399 const char CR
= '\r';
3400 const char LF
= '\n';
3401 const char CRLFCRLF
[] = {CR
,LF
,CR
,LF
,'\0'}; // C string"\r\n\r\n"
3402 const char ContentLenHeader
[] = "Content-length";
3404 nsAutoTArray
<const char*, 8> singleLF
;
3405 const char *pSCntlh
= 0;// pointer to start of ContentLenHeader in inPostData
3406 const char *pSod
= 0; // pointer to start of data in inPostData
3407 const char *pEoh
= 0; // pointer to end of headers in inPostData
3408 const char *pEod
= inPostData
+ inPostDataLen
; // pointer to end of inPostData
3409 if (*inPostData
== LF
) {
3410 // If no custom headers are required, simply add a blank
3411 // line ('\n') to the beginning of the file or buffer.
3412 // so *inPostData == '\n' is valid
3413 pSod
= inPostData
+ 1;
3415 const char *s
= inPostData
; //tmp pointer to sourse inPostData
3418 (*s
== 'C' || *s
== 'c') &&
3419 (s
+ sizeof(ContentLenHeader
) - 1 < pEod
) &&
3420 (!PL_strncasecmp(s
, ContentLenHeader
, sizeof(ContentLenHeader
) - 1)))
3422 // lets assume this is ContentLenHeader for now
3423 const char *p
= pSCntlh
= s
;
3424 p
+= sizeof(ContentLenHeader
) - 1;
3425 // search for first CR or LF == end of ContentLenHeader
3426 for (; p
< pEod
; p
++) {
3427 if (*p
== CR
|| *p
== LF
) {
3429 // one more check; if previous char is a digit
3430 // most likely pSCntlh points to the start of ContentLenHeader
3431 if (*(p
-1) >= '0' && *(p
-1) <= '9') {
3437 if (pSCntlh
== s
) { // curret ptr is the same
3438 pSCntlh
= 0; // that was not ContentLenHeader
3439 break; // there is nothing to parse, break *WHILE LOOP* here
3444 if (pSCntlh
&& // only if ContentLenHeader is found we are looking for end of headers
3445 ((s
+ sizeof(CRLFCRLF
)-1) <= pEod
) &&
3446 !memcmp(s
, CRLFCRLF
, sizeof(CRLFCRLF
)-1))
3448 s
+= sizeof(CRLFCRLF
)-1;
3449 pEoh
= pSod
= s
; // data stars here
3452 } else if (*s
== LF
) {
3454 singleLF
.AppendElement(s
);
3456 if (pSCntlh
&& (s
+1 < pEod
) && (*(s
+1) == LF
)) {
3458 singleLF
.AppendElement(s
);
3460 pEoh
= pSod
= s
; // data stars here
3468 // deal with output buffer
3469 if (!pSod
) { // lets assume whole buffer is a data
3473 uint32_t newBufferLen
= 0;
3474 uint32_t dataLen
= pEod
- pSod
;
3475 uint32_t headersLen
= pEoh
? pSod
- inPostData
: 0;
3477 char *p
; // tmp ptr into new output buf
3478 if (headersLen
) { // we got a headers
3479 // this function does not make any assumption on correctness
3480 // of ContentLenHeader value in this case.
3482 newBufferLen
= dataLen
+ headersLen
;
3483 // in case there were single LFs in headers
3484 // reserve an extra space for CR will be added before each single LF
3485 int cntSingleLF
= singleLF
.Length();
3486 newBufferLen
+= cntSingleLF
;
3488 if (!(*outPostData
= p
= (char*)nsMemory::Alloc(newBufferLen
)))
3489 return NS_ERROR_OUT_OF_MEMORY
;
3491 // deal with single LF
3492 const char *s
= inPostData
;
3494 for (int i
=0; i
<cntSingleLF
; i
++) {
3495 const char *plf
= singleLF
.ElementAt(i
); // ptr to single LF in headers
3496 int n
= plf
- s
; // bytes to copy
3497 if (n
) { // for '\n\n' there is nothing to memcpy
3506 // are we done with headers?
3507 headersLen
= pEoh
- s
;
3508 if (headersLen
) { // not yet
3509 memcpy(p
, s
, headersLen
); // copy the rest
3512 } else if (dataLen
) { // no ContentLenHeader is found but there is a data
3513 // make new output buffer big enough
3514 // to keep ContentLenHeader+value followed by data
3515 uint32_t l
= sizeof(ContentLenHeader
) + sizeof(CRLFCRLF
) + 32;
3516 newBufferLen
= dataLen
+ l
;
3517 if (!(*outPostData
= p
= (char*)nsMemory::Alloc(newBufferLen
)))
3518 return NS_ERROR_OUT_OF_MEMORY
;
3519 headersLen
= PR_snprintf(p
, l
,"%s: %ld%s", ContentLenHeader
, dataLen
, CRLFCRLF
);
3520 if (headersLen
== l
) { // if PR_snprintf has ate all extra space consider this as an error
3523 return NS_ERROR_FAILURE
;
3526 newBufferLen
= headersLen
+ dataLen
;
3528 // at this point we've done with headers.
3529 // there is a possibility that input buffer has only headers info in it
3530 // which already parsed and copied into output buffer.
3533 memcpy(p
, pSod
, dataLen
);
3536 *outPostDataLen
= newBufferLen
;
3542 nsPluginHost::CreateTempFileToPost(const char *aPostDataURL
, nsIFile
**aTmpFile
)
3546 nsAutoCString filename
;
3548 // stat file == get size & convert file:///c:/ to c: if needed
3549 nsCOMPtr
<nsIFile
> inFile
;
3550 rv
= NS_GetFileFromURLSpec(nsDependentCString(aPostDataURL
),
3551 getter_AddRefs(inFile
));
3552 if (NS_FAILED(rv
)) {
3553 nsCOMPtr
<nsIFile
> localFile
;
3554 rv
= NS_NewNativeLocalFile(nsDependentCString(aPostDataURL
), false,
3555 getter_AddRefs(localFile
));
3556 if (NS_FAILED(rv
)) return rv
;
3559 rv
= inFile
->GetFileSize(&fileSize
);
3560 if (NS_FAILED(rv
)) return rv
;
3561 rv
= inFile
->GetNativePath(filename
);
3562 if (NS_FAILED(rv
)) return rv
;
3564 if (fileSize
!= 0) {
3565 nsCOMPtr
<nsIInputStream
> inStream
;
3566 rv
= NS_NewLocalFileInputStream(getter_AddRefs(inStream
), inFile
);
3567 if (NS_FAILED(rv
)) return rv
;
3569 // Create a temporary file to write the http Content-length:
3570 // %ld\r\n\" header and "\r\n" == end of headers for post data to
3572 nsCOMPtr
<nsIFile
> tempFile
;
3573 rv
= GetPluginTempDir(getter_AddRefs(tempFile
));
3577 nsAutoCString inFileName
;
3578 inFile
->GetNativeLeafName(inFileName
);
3579 // XXX hack around bug 70083
3580 inFileName
.Insert(NS_LITERAL_CSTRING("post-"), 0);
3581 rv
= tempFile
->AppendNative(inFileName
);
3586 // make it unique, and mode == 0600, not world-readable
3587 rv
= tempFile
->CreateUnique(nsIFile::NORMAL_FILE_TYPE
, 0600);
3591 nsCOMPtr
<nsIOutputStream
> outStream
;
3592 if (NS_SUCCEEDED(rv
)) {
3593 rv
= NS_NewLocalFileOutputStream(getter_AddRefs(outStream
),
3595 (PR_WRONLY
| PR_CREATE_FILE
| PR_TRUNCATE
),
3596 0600); // 600 so others can't read our form data
3598 NS_ASSERTION(NS_SUCCEEDED(rv
), "Post data file couldn't be created!");
3604 bool firstRead
= true;
3606 // Read() mallocs if buffer is null
3607 rv
= inStream
->Read(buf
, 1024, &br
);
3608 if (NS_FAILED(rv
) || (int32_t)br
<= 0)
3611 //"For protocols in which the headers must be distinguished from the body,
3612 // such as HTTP, the buffer or file should contain the headers, followed by
3613 // a blank line, then the body. If no custom headers are required, simply
3614 // add a blank line ('\n') to the beginning of the file or buffer.
3617 // assuming first 1K (or what we got) has all headers in,
3618 // lets parse it through nsPluginHost::ParsePostBufferToFixHeaders()
3619 ParsePostBufferToFixHeaders((const char *)buf
, br
, &parsedBuf
, &bw
);
3620 rv
= outStream
->Write(parsedBuf
, bw
, &br
);
3621 nsMemory::Free(parsedBuf
);
3622 if (NS_FAILED(rv
) || (bw
!= br
))
3629 rv
= outStream
->Write(buf
, bw
, &br
);
3630 if (NS_FAILED(rv
) || (bw
!= br
))
3636 if (NS_SUCCEEDED(rv
))
3637 tempFile
.forget(aTmpFile
);
3643 nsPluginHost::NewPluginNativeWindow(nsPluginNativeWindow
** aPluginNativeWindow
)
3645 return PLUG_NewPluginNativeWindow(aPluginNativeWindow
);
3649 nsPluginHost::GetPluginName(nsNPAPIPluginInstance
*aPluginInstance
,
3650 const char** aPluginName
)
3652 nsNPAPIPluginInstance
*instance
= static_cast<nsNPAPIPluginInstance
*>(aPluginInstance
);
3654 return NS_ERROR_FAILURE
;
3656 nsNPAPIPlugin
* plugin
= instance
->GetPlugin();
3658 return NS_ERROR_FAILURE
;
3660 *aPluginName
= TagForPlugin(plugin
)->mName
.get();
3666 nsPluginHost::GetPluginTagForInstance(nsNPAPIPluginInstance
*aPluginInstance
,
3667 nsIPluginTag
**aPluginTag
)
3669 NS_ENSURE_ARG_POINTER(aPluginInstance
);
3670 NS_ENSURE_ARG_POINTER(aPluginTag
);
3672 nsNPAPIPlugin
*plugin
= aPluginInstance
->GetPlugin();
3674 return NS_ERROR_FAILURE
;
3676 *aPluginTag
= TagForPlugin(plugin
);
3678 NS_ADDREF(*aPluginTag
);
3682 NS_IMETHODIMP
nsPluginHost::Notify(nsITimer
* timer
)
3684 nsRefPtr
<nsPluginTag
> pluginTag
= mPlugins
;
3686 if (pluginTag
->mUnloadTimer
== timer
) {
3687 if (!IsRunningPlugin(pluginTag
)) {
3688 pluginTag
->TryUnloadPlugin(false);
3692 pluginTag
= pluginTag
->mNext
;
3695 return NS_ERROR_FAILURE
;
3699 // Re-enable any top level browser windows that were disabled by modal dialogs
3700 // displayed by the crashed plugin.
3702 CheckForDisabledWindows()
3704 nsCOMPtr
<nsIWindowMediator
> wm(do_GetService(NS_WINDOWMEDIATOR_CONTRACTID
));
3708 nsCOMPtr
<nsISimpleEnumerator
> windowList
;
3709 wm
->GetXULWindowEnumerator(nullptr, getter_AddRefs(windowList
));
3715 windowList
->HasMoreElements(&haveWindows
);
3719 nsCOMPtr
<nsISupports
> supportsWindow
;
3720 windowList
->GetNext(getter_AddRefs(supportsWindow
));
3721 nsCOMPtr
<nsIBaseWindow
> baseWin(do_QueryInterface(supportsWindow
));
3723 nsCOMPtr
<nsIWidget
> widget
;
3724 baseWin
->GetMainWidget(getter_AddRefs(widget
));
3725 if (widget
&& !widget
->GetParent() &&
3726 widget
->IsVisible() &&
3727 !widget
->IsEnabled()) {
3728 nsIWidget
* child
= widget
->GetFirstChild();
3731 if (child
->WindowType() == eWindowType_dialog
) {
3735 child
= child
->GetNextSibling();
3738 widget
->Enable(true);
3742 } while (haveWindows
);
3747 nsPluginHost::PluginCrashed(nsNPAPIPlugin
* aPlugin
,
3748 const nsAString
& pluginDumpID
,
3749 const nsAString
& browserDumpID
)
3751 nsPluginTag
* crashedPluginTag
= TagForPlugin(aPlugin
);
3753 // Notify the app's observer that a plugin crashed so it can submit
3755 bool submittedCrashReport
= false;
3756 nsCOMPtr
<nsIObserverService
> obsService
=
3757 mozilla::services::GetObserverService();
3758 nsCOMPtr
<nsIWritablePropertyBag2
> propbag
=
3759 do_CreateInstance("@mozilla.org/hash-property-bag;1");
3760 if (obsService
&& propbag
) {
3761 propbag
->SetPropertyAsAString(NS_LITERAL_STRING("pluginDumpID"),
3763 propbag
->SetPropertyAsAString(NS_LITERAL_STRING("browserDumpID"),
3765 propbag
->SetPropertyAsBool(NS_LITERAL_STRING("submittedCrashReport"),
3766 submittedCrashReport
);
3767 obsService
->NotifyObservers(propbag
, "plugin-crashed", nullptr);
3768 // see if an observer submitted a crash report.
3769 propbag
->GetPropertyAsBool(NS_LITERAL_STRING("submittedCrashReport"),
3770 &submittedCrashReport
);
3773 // Invalidate each nsPluginInstanceTag for the crashed plugin
3775 for (uint32_t i
= mInstances
.Length(); i
> 0; i
--) {
3776 nsNPAPIPluginInstance
* instance
= mInstances
[i
- 1];
3777 if (instance
->GetPlugin() == aPlugin
) {
3778 // notify the content node (nsIObjectLoadingContent) that the
3779 // plugin has crashed
3780 nsCOMPtr
<nsIDOMElement
> domElement
;
3781 instance
->GetDOMElement(getter_AddRefs(domElement
));
3782 nsCOMPtr
<nsIObjectLoadingContent
> objectContent(do_QueryInterface(domElement
));
3783 if (objectContent
) {
3784 objectContent
->PluginCrashed(crashedPluginTag
, pluginDumpID
, browserDumpID
,
3785 submittedCrashReport
);
3788 instance
->Destroy();
3789 mInstances
.RemoveElement(instance
);
3790 OnPluginInstanceDestroyed(crashedPluginTag
);
3794 // Only after all instances have been invalidated is it safe to null
3795 // out nsPluginTag.mPlugin. The next time we try to create an
3796 // instance of this plugin we reload it (launch a new plugin process).
3798 crashedPluginTag
->mPlugin
= nullptr;
3799 crashedPluginTag
->mContentProcessRunningCount
= 0;
3802 CheckForDisabledWindows();
3806 nsNPAPIPluginInstance
*
3807 nsPluginHost::FindInstance(const char *mimetype
)
3809 for (uint32_t i
= 0; i
< mInstances
.Length(); i
++) {
3810 nsNPAPIPluginInstance
* instance
= mInstances
[i
];
3813 nsresult rv
= instance
->GetMIMEType(&mt
);
3817 if (PL_strcasecmp(mt
, mimetype
) == 0)
3824 nsNPAPIPluginInstance
*
3825 nsPluginHost::FindOldestStoppedInstance()
3827 nsNPAPIPluginInstance
*oldestInstance
= nullptr;
3828 TimeStamp oldestTime
= TimeStamp::Now();
3829 for (uint32_t i
= 0; i
< mInstances
.Length(); i
++) {
3830 nsNPAPIPluginInstance
*instance
= mInstances
[i
];
3831 if (instance
->IsRunning())
3834 TimeStamp time
= instance
->StopTime();
3835 if (time
< oldestTime
) {
3837 oldestInstance
= instance
;
3841 return oldestInstance
;
3845 nsPluginHost::StoppedInstanceCount()
3847 uint32_t stoppedCount
= 0;
3848 for (uint32_t i
= 0; i
< mInstances
.Length(); i
++) {
3849 nsNPAPIPluginInstance
*instance
= mInstances
[i
];
3850 if (!instance
->IsRunning())
3853 return stoppedCount
;
3856 nsTArray
< nsRefPtr
<nsNPAPIPluginInstance
> >*
3857 nsPluginHost::InstanceArray()
3863 nsPluginHost::DestroyRunningInstances(nsPluginTag
* aPluginTag
)
3865 for (int32_t i
= mInstances
.Length(); i
> 0; i
--) {
3866 nsNPAPIPluginInstance
*instance
= mInstances
[i
- 1];
3867 if (instance
->IsRunning() && (!aPluginTag
|| aPluginTag
== TagForPlugin(instance
->GetPlugin()))) {
3868 instance
->SetWindow(nullptr);
3871 // Get rid of all the instances without the possibility of caching.
3872 nsPluginTag
* pluginTag
= TagForPlugin(instance
->GetPlugin());
3873 instance
->SetWindow(nullptr);
3875 nsCOMPtr
<nsIDOMElement
> domElement
;
3876 instance
->GetDOMElement(getter_AddRefs(domElement
));
3877 nsCOMPtr
<nsIObjectLoadingContent
> objectContent
=
3878 do_QueryInterface(domElement
);
3880 instance
->Destroy();
3882 mInstances
.RemoveElement(instance
);
3883 OnPluginInstanceDestroyed(pluginTag
);
3885 // Notify owning content that we destroyed its plugin out from under it
3886 if (objectContent
) {
3887 objectContent
->PluginDestroyed();
3893 // Runnable that does an async destroy of a plugin.
3895 class nsPluginDestroyRunnable
: public nsRunnable
,
3899 explicit nsPluginDestroyRunnable(nsNPAPIPluginInstance
*aInstance
)
3900 : mInstance(aInstance
)
3902 PR_INIT_CLIST(this);
3903 PR_APPEND_LINK(this, &sRunnableListHead
);
3906 virtual ~nsPluginDestroyRunnable()
3908 PR_REMOVE_LINK(this);
3913 nsRefPtr
<nsNPAPIPluginInstance
> instance
;
3915 // Null out mInstance to make sure this code in another runnable
3916 // will do the right thing even if someone was holding on to this
3917 // runnable longer than we expect.
3918 instance
.swap(mInstance
);
3920 if (PluginDestructionGuard::DelayDestroy(instance
)) {
3921 // It's still not safe to destroy the plugin, it's now up to the
3922 // outermost guard on the stack to take care of the destruction.
3926 nsPluginDestroyRunnable
*r
=
3927 static_cast<nsPluginDestroyRunnable
*>(PR_NEXT_LINK(&sRunnableListHead
));
3929 while (r
!= &sRunnableListHead
) {
3930 if (r
!= this && r
->mInstance
== instance
) {
3931 // There's another runnable scheduled to tear down
3932 // instance. Let it do the job.
3935 r
= static_cast<nsPluginDestroyRunnable
*>(PR_NEXT_LINK(r
));
3938 PLUGIN_LOG(PLUGIN_LOG_NORMAL
,
3939 ("Doing delayed destroy of instance %p\n", instance
.get()));
3941 nsRefPtr
<nsPluginHost
> host
= nsPluginHost::GetInst();
3943 host
->StopPluginInstance(instance
);
3945 PLUGIN_LOG(PLUGIN_LOG_NORMAL
,
3946 ("Done with delayed destroy of instance %p\n", instance
.get()));
3952 nsRefPtr
<nsNPAPIPluginInstance
> mInstance
;
3954 static PRCList sRunnableListHead
;
3957 PRCList
nsPluginDestroyRunnable::sRunnableListHead
=
3958 PR_INIT_STATIC_CLIST(&nsPluginDestroyRunnable::sRunnableListHead
);
3960 PRCList
PluginDestructionGuard::sListHead
=
3961 PR_INIT_STATIC_CLIST(&PluginDestructionGuard::sListHead
);
3963 PluginDestructionGuard::PluginDestructionGuard(nsNPAPIPluginInstance
*aInstance
)
3964 : mInstance(aInstance
)
3969 PluginDestructionGuard::PluginDestructionGuard(PluginAsyncSurrogate
*aSurrogate
)
3970 : mInstance(static_cast<nsNPAPIPluginInstance
*>(aSurrogate
->GetNPP()->ndata
))
3975 PluginDestructionGuard::PluginDestructionGuard(NPP npp
)
3976 : mInstance(npp
? static_cast<nsNPAPIPluginInstance
*>(npp
->ndata
) : nullptr)
3981 PluginDestructionGuard::~PluginDestructionGuard()
3983 NS_ASSERTION(NS_IsMainThread(), "Should be on the main thread");
3985 PR_REMOVE_LINK(this);
3987 if (mDelayedDestroy
) {
3988 // We've attempted to destroy the plugin instance we're holding on
3989 // to while we were guarding it. Do the actual destroy now, off of
3991 nsRefPtr
<nsPluginDestroyRunnable
> evt
=
3992 new nsPluginDestroyRunnable(mInstance
);
3994 NS_DispatchToMainThread(evt
);
4000 PluginDestructionGuard::DelayDestroy(nsNPAPIPluginInstance
*aInstance
)
4002 NS_ASSERTION(NS_IsMainThread(), "Should be on the main thread");
4003 NS_ASSERTION(aInstance
, "Uh, I need an instance!");
4005 // Find the first guard on the stack and make it do a delayed
4006 // destroy upon destruction.
4008 PluginDestructionGuard
*g
=
4009 static_cast<PluginDestructionGuard
*>(PR_LIST_HEAD(&sListHead
));
4011 while (g
!= &sListHead
) {
4012 if (g
->mInstance
== aInstance
) {
4013 g
->mDelayedDestroy
= true;
4017 g
= static_cast<PluginDestructionGuard
*>(PR_NEXT_LINK(g
));