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 "nsIComponentManager.h"
16 #include "nsNPAPIPlugin.h"
17 #include "nsNPAPIPluginStreamListener.h"
18 #include "nsNPAPIPluginInstance.h"
19 #include "nsPluginInstanceOwner.h"
20 #include "nsObjectLoadingContent.h"
21 #include "nsIHTTPHeaderListener.h"
22 #include "nsIHttpHeaderVisitor.h"
23 #include "nsIObserverService.h"
24 #include "nsIHttpProtocolHandler.h"
25 #include "nsIHttpChannel.h"
26 #include "nsIHttpChannelInternal.h"
27 #include "nsIUploadChannel.h"
28 #include "nsIByteRangeRequest.h"
29 #include "nsIStreamListener.h"
30 #include "nsIInputStream.h"
31 #include "nsIOutputStream.h"
34 #include "nsReadableUtils.h"
35 #include "nsIProtocolProxyService2.h"
36 #include "nsIStreamConverterService.h"
38 #if defined(XP_MACOSX)
39 #include "nsILocalFileMac.h"
41 #include "nsIInputStream.h"
42 #include "nsIIOService.h"
44 #include "nsIChannel.h"
45 #include "nsISeekableStream.h"
46 #include "nsNetUtil.h"
47 #include "nsIProgressEventSink.h"
48 #include "nsIDocument.h"
49 #include "nsICachingChannel.h"
50 #include "nsHashtable.h"
51 #include "nsIProxyInfo.h"
52 #include "nsPluginLogging.h"
53 #include "nsIScriptChannel.h"
54 #include "nsIBlocklistService.h"
55 #include "nsVersionComparator.h"
56 #include "nsIObjectLoadingContent.h"
57 #include "nsIWritablePropertyBag2.h"
58 #include "nsICategoryManager.h"
59 #include "nsPluginStreamListenerPeer.h"
60 #include "mozilla/Preferences.h"
62 #include "nsEnumeratorUtils.h"
64 #include "nsXPCOMCID.h"
65 #include "nsISupportsPrimitives.h"
67 #include "nsXULAppAPI.h"
68 #include "nsIXULRuntime.h"
71 #include "nsIWindowWatcher.h"
72 #include "nsIDOMWindow.h"
74 #include "nsIScriptGlobalObject.h"
75 #include "nsIScriptGlobalObjectOwner.h"
76 #include "nsIPrincipal.h"
79 #include "nsIDOMPlugin.h"
80 #include "nsIDOMMimeType.h"
81 #include "nsMimeTypes.h"
83 #include "nsThreadUtils.h"
84 #include "nsIInputStreamTee.h"
85 #include "nsIInterfaceInfoManager.h"
88 #include "nsIMIMEService.h"
89 #include "nsCExternalHandlerService.h"
90 #include "nsIFileChannel.h"
92 #include "nsICharsetConverterManager.h"
93 #include "nsIPlatformCharset.h"
95 #include "nsIDirectoryService.h"
96 #include "nsDirectoryServiceDefs.h"
97 #include "nsXULAppAPI.h"
98 #include "nsAppDirectoryServiceDefs.h"
99 #include "nsPluginDirServiceProvider.h"
102 #include "nsUnicharUtils.h"
103 #include "nsPluginManifestLineReader.h"
105 #include "nsIWeakReferenceUtils.h"
106 #include "nsIDOMElement.h"
107 #include "nsIDOMHTMLObjectElement.h"
108 #include "nsIDOMHTMLEmbedElement.h"
109 #include "nsIPresShell.h"
110 #include "nsIWebNavigation.h"
111 #include "nsIDocShell.h"
112 #include "nsPluginNativeWindow.h"
113 #include "nsIScriptSecurityManager.h"
114 #include "nsIContentPolicy.h"
115 #include "nsContentPolicyUtils.h"
116 #include "mozilla/TimeStamp.h"
117 #include "mozilla/Telemetry.h"
118 #include "nsIImageLoadingContent.h"
119 #include "mozilla/Preferences.h"
120 #include "nsVersionComparator.h"
123 #include "nsIWindowMediator.h"
124 #include "nsIBaseWindow.h"
130 #include <android/log.h>
131 #define LOG(args...) __android_log_print(ANDROID_LOG_INFO, "GeckoPlugins" , ## args)
134 #if MOZ_CRASHREPORTER
135 #include "nsExceptionHandler.h"
138 using namespace mozilla
;
139 using mozilla::TimeStamp
;
141 // Null out a strong ref to a linked list iteratively to avoid
142 // exhausting the stack (bug 486349).
143 #define NS_ITERATIVE_UNREF_LIST(type_, list_, mNext_) \
146 type_ temp = list_->mNext_; \
147 list_->mNext_ = nullptr; \
152 // this is the name of the directory which will be created
153 // to cache temporary files.
154 #define kPluginTmpDirName NS_LITERAL_CSTRING("plugtmp")
156 static const char *kPrefWhitelist
= "plugin.allowed_types";
157 static const char *kPrefDisableFullPage
= "plugin.disable_full_page_plugin_for_types";
159 // Version of cached plugin info
160 // 0.01 first implementation
161 // 0.02 added caching of CanUnload to fix bug 105935
162 // 0.03 changed name, description and mime desc from string to bytes, bug 108246
163 // 0.04 added new mime entry point on Mac, bug 113464
164 // 0.05 added new entry point check for the default plugin, bug 132430
165 // 0.06 strip off suffixes in mime description strings, bug 53895
166 // 0.07 changed nsIRegistry to flat file support for caching plugins info
167 // 0.08 mime entry point on MachO, bug 137535
168 // 0.09 the file encoding is changed to UTF-8, bug 420285
169 // 0.10 added plugin versions on appropriate platforms, bug 427743
170 // 0.11 file name and full path fields now store expected values on all platforms, bug 488181
171 // 0.12 force refresh due to quicktime pdf claim fix, bug 611197
172 // 0.13 add architecture and list of invalid plugins, bug 616271
173 // 0.14 force refresh due to locale comparison fix, bug 611296
174 // 0.15 force refresh due to bug in reading Java plist MIME data, bug 638171
175 // 0.16 version bump to avoid importing the plugin flags in newer versions
176 // The current plugin registry version (and the maximum version we know how to read)
177 static const char *kPluginRegistryVersion
= "0.16";
178 // The minimum registry version we know how to read
179 static const char *kMinimumRegistryVersion
= "0.9";
181 static NS_DEFINE_IID(kIPluginTagInfoIID
, NS_IPLUGINTAGINFO_IID
);
182 static const char kDirectoryServiceContractID
[] = "@mozilla.org/file/directory_service;1";
184 // Registry keys for caching plugin info
185 static const char kPluginsRootKey
[] = "software/plugins";
186 static const char kPluginsNameKey
[] = "name";
187 static const char kPluginsDescKey
[] = "description";
188 static const char kPluginsFilenameKey
[] = "filename";
189 static const char kPluginsFullpathKey
[] = "fullpath";
190 static const char kPluginsModTimeKey
[] = "lastModTimeStamp";
191 static const char kPluginsCanUnload
[] = "canUnload";
192 static const char kPluginsVersionKey
[] = "version";
193 static const char kPluginsMimeTypeKey
[] = "mimetype";
194 static const char kPluginsMimeDescKey
[] = "description";
195 static const char kPluginsMimeExtKey
[] = "extension";
197 #define kPluginRegistryFilename NS_LITERAL_CSTRING("pluginreg.dat")
199 #ifdef PLUGIN_LOGGING
200 PRLogModuleInfo
* nsPluginLogging::gNPNLog
= nullptr;
201 PRLogModuleInfo
* nsPluginLogging::gNPPLog
= nullptr;
202 PRLogModuleInfo
* nsPluginLogging::gPluginLog
= nullptr;
205 // #defines for plugin cache and prefs
206 #define NS_PREF_MAX_NUM_CACHED_INSTANCES "browser.plugins.max_num_cached_plugins"
207 // Raise this from '10' to '50' to work around a bug in Apple's current Java
208 // plugins on OS X Lion and SnowLeopard. See bug 705931.
209 #define DEFAULT_NUMBER_OF_STOPPED_INSTANCES 50
211 nsIFile
*nsPluginHost::sPluginTempDir
;
212 nsPluginHost
*nsPluginHost::sInst
;
214 NS_IMPL_ISUPPORTS0(nsInvalidPluginTag
)
216 nsInvalidPluginTag::nsInvalidPluginTag(const char* aFullPath
, int64_t aLastModifiedTime
)
217 : mFullPath(aFullPath
),
218 mLastModifiedTime(aLastModifiedTime
),
222 nsInvalidPluginTag::~nsInvalidPluginTag()
225 // Helper to check for a MIME in a comma-delimited preference
227 IsTypeInList(nsCString
&aMimeType
, nsCString aTypeList
)
229 nsAutoCString searchStr
;
230 searchStr
.Assign(',');
231 searchStr
.Append(aTypeList
);
232 searchStr
.Append(',');
234 nsACString::const_iterator start
, end
;
236 searchStr
.BeginReading(start
);
237 searchStr
.EndReading(end
);
239 nsAutoCString commaSeparated
;
240 commaSeparated
.Assign(',');
241 commaSeparated
+= aMimeType
;
242 commaSeparated
.Append(',');
244 return FindInReadable(commaSeparated
, start
, end
);
247 // flat file reg funcs
249 bool ReadSectionHeader(nsPluginManifestLineReader
& reader
, const char *token
)
252 if (*reader
.LinePtr() == '[') {
253 char* p
= reader
.LinePtr() + (reader
.LineLength() - 1);
259 if (1 != reader
.ParseLine(values
, 1))
261 // ignore the leading '['
262 if (PL_strcmp(values
[0]+1, token
)) {
263 break; // it's wrong token
267 } while (reader
.NextLine());
271 static bool UnloadPluginsASAP()
273 return Preferences::GetBool("dom.ipc.plugins.unloadASAP", false);
276 nsPluginHost::nsPluginHost()
277 // No need to initialize members to nullptr, false etc because this class
278 // has a zeroing operator new.
280 // check to see if pref is set at startup to let plugins take over in
281 // full page mode for certain image mime types that we handle internally
282 mOverrideInternalTypes
=
283 Preferences::GetBool("plugin.override_internal_types", false);
285 mPluginsDisabled
= Preferences::GetBool("plugin.disable", false);
286 mPluginsClickToPlay
= Preferences::GetBool("plugins.click_to_play", false);
288 Preferences::AddStrongObserver(this, "plugin.disable");
289 Preferences::AddStrongObserver(this, "plugins.click_to_play");
291 nsCOMPtr
<nsIObserverService
> obsService
=
292 mozilla::services::GetObserverService();
294 obsService
->AddObserver(this, NS_XPCOM_SHUTDOWN_OBSERVER_ID
, false);
295 obsService
->AddObserver(this, "blocklist-updated", false);
296 #ifdef MOZ_WIDGET_ANDROID
297 obsService
->AddObserver(this, "application-foreground", false);
298 obsService
->AddObserver(this, "application-background", false);
302 #ifdef PLUGIN_LOGGING
303 nsPluginLogging::gNPNLog
= PR_NewLogModule(NPN_LOG_NAME
);
304 nsPluginLogging::gNPPLog
= PR_NewLogModule(NPP_LOG_NAME
);
305 nsPluginLogging::gPluginLog
= PR_NewLogModule(PLUGIN_LOG_NAME
);
307 PR_LOG(nsPluginLogging::gNPNLog
, PLUGIN_LOG_ALWAYS
,("NPN Logging Active!\n"));
308 PR_LOG(nsPluginLogging::gPluginLog
, PLUGIN_LOG_ALWAYS
,("General Plugin Logging Active! (nsPluginHost::ctor)\n"));
309 PR_LOG(nsPluginLogging::gNPPLog
, PLUGIN_LOG_ALWAYS
,("NPP Logging Active!\n"));
311 PLUGIN_LOG(PLUGIN_LOG_ALWAYS
,("nsPluginHost::ctor\n"));
316 nsPluginHost::~nsPluginHost()
318 PLUGIN_LOG(PLUGIN_LOG_ALWAYS
,("nsPluginHost::dtor\n"));
324 NS_IMPL_ISUPPORTS4(nsPluginHost
,
328 nsISupportsWeakReference
)
330 already_AddRefed
<nsPluginHost
>
331 nsPluginHost::GetInst()
334 sInst
= new nsPluginHost();
340 nsRefPtr
<nsPluginHost
> inst
= sInst
;
341 return inst
.forget();
344 bool nsPluginHost::IsRunningPlugin(nsPluginTag
* aPluginTag
)
346 if (!aPluginTag
|| !aPluginTag
->mPlugin
) {
350 for (uint32_t i
= 0; i
< mInstances
.Length(); i
++) {
351 nsNPAPIPluginInstance
*instance
= mInstances
[i
].get();
353 instance
->GetPlugin() == aPluginTag
->mPlugin
&&
354 instance
->IsRunning()) {
362 nsresult
nsPluginHost::ReloadPlugins()
364 PLUGIN_LOG(PLUGIN_LOG_NORMAL
,
365 ("nsPluginHost::ReloadPlugins Begin\n"));
369 // this will create the initial plugin list out of cache
370 // if it was not created yet
372 return LoadPlugins();
374 // we are re-scanning plugins. New plugins may have been added, also some
375 // plugins may have been removed, so we should probably shut everything down
376 // but don't touch running (active and not stopped) plugins
378 // check if plugins changed, no need to do anything else
379 // if no changes to plugins have been made
380 // false instructs not to touch the plugin list, just to
381 // look for possible changes
382 bool pluginschanged
= true;
383 FindPlugins(false, &pluginschanged
);
385 // if no changed detected, return an appropriate error code
387 return NS_ERROR_PLUGINS_PLUGINSNOTCHANGED
;
389 // shutdown plugins and kill the list if there are no running plugins
390 nsRefPtr
<nsPluginTag
> prev
;
391 nsRefPtr
<nsPluginTag
> next
;
393 for (nsRefPtr
<nsPluginTag
> p
= mPlugins
; p
!= nullptr;) {
396 // only remove our plugin from the list if it's not running.
397 if (!IsRunningPlugin(p
)) {
405 // attempt to unload plugins whenever they are removed from the list
406 p
->TryUnloadPlugin(false);
417 mPluginsLoaded
= false;
422 PLUGIN_LOG(PLUGIN_LOG_NORMAL
,
423 ("nsPluginHost::ReloadPlugins End\n"));
428 #define NS_RETURN_UASTRING_SIZE 128
430 nsresult
nsPluginHost::UserAgent(const char **retstring
)
432 static char resultString
[NS_RETURN_UASTRING_SIZE
];
435 nsCOMPtr
<nsIHttpProtocolHandler
> http
= do_GetService(NS_NETWORK_PROTOCOL_CONTRACTID_PREFIX
"http", &res
);
439 nsAutoCString uaString
;
440 res
= http
->GetUserAgent(uaString
);
442 if (NS_SUCCEEDED(res
)) {
443 if (NS_RETURN_UASTRING_SIZE
> uaString
.Length()) {
444 PL_strcpy(resultString
, uaString
.get());
446 // Copy as much of UA string as we can (terminate at right-most space).
447 PL_strncpy(resultString
, uaString
.get(), NS_RETURN_UASTRING_SIZE
);
448 for (int i
= NS_RETURN_UASTRING_SIZE
- 1; i
>= 0; i
--) {
450 resultString
[NS_RETURN_UASTRING_SIZE
- 1] = '\0';
452 else if (resultString
[i
] == ' ') {
453 resultString
[i
] = '\0';
458 *retstring
= resultString
;
461 *retstring
= nullptr;
464 PLUGIN_LOG(PLUGIN_LOG_NORMAL
, ("nsPluginHost::UserAgent return=%s\n", *retstring
));
469 nsresult
nsPluginHost::GetPrompt(nsIPluginInstanceOwner
*aOwner
, nsIPrompt
**aPrompt
)
472 nsCOMPtr
<nsIPrompt
> prompt
;
473 nsCOMPtr
<nsIWindowWatcher
> wwatch
= do_GetService(NS_WINDOWWATCHER_CONTRACTID
, &rv
);
476 nsCOMPtr
<nsIDOMWindow
> domWindow
;
478 nsCOMPtr
<nsIDocument
> document
;
479 aOwner
->GetDocument(getter_AddRefs(document
));
481 domWindow
= document
->GetWindow();
486 wwatch
->GetWindowByName(NS_LITERAL_STRING("_content").get(), nullptr, getter_AddRefs(domWindow
));
488 rv
= wwatch
->GetNewPrompter(domWindow
, getter_AddRefs(prompt
));
491 NS_IF_ADDREF(*aPrompt
= prompt
);
495 nsresult
nsPluginHost::GetURL(nsISupports
* pluginInst
,
498 nsNPAPIPluginStreamListener
* streamListener
,
500 const char* referrer
,
503 return GetURLWithHeaders(static_cast<nsNPAPIPluginInstance
*>(pluginInst
),
504 url
, target
, streamListener
, altHost
, referrer
,
505 forceJSEnabled
, 0, nullptr);
508 nsresult
nsPluginHost::GetURLWithHeaders(nsNPAPIPluginInstance
* pluginInst
,
511 nsNPAPIPluginStreamListener
* streamListener
,
513 const char* referrer
,
515 uint32_t getHeadersLength
,
516 const char* getHeaders
)
518 // we can only send a stream back to the plugin (as specified by a
519 // null target) if we also have a nsNPAPIPluginStreamListener to talk to
520 if (!target
&& !streamListener
)
521 return NS_ERROR_ILLEGAL_VALUE
;
523 nsresult rv
= DoURLLoadSecurityCheck(pluginInst
, url
);
528 nsRefPtr
<nsPluginInstanceOwner
> owner
= pluginInst
->GetOwner();
530 if ((0 == PL_strcmp(target
, "newwindow")) ||
531 (0 == PL_strcmp(target
, "_new")))
533 else if (0 == PL_strcmp(target
, "_current"))
536 rv
= owner
->GetURL(url
, target
, nullptr, nullptr, 0);
541 rv
= NewPluginURLStream(NS_ConvertUTF8toUTF16(url
), pluginInst
,
542 streamListener
, nullptr,
543 getHeaders
, getHeadersLength
);
548 nsresult
nsPluginHost::PostURL(nsISupports
* pluginInst
,
550 uint32_t postDataLen
,
551 const char* postData
,
554 nsNPAPIPluginStreamListener
* streamListener
,
556 const char* referrer
,
558 uint32_t postHeadersLength
,
559 const char* postHeaders
)
563 // we can only send a stream back to the plugin (as specified
564 // by a null target) if we also have a nsNPAPIPluginStreamListener
566 if (!target
&& !streamListener
)
567 return NS_ERROR_ILLEGAL_VALUE
;
569 nsNPAPIPluginInstance
* instance
= static_cast<nsNPAPIPluginInstance
*>(pluginInst
);
571 rv
= DoURLLoadSecurityCheck(instance
, url
);
575 nsCOMPtr
<nsIInputStream
> postStream
;
577 nsCOMPtr
<nsIFile
> file
;
578 rv
= CreateTempFileToPost(postData
, getter_AddRefs(file
));
582 nsCOMPtr
<nsIInputStream
> fileStream
;
583 rv
= NS_NewLocalFileInputStream(getter_AddRefs(fileStream
),
587 nsIFileInputStream::DELETE_ON_CLOSE
|
588 nsIFileInputStream::CLOSE_ON_EOF
);
592 rv
= NS_NewBufferedInputStream(getter_AddRefs(postStream
), fileStream
, 8192);
597 uint32_t newDataToPostLen
;
598 ParsePostBufferToFixHeaders(postData
, postDataLen
, &dataToPost
, &newDataToPostLen
);
600 return NS_ERROR_UNEXPECTED
;
602 nsCOMPtr
<nsIStringInputStream
> sis
= do_CreateInstance("@mozilla.org/io/string-input-stream;1", &rv
);
608 // data allocated by ParsePostBufferToFixHeaders() is managed and
609 // freed by the string stream.
610 postDataLen
= newDataToPostLen
;
611 sis
->AdoptData(dataToPost
, postDataLen
);
616 nsRefPtr
<nsPluginInstanceOwner
> owner
= instance
->GetOwner();
618 if ((0 == PL_strcmp(target
, "newwindow")) ||
619 (0 == PL_strcmp(target
, "_new"))) {
621 } else if (0 == PL_strcmp(target
, "_current")) {
624 rv
= owner
->GetURL(url
, target
, postStream
,
625 (void*)postHeaders
, postHeadersLength
);
629 // if we don't have a target, just create a stream. This does
632 rv
= NewPluginURLStream(NS_ConvertUTF8toUTF16(url
), instance
,
634 postStream
, postHeaders
, postHeadersLength
);
639 /* This method queries the prefs for proxy information.
640 * It has been tested and is known to work in the following three cases
641 * when no proxy host or port is specified
642 * when only the proxy host is specified
643 * when only the proxy port is specified
644 * This method conforms to the return code specified in
645 * http://developer.netscape.com/docs/manuals/proxy/adminnt/autoconf.htm#1020923
646 * with the exception that multiple values are not implemented.
649 nsresult
nsPluginHost::FindProxyForURL(const char* url
, char* *result
)
651 if (!url
|| !result
) {
652 return NS_ERROR_INVALID_ARG
;
656 nsCOMPtr
<nsIURI
> uriIn
;
657 nsCOMPtr
<nsIProtocolProxyService
> proxyService
;
658 nsCOMPtr
<nsIProtocolProxyService2
> proxyService2
;
659 nsCOMPtr
<nsIIOService
> ioService
;
661 proxyService
= do_GetService(NS_PROTOCOLPROXYSERVICE_CONTRACTID
, &res
);
662 if (NS_FAILED(res
) || !proxyService
)
665 proxyService2
= do_QueryInterface(proxyService
, &res
);
666 if (NS_FAILED(res
) || !proxyService2
)
669 ioService
= do_GetService(NS_IOSERVICE_CONTRACTID
, &res
);
670 if (NS_FAILED(res
) || !ioService
)
673 // make an nsURI from the argument url
674 res
= ioService
->NewURI(nsDependentCString(url
), nullptr, nullptr, getter_AddRefs(uriIn
));
678 nsCOMPtr
<nsIProxyInfo
> pi
;
680 // Remove this with bug 778201
681 res
= proxyService2
->DeprecatedBlockingResolve(uriIn
, 0, getter_AddRefs(pi
));
685 nsAutoCString host
, type
;
688 // These won't fail, and even if they do... we'll be ok.
695 if (!pi
|| host
.IsEmpty() || port
<= 0 || host
.EqualsLiteral("direct")) {
696 *result
= PL_strdup("DIRECT");
697 } else if (type
.EqualsLiteral("http")) {
698 *result
= PR_smprintf("PROXY %s:%d", host
.get(), port
);
699 } else if (type
.EqualsLiteral("socks4")) {
700 *result
= PR_smprintf("SOCKS %s:%d", host
.get(), port
);
701 } else if (type
.EqualsLiteral("socks")) {
702 // XXX - this is socks5, but there is no API for us to tell the
703 // plugin that fact. SOCKS for now, in case the proxy server
704 // speaks SOCKS4 as well. See bug 78176
705 // For a long time this was returning an http proxy type, so
706 // very little is probably broken by this
707 *result
= PR_smprintf("SOCKS %s:%d", host
.get(), port
);
709 NS_ASSERTION(false, "Unknown proxy type!");
710 *result
= PL_strdup("DIRECT");
713 if (nullptr == *result
)
714 res
= NS_ERROR_OUT_OF_MEMORY
;
719 nsresult
nsPluginHost::Init()
724 nsresult
nsPluginHost::UnloadPlugins()
726 PLUGIN_LOG(PLUGIN_LOG_NORMAL
, ("nsPluginHost::UnloadPlugins Called\n"));
731 // we should call nsIPluginInstance::Stop and nsIPluginInstance::SetWindow
732 // for those plugins who want it
733 DestroyRunningInstances(nullptr);
735 nsPluginTag
*pluginTag
;
736 for (pluginTag
= mPlugins
; pluginTag
; pluginTag
= pluginTag
->mNext
) {
737 pluginTag
->TryUnloadPlugin(true);
740 NS_ITERATIVE_UNREF_LIST(nsRefPtr
<nsPluginTag
>, mPlugins
, mNext
);
741 NS_ITERATIVE_UNREF_LIST(nsRefPtr
<nsPluginTag
>, mCachedPlugins
, mNext
);
742 NS_ITERATIVE_UNREF_LIST(nsRefPtr
<nsInvalidPluginTag
>, mInvalidPlugins
, mNext
);
744 // Lets remove any of the temporary files that we created.
745 if (sPluginTempDir
) {
746 sPluginTempDir
->Remove(true);
747 NS_RELEASE(sPluginTempDir
);
751 if (mPrivateDirServiceProvider
) {
752 nsCOMPtr
<nsIDirectoryService
> dirService
=
753 do_GetService(kDirectoryServiceContractID
);
755 dirService
->UnregisterProvider(mPrivateDirServiceProvider
);
756 mPrivateDirServiceProvider
= nullptr;
760 mPluginsLoaded
= false;
765 void nsPluginHost::OnPluginInstanceDestroyed(nsPluginTag
* aPluginTag
)
767 bool hasInstance
= false;
768 for (uint32_t i
= 0; i
< mInstances
.Length(); i
++) {
769 if (TagForPlugin(mInstances
[i
]->GetPlugin()) == aPluginTag
) {
775 // We have some options for unloading plugins if they have no instances.
777 // Unloading plugins immediately can be bad - some plugins retain state
778 // between instances even when there are none. This is largely limited to
779 // going from one page to another, so state is retained without an instance
780 // for only a very short period of time. In order to allow this to work
781 // we don't unload plugins immediately by default. This is supported
782 // via a hidden user pref though.
784 // Another reason not to unload immediately is that loading is expensive,
785 // and it is better to leave popular plugins loaded.
787 // Our default behavior is to try to unload a plugin three minutes after
788 // its last instance is destroyed. This seems like a reasonable compromise
789 // that allows us to reclaim memory while allowing short state retention
790 // and avoid perf hits for loading popular plugins.
792 if (UnloadPluginsASAP()) {
793 aPluginTag
->TryUnloadPlugin(false);
795 if (aPluginTag
->mUnloadTimer
) {
796 aPluginTag
->mUnloadTimer
->Cancel();
798 aPluginTag
->mUnloadTimer
= do_CreateInstance(NS_TIMER_CONTRACTID
);
800 aPluginTag
->mUnloadTimer
->InitWithCallback(this, 1000 * 60 * 3, nsITimer::TYPE_ONE_SHOT
);
806 nsPluginHost::GetPluginTempDir(nsIFile
**aDir
)
808 if (!sPluginTempDir
) {
809 nsCOMPtr
<nsIFile
> tmpDir
;
810 nsresult rv
= NS_GetSpecialDirectory(NS_OS_TEMP_DIR
,
811 getter_AddRefs(tmpDir
));
812 NS_ENSURE_SUCCESS(rv
, rv
);
814 rv
= tmpDir
->AppendNative(kPluginTmpDirName
);
816 // make it unique, and mode == 0700, not world-readable
817 rv
= tmpDir
->CreateUnique(nsIFile::DIRECTORY_TYPE
, 0700);
818 NS_ENSURE_SUCCESS(rv
, rv
);
820 tmpDir
.swap(sPluginTempDir
);
823 return sPluginTempDir
->Clone(aDir
);
827 nsPluginHost::InstantiatePluginInstance(const char *aMimeType
, nsIURI
* aURL
,
828 nsObjectLoadingContent
*aContent
,
829 nsPluginInstanceOwner
** aOwner
)
831 NS_ENSURE_ARG_POINTER(aOwner
);
833 #ifdef PLUGIN_LOGGING
834 nsAutoCString urlSpec
;
836 aURL
->GetAsciiSpec(urlSpec
);
838 PR_LOG(nsPluginLogging::gPluginLog
, PLUGIN_LOG_NORMAL
,
839 ("nsPluginHost::InstantiatePlugin Begin mime=%s, url=%s\n",
840 aMimeType
, urlSpec
.get()));
846 NS_NOTREACHED("Attempting to spawn a plugin with no mime type");
847 return NS_ERROR_FAILURE
;
850 nsRefPtr
<nsPluginInstanceOwner
> instanceOwner
= new nsPluginInstanceOwner();
851 if (!instanceOwner
) {
852 return NS_ERROR_OUT_OF_MEMORY
;
855 nsCOMPtr
<nsIContent
> ourContent
= do_QueryInterface(static_cast<nsIImageLoadingContent
*>(aContent
));
856 nsresult rv
= instanceOwner
->Init(ourContent
);
861 nsCOMPtr
<nsIPluginTagInfo
> pti
;
862 rv
= instanceOwner
->QueryInterface(kIPluginTagInfoIID
, getter_AddRefs(pti
));
867 nsPluginTagType tagType
;
868 rv
= pti
->GetTagType(&tagType
);
873 if (tagType
!= nsPluginTagType_Embed
&&
874 tagType
!= nsPluginTagType_Applet
&&
875 tagType
!= nsPluginTagType_Object
) {
876 return NS_ERROR_FAILURE
;
879 rv
= SetUpPluginInstance(aMimeType
, aURL
, instanceOwner
);
881 return NS_ERROR_FAILURE
;
884 nsRefPtr
<nsNPAPIPluginInstance
> instance
;
885 rv
= instanceOwner
->GetInstance(getter_AddRefs(instance
));
891 instanceOwner
->CreateWidget();
893 // If we've got a native window, the let the plugin know about it.
894 instanceOwner
->CallSetWindow();
897 // At this point we consider instantiation to be successful. Do not return an error.
898 instanceOwner
.forget(aOwner
);
900 #ifdef PLUGIN_LOGGING
901 nsAutoCString urlSpec2
;
902 if (aURL
!= nullptr) aURL
->GetAsciiSpec(urlSpec2
);
904 PR_LOG(nsPluginLogging::gPluginLog
, PLUGIN_LOG_NORMAL
,
905 ("nsPluginHost::InstantiatePlugin Finished mime=%s, rv=%d, url=%s\n",
906 aMimeType
, rv
, urlSpec2
.get()));
915 nsPluginHost::FindTagForLibrary(PRLibrary
* aLibrary
)
917 nsPluginTag
* pluginTag
;
918 for (pluginTag
= mPlugins
; pluginTag
; pluginTag
= pluginTag
->mNext
) {
919 if (pluginTag
->mLibrary
== aLibrary
) {
927 nsPluginHost::TagForPlugin(nsNPAPIPlugin
* aPlugin
)
929 nsPluginTag
* pluginTag
;
930 for (pluginTag
= mPlugins
; pluginTag
; pluginTag
= pluginTag
->mNext
) {
931 if (pluginTag
->mPlugin
== aPlugin
) {
935 // a plugin should never exist without a corresponding tag
936 NS_ERROR("TagForPlugin has failed");
940 nsresult
nsPluginHost::SetUpPluginInstance(const char *aMimeType
,
942 nsPluginInstanceOwner
*aOwner
)
944 NS_ENSURE_ARG_POINTER(aOwner
);
946 nsresult rv
= TrySetUpPluginInstance(aMimeType
, aURL
, aOwner
);
947 if (NS_SUCCEEDED(rv
)) {
951 // If we failed to load a plugin instance we'll try again after
952 // reloading our plugin list. Only do that once per document to
953 // avoid redundant high resource usage on pages with multiple
954 // unkown instance types. We'll do that by caching the document.
955 nsCOMPtr
<nsIDocument
> document
;
956 aOwner
->GetDocument(getter_AddRefs(document
));
958 nsCOMPtr
<nsIDocument
> currentdocument
= do_QueryReferent(mCurrentDocument
);
959 if (document
== currentdocument
) {
963 mCurrentDocument
= do_GetWeakReference(document
);
965 // Don't try to set up an instance again if nothing changed.
966 if (ReloadPlugins() == NS_ERROR_PLUGINS_PLUGINSNOTCHANGED
) {
970 return TrySetUpPluginInstance(aMimeType
, aURL
, aOwner
);
974 nsPluginHost::TrySetUpPluginInstance(const char *aMimeType
,
976 nsPluginInstanceOwner
*aOwner
)
978 #ifdef PLUGIN_LOGGING
979 nsAutoCString urlSpec
;
980 if (aURL
!= nullptr) aURL
->GetSpec(urlSpec
);
982 PR_LOG(nsPluginLogging::gPluginLog
, PLUGIN_LOG_NORMAL
,
983 ("nsPluginHost::TrySetupPluginInstance Begin mime=%s, owner=%p, url=%s\n",
984 aMimeType
, aOwner
, urlSpec
.get()));
989 nsRefPtr
<nsNPAPIPlugin
> plugin
;
990 GetPlugin(aMimeType
, getter_AddRefs(plugin
));
992 return NS_ERROR_FAILURE
;
995 nsPluginTag
* pluginTag
= FindPluginForType(aMimeType
, true);
997 NS_ASSERTION(pluginTag
, "Must have plugin tag here!");
999 #if defined(MOZ_WIDGET_ANDROID) && defined(MOZ_CRASHREPORTER)
1000 if (pluginTag
->mIsFlashPlugin
) {
1001 CrashReporter::AnnotateCrashReport(NS_LITERAL_CSTRING("FlashVersion"), pluginTag
->mVersion
);
1005 nsRefPtr
<nsNPAPIPluginInstance
> instance
= new nsNPAPIPluginInstance();
1007 // This will create the owning reference. The connection must be made between the
1008 // instance and the instance owner before initialization. Plugins can call into
1009 // the browser during initialization.
1010 aOwner
->SetInstance(instance
.get());
1012 // Add the instance to the instances list before we call NPP_New so that
1013 // it is "in play" before NPP_New happens. Take it out if NPP_New fails.
1014 mInstances
.AppendElement(instance
.get());
1016 // this should not addref the instance or owner
1017 // except in some cases not Java, see bug 140931
1018 // our COM pointer will free the peer
1019 nsresult rv
= instance
->Initialize(plugin
.get(), aOwner
, aMimeType
);
1020 if (NS_FAILED(rv
)) {
1021 mInstances
.RemoveElement(instance
.get());
1022 aOwner
->SetInstance(nullptr);
1026 // Cancel the plugin unload timer since we are creating
1027 // an instance for it.
1028 if (pluginTag
->mUnloadTimer
) {
1029 pluginTag
->mUnloadTimer
->Cancel();
1032 #ifdef PLUGIN_LOGGING
1033 nsAutoCString urlSpec2
;
1035 aURL
->GetSpec(urlSpec2
);
1037 PR_LOG(nsPluginLogging::gPluginLog
, PLUGIN_LOG_BASIC
,
1038 ("nsPluginHost::TrySetupPluginInstance Finished mime=%s, rv=%d, owner=%p, url=%s\n",
1039 aMimeType
, rv
, aOwner
, urlSpec2
.get()));
1048 nsPluginHost::PluginExistsForType(const char* aMimeType
)
1050 nsPluginTag
*plugin
= FindPluginForType(aMimeType
, false);
1051 return nullptr != plugin
;
1055 nsPluginHost::GetStateForType(const nsACString
&aMimeType
, uint32_t* aResult
)
1057 nsPluginTag
*plugin
= FindPluginForType(aMimeType
.Data(), true);
1059 return NS_ERROR_UNEXPECTED
;
1062 return plugin
->GetEnabledState(aResult
);
1066 nsPluginHost::GetBlocklistStateForType(const char *aMimeType
, uint32_t *aState
)
1068 nsPluginTag
*plugin
= FindPluginForType(aMimeType
, true);
1070 plugin
= FindPluginForType(aMimeType
, false);
1073 return NS_ERROR_FAILURE
;
1076 *aState
= plugin
->GetBlocklistState();
1081 nsPluginHost::GetPermissionStringForType(const nsACString
&aMimeType
, nsACString
&aPermissionString
)
1083 aPermissionString
.Truncate();
1084 uint32_t blocklistState
;
1085 nsresult rv
= GetBlocklistStateForType(aMimeType
.Data(), &blocklistState
);
1086 NS_ENSURE_SUCCESS(rv
, rv
);
1087 nsPluginTag
*tag
= FindPluginForType(aMimeType
.Data(), true);
1089 tag
= FindPluginForType(aMimeType
.Data(), false);
1092 return NS_ERROR_FAILURE
;
1095 if (blocklistState
== nsIBlocklistService::STATE_VULNERABLE_UPDATE_AVAILABLE
||
1096 blocklistState
== nsIBlocklistService::STATE_VULNERABLE_NO_UPDATE
) {
1097 aPermissionString
.AssignLiteral("plugin-vulnerable:");
1100 aPermissionString
.AssignLiteral("plugin:");
1103 aPermissionString
.Append(tag
->GetNiceFileName());
1108 // check comma delimitered extensions
1109 static int CompareExtensions(const char *aExtensionList
, const char *aExtension
)
1111 if (!aExtensionList
|| !aExtension
)
1114 const char *pExt
= aExtensionList
;
1115 const char *pComma
= strchr(pExt
, ',');
1117 return PL_strcasecmp(pExt
, aExtension
);
1119 int extlen
= strlen(aExtension
);
1121 int length
= pComma
- pExt
;
1122 if (length
== extlen
&& 0 == PL_strncasecmp(aExtension
, pExt
, length
))
1126 pComma
= strchr(pExt
, ',');
1130 return PL_strcasecmp(pExt
, aExtension
);
1134 nsPluginHost::IsPluginEnabledForExtension(const char* aExtension
,
1135 const char* &aMimeType
)
1137 nsPluginTag
*plugin
= FindPluginEnabledForExtension(aExtension
, aMimeType
);
1141 return NS_ERROR_FAILURE
;
1144 class DOMPluginImpl
: public nsIDOMPlugin
{
1148 DOMPluginImpl(nsPluginTag
* aPluginTag
) : mPluginTag(aPluginTag
)
1152 virtual ~DOMPluginImpl() {
1155 NS_METHOD
GetDescription(nsAString
& aDescription
)
1157 CopyUTF8toUTF16(mPluginTag
.mDescription
, aDescription
);
1161 NS_METHOD
GetFilename(nsAString
& aFilename
)
1163 CopyUTF8toUTF16(mPluginTag
.mFileName
, aFilename
);
1167 NS_METHOD
GetVersion(nsAString
& aVersion
)
1169 CopyUTF8toUTF16(mPluginTag
.mVersion
, aVersion
);
1173 NS_METHOD
GetName(nsAString
& aName
)
1175 CopyUTF8toUTF16(mPluginTag
.mName
, aName
);
1179 NS_METHOD
GetLength(uint32_t* aLength
)
1181 *aLength
= mPluginTag
.mMimeTypes
.Length();
1185 NS_METHOD
Item(uint32_t aIndex
, nsIDOMMimeType
** aReturn
)
1187 nsIDOMMimeType
* mimeType
= new DOMMimeTypeImpl(&mPluginTag
, aIndex
);
1188 NS_IF_ADDREF(mimeType
);
1189 *aReturn
= mimeType
;
1193 NS_METHOD
NamedItem(const nsAString
& aName
, nsIDOMMimeType
** aReturn
)
1195 for (int i
= mPluginTag
.mMimeTypes
.Length() - 1; i
>= 0; --i
) {
1196 if (aName
.Equals(NS_ConvertUTF8toUTF16(mPluginTag
.mMimeTypes
[i
])))
1197 return Item(i
, aReturn
);
1203 nsPluginTag mPluginTag
;
1206 NS_IMPL_ISUPPORTS1(DOMPluginImpl
, nsIDOMPlugin
)
1209 nsPluginHost::GetPluginCount(uint32_t* aPluginCount
)
1215 nsPluginTag
* plugin
= mPlugins
;
1216 while (plugin
!= nullptr) {
1217 if (plugin
->IsActive()) {
1220 plugin
= plugin
->mNext
;
1223 *aPluginCount
= count
;
1229 nsPluginHost::GetPlugins(uint32_t aPluginCount
, nsIDOMPlugin
** aPluginArray
)
1233 nsPluginTag
* plugin
= mPlugins
;
1234 for (uint32_t i
= 0; i
< aPluginCount
&& plugin
; plugin
= plugin
->mNext
) {
1235 if (plugin
->IsActive()) {
1236 nsIDOMPlugin
* domPlugin
= new DOMPluginImpl(plugin
);
1237 NS_IF_ADDREF(domPlugin
);
1238 aPluginArray
[i
++] = domPlugin
;
1246 nsPluginHost::GetPluginTags(uint32_t* aPluginCount
, nsIPluginTag
*** aResults
)
1251 nsRefPtr
<nsPluginTag
> plugin
= mPlugins
;
1252 while (plugin
!= nullptr) {
1254 plugin
= plugin
->mNext
;
1257 *aResults
= static_cast<nsIPluginTag
**>
1258 (nsMemory::Alloc(count
* sizeof(**aResults
)));
1260 return NS_ERROR_OUT_OF_MEMORY
;
1262 *aPluginCount
= count
;
1265 for (uint32_t i
= 0; i
< count
; i
++) {
1266 (*aResults
)[i
] = plugin
;
1267 NS_ADDREF((*aResults
)[i
]);
1268 plugin
= plugin
->mNext
;
1275 nsPluginHost::FindPreferredPlugin(const InfallibleTArray
<nsPluginTag
*>& matches
)
1277 // We prefer the plugin with the highest version number.
1278 /// XXX(johns): This seems to assume the only time multiple plugins will have
1279 /// the same MIME type is if they're multiple versions of the same
1280 /// plugin -- but since plugin filenames and pretty names can both
1281 /// update, it's probably less arbitrary than just going at it
1284 if (matches
.IsEmpty()) {
1288 nsPluginTag
*preferredPlugin
= matches
[0];
1289 for (unsigned int i
= 1; i
< matches
.Length(); i
++) {
1290 if (mozilla::Version(matches
[i
]->mVersion
.get()) > preferredPlugin
->mVersion
.get()) {
1291 preferredPlugin
= matches
[i
];
1295 return preferredPlugin
;
1299 nsPluginHost::FindPluginForType(const char* aMimeType
,
1308 InfallibleTArray
<nsPluginTag
*> matchingPlugins
;
1310 nsPluginTag
*plugin
= mPlugins
;
1312 if (!aCheckEnabled
|| plugin
->IsActive()) {
1313 int32_t mimeCount
= plugin
->mMimeTypes
.Length();
1314 for (int32_t i
= 0; i
< mimeCount
; i
++) {
1315 if (0 == PL_strcasecmp(plugin
->mMimeTypes
[i
].get(), aMimeType
)) {
1316 matchingPlugins
.AppendElement(plugin
);
1321 plugin
= plugin
->mNext
;
1324 return FindPreferredPlugin(matchingPlugins
);
1328 nsPluginHost::FindPluginEnabledForExtension(const char* aExtension
,
1329 const char*& aMimeType
)
1337 InfallibleTArray
<nsPluginTag
*> matchingPlugins
;
1339 nsPluginTag
*plugin
= mPlugins
;
1341 if (plugin
->IsActive()) {
1342 int32_t variants
= plugin
->mExtensions
.Length();
1343 for (int32_t i
= 0; i
< variants
; i
++) {
1344 // mExtensionsArray[cnt] is a list of extensions separated by commas
1345 if (0 == CompareExtensions(plugin
->mExtensions
[i
].get(), aExtension
)) {
1346 matchingPlugins
.AppendElement(plugin
);
1351 plugin
= plugin
->mNext
;
1354 nsPluginTag
*preferredPlugin
= FindPreferredPlugin(matchingPlugins
);
1355 if (!preferredPlugin
) {
1359 int32_t variants
= preferredPlugin
->mExtensions
.Length();
1360 for (int32_t i
= 0; i
< variants
; i
++) {
1361 // mExtensionsArray[cnt] is a list of extensions separated by commas
1362 if (0 == CompareExtensions(preferredPlugin
->mExtensions
[i
].get(), aExtension
)) {
1363 aMimeType
= preferredPlugin
->mMimeTypes
[i
].get();
1368 return preferredPlugin
;
1371 static nsresult
CreateNPAPIPlugin(nsPluginTag
*aPluginTag
,
1372 nsNPAPIPlugin
**aOutNPAPIPlugin
)
1374 // If this is an in-process plugin we'll need to load it here if we haven't already.
1375 if (!nsNPAPIPlugin::RunPluginOOP(aPluginTag
)) {
1376 if (aPluginTag
->mFullPath
.IsEmpty())
1377 return NS_ERROR_FAILURE
;
1378 nsCOMPtr
<nsIFile
> file
= do_CreateInstance("@mozilla.org/file/local;1");
1379 file
->InitWithPath(NS_ConvertUTF8toUTF16(aPluginTag
->mFullPath
));
1380 nsPluginFile
pluginFile(file
);
1381 PRLibrary
* pluginLibrary
= NULL
;
1383 if (NS_FAILED(pluginFile
.LoadPlugin(&pluginLibrary
)) || !pluginLibrary
)
1384 return NS_ERROR_FAILURE
;
1386 aPluginTag
->mLibrary
= pluginLibrary
;
1390 rv
= nsNPAPIPlugin::CreatePlugin(aPluginTag
, aOutNPAPIPlugin
);
1395 nsresult
nsPluginHost::EnsurePluginLoaded(nsPluginTag
* aPluginTag
)
1397 nsRefPtr
<nsNPAPIPlugin
> plugin
= aPluginTag
->mPlugin
;
1399 nsresult rv
= CreateNPAPIPlugin(aPluginTag
, getter_AddRefs(plugin
));
1400 if (NS_FAILED(rv
)) {
1403 aPluginTag
->mPlugin
= plugin
;
1408 nsresult
nsPluginHost::GetPlugin(const char *aMimeType
, nsNPAPIPlugin
** aPlugin
)
1410 nsresult rv
= NS_ERROR_FAILURE
;
1414 return NS_ERROR_ILLEGAL_VALUE
;
1416 // If plugins haven't been scanned yet, do so now
1419 nsPluginTag
* pluginTag
= FindPluginForType(aMimeType
, true);
1422 PLUGIN_LOG(PLUGIN_LOG_BASIC
,
1423 ("nsPluginHost::GetPlugin Begin mime=%s, plugin=%s\n",
1424 aMimeType
, pluginTag
->mFileName
.get()));
1427 if (aMimeType
&& !pluginTag
->mFileName
.IsEmpty())
1428 printf("For %s found plugin %s\n", aMimeType
, pluginTag
->mFileName
.get());
1431 rv
= EnsurePluginLoaded(pluginTag
);
1432 if (NS_FAILED(rv
)) {
1436 NS_ADDREF(*aPlugin
= pluginTag
->mPlugin
);
1440 PLUGIN_LOG(PLUGIN_LOG_NORMAL
,
1441 ("nsPluginHost::GetPlugin End mime=%s, rv=%d, plugin=%p name=%s\n",
1442 aMimeType
, rv
, *aPlugin
,
1443 (pluginTag
? pluginTag
->mFileName
.get() : "(not found)")));
1448 // Normalize 'host' to ACE.
1450 nsPluginHost::NormalizeHostname(nsCString
& host
)
1452 if (IsASCII(host
)) {
1459 mIDNService
= do_GetService(NS_IDNSERVICE_CONTRACTID
, &rv
);
1460 NS_ENSURE_SUCCESS(rv
, rv
);
1463 return mIDNService
->ConvertUTF8toACE(host
, host
);
1466 // Enumerate a 'sites' array returned by GetSitesWithData and determine if
1467 // any of them have a base domain in common with 'domain'; if so, append them
1468 // to the 'result' array. If 'firstMatchOnly' is true, return after finding the
1471 nsPluginHost::EnumerateSiteData(const nsACString
& domain
,
1472 const InfallibleTArray
<nsCString
>& sites
,
1473 InfallibleTArray
<nsCString
>& result
,
1474 bool firstMatchOnly
)
1476 NS_ASSERTION(!domain
.IsVoid(), "null domain string");
1480 mTLDService
= do_GetService(NS_EFFECTIVETLDSERVICE_CONTRACTID
, &rv
);
1481 NS_ENSURE_SUCCESS(rv
, rv
);
1484 // Get the base domain from the domain.
1485 nsCString baseDomain
;
1486 rv
= mTLDService
->GetBaseDomainFromHost(domain
, 0, baseDomain
);
1487 bool isIP
= rv
== NS_ERROR_HOST_IS_IP_ADDRESS
;
1488 if (isIP
|| rv
== NS_ERROR_INSUFFICIENT_DOMAIN_LEVELS
) {
1489 // The base domain is the site itself. However, we must be careful to
1491 baseDomain
= domain
;
1492 rv
= NormalizeHostname(baseDomain
);
1493 NS_ENSURE_SUCCESS(rv
, rv
);
1494 } else if (NS_FAILED(rv
)) {
1498 // Enumerate the array of sites with data.
1499 for (uint32_t i
= 0; i
< sites
.Length(); ++i
) {
1500 const nsCString
& site
= sites
[i
];
1502 // Check if the site is an IP address.
1504 site
.Length() >= 2 && site
.First() == '[' && site
.Last() == ']';
1505 if (siteIsIP
!= isIP
)
1508 nsCString siteBaseDomain
;
1511 siteBaseDomain
= Substring(site
, 1, site
.Length() - 2);
1513 // Determine the base domain of the site.
1514 rv
= mTLDService
->GetBaseDomainFromHost(site
, 0, siteBaseDomain
);
1515 if (rv
== NS_ERROR_INSUFFICIENT_DOMAIN_LEVELS
) {
1516 // The base domain is the site itself. However, we must be careful to
1518 siteBaseDomain
= site
;
1519 rv
= NormalizeHostname(siteBaseDomain
);
1520 NS_ENSURE_SUCCESS(rv
, rv
);
1521 } else if (NS_FAILED(rv
)) {
1526 // At this point, we can do an exact comparison of the two domains.
1527 if (baseDomain
!= siteBaseDomain
) {
1531 // Append the site to the result array.
1532 result
.AppendElement(site
);
1534 // If we're supposed to return early, do so.
1535 if (firstMatchOnly
) {
1544 nsPluginHost::RegisterPlayPreviewMimeType(const nsACString
& mimeType
,
1546 const nsACString
& redirectURL
)
1548 nsAutoCString
mt(mimeType
);
1549 nsAutoCString
url(redirectURL
);
1550 if (url
.Length() == 0) {
1551 // using default play preview iframe URL, if redirectURL is not specified
1552 url
.Assign("data:application/x-moz-playpreview;,");
1553 url
.Append(mimeType
);
1556 nsRefPtr
<nsPluginPlayPreviewInfo
> playPreview
=
1557 new nsPluginPlayPreviewInfo(mt
.get(), ignoreCTP
, url
.get());
1558 mPlayPreviewMimeTypes
.AppendElement(playPreview
);
1563 nsPluginHost::UnregisterPlayPreviewMimeType(const nsACString
& mimeType
)
1565 nsAutoCString
mimeTypeToRemove(mimeType
);
1566 for (uint32_t i
= mPlayPreviewMimeTypes
.Length(); i
> 0; i
--) {
1567 nsRefPtr
<nsPluginPlayPreviewInfo
> pp
= mPlayPreviewMimeTypes
[i
- 1];
1568 if (PL_strcasecmp(pp
.get()->mMimeType
.get(), mimeTypeToRemove
.get()) == 0) {
1569 mPlayPreviewMimeTypes
.RemoveElementAt(i
- 1);
1577 nsPluginHost::GetPlayPreviewInfo(const nsACString
& mimeType
,
1578 nsIPluginPlayPreviewInfo
** aResult
)
1580 nsAutoCString
mimeTypeToFind(mimeType
);
1581 for (uint32_t i
= 0; i
< mPlayPreviewMimeTypes
.Length(); i
++) {
1582 nsRefPtr
<nsPluginPlayPreviewInfo
> pp
= mPlayPreviewMimeTypes
[i
];
1583 if (PL_strcasecmp(pp
.get()->mMimeType
.get(), mimeTypeToFind
.get()) == 0) {
1584 *aResult
= new nsPluginPlayPreviewInfo(pp
.get());
1585 NS_ADDREF(*aResult
);
1590 return NS_ERROR_NOT_AVAILABLE
;
1594 nsPluginHost::ClearSiteData(nsIPluginTag
* plugin
, const nsACString
& domain
,
1595 uint64_t flags
, int64_t maxAge
)
1597 // maxAge must be either a nonnegative integer or -1.
1598 NS_ENSURE_ARG(maxAge
>= 0 || maxAge
== -1);
1600 // Caller may give us a tag object that is no longer live.
1601 if (!IsLiveTag(plugin
)) {
1602 return NS_ERROR_NOT_AVAILABLE
;
1605 nsPluginTag
* tag
= static_cast<nsPluginTag
*>(plugin
);
1607 // We only ensure support for clearing Flash site data for now.
1608 // We will also attempt to clear data for any plugin that happens
1609 // to be loaded already.
1610 if (!tag
->mIsFlashPlugin
&& !tag
->mPlugin
) {
1611 return NS_ERROR_FAILURE
;
1614 // Make sure the plugin is loaded.
1615 nsresult rv
= EnsurePluginLoaded(tag
);
1616 if (NS_FAILED(rv
)) {
1620 PluginLibrary
* library
= tag
->mPlugin
->GetLibrary();
1622 // If 'domain' is the null string, clear everything.
1623 if (domain
.IsVoid()) {
1624 return library
->NPP_ClearSiteData(NULL
, flags
, maxAge
);
1627 // Get the list of sites from the plugin.
1628 InfallibleTArray
<nsCString
> sites
;
1629 rv
= library
->NPP_GetSitesWithData(sites
);
1630 NS_ENSURE_SUCCESS(rv
, rv
);
1632 // Enumerate the sites and build a list of matches.
1633 InfallibleTArray
<nsCString
> matches
;
1634 rv
= EnumerateSiteData(domain
, sites
, matches
, false);
1635 NS_ENSURE_SUCCESS(rv
, rv
);
1637 // Clear the matches.
1638 for (uint32_t i
= 0; i
< matches
.Length(); ++i
) {
1639 const nsCString
& match
= matches
[i
];
1640 rv
= library
->NPP_ClearSiteData(match
.get(), flags
, maxAge
);
1641 NS_ENSURE_SUCCESS(rv
, rv
);
1648 nsPluginHost::SiteHasData(nsIPluginTag
* plugin
, const nsACString
& domain
,
1651 // Caller may give us a tag object that is no longer live.
1652 if (!IsLiveTag(plugin
)) {
1653 return NS_ERROR_NOT_AVAILABLE
;
1656 nsPluginTag
* tag
= static_cast<nsPluginTag
*>(plugin
);
1658 // We only ensure support for clearing Flash site data for now.
1659 // We will also attempt to clear data for any plugin that happens
1660 // to be loaded already.
1661 if (!tag
->mIsFlashPlugin
&& !tag
->mPlugin
) {
1662 return NS_ERROR_FAILURE
;
1665 // Make sure the plugin is loaded.
1666 nsresult rv
= EnsurePluginLoaded(tag
);
1667 if (NS_FAILED(rv
)) {
1671 PluginLibrary
* library
= tag
->mPlugin
->GetLibrary();
1673 // Get the list of sites from the plugin.
1674 InfallibleTArray
<nsCString
> sites
;
1675 rv
= library
->NPP_GetSitesWithData(sites
);
1676 NS_ENSURE_SUCCESS(rv
, rv
);
1678 // If there's no data, we're done.
1679 if (sites
.IsEmpty()) {
1684 // If 'domain' is the null string, and there's data for at least one site,
1686 if (domain
.IsVoid()) {
1691 // Enumerate the sites and determine if there's a match.
1692 InfallibleTArray
<nsCString
> matches
;
1693 rv
= EnumerateSiteData(domain
, sites
, matches
, true);
1694 NS_ENSURE_SUCCESS(rv
, rv
);
1696 *result
= !matches
.IsEmpty();
1700 bool nsPluginHost::IsJavaMIMEType(const char* aType
)
1703 ((0 == PL_strncasecmp(aType
, "application/x-java-vm",
1704 sizeof("application/x-java-vm") - 1)) ||
1705 (0 == PL_strncasecmp(aType
, "application/x-java-applet",
1706 sizeof("application/x-java-applet") - 1)) ||
1707 (0 == PL_strncasecmp(aType
, "application/x-java-bean",
1708 sizeof("application/x-java-bean") - 1)));
1711 // Check whether or not a tag is a live, valid tag, and that it's loaded.
1713 nsPluginHost::IsLiveTag(nsIPluginTag
* aPluginTag
)
1716 for (tag
= mPlugins
; tag
; tag
= tag
->mNext
) {
1717 if (tag
== aPluginTag
) {
1725 nsPluginHost::HaveSamePlugin(const nsPluginTag
* aPluginTag
)
1727 for (nsPluginTag
* tag
= mPlugins
; tag
; tag
= tag
->mNext
) {
1728 if (tag
->HasSameNameAndMimes(aPluginTag
)) {
1736 nsPluginHost::FirstPluginWithPath(const nsCString
& path
)
1738 for (nsPluginTag
* tag
= mPlugins
; tag
; tag
= tag
->mNext
) {
1739 if (tag
->mFullPath
.Equals(path
)) {
1748 int64_t GetPluginLastModifiedTime(const nsCOMPtr
<nsIFile
>& localfile
)
1750 PRTime fileModTime
= 0;
1752 #if defined(XP_MACOSX)
1753 // On OS X the date of a bundle's "contents" (i.e. of its Info.plist file)
1754 // is a much better guide to when it was last modified than the date of
1755 // its package directory. See bug 313700.
1756 nsCOMPtr
<nsILocalFileMac
> localFileMac
= do_QueryInterface(localfile
);
1758 localFileMac
->GetBundleContentsLastModifiedTime(&fileModTime
);
1760 localfile
->GetLastModifiedTime(&fileModTime
);
1763 localfile
->GetLastModifiedTime(&fileModTime
);
1769 struct CompareFilesByTime
1772 LessThan(const nsCOMPtr
<nsIFile
>& a
, const nsCOMPtr
<nsIFile
>& b
) const
1774 return GetPluginLastModifiedTime(a
) < GetPluginLastModifiedTime(b
);
1778 Equals(const nsCOMPtr
<nsIFile
>& a
, const nsCOMPtr
<nsIFile
>& b
) const
1780 return GetPluginLastModifiedTime(a
) == GetPluginLastModifiedTime(b
);
1784 } // anonymous namespace
1786 typedef NS_NPAPIPLUGIN_CALLBACK(char *, NP_GETMIMEDESCRIPTION
)(void);
1788 nsresult
nsPluginHost::ScanPluginsDirectory(nsIFile
*pluginsDir
,
1789 bool aCreatePluginList
,
1790 bool *aPluginsChanged
)
1792 NS_ENSURE_ARG_POINTER(aPluginsChanged
);
1795 *aPluginsChanged
= false;
1797 #ifdef PLUGIN_LOGGING
1798 nsAutoCString dirPath
;
1799 pluginsDir
->GetNativePath(dirPath
);
1800 PLUGIN_LOG(PLUGIN_LOG_BASIC
,
1801 ("nsPluginHost::ScanPluginsDirectory dir=%s\n", dirPath
.get()));
1804 nsCOMPtr
<nsISimpleEnumerator
> iter
;
1805 rv
= pluginsDir
->GetDirectoryEntries(getter_AddRefs(iter
));
1809 nsAutoTArray
<nsCOMPtr
<nsIFile
>, 6> pluginFiles
;
1812 while (NS_SUCCEEDED(iter
->HasMoreElements(&hasMore
)) && hasMore
) {
1813 nsCOMPtr
<nsISupports
> supports
;
1814 rv
= iter
->GetNext(getter_AddRefs(supports
));
1817 nsCOMPtr
<nsIFile
> dirEntry(do_QueryInterface(supports
, &rv
));
1821 // Sun's JRE 1.3.1 plugin must have symbolic links resolved or else it'll crash.
1823 dirEntry
->Normalize();
1825 if (nsPluginsDir::IsPluginFile(dirEntry
)) {
1826 pluginFiles
.AppendElement(dirEntry
);
1830 pluginFiles
.Sort(CompareFilesByTime());
1832 bool warnOutdated
= false;
1834 for (int32_t i
= (pluginFiles
.Length() - 1); i
>= 0; i
--) {
1835 nsCOMPtr
<nsIFile
>& localfile
= pluginFiles
[i
];
1837 nsString utf16FilePath
;
1838 rv
= localfile
->GetPath(utf16FilePath
);
1842 int64_t fileModTime
= GetPluginLastModifiedTime(localfile
);
1844 // Look for it in our cache
1845 NS_ConvertUTF16toUTF8
filePath(utf16FilePath
);
1846 nsRefPtr
<nsPluginTag
> pluginTag
;
1847 RemoveCachedPluginsInfo(filePath
.get(), getter_AddRefs(pluginTag
));
1849 bool seenBefore
= false;
1853 // If plugin changed, delete cachedPluginTag and don't use cache
1854 if (fileModTime
!= pluginTag
->mLastModifiedTime
) {
1855 // Plugins has changed. Don't use cached plugin info.
1856 pluginTag
= nullptr;
1858 // plugin file changed, flag this fact
1859 *aPluginsChanged
= true;
1862 // If we're not creating a list and we already know something changed then
1864 if (!aCreatePluginList
) {
1865 if (*aPluginsChanged
) {
1872 bool isKnownInvalidPlugin
= false;
1873 for (nsRefPtr
<nsInvalidPluginTag
> invalidPlugins
= mInvalidPlugins
;
1874 invalidPlugins
; invalidPlugins
= invalidPlugins
->mNext
) {
1875 // If already marked as invalid, ignore it
1876 if (invalidPlugins
->mFullPath
.Equals(filePath
.get()) &&
1877 invalidPlugins
->mLastModifiedTime
== fileModTime
) {
1878 if (aCreatePluginList
) {
1879 invalidPlugins
->mSeen
= true;
1881 isKnownInvalidPlugin
= true;
1885 if (isKnownInvalidPlugin
) {
1889 // if it is not found in cache info list or has been changed, create a new one
1891 nsPluginFile
pluginFile(localfile
);
1893 // create a tag describing this plugin.
1894 PRLibrary
*library
= nullptr;
1896 memset(&info
, 0, sizeof(info
));
1898 // Opening a block for the telemetry AutoTimer
1900 Telemetry::AutoTimer
<Telemetry::PLUGIN_LOAD_METADATA
> telemetry
;
1901 res
= pluginFile
.GetPluginInfo(info
, &library
);
1903 // if we don't have mime type don't proceed, this is not a plugin
1904 if (NS_FAILED(res
) || !info
.fMimeTypeArray
) {
1905 nsRefPtr
<nsInvalidPluginTag
> invalidTag
= new nsInvalidPluginTag(filePath
.get(),
1907 pluginFile
.FreePluginInfo(info
);
1909 if (aCreatePluginList
) {
1910 invalidTag
->mSeen
= true;
1912 invalidTag
->mNext
= mInvalidPlugins
;
1913 if (mInvalidPlugins
) {
1914 mInvalidPlugins
->mPrev
= invalidTag
;
1916 mInvalidPlugins
= invalidTag
;
1918 // Mark aPluginsChanged so pluginreg is rewritten
1919 *aPluginsChanged
= true;
1923 pluginTag
= new nsPluginTag(&info
);
1924 pluginFile
.FreePluginInfo(info
);
1926 return NS_ERROR_OUT_OF_MEMORY
;
1928 pluginTag
->mLibrary
= library
;
1929 pluginTag
->mLastModifiedTime
= fileModTime
;
1930 uint32_t state
= pluginTag
->GetBlocklistState();
1932 // If the blocklist says it is risky and we have never seen this
1933 // plugin before, then disable it.
1934 // If the blocklist says this is an outdated plugin, warn about
1935 // outdated plugins.
1936 if (state
== nsIBlocklistService::STATE_SOFTBLOCKED
&& !seenBefore
) {
1937 pluginTag
->SetEnabledState(nsIPluginTag::STATE_DISABLED
);
1939 if (state
== nsIBlocklistService::STATE_OUTDATED
&& !seenBefore
) {
1940 warnOutdated
= true;
1943 // Plugin unloading is tag-based. If we created a new tag and loaded
1944 // the library in the process then we want to attempt to unload it here.
1945 // Only do this if the pref is set for aggressive unloading.
1946 if (UnloadPluginsASAP()) {
1947 pluginTag
->TryUnloadPlugin(false);
1951 // do it if we still want it
1953 // We have a valid new plugin so report that plugins have changed.
1954 *aPluginsChanged
= true;
1957 // Avoid adding different versions of the same plugin if they are running
1958 // in-process, otherwise we risk undefined behaviour.
1959 if (!nsNPAPIPlugin::RunPluginOOP(pluginTag
)) {
1960 if (HaveSamePlugin(pluginTag
)) {
1965 // Don't add the same plugin again if it hasn't changed
1966 if (nsPluginTag
* duplicate
= FirstPluginWithPath(pluginTag
->mFullPath
)) {
1967 if (pluginTag
->mLastModifiedTime
== duplicate
->mLastModifiedTime
) {
1972 // If we're not creating a plugin list, simply looking for changes,
1974 if (!aCreatePluginList
) {
1978 // Add plugin tags such that the list is ordered by modification date,
1979 // newest to oldest. This is ugly, it'd be easier with just about anything
1980 // other than a single-directional linked list.
1982 nsPluginTag
*prev
= nullptr;
1983 nsPluginTag
*next
= mPlugins
;
1985 if (pluginTag
->mLastModifiedTime
>= next
->mLastModifiedTime
) {
1986 pluginTag
->mNext
= next
;
1988 prev
->mNext
= pluginTag
;
1990 mPlugins
= pluginTag
;
1997 prev
->mNext
= pluginTag
;
2001 mPlugins
= pluginTag
;
2004 if (pluginTag
->IsActive()) {
2005 nsAdoptingCString disableFullPage
=
2006 Preferences::GetCString(kPrefDisableFullPage
);
2007 for (uint32_t i
= 0; i
< pluginTag
->mMimeTypes
.Length(); i
++) {
2008 if (!IsTypeInList(pluginTag
->mMimeTypes
[i
], disableFullPage
)) {
2009 RegisterWithCategoryManager(pluginTag
->mMimeTypes
[i
],
2017 Preferences::SetBool("plugins.update.notifyUser", true);
2023 nsresult
nsPluginHost::ScanPluginsDirectoryList(nsISimpleEnumerator
*dirEnum
,
2024 bool aCreatePluginList
,
2025 bool *aPluginsChanged
)
2028 while (NS_SUCCEEDED(dirEnum
->HasMoreElements(&hasMore
)) && hasMore
) {
2029 nsCOMPtr
<nsISupports
> supports
;
2030 nsresult rv
= dirEnum
->GetNext(getter_AddRefs(supports
));
2033 nsCOMPtr
<nsIFile
> nextDir(do_QueryInterface(supports
, &rv
));
2037 // don't pass aPluginsChanged directly to prevent it from been reset
2038 bool pluginschanged
= false;
2039 ScanPluginsDirectory(nextDir
, aCreatePluginList
, &pluginschanged
);
2042 *aPluginsChanged
= true;
2044 // if changes are detected and we are not creating the list, do not proceed
2045 if (!aCreatePluginList
&& *aPluginsChanged
)
2051 nsresult
nsPluginHost::LoadPlugins()
2054 if (XRE_GetProcessType() == GeckoProcessType_Content
) {
2058 // do not do anything if it is already done
2059 // use ReloadPlugins() to enforce loading
2063 if (mPluginsDisabled
)
2066 bool pluginschanged
;
2067 nsresult rv
= FindPlugins(true, &pluginschanged
);
2071 // only if plugins have changed will we notify plugin-change observers
2072 if (pluginschanged
) {
2073 nsCOMPtr
<nsIObserverService
> obsService
=
2074 mozilla::services::GetObserverService();
2076 obsService
->NotifyObservers(nullptr, "plugins-list-updated", nullptr);
2082 // if aCreatePluginList is false we will just scan for plugins
2083 // and see if any changes have been made to the plugins.
2084 // This is needed in ReloadPlugins to prevent possible recursive reloads
2085 nsresult
nsPluginHost::FindPlugins(bool aCreatePluginList
, bool * aPluginsChanged
)
2087 Telemetry::AutoTimer
<Telemetry::FIND_PLUGINS
> telemetry
;
2089 NS_ENSURE_ARG_POINTER(aPluginsChanged
);
2091 *aPluginsChanged
= false;
2094 // Read cached plugins info. If the profile isn't yet available then don't
2096 if (ReadPluginInfo() == NS_ERROR_NOT_AVAILABLE
)
2100 // Failure here is not a show-stopper so just warn.
2101 rv
= EnsurePrivateDirServiceProvider();
2102 NS_ASSERTION(NS_SUCCEEDED(rv
), "Failed to register dir service provider.");
2105 nsCOMPtr
<nsIProperties
> dirService(do_GetService(kDirectoryServiceContractID
, &rv
));
2109 nsCOMPtr
<nsISimpleEnumerator
> dirList
;
2111 // Scan plugins directories;
2112 // don't pass aPluginsChanged directly, to prevent its
2113 // possible reset in subsequent ScanPluginsDirectory calls
2114 bool pluginschanged
= false;
2116 // Scan the app-defined list of plugin dirs.
2117 rv
= dirService
->Get(NS_APP_PLUGINS_DIR_LIST
, NS_GET_IID(nsISimpleEnumerator
), getter_AddRefs(dirList
));
2118 if (NS_SUCCEEDED(rv
)) {
2119 ScanPluginsDirectoryList(dirList
, aCreatePluginList
, &pluginschanged
);
2122 *aPluginsChanged
= true;
2124 // if we are just looking for possible changes,
2125 // no need to proceed if changes are detected
2126 if (!aCreatePluginList
&& *aPluginsChanged
) {
2127 NS_ITERATIVE_UNREF_LIST(nsRefPtr
<nsPluginTag
>, mCachedPlugins
, mNext
);
2128 NS_ITERATIVE_UNREF_LIST(nsRefPtr
<nsInvalidPluginTag
>, mInvalidPlugins
, mNext
);
2133 LOG("getting plugins dir failed");
2137 mPluginsLoaded
= true; // at this point 'some' plugins have been loaded,
2138 // the rest is optional
2141 bool bScanPLIDs
= Preferences::GetBool("plugin.scan.plid.all", false);
2143 // Now lets scan any PLID directories
2144 if (bScanPLIDs
&& mPrivateDirServiceProvider
) {
2145 rv
= mPrivateDirServiceProvider
->GetPLIDDirectories(getter_AddRefs(dirList
));
2146 if (NS_SUCCEEDED(rv
)) {
2147 ScanPluginsDirectoryList(dirList
, aCreatePluginList
, &pluginschanged
);
2150 *aPluginsChanged
= true;
2152 // if we are just looking for possible changes,
2153 // no need to proceed if changes are detected
2154 if (!aCreatePluginList
&& *aPluginsChanged
) {
2155 NS_ITERATIVE_UNREF_LIST(nsRefPtr
<nsPluginTag
>, mCachedPlugins
, mNext
);
2156 NS_ITERATIVE_UNREF_LIST(nsRefPtr
<nsInvalidPluginTag
>, mInvalidPlugins
, mNext
);
2163 // Scan the installation paths of our popular plugins if the prefs are enabled
2165 // This table controls the order of scanning
2166 const char* const prefs
[] = {NS_WIN_ACROBAT_SCAN_KEY
,
2167 NS_WIN_QUICKTIME_SCAN_KEY
,
2168 NS_WIN_WMP_SCAN_KEY
};
2170 uint32_t size
= sizeof(prefs
) / sizeof(prefs
[0]);
2172 for (uint32_t i
= 0; i
< size
; i
+=1) {
2173 nsCOMPtr
<nsIFile
> dirToScan
;
2175 if (NS_SUCCEEDED(dirService
->Get(prefs
[i
], NS_GET_IID(nsIFile
), getter_AddRefs(dirToScan
))) &&
2177 NS_SUCCEEDED(dirToScan
->Exists(&bExists
)) &&
2180 ScanPluginsDirectory(dirToScan
, aCreatePluginList
, &pluginschanged
);
2183 *aPluginsChanged
= true;
2185 // if we are just looking for possible changes,
2186 // no need to proceed if changes are detected
2187 if (!aCreatePluginList
&& *aPluginsChanged
) {
2188 NS_ITERATIVE_UNREF_LIST(nsRefPtr
<nsPluginTag
>, mCachedPlugins
, mNext
);
2189 NS_ITERATIVE_UNREF_LIST(nsRefPtr
<nsInvalidPluginTag
>, mInvalidPlugins
, mNext
);
2196 // We should also consider plugins to have changed if any plugins have been removed.
2197 // We'll know if any were removed if they weren't taken out of the cached plugins list
2198 // during our scan, thus we can assume something was removed if the cached plugins list
2199 // contains anything.
2200 if (!*aPluginsChanged
&& mCachedPlugins
) {
2201 *aPluginsChanged
= true;
2204 // Remove unseen invalid plugins
2205 nsRefPtr
<nsInvalidPluginTag
> invalidPlugins
= mInvalidPlugins
;
2206 while (invalidPlugins
) {
2207 if (!invalidPlugins
->mSeen
) {
2208 nsRefPtr
<nsInvalidPluginTag
> invalidPlugin
= invalidPlugins
;
2210 if (invalidPlugin
->mPrev
) {
2211 invalidPlugin
->mPrev
->mNext
= invalidPlugin
->mNext
;
2214 mInvalidPlugins
= invalidPlugin
->mNext
;
2216 if (invalidPlugin
->mNext
) {
2217 invalidPlugin
->mNext
->mPrev
= invalidPlugin
->mPrev
;
2220 invalidPlugins
= invalidPlugin
->mNext
;
2222 invalidPlugin
->mPrev
= NULL
;
2223 invalidPlugin
->mNext
= NULL
;
2226 invalidPlugins
->mSeen
= false;
2227 invalidPlugins
= invalidPlugins
->mNext
;
2231 // if we are not creating the list, there is no need to proceed
2232 if (!aCreatePluginList
) {
2233 NS_ITERATIVE_UNREF_LIST(nsRefPtr
<nsPluginTag
>, mCachedPlugins
, mNext
);
2234 NS_ITERATIVE_UNREF_LIST(nsRefPtr
<nsInvalidPluginTag
>, mInvalidPlugins
, mNext
);
2238 // if we are creating the list, it is already done;
2239 // update the plugins info cache if changes are detected
2240 if (*aPluginsChanged
)
2243 // No more need for cached plugins. Clear it up.
2244 NS_ITERATIVE_UNREF_LIST(nsRefPtr
<nsPluginTag
>, mCachedPlugins
, mNext
);
2245 NS_ITERATIVE_UNREF_LIST(nsRefPtr
<nsInvalidPluginTag
>, mInvalidPlugins
, mNext
);
2251 nsPluginHost::UpdatePluginInfo(nsPluginTag
* aPluginTag
)
2255 NS_ITERATIVE_UNREF_LIST(nsRefPtr
<nsPluginTag
>, mCachedPlugins
, mNext
);
2256 NS_ITERATIVE_UNREF_LIST(nsRefPtr
<nsInvalidPluginTag
>, mInvalidPlugins
, mNext
);
2262 // Update types with category manager
2263 nsAdoptingCString disableFullPage
=
2264 Preferences::GetCString(kPrefDisableFullPage
);
2265 for (uint32_t i
= 0; i
< aPluginTag
->mMimeTypes
.Length(); i
++) {
2266 nsRegisterType shouldRegister
;
2268 if (IsTypeInList(aPluginTag
->mMimeTypes
[i
], disableFullPage
)) {
2269 shouldRegister
= ePluginUnregister
;
2271 nsPluginTag
*plugin
= FindPluginForType(aPluginTag
->mMimeTypes
[i
].get(),
2273 shouldRegister
= plugin
? ePluginRegister
: ePluginUnregister
;
2276 RegisterWithCategoryManager(aPluginTag
->mMimeTypes
[i
], shouldRegister
);
2279 nsCOMPtr
<nsIObserverService
> obsService
=
2280 mozilla::services::GetObserverService();
2282 obsService
->NotifyObservers(nullptr, "plugin-info-updated", nullptr);
2284 // Reload instances if needed
2285 if (aPluginTag
->IsActive()) {
2293 nsPluginHost::IsTypeWhitelisted(const char *aMimeType
)
2295 nsAdoptingCString whitelist
= Preferences::GetCString(kPrefWhitelist
);
2296 if (!whitelist
.Length()) {
2299 nsDependentCString
wrap(aMimeType
);
2300 return IsTypeInList(wrap
, whitelist
);
2304 nsPluginHost::RegisterWithCategoryManager(nsCString
&aMimeType
,
2305 nsRegisterType aType
)
2307 PLUGIN_LOG(PLUGIN_LOG_NORMAL
,
2308 ("nsPluginTag::RegisterWithCategoryManager type = %s, removing = %s\n",
2309 aMimeType
.get(), aType
== ePluginUnregister
? "yes" : "no"));
2311 nsCOMPtr
<nsICategoryManager
> catMan
=
2312 do_GetService(NS_CATEGORYMANAGER_CONTRACTID
);
2317 const char *contractId
=
2318 "@mozilla.org/content/plugin/document-loader-factory;1";
2320 if (aType
== ePluginRegister
) {
2321 catMan
->AddCategoryEntry("Gecko-Content-Viewers",
2324 false, /* persist: broken by bug 193031 */
2325 mOverrideInternalTypes
,
2328 // Only delete the entry if a plugin registered for it
2329 nsXPIDLCString value
;
2330 nsresult rv
= catMan
->GetCategoryEntry("Gecko-Content-Viewers",
2332 getter_Copies(value
));
2333 if (NS_SUCCEEDED(rv
) && strcmp(value
, contractId
) == 0) {
2334 catMan
->DeleteCategoryEntry("Gecko-Content-Viewers",
2342 nsPluginHost::WritePluginInfo()
2345 nsresult rv
= NS_OK
;
2346 nsCOMPtr
<nsIProperties
> directoryService(do_GetService(NS_DIRECTORY_SERVICE_CONTRACTID
,&rv
));
2350 directoryService
->Get(NS_APP_USER_PROFILE_50_DIR
, NS_GET_IID(nsIFile
),
2351 getter_AddRefs(mPluginRegFile
));
2353 if (!mPluginRegFile
)
2354 return NS_ERROR_FAILURE
;
2356 PRFileDesc
* fd
= nullptr;
2358 nsCOMPtr
<nsIFile
> pluginReg
;
2360 rv
= mPluginRegFile
->Clone(getter_AddRefs(pluginReg
));
2364 nsAutoCString
filename(kPluginRegistryFilename
);
2365 filename
.Append(".tmp");
2366 rv
= pluginReg
->AppendNative(filename
);
2370 rv
= pluginReg
->OpenNSPRFileDesc(PR_WRONLY
| PR_CREATE_FILE
| PR_TRUNCATE
, 0600, &fd
);
2374 nsCOMPtr
<nsIXULRuntime
> runtime
= do_GetService("@mozilla.org/xre/runtime;1");
2376 return NS_ERROR_FAILURE
;
2380 rv
= runtime
->GetXPCOMABI(arch
);
2381 if (NS_FAILED(rv
)) {
2385 PR_fprintf(fd
, "Generated File. Do not edit.\n");
2387 PR_fprintf(fd
, "\n[HEADER]\nVersion%c%s%c%c\nArch%c%s%c%c\n",
2388 PLUGIN_REGISTRY_FIELD_DELIMITER
,
2389 kPluginRegistryVersion
,
2390 PLUGIN_REGISTRY_FIELD_DELIMITER
,
2391 PLUGIN_REGISTRY_END_OF_LINE_MARKER
,
2392 PLUGIN_REGISTRY_FIELD_DELIMITER
,
2394 PLUGIN_REGISTRY_FIELD_DELIMITER
,
2395 PLUGIN_REGISTRY_END_OF_LINE_MARKER
);
2397 // Store all plugins in the mPlugins list - all plugins currently in use.
2398 PR_fprintf(fd
, "\n[PLUGINS]\n");
2400 for (nsPluginTag
*tag
= mPlugins
; tag
; tag
= tag
->mNext
) {
2401 // store each plugin info into the registry
2402 // filename & fullpath are on separate line
2403 // because they can contain field delimiter char
2404 PR_fprintf(fd
, "%s%c%c\n%s%c%c\n%s%c%c\n",
2405 (tag
->mFileName
.get()),
2406 PLUGIN_REGISTRY_FIELD_DELIMITER
,
2407 PLUGIN_REGISTRY_END_OF_LINE_MARKER
,
2408 (tag
->mFullPath
.get()),
2409 PLUGIN_REGISTRY_FIELD_DELIMITER
,
2410 PLUGIN_REGISTRY_END_OF_LINE_MARKER
,
2411 (tag
->mVersion
.get()),
2412 PLUGIN_REGISTRY_FIELD_DELIMITER
,
2413 PLUGIN_REGISTRY_END_OF_LINE_MARKER
);
2415 // lastModifiedTimeStamp|canUnload|tag->mFlags
2416 PR_fprintf(fd
, "%lld%c%d%c%lu%c%c\n",
2417 tag
->mLastModifiedTime
,
2418 PLUGIN_REGISTRY_FIELD_DELIMITER
,
2419 false, // did store whether or not to unload in-process plugins
2420 PLUGIN_REGISTRY_FIELD_DELIMITER
,
2421 0, // legacy field for flags
2422 PLUGIN_REGISTRY_FIELD_DELIMITER
,
2423 PLUGIN_REGISTRY_END_OF_LINE_MARKER
);
2425 //description, name & mtypecount are on separate line
2426 PR_fprintf(fd
, "%s%c%c\n%s%c%c\n%d\n",
2427 (tag
->mDescription
.get()),
2428 PLUGIN_REGISTRY_FIELD_DELIMITER
,
2429 PLUGIN_REGISTRY_END_OF_LINE_MARKER
,
2431 PLUGIN_REGISTRY_FIELD_DELIMITER
,
2432 PLUGIN_REGISTRY_END_OF_LINE_MARKER
,
2433 tag
->mMimeTypes
.Length());
2435 // Add in each mimetype this plugin supports
2436 for (uint32_t i
= 0; i
< tag
->mMimeTypes
.Length(); i
++) {
2437 PR_fprintf(fd
, "%d%c%s%c%s%c%s%c%c\n",
2438 i
,PLUGIN_REGISTRY_FIELD_DELIMITER
,
2439 (tag
->mMimeTypes
[i
].get()),
2440 PLUGIN_REGISTRY_FIELD_DELIMITER
,
2441 (tag
->mMimeDescriptions
[i
].get()),
2442 PLUGIN_REGISTRY_FIELD_DELIMITER
,
2443 (tag
->mExtensions
[i
].get()),
2444 PLUGIN_REGISTRY_FIELD_DELIMITER
,
2445 PLUGIN_REGISTRY_END_OF_LINE_MARKER
);
2449 PR_fprintf(fd
, "\n[INVALID]\n");
2451 nsRefPtr
<nsInvalidPluginTag
> invalidPlugins
= mInvalidPlugins
;
2452 while (invalidPlugins
) {
2454 PR_fprintf(fd
, "%s%c%c\n",
2455 (!invalidPlugins
->mFullPath
.IsEmpty() ? invalidPlugins
->mFullPath
.get() : ""),
2456 PLUGIN_REGISTRY_FIELD_DELIMITER
,
2457 PLUGIN_REGISTRY_END_OF_LINE_MARKER
);
2459 // lastModifiedTimeStamp
2460 PR_fprintf(fd
, "%lld%c%c\n",
2461 invalidPlugins
->mLastModifiedTime
,
2462 PLUGIN_REGISTRY_FIELD_DELIMITER
,
2463 PLUGIN_REGISTRY_END_OF_LINE_MARKER
);
2465 invalidPlugins
= invalidPlugins
->mNext
;
2469 nsCOMPtr
<nsIFile
> parent
;
2470 rv
= pluginReg
->GetParent(getter_AddRefs(parent
));
2471 NS_ENSURE_SUCCESS(rv
, rv
);
2472 rv
= pluginReg
->MoveToNative(parent
, kPluginRegistryFilename
);
2477 nsPluginHost::ReadPluginInfo()
2479 const long PLUGIN_REG_MIMETYPES_ARRAY_SIZE
= 12;
2480 const long PLUGIN_REG_MAX_MIMETYPES
= 1000;
2482 // we need to import the legacy flags from the plugin registry once
2483 const bool pluginStateImported
=
2484 Preferences::GetDefaultBool("plugin.importedState", false);
2488 nsCOMPtr
<nsIProperties
> directoryService(do_GetService(NS_DIRECTORY_SERVICE_CONTRACTID
,&rv
));
2492 directoryService
->Get(NS_APP_USER_PROFILE_50_DIR
, NS_GET_IID(nsIFile
),
2493 getter_AddRefs(mPluginRegFile
));
2495 if (!mPluginRegFile
) {
2496 // There is no profile yet, this will tell us if there is going to be one
2498 directoryService
->Get(NS_APP_PROFILE_DIR_STARTUP
, NS_GET_IID(nsIFile
),
2499 getter_AddRefs(mPluginRegFile
));
2500 if (!mPluginRegFile
)
2501 return NS_ERROR_FAILURE
;
2503 return NS_ERROR_NOT_AVAILABLE
;
2506 PRFileDesc
* fd
= nullptr;
2508 nsCOMPtr
<nsIFile
> pluginReg
;
2510 rv
= mPluginRegFile
->Clone(getter_AddRefs(pluginReg
));
2514 rv
= pluginReg
->AppendNative(kPluginRegistryFilename
);
2519 rv
= pluginReg
->GetFileSize(&fileSize
);
2523 if (fileSize
> INT32_MAX
) {
2524 return NS_ERROR_FAILURE
;
2526 int32_t flen
= int32_t(fileSize
);
2528 NS_WARNING("Plugins Registry Empty!");
2529 return NS_OK
; // ERROR CONDITION
2532 nsPluginManifestLineReader reader
;
2533 char* registry
= reader
.Init(flen
);
2535 return NS_ERROR_OUT_OF_MEMORY
;
2537 rv
= pluginReg
->OpenNSPRFileDesc(PR_RDONLY
, 0444, &fd
);
2541 // set rv to return an error on goto out
2542 rv
= NS_ERROR_FAILURE
;
2544 int32_t bread
= PR_Read(fd
, registry
, flen
);
2550 if (!ReadSectionHeader(reader
, "HEADER"))
2553 if (!reader
.NextLine())
2558 // VersionLiteral, kPluginRegistryVersion
2559 if (2 != reader
.ParseLine(values
, 2))
2563 if (PL_strcmp(values
[0], "Version"))
2566 // kPluginRegistryVersion
2567 int32_t vdiff
= mozilla::CompareVersions(values
[1], kPluginRegistryVersion
);
2568 mozilla::Version
version(values
[1]);
2569 // If this is a registry from some future version then don't attempt to read it
2572 // If this is a registry from before the minimum then don't attempt to read it
2573 if (version
< kMinimumRegistryVersion
)
2576 // Registry v0.10 and upwards includes the plugin version field
2577 bool regHasVersion
= (version
>= "0.10");
2579 // Registry v0.13 and upwards includes the architecture
2580 if (version
>= "0.13") {
2581 char* archValues
[6];
2583 if (!reader
.NextLine()) {
2587 // ArchLiteral, Architecture
2588 if (2 != reader
.ParseLine(archValues
, 2)) {
2593 if (PL_strcmp(archValues
[0], "Arch")) {
2597 nsCOMPtr
<nsIXULRuntime
> runtime
= do_GetService("@mozilla.org/xre/runtime;1");
2603 if (NS_FAILED(runtime
->GetXPCOMABI(arch
))) {
2607 // If this is a registry from a different architecture then don't attempt to read it
2608 if (PL_strcmp(archValues
[1], arch
.get())) {
2613 // Registry v0.13 and upwards includes the list of invalid plugins
2614 bool hasInvalidPlugins
= (version
>= "0.13");
2616 // Registry v0.16 and upwards always have 0 for their plugin flags, prefs are used instead
2617 const bool hasValidFlags
= (version
< "0.16");
2619 if (!ReadSectionHeader(reader
, "PLUGINS"))
2622 #if defined(XP_MACOSX)
2623 bool hasFullPathInFileNameField
= false;
2625 bool hasFullPathInFileNameField
= (version
< "0.11");
2628 while (reader
.NextLine()) {
2629 const char *filename
;
2630 const char *fullpath
;
2631 nsAutoCString derivedFileName
;
2633 if (hasInvalidPlugins
&& *reader
.LinePtr() == '[') {
2637 if (hasFullPathInFileNameField
) {
2638 fullpath
= reader
.LinePtr();
2639 if (!reader
.NextLine())
2641 // try to derive a file name from the full path
2643 nsCOMPtr
<nsIFile
> file
= do_CreateInstance("@mozilla.org/file/local;1");
2644 file
->InitWithNativePath(nsDependentCString(fullpath
));
2645 file
->GetNativeLeafName(derivedFileName
);
2646 filename
= derivedFileName
.get();
2651 // skip the next line, useless in this version
2652 if (!reader
.NextLine())
2655 filename
= reader
.LinePtr();
2656 if (!reader
.NextLine())
2659 fullpath
= reader
.LinePtr();
2660 if (!reader
.NextLine())
2664 const char *version
;
2665 if (regHasVersion
) {
2666 version
= reader
.LinePtr();
2667 if (!reader
.NextLine())
2673 // lastModifiedTimeStamp|canUnload|tag.mFlag
2674 if (reader
.ParseLine(values
, 3) != 3)
2677 // If this is an old plugin registry mark this plugin tag to be refreshed
2678 int64_t lastmod
= (vdiff
== 0) ? nsCRT::atoll(values
[0]) : -1;
2679 uint32_t tagflag
= atoi(values
[2]);
2680 if (!reader
.NextLine())
2683 char *description
= reader
.LinePtr();
2684 if (!reader
.NextLine())
2687 #if MOZ_WIDGET_ANDROID
2688 // Flash on Android does not populate the version field, but it is tacked on to the description.
2689 // For example, "Shockwave Flash 11.1 r115"
2690 if (PL_strncmp("Shockwave Flash ", description
, 16) == 0 && description
[16]) {
2691 version
= &description
[16];
2695 const char *name
= reader
.LinePtr();
2696 if (!reader
.NextLine())
2699 long mimetypecount
= std::strtol(reader
.LinePtr(), nullptr, 10);
2700 if (mimetypecount
== LONG_MAX
|| mimetypecount
== LONG_MIN
||
2701 mimetypecount
>= PLUGIN_REG_MAX_MIMETYPES
|| mimetypecount
< 0) {
2702 return NS_ERROR_FAILURE
;
2705 char *stackalloced
[PLUGIN_REG_MIMETYPES_ARRAY_SIZE
* 3];
2707 char **mimedescriptions
;
2709 char **heapalloced
= 0;
2710 if (mimetypecount
> PLUGIN_REG_MIMETYPES_ARRAY_SIZE
- 1) {
2711 heapalloced
= new char *[mimetypecount
* 3];
2712 mimetypes
= heapalloced
;
2714 mimetypes
= stackalloced
;
2716 mimedescriptions
= mimetypes
+ mimetypecount
;
2717 extensions
= mimedescriptions
+ mimetypecount
;
2719 int mtr
= 0; //mimetype read
2720 for (; mtr
< mimetypecount
; mtr
++) {
2721 if (!reader
.NextLine())
2724 //line number|mimetype|description|extension
2725 if (4 != reader
.ParseLine(values
, 4))
2727 int line
= atoi(values
[0]);
2730 mimetypes
[mtr
] = values
[1];
2731 mimedescriptions
[mtr
] = values
[2];
2732 extensions
[mtr
] = values
[3];
2735 if (mtr
!= mimetypecount
) {
2737 delete [] heapalloced
;
2742 nsRefPtr
<nsPluginTag
> tag
= new nsPluginTag(name
,
2747 (const char* const*)mimetypes
,
2748 (const char* const*)mimedescriptions
,
2749 (const char* const*)extensions
,
2750 mimetypecount
, lastmod
, true);
2752 delete [] heapalloced
;
2757 // Import flags from registry into prefs for old registry versions
2758 if (hasValidFlags
&& !pluginStateImported
) {
2759 tag
->ImportFlagsToPrefs(tagflag
);
2762 PR_LOG(nsPluginLogging::gPluginLog
, PLUGIN_LOG_BASIC
,
2763 ("LoadCachedPluginsInfo : Loading Cached plugininfo for %s\n", tag
->mFileName
.get()));
2764 tag
->mNext
= mCachedPlugins
;
2765 mCachedPlugins
= tag
;
2768 if (hasInvalidPlugins
) {
2769 if (!ReadSectionHeader(reader
, "INVALID")) {
2773 while (reader
.NextLine()) {
2774 const char *fullpath
= reader
.LinePtr();
2775 if (!reader
.NextLine()) {
2779 const char *lastModifiedTimeStamp
= reader
.LinePtr();
2780 int64_t lastmod
= (vdiff
== 0) ? nsCRT::atoll(lastModifiedTimeStamp
) : -1;
2782 nsRefPtr
<nsInvalidPluginTag
> invalidTag
= new nsInvalidPluginTag(fullpath
, lastmod
);
2784 invalidTag
->mNext
= mInvalidPlugins
;
2785 if (mInvalidPlugins
) {
2786 mInvalidPlugins
->mPrev
= invalidTag
;
2788 mInvalidPlugins
= invalidTag
;
2792 // flip the pref so we don't import the legacy flags again
2793 Preferences::SetBool("plugin.importedState", true);
2799 nsPluginHost::RemoveCachedPluginsInfo(const char *filePath
, nsPluginTag
**result
)
2801 nsRefPtr
<nsPluginTag
> prev
;
2802 nsRefPtr
<nsPluginTag
> tag
= mCachedPlugins
;
2805 if (tag
->mFullPath
.Equals(filePath
)) {
2806 // Found it. Remove it from our list
2808 prev
->mNext
= tag
->mNext
;
2810 mCachedPlugins
= tag
->mNext
;
2811 tag
->mNext
= nullptr;
2823 nsPluginHost::EnsurePrivateDirServiceProvider()
2825 if (!mPrivateDirServiceProvider
) {
2827 mPrivateDirServiceProvider
= new nsPluginDirServiceProvider();
2828 if (!mPrivateDirServiceProvider
)
2829 return NS_ERROR_OUT_OF_MEMORY
;
2830 nsCOMPtr
<nsIDirectoryService
> dirService(do_GetService(kDirectoryServiceContractID
, &rv
));
2833 rv
= dirService
->RegisterProvider(mPrivateDirServiceProvider
);
2841 nsresult
nsPluginHost::NewPluginURLStream(const nsString
& aURL
,
2842 nsNPAPIPluginInstance
*aInstance
,
2843 nsNPAPIPluginStreamListener
* aListener
,
2844 nsIInputStream
*aPostStream
,
2845 const char *aHeadersData
,
2846 uint32_t aHeadersDataLen
)
2848 nsCOMPtr
<nsIURI
> url
;
2849 nsAutoString absUrl
;
2852 if (aURL
.Length() <= 0)
2855 // get the base URI for the plugin to create an absolute url
2856 // in case aURL is relative
2857 nsRefPtr
<nsPluginInstanceOwner
> owner
= aInstance
->GetOwner();
2859 rv
= NS_MakeAbsoluteURI(absUrl
, aURL
, nsCOMPtr
<nsIURI
>(owner
->GetBaseURI()));
2862 if (absUrl
.IsEmpty())
2863 absUrl
.Assign(aURL
);
2865 rv
= NS_NewURI(getter_AddRefs(url
), absUrl
);
2869 nsCOMPtr
<nsIDOMElement
> element
;
2870 nsCOMPtr
<nsIDocument
> doc
;
2872 owner
->GetDOMElement(getter_AddRefs(element
));
2873 owner
->GetDocument(getter_AddRefs(doc
));
2876 int16_t shouldLoad
= nsIContentPolicy::ACCEPT
;
2877 rv
= NS_CheckContentLoadPolicy(nsIContentPolicy::TYPE_OBJECT_SUBREQUEST
,
2879 (doc
? doc
->NodePrincipal() : nullptr),
2881 EmptyCString(), //mime guess
2886 if (NS_CP_REJECTED(shouldLoad
)) {
2887 // Disallowed by content policy
2888 return NS_ERROR_CONTENT_BLOCKED
;
2891 nsRefPtr
<nsPluginStreamListenerPeer
> listenerPeer
= new nsPluginStreamListenerPeer();
2893 return NS_ERROR_OUT_OF_MEMORY
;
2895 rv
= listenerPeer
->Initialize(url
, aInstance
, aListener
);
2899 nsCOMPtr
<nsIChannel
> channel
;
2900 rv
= NS_NewChannel(getter_AddRefs(channel
), url
, nullptr,
2901 nullptr, /* do not add this internal plugin's channel
2902 on the load group otherwise this channel could be canceled
2903 form |nsDocShell::OnLinkClickSync| bug 166613 */
2909 // Set the owner of channel to the document principal...
2910 channel
->SetOwner(doc
->NodePrincipal());
2912 // And if it's a script allow it to execute against the
2913 // document's script context.
2914 nsCOMPtr
<nsIScriptChannel
> scriptChannel(do_QueryInterface(channel
));
2915 if (scriptChannel
) {
2916 scriptChannel
->SetExecutionPolicy(nsIScriptChannel::EXECUTE_NORMAL
);
2917 // Plug-ins seem to depend on javascript: URIs running synchronously
2918 scriptChannel
->SetExecuteAsync(false);
2922 // deal with headers and post data
2923 nsCOMPtr
<nsIHttpChannel
> httpChannel(do_QueryInterface(channel
));
2926 // Only set the Referer header for GET requests because IIS throws
2927 // errors about malformed requests if we include it in POSTs. See
2929 nsCOMPtr
<nsIURI
> referer
;
2931 nsCOMPtr
<nsIObjectLoadingContent
> olc
= do_QueryInterface(element
);
2933 olc
->GetSrcURI(getter_AddRefs(referer
));
2938 return NS_ERROR_FAILURE
;
2940 referer
= doc
->GetDocumentURI();
2943 rv
= httpChannel
->SetReferrer(referer
);
2944 NS_ENSURE_SUCCESS(rv
,rv
);
2948 // XXX it's a bit of a hack to rewind the postdata stream
2949 // here but it has to be done in case the post data is
2950 // being reused multiple times.
2951 nsCOMPtr
<nsISeekableStream
>
2952 postDataSeekable(do_QueryInterface(aPostStream
));
2953 if (postDataSeekable
)
2954 postDataSeekable
->Seek(nsISeekableStream::NS_SEEK_SET
, 0);
2956 nsCOMPtr
<nsIUploadChannel
> uploadChannel(do_QueryInterface(httpChannel
));
2957 NS_ASSERTION(uploadChannel
, "http must support nsIUploadChannel");
2959 uploadChannel
->SetUploadStream(aPostStream
, EmptyCString(), -1);
2963 rv
= AddHeadersToChannel(aHeadersData
, aHeadersDataLen
, httpChannel
);
2964 NS_ENSURE_SUCCESS(rv
,rv
);
2967 rv
= channel
->AsyncOpen(listenerPeer
, nullptr);
2968 if (NS_SUCCEEDED(rv
))
2969 listenerPeer
->TrackRequest(channel
);
2973 // Called by GetURL and PostURL
2975 nsPluginHost::DoURLLoadSecurityCheck(nsNPAPIPluginInstance
*aInstance
,
2978 if (!aURL
|| *aURL
== '\0')
2981 // get the base URI for the plugin element
2982 nsRefPtr
<nsPluginInstanceOwner
> owner
= aInstance
->GetOwner();
2984 return NS_ERROR_FAILURE
;
2986 nsCOMPtr
<nsIURI
> baseURI
= owner
->GetBaseURI();
2988 return NS_ERROR_FAILURE
;
2990 // Create an absolute URL for the target in case the target is relative
2991 nsCOMPtr
<nsIURI
> targetURL
;
2992 NS_NewURI(getter_AddRefs(targetURL
), aURL
, baseURI
);
2994 return NS_ERROR_FAILURE
;
2996 nsCOMPtr
<nsIDocument
> doc
;
2997 owner
->GetDocument(getter_AddRefs(doc
));
2999 return NS_ERROR_FAILURE
;
3002 nsCOMPtr
<nsIScriptSecurityManager
> secMan(
3003 do_GetService(NS_SCRIPTSECURITYMANAGER_CONTRACTID
, &rv
));
3007 return secMan
->CheckLoadURIWithPrincipal(doc
->NodePrincipal(), targetURL
,
3008 nsIScriptSecurityManager::STANDARD
);
3013 nsPluginHost::AddHeadersToChannel(const char *aHeadersData
,
3014 uint32_t aHeadersDataLen
,
3015 nsIChannel
*aGenericChannel
)
3017 nsresult rv
= NS_OK
;
3019 nsCOMPtr
<nsIHttpChannel
> aChannel
= do_QueryInterface(aGenericChannel
);
3021 return NS_ERROR_NULL_POINTER
;
3024 // used during the manipulation of the String from the aHeadersData
3025 nsAutoCString headersString
;
3026 nsAutoCString oneHeader
;
3027 nsAutoCString headerName
;
3028 nsAutoCString headerValue
;
3032 // Turn the char * buffer into an nsString.
3033 headersString
= aHeadersData
;
3035 // Iterate over the nsString: for each "\r\n" delimited chunk,
3036 // add the value as a header to the nsIHTTPChannel
3038 crlf
= headersString
.Find("\r\n", true);
3043 headersString
.Mid(oneHeader
, 0, crlf
);
3044 headersString
.Cut(0, crlf
+ 2);
3045 oneHeader
.StripWhitespace();
3046 colon
= oneHeader
.Find(":");
3048 rv
= NS_ERROR_NULL_POINTER
;
3051 oneHeader
.Left(headerName
, colon
);
3053 oneHeader
.Mid(headerValue
, colon
, oneHeader
.Length() - colon
);
3055 // FINALLY: we can set the header!
3057 rv
= aChannel
->SetRequestHeader(headerName
, headerValue
, true);
3058 if (NS_FAILED(rv
)) {
3059 rv
= NS_ERROR_NULL_POINTER
;
3067 nsPluginHost::StopPluginInstance(nsNPAPIPluginInstance
* aInstance
)
3069 if (PluginDestructionGuard::DelayDestroy(aInstance
)) {
3073 PLUGIN_LOG(PLUGIN_LOG_NORMAL
,
3074 ("nsPluginHost::StopPluginInstance called instance=%p\n",aInstance
));
3076 if (aInstance
->HasStartedDestroying()) {
3080 Telemetry::AutoTimer
<Telemetry::PLUGIN_SHUTDOWN_MS
> timer
;
3083 // if the instance does not want to be 'cached' just remove it
3084 bool doCache
= aInstance
->ShouldCache();
3086 // try to get the max cached instances from a pref or use default
3087 uint32_t cachedInstanceLimit
=
3088 Preferences::GetUint(NS_PREF_MAX_NUM_CACHED_INSTANCES
,
3089 DEFAULT_NUMBER_OF_STOPPED_INSTANCES
);
3090 if (StoppedInstanceCount() >= cachedInstanceLimit
) {
3091 nsNPAPIPluginInstance
*oldestInstance
= FindOldestStoppedInstance();
3092 if (oldestInstance
) {
3093 nsPluginTag
* pluginTag
= TagForPlugin(oldestInstance
->GetPlugin());
3094 oldestInstance
->Destroy();
3095 mInstances
.RemoveElement(oldestInstance
);
3096 // TODO: Remove this check once bug 752422 was investigated
3098 OnPluginInstanceDestroyed(pluginTag
);
3103 nsPluginTag
* pluginTag
= TagForPlugin(aInstance
->GetPlugin());
3104 aInstance
->Destroy();
3105 mInstances
.RemoveElement(aInstance
);
3106 // TODO: Remove this check once bug 752422 was investigated
3108 OnPluginInstanceDestroyed(pluginTag
);
3115 nsresult
nsPluginHost::NewPluginStreamListener(nsIURI
* aURI
,
3116 nsNPAPIPluginInstance
* aInstance
,
3117 nsIStreamListener
**aStreamListener
)
3119 NS_ENSURE_ARG_POINTER(aURI
);
3120 NS_ENSURE_ARG_POINTER(aStreamListener
);
3122 nsRefPtr
<nsPluginStreamListenerPeer
> listener
= new nsPluginStreamListenerPeer();
3123 nsresult rv
= listener
->Initialize(aURI
, aInstance
, nullptr);
3124 if (NS_FAILED(rv
)) {
3128 listener
.forget(aStreamListener
);
3133 NS_IMETHODIMP
nsPluginHost::Observe(nsISupports
*aSubject
,
3135 const PRUnichar
*someData
)
3137 if (!strcmp(NS_XPCOM_SHUTDOWN_OBSERVER_ID
, aTopic
)) {
3142 if (!strcmp(NS_PREFBRANCH_PREFCHANGE_TOPIC_ID
, aTopic
)) {
3143 mPluginsDisabled
= Preferences::GetBool("plugin.disable", false);
3144 mPluginsClickToPlay
= Preferences::GetBool("plugins.click_to_play", false);
3145 // Unload or load plugins as needed
3146 if (mPluginsDisabled
) {
3152 if (!strcmp("blocklist-updated", aTopic
)) {
3153 nsPluginTag
* plugin
= mPlugins
;
3155 plugin
->InvalidateBlocklistState();
3156 plugin
= plugin
->mNext
;
3159 #ifdef MOZ_WIDGET_ANDROID
3160 if (!strcmp("application-background", aTopic
)) {
3161 for(uint32_t i
= 0; i
< mInstances
.Length(); i
++) {
3162 mInstances
[i
]->NotifyForeground(false);
3165 if (!strcmp("application-foreground", aTopic
)) {
3166 for(uint32_t i
= 0; i
< mInstances
.Length(); i
++) {
3167 if (mInstances
[i
]->IsOnScreen())
3168 mInstances
[i
]->NotifyForeground(true);
3171 if (!strcmp("memory-pressure", aTopic
)) {
3172 for(uint32_t i
= 0; i
< mInstances
.Length(); i
++) {
3173 mInstances
[i
]->MemoryPressure();
3181 nsPluginHost::ParsePostBufferToFixHeaders(const char *inPostData
, uint32_t inPostDataLen
,
3182 char **outPostData
, uint32_t *outPostDataLen
)
3184 if (!inPostData
|| !outPostData
|| !outPostDataLen
)
3185 return NS_ERROR_NULL_POINTER
;
3188 *outPostDataLen
= 0;
3190 const char CR
= '\r';
3191 const char LF
= '\n';
3192 const char CRLFCRLF
[] = {CR
,LF
,CR
,LF
,'\0'}; // C string"\r\n\r\n"
3193 const char ContentLenHeader
[] = "Content-length";
3195 nsAutoTArray
<const char*, 8> singleLF
;
3196 const char *pSCntlh
= 0;// pointer to start of ContentLenHeader in inPostData
3197 const char *pSod
= 0; // pointer to start of data in inPostData
3198 const char *pEoh
= 0; // pointer to end of headers in inPostData
3199 const char *pEod
= inPostData
+ inPostDataLen
; // pointer to end of inPostData
3200 if (*inPostData
== LF
) {
3201 // If no custom headers are required, simply add a blank
3202 // line ('\n') to the beginning of the file or buffer.
3203 // so *inPostData == '\n' is valid
3204 pSod
= inPostData
+ 1;
3206 const char *s
= inPostData
; //tmp pointer to sourse inPostData
3209 (*s
== 'C' || *s
== 'c') &&
3210 (s
+ sizeof(ContentLenHeader
) - 1 < pEod
) &&
3211 (!PL_strncasecmp(s
, ContentLenHeader
, sizeof(ContentLenHeader
) - 1)))
3213 // lets assume this is ContentLenHeader for now
3214 const char *p
= pSCntlh
= s
;
3215 p
+= sizeof(ContentLenHeader
) - 1;
3216 // search for first CR or LF == end of ContentLenHeader
3217 for (; p
< pEod
; p
++) {
3218 if (*p
== CR
|| *p
== LF
) {
3220 // one more check; if previous char is a digit
3221 // most likely pSCntlh points to the start of ContentLenHeader
3222 if (*(p
-1) >= '0' && *(p
-1) <= '9') {
3228 if (pSCntlh
== s
) { // curret ptr is the same
3229 pSCntlh
= 0; // that was not ContentLenHeader
3230 break; // there is nothing to parse, break *WHILE LOOP* here
3235 if (pSCntlh
&& // only if ContentLenHeader is found we are looking for end of headers
3236 ((s
+ sizeof(CRLFCRLF
)-1) <= pEod
) &&
3237 !memcmp(s
, CRLFCRLF
, sizeof(CRLFCRLF
)-1))
3239 s
+= sizeof(CRLFCRLF
)-1;
3240 pEoh
= pSod
= s
; // data stars here
3243 } else if (*s
== LF
) {
3245 singleLF
.AppendElement(s
);
3247 if (pSCntlh
&& (s
+1 < pEod
) && (*(s
+1) == LF
)) {
3249 singleLF
.AppendElement(s
);
3251 pEoh
= pSod
= s
; // data stars here
3259 // deal with output buffer
3260 if (!pSod
) { // lets assume whole buffer is a data
3264 uint32_t newBufferLen
= 0;
3265 uint32_t dataLen
= pEod
- pSod
;
3266 uint32_t headersLen
= pEoh
? pSod
- inPostData
: 0;
3268 char *p
; // tmp ptr into new output buf
3269 if (headersLen
) { // we got a headers
3270 // this function does not make any assumption on correctness
3271 // of ContentLenHeader value in this case.
3273 newBufferLen
= dataLen
+ headersLen
;
3274 // in case there were single LFs in headers
3275 // reserve an extra space for CR will be added before each single LF
3276 int cntSingleLF
= singleLF
.Length();
3277 newBufferLen
+= cntSingleLF
;
3279 if (!(*outPostData
= p
= (char*)nsMemory::Alloc(newBufferLen
)))
3280 return NS_ERROR_OUT_OF_MEMORY
;
3282 // deal with single LF
3283 const char *s
= inPostData
;
3285 for (int i
=0; i
<cntSingleLF
; i
++) {
3286 const char *plf
= singleLF
.ElementAt(i
); // ptr to single LF in headers
3287 int n
= plf
- s
; // bytes to copy
3288 if (n
) { // for '\n\n' there is nothing to memcpy
3297 // are we done with headers?
3298 headersLen
= pEoh
- s
;
3299 if (headersLen
) { // not yet
3300 memcpy(p
, s
, headersLen
); // copy the rest
3303 } else if (dataLen
) { // no ContentLenHeader is found but there is a data
3304 // make new output buffer big enough
3305 // to keep ContentLenHeader+value followed by data
3306 uint32_t l
= sizeof(ContentLenHeader
) + sizeof(CRLFCRLF
) + 32;
3307 newBufferLen
= dataLen
+ l
;
3308 if (!(*outPostData
= p
= (char*)nsMemory::Alloc(newBufferLen
)))
3309 return NS_ERROR_OUT_OF_MEMORY
;
3310 headersLen
= PR_snprintf(p
, l
,"%s: %ld%s", ContentLenHeader
, dataLen
, CRLFCRLF
);
3311 if (headersLen
== l
) { // if PR_snprintf has ate all extra space consider this as an error
3314 return NS_ERROR_FAILURE
;
3317 newBufferLen
= headersLen
+ dataLen
;
3319 // at this point we've done with headers.
3320 // there is a possibility that input buffer has only headers info in it
3321 // which already parsed and copied into output buffer.
3324 memcpy(p
, pSod
, dataLen
);
3327 *outPostDataLen
= newBufferLen
;
3333 nsPluginHost::CreateTempFileToPost(const char *aPostDataURL
, nsIFile
**aTmpFile
)
3337 nsAutoCString filename
;
3339 // stat file == get size & convert file:///c:/ to c: if needed
3340 nsCOMPtr
<nsIFile
> inFile
;
3341 rv
= NS_GetFileFromURLSpec(nsDependentCString(aPostDataURL
),
3342 getter_AddRefs(inFile
));
3343 if (NS_FAILED(rv
)) {
3344 nsCOMPtr
<nsIFile
> localFile
;
3345 rv
= NS_NewNativeLocalFile(nsDependentCString(aPostDataURL
), false,
3346 getter_AddRefs(localFile
));
3347 if (NS_FAILED(rv
)) return rv
;
3350 rv
= inFile
->GetFileSize(&fileSize
);
3351 if (NS_FAILED(rv
)) return rv
;
3352 rv
= inFile
->GetNativePath(filename
);
3353 if (NS_FAILED(rv
)) return rv
;
3355 if (fileSize
!= 0) {
3356 nsCOMPtr
<nsIInputStream
> inStream
;
3357 rv
= NS_NewLocalFileInputStream(getter_AddRefs(inStream
), inFile
);
3358 if (NS_FAILED(rv
)) return rv
;
3360 // Create a temporary file to write the http Content-length:
3361 // %ld\r\n\" header and "\r\n" == end of headers for post data to
3363 nsCOMPtr
<nsIFile
> tempFile
;
3364 rv
= GetPluginTempDir(getter_AddRefs(tempFile
));
3368 nsAutoCString inFileName
;
3369 inFile
->GetNativeLeafName(inFileName
);
3370 // XXX hack around bug 70083
3371 inFileName
.Insert(NS_LITERAL_CSTRING("post-"), 0);
3372 rv
= tempFile
->AppendNative(inFileName
);
3377 // make it unique, and mode == 0600, not world-readable
3378 rv
= tempFile
->CreateUnique(nsIFile::NORMAL_FILE_TYPE
, 0600);
3382 nsCOMPtr
<nsIOutputStream
> outStream
;
3383 if (NS_SUCCEEDED(rv
)) {
3384 rv
= NS_NewLocalFileOutputStream(getter_AddRefs(outStream
),
3386 (PR_WRONLY
| PR_CREATE_FILE
| PR_TRUNCATE
),
3387 0600); // 600 so others can't read our form data
3389 NS_ASSERTION(NS_SUCCEEDED(rv
), "Post data file couldn't be created!");
3395 bool firstRead
= true;
3397 // Read() mallocs if buffer is null
3398 rv
= inStream
->Read(buf
, 1024, &br
);
3399 if (NS_FAILED(rv
) || (int32_t)br
<= 0)
3402 //"For protocols in which the headers must be distinguished from the body,
3403 // such as HTTP, the buffer or file should contain the headers, followed by
3404 // a blank line, then the body. If no custom headers are required, simply
3405 // add a blank line ('\n') to the beginning of the file or buffer.
3408 // assuming first 1K (or what we got) has all headers in,
3409 // lets parse it through nsPluginHost::ParsePostBufferToFixHeaders()
3410 ParsePostBufferToFixHeaders((const char *)buf
, br
, &parsedBuf
, &bw
);
3411 rv
= outStream
->Write(parsedBuf
, bw
, &br
);
3412 nsMemory::Free(parsedBuf
);
3413 if (NS_FAILED(rv
) || (bw
!= br
))
3420 rv
= outStream
->Write(buf
, bw
, &br
);
3421 if (NS_FAILED(rv
) || (bw
!= br
))
3427 if (NS_SUCCEEDED(rv
))
3428 *aTmpFile
= tempFile
.forget().get();
3434 nsPluginHost::NewPluginNativeWindow(nsPluginNativeWindow
** aPluginNativeWindow
)
3436 return PLUG_NewPluginNativeWindow(aPluginNativeWindow
);
3440 nsPluginHost::GetPluginName(nsNPAPIPluginInstance
*aPluginInstance
,
3441 const char** aPluginName
)
3443 nsNPAPIPluginInstance
*instance
= static_cast<nsNPAPIPluginInstance
*>(aPluginInstance
);
3445 return NS_ERROR_FAILURE
;
3447 nsNPAPIPlugin
* plugin
= instance
->GetPlugin();
3449 return NS_ERROR_FAILURE
;
3451 *aPluginName
= TagForPlugin(plugin
)->mName
.get();
3457 nsPluginHost::GetPluginTagForInstance(nsNPAPIPluginInstance
*aPluginInstance
,
3458 nsIPluginTag
**aPluginTag
)
3460 NS_ENSURE_ARG_POINTER(aPluginInstance
);
3461 NS_ENSURE_ARG_POINTER(aPluginTag
);
3463 nsNPAPIPlugin
*plugin
= aPluginInstance
->GetPlugin();
3465 return NS_ERROR_FAILURE
;
3467 *aPluginTag
= TagForPlugin(plugin
);
3469 NS_ADDREF(*aPluginTag
);
3473 NS_IMETHODIMP
nsPluginHost::Notify(nsITimer
* timer
)
3475 nsRefPtr
<nsPluginTag
> pluginTag
= mPlugins
;
3477 if (pluginTag
->mUnloadTimer
== timer
) {
3478 if (!IsRunningPlugin(pluginTag
)) {
3479 pluginTag
->TryUnloadPlugin(false);
3483 pluginTag
= pluginTag
->mNext
;
3486 return NS_ERROR_FAILURE
;
3490 // Re-enable any top level browser windows that were disabled by modal dialogs
3491 // displayed by the crashed plugin.
3493 CheckForDisabledWindows()
3495 nsCOMPtr
<nsIWindowMediator
> wm(do_GetService(NS_WINDOWMEDIATOR_CONTRACTID
));
3499 nsCOMPtr
<nsISimpleEnumerator
> windowList
;
3500 wm
->GetXULWindowEnumerator(nullptr, getter_AddRefs(windowList
));
3506 windowList
->HasMoreElements(&haveWindows
);
3510 nsCOMPtr
<nsISupports
> supportsWindow
;
3511 windowList
->GetNext(getter_AddRefs(supportsWindow
));
3512 nsCOMPtr
<nsIBaseWindow
> baseWin(do_QueryInterface(supportsWindow
));
3514 nsCOMPtr
<nsIWidget
> widget
;
3515 baseWin
->GetMainWidget(getter_AddRefs(widget
));
3516 if (widget
&& !widget
->GetParent() &&
3517 widget
->IsVisible() &&
3518 !widget
->IsEnabled()) {
3519 nsIWidget
* child
= widget
->GetFirstChild();
3523 if (NS_SUCCEEDED(child
->GetWindowType(aType
)) &&
3524 aType
== eWindowType_dialog
) {
3528 child
= child
->GetNextSibling();
3531 widget
->Enable(true);
3535 } while (haveWindows
);
3540 nsPluginHost::PluginCrashed(nsNPAPIPlugin
* aPlugin
,
3541 const nsAString
& pluginDumpID
,
3542 const nsAString
& browserDumpID
)
3544 nsPluginTag
* crashedPluginTag
= TagForPlugin(aPlugin
);
3546 // Notify the app's observer that a plugin crashed so it can submit
3548 bool submittedCrashReport
= false;
3549 nsCOMPtr
<nsIObserverService
> obsService
=
3550 mozilla::services::GetObserverService();
3551 nsCOMPtr
<nsIWritablePropertyBag2
> propbag
=
3552 do_CreateInstance("@mozilla.org/hash-property-bag;1");
3553 if (obsService
&& propbag
) {
3554 propbag
->SetPropertyAsAString(NS_LITERAL_STRING("pluginDumpID"),
3556 propbag
->SetPropertyAsAString(NS_LITERAL_STRING("browserDumpID"),
3558 propbag
->SetPropertyAsBool(NS_LITERAL_STRING("submittedCrashReport"),
3559 submittedCrashReport
);
3560 obsService
->NotifyObservers(propbag
, "plugin-crashed", nullptr);
3561 // see if an observer submitted a crash report.
3562 propbag
->GetPropertyAsBool(NS_LITERAL_STRING("submittedCrashReport"),
3563 &submittedCrashReport
);
3566 // Invalidate each nsPluginInstanceTag for the crashed plugin
3568 for (uint32_t i
= mInstances
.Length(); i
> 0; i
--) {
3569 nsNPAPIPluginInstance
* instance
= mInstances
[i
- 1];
3570 if (instance
->GetPlugin() == aPlugin
) {
3571 // notify the content node (nsIObjectLoadingContent) that the
3572 // plugin has crashed
3573 nsCOMPtr
<nsIDOMElement
> domElement
;
3574 instance
->GetDOMElement(getter_AddRefs(domElement
));
3575 nsCOMPtr
<nsIObjectLoadingContent
> objectContent(do_QueryInterface(domElement
));
3576 if (objectContent
) {
3577 objectContent
->PluginCrashed(crashedPluginTag
, pluginDumpID
, browserDumpID
,
3578 submittedCrashReport
);
3581 instance
->Destroy();
3582 mInstances
.RemoveElement(instance
);
3583 OnPluginInstanceDestroyed(crashedPluginTag
);
3587 // Only after all instances have been invalidated is it safe to null
3588 // out nsPluginTag.mPlugin. The next time we try to create an
3589 // instance of this plugin we reload it (launch a new plugin process).
3591 crashedPluginTag
->mPlugin
= nullptr;
3594 CheckForDisabledWindows();
3598 nsNPAPIPluginInstance
*
3599 nsPluginHost::FindInstance(const char *mimetype
)
3601 for (uint32_t i
= 0; i
< mInstances
.Length(); i
++) {
3602 nsNPAPIPluginInstance
* instance
= mInstances
[i
];
3605 nsresult rv
= instance
->GetMIMEType(&mt
);
3609 if (PL_strcasecmp(mt
, mimetype
) == 0)
3616 nsNPAPIPluginInstance
*
3617 nsPluginHost::FindOldestStoppedInstance()
3619 nsNPAPIPluginInstance
*oldestInstance
= nullptr;
3620 TimeStamp oldestTime
= TimeStamp::Now();
3621 for (uint32_t i
= 0; i
< mInstances
.Length(); i
++) {
3622 nsNPAPIPluginInstance
*instance
= mInstances
[i
];
3623 if (instance
->IsRunning())
3626 TimeStamp time
= instance
->StopTime();
3627 if (time
< oldestTime
) {
3629 oldestInstance
= instance
;
3633 return oldestInstance
;
3637 nsPluginHost::StoppedInstanceCount()
3639 uint32_t stoppedCount
= 0;
3640 for (uint32_t i
= 0; i
< mInstances
.Length(); i
++) {
3641 nsNPAPIPluginInstance
*instance
= mInstances
[i
];
3642 if (!instance
->IsRunning())
3645 return stoppedCount
;
3648 nsTArray
< nsRefPtr
<nsNPAPIPluginInstance
> >*
3649 nsPluginHost::InstanceArray()
3655 nsPluginHost::DestroyRunningInstances(nsPluginTag
* aPluginTag
)
3657 for (int32_t i
= mInstances
.Length(); i
> 0; i
--) {
3658 nsNPAPIPluginInstance
*instance
= mInstances
[i
- 1];
3659 if (instance
->IsRunning() && (!aPluginTag
|| aPluginTag
== TagForPlugin(instance
->GetPlugin()))) {
3660 instance
->SetWindow(nullptr);
3663 // Get rid of all the instances without the possibility of caching.
3664 nsPluginTag
* pluginTag
= TagForPlugin(instance
->GetPlugin());
3665 instance
->SetWindow(nullptr);
3667 nsCOMPtr
<nsIDOMElement
> domElement
;
3668 instance
->GetDOMElement(getter_AddRefs(domElement
));
3669 nsCOMPtr
<nsIObjectLoadingContent
> objectContent
=
3670 do_QueryInterface(domElement
);
3672 instance
->Destroy();
3674 mInstances
.RemoveElement(instance
);
3675 OnPluginInstanceDestroyed(pluginTag
);
3677 // Notify owning content that we destroyed its plugin out from under it
3678 if (objectContent
) {
3679 objectContent
->PluginDestroyed();
3685 // Runnable that does an async destroy of a plugin.
3687 class nsPluginDestroyRunnable
: public nsRunnable
,
3691 nsPluginDestroyRunnable(nsNPAPIPluginInstance
*aInstance
)
3692 : mInstance(aInstance
)
3694 PR_INIT_CLIST(this);
3695 PR_APPEND_LINK(this, &sRunnableListHead
);
3698 virtual ~nsPluginDestroyRunnable()
3700 PR_REMOVE_LINK(this);
3705 nsRefPtr
<nsNPAPIPluginInstance
> instance
;
3707 // Null out mInstance to make sure this code in another runnable
3708 // will do the right thing even if someone was holding on to this
3709 // runnable longer than we expect.
3710 instance
.swap(mInstance
);
3712 if (PluginDestructionGuard::DelayDestroy(instance
)) {
3713 // It's still not safe to destroy the plugin, it's now up to the
3714 // outermost guard on the stack to take care of the destruction.
3718 nsPluginDestroyRunnable
*r
=
3719 static_cast<nsPluginDestroyRunnable
*>(PR_NEXT_LINK(&sRunnableListHead
));
3721 while (r
!= &sRunnableListHead
) {
3722 if (r
!= this && r
->mInstance
== instance
) {
3723 // There's another runnable scheduled to tear down
3724 // instance. Let it do the job.
3727 r
= static_cast<nsPluginDestroyRunnable
*>(PR_NEXT_LINK(r
));
3730 PLUGIN_LOG(PLUGIN_LOG_NORMAL
,
3731 ("Doing delayed destroy of instance %p\n", instance
.get()));
3733 nsRefPtr
<nsPluginHost
> host
= nsPluginHost::GetInst();
3735 host
->StopPluginInstance(instance
);
3737 PLUGIN_LOG(PLUGIN_LOG_NORMAL
,
3738 ("Done with delayed destroy of instance %p\n", instance
.get()));
3744 nsRefPtr
<nsNPAPIPluginInstance
> mInstance
;
3746 static PRCList sRunnableListHead
;
3749 PRCList
nsPluginDestroyRunnable::sRunnableListHead
=
3750 PR_INIT_STATIC_CLIST(&nsPluginDestroyRunnable::sRunnableListHead
);
3752 PRCList
PluginDestructionGuard::sListHead
=
3753 PR_INIT_STATIC_CLIST(&PluginDestructionGuard::sListHead
);
3755 PluginDestructionGuard::~PluginDestructionGuard()
3757 NS_ASSERTION(NS_IsMainThread(), "Should be on the main thread");
3759 PR_REMOVE_LINK(this);
3761 if (mDelayedDestroy
) {
3762 // We've attempted to destroy the plugin instance we're holding on
3763 // to while we were guarding it. Do the actual destroy now, off of
3765 nsRefPtr
<nsPluginDestroyRunnable
> evt
=
3766 new nsPluginDestroyRunnable(mInstance
);
3768 NS_DispatchToMainThread(evt
);
3774 PluginDestructionGuard::DelayDestroy(nsNPAPIPluginInstance
*aInstance
)
3776 NS_ASSERTION(NS_IsMainThread(), "Should be on the main thread");
3777 NS_ASSERTION(aInstance
, "Uh, I need an instance!");
3779 // Find the first guard on the stack and make it do a delayed
3780 // destroy upon destruction.
3782 PluginDestructionGuard
*g
=
3783 static_cast<PluginDestructionGuard
*>(PR_LIST_HEAD(&sListHead
));
3785 while (g
!= &sListHead
) {
3786 if (g
->mInstance
== aInstance
) {
3787 g
->mDelayedDestroy
= true;
3791 g
= static_cast<PluginDestructionGuard
*>(PR_NEXT_LINK(g
));