1 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2 /* ***** BEGIN LICENSE BLOCK *****
3 * Version: MPL 1.1/GPL 2.0/LGPL 2.1
5 * The contents of this file are subject to the Mozilla Public License Version
6 * 1.1 (the "License"); you may not use this file except in compliance with
7 * the License. You may obtain a copy of the License at
8 * http://www.mozilla.org/MPL/
10 * Software distributed under the License is distributed on an "AS IS" basis,
11 * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
12 * for the specific language governing rights and limitations under the
15 * The Original Code is mozilla.org code.
17 * The Initial Developer of the Original Code is
18 * Netscape Communications Corporation.
19 * Portions created by the Initial Developer are Copyright (C) 1998
20 * the Initial Developer. All Rights Reserved.
23 * Sean Echevarria <sean@beatnik.com>
24 * HÃ¥kan Waara <hwaara@chello.se>
25 * Josh Aas <josh@mozilla.com>
27 * Alternatively, the contents of this file may be used under the terms of
28 * either the GNU General Public License Version 2 or later (the "GPL"), or
29 * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
30 * in which case the provisions of the GPL or the LGPL are applicable instead
31 * of those above. If you wish to allow use of your version of this file only
32 * under the terms of either the GPL or the LGPL, and not to allow others to
33 * use your version of this file under the terms of the MPL, indicate your
34 * decision by deleting the provisions above and replace them with the notice
35 * and other provisions required by the GPL or the LGPL. If you do not delete
36 * the provisions above, a recipient may use your version of this file under
37 * the terms of any one of the MPL, the GPL or the LGPL.
39 * ***** END LICENSE BLOCK ***** */
41 /* nsPluginHostImpl.cpp - bulk of code for managing plugins */
44 #include "nsPluginHostImpl.h"
49 #include "nsNPAPIPlugin.h"
50 #include "nsNPAPIPluginStreamListener.h"
51 #include "nsPluginInstancePeer.h"
52 #include "nsIPlugin.h"
53 #include "nsIPluginInstanceInternal.h"
55 #include "nsIJVMPlugin.h"
56 #include "nsIJVMPluginInstance.h"
57 #include "nsIJVMManager.h"
59 #include "nsIPluginStreamListener.h"
60 #include "nsIHTTPHeaderListener.h"
61 #include "nsIHttpHeaderVisitor.h"
62 #include "nsIObserverService.h"
63 #include "nsIHttpProtocolHandler.h"
64 #include "nsIHttpChannel.h"
65 #include "nsIHttpChannelInternal.h"
66 #include "nsIUploadChannel.h"
67 #include "nsIByteRangeRequest.h"
68 #include "nsIStreamListener.h"
69 #include "nsIInputStream.h"
70 #include "nsIOutputStream.h"
72 #include "nsXPIDLString.h"
73 #include "nsReadableUtils.h"
74 #include "nsIProtocolProxyService.h"
75 #include "nsIStreamConverterService.h"
77 #include "nsIInputStream.h"
78 #include "nsIIOService.h"
80 #include "nsIChannel.h"
81 #include "nsISeekableStream.h"
82 #include "nsNetUtil.h"
83 #include "nsIProgressEventSink.h"
84 #include "nsIDocument.h"
85 #include "nsIScriptablePlugin.h"
86 #include "nsICachingChannel.h"
87 #include "nsHashtable.h"
88 #include "nsIProxyInfo.h"
89 #include "nsObsoleteModuleLoading.h"
90 #include "nsIComponentRegistrar.h"
91 #include "nsPluginLogging.h"
92 #include "nsIPrefBranch2.h"
93 #include "nsIScriptChannel.h"
94 #include "nsPrintfCString.h"
95 #include "nsIBlocklistService.h"
96 #include "nsVersionComparator.h"
98 // Friggin' X11 has to "#define None". Lame!
104 #undef CursorShape /*X.h defines it as 0,
105 qnamespace.h makes an enum type by that name
109 //#include "nsIRegistry.h"
110 #include "nsEnumeratorUtils.h"
112 #include "nsXPCOMCID.h"
113 #include "nsICategoryManager.h"
114 #include "nsISupportsPrimitives.h"
116 #include "nsIStringBundle.h"
117 #include "nsIWindowWatcher.h"
118 #include "nsPIDOMWindow.h"
120 #include "nsIScriptGlobalObject.h"
121 #include "nsIScriptGlobalObjectOwner.h"
122 #include "nsIPrincipal.h"
124 #include "nsIServiceManager.h"
125 #include "nsNetCID.h"
126 #include "nsICookieService.h"
127 #include "nsIDOMPlugin.h"
128 #include "nsIDOMMimeType.h"
129 #include "nsMimeTypes.h"
131 #include "nsThreadUtils.h"
132 #include "nsIInputStreamTee.h"
133 #include "nsIInterfaceInfoManager.h"
141 #include "nsIMIMEService.h"
142 #include "nsCExternalHandlerService.h"
143 #include "nsILocalFile.h"
144 #include "nsIFileChannel.h"
146 #include "nsPluginSafety.h"
148 #include "nsICharsetConverterManager.h"
149 #include "nsIPlatformCharset.h"
151 #include "nsIDirectoryService.h"
152 #include "nsDirectoryServiceDefs.h"
153 #include "nsAppDirectoryServiceDefs.h"
155 #include "nsPluginDirServiceProvider.h"
157 #include "nsPluginError.h"
159 #include "nsUnicharUtils.h"
160 #include "nsPluginManifestLineReader.h"
162 #include "imgILoader.h"
163 #include "nsDefaultPlugin.h"
164 #include "nsWeakReference.h"
165 #include "nsIDOMElement.h"
166 #include "nsIDOMHTMLObjectElement.h"
167 #include "nsIDOMHTMLEmbedElement.h"
168 #include "nsIPresShell.h"
169 #include "nsPresContext.h"
170 #include "nsIWebNavigation.h"
171 #include "nsISupportsArray.h"
172 #include "nsIDocShell.h"
173 #include "nsPluginNativeWindow.h"
174 #include "nsIScriptSecurityManager.h"
175 #include "nsIContentPolicy.h"
176 #include "nsContentPolicyUtils.h"
177 #include "nsContentErrors.h"
179 #if defined(XP_UNIX) && defined(MOZ_WIDGET_GTK2) & defined(MOZ_X11)
180 #include <gdk/gdkx.h> // for GDK_DISPLAY()
184 #include <Carbon/Carbon.h> // for ::UseInputWindow()
185 #include <mach-o/loader.h>
186 #include <mach-o/fat.h>
190 #include "nsILegacyPluginWrapperOS2.h"
193 // this is the name of the directory which will be created
194 // to cache temporary files.
195 #define kPluginTmpDirName NS_LITERAL_CSTRING("plugtmp")
197 // Version of cached plugin info
198 // 0.01 first implementation
199 // 0.02 added caching of CanUnload to fix bug 105935
200 // 0.03 changed name, description and mime desc from string to bytes, bug 108246
201 // 0.04 added new mime entry point on Mac, bug 113464
202 // 0.05 added new entry point check for the default plugin, bug 132430
203 // 0.06 strip off suffixes in mime description strings, bug 53895
204 // 0.07 changed nsIRegistry to flat file support for caching plugins info
205 // 0.08 mime entry point on MachO, bug 137535
206 // 0.09 the file encoding is changed to UTF-8, bug 420285
207 // 0.10 added plugin versions on appropriate platforms, bug 427743
208 // The current plugin registry version (and the maximum version we know how to read)
209 static const char *kPluginRegistryVersion
= "0.10";
210 // The minimum registry version we know how to read
211 static const char *kMinimumRegistryVersion
= "0.9";
214 static NS_DEFINE_IID(kIPluginInstanceIID
, NS_IPLUGININSTANCE_IID
);
215 static NS_DEFINE_CID(kPluginCID
, NS_PLUGIN_CID
);
216 static NS_DEFINE_IID(kIPluginTagInfo2IID
, NS_IPLUGINTAGINFO2_IID
);
217 static const char kDirectoryServiceContractID
[] = "@mozilla.org/file/directory_service;1";
219 static NS_DEFINE_CID(kCPluginManagerCID
, NS_PLUGINMANAGER_CID
); // needed for NS_TRY_SAFE_CALL
221 // Registry keys for caching plugin info
222 static const char kPluginsRootKey
[] = "software/plugins";
223 static const char kPluginsNameKey
[] = "name";
224 static const char kPluginsDescKey
[] = "description";
225 static const char kPluginsFilenameKey
[] = "filename";
226 static const char kPluginsFullpathKey
[] = "fullpath";
227 static const char kPluginsModTimeKey
[] = "lastModTimeStamp";
228 static const char kPluginsCanUnload
[] = "canUnload";
229 static const char kPluginsVersionKey
[] = "version";
230 static const char kPluginsMimeTypeKey
[] = "mimetype";
231 static const char kPluginsMimeDescKey
[] = "description";
232 static const char kPluginsMimeExtKey
[] = "extension";
234 #define kPluginRegistryFilename NS_LITERAL_CSTRING("pluginreg.dat")
236 #ifdef PLUGIN_LOGGING
237 PRLogModuleInfo
* nsPluginLogging::gNPNLog
= nsnull
;
238 PRLogModuleInfo
* nsPluginLogging::gNPPLog
= nsnull
;
239 PRLogModuleInfo
* nsPluginLogging::gPluginLog
= nsnull
;
242 #define BRAND_PROPERTIES_URL "chrome://branding/locale/brand.properties"
243 #define PLUGIN_PROPERTIES_URL "chrome://global/locale/downloadProgress.properties"
244 #define PLUGIN_REGIONAL_URL "chrome://global-region/locale/region.properties"
246 // #defines for reading prefs and extra search plugin paths from windows registry
247 #define _MAXKEYVALUE_ 8196
248 #define _NS_PREF_COMMON_PLUGIN_REG_KEY_ "browser.plugins.registry_plugins_folder_key_location"
249 #define _NS_COMMON_PLUGIN_KEY_NAME_ "Plugins Folders"
251 // #defines for plugin cache and prefs
252 #define NS_PREF_MAX_NUM_CACHED_PLUGINS "browser.plugins.max_num_cached_plugins"
253 #define DEFAULT_NUMBER_OF_STOPPED_PLUGINS 10
255 #define MAGIC_REQUEST_CONTEXT 0x01020304
257 nsresult
PostPluginUnloadEvent(PRLibrary
* aLibrary
);
259 static nsActivePluginList
*gActivePluginList
;
261 #ifdef CALL_SAFETY_ON
262 PRBool gSkipPluginSafeCalls
= PR_FALSE
;
265 nsIFile
*nsPluginHostImpl::sPluginTempDir
;
266 nsPluginHostImpl
*nsPluginHostImpl::sInst
;
268 // flat file reg funcs
270 PRBool
ReadSectionHeader(nsPluginManifestLineReader
& reader
, const char *token
)
273 if (*reader
.LinePtr() == '[') {
274 char* p
= reader
.LinePtr() + (reader
.LineLength() - 1);
280 if (1 != reader
.ParseLine(values
, 1))
282 // ignore the leading '['
283 if (PL_strcmp(values
[0]+1, token
)) {
284 break; // it's wrong token
288 } while (reader
.NextLine());
292 // Little helper struct to asynchronously reframe any presentations (embedded)
293 // or reload any documents (full-page), that contained plugins
294 // which were shutdown as a result of a plugins.refresh(1)
295 class nsPluginDocReframeEvent
: public nsRunnable
{
297 nsPluginDocReframeEvent(nsISupportsArray
* aDocs
) { mDocs
= aDocs
; }
301 nsCOMPtr
<nsISupportsArray
> mDocs
;
304 NS_IMETHODIMP
nsPluginDocReframeEvent::Run() {
305 NS_ENSURE_TRUE(mDocs
, NS_ERROR_FAILURE
);
310 // for each document (which previously had a running instance), tell
311 // the frame constructor to rebuild
312 for (PRUint32 i
= 0; i
< c
; i
++) {
313 nsCOMPtr
<nsIDocument
> doc (do_QueryElementAt(mDocs
, i
));
315 nsIPresShell
*shell
= doc
->GetPrimaryShell();
317 // if this document has a presentation shell, then it has frames and can be reframed
319 /* A reframe will cause a fresh object frame, instance owner, and instance
320 * to be created. Reframing of the entire document is necessary as we may have
321 * recently found new plugins and we want a shot at trying to use them instead
322 * of leaving alternate renderings.
323 * We do not want to completely reload all the documents that had running plugins
324 * because we could possibly trigger a script to run in the unload event handler
325 * which may want to access our defunct plugin and cause us to crash.
328 shell
->ReconstructFrames(); // causes reframe of document
329 } else { // no pres shell --> full-page plugin
331 NS_NOTREACHED("all plugins should have a pres shell!");
337 return mDocs
->Clear();
340 nsActivePlugin::nsActivePlugin(nsPluginTag
* aPluginTag
,
341 nsIPluginInstance
* aInstance
,
343 PRBool aDefaultPlugin
,
344 nsIPluginInstancePeer
* peer
)
348 mPluginTag
= aPluginTag
;
350 mURL
= PL_strdup(url
);
351 mInstance
= aInstance
;
352 if (aInstance
&& peer
) {
355 NS_ADDREF(aInstance
);
357 mXPConnected
= PR_FALSE
;
358 mDefaultPlugin
= aDefaultPlugin
;
360 mllStopTime
= LL_ZERO
;
363 nsActivePlugin::~nsActivePlugin()
369 nsCOMPtr
<nsPIPluginInstancePeer
> peer(do_QueryInterface(mPeer
));
370 nsCOMPtr
<nsIPluginInstanceOwner
> owner
;
371 rv
= peer
->GetOwner(getter_AddRefs(owner
));
373 owner
->SetInstance(nsnull
);
376 // now check for cached plugins because they haven't had nsIPluginInstance::Destroy()
377 // called yet. For non-cached plugins, nsIPluginInstance::Destroy() is called
378 // in either nsObjectFrame::Destroy() or nsActivePluginList::stopRunning()
379 PRBool doCache
= PR_TRUE
;
380 mInstance
->GetValue(nsPluginInstanceVariable_DoCacheBool
, (void *) &doCache
);
382 mInstance
->Destroy();
384 NS_RELEASE(mInstance
);
385 NS_IF_RELEASE(mPeer
);
390 void nsActivePlugin::setStopped(PRBool stopped
)
393 if (mStopped
) // plugin instance is told to stop
394 mllStopTime
= PR_Now();
396 mllStopTime
= LL_ZERO
;
399 nsActivePluginList::nsActivePluginList()
406 nsActivePluginList::~nsActivePluginList()
408 if (mFirst
== nsnull
)
413 void nsActivePluginList::shut()
418 for (nsActivePlugin
* plugin
= mFirst
; plugin
!= nsnull
;) {
419 nsActivePlugin
* next
= plugin
->mNext
;
427 PRInt32
nsActivePluginList::add(nsActivePlugin
* plugin
)
432 mFirst
->mNext
= nsnull
;
435 mLast
->mNext
= plugin
;
438 mLast
->mNext
= nsnull
;
443 PRBool
nsActivePluginList::IsLastInstance(nsActivePlugin
* plugin
)
448 if (!plugin
->mPluginTag
)
451 for (nsActivePlugin
* p
= mFirst
; p
!= nsnull
; p
= p
->mNext
) {
452 if ((p
->mPluginTag
== plugin
->mPluginTag
) && (p
!= plugin
))
458 PRBool
nsActivePluginList::remove(nsActivePlugin
* plugin
)
460 if (mFirst
== nsnull
)
463 nsActivePlugin
* prev
= nsnull
;
464 for (nsActivePlugin
* p
= mFirst
; p
!= nsnull
; p
= p
->mNext
) {
466 PRBool lastInstance
= IsLastInstance(p
);
471 prev
->mNext
= p
->mNext
;
473 if ((prev
!= nsnull
) && (prev
->mNext
== nsnull
))
476 // see if this is going to be the last instance of a plugin
477 // if so we should perform nsIPlugin::Shutdown and unload the library
478 // by calling nsPluginTag::TryUnloadPlugin()
480 // cache some things as we are going to destroy it right now
481 nsPluginTag
*pluginTag
= p
->mPluginTag
;
483 delete p
; // plugin instance is destroyed here
486 pluginTag
->TryUnloadPlugin();
488 NS_ASSERTION(pluginTag
, "pluginTag was not set, plugin not shutdown");
502 // This method terminates all running instances of plugins and collects their
503 // documents to be returned through an array. This method is used
504 // when we are shutting down or when a plugins.refresh(1) happens.
505 // If aPluginTag is given, then only that plugin is terminated
506 void nsActivePluginList::stopRunning(nsISupportsArray
* aReloadDocs
,
507 nsPluginTag
* aPluginTag
)
509 if (mFirst
== nsnull
)
512 PRBool doCallSetWindowAfterDestroy
= PR_FALSE
;
514 for (nsActivePlugin
* p
= mFirst
; p
!= nsnull
; p
= p
->mNext
) {
515 if (!p
->mStopped
&& p
->mInstance
&&
516 (!aPluginTag
|| aPluginTag
== p
->mPluginTag
)) {
517 // then determine if the plugin wants Destroy to be called after
518 // Set Window. This is for bug 50547.
519 p
->mInstance
->GetValue(nsPluginInstanceVariable_CallSetWindowAfterDestroyBool
,
520 (void *) &doCallSetWindowAfterDestroy
);
521 if (doCallSetWindowAfterDestroy
) {
522 p
->mInstance
->Stop();
523 p
->mInstance
->Destroy();
524 p
->mInstance
->SetWindow(nsnull
);
527 p
->mInstance
->SetWindow(nsnull
);
528 p
->mInstance
->Stop();
529 p
->mInstance
->Destroy();
531 doCallSetWindowAfterDestroy
= PR_FALSE
;
532 p
->setStopped(PR_TRUE
);
534 // If we've been passed an array to return, lets collect all our documents,
535 // removing duplicates. These will be reframed (embedded) or reloaded (full-page) later
536 // to kickstart our instances.
537 if (aReloadDocs
&& p
->mPeer
) {
538 nsCOMPtr
<nsPIPluginInstancePeer
> peer(do_QueryInterface(p
->mPeer
));
539 nsCOMPtr
<nsIPluginInstanceOwner
> owner
;
540 peer
->GetOwner(getter_AddRefs(owner
));
542 nsCOMPtr
<nsIDocument
> doc
;
543 owner
->GetDocument(getter_AddRefs(doc
));
544 if (doc
&& aReloadDocs
->IndexOf(doc
) == -1) // don't allow for duplicates
545 aReloadDocs
->AppendElement(doc
);
552 void nsActivePluginList::removeAllStopped()
554 if (mFirst
== nsnull
)
557 nsActivePlugin
* next
= nsnull
;
559 for (nsActivePlugin
* p
= mFirst
; p
!= nsnull
;) {
570 nsActivePlugin
* nsActivePluginList::find(nsIPluginInstance
* instance
)
572 for (nsActivePlugin
* p
= mFirst
; p
!= nsnull
; p
= p
->mNext
) {
573 if (p
->mInstance
== instance
) {
575 PRBool doCache
= PR_TRUE
;
576 p
->mInstance
->GetValue(nsPluginInstanceVariable_DoCacheBool
, (void *) &doCache
);
577 NS_ASSERTION(!p
->mStopped
|| doCache
, "This plugin is not supposed to be cached!");
585 nsActivePlugin
* nsActivePluginList::find(const char * mimetype
)
587 PRBool defaultplugin
= (PL_strcmp(mimetype
, "*") == 0);
589 for (nsActivePlugin
* p
= mFirst
; p
!= nsnull
; p
= p
->mNext
) {
590 // give it some special treatment for the default plugin first
591 // because we cannot tell the default plugin by asking peer for a mime type
592 if (defaultplugin
&& p
->mDefaultPlugin
)
600 nsresult res
= p
->mPeer
->GetMIMEType(&mt
);
605 if (PL_strcasecmp(mt
, mimetype
) == 0) {
607 PRBool doCache
= PR_TRUE
;
608 p
->mInstance
->GetValue(nsPluginInstanceVariable_DoCacheBool
, (void *) &doCache
);
609 NS_ASSERTION(!p
->mStopped
|| doCache
, "This plugin is not supposed to be cached!");
617 nsActivePlugin
* nsActivePluginList::findStopped(const char * url
)
619 for (nsActivePlugin
* p
= mFirst
; p
!= nsnull
; p
= p
->mNext
) {
620 if (!PL_strcmp(url
, p
->mURL
) && p
->mStopped
) {
622 PRBool doCache
= PR_TRUE
;
623 p
->mInstance
->GetValue(nsPluginInstanceVariable_DoCacheBool
, (void *) &doCache
);
624 NS_ASSERTION(doCache
, "This plugin is not supposed to be cached!");
632 PRUint32
nsActivePluginList::getStoppedCount()
634 PRUint32 stoppedCount
= 0;
635 for (nsActivePlugin
* p
= mFirst
; p
!= nsnull
; p
= p
->mNext
) {
642 nsActivePlugin
* nsActivePluginList::findOldestStopped()
644 nsActivePlugin
* res
= nsnull
;
645 PRInt64 llTime
= LL_MAXINT
;
646 for (nsActivePlugin
* p
= mFirst
; p
!= nsnull
; p
= p
->mNext
) {
650 if (LL_CMP(p
->mllStopTime
, <, llTime
)) {
651 llTime
= p
->mllStopTime
;
658 PRBool doCache
= PR_TRUE
;
659 res
->mInstance
->GetValue(nsPluginInstanceVariable_DoCacheBool
, (void *) &doCache
);
660 NS_ASSERTION(doCache
, "This plugin is not supposed to be cached!");
667 inline char* new_str(const char* str
)
672 char* result
= new char[strlen(str
) + 1];
673 if (result
!= nsnull
)
674 return strcpy(result
, str
);
678 nsPluginTag::nsPluginTag(nsPluginTag
* aPluginTag
)
679 : mPluginHost(nsnull
),
680 mName(aPluginTag
->mName
),
681 mDescription(aPluginTag
->mDescription
),
682 mVariants(aPluginTag
->mVariants
),
683 mMimeTypeArray(nsnull
),
684 mMimeDescriptionArray(aPluginTag
->mMimeDescriptionArray
),
685 mExtensionsArray(nsnull
),
688 mCanUnloadLibrary(PR_TRUE
),
689 mXPConnected(PR_FALSE
),
690 mIsJavaPlugin(aPluginTag
->mIsJavaPlugin
),
691 mIsNPRuntimeEnabledJavaPlugin(aPluginTag
->mIsNPRuntimeEnabledJavaPlugin
),
692 mFileName(aPluginTag
->mFileName
),
693 mFullPath(aPluginTag
->mFullPath
),
694 mVersion(aPluginTag
->mVersion
),
695 mLastModifiedTime(0),
696 mFlags(NS_PLUGIN_FLAG_ENABLED
)
698 if (aPluginTag
->mMimeTypeArray
!= nsnull
) {
699 mMimeTypeArray
= new char*[mVariants
];
700 for (int i
= 0; i
< mVariants
; i
++)
701 mMimeTypeArray
[i
] = new_str(aPluginTag
->mMimeTypeArray
[i
]);
704 if (aPluginTag
->mExtensionsArray
!= nsnull
) {
705 mExtensionsArray
= new char*[mVariants
];
706 for (int i
= 0; i
< mVariants
; i
++)
707 mExtensionsArray
[i
] = new_str(aPluginTag
->mExtensionsArray
[i
]);
711 nsPluginTag::nsPluginTag(nsPluginInfo
* aPluginInfo
)
712 : mPluginHost(nsnull
),
713 mName(aPluginInfo
->fName
),
714 mDescription(aPluginInfo
->fDescription
),
715 mVariants(aPluginInfo
->fVariantCount
),
716 mMimeTypeArray(nsnull
),
717 mExtensionsArray(nsnull
),
721 mCanUnloadLibrary(!aPluginInfo
->fBundle
),
723 mCanUnloadLibrary(PR_TRUE
),
725 mXPConnected(PR_FALSE
),
726 mIsJavaPlugin(PR_FALSE
),
727 mIsNPRuntimeEnabledJavaPlugin(PR_FALSE
),
728 mFileName(aPluginInfo
->fFileName
),
729 mFullPath(aPluginInfo
->fFullPath
),
730 mVersion(aPluginInfo
->fVersion
),
731 mLastModifiedTime(0),
732 mFlags(NS_PLUGIN_FLAG_ENABLED
)
734 if (aPluginInfo
->fMimeTypeArray
!= nsnull
) {
735 mMimeTypeArray
= new char*[mVariants
];
736 for (int i
= 0; i
< mVariants
; i
++) {
737 if (mIsJavaPlugin
&& aPluginInfo
->fMimeTypeArray
[i
] &&
738 strcmp(aPluginInfo
->fMimeTypeArray
[i
],
739 "application/x-java-vm-npruntime") == 0) {
740 mIsNPRuntimeEnabledJavaPlugin
= PR_TRUE
;
742 // Stop processing here, any mimetypes after the magic "I'm a
743 // NPRuntime enabled Java plugin" mimetype will be ignored.
749 mMimeTypeArray
[i
] = new_str(aPluginInfo
->fMimeTypeArray
[i
]);
750 if (nsPluginHostImpl::IsJavaMIMEType(mMimeTypeArray
[i
]))
751 mIsJavaPlugin
= PR_TRUE
;
755 if (aPluginInfo
->fMimeDescriptionArray
!= nsnull
) {
756 for (int i
= 0; i
< mVariants
; i
++) {
757 // we should cut off the list of suffixes which the mime
758 // description string may have, see bug 53895
759 // it is usually in form "some description (*.sf1, *.sf2)"
760 // so we can search for the opening round bracket
763 char * p
= PL_strrchr(aPluginInfo
->fMimeDescriptionArray
[i
], '(');
764 if (p
&& (p
!= aPluginInfo
->fMimeDescriptionArray
[i
])) {
765 if ((p
- 1) && *(p
- 1) == ' ') {
774 mMimeDescriptionArray
.AppendElement(
775 aPluginInfo
->fMimeDescriptionArray
[i
]);
776 // restore the original string
783 mMimeDescriptionArray
.SetLength(mVariants
);
786 if (aPluginInfo
->fExtensionArray
!= nsnull
) {
787 mExtensionsArray
= new char*[mVariants
];
788 for (int i
= 0; i
< mVariants
; i
++)
789 mExtensionsArray
[i
] = new_str(aPluginInfo
->fExtensionArray
[i
]);
792 EnsureMembersAreUTF8();
795 nsPluginTag::nsPluginTag(const char* aName
,
796 const char* aDescription
,
797 const char* aFileName
,
798 const char* aFullPath
,
799 const char* aVersion
,
800 const char* const* aMimeTypes
,
801 const char* const* aMimeDescriptions
,
802 const char* const* aExtensions
,
804 PRInt64 aLastModifiedTime
,
807 : mPluginHost(nsnull
),
809 mDescription(aDescription
),
810 mVariants(aVariants
),
811 mMimeTypeArray(nsnull
),
812 mExtensionsArray(nsnull
),
815 mCanUnloadLibrary(aCanUnload
),
816 mXPConnected(PR_FALSE
),
817 mIsJavaPlugin(PR_FALSE
),
818 mIsNPRuntimeEnabledJavaPlugin(PR_FALSE
),
819 mFileName(aFileName
),
820 mFullPath(aFullPath
),
822 mLastModifiedTime(aLastModifiedTime
),
823 mFlags(0) // Caller will read in our flags from cache
826 mMimeTypeArray
= new char*[mVariants
];
827 mExtensionsArray
= new char*[mVariants
];
829 for (PRInt32 i
= 0; i
< aVariants
; ++i
) {
830 if (mIsJavaPlugin
&& aMimeTypes
[i
] &&
831 strcmp(aMimeTypes
[i
], "application/x-java-vm-npruntime") == 0) {
832 mIsNPRuntimeEnabledJavaPlugin
= PR_TRUE
;
834 // Stop processing here, any mimetypes after the magic "I'm a
835 // NPRuntime enabled Java plugin" mimetype will be ignored.
841 mMimeTypeArray
[i
] = new_str(aMimeTypes
[i
]);
842 mMimeDescriptionArray
.AppendElement(aMimeDescriptions
[i
]);
843 mExtensionsArray
[i
] = new_str(aExtensions
[i
]);
844 if (nsPluginHostImpl::IsJavaMIMEType(mMimeTypeArray
[i
]))
845 mIsJavaPlugin
= PR_TRUE
;
850 EnsureMembersAreUTF8();
853 nsPluginTag::~nsPluginTag()
855 TryUnloadPlugin(PR_TRUE
);
857 // Remove mime types added to the category manager
858 // only if we were made 'active' by setting the host
860 RegisterWithCategoryManager(PR_FALSE
, nsPluginTag::ePluginUnregister
);
863 if (mMimeTypeArray
) {
864 for (int i
= 0; i
< mVariants
; i
++)
865 delete[] mMimeTypeArray
[i
];
867 delete[] (mMimeTypeArray
);
868 mMimeTypeArray
= nsnull
;
871 if (mExtensionsArray
) {
872 for (int i
= 0; i
< mVariants
; i
++)
873 delete[] mExtensionsArray
[i
];
875 delete[] (mExtensionsArray
);
876 mExtensionsArray
= nsnull
;
880 NS_IMPL_ISUPPORTS1(nsPluginTag
, nsIPluginTag
)
882 static nsresult
ConvertToUTF8(nsIUnicodeDecoder
*aUnicodeDecoder
,
883 nsAFlatCString
& aString
)
887 PRInt32 numberOfBytes
= aString
.Length();
888 PRInt32 outUnicodeLen
;
890 rv
= aUnicodeDecoder
->GetMaxLength(aString
.get(), numberOfBytes
,
892 NS_ENSURE_SUCCESS(rv
, rv
);
893 if (!EnsureStringLength(buffer
, outUnicodeLen
))
894 return NS_ERROR_OUT_OF_MEMORY
;
895 rv
= aUnicodeDecoder
->Convert(aString
.get(), &numberOfBytes
,
896 buffer
.BeginWriting(), &outUnicodeLen
);
897 NS_ENSURE_SUCCESS(rv
, rv
);
898 buffer
.SetLength(outUnicodeLen
);
899 CopyUTF16toUTF8(buffer
, aString
);
904 nsresult
nsPluginTag::EnsureMembersAreUTF8()
908 nsCOMPtr
<nsIPlatformCharset
> pcs
=
909 do_GetService(NS_PLATFORMCHARSET_CONTRACTID
, &rv
);
910 NS_ENSURE_SUCCESS(rv
, rv
);
911 nsCOMPtr
<nsIUnicodeDecoder
> decoder
;
912 nsCOMPtr
<nsICharsetConverterManager
> ccm
=
913 do_GetService(NS_CHARSETCONVERTERMANAGER_CONTRACTID
, &rv
);
914 NS_ENSURE_SUCCESS(rv
, rv
);
916 nsCAutoString charset
;
917 rv
= pcs
->GetCharset(kPlatformCharsetSel_FileName
, charset
);
918 NS_ENSURE_SUCCESS(rv
, rv
);
919 if (!charset
.LowerCaseEqualsLiteral("utf-8")) {
920 rv
= ccm
->GetUnicodeDecoderRaw(charset
.get(), getter_AddRefs(decoder
));
921 NS_ENSURE_SUCCESS(rv
, rv
);
923 ConvertToUTF8(decoder
, mFileName
);
924 ConvertToUTF8(decoder
, mFullPath
);
927 // The description of the plug-in and the various MIME type descriptions
928 // should be encoded in the standard plain text file encoding for this system.
929 // XXX should we add kPlatformCharsetSel_PluginResource?
930 rv
= pcs
->GetCharset(kPlatformCharsetSel_PlainTextInFile
, charset
);
931 NS_ENSURE_SUCCESS(rv
, rv
);
932 if (!charset
.LowerCaseEqualsLiteral("utf-8")) {
933 rv
= ccm
->GetUnicodeDecoderRaw(charset
.get(), getter_AddRefs(decoder
));
934 NS_ENSURE_SUCCESS(rv
, rv
);
936 ConvertToUTF8(decoder
, mName
);
937 ConvertToUTF8(decoder
, mDescription
);
938 for (PRUint32 i
= 0; i
< mMimeDescriptionArray
.Length(); ++i
) {
939 ConvertToUTF8(decoder
, mMimeDescriptionArray
[i
]);
945 void nsPluginTag::SetHost(nsPluginHostImpl
* aHost
)
951 nsPluginTag::GetDescription(nsACString
& aDescription
)
953 aDescription
= mDescription
;
958 nsPluginTag::GetFilename(nsACString
& aFileName
)
960 aFileName
= mFileName
;
965 nsPluginTag::GetVersion(nsACString
& aVersion
)
972 nsPluginTag::GetName(nsACString
& aName
)
979 nsPluginTag::GetDisabled(PRBool
* aDisabled
)
981 *aDisabled
= !HasFlag(NS_PLUGIN_FLAG_ENABLED
);
986 nsPluginTag::SetDisabled(PRBool aDisabled
)
988 if (HasFlag(NS_PLUGIN_FLAG_ENABLED
) == !aDisabled
)
993 nsCOMPtr
<nsIPrefBranch
> pref(do_GetService(NS_PREFSERVICE_CONTRACTID
, &rv
));
994 NS_ENSURE_SUCCESS(rv
, rv
);
997 rv
= pref
->GetBoolPref("security.enable_java", &javaEnabled
);
998 NS_ENSURE_SUCCESS(rv
, rv
);
1000 if (javaEnabled
== aDisabled
)
1001 return pref
->SetBoolPref("security.enable_java", !aDisabled
);
1005 UnMark(NS_PLUGIN_FLAG_ENABLED
);
1007 Mark(NS_PLUGIN_FLAG_ENABLED
);
1009 mPluginHost
->UpdatePluginInfo(this);
1014 nsPluginTag::GetBlocklisted(PRBool
* aBlocklisted
)
1016 *aBlocklisted
= HasFlag(NS_PLUGIN_FLAG_BLOCKLISTED
);
1021 nsPluginTag::SetBlocklisted(PRBool aBlocklisted
)
1023 if (HasFlag(NS_PLUGIN_FLAG_BLOCKLISTED
) == aBlocklisted
)
1027 Mark(NS_PLUGIN_FLAG_BLOCKLISTED
);
1029 UnMark(NS_PLUGIN_FLAG_BLOCKLISTED
);
1031 mPluginHost
->UpdatePluginInfo(nsnull
);
1035 // helper struct for asynchronous handeling of plugin unloading
1036 class nsPluginUnloadEvent
: public nsRunnable
{
1038 nsPluginUnloadEvent(PRLibrary
* aLibrary
)
1039 : mLibrary(aLibrary
)
1044 PRLibrary
* mLibrary
;
1047 NS_IMETHODIMP
nsPluginUnloadEvent::Run()
1050 // put our unload call in a saftey wrapper
1051 NS_TRY_SAFE_CALL_VOID(PR_UnloadLibrary(mLibrary
), nsnull
, nsnull
);
1053 NS_WARNING("missing library from nsPluginUnloadEvent");
1058 // unload plugin asynchronously if possible, otherwise just unload now
1059 nsresult
PostPluginUnloadEvent(PRLibrary
* aLibrary
)
1061 nsCOMPtr
<nsIRunnable
> ev
= new nsPluginUnloadEvent(aLibrary
);
1062 if (ev
&& NS_SUCCEEDED(NS_DispatchToCurrentThread(ev
)))
1066 NS_TRY_SAFE_CALL_VOID(PR_UnloadLibrary(aLibrary
), nsnull
, nsnull
);
1068 return NS_ERROR_FAILURE
;
1071 void nsPluginTag::TryUnloadPlugin(PRBool aForceShutdown
)
1073 PRBool isXPCOM
= PR_FALSE
;
1074 if (!(mFlags
& NS_PLUGIN_FLAG_OLDSCHOOL
))
1077 if (isXPCOM
&& !aForceShutdown
) return;
1080 mEntryPoint
->Shutdown();
1081 mEntryPoint
->Release();
1082 mEntryPoint
= nsnull
;
1085 // before we unload check if we are allowed to, see bug #61388
1086 // also, never unload an XPCOM plugin library
1087 if (mLibrary
&& mCanUnloadLibrary
&& !isXPCOM
) {
1088 // NPAPI plugins can be unloaded now if they don't use XPConnect
1090 // unload the plugin asynchronously by posting a PLEvent
1091 PostPluginUnloadEvent(mLibrary
);
1093 // add library to the unused library list to handle it later
1095 mPluginHost
->AddUnusedLibrary(mLibrary
);
1099 // we should zero it anyway, it is going to be unloaded by
1100 // CleanUnsedLibraries before we need to call the library
1101 // again so the calling code should not be fooled and reload
1102 // the library fresh
1106 PRBool
nsPluginTag::Equals(nsPluginTag
*aPluginTag
)
1108 NS_ENSURE_TRUE(aPluginTag
, PR_FALSE
);
1110 if ((!mName
.Equals(aPluginTag
->mName
)) ||
1111 (!mDescription
.Equals(aPluginTag
->mDescription
)) ||
1112 (mVariants
!= aPluginTag
->mVariants
))
1115 if (mVariants
&& mMimeTypeArray
&& aPluginTag
->mMimeTypeArray
) {
1116 for (PRInt32 i
= 0; i
< mVariants
; i
++) {
1117 if (PL_strcmp(mMimeTypeArray
[i
], aPluginTag
->mMimeTypeArray
[i
]) != 0)
1124 class nsPluginStreamListenerPeer
;
1126 class nsPluginStreamInfo
: public nsINPAPIPluginStreamInfo
1129 nsPluginStreamInfo();
1130 virtual ~nsPluginStreamInfo();
1134 // nsINPAPIPluginStreamInfo interface
1137 GetContentType(nsMIMEType
* result
);
1140 IsSeekable(PRBool
* result
);
1143 GetLength(PRUint32
* result
);
1146 GetLastModified(PRUint32
* result
);
1149 GetURL(const char** result
);
1152 RequestRead(nsByteRange
* rangeList
);
1155 GetStreamOffset(PRInt32
*result
);
1158 SetStreamOffset(PRInt32 result
);
1163 SetContentType(const nsMIMEType contentType
);
1166 SetSeekable(const PRBool seekable
);
1169 SetLength(const PRUint32 length
);
1172 SetLastModified(const PRUint32 modified
);
1175 SetURL(const char* url
);
1178 SetPluginInstance(nsIPluginInstance
* aPluginInstance
);
1181 SetPluginStreamListenerPeer(nsPluginStreamListenerPeer
* aPluginStreamListenerPeer
);
1184 MakeByteRangeString(nsByteRange
* aRangeList
, nsACString
&string
, PRInt32
*numRequests
);
1187 UseExistingPluginCacheFile(nsPluginStreamInfo
* psi
);
1190 SetStreamComplete(const PRBool complete
);
1193 SetRequest(nsIRequest
*request
)
1205 nsIPluginInstance
* mPluginInstance
;
1206 nsPluginStreamListenerPeer
* mPluginStreamListenerPeer
;
1207 PRInt32 mStreamOffset
;
1208 PRBool mStreamComplete
;
1211 class nsPluginStreamListenerPeer
: public nsIStreamListener
,
1212 public nsIProgressEventSink
,
1213 public nsIHttpHeaderVisitor
,
1214 public nsSupportsWeakReference
1217 nsPluginStreamListenerPeer();
1218 virtual ~nsPluginStreamListenerPeer();
1221 NS_DECL_NSIPROGRESSEVENTSINK
1222 NS_DECL_NSIREQUESTOBSERVER
1223 NS_DECL_NSISTREAMLISTENER
1224 NS_DECL_NSIHTTPHEADERVISITOR
1226 // Called by GetURL and PostURL (via NewStream)
1227 nsresult
Initialize(nsIURI
*aURL
,
1228 nsIPluginInstance
*aInstance
,
1229 nsIPluginStreamListener
*aListener
,
1230 PRInt32 requestCount
= 1);
1232 nsresult
InitializeEmbedded(nsIURI
*aURL
,
1233 nsIPluginInstance
* aInstance
,
1234 nsIPluginInstanceOwner
*aOwner
= nsnull
,
1235 nsIPluginHost
*aHost
= nsnull
);
1237 nsresult
InitializeFullPage(nsIPluginInstance
*aInstance
);
1239 nsresult
OnFileAvailable(nsIFile
* aFile
);
1241 nsresult
ServeStreamAsFile(nsIRequest
*request
, nsISupports
*ctxt
);
1243 nsIPluginInstance
*GetPluginInstance() { return mInstance
; }
1246 nsresult
SetUpCache(nsIURI
* aURL
); // todo: see about removing this...
1247 nsresult
SetUpStreamListener(nsIRequest
* request
, nsIURI
* aURL
);
1248 nsresult
SetupPluginCacheFile(nsIChannel
* channel
);
1251 nsIPluginInstanceOwner
*mOwner
;
1252 nsIPluginInstance
*mInstance
;
1253 nsIPluginStreamListener
*mPStreamListener
;
1254 nsRefPtr
<nsPluginStreamInfo
> mPluginStreamInfo
;
1256 // Set to PR_TRUE if we request failed (like with a HTTP response of 404)
1257 PRPackedBool mRequestFailed
;
1260 * Set to PR_TRUE after nsIPluginInstancePeer::OnStartBinding() has
1261 * been called. Checked in ::OnStopRequest so we can call the
1262 * plugin's OnStartBinding if, for some reason, it has not already
1265 PRPackedBool mStartBinding
;
1266 PRPackedBool mHaveFiredOnStartRequest
;
1267 // these get passed to the plugin stream listener
1270 nsPluginStreamType mStreamType
;
1271 nsIPluginHost
*mHost
;
1273 // local cached file, we save the content into local cache if browser cache is not available,
1274 // or plugin asks stream as file and it expects file extension until bug 90558 got fixed
1275 nsIFile
*mLocalCachedFile
;
1276 nsCOMPtr
<nsIOutputStream
> mFileCacheOutputStream
;
1277 nsHashtable
*mDataForwardToRequest
;
1281 PRInt32 mPendingRequests
;
1282 nsWeakPtr mWeakPtrChannelCallbacks
;
1283 nsWeakPtr mWeakPtrChannelLoadGroup
;
1286 class nsPluginByteRangeStreamListener
: public nsIStreamListener
{
1288 nsPluginByteRangeStreamListener(nsIWeakReference
* aWeakPtr
);
1289 virtual ~nsPluginByteRangeStreamListener();
1294 // nsIRequestObserver methods:
1295 NS_DECL_NSIREQUESTOBSERVER
1297 // nsIStreamListener methods:
1298 NS_DECL_NSISTREAMLISTENER
1301 nsCOMPtr
<nsIStreamListener
> mStreamConverter
;
1302 nsWeakPtr mWeakPtrPluginStreamListenerPeer
;
1303 PRBool mRemoveMagicNumber
;
1306 nsPluginStreamInfo::nsPluginStreamInfo()
1308 mPluginInstance
= nsnull
;
1309 mPluginStreamListenerPeer
= nsnull
;
1311 mContentType
= nsnull
;
1313 mSeekable
= PR_FALSE
;
1317 mStreamComplete
= PR_FALSE
;
1320 nsPluginStreamInfo::~nsPluginStreamInfo()
1323 PL_strfree(mContentType
);
1327 NS_IF_RELEASE(mPluginInstance
);
1330 NS_IMPL_ISUPPORTS2(nsPluginStreamInfo
, nsIPluginStreamInfo
,
1331 nsINPAPIPluginStreamInfo
)
1334 nsPluginStreamInfo::GetContentType(nsMIMEType
* result
)
1336 *result
= mContentType
;
1341 nsPluginStreamInfo::IsSeekable(PRBool
* result
)
1343 *result
= mSeekable
;
1348 nsPluginStreamInfo::GetLength(PRUint32
* result
)
1355 nsPluginStreamInfo::GetLastModified(PRUint32
* result
)
1357 *result
= mModified
;
1362 nsPluginStreamInfo::GetURL(const char** result
)
1369 nsPluginStreamInfo::MakeByteRangeString(nsByteRange
* aRangeList
, nsACString
&rangeRequest
, PRInt32
*numRequests
)
1371 rangeRequest
.Truncate();
1373 //the string should look like this: bytes=500-700,601-999
1377 PRInt32 requestCnt
= 0;
1378 nsCAutoString
string("bytes=");
1380 for (nsByteRange
* range
= aRangeList
; range
!= nsnull
; range
= range
->next
) {
1385 // XXX needs to be fixed for negative offsets
1386 string
.AppendInt(range
->offset
);
1388 string
.AppendInt(range
->offset
+ range
->length
- 1);
1395 // get rid of possible trailing comma
1396 string
.Trim(",", PR_FALSE
);
1398 rangeRequest
= string
;
1399 *numRequests
= requestCnt
;
1404 nsPluginStreamInfo::RequestRead(nsByteRange
* rangeList
)
1406 nsCAutoString rangeString
;
1407 PRInt32 numRequests
;
1409 //first of all lets see if mPluginStreamListenerPeer is still alive
1410 nsCOMPtr
<nsISupportsWeakReference
> suppWeakRef(
1411 do_QueryInterface((nsISupportsWeakReference
*)(mPluginStreamListenerPeer
)));
1413 return NS_ERROR_FAILURE
;
1415 nsCOMPtr
<nsIWeakReference
> pWeakRefPluginStreamListenerPeer
=
1416 do_GetWeakReference(suppWeakRef
);
1417 if (!pWeakRefPluginStreamListenerPeer
)
1418 return NS_ERROR_FAILURE
;
1420 MakeByteRangeString(rangeList
, rangeString
, &numRequests
);
1422 if (numRequests
== 0)
1423 return NS_ERROR_FAILURE
;
1425 nsresult rv
= NS_OK
;
1426 nsCOMPtr
<nsIURI
> url
;
1428 rv
= NS_NewURI(getter_AddRefs(url
), nsDependentCString(mURL
));
1430 nsCOMPtr
<nsIInterfaceRequestor
> callbacks
= do_QueryReferent(mPluginStreamListenerPeer
->mWeakPtrChannelCallbacks
);
1431 nsCOMPtr
<nsILoadGroup
> loadGroup
= do_QueryReferent(mPluginStreamListenerPeer
->mWeakPtrChannelLoadGroup
);
1432 nsCOMPtr
<nsIChannel
> channel
;
1433 rv
= NS_NewChannel(getter_AddRefs(channel
), url
, nsnull
, loadGroup
, callbacks
);
1437 nsCOMPtr
<nsIHttpChannel
> httpChannel(do_QueryInterface(channel
));
1439 return NS_ERROR_FAILURE
;
1441 httpChannel
->SetRequestHeader(NS_LITERAL_CSTRING("Range"), rangeString
, PR_FALSE
);
1443 mPluginStreamListenerPeer
->mAbort
= PR_TRUE
; // instruct old stream listener to cancel
1444 // the request on the next ODA.
1446 nsCOMPtr
<nsIStreamListener
> converter
;
1448 if (numRequests
== 1) {
1449 converter
= mPluginStreamListenerPeer
;
1451 // set current stream offset equal to the first offset in the range list
1452 // it will work for single byte range request
1453 // for multy range we'll reset it in ODA
1454 SetStreamOffset(rangeList
->offset
);
1456 nsPluginByteRangeStreamListener
*brrListener
=
1457 new nsPluginByteRangeStreamListener(pWeakRefPluginStreamListenerPeer
);
1459 converter
= brrListener
;
1461 return NS_ERROR_OUT_OF_MEMORY
;
1464 mPluginStreamListenerPeer
->mPendingRequests
+= numRequests
;
1466 nsCOMPtr
<nsISupportsPRUint32
> container
= do_CreateInstance(NS_SUPPORTS_PRUINT32_CONTRACTID
, &rv
);
1469 rv
= container
->SetData(MAGIC_REQUEST_CONTEXT
);
1473 return channel
->AsyncOpen(converter
, container
);
1477 nsPluginStreamInfo::GetStreamOffset(PRInt32
*result
)
1479 *result
= mStreamOffset
;
1484 nsPluginStreamInfo::SetStreamOffset(PRInt32 offset
)
1486 mStreamOffset
= offset
;
1491 nsPluginStreamInfo::SetContentType(const nsMIMEType contentType
)
1493 if (mContentType
!= nsnull
)
1494 PL_strfree(mContentType
);
1496 mContentType
= PL_strdup(contentType
);
1500 nsPluginStreamInfo::SetSeekable(const PRBool seekable
)
1502 mSeekable
= seekable
;
1506 nsPluginStreamInfo::SetLength(const PRUint32 length
)
1512 nsPluginStreamInfo::SetLastModified(const PRUint32 modified
)
1514 mModified
= modified
;
1518 nsPluginStreamInfo::SetURL(const char* url
)
1523 mURL
= PL_strdup(url
);
1527 nsPluginStreamInfo::SetPluginInstance(nsIPluginInstance
* aPluginInstance
)
1529 NS_IF_ADDREF(mPluginInstance
= aPluginInstance
);
1533 nsPluginStreamInfo::SetPluginStreamListenerPeer(nsPluginStreamListenerPeer
* aPluginStreamListenerPeer
)
1535 // not addref'd - nsPluginStreamInfo is owned by mPluginStreamListenerPeer
1536 mPluginStreamListenerPeer
= aPluginStreamListenerPeer
;
1539 class nsPluginCacheListener
: public nsIStreamListener
1542 nsPluginCacheListener(nsPluginStreamListenerPeer
* aListener
);
1543 virtual ~nsPluginCacheListener();
1547 NS_DECL_NSIREQUESTOBSERVER
1548 NS_DECL_NSISTREAMLISTENER
1551 nsPluginStreamListenerPeer
* mListener
;
1554 nsPluginCacheListener::nsPluginCacheListener(nsPluginStreamListenerPeer
* aListener
)
1556 mListener
= aListener
;
1557 NS_ADDREF(mListener
);
1560 nsPluginCacheListener::~nsPluginCacheListener()
1562 NS_IF_RELEASE(mListener
);
1565 NS_IMPL_ISUPPORTS1(nsPluginCacheListener
, nsIStreamListener
)
1568 nsPluginCacheListener::OnStartRequest(nsIRequest
*request
, nsISupports
* ctxt
)
1574 nsPluginCacheListener::OnDataAvailable(nsIRequest
*request
, nsISupports
* ctxt
,
1575 nsIInputStream
* aIStream
,
1576 PRUint32 sourceOffset
,
1581 char* buffer
= (char*) PR_Malloc(aLength
);
1583 // if we don't read from the stream, OnStopRequest will never be called
1585 return NS_ERROR_OUT_OF_MEMORY
;
1587 nsresult rv
= aIStream
->Read(buffer
, aLength
, &readlen
);
1589 NS_ASSERTION(aLength
== readlen
, "nsCacheListener->OnDataAvailable: "
1590 "readlen != aLength");
1597 nsPluginCacheListener::OnStopRequest(nsIRequest
*request
,
1598 nsISupports
* aContext
,
1604 nsPluginStreamListenerPeer::nsPluginStreamListenerPeer()
1609 mPStreamListener
= nsnull
;
1611 mStreamType
= nsPluginStreamType_Normal
;
1612 mStartBinding
= PR_FALSE
;
1614 mRequestFailed
= PR_FALSE
;
1616 mPendingRequests
= 0;
1617 mHaveFiredOnStartRequest
= PR_FALSE
;
1618 mDataForwardToRequest
= nsnull
;
1619 mLocalCachedFile
= nsnull
;
1622 nsPluginStreamListenerPeer::~nsPluginStreamListenerPeer()
1624 #ifdef PLUGIN_LOGGING
1625 nsCAutoString urlSpec
;
1626 if (mURL
!= nsnull
) (void)mURL
->GetSpec(urlSpec
);
1628 PR_LOG(nsPluginLogging::gPluginLog
, PLUGIN_LOG_NORMAL
,
1629 ("nsPluginStreamListenerPeer::dtor this=%p, url=%s%c",this, urlSpec
.get(), mLocalCachedFile
?',':'\n'));
1632 NS_IF_RELEASE(mURL
);
1633 NS_IF_RELEASE(mOwner
);
1634 NS_IF_RELEASE(mInstance
);
1635 NS_IF_RELEASE(mPStreamListener
);
1636 NS_IF_RELEASE(mHost
);
1638 // close FD of mFileCacheOutputStream if it's still open
1639 // or we won't be able to remove the cache file
1640 if (mFileCacheOutputStream
)
1641 mFileCacheOutputStream
= nsnull
;
1643 // if we have mLocalCachedFile lets release it
1644 // and it'll be fiscally remove if refcnt == 1
1645 if (mLocalCachedFile
) {
1647 NS_RELEASE2(mLocalCachedFile
, refcnt
);
1649 #ifdef PLUGIN_LOGGING
1650 nsCAutoString filePath
;
1651 mLocalCachedFile
->GetNativePath(filePath
);
1653 PR_LOG(nsPluginLogging::gPluginLog
, PLUGIN_LOG_NORMAL
,
1654 ("LocalyCachedFile=%s has %d refcnt and will %s be deleted now\n",filePath
.get(),refcnt
,refcnt
==1?"":"NOT"));
1658 mLocalCachedFile
->Remove(PR_FALSE
);
1659 NS_RELEASE(mLocalCachedFile
);
1663 delete mDataForwardToRequest
;
1666 NS_IMPL_ISUPPORTS4(nsPluginStreamListenerPeer
,
1669 nsIHttpHeaderVisitor
,
1670 nsISupportsWeakReference
)
1672 // Called as a result of GetURL and PostURL
1673 nsresult
nsPluginStreamListenerPeer::Initialize(nsIURI
*aURL
,
1674 nsIPluginInstance
*aInstance
,
1675 nsIPluginStreamListener
* aListener
,
1676 PRInt32 requestCount
)
1678 #ifdef PLUGIN_LOGGING
1679 nsCAutoString urlSpec
;
1680 if (aURL
!= nsnull
) (void)aURL
->GetAsciiSpec(urlSpec
);
1682 PR_LOG(nsPluginLogging::gPluginLog
, PLUGIN_LOG_NORMAL
,
1683 ("nsPluginStreamListenerPeer::Initialize instance=%p, url=%s\n", aInstance
, urlSpec
.get()));
1691 mInstance
= aInstance
;
1692 NS_ADDREF(mInstance
);
1694 mPStreamListener
= aListener
;
1695 NS_ADDREF(mPStreamListener
);
1697 mPluginStreamInfo
= new nsPluginStreamInfo();
1698 if (!mPluginStreamInfo
)
1699 return NS_ERROR_OUT_OF_MEMORY
;
1701 mPluginStreamInfo
->SetPluginInstance(aInstance
);
1702 mPluginStreamInfo
->SetPluginStreamListenerPeer(this);
1704 mPendingRequests
= requestCount
;
1706 mDataForwardToRequest
= new nsHashtable(16, PR_FALSE
);
1707 if (!mDataForwardToRequest
)
1708 return NS_ERROR_FAILURE
;
1714 /* Called by NewEmbeddedPluginStream() - if this is called, we weren't
1715 * able to load the plugin, so we need to load it later once we figure
1716 * out the mimetype. In order to load it later, we need the plugin
1717 * host and instance owner.
1719 nsresult
nsPluginStreamListenerPeer::InitializeEmbedded(nsIURI
*aURL
,
1720 nsIPluginInstance
* aInstance
,
1721 nsIPluginInstanceOwner
*aOwner
,
1722 nsIPluginHost
*aHost
)
1724 #ifdef PLUGIN_LOGGING
1725 nsCAutoString urlSpec
;
1726 (void)aURL
->GetSpec(urlSpec
);
1728 PR_LOG(nsPluginLogging::gPluginLog
, PLUGIN_LOG_NORMAL
,
1729 ("nsPluginStreamListenerPeer::InitializeEmbedded url=%s\n", urlSpec
.get()));
1738 NS_ASSERTION(mInstance
== nsnull
, "nsPluginStreamListenerPeer::InitializeEmbedded mInstance != nsnull");
1739 mInstance
= aInstance
;
1740 NS_ADDREF(mInstance
);
1743 NS_IF_ADDREF(mOwner
);
1746 NS_IF_ADDREF(mHost
);
1749 mPluginStreamInfo
= new nsPluginStreamInfo();
1750 if (!mPluginStreamInfo
)
1751 return NS_ERROR_OUT_OF_MEMORY
;
1753 mPluginStreamInfo
->SetPluginInstance(aInstance
);
1754 mPluginStreamInfo
->SetPluginStreamListenerPeer(this);
1756 mDataForwardToRequest
= new nsHashtable(16, PR_FALSE
);
1757 if (!mDataForwardToRequest
)
1758 return NS_ERROR_FAILURE
;
1764 // Called by NewFullPagePluginStream()
1765 nsresult
nsPluginStreamListenerPeer::InitializeFullPage(nsIPluginInstance
*aInstance
)
1767 PLUGIN_LOG(PLUGIN_LOG_NORMAL
,
1768 ("nsPluginStreamListenerPeer::InitializeFullPage instance=%p\n",aInstance
));
1770 NS_ASSERTION(mInstance
== nsnull
, "nsPluginStreamListenerPeer::InitializeFullPage mInstance != nsnull");
1771 mInstance
= aInstance
;
1772 NS_ADDREF(mInstance
);
1774 mPluginStreamInfo
= new nsPluginStreamInfo();
1775 if (!mPluginStreamInfo
)
1776 return NS_ERROR_OUT_OF_MEMORY
;
1778 mPluginStreamInfo
->SetPluginInstance(aInstance
);
1779 mPluginStreamInfo
->SetPluginStreamListenerPeer(this);
1781 mDataForwardToRequest
= new nsHashtable(16, PR_FALSE
);
1782 if (!mDataForwardToRequest
)
1783 return NS_ERROR_FAILURE
;
1788 // SetupPluginCacheFile is called if we have to save the stream to disk.
1789 // the most likely cause for this is either there is no disk cache available
1790 // or the stream is coming from a https server.
1792 // These files will be deleted when the host is destroyed.
1794 // TODO? What if we fill up the the dest dir?
1796 nsPluginStreamListenerPeer::SetupPluginCacheFile(nsIChannel
* channel
)
1798 nsresult rv
= NS_OK
;
1799 // lets try to reused a file if we already have in the local plugin cache
1800 // we loop through all of active plugins
1801 // and call |nsPluginStreamInfo::UseExistingPluginCacheFile()| on opened stream
1802 // will return RP_TRUE if file exisrs
1803 // and some conditions are matched, in this case that file will be use
1804 // in |::OnFileAvailable()| calls w/o rewriting the file again.
1805 // The file will be deleted in |nsPluginStreamListenerPeer::~nsPluginStreamListenerPeer|
1806 PRBool useExistingCacheFile
= PR_FALSE
;
1807 nsActivePlugin
*pActivePlugins
= gActivePluginList
->mFirst
;
1808 while (pActivePlugins
&& pActivePlugins
->mStreams
&& !useExistingCacheFile
) {
1809 // most recent streams are at the end of list
1811 pActivePlugins
->mStreams
->Count((PRUint32
*)&cnt
);
1812 while (--cnt
>= 0 && !useExistingCacheFile
) {
1813 nsPluginStreamListenerPeer
*lp
=
1814 reinterpret_cast<nsPluginStreamListenerPeer
*>(pActivePlugins
->mStreams
->ElementAt(cnt
));
1816 if (lp
->mLocalCachedFile
&&
1817 lp
->mPluginStreamInfo
&&
1818 (useExistingCacheFile
=
1819 lp
->mPluginStreamInfo
->UseExistingPluginCacheFile(mPluginStreamInfo
))) {
1820 NS_ADDREF(mLocalCachedFile
= lp
->mLocalCachedFile
);
1825 pActivePlugins
= pActivePlugins
->mNext
;
1828 if (!useExistingCacheFile
) {
1829 nsCOMPtr
<nsIFile
> pluginTmp
;
1830 rv
= nsPluginHostImpl::GetPluginTempDir(getter_AddRefs(pluginTmp
));
1831 if (NS_FAILED(rv
)) {
1835 // Get the filename from the channel
1836 nsCOMPtr
<nsIURI
> uri
;
1837 rv
= channel
->GetURI(getter_AddRefs(uri
));
1838 if (NS_FAILED(rv
)) return rv
;
1840 nsCOMPtr
<nsIURL
> url(do_QueryInterface(uri
));
1842 return NS_ERROR_FAILURE
;
1844 nsCAutoString filename
;
1845 url
->GetFileName(filename
);
1849 // Create a file to save our stream into. Should we scramble the name?
1850 filename
.Insert(NS_LITERAL_CSTRING("plugin-"), 0);
1851 rv
= pluginTmp
->AppendNative(filename
);
1855 // Yes, make it unique.
1856 rv
= pluginTmp
->CreateUnique(nsIFile::NORMAL_FILE_TYPE
, 0600);
1860 // create a file output stream to write to...
1861 nsCOMPtr
<nsIOutputStream
> outstream
;
1862 rv
= NS_NewLocalFileOutputStream(getter_AddRefs(mFileCacheOutputStream
), pluginTmp
, -1, 00600);
1867 CallQueryInterface(pluginTmp
, &mLocalCachedFile
); // no need to check return value, just addref
1868 // add one extra refcnt, we can use NS_RELEASE2(mLocalCachedFile...) in dtor
1869 // to remove this file when refcnt == 1
1870 NS_ADDREF(mLocalCachedFile
);
1873 // add this listenerPeer to list of stream peers for this instance
1874 // it'll delay release of listenerPeer until nsActivePlugin::~nsActivePlugin
1875 // and the temp file is going to stay alive until then
1876 pActivePlugins
= gActivePluginList
->find(mInstance
);
1877 if (pActivePlugins
) {
1878 if (!pActivePlugins
->mStreams
&&
1879 (NS_FAILED(rv
= NS_NewISupportsArray(getter_AddRefs(pActivePlugins
->mStreams
))))) {
1883 nsISupports
* supports
= static_cast<nsISupports
*>((static_cast<nsIStreamListener
*>(this)));
1884 pActivePlugins
->mStreams
->AppendElement(supports
);
1891 nsPluginStreamListenerPeer::OnStartRequest(nsIRequest
*request
,
1892 nsISupports
* aContext
)
1894 nsresult rv
= NS_OK
;
1896 if (mHaveFiredOnStartRequest
) {
1900 mHaveFiredOnStartRequest
= PR_TRUE
;
1902 nsCOMPtr
<nsIChannel
> channel
= do_QueryInterface(request
);
1903 NS_ENSURE_TRUE(channel
, NS_ERROR_FAILURE
);
1905 // deal with 404 (Not Found) HTTP response,
1906 // just return, this causes the request to be ignored.
1907 nsCOMPtr
<nsIHttpChannel
> httpChannel(do_QueryInterface(channel
));
1909 PRUint32 responseCode
= 0;
1910 rv
= httpChannel
->GetResponseStatus(&responseCode
);
1911 if (NS_FAILED(rv
)) {
1912 // NPP_Notify() will be called from OnStopRequest
1913 // in nsNPAPIPluginStreamListener::CleanUpStream
1914 // return error will cancel this request
1915 // ...and we also need to tell the plugin that
1916 mRequestFailed
= PR_TRUE
;
1917 return NS_ERROR_FAILURE
;
1920 if (responseCode
> 206) { // not normal
1921 PRBool bWantsAllNetworkStreams
= PR_FALSE
;
1922 mInstance
->GetValue(nsPluginInstanceVariable_WantsAllNetworkStreams
,
1923 (void *)&bWantsAllNetworkStreams
);
1924 if (!bWantsAllNetworkStreams
) {
1925 mRequestFailed
= PR_TRUE
;
1926 return NS_ERROR_FAILURE
;
1931 // do a little sanity check to make sure our frame isn't gone
1932 // by getting the tag type and checking for an error, we can determine if
1933 // the frame is gone
1935 nsCOMPtr
<nsIPluginTagInfo2
> pti2
= do_QueryInterface(mOwner
);
1936 NS_ENSURE_TRUE(pti2
, NS_ERROR_FAILURE
);
1937 nsPluginTagType tagType
;
1938 if (NS_FAILED(pti2
->GetTagType(&tagType
)))
1939 return NS_ERROR_FAILURE
; // something happened to our object frame, so bail!
1942 // Get the notification callbacks from the channel and save it as
1943 // week ref we'll use it in nsPluginStreamInfo::RequestRead() when
1944 // we'll create channel for byte range request.
1945 nsCOMPtr
<nsIInterfaceRequestor
> callbacks
;
1946 channel
->GetNotificationCallbacks(getter_AddRefs(callbacks
));
1948 mWeakPtrChannelCallbacks
= do_GetWeakReference(callbacks
);
1950 nsCOMPtr
<nsILoadGroup
> loadGroup
;
1951 channel
->GetLoadGroup(getter_AddRefs(loadGroup
));
1953 mWeakPtrChannelLoadGroup
= do_GetWeakReference(loadGroup
);
1956 rv
= channel
->GetContentLength(&length
);
1958 // it's possible for the server to not send a Content-Length.
1959 // we should still work in this case.
1960 if (NS_FAILED(rv
) || length
== -1) {
1961 // check out if this is file channel
1962 nsCOMPtr
<nsIFileChannel
> fileChannel
= do_QueryInterface(channel
);
1964 // file does not exist
1965 mRequestFailed
= PR_TRUE
;
1966 return NS_ERROR_FAILURE
;
1968 mPluginStreamInfo
->SetLength(PRUint32(0));
1971 mPluginStreamInfo
->SetLength(length
);
1974 mPluginStreamInfo
->SetRequest(request
);
1976 nsCAutoString aContentType
; // XXX but we already got the type above!
1977 rv
= channel
->GetContentType(aContentType
);
1981 nsCOMPtr
<nsIURI
> aURL
;
1982 rv
= channel
->GetURI(getter_AddRefs(aURL
));
1986 nsCAutoString urlSpec
;
1987 aURL
->GetSpec(urlSpec
);
1988 mPluginStreamInfo
->SetURL(urlSpec
.get());
1990 if (!aContentType
.IsEmpty())
1991 mPluginStreamInfo
->SetContentType(aContentType
.get());
1993 #ifdef PLUGIN_LOGGING
1994 PR_LOG(nsPluginLogging::gPluginLog
, PLUGIN_LOG_NOISY
,
1995 ("nsPluginStreamListenerPeer::OnStartRequest this=%p request=%p mime=%s, url=%s\n",
1996 this, request
, aContentType
.get(), urlSpec
.get()));
2001 nsPluginWindow
*window
= nsnull
;
2003 // if we don't have an nsIPluginInstance (mInstance), it means
2004 // we weren't able to load a plugin previously because we
2005 // didn't have the mimetype. Now that we do (aContentType),
2006 // we'll try again with SetUpPluginInstance()
2007 // which is called by InstantiateEmbeddedPlugin()
2008 // NOTE: we don't want to try again if we didn't get the MIME type this time
2010 if (!mInstance
&& mOwner
&& !aContentType
.IsEmpty()) {
2011 mOwner
->GetInstance(mInstance
);
2012 mOwner
->GetWindow(window
);
2013 if (!mInstance
&& mHost
&& window
) {
2014 // determine if we need to try embedded again. FullPage takes a different code path
2016 mOwner
->GetMode(&mode
);
2017 if (mode
== nsPluginMode_Embedded
)
2018 rv
= mHost
->InstantiateEmbeddedPlugin(aContentType
.get(), aURL
, mOwner
);
2020 rv
= mHost
->SetUpPluginInstance(aContentType
.get(), aURL
, mOwner
);
2023 // GetInstance() adds a ref
2024 mOwner
->GetInstance(mInstance
);
2027 mOwner
->CreateWidget();
2028 // If we've got a native window, the let the plugin know about it.
2029 if (window
->window
) {
2030 nsCOMPtr
<nsIPluginInstance
> inst
= mInstance
;
2031 ((nsPluginNativeWindow
*)window
)->CallSetWindow(inst
);
2038 // Set up the stream listener...
2039 rv
= SetUpStreamListener(request
, aURL
);
2040 if (NS_FAILED(rv
)) return rv
;
2045 NS_IMETHODIMP
nsPluginStreamListenerPeer::OnProgress(nsIRequest
*request
,
2046 nsISupports
* aContext
,
2048 PRUint64 aProgressMax
)
2050 nsresult rv
= NS_OK
;
2054 NS_IMETHODIMP
nsPluginStreamListenerPeer::OnStatus(nsIRequest
*request
,
2055 nsISupports
* aContext
,
2057 const PRUnichar
* aStatusArg
)
2062 class nsPRUintKey
: public nsHashKey
{
2066 nsPRUintKey(PRUint32 key
) : mKey(key
) {}
2068 PRUint32
HashCode(void) const {
2072 PRBool
Equals(const nsHashKey
*aKey
) const {
2073 return mKey
== ((const nsPRUintKey
*)aKey
)->mKey
;
2075 nsHashKey
*Clone() const {
2076 return new nsPRUintKey(mKey
);
2078 PRUint32
GetValue() { return mKey
; }
2081 NS_IMETHODIMP
nsPluginStreamListenerPeer::OnDataAvailable(nsIRequest
*request
,
2082 nsISupports
* aContext
,
2083 nsIInputStream
*aIStream
,
2084 PRUint32 sourceOffset
,
2088 return NS_ERROR_FAILURE
;
2091 PRUint32 magicNumber
= 0; // set it to something that is not the magic number.
2092 nsCOMPtr
<nsISupportsPRUint32
> container
= do_QueryInterface(aContext
);
2094 container
->GetData(&magicNumber
);
2096 if (magicNumber
!= MAGIC_REQUEST_CONTEXT
) {
2097 // this is not one of our range requests
2099 return NS_BINDING_ABORTED
;
2103 nsresult rv
= NS_OK
;
2105 if (!mPStreamListener
|| !mPluginStreamInfo
)
2106 return NS_ERROR_FAILURE
;
2108 mPluginStreamInfo
->SetRequest(request
);
2110 const char * url
= nsnull
;
2111 mPluginStreamInfo
->GetURL(&url
);
2113 PLUGIN_LOG(PLUGIN_LOG_NOISY
,
2114 ("nsPluginStreamListenerPeer::OnDataAvailable this=%p request=%p, offset=%d, length=%d, url=%s\n",
2115 this, request
, sourceOffset
, aLength
, url
? url
: "no url set"));
2117 // if the plugin has requested an AsFileOnly stream, then don't
2118 // call OnDataAvailable
2119 if (mStreamType
!= nsPluginStreamType_AsFileOnly
) {
2120 // get the absolute offset of the request, if one exists.
2121 nsCOMPtr
<nsIByteRangeRequest
> brr
= do_QueryInterface(request
);
2123 if (!mDataForwardToRequest
)
2124 return NS_ERROR_FAILURE
;
2126 PRInt64 absoluteOffset64
= LL_ZERO
;
2127 brr
->GetStartRange(&absoluteOffset64
);
2129 // XXX handle 64-bit for real
2130 PRInt32 absoluteOffset
= (PRInt32
)nsInt64(absoluteOffset64
);
2132 // we need to track how much data we have forwarded to the
2135 // FIXME: http://bugzilla.mozilla.org/show_bug.cgi?id=240130
2137 // Why couldn't this be tracked on the plugin info, and not in a
2139 nsPRUintKey
key(absoluteOffset
);
2140 PRInt32 amtForwardToPlugin
=
2141 NS_PTR_TO_INT32(mDataForwardToRequest
->Get(&key
));
2142 mDataForwardToRequest
->Put(&key
, NS_INT32_TO_PTR(amtForwardToPlugin
+ aLength
));
2144 mPluginStreamInfo
->SetStreamOffset(absoluteOffset
+ amtForwardToPlugin
);
2147 nsCOMPtr
<nsIInputStream
> stream
= aIStream
;
2149 // if we are caching the file ourselves to disk, we want to 'tee' off
2150 // the data as the plugin read from the stream. We do this by the magic
2151 // of an input stream tee.
2153 if (mFileCacheOutputStream
) {
2154 rv
= NS_NewInputStreamTee(getter_AddRefs(stream
), aIStream
, mFileCacheOutputStream
);
2159 rv
= mPStreamListener
->OnDataAvailable(mPluginStreamInfo
,
2163 // if a plugin returns an error, the peer must kill the stream
2164 // else the stream and PluginStreamListener leak
2166 request
->Cancel(rv
);
2170 // if we don't read from the stream, OnStopRequest will never be called
2171 char* buffer
= new char[aLength
];
2172 PRUint32 amountRead
, amountWrote
= 0;
2173 rv
= aIStream
->Read(buffer
, aLength
, &amountRead
);
2175 // if we are caching this to disk ourselves, lets write the bytes out.
2176 if (mFileCacheOutputStream
) {
2177 while (amountWrote
< amountRead
&& NS_SUCCEEDED(rv
)) {
2178 rv
= mFileCacheOutputStream
->Write(buffer
, amountRead
, &amountWrote
);
2186 NS_IMETHODIMP
nsPluginStreamListenerPeer::OnStopRequest(nsIRequest
*request
,
2187 nsISupports
* aContext
,
2190 nsresult rv
= NS_OK
;
2192 PLUGIN_LOG(PLUGIN_LOG_NOISY
,
2193 ("nsPluginStreamListenerPeer::OnStopRequest this=%p aStatus=%d request=%p\n",
2194 this, aStatus
, request
));
2196 // for ByteRangeRequest we're just updating the mDataForwardToRequest hash and return.
2197 nsCOMPtr
<nsIByteRangeRequest
> brr
= do_QueryInterface(request
);
2199 PRInt64 absoluteOffset64
= LL_ZERO
;
2200 brr
->GetStartRange(&absoluteOffset64
);
2201 // XXX support 64-bit offsets
2202 PRInt32 absoluteOffset
= (PRInt32
)nsInt64(absoluteOffset64
);
2204 nsPRUintKey
key(absoluteOffset
);
2206 // remove the request from our data forwarding count hash.
2207 (void) mDataForwardToRequest
->Remove(&key
);
2210 PLUGIN_LOG(PLUGIN_LOG_NOISY
,
2211 (" ::OnStopRequest for ByteRangeRequest Started=%d\n",
2214 // if this is not byte range request and
2215 // if we are writting the stream to disk ourselves,
2216 // close & tear it down here
2217 mFileCacheOutputStream
= nsnull
;
2220 // if we still have pending stuff to do, lets not close the plugin socket.
2221 if (--mPendingRequests
> 0)
2224 // we keep our connections around...
2225 nsCOMPtr
<nsISupportsPRUint32
> container
= do_QueryInterface(aContext
);
2227 PRUint32 magicNumber
= 0; // set it to something that is not the magic number.
2228 container
->GetData(&magicNumber
);
2229 if (magicNumber
== MAGIC_REQUEST_CONTEXT
) {
2230 // this is one of our range requests
2235 if (!mPStreamListener
)
2236 return NS_ERROR_FAILURE
;
2238 nsCOMPtr
<nsIChannel
> channel
= do_QueryInterface(request
);
2240 return NS_ERROR_FAILURE
;
2241 // Set the content type to ensure we don't pass null to the plugin
2242 nsCAutoString aContentType
;
2243 rv
= channel
->GetContentType(aContentType
);
2244 if (NS_FAILED(rv
) && !mRequestFailed
)
2247 if (!aContentType
.IsEmpty())
2248 mPluginStreamInfo
->SetContentType(aContentType
.get());
2250 // set error status if stream failed so we notify the plugin
2252 aStatus
= NS_ERROR_FAILURE
;
2254 if (NS_FAILED(aStatus
)) {
2255 // on error status cleanup the stream
2256 // and return w/o OnFileAvailable()
2257 mPStreamListener
->OnStopBinding(mPluginStreamInfo
, aStatus
);
2261 // call OnFileAvailable if plugin requests stream type StreamType_AsFile or StreamType_AsFileOnly
2262 if (mStreamType
>= nsPluginStreamType_AsFile
) {
2263 nsCOMPtr
<nsIFile
> localFile
= do_QueryInterface(mLocalCachedFile
);
2265 nsCOMPtr
<nsICachingChannel
> cacheChannel
= do_QueryInterface(request
);
2267 cacheChannel
->GetCacheFile(getter_AddRefs(localFile
));
2269 // see if it is a file channel.
2270 nsCOMPtr
<nsIFileChannel
> fileChannel
= do_QueryInterface(request
);
2272 fileChannel
->GetFile(getter_AddRefs(localFile
));
2278 OnFileAvailable(localFile
);
2282 if (mStartBinding
) {
2283 // On start binding has been called
2284 mPStreamListener
->OnStopBinding(mPluginStreamInfo
, aStatus
);
2286 // OnStartBinding hasn't been called, so complete the action.
2287 mPStreamListener
->OnStartBinding(mPluginStreamInfo
);
2288 mPStreamListener
->OnStopBinding(mPluginStreamInfo
, aStatus
);
2291 if (NS_SUCCEEDED(aStatus
))
2292 mPluginStreamInfo
->SetStreamComplete(PR_TRUE
);
2297 // private methods for nsPluginStreamListenerPeer
2298 nsresult
nsPluginStreamListenerPeer::SetUpCache(nsIURI
* aURL
)
2300 nsPluginCacheListener
* cacheListener
= new nsPluginCacheListener(this);
2301 // XXX: Null LoadGroup?
2302 return NS_OpenURI(cacheListener
, nsnull
, aURL
, nsnull
);
2305 nsresult
nsPluginStreamListenerPeer::SetUpStreamListener(nsIRequest
*request
,
2308 nsresult rv
= NS_OK
;
2310 // If we don't yet have a stream listener, we need to get
2311 // one from the plugin.
2312 // NOTE: this should only happen when a stream was NOT created
2313 // with GetURL or PostURL (i.e. it's the initial stream we
2314 // send to the plugin as determined by the SRC or DATA attribute)
2315 if (mPStreamListener
== nsnull
&& mInstance
!= nsnull
)
2316 rv
= mInstance
->NewStream(&mPStreamListener
);
2321 if (mPStreamListener
== nsnull
)
2322 return NS_ERROR_NULL_POINTER
;
2324 PRBool useLocalCache
= PR_FALSE
;
2326 // get httpChannel to retrieve some info we need for nsIPluginStreamInfo setup
2327 nsCOMPtr
<nsIChannel
> channel
= do_QueryInterface(request
);
2328 nsCOMPtr
<nsIHttpChannel
> httpChannel
= do_QueryInterface(channel
);
2332 * By the time nsPluginStreamListenerPeer::OnDataAvailable() gets
2333 * called, all the headers have been read.
2336 // Reassemble the HTTP response status line and provide it to our
2337 // listener. Would be nice if we could get the raw status line,
2338 // but nsIHttpChannel doesn't currently provide that.
2339 nsCOMPtr
<nsIHTTPHeaderListener
> listener
=
2340 do_QueryInterface(mPStreamListener
);
2342 // Status code: required; the status line isn't useful without it.
2344 if (NS_SUCCEEDED(httpChannel
->GetResponseStatus(&statusNum
)) &&
2346 // HTTP version: provide if available. Defaults to empty string.
2348 nsCOMPtr
<nsIHttpChannelInternal
> httpChannelInternal
=
2349 do_QueryInterface(channel
);
2350 if (httpChannelInternal
) {
2351 PRUint32 major
, minor
;
2352 if (NS_SUCCEEDED(httpChannelInternal
->GetResponseVersion(&major
,
2354 ver
= nsPrintfCString("/%lu.%lu", major
, minor
);
2358 // Status text: provide if available. Defaults to "OK".
2359 nsCString statusText
;
2360 if (NS_FAILED(httpChannel
->GetResponseStatusText(statusText
))) {
2364 // Assemble everything and pass to listener.
2365 nsPrintfCString
status(100, "HTTP%s %lu %s", ver
.get(), statusNum
,
2367 listener
->StatusLine(status
.get());
2371 // Also provide all HTTP response headers to our listener.
2372 httpChannel
->VisitResponseHeaders(this);
2374 PRBool bSeekable
= PR_FALSE
;
2375 // first we look for a content-encoding header. If we find one, we tell the
2376 // plugin that stream is not seekable, because the plugin always sees
2377 // uncompressed data, so it can't make meaningful range requests on a
2378 // compressed entity. Also, we force the plugin to use
2379 // nsPluginStreamType_AsFile stream type and we have to save decompressed
2380 // file into local plugin cache, because necko cache contains original
2382 nsCAutoString contentEncoding
;
2383 if (NS_SUCCEEDED(httpChannel
->GetResponseHeader(NS_LITERAL_CSTRING("Content-Encoding"),
2384 contentEncoding
))) {
2385 useLocalCache
= PR_TRUE
;
2387 // set seekability (seekable if the stream has a known length and if the
2388 // http server accepts byte ranges).
2390 mPluginStreamInfo
->GetLength(&length
);
2392 nsCAutoString range
;
2393 if (NS_SUCCEEDED(httpChannel
->GetResponseHeader(NS_LITERAL_CSTRING("accept-ranges"), range
)) &&
2394 range
.Equals(NS_LITERAL_CSTRING("bytes"), nsCaseInsensitiveCStringComparator())) {
2395 bSeekable
= PR_TRUE
;
2396 // nsPluginStreamInfo.mSeekable intitialized by PR_FALSE in ctor of nsPluginStreamInfo
2397 // so we reset it only here.
2398 mPluginStreamInfo
->SetSeekable(bSeekable
);
2403 // we require a content len
2404 // get Last-Modified header for plugin info
2405 nsCAutoString lastModified
;
2406 if (NS_SUCCEEDED(httpChannel
->GetResponseHeader(NS_LITERAL_CSTRING("last-modified"), lastModified
)) &&
2407 !lastModified
.IsEmpty()) {
2409 PR_ParseTimeString(lastModified
.get(), PR_TRUE
, &time64
); //convert string time to integer time
2411 // Convert PRTime to unix-style time_t, i.e. seconds since the epoch
2413 LL_L2D(fpTime
, time64
);
2414 mPluginStreamInfo
->SetLastModified((PRUint32
)(fpTime
* 1e-6 + 0.5));
2418 rv
= mPStreamListener
->OnStartBinding(mPluginStreamInfo
);
2420 mStartBinding
= PR_TRUE
;
2425 mPStreamListener
->GetStreamType(&mStreamType
);
2427 if (!useLocalCache
&& mStreamType
>= nsPluginStreamType_AsFile
) {
2428 // check it out if this is not a file channel.
2429 nsCOMPtr
<nsIFileChannel
> fileChannel
= do_QueryInterface(request
);
2431 // and browser cache is not available
2432 nsCOMPtr
<nsICachingChannel
> cacheChannel
= do_QueryInterface(request
);
2433 if (!(cacheChannel
&& (NS_SUCCEEDED(cacheChannel
->SetCacheAsFile(PR_TRUE
))))) {
2434 useLocalCache
= PR_TRUE
;
2439 if (useLocalCache
) {
2440 SetupPluginCacheFile(channel
);
2447 nsPluginStreamListenerPeer::OnFileAvailable(nsIFile
* aFile
)
2450 if (!mPStreamListener
)
2451 return NS_ERROR_FAILURE
;
2454 rv
= aFile
->GetNativePath(path
);
2455 if (NS_FAILED(rv
)) return rv
;
2457 if (path
.IsEmpty()) {
2458 NS_WARNING("empty path");
2462 rv
= mPStreamListener
->OnFileAvailable(mPluginStreamInfo
, path
.get());
2467 nsPluginStreamListenerPeer::VisitHeader(const nsACString
&header
, const nsACString
&value
)
2469 nsCOMPtr
<nsIHTTPHeaderListener
> listener
= do_QueryInterface(mPStreamListener
);
2471 return NS_ERROR_FAILURE
;
2473 return listener
->NewResponseHeader(PromiseFlatCString(header
).get(),
2474 PromiseFlatCString(value
).get());
2477 nsPluginHostImpl::nsPluginHostImpl()
2479 mPluginsLoaded
= PR_FALSE
;
2480 mDontShowBadPluginMessage
= PR_FALSE
;
2481 mIsDestroyed
= PR_FALSE
;
2482 mOverrideInternalTypes
= PR_FALSE
;
2483 mAllowAlienStarHandler
= PR_FALSE
;
2484 mUnusedLibraries
.Clear();
2485 mDefaultPluginDisabled
= PR_FALSE
;
2486 mJavaEnabled
= PR_TRUE
;
2488 gActivePluginList
= &mActivePluginList
;
2490 // check to see if pref is set at startup to let plugins take over in
2491 // full page mode for certain image mime types that we handle internally
2492 mPrefService
= do_GetService(NS_PREFSERVICE_CONTRACTID
);
2495 nsresult rv
= mPrefService
->GetBoolPref("plugin.override_internal_types",
2497 if (NS_SUCCEEDED(rv
)) {
2498 mOverrideInternalTypes
= tmp
;
2501 rv
= mPrefService
->GetBoolPref("plugin.allow_alien_star_handler", &tmp
);
2502 if (NS_SUCCEEDED(rv
)) {
2503 mAllowAlienStarHandler
= tmp
;
2506 rv
= mPrefService
->GetBoolPref("plugin.default_plugin_disabled", &tmp
);
2507 if (NS_SUCCEEDED(rv
)) {
2508 mDefaultPluginDisabled
= tmp
;
2512 mDefaultPluginDisabled
= PR_TRUE
;
2515 rv
= mPrefService
->GetBoolPref("security.enable_java", &tmp
);
2516 if (NS_SUCCEEDED(rv
)) {
2521 nsCOMPtr
<nsIObserverService
> obsService
= do_GetService("@mozilla.org/observer-service;1");
2524 obsService
->AddObserver(this, NS_XPCOM_SHUTDOWN_OBSERVER_ID
, PR_FALSE
);
2527 #ifdef PLUGIN_LOGGING
2528 nsPluginLogging::gNPNLog
= PR_NewLogModule(NPN_LOG_NAME
);
2529 nsPluginLogging::gNPPLog
= PR_NewLogModule(NPP_LOG_NAME
);
2530 nsPluginLogging::gPluginLog
= PR_NewLogModule(PLUGIN_LOG_NAME
);
2532 PR_LOG(nsPluginLogging::gNPNLog
, PLUGIN_LOG_ALWAYS
,("NPN Logging Active!\n"));
2533 PR_LOG(nsPluginLogging::gPluginLog
, PLUGIN_LOG_ALWAYS
,("General Plugin Logging Active! (nsPluginHostImpl::ctor)\n"));
2534 PR_LOG(nsPluginLogging::gNPPLog
, PLUGIN_LOG_ALWAYS
,("NPP Logging Active!\n"));
2536 PLUGIN_LOG(PLUGIN_LOG_ALWAYS
,("nsPluginHostImpl::ctor\n"));
2539 mCachedPlugins
= nsnull
;
2542 nsPluginHostImpl::~nsPluginHostImpl()
2544 PLUGIN_LOG(PLUGIN_LOG_ALWAYS
,("nsPluginHostImpl::dtor\n"));
2550 NS_IMPL_ISUPPORTS8(nsPluginHostImpl
,
2558 nsISupportsWeakReference
)
2561 nsPluginHostImpl::GetInst()
2564 sInst
= new nsPluginHostImpl();
2569 // Must call this after the refcount is already 1!
2570 if (NS_FAILED(sInst
->AddPrefObserver())) {
2582 nsPluginHostImpl::GetPluginName(nsIPluginInstance
*aPluginInstance
)
2584 nsActivePlugin
*plugin
=
2585 gActivePluginList
? gActivePluginList
->find(aPluginInstance
) : nsnull
;
2587 if (plugin
&& plugin
->mPluginTag
)
2588 return plugin
->mPluginTag
->mName
.get();
2593 NS_IMETHODIMP
nsPluginHostImpl::GetValue(nsPluginManagerVariable aVariable
, void *aValue
)
2595 nsresult rv
= NS_OK
;
2597 NS_ENSURE_ARG_POINTER(aValue
);
2599 #if defined(XP_UNIX) && !defined(XP_MACOSX) && defined(MOZ_X11)
2600 if (nsPluginManagerVariable_XDisplay
== aVariable
) {
2601 Display
** value
= reinterpret_cast<Display
**>(aValue
);
2602 #if defined (MOZ_WIDGET_GTK2)
2603 *value
= GDK_DISPLAY();
2606 return NS_ERROR_FAILURE
;
2609 if (nsPluginManagerVariable_SupportsXEmbed
== aVariable
) {
2610 #ifdef MOZ_WIDGET_GTK2
2611 *(NPBool
*)aValue
= PR_TRUE
;
2613 *(NPBool
*)aValue
= PR_FALSE
;
2619 PRBool
nsPluginHostImpl::IsRunningPlugin(nsPluginTag
* plugin
)
2624 // we can check for mLibrary to be non-zero and then querry nsIPluginInstancePeer
2625 // in nsActivePluginList to see if plugin with matching mime type is not stopped
2626 if (!plugin
->mLibrary
)
2629 for (int i
= 0; i
< plugin
->mVariants
; i
++) {
2630 nsActivePlugin
* p
= mActivePluginList
.find(plugin
->mMimeTypeArray
[i
]);
2631 if (p
&& !p
->mStopped
)
2638 nsresult
nsPluginHostImpl::ReloadPlugins(PRBool reloadPages
)
2640 PLUGIN_LOG(PLUGIN_LOG_NORMAL
,
2641 ("nsPluginHostImpl::ReloadPlugins Begin reloadPages=%d, active_instance_count=%d\n",
2642 reloadPages
, mActivePluginList
.mCount
));
2644 nsresult rv
= NS_OK
;
2646 // this will create the initial plugin list out of cache
2647 // if it was not created yet
2648 if (!mPluginsLoaded
)
2649 return LoadPlugins();
2651 // we are re-scanning plugins. New plugins may have been added, also some
2652 // plugins may have been removed, so we should probably shut everything down
2653 // but don't touch running (active and not stopped) plugins
2655 // check if plugins changed, no need to do anything else
2656 // if no changes to plugins have been made
2657 // PR_FALSE instructs not to touch the plugin list, just to
2658 // look for possible changes
2659 PRBool pluginschanged
= PR_TRUE
;
2660 FindPlugins(PR_FALSE
, &pluginschanged
);
2662 // if no changed detected, return an appropriate error code
2663 if (!pluginschanged
)
2664 return NS_ERROR_PLUGINS_PLUGINSNOTCHANGED
;
2666 nsCOMPtr
<nsISupportsArray
> instsToReload
;
2669 NS_NewISupportsArray(getter_AddRefs(instsToReload
));
2671 // Then stop any running plugin instances but hold on to the documents in the array
2672 // We are going to need to restart the instances in these documents later
2673 mActivePluginList
.stopRunning(instsToReload
, nsnull
);
2676 // clean active plugin list
2677 mActivePluginList
.removeAllStopped();
2679 // shutdown plugins and kill the list if there are no running plugins
2680 nsRefPtr
<nsPluginTag
> prev
;
2681 nsRefPtr
<nsPluginTag
> next
;
2683 for (nsRefPtr
<nsPluginTag
> p
= mPlugins
; p
!= nsnull
;) {
2686 // XXX only remove our plugin from the list if it's not running and not
2687 // an XPCOM plugin. XPCOM plugins do not get a call to nsIPlugin::Shutdown
2688 // if plugins are reloaded. This also fixes a crash on UNIX where the call
2689 // to shutdown would break the ProxyJNI connection to the JRE after a reload.
2691 if (!IsRunningPlugin(p
) && (!p
->mEntryPoint
|| p
->HasFlag(NS_PLUGIN_FLAG_OLDSCHOOL
))) {
2707 mPluginsLoaded
= PR_FALSE
;
2712 // If we have shut down any plugin instances, we've now got to restart them.
2713 // Post an event to do the rest as we are going to be destroying the frame tree and we also want
2714 // any posted unload events to finish
2718 NS_SUCCEEDED(instsToReload
->Count(&c
)) &&
2720 nsCOMPtr
<nsIRunnable
> ev
= new nsPluginDocReframeEvent(instsToReload
);
2722 NS_DispatchToCurrentThread(ev
);
2725 PLUGIN_LOG(PLUGIN_LOG_NORMAL
,
2726 ("nsPluginHostImpl::ReloadPlugins End active_instance_count=%d\n",
2727 mActivePluginList
.mCount
));
2732 #define NS_RETURN_UASTRING_SIZE 128
2734 nsresult
nsPluginHostImpl::UserAgent(const char **retstring
)
2736 static char resultString
[NS_RETURN_UASTRING_SIZE
];
2739 nsCOMPtr
<nsIHttpProtocolHandler
> http
= do_GetService(NS_NETWORK_PROTOCOL_CONTRACTID_PREFIX
"http", &res
);
2743 nsCAutoString uaString
;
2744 res
= http
->GetUserAgent(uaString
);
2746 if (NS_SUCCEEDED(res
)) {
2747 if (NS_RETURN_UASTRING_SIZE
> uaString
.Length()) {
2748 PL_strcpy(resultString
, uaString
.get());
2750 // Copy as much of UA string as we can (terminate at right-most space).
2751 PL_strncpy(resultString
, uaString
.get(), NS_RETURN_UASTRING_SIZE
);
2752 for (int i
= NS_RETURN_UASTRING_SIZE
- 1; i
>= 0; i
--) {
2754 resultString
[NS_RETURN_UASTRING_SIZE
- 1] = '\0';
2756 else if (resultString
[i
] == ' ') {
2757 resultString
[i
] = '\0';
2762 *retstring
= resultString
;
2765 *retstring
= nsnull
;
2768 PLUGIN_LOG(PLUGIN_LOG_NORMAL
, ("nsPluginHostImpl::UserAgent return=%s\n", *retstring
));
2773 nsresult
nsPluginHostImpl::GetPrompt(nsIPluginInstanceOwner
*aOwner
, nsIPrompt
**aPrompt
)
2776 nsCOMPtr
<nsIPrompt
> prompt
;
2777 nsCOMPtr
<nsIWindowWatcher
> wwatch
= do_GetService(NS_WINDOWWATCHER_CONTRACTID
, &rv
);
2780 nsCOMPtr
<nsIDOMWindow
> domWindow
;
2782 nsCOMPtr
<nsIDocument
> document
;
2783 aOwner
->GetDocument(getter_AddRefs(document
));
2785 domWindow
= document
->GetWindow();
2790 wwatch
->GetWindowByName(NS_LITERAL_STRING("_content").get(), nsnull
, getter_AddRefs(domWindow
));
2792 rv
= wwatch
->GetNewPrompter(domWindow
, getter_AddRefs(prompt
));
2795 NS_IF_ADDREF(*aPrompt
= prompt
);
2799 NS_IMETHODIMP
nsPluginHostImpl::GetURL(nsISupports
* pluginInst
,
2802 nsIPluginStreamListener
* streamListener
,
2803 const char* altHost
,
2804 const char* referrer
,
2805 PRBool forceJSEnabled
)
2807 return GetURLWithHeaders(pluginInst
, url
, target
, streamListener
,
2808 altHost
, referrer
, forceJSEnabled
, nsnull
, nsnull
);
2811 NS_IMETHODIMP
nsPluginHostImpl::GetURLWithHeaders(nsISupports
* pluginInst
,
2814 nsIPluginStreamListener
* streamListener
,
2815 const char* altHost
,
2816 const char* referrer
,
2817 PRBool forceJSEnabled
,
2818 PRUint32 getHeadersLength
,
2819 const char* getHeaders
)
2821 nsAutoString string
;
2822 string
.AssignWithConversion(url
);
2824 // we can only send a stream back to the plugin (as specified by a
2825 // null target) if we also have a nsIPluginStreamListener to talk to
2826 if (!target
&& !streamListener
)
2827 return NS_ERROR_ILLEGAL_VALUE
;
2830 nsCOMPtr
<nsIPluginInstance
> instance
= do_QueryInterface(pluginInst
, &rv
);
2831 if (NS_SUCCEEDED(rv
))
2832 rv
= DoURLLoadSecurityCheck(instance
, url
);
2834 if (NS_SUCCEEDED(rv
)) {
2836 nsCOMPtr
<nsIPluginInstancePeer
> peer
;
2837 rv
= instance
->GetPeer(getter_AddRefs(peer
));
2838 if (NS_SUCCEEDED(rv
) && peer
) {
2839 nsCOMPtr
<nsPIPluginInstancePeer
> privpeer(do_QueryInterface(peer
));
2840 nsCOMPtr
<nsIPluginInstanceOwner
> owner
;
2841 rv
= privpeer
->GetOwner(getter_AddRefs(owner
));
2843 if ((0 == PL_strcmp(target
, "newwindow")) ||
2844 (0 == PL_strcmp(target
, "_new")))
2846 else if (0 == PL_strcmp(target
, "_current"))
2849 rv
= owner
->GetURL(url
, target
, nsnull
, 0, (void *) getHeaders
, getHeadersLength
);
2854 if (streamListener
) {
2855 rv
= NewPluginURLStream(string
, instance
, streamListener
, nsnull
,
2856 PR_FALSE
, nsnull
, getHeaders
, getHeadersLength
);
2863 NS_IMETHODIMP
nsPluginHostImpl::PostURL(nsISupports
* pluginInst
,
2865 PRUint32 postDataLen
,
2866 const char* postData
,
2869 nsIPluginStreamListener
* streamListener
,
2870 const char* altHost
,
2871 const char* referrer
,
2872 PRBool forceJSEnabled
,
2873 PRUint32 postHeadersLength
,
2874 const char* postHeaders
)
2876 nsAutoString string
; string
.AssignWithConversion(url
);
2879 // we can only send a stream back to the plugin (as specified
2880 // by a null target) if we also have a nsIPluginStreamListener
2882 if (!target
&& !streamListener
)
2883 return NS_ERROR_ILLEGAL_VALUE
;
2885 nsCOMPtr
<nsIPluginInstance
> instance
= do_QueryInterface(pluginInst
, &rv
);
2886 if (NS_SUCCEEDED(rv
))
2887 rv
= DoURLLoadSecurityCheck(instance
, url
);
2889 if (NS_SUCCEEDED(rv
)) {
2892 rv
= CreateTmpFileToPost(postData
, &dataToPost
);
2893 if (NS_FAILED(rv
) || !dataToPost
)
2896 PRUint32 newDataToPostLen
;
2897 ParsePostBufferToFixHeaders(postData
, postDataLen
, &dataToPost
, &newDataToPostLen
);
2899 return NS_ERROR_UNEXPECTED
;
2901 // we use nsIStringInputStream::adoptDataa()
2902 // in NS_NewPluginPostDataStream to set the stream
2903 // all new data alloced in ParsePostBufferToFixHeaders()
2904 // well be nsMemory::Free()d on destroy the stream
2905 postDataLen
= newDataToPostLen
;
2909 nsCOMPtr
<nsIPluginInstancePeer
> peer
;
2910 rv
= instance
->GetPeer(getter_AddRefs(peer
));
2911 if (NS_SUCCEEDED(rv
) && peer
) {
2912 nsCOMPtr
<nsPIPluginInstancePeer
> privpeer(do_QueryInterface(peer
));
2913 nsCOMPtr
<nsIPluginInstanceOwner
> owner
;
2914 rv
= privpeer
->GetOwner(getter_AddRefs(owner
));
2920 if ((0 == PL_strcmp(target
, "newwindow")) ||
2921 (0 == PL_strcmp(target
, "_new"))) {
2924 else if (0 == PL_strcmp(target
, "_current")) {
2928 rv
= owner
->GetURL(url
, target
, (void*)dataToPost
, postDataLen
,
2929 (void*)postHeaders
, postHeadersLength
, isFile
);
2934 // if we don't have a target, just create a stream. This does
2937 rv
= NewPluginURLStream(string
, instance
, streamListener
,
2938 (const char*)dataToPost
, isFile
, postDataLen
,
2939 postHeaders
, postHeadersLength
);
2941 NS_Free(dataToPost
);
2947 NS_IMETHODIMP
nsPluginHostImpl::RegisterPlugin(REFNSIID aCID
,
2948 const char* aPluginName
,
2949 const char* aDescription
,
2950 const char** aMimeTypes
,
2951 const char** aMimeDescriptions
,
2952 const char** aFileExtensions
,
2955 return NS_ERROR_NOT_IMPLEMENTED
;
2958 NS_IMETHODIMP
nsPluginHostImpl::UnregisterPlugin(REFNSIID aCID
)
2960 return NS_ERROR_NOT_IMPLEMENTED
;
2963 NS_IMETHODIMP
nsPluginHostImpl::BeginWaitCursor(void)
2965 return NS_ERROR_NOT_IMPLEMENTED
;
2968 NS_IMETHODIMP
nsPluginHostImpl::EndWaitCursor(void)
2970 return NS_ERROR_NOT_IMPLEMENTED
;
2973 NS_IMETHODIMP
nsPluginHostImpl::SupportsURLProtocol(const char* protocol
, PRBool
*result
)
2975 return NS_ERROR_NOT_IMPLEMENTED
;
2978 NS_IMETHODIMP
nsPluginHostImpl::NotifyStatusChange(nsIPlugin
* plugin
, nsresult errorStatus
)
2980 return NS_ERROR_NOT_IMPLEMENTED
;
2984 /* This method queries the prefs for proxy information.
2985 * It has been tested and is known to work in the following three cases
2986 * when no proxy host or port is specified
2987 * when only the proxy host is specified
2988 * when only the proxy port is specified
2989 * This method conforms to the return code specified in
2990 * http://developer.netscape.com/docs/manuals/proxy/adminnt/autoconf.htm#1020923
2991 * with the exception that multiple values are not implemented.
2994 NS_IMETHODIMP
nsPluginHostImpl::FindProxyForURL(const char* url
, char* *result
)
2996 if (!url
|| !result
) {
2997 return NS_ERROR_INVALID_ARG
;
3001 nsCOMPtr
<nsIURI
> uriIn
;
3002 nsCOMPtr
<nsIProtocolProxyService
> proxyService
;
3003 nsCOMPtr
<nsIIOService
> ioService
;
3005 proxyService
= do_GetService(NS_PROTOCOLPROXYSERVICE_CONTRACTID
, &res
);
3006 if (NS_FAILED(res
) || !proxyService
)
3009 ioService
= do_GetService(NS_IOSERVICE_CONTRACTID
, &res
);
3010 if (NS_FAILED(res
) || !ioService
)
3013 // make an nsURI from the argument url
3014 res
= ioService
->NewURI(nsDependentCString(url
), nsnull
, nsnull
, getter_AddRefs(uriIn
));
3018 nsCOMPtr
<nsIProxyInfo
> pi
;
3020 res
= proxyService
->Resolve(uriIn
, 0, getter_AddRefs(pi
));
3024 nsCAutoString host
, type
;
3027 // These won't fail, and even if they do... we'll be ok.
3034 if (!pi
|| host
.IsEmpty() || port
<= 0 || host
.EqualsLiteral("direct")) {
3035 *result
= PL_strdup("DIRECT");
3036 } else if (type
.EqualsLiteral("http")) {
3037 *result
= PR_smprintf("PROXY %s:%d", host
.get(), port
);
3038 } else if (type
.EqualsLiteral("socks4")) {
3039 *result
= PR_smprintf("SOCKS %s:%d", host
.get(), port
);
3040 } else if (type
.EqualsLiteral("socks")) {
3041 // XXX - this is socks5, but there is no API for us to tell the
3042 // plugin that fact. SOCKS for now, in case the proxy server
3043 // speaks SOCKS4 as well. See bug 78176
3044 // For a long time this was returning an http proxy type, so
3045 // very little is probably broken by this
3046 *result
= PR_smprintf("SOCKS %s:%d", host
.get(), port
);
3048 NS_ASSERTION(PR_FALSE
, "Unknown proxy type!");
3049 *result
= PL_strdup("DIRECT");
3052 if (nsnull
== *result
)
3053 res
= NS_ERROR_OUT_OF_MEMORY
;
3058 NS_IMETHODIMP
nsPluginHostImpl::RegisterWindow(nsIEventHandler
* handler
, nsPluginPlatformWindowRef window
)
3060 return NS_ERROR_NOT_IMPLEMENTED
;
3063 NS_IMETHODIMP
nsPluginHostImpl::UnregisterWindow(nsIEventHandler
* handler
, nsPluginPlatformWindowRef window
)
3065 return NS_ERROR_NOT_IMPLEMENTED
;
3068 NS_IMETHODIMP
nsPluginHostImpl::AllocateMenuID(nsIEventHandler
* handler
, PRBool isSubmenu
, PRInt16
*result
)
3070 return NS_ERROR_NOT_IMPLEMENTED
;
3073 NS_IMETHODIMP
nsPluginHostImpl::DeallocateMenuID(nsIEventHandler
* handler
, PRInt16 menuID
)
3075 return NS_ERROR_NOT_IMPLEMENTED
;
3078 NS_IMETHODIMP
nsPluginHostImpl::HasAllocatedMenuID(nsIEventHandler
* handler
, PRInt16 menuID
, PRBool
*result
)
3080 return NS_ERROR_NOT_IMPLEMENTED
;
3083 NS_IMETHODIMP
nsPluginHostImpl::ProcessNextEvent(PRBool
*bEventHandled
)
3085 return NS_ERROR_NOT_IMPLEMENTED
;
3088 NS_IMETHODIMP
nsPluginHostImpl::CreateInstance(nsISupports
*aOuter
,
3092 NS_NOTREACHED("how'd I get here?");
3093 return NS_ERROR_UNEXPECTED
;
3096 NS_IMETHODIMP
nsPluginHostImpl::LockFactory(PRBool aLock
)
3098 NS_NOTREACHED("how'd I get here?");
3099 return NS_ERROR_UNEXPECTED
;
3102 NS_IMETHODIMP
nsPluginHostImpl::Init(void)
3107 NS_IMETHODIMP
nsPluginHostImpl::Destroy(void)
3109 PLUGIN_LOG(PLUGIN_LOG_NORMAL
, ("nsPluginHostImpl::Destroy Called\n"));
3114 mIsDestroyed
= PR_TRUE
;
3116 // we should call nsIPluginInstance::Stop and nsIPluginInstance::SetWindow
3117 // for those plugins who want it
3118 mActivePluginList
.stopRunning(nsnull
, nsnull
);
3120 // at this point nsIPlugin::Shutdown calls will be performed if needed
3121 mActivePluginList
.shut();
3124 PR_Free(mPluginPath
);
3125 mPluginPath
= nsnull
;
3129 nsRefPtr
<nsPluginTag
> temp
= mPlugins
->mNext
;
3130 // while walking through the list of the plugins see if we still have anything
3131 // to shutdown some plugins may have never created an instance but still expect
3132 // the shutdown call see bugzilla bug 73071
3133 // with current logic, no need to do anything special as nsIPlugin::Shutdown
3134 // will be performed in the destructor
3135 mPlugins
->mNext
= nsnull
;
3139 // Delete any remaining cached plugins list
3140 mCachedPlugins
= nsnull
;
3142 // Lets remove any of the temporary files that we created.
3143 if (sPluginTempDir
) {
3144 sPluginTempDir
->Remove(PR_TRUE
);
3145 NS_RELEASE(sPluginTempDir
);
3149 if (mPrivateDirServiceProvider
) {
3150 nsCOMPtr
<nsIDirectoryService
> dirService
=
3151 do_GetService(kDirectoryServiceContractID
);
3153 dirService
->UnregisterProvider(mPrivateDirServiceProvider
);
3154 mPrivateDirServiceProvider
= nsnull
;
3158 nsCOMPtr
<nsIPrefBranch2
> prefBranch(do_QueryInterface(mPrefService
));
3160 prefBranch
->RemoveObserver("security.enable_java", this);
3161 mPrefService
= nsnull
; // release prefs service to avoid leaks!
3166 void nsPluginHostImpl::UnloadUnusedLibraries()
3168 // unload any remaining plugin libraries from memory
3169 for (PRInt32 i
= 0; i
< mUnusedLibraries
.Count(); i
++) {
3170 PRLibrary
* library
= (PRLibrary
*)mUnusedLibraries
[i
];
3172 PostPluginUnloadEvent(library
);
3174 mUnusedLibraries
.Clear();
3178 nsPluginHostImpl::GetPluginTempDir(nsIFile
**aDir
)
3180 if (!sPluginTempDir
) {
3181 nsCOMPtr
<nsIFile
> tmpDir
;
3182 nsresult rv
= NS_GetSpecialDirectory(NS_OS_TEMP_DIR
,
3183 getter_AddRefs(tmpDir
));
3184 NS_ENSURE_SUCCESS(rv
, rv
);
3186 rv
= tmpDir
->AppendNative(kPluginTmpDirName
);
3188 // make it unique, and mode == 0700, not world-readable
3189 rv
= tmpDir
->CreateUnique(nsIFile::DIRECTORY_TYPE
, 0700);
3190 NS_ENSURE_SUCCESS(rv
, rv
);
3192 tmpDir
.swap(sPluginTempDir
);
3195 return sPluginTempDir
->Clone(aDir
);
3198 NS_IMETHODIMP
nsPluginHostImpl::InstantiatePluginForChannel(nsIChannel
* aChannel
,
3199 nsIPluginInstanceOwner
* aOwner
,
3200 nsIStreamListener
** aListener
)
3202 NS_PRECONDITION(aChannel
&& aOwner
,
3203 "Invalid arguments to InstantiatePluginForChannel");
3204 nsCOMPtr
<nsIURI
> uri
;
3205 nsresult rv
= aChannel
->GetURI(getter_AddRefs(uri
));
3209 #ifdef PLUGIN_LOGGING
3210 if (PR_LOG_TEST(nsPluginLogging::gPluginLog
, PLUGIN_LOG_NORMAL
)) {
3211 nsCAutoString urlSpec
;
3212 uri
->GetAsciiSpec(urlSpec
);
3214 PR_LOG(nsPluginLogging::gPluginLog
, PLUGIN_LOG_NORMAL
,
3215 ("nsPluginHostImpl::InstantiatePluginForChannel Begin owner=%p, url=%s\n",
3216 aOwner
, urlSpec
.get()));
3222 // XXX do we need to look for stopped plugins, like InstantiateEmbeddedPlugin
3225 return NewEmbeddedPluginStreamListener(uri
, aOwner
, nsnull
, aListener
);
3228 // Called by nsPluginInstanceOwner (nsObjectFrame.cpp - embedded case)
3229 NS_IMETHODIMP
nsPluginHostImpl::InstantiateEmbeddedPlugin(const char *aMimeType
,
3231 nsIPluginInstanceOwner
*aOwner
)
3233 NS_ENSURE_ARG_POINTER(aOwner
);
3235 #ifdef PLUGIN_LOGGING
3236 nsCAutoString urlSpec
;
3238 aURL
->GetAsciiSpec(urlSpec
);
3240 PR_LOG(nsPluginLogging::gPluginLog
, PLUGIN_LOG_NORMAL
,
3241 ("nsPluginHostImpl::InstantiateEmbeddedPlugin Begin mime=%s, owner=%p, url=%s\n",
3242 aMimeType
, aOwner
, urlSpec
.get()));
3248 nsIPluginInstance
*instance
= nsnull
;
3249 nsCOMPtr
<nsIPluginTagInfo2
> pti2
;
3250 nsPluginTagType tagType
;
3252 rv
= aOwner
->QueryInterface(kIPluginTagInfo2IID
, getter_AddRefs(pti2
));
3257 rv
= pti2
->GetTagType(&tagType
);
3259 if ((rv
!= NS_OK
) || !((tagType
== nsPluginTagType_Embed
)
3260 || (tagType
== nsPluginTagType_Applet
)
3261 || (tagType
== nsPluginTagType_Object
))) {
3266 // Can't do security checks without a URI - hopefully the plugin will take
3269 nsCOMPtr
<nsIScriptSecurityManager
> secMan
=
3270 do_GetService(NS_SCRIPTSECURITYMANAGER_CONTRACTID
, &rv
);
3272 return rv
; // Better fail if we can't do security checks
3274 nsCOMPtr
<nsIDocument
> doc
;
3275 aOwner
->GetDocument(getter_AddRefs(doc
));
3277 return NS_ERROR_NULL_POINTER
;
3279 rv
= secMan
->CheckLoadURIWithPrincipal(doc
->NodePrincipal(), aURL
, 0);
3283 nsCOMPtr
<nsIDOMElement
> elem
;
3284 pti2
->GetDOMElement(getter_AddRefs(elem
));
3286 PRInt16 shouldLoad
= nsIContentPolicy::ACCEPT
; // default permit
3288 NS_CheckContentLoadPolicy(nsIContentPolicy::TYPE_OBJECT
,
3290 doc
->NodePrincipal(),
3292 nsDependentCString(aMimeType
? aMimeType
: ""),
3295 if (NS_FAILED(rv
) || NS_CP_REJECTED(shouldLoad
))
3296 return NS_ERROR_CONTENT_BLOCKED_SHOW_ALT
;
3299 // Look for even disabled plugins, because if the plugin for this type is
3300 // disabled, we don't want to go on and end up in SetUpDefaultPluginInstance.
3301 nsPluginTag
* pluginTag
= FindPluginForType(aMimeType
, PR_FALSE
);
3303 if (!pluginTag
->IsEnabled())
3304 return NS_ERROR_NOT_AVAILABLE
;
3305 } else if (!mJavaEnabled
&& IsJavaMIMEType(aMimeType
)) {
3306 // Even if we had no Java plugin, if mJavaEnabled is false we should throw
3307 // here for Java types. Note that we only need to do this for the case
3308 // when pluginTag is null; if we had a pluginTag, it would have its
3309 // NS_PLUGIN_FLAG_ENABLED set the right way.
3310 return NS_ERROR_NOT_AVAILABLE
;
3313 PRBool isJava
= pluginTag
&& pluginTag
->mIsJavaPlugin
;
3315 // Determine if the scheme of this URL is one we can handle internaly because we should
3316 // only open the initial stream if it's one that we can handle internally. Otherwise
3317 // |NS_OpenURI| in |InstantiateEmbeddedPlugin| may open up a OS protocal registered helper app
3318 PRBool bCanHandleInternally
= PR_FALSE
;
3319 nsCAutoString scheme
;
3320 if (aURL
&& NS_SUCCEEDED(aURL
->GetScheme(scheme
))) {
3321 nsCAutoString
contractID(NS_NETWORK_PROTOCOL_CONTRACTID_PREFIX
);
3322 contractID
+= scheme
;
3323 ToLowerCase(contractID
);
3324 nsCOMPtr
<nsIProtocolHandler
> handler
= do_GetService(contractID
.get());
3326 bCanHandleInternally
= PR_TRUE
;
3329 if (FindStoppedPluginForURL(aURL
, aOwner
) == NS_OK
) {
3331 PLUGIN_LOG(PLUGIN_LOG_NOISY
,
3332 ("nsPluginHostImpl::InstantiateEmbeddedPlugin FoundStopped mime=%s\n", aMimeType
));
3334 aOwner
->GetInstance(instance
);
3335 if (!isJava
&& bCanHandleInternally
)
3336 rv
= NewEmbeddedPluginStream(aURL
, aOwner
, instance
);
3338 // notify Java DOM component
3340 nsCOMPtr
<nsIPluginInstanceOwner
> javaDOM
=
3341 do_GetService("@mozilla.org/blackwood/java-dom;1", &res
);
3342 if (NS_SUCCEEDED(res
) && javaDOM
)
3343 javaDOM
->SetInstance(instance
);
3345 NS_IF_RELEASE(instance
);
3349 // if we don't have a MIME type at this point, we still have one more chance by
3350 // opening the stream and seeing if the server hands one back
3352 return bCanHandleInternally
? NewEmbeddedPluginStream(aURL
, aOwner
, nsnull
) : NS_ERROR_FAILURE
;
3354 rv
= SetUpPluginInstance(aMimeType
, aURL
, aOwner
);
3357 rv
= aOwner
->GetInstance(instance
);
3359 /* If we are here, it's time to either show the default plugin
3360 * or return failure so layout will replace us.
3362 * Currently, the default plugin is shown for all EMBED and APPLET
3363 * tags and also any OBJECT tag that has a PLUGINURL PARAM tag name.
3366 PRBool bHasPluginURL
= PR_FALSE
;
3367 nsCOMPtr
<nsIPluginTagInfo2
> pti2(do_QueryInterface(aOwner
));
3371 bHasPluginURL
= NS_SUCCEEDED(pti2
->GetParameter("PLUGINURL", &value
));
3374 // if we didn't find a pluginURL param on the object tag,
3375 // there's nothing more to do here
3376 if (nsPluginTagType_Object
== tagType
&& !bHasPluginURL
)
3379 if (NS_FAILED(SetUpDefaultPluginInstance(aMimeType
, aURL
, aOwner
)))
3380 return NS_ERROR_FAILURE
;
3382 if (NS_FAILED(aOwner
->GetInstance(instance
)))
3383 return NS_ERROR_FAILURE
;
3388 // if we have a failure error, it means we found a plugin for the mimetype,
3389 // but we had a problem with the entry point
3390 if (rv
== NS_ERROR_FAILURE
)
3393 // if we are here then we have loaded a plugin for this mimetype
3394 // and it could be the Default plugin
3396 nsPluginWindow
*window
= nsnull
;
3398 //we got a plugin built, now stream
3399 aOwner
->GetWindow(window
);
3403 aOwner
->CreateWidget();
3405 // If we've got a native window, the let the plugin know about it.
3406 if (window
->window
) {
3407 nsCOMPtr
<nsIPluginInstance
> inst
= instance
;
3408 ((nsPluginNativeWindow
*)window
)->CallSetWindow(inst
);
3411 // create an initial stream with data
3412 // don't make the stream if it's a java applet or we don't have SRC or DATA attribute
3413 PRBool havedata
= PR_FALSE
;
3415 nsCOMPtr
<nsIPluginTagInfo
> pti(do_QueryInterface(aOwner
, &rv
));
3419 havedata
= NS_SUCCEEDED(pti
->GetAttribute("SRC", &value
));
3420 // no need to check for "data" as it would have been converted to "src"
3423 if (havedata
&& !isJava
&& bCanHandleInternally
)
3424 rv
= NewEmbeddedPluginStream(aURL
, aOwner
, instance
);
3426 // notify Java DOM component
3428 nsCOMPtr
<nsIPluginInstanceOwner
> javaDOM
=
3429 do_GetService("@mozilla.org/blackwood/java-dom;1", &res
);
3430 if (NS_SUCCEEDED(res
) && javaDOM
)
3431 javaDOM
->SetInstance(instance
);
3433 NS_RELEASE(instance
);
3436 #ifdef PLUGIN_LOGGING
3437 nsCAutoString urlSpec2
;
3438 if (aURL
!= nsnull
) (void)aURL
->GetAsciiSpec(urlSpec2
);
3440 PR_LOG(nsPluginLogging::gPluginLog
, PLUGIN_LOG_NORMAL
,
3441 ("nsPluginHostImpl::InstantiateEmbeddedPlugin Finished mime=%s, rv=%d, owner=%p, url=%s\n",
3442 aMimeType
, rv
, aOwner
, urlSpec2
.get()));
3450 // Called by full-page case
3451 NS_IMETHODIMP
nsPluginHostImpl::InstantiateFullPagePlugin(const char *aMimeType
,
3453 nsIStreamListener
*&aStreamListener
,
3454 nsIPluginInstanceOwner
*aOwner
)
3456 #ifdef PLUGIN_LOGGING
3457 nsCAutoString urlSpec
;
3458 aURI
->GetSpec(urlSpec
);
3459 PLUGIN_LOG(PLUGIN_LOG_NORMAL
,
3460 ("nsPluginHostImpl::InstantiateFullPagePlugin Begin mime=%s, owner=%p, url=%s\n",
3461 aMimeType
, aOwner
, urlSpec
.get()));
3464 if (FindStoppedPluginForURL(aURI
, aOwner
) == NS_OK
) {
3465 PLUGIN_LOG(PLUGIN_LOG_NOISY
,
3466 ("nsPluginHostImpl::InstantiateFullPagePlugin FoundStopped mime=%s\n",aMimeType
));
3468 nsIPluginInstance
* instance
;
3469 aOwner
->GetInstance(instance
);
3470 nsPluginTag
* pluginTag
= FindPluginForType(aMimeType
, PR_TRUE
);
3471 if (!pluginTag
|| !pluginTag
->mIsJavaPlugin
)
3472 NewFullPagePluginStream(aStreamListener
, instance
);
3473 NS_IF_RELEASE(instance
);
3477 nsresult rv
= SetUpPluginInstance(aMimeType
, aURI
, aOwner
);
3480 nsCOMPtr
<nsIPluginInstance
> instance
;
3481 nsPluginWindow
* win
= nsnull
;
3483 aOwner
->GetInstance(*getter_AddRefs(instance
));
3484 aOwner
->GetWindow(win
);
3486 if (win
&& instance
) {
3488 aOwner
->CreateWidget();
3490 // If we've got a native window, the let the plugin know about it.
3491 nsPluginNativeWindow
* window
= (nsPluginNativeWindow
*)win
;
3493 window
->CallSetWindow(instance
);
3495 rv
= NewFullPagePluginStream(aStreamListener
, instance
);
3497 // If we've got a native window, the let the plugin know about it.
3499 window
->CallSetWindow(instance
);
3503 PLUGIN_LOG(PLUGIN_LOG_NORMAL
,
3504 ("nsPluginHostImpl::InstantiateFullPagePlugin End mime=%s, rv=%d, owner=%p, url=%s\n",
3505 aMimeType
, rv
, aOwner
, urlSpec
.get()));
3510 nsresult
nsPluginHostImpl::FindStoppedPluginForURL(nsIURI
* aURL
,
3511 nsIPluginInstanceOwner
*aOwner
)
3515 return NS_ERROR_FAILURE
;
3517 aURL
->GetAsciiSpec(url
);
3519 nsActivePlugin
* plugin
= mActivePluginList
.findStopped(url
.get());
3521 if (plugin
&& plugin
->mStopped
) {
3522 nsIPluginInstance
* instance
= plugin
->mInstance
;
3523 nsPluginWindow
*window
= nsnull
;
3524 aOwner
->GetWindow(window
);
3526 aOwner
->SetInstance(instance
);
3528 // we have to reset the owner and instance in the plugin instance peer
3529 //instance->GetPeer(&peer);
3530 ((nsPluginInstancePeerImpl
*)plugin
->mPeer
)->SetOwner(aOwner
);
3533 aOwner
->CreateWidget();
3535 // If we've got a native window, the let the plugin know about it.
3536 if (window
->window
) {
3537 nsCOMPtr
<nsIPluginInstance
> inst
= instance
;
3538 ((nsPluginNativeWindow
*)window
)->CallSetWindow(inst
);
3541 plugin
->setStopped(PR_FALSE
);
3544 return NS_ERROR_FAILURE
;
3547 nsresult
nsPluginHostImpl::AddInstanceToActiveList(nsCOMPtr
<nsIPlugin
> aPlugin
,
3548 nsIPluginInstance
* aInstance
,
3550 PRBool aDefaultPlugin
,
3551 nsIPluginInstancePeer
* peer
)
3555 // It's OK to not have a URL here, as is the case with the dummy
3556 // Java plugin. In that case simply use an empty string...
3560 // let's find the corresponding plugin tag by matching nsIPlugin pointer
3561 // it's legal for XPCOM plugins not to have nsIPlugin implemented but
3562 // this is OK, we don't need the plugin tag for XPCOM plugins. It is going
3563 // to be used later when we decide whether or not we should delay unloading
3564 // NPAPI dll from memory, and XPCOM dlls will stay in memory anyway.
3565 nsPluginTag
* pluginTag
= nsnull
;
3567 for (pluginTag
= mPlugins
; pluginTag
!= nsnull
; pluginTag
= pluginTag
->mNext
) {
3568 if (pluginTag
->mEntryPoint
== aPlugin
)
3571 NS_ASSERTION(pluginTag
, "Plugin tag not found");
3574 nsActivePlugin
* plugin
= new nsActivePlugin(pluginTag
, aInstance
, url
.get(), aDefaultPlugin
, peer
);
3577 return NS_ERROR_OUT_OF_MEMORY
;
3579 mActivePluginList
.add(plugin
);
3584 nsPluginTag::RegisterWithCategoryManager(PRBool aOverrideInternalTypes
,
3585 nsPluginTag::nsRegisterType aType
)
3587 if (!mMimeTypeArray
)
3590 PLUGIN_LOG(PLUGIN_LOG_NORMAL
,
3591 ("nsPluginTag::RegisterWithCategoryManager plugin=%s, removing = %s\n",
3592 mFileName
.get(), aType
== ePluginUnregister
? "yes" : "no"));
3594 nsCOMPtr
<nsICategoryManager
> catMan
= do_GetService(NS_CATEGORYMANAGER_CONTRACTID
);
3598 const char *contractId
= "@mozilla.org/content/plugin/document-loader-factory;1";
3600 nsCOMPtr
<nsIPrefBranch
> psvc(do_GetService(NS_PREFSERVICE_CONTRACTID
));
3602 return; // NS_ERROR_OUT_OF_MEMORY
3604 // A preference controls whether or not the full page plugin is disabled for
3605 // a particular type. The string must be in the form:
3606 // type1,type2,type3,type4
3607 // Note: need an actual interface to control this and subsequent disabling
3608 // (and other plugin host settings) so applications can reliably disable
3609 // plugins - without relying on implementation details such as prefs/category
3611 nsXPIDLCString overrideTypes
;
3612 psvc
->GetCharPref("plugin.disable_full_page_plugin_for_types", getter_Copies(overrideTypes
));
3613 nsCAutoString overrideTypesFormatted
;
3614 overrideTypesFormatted
.Assign(',');
3615 overrideTypesFormatted
+= overrideTypes
;
3616 overrideTypesFormatted
.Append(',');
3618 nsACString::const_iterator start
, end
;
3619 for (int i
= 0; i
< mVariants
; i
++) {
3620 if (aType
== ePluginUnregister
) {
3621 nsXPIDLCString value
;
3622 if (NS_SUCCEEDED(catMan
->GetCategoryEntry("Gecko-Content-Viewers",
3624 getter_Copies(value
)))) {
3625 // Only delete the entry if a plugin registered for it
3626 if (strcmp(value
, contractId
) == 0) {
3627 catMan
->DeleteCategoryEntry("Gecko-Content-Viewers",
3633 overrideTypesFormatted
.BeginReading(start
);
3634 overrideTypesFormatted
.EndReading(end
);
3636 nsDependentCString
mimeType(mMimeTypeArray
[i
]);
3637 nsCAutoString commaSeparated
;
3638 commaSeparated
.Assign(',');
3639 commaSeparated
+= mimeType
;
3640 commaSeparated
.Append(',');
3641 if (!FindInReadable(commaSeparated
, start
, end
)) {
3642 catMan
->AddCategoryEntry("Gecko-Content-Viewers",
3645 PR_FALSE
, /* persist: broken by bug 193031 */
3646 aOverrideInternalTypes
, /* replace if we're told to */
3651 PLUGIN_LOG(PLUGIN_LOG_NOISY
,
3652 ("nsPluginTag::RegisterWithCategoryManager mime=%s, plugin=%s\n",
3653 mMimeTypeArray
[i
], mFileName
.get()));
3657 NS_IMETHODIMP
nsPluginHostImpl::SetUpPluginInstance(const char *aMimeType
,
3659 nsIPluginInstanceOwner
*aOwner
)
3661 nsresult rv
= NS_OK
;
3663 rv
= TrySetUpPluginInstance(aMimeType
, aURL
, aOwner
);
3665 // if we fail, refresh plugin list just in case the plugin has been
3666 // just added and try to instantiate plugin instance again, see bug 143178
3667 if (NS_FAILED(rv
)) {
3668 // we should also make sure not to do this more than once per page
3669 // so if there are a few embed tags with unknown plugins,
3670 // we don't get unnecessary overhead
3671 // let's cache document to decide whether this is the same page or not
3672 nsCOMPtr
<nsIDocument
> document
;
3674 aOwner
->GetDocument(getter_AddRefs(document
));
3676 nsCOMPtr
<nsIDocument
> currentdocument
= do_QueryReferent(mCurrentDocument
);
3677 if (document
== currentdocument
)
3680 mCurrentDocument
= do_GetWeakReference(document
);
3682 // ReloadPlugins will do the job smartly: nothing will be done
3683 // if no changes detected, in such a case just return
3684 if (NS_ERROR_PLUGINS_PLUGINSNOTCHANGED
== ReloadPlugins(PR_FALSE
))
3687 // other failure return codes may be not fatal, so we can still try
3688 rv
= TrySetUpPluginInstance(aMimeType
, aURL
, aOwner
);
3695 nsPluginHostImpl::TrySetUpPluginInstance(const char *aMimeType
,
3697 nsIPluginInstanceOwner
*aOwner
)
3699 #ifdef PLUGIN_LOGGING
3700 nsCAutoString urlSpec
;
3701 if (aURL
!= nsnull
) (void)aURL
->GetSpec(urlSpec
);
3703 PR_LOG(nsPluginLogging::gPluginLog
, PLUGIN_LOG_NORMAL
,
3704 ("nsPluginHostImpl::TrySetupPluginInstance Begin mime=%s, owner=%p, url=%s\n",
3705 aMimeType
, aOwner
, urlSpec
.get()));
3711 nsresult result
= NS_ERROR_FAILURE
;
3712 nsCOMPtr
<nsIPluginInstance
> instance
;
3713 nsCOMPtr
<nsIPlugin
> plugin
;
3714 const char* mimetype
= nsnull
;
3716 // if don't have a mimetype or no plugin can handle this mimetype
3717 // check by file extension
3718 nsPluginTag
* pluginTag
= FindPluginForType(aMimeType
, PR_TRUE
);
3720 nsCOMPtr
<nsIURL
> url
= do_QueryInterface(aURL
);
3721 if (!url
) return NS_ERROR_FAILURE
;
3723 nsCAutoString fileExtension
;
3724 url
->GetFileExtension(fileExtension
);
3726 // if we don't have an extension or no plugin for this extension,
3727 // return failure as there is nothing more we can do
3728 if (fileExtension
.IsEmpty() ||
3729 !(pluginTag
= FindPluginEnabledForExtension(fileExtension
.get(),
3731 return NS_ERROR_FAILURE
;
3735 mimetype
= aMimeType
;
3737 NS_ASSERTION(pluginTag
, "Must have plugin tag here!");
3738 PRBool isJavaPlugin
= pluginTag
->mIsJavaPlugin
;
3740 if (isJavaPlugin
&& !pluginTag
->mIsNPRuntimeEnabledJavaPlugin
) {
3741 #if !defined(OJI) && defined(XP_MACOSX)
3742 // The MRJ plugin hangs if you try to load it with OJI disabled,
3743 // don't even try to go there.
3744 return NS_ERROR_FAILURE
;
3747 // We must make sure LiveConnect is started, if needed.
3748 nsCOMPtr
<nsIDocument
> document
;
3749 aOwner
->GetDocument(getter_AddRefs(document
));
3751 nsCOMPtr
<nsPIDOMWindow
> window
=
3752 do_QueryInterface(document
->GetScriptGlobalObject());
3755 window
->InitJavaProperties();
3759 #if defined(OJI) && ((defined(XP_UNIX) && !defined(XP_MACOSX)) || defined(XP_OS2))
3760 // This is a work-around on Unix for a LiveConnect problem (bug
3763 // The proxy JNI needs to be created by the browser. If it is
3764 // created by someone else (e.g., a plugin) on a different thread,
3765 // the proxy JNI will not work, and break LiveConnect. Currently,
3766 // on Unix, when instantiating a Java plugin instance (by calling
3767 // InstantiateEmbeddedPlugin() next), Java plugin will create the
3768 // proxy JNI if it is not created yet. If that happens,
3769 // LiveConnect will be broken. Before lazy start JVM was
3770 // implemented, since at this point the browser already created
3771 // the proxy JNI during startup, the problem did not happen.
3772 // But after the lazy start was implemented, at this point the
3773 // proxy JNI was not created yet, so the Java plugin created the
3774 // proxy JNI, and broke liveConnect.
3775 // On Windows and Mac, Java plugin does not create the proxy JNI,
3776 // but lets the browser to create it. Hence this is a Unix-only
3780 // The root cause of the problem is in Java plugin's Unix
3781 // implementation, which should not create the proxy JNI. As a
3782 // work-around, here we make sure the proxy JNI has been created
3783 // by the browser, before plugin gets a chance.
3786 // If Java is installed, get proxy JNI.
3787 nsCOMPtr
<nsIJVMManager
> jvmManager
= do_GetService(nsIJVMManager::GetCID(),
3789 if (NS_SUCCEEDED(result
)) {
3791 // Get proxy JNI, if not created yet, create it.
3792 jvmManager
->GetProxyJNI(&proxyEnv
);
3797 nsCAutoString
contractID(
3798 NS_LITERAL_CSTRING(NS_INLINE_PLUGIN_CONTRACTID_PREFIX
) +
3799 nsDependentCString(mimetype
));
3801 GetPluginFactory(mimetype
, getter_AddRefs(plugin
));
3803 instance
= do_CreateInstance(contractID
.get(), &result
);
3805 // couldn't create an XPCOM plugin, try to create wrapper for a
3807 if (NS_FAILED(result
)) {
3810 static BOOL firstJavaPlugin
= FALSE
;
3811 BOOL restoreOrigDir
= FALSE
;
3812 char origDir
[_MAX_PATH
];
3813 if (isJavaPlugin
&& !firstJavaPlugin
) {
3814 DWORD dw
= ::GetCurrentDirectory(_MAX_PATH
, origDir
);
3815 NS_ASSERTION(dw
<= _MAX_PATH
, "Falied to obtain the current directory, which may leads to incorrect class laoding");
3816 nsCOMPtr
<nsIFile
> binDirectory
;
3817 result
= NS_GetSpecialDirectory(NS_XPCOM_CURRENT_PROCESS_DIR
,
3818 getter_AddRefs(binDirectory
));
3820 if (NS_SUCCEEDED(result
)) {
3822 binDirectory
->GetNativePath(path
);
3823 restoreOrigDir
= ::SetCurrentDirectory(path
.get());
3827 result
= plugin
->CreateInstance(NULL
, kIPluginInstanceIID
, (void **)getter_AddRefs(instance
));
3830 if (!firstJavaPlugin
&& restoreOrigDir
) {
3831 BOOL bCheck
= ::SetCurrentDirectory(origDir
);
3832 NS_ASSERTION(bCheck
, " Error restoring driectoy");
3833 firstJavaPlugin
= TRUE
;
3838 if (NS_FAILED(result
)) {
3839 nsCOMPtr
<nsIPlugin
> bwPlugin
=
3840 do_GetService("@mozilla.org/blackwood/pluglet-engine;1", &result
);
3841 if (NS_SUCCEEDED(result
)) {
3842 result
= bwPlugin
->CreatePluginInstance(NULL
,
3843 kIPluginInstanceIID
,
3845 (void **)getter_AddRefs(instance
));
3850 // neither an XPCOM or legacy plugin could be instantiated,
3851 // so return the failure
3852 if (NS_FAILED(result
))
3855 // it is adreffed here
3856 aOwner
->SetInstance(instance
);
3858 nsRefPtr
<nsPluginInstancePeerImpl
> peer
= new nsPluginInstancePeerImpl();
3860 return NS_ERROR_OUT_OF_MEMORY
;
3862 // set up the peer for the instance
3863 peer
->Initialize(aOwner
, mimetype
);
3865 result
= instance
->Initialize(peer
); // this should addref the peer but not the instance or owner
3866 if (NS_FAILED(result
)) // except in some cases not Java, see bug 140931
3867 return result
; // our COM pointer will free the peer
3869 // instance and peer will be addreffed here
3870 result
= AddInstanceToActiveList(plugin
, instance
, aURL
, PR_FALSE
, peer
);
3872 #ifdef PLUGIN_LOGGING
3873 nsCAutoString urlSpec2
;
3875 aURL
->GetSpec(urlSpec2
);
3877 PR_LOG(nsPluginLogging::gPluginLog
, PLUGIN_LOG_BASIC
,
3878 ("nsPluginHostImpl::TrySetupPluginInstance Finished mime=%s, rv=%d, owner=%p, url=%s\n",
3879 aMimeType
, result
, aOwner
, urlSpec2
.get()));
3888 nsPluginHostImpl::SetUpDefaultPluginInstance(const char *aMimeType
,
3890 nsIPluginInstanceOwner
*aOwner
)
3892 if (mDefaultPluginDisabled
) {
3893 // The default plugin is disabled, don't load it.
3898 nsCOMPtr
<nsIPluginInstance
> instance
;
3899 nsCOMPtr
<nsIPlugin
> plugin
= NULL
;
3900 const char* mimetype
= aMimeType
;
3903 return NS_ERROR_FAILURE
;
3905 GetPluginFactory("*", getter_AddRefs(plugin
));
3908 instance
= do_CreateInstance(NS_INLINE_PLUGIN_CONTRACTID_PREFIX
"*",
3911 // couldn't create an XPCOM plugin, try to create wrapper for a
3913 if (NS_FAILED(result
)) {
3915 result
= plugin
->CreateInstance(NULL
, kIPluginInstanceIID
,
3916 getter_AddRefs(instance
));
3919 // neither an XPCOM or legacy plugin could be instantiated, so
3920 // return the failure
3921 if (NS_FAILED(result
))
3924 // it is adreffed here
3925 aOwner
->SetInstance(instance
);
3927 nsRefPtr
<nsPluginInstancePeerImpl
> peer
= new nsPluginInstancePeerImpl();
3929 return NS_ERROR_OUT_OF_MEMORY
;
3931 // if we don't have a mimetype, check by file extension
3933 if (!mimetype
|| !*mimetype
) {
3934 nsresult res
= NS_OK
;
3935 nsCOMPtr
<nsIMIMEService
> ms (do_GetService(NS_MIMESERVICE_CONTRACTID
, &res
));
3936 if (NS_SUCCEEDED(res
)) {
3937 res
= ms
->GetTypeFromURI(aURL
, mt
);
3938 if (NS_SUCCEEDED(res
))
3939 mimetype
= mt
.get();
3943 // set up the peer for the instance
3944 peer
->Initialize(aOwner
, mimetype
);
3946 // this should addref the peer but not the instance or owner except
3947 // in some cases not Java, see bug 140931 our COM pointer will free
3949 result
= instance
->Initialize(peer
);
3950 if (NS_FAILED(result
))
3953 // instance and peer will be addreffed here
3954 result
= AddInstanceToActiveList(plugin
, instance
, aURL
, PR_TRUE
, peer
);
3960 nsPluginHostImpl::IsPluginEnabledForType(const char* aMimeType
)
3962 // Pass PR_FALSE as the second arg so we can return NS_ERROR_PLUGIN_DISABLED
3963 // for disabled plug-ins.
3964 nsPluginTag
*plugin
= FindPluginForType(aMimeType
, PR_FALSE
);
3966 return NS_ERROR_FAILURE
;
3968 if (!plugin
->IsEnabled()) {
3969 if (plugin
->HasFlag(NS_PLUGIN_FLAG_BLOCKLISTED
))
3970 return NS_ERROR_PLUGIN_BLOCKLISTED
;
3972 return NS_ERROR_PLUGIN_DISABLED
;
3978 // check comma delimitered extensions
3979 static int CompareExtensions(const char *aExtensionList
, const char *aExtension
)
3981 if (!aExtensionList
|| !aExtension
)
3984 const char *pExt
= aExtensionList
;
3985 const char *pComma
= strchr(pExt
, ',');
3987 return PL_strcasecmp(pExt
, aExtension
);
3989 int extlen
= strlen(aExtension
);
3991 int length
= pComma
- pExt
;
3992 if (length
== extlen
&& 0 == PL_strncasecmp(aExtension
, pExt
, length
))
3996 pComma
= strchr(pExt
, ',');
4000 return PL_strcasecmp(pExt
, aExtension
);
4004 nsPluginHostImpl::IsPluginEnabledForExtension(const char* aExtension
,
4005 const char* &aMimeType
)
4007 nsPluginTag
*plugin
= FindPluginEnabledForExtension(aExtension
, aMimeType
);
4008 return plugin
? NS_OK
: NS_ERROR_FAILURE
;
4011 class DOMMimeTypeImpl
: public nsIDOMMimeType
{
4015 DOMMimeTypeImpl(nsPluginTag
* aTag
, PRUint32 aMimeTypeIndex
)
4019 CopyUTF8toUTF16(aTag
->mMimeDescriptionArray
[aMimeTypeIndex
], mDescription
);
4020 if (aTag
->mExtensionsArray
)
4021 CopyUTF8toUTF16(aTag
->mExtensionsArray
[aMimeTypeIndex
], mSuffixes
);
4022 if (aTag
->mMimeTypeArray
)
4023 CopyUTF8toUTF16(aTag
->mMimeTypeArray
[aMimeTypeIndex
], mType
);
4026 virtual ~DOMMimeTypeImpl() {
4029 NS_METHOD
GetDescription(nsAString
& aDescription
)
4031 aDescription
.Assign(mDescription
);
4035 NS_METHOD
GetEnabledPlugin(nsIDOMPlugin
** aEnabledPlugin
)
4037 // this has to be implemented by the DOM version.
4038 *aEnabledPlugin
= nsnull
;
4042 NS_METHOD
GetSuffixes(nsAString
& aSuffixes
)
4044 aSuffixes
.Assign(mSuffixes
);
4048 NS_METHOD
GetType(nsAString
& aType
)
4050 aType
.Assign(mType
);
4055 nsString mDescription
;
4060 NS_IMPL_ISUPPORTS1(DOMMimeTypeImpl
, nsIDOMMimeType
)
4062 class DOMPluginImpl
: public nsIDOMPlugin
{
4066 DOMPluginImpl(nsPluginTag
* aPluginTag
) : mPluginTag(aPluginTag
)
4070 virtual ~DOMPluginImpl() {
4073 NS_METHOD
GetDescription(nsAString
& aDescription
)
4075 CopyUTF8toUTF16(mPluginTag
.mDescription
, aDescription
);
4079 NS_METHOD
GetFilename(nsAString
& aFilename
)
4082 nsCOMPtr
<nsIPrefBranch
> prefService
= do_GetService(NS_PREFSERVICE_CONTRACTID
);
4084 NS_SUCCEEDED(prefService
->GetBoolPref("plugin.expose_full_path",&bShowPath
)) &&
4086 // only show the full path if people have set the pref,
4087 // the default should not reveal path information (bug 88183)
4088 #if defined(XP_MACOSX)
4089 CopyUTF8toUTF16(mPluginTag
.mFullPath
, aFilename
);
4091 CopyUTF8toUTF16(mPluginTag
.mFileName
, aFilename
);
4097 if (!mPluginTag
.mFullPath
.IsEmpty()) {
4098 #if !defined(XP_MACOSX)
4099 NS_ERROR("Only MAC should be using nsPluginTag::mFullPath!");
4101 CopyUTF8toUTF16(mPluginTag
.mFullPath
, spec
);
4103 CopyUTF8toUTF16(mPluginTag
.mFileName
, spec
);
4107 nsCOMPtr
<nsILocalFile
> pluginPath
;
4108 NS_NewLocalFile(spec
, PR_TRUE
, getter_AddRefs(pluginPath
));
4110 return pluginPath
->GetLeafName(aFilename
);
4113 NS_METHOD
GetName(nsAString
& aName
)
4115 CopyUTF8toUTF16(mPluginTag
.mName
, aName
);
4119 NS_METHOD
GetLength(PRUint32
* aLength
)
4121 *aLength
= mPluginTag
.mVariants
;
4125 NS_METHOD
Item(PRUint32 aIndex
, nsIDOMMimeType
** aReturn
)
4127 nsIDOMMimeType
* mimeType
= new DOMMimeTypeImpl(&mPluginTag
, aIndex
);
4128 NS_IF_ADDREF(mimeType
);
4129 *aReturn
= mimeType
;
4133 NS_METHOD
NamedItem(const nsAString
& aName
, nsIDOMMimeType
** aReturn
)
4135 for (int i
= mPluginTag
.mVariants
- 1; i
>= 0; --i
) {
4136 if (aName
.Equals(NS_ConvertUTF8toUTF16(mPluginTag
.mMimeTypeArray
[i
])))
4137 return Item(i
, aReturn
);
4143 nsPluginTag mPluginTag
;
4146 NS_IMPL_ISUPPORTS1(DOMPluginImpl
, nsIDOMPlugin
)
4149 nsPluginHostImpl::GetPluginCount(PRUint32
* aPluginCount
)
4155 nsPluginTag
* plugin
= mPlugins
;
4156 while (plugin
!= nsnull
) {
4157 if (plugin
->IsEnabled()) {
4160 plugin
= plugin
->mNext
;
4163 *aPluginCount
= count
;
4169 nsPluginHostImpl::GetPlugins(PRUint32 aPluginCount
, nsIDOMPlugin
** aPluginArray
)
4173 nsPluginTag
* plugin
= mPlugins
;
4174 for (PRUint32 i
= 0; i
< aPluginCount
&& plugin
; plugin
= plugin
->mNext
) {
4175 if (plugin
->IsEnabled()) {
4176 nsIDOMPlugin
* domPlugin
= new DOMPluginImpl(plugin
);
4177 NS_IF_ADDREF(domPlugin
);
4178 aPluginArray
[i
++] = domPlugin
;
4186 nsPluginHostImpl::GetPluginTags(PRUint32
* aPluginCount
, nsIPluginTag
*** aResults
)
4191 nsRefPtr
<nsPluginTag
> plugin
= mPlugins
;
4192 while (plugin
!= nsnull
) {
4194 plugin
= plugin
->mNext
;
4197 *aResults
= static_cast<nsIPluginTag
**>
4198 (nsMemory::Alloc(count
* sizeof(**aResults
)));
4200 return NS_ERROR_OUT_OF_MEMORY
;
4202 *aPluginCount
= count
;
4206 for (i
= 0; i
< count
; i
++) {
4207 (*aResults
)[i
] = plugin
;
4208 NS_ADDREF((*aResults
)[i
]);
4209 plugin
= plugin
->mNext
;
4216 nsPluginHostImpl::FindPluginForType(const char* aMimeType
,
4217 PRBool aCheckEnabled
)
4219 nsPluginTag
*plugins
= nsnull
;
4220 PRInt32 variants
, cnt
;
4224 // if we have a mimetype passed in, search the mPlugins
4225 // linked list for a match
4226 if (nsnull
!= aMimeType
) {
4229 while (nsnull
!= plugins
) {
4230 variants
= plugins
->mVariants
;
4231 for (cnt
= 0; cnt
< variants
; cnt
++) {
4232 if ((!aCheckEnabled
|| plugins
->IsEnabled()) &&
4233 plugins
->mMimeTypeArray
[cnt
] &&
4234 (0 == PL_strcasecmp(plugins
->mMimeTypeArray
[cnt
], aMimeType
))) {
4239 plugins
= plugins
->mNext
;
4247 nsPluginHostImpl::FindPluginEnabledForExtension(const char* aExtension
,
4248 const char*& aMimeType
)
4250 nsPluginTag
*plugins
= nsnull
;
4251 PRInt32 variants
, cnt
;
4255 // if we have a mimetype passed in, search the mPlugins linked
4260 variants
= plugins
->mVariants
;
4261 if (plugins
->mExtensionsArray
) {
4262 for (cnt
= 0; cnt
< variants
; cnt
++) {
4263 // mExtensionsArray[cnt] is a list of extensions separated
4265 if (plugins
->IsEnabled() &&
4266 0 == CompareExtensions(plugins
->mExtensionsArray
[cnt
], aExtension
)) {
4267 aMimeType
= plugins
->mMimeTypeArray
[cnt
];
4273 plugins
= plugins
->mNext
;
4280 #if defined(XP_MACOSX)
4281 /* The following code examines the format of a Mac OS X binary, and determines whether it
4282 * is compatible with the current executable.
4285 #include <sys/stat.h>
4286 #include <sys/fcntl.h>
4289 static inline PRBool
is_directory(const char* path
)
4292 return ::stat(path
, &sb
) == 0 && S_ISDIR(sb
.st_mode
);
4295 static inline PRBool
is_symbolic_link(const char* path
)
4298 return ::lstat(path
, &sb
) == 0 && S_ISLNK(sb
.st_mode
);
4301 static int open_executable(const char* path
)
4304 char resolvedPath
[PATH_MAX
] = "\0";
4306 // If the root of the bundle as referred to by path is a symbolic link,
4307 // CFBundleCopyExecutableURL will not return an absolute URL, but will
4308 // instead only return the executable name, such as "MRJPlugin". Work
4309 // around that by always using a fully-resolved absolute pathname.
4310 if (is_symbolic_link(path
)) {
4311 path
= realpath(path
, resolvedPath
);
4316 // if this is a directory, it must be a bundle, so get the true path using CFBundle...
4317 if (is_directory(path
)) {
4318 CFBundleRef bundle
= NULL
;
4319 CFStringRef pathRef
= CFStringCreateWithCString(NULL
, path
, kCFStringEncodingUTF8
);
4321 CFURLRef bundleURL
= CFURLCreateWithFileSystemPath(NULL
, pathRef
, kCFURLPOSIXPathStyle
, true);
4323 if (bundleURL
!= NULL
) {
4324 bundle
= CFBundleCreate(NULL
, bundleURL
);
4325 CFRelease(bundleURL
);
4327 CFURLRef executableURL
= CFBundleCopyExecutableURL(bundle
);
4328 if (executableURL
) {
4329 pathRef
= CFURLCopyFileSystemPath(executableURL
, kCFURLPOSIXPathStyle
);
4330 CFRelease(executableURL
);
4332 CFIndex bufferSize
= CFStringGetMaximumSizeForEncoding(CFStringGetLength(pathRef
), kCFStringEncodingUTF8
) + 1;
4333 char* executablePath
= new char[bufferSize
];
4334 if (executablePath
&& CFStringGetCString(pathRef
, executablePath
, bufferSize
, kCFStringEncodingUTF8
)) {
4335 fd
= open(executablePath
, O_RDONLY
, 0);
4336 delete[] executablePath
;
4346 fd
= open(path
, O_RDONLY
, 0);
4351 static PRBool
IsCompatibleExecutable(const char* path
)
4353 int fd
= open_executable(path
);
4355 // Check the executable header to see if it is something we can use. Currently
4356 // we can only use 32-bit mach-o and FAT binaries (FAT headers are always big
4357 // endian, so we do network-to-host swap on the bytes from disk).
4358 // Note: We assume FAT binaries contain the right arch. Maybe fix that later.
4360 ssize_t n
= read(fd
, &magic
, sizeof(magic
));
4362 if (n
== sizeof(magic
)) {
4363 if ((magic
== MH_MAGIC
) || (PR_ntohl(magic
) == FAT_MAGIC
))
4372 inline PRBool
IsCompatibleExecutable(const char* path
) { return PR_TRUE
; }
4376 static nsresult
ConvertToNative(nsIUnicodeEncoder
*aEncoder
,
4377 const nsACString
& aUTF8String
,
4378 nsACString
& aNativeString
)
4380 NS_ConvertUTF8toUTF16
utf16(aUTF8String
);
4381 PRInt32 len
= utf16
.Length();
4383 nsresult rv
= aEncoder
->GetMaxLength(utf16
.get(), len
, &outLen
);
4384 NS_ENSURE_SUCCESS(rv
, rv
);
4385 if (!EnsureStringLength(aNativeString
, outLen
))
4386 return NS_ERROR_OUT_OF_MEMORY
;
4387 rv
= aEncoder
->Convert(utf16
.get(), &len
,
4388 aNativeString
.BeginWriting(), &outLen
);
4389 NS_ENSURE_SUCCESS(rv
, rv
);
4390 aNativeString
.SetLength(outLen
);
4394 static nsresult
CreateNPAPIPlugin(nsIServiceManagerObsolete
* aServiceManager
,
4395 const nsPluginTag
*aPluginTag
,
4396 nsIPlugin
**aOutNPAPIPlugnin
)
4399 nsCOMPtr
<nsIPlatformCharset
> pcs
=
4400 do_GetService(NS_PLATFORMCHARSET_CONTRACTID
, &rv
);
4401 NS_ENSURE_SUCCESS(rv
, rv
);
4403 nsCAutoString charset
;
4404 rv
= pcs
->GetCharset(kPlatformCharsetSel_FileName
, charset
);
4405 NS_ENSURE_SUCCESS(rv
, rv
);
4407 nsCAutoString fileName
, fullPath
;
4408 if (!charset
.LowerCaseEqualsLiteral("utf-8")) {
4409 nsCOMPtr
<nsIUnicodeEncoder
> encoder
;
4410 nsCOMPtr
<nsICharsetConverterManager
> ccm
=
4411 do_GetService(NS_CHARSETCONVERTERMANAGER_CONTRACTID
, &rv
);
4412 NS_ENSURE_SUCCESS(rv
, rv
);
4413 rv
= ccm
->GetUnicodeEncoderRaw(charset
.get(), getter_AddRefs(encoder
));
4414 NS_ENSURE_SUCCESS(rv
, rv
);
4415 rv
= ConvertToNative(encoder
, aPluginTag
->mFileName
, fileName
);
4416 NS_ENSURE_SUCCESS(rv
, rv
);
4417 rv
= ConvertToNative(encoder
, aPluginTag
->mFullPath
, fullPath
);
4418 NS_ENSURE_SUCCESS(rv
, rv
);
4420 fileName
= aPluginTag
->mFileName
;
4421 fullPath
= aPluginTag
->mFullPath
;
4424 return nsNPAPIPlugin::CreatePlugin(fileName
.get(),
4426 aPluginTag
->mLibrary
,
4430 NS_IMETHODIMP
nsPluginHostImpl::GetPluginFactory(const char *aMimeType
, nsIPlugin
** aPlugin
)
4432 nsresult rv
= NS_ERROR_FAILURE
;
4436 return NS_ERROR_ILLEGAL_VALUE
;
4438 // If plugins haven't been scanned yet, do so now
4441 nsPluginTag
* pluginTag
= FindPluginForType(aMimeType
, PR_TRUE
);
4444 PLUGIN_LOG(PLUGIN_LOG_BASIC
,
4445 ("nsPluginHostImpl::GetPluginFactory Begin mime=%s, plugin=%s\n",
4446 aMimeType
, pluginTag
->mFileName
.get()));
4449 if (aMimeType
&& !pluginTag
->mFileName
.IsEmpty())
4450 printf("For %s found plugin %s\n", aMimeType
, pluginTag
->mFileName
.get());
4453 if (!pluginTag
->mLibrary
) { // if we haven't done this yet
4454 nsCOMPtr
<nsILocalFile
> file
= do_CreateInstance("@mozilla.org/file/local;1");
4455 #if !defined(XP_MACOSX)
4456 file
->InitWithPath(NS_ConvertUTF8toUTF16(pluginTag
->mFileName
));
4458 if (pluginTag
->mFullPath
.IsEmpty())
4459 return NS_ERROR_FAILURE
;
4460 file
->InitWithPath(NS_ConvertUTF8toUTF16(pluginTag
->mFullPath
));
4462 nsPluginFile
pluginFile(file
);
4463 PRLibrary
* pluginLibrary
= NULL
;
4465 if (pluginFile
.LoadPlugin(pluginLibrary
) != NS_OK
|| pluginLibrary
== NULL
)
4466 return NS_ERROR_FAILURE
;
4468 // remove from unused lib list, if it is there
4469 if (mUnusedLibraries
.IndexOf(pluginLibrary
) > -1)
4470 mUnusedLibraries
.RemoveElement(pluginLibrary
);
4472 pluginTag
->mLibrary
= pluginLibrary
;
4475 nsIPlugin
* plugin
= pluginTag
->mEntryPoint
;
4477 // nsIPlugin* of xpcom plugins can be found thru a call to
4478 // nsIComponentManager::GetClassObjectByContractID()
4479 nsCAutoString
contractID(
4480 NS_LITERAL_CSTRING(NS_INLINE_PLUGIN_CONTRACTID_PREFIX
) +
4481 nsDependentCString(aMimeType
));
4482 nsresult rv
= CallGetClassObject(contractID
.get(), &plugin
);
4483 if (NS_SUCCEEDED(rv
) && plugin
) {
4484 // plugin is already addref'd
4485 pluginTag
->mEntryPoint
= plugin
;
4486 plugin
->Initialize();
4491 // No, this is not a leak. GetGlobalServiceManager() doesn't
4492 // addref the pointer on the way out. It probably should.
4493 nsIServiceManagerObsolete
* serviceManager
;
4494 nsServiceManager::GetGlobalServiceManager((nsIServiceManager
**)&serviceManager
);
4496 // need to get the plugin factory from this plugin.
4497 nsFactoryProc nsGetFactory
= nsnull
;
4499 nsGetFactory
= (nsFactoryProc
) PR_FindFunctionSymbol(pluginTag
->mLibrary
, "_NSGetFactory");
4501 nsGetFactory
= (nsFactoryProc
) PR_FindFunctionSymbol(pluginTag
->mLibrary
, "NSGetFactory");
4503 if (nsGetFactory
&& IsCompatibleExecutable(pluginTag
->mFullPath
.get())) {
4504 // XPCOM-style plugins (or at least the OJI one) cause crashes on
4505 // on windows GCC builds, so we're just turning them off for now.
4506 #if !defined(XP_WIN) || !defined(__GNUC__)
4507 rv
= nsGetFactory(serviceManager
, kPluginCID
, nsnull
, nsnull
, // XXX fix ClassName/ContractID
4508 (nsIFactory
**)&pluginTag
->mEntryPoint
);
4509 plugin
= pluginTag
->mEntryPoint
;
4511 plugin
->Initialize();
4515 // on OS2, first check if this might be legacy XPCOM module.
4516 else if (PR_FindSymbol(pluginTag
->mLibrary
, "NSGetFactory") &&
4517 IsCompatibleExecutable(pluginTag
->mFullPath
.get())) {
4518 // Possibly a legacy XPCOM module. We'll need to create a calling
4519 // vtable/calling convention wrapper for it.
4520 nsCOMPtr
<nsILegacyPluginWrapperOS2
> wrapper
=
4521 do_GetService(NS_LEGACY_PLUGIN_WRAPPER_CONTRACTID
, &rv
);
4522 if (NS_SUCCEEDED(rv
)) {
4523 rv
= wrapper
->GetFactory(serviceManager
, kPluginCID
, nsnull
, nsnull
,
4524 pluginTag
->mLibrary
, &pluginTag
->mEntryPoint
);
4525 plugin
= pluginTag
->mEntryPoint
;
4527 plugin
->Initialize();
4532 // Now lets try to get the entry point from a 4.x plugin
4533 rv
= CreateNPAPIPlugin(serviceManager
, pluginTag
, &plugin
);
4534 if (NS_SUCCEEDED(rv
))
4535 pluginTag
->mEntryPoint
= plugin
;
4536 pluginTag
->Mark(NS_PLUGIN_FLAG_OLDSCHOOL
);
4537 // no need to initialize, already done by CreatePlugin()
4541 #if defined (XP_MACOSX)
4542 /* Flash 6.0 r50 and older on Mac has a bug which calls ::UseInputWindow(NULL, true)
4543 which turn off all our inline IME. Turn it back after the plugin
4544 initializtion and hope that future versions will be fixed. See bug 159016
4546 if (StringBeginsWith(pluginTag
->mDescription
,
4547 NS_LITERAL_CSTRING("Shockwave Flash 6.0"),
4548 nsCaseInsensitiveCStringComparator()) &&
4549 pluginTag
->mDescription
.Length() > 21) {
4550 int ver
= atoi(pluginTag
->mDescription
.get() + 21);
4551 if (ver
&& ver
<= 50)
4552 ::UseInputWindow(NULL
, false);
4563 PLUGIN_LOG(PLUGIN_LOG_NORMAL
,
4564 ("nsPluginHostImpl::GetPluginFactory End mime=%s, rv=%d, plugin=%p name=%s\n",
4565 aMimeType
, rv
, *aPlugin
,
4566 (pluginTag
? pluginTag
->mFileName
.get() : "(not found)")));
4571 // XXX called from ScanPluginsDirectory only when told to filter
4572 // currently 'unwanted' plugins are Java, and all other plugins except
4573 // Acrobat, Flash, Quicktime and Shockwave
4574 static PRBool
isUnwantedPlugin(nsPluginTag
* tag
)
4576 if (tag
->mFileName
.IsEmpty())
4579 for (PRInt32 i
= 0; i
< tag
->mVariants
; ++i
) {
4580 if (nsnull
== PL_strcasecmp(tag
->mMimeTypeArray
[i
], "application/pdf"))
4583 if (nsnull
== PL_strcasecmp(tag
->mMimeTypeArray
[i
], "application/x-shockwave-flash"))
4586 if (nsnull
== PL_strcasecmp(tag
->mMimeTypeArray
[i
],"application/x-director"))
4590 // On Windows, we also want to include the Quicktime plugin from the 4.x directory
4591 // But because it spans several DLL's, the best check for now is by filename
4592 if (tag
->mFileName
.Find("npqtplugin", PR_TRUE
, 0, -1) != kNotFound
)
4598 PRBool
nsPluginHostImpl::IsJavaMIMEType(const char* aType
)
4601 ((0 == PL_strncasecmp(aType
, "application/x-java-vm",
4602 sizeof("application/x-java-vm") - 1)) ||
4603 (0 == PL_strncasecmp(aType
, "application/x-java-applet",
4604 sizeof("application/x-java-applet") - 1)) ||
4605 (0 == PL_strncasecmp(aType
, "application/x-java-bean",
4606 sizeof("application/x-java-bean") - 1)));
4609 nsPluginTag
* nsPluginHostImpl::HaveSamePlugin(nsPluginTag
* aPluginTag
)
4611 for (nsPluginTag
* tag
= mPlugins
; tag
; tag
= tag
->mNext
) {
4612 if (tag
->Equals(aPluginTag
))
4618 PRBool
nsPluginHostImpl::IsDuplicatePlugin(nsPluginTag
* aPluginTag
)
4620 nsPluginTag
* tag
= HaveSamePlugin(aPluginTag
);
4622 // if we got the same plugin, check the full path to see if this is a dup;
4624 // mFileName contains full path on Windows and Unix and leaf name on Mac
4625 // if those are not equal, we have the same plugin with different path,
4626 // i.e. duplicate, return true
4627 if (!tag
->mFileName
.Equals(aPluginTag
->mFileName
))
4630 // if they are equal, compare mFullPath fields just in case
4631 // mFileName contained leaf name only, and if not equal, return true
4632 if (!tag
->mFullPath
.Equals(aPluginTag
->mFullPath
))
4636 // we do not have it at all, return false
4640 // Structure for collecting plugin files found during directory scanning
4641 struct pluginFileinDirectory
4646 pluginFileinDirectory()
4652 // QuickSort callback for comparing the modification time of two files
4653 // if the times are the same, compare the filenames
4654 static int ComparePluginFileInDirectory (const void *v1
, const void *v2
, void *)
4656 const pluginFileinDirectory
* pfd1
= static_cast<const pluginFileinDirectory
*>(v1
);
4657 const pluginFileinDirectory
* pfd2
= static_cast<const pluginFileinDirectory
*>(v2
);
4660 if (LL_EQ(pfd1
->mModTime
, pfd2
->mModTime
))
4661 result
= Compare(pfd1
->mFilename
, pfd2
->mFilename
, nsCaseInsensitiveStringComparator());
4662 else if (LL_CMP(pfd1
->mModTime
, >, pfd2
->mModTime
))
4670 typedef NS_NPAPIPLUGIN_CALLBACK(char *, NP_GETMIMEDESCRIPTION
)(void);
4672 static nsresult
FixUpPluginInfo(nsPluginInfo
&aInfo
, nsPluginFile
&aPluginFile
)
4678 for (PRUint32 i
= 0; i
< aInfo
.fVariantCount
; i
++) {
4679 if (PL_strcmp(aInfo
.fMimeTypeArray
[i
], "*"))
4683 // check if this is an alien plugin (not our default plugin)
4684 // by trying to find a special entry point
4685 PRLibrary
*library
= nsnull
;
4686 if (NS_FAILED(aPluginFile
.LoadPlugin(library
)) || !library
)
4687 return NS_ERROR_FAILURE
;
4689 NP_GETMIMEDESCRIPTION pf
= (NP_GETMIMEDESCRIPTION
)PR_FindFunctionSymbol(library
, "NP_GetMIMEDescription");
4692 // if we found it, this is the default plugin, return
4693 char * mimedescription
= pf();
4694 if (!PL_strncmp(mimedescription
, NS_PLUGIN_DEFAULT_MIME_DESCRIPTION
, 1))
4698 // if we are here that means we have an alien plugin
4699 // which wants to take over "*" type
4701 // change its "*" mime type to "[*]"
4702 PL_strfree(aInfo
.fMimeTypeArray
[i
]);
4703 aInfo
.fMimeTypeArray
[i
] = PL_strdup("[*]");
4705 // continue the loop?
4710 /* Helper class which automatically deallocates a nsVoidArray of
4711 * pluginFileinDirectories when the array goes out of scope.
4713 class nsAutoPluginFileDeleter
4716 nsAutoPluginFileDeleter (nsAutoVoidArray
& aPluginFiles
)
4717 :mPluginFiles(aPluginFiles
)
4720 ~nsAutoPluginFileDeleter()
4722 for (PRInt32 i
= 0; i
< mPluginFiles
.Count(); ++i
) {
4723 pluginFileinDirectory
* pfd
= static_cast<pluginFileinDirectory
*>(mPluginFiles
[i
]);
4728 // A reference to the array for which to perform deallocation.
4729 nsAutoVoidArray
& mPluginFiles
;
4732 nsresult
nsPluginHostImpl::ScanPluginsDirectory(nsIFile
* pluginsDir
,
4733 nsIComponentManager
* compManager
,
4734 PRBool aCreatePluginList
,
4735 PRBool
* aPluginsChanged
,
4736 PRBool checkForUnwantedPlugins
)
4738 NS_ENSURE_ARG_POINTER(aPluginsChanged
);
4741 *aPluginsChanged
= PR_FALSE
;
4743 #ifdef PLUGIN_LOGGING
4744 nsCAutoString dirPath
;
4745 pluginsDir
->GetNativePath(dirPath
);
4746 PLUGIN_LOG(PLUGIN_LOG_BASIC
,
4747 ("nsPluginHostImpl::ScanPluginsDirectory dir=%s\n", dirPath
.get()));
4750 nsCOMPtr
<nsISimpleEnumerator
> iter
;
4751 rv
= pluginsDir
->GetDirectoryEntries(getter_AddRefs(iter
));
4755 // Collect all the files in this directory in a void array we can sort later
4756 nsAutoVoidArray pluginFilesArray
; // array for sorting files in this directory
4758 // Setup the helper which will cleanup the array.
4759 nsAutoPluginFileDeleter
pluginFileArrayDeleter(pluginFilesArray
);
4762 while (NS_SUCCEEDED(iter
->HasMoreElements(&hasMore
)) && hasMore
) {
4763 nsCOMPtr
<nsISupports
> supports
;
4764 rv
= iter
->GetNext(getter_AddRefs(supports
));
4767 nsCOMPtr
<nsILocalFile
> dirEntry(do_QueryInterface(supports
, &rv
));
4771 // Sun's JRE 1.3.1 plugin must have symbolic links resolved or else it'll crash.
4773 dirEntry
->Normalize();
4775 nsAutoString filePath
;
4776 rv
= dirEntry
->GetPath(filePath
);
4780 if (nsPluginsDir::IsPluginFile(dirEntry
)) {
4781 pluginFileinDirectory
* item
= new pluginFileinDirectory();
4783 return NS_ERROR_OUT_OF_MEMORY
;
4785 // Get file mod time
4786 PRInt64 fileModTime
= LL_ZERO
;
4787 dirEntry
->GetLastModifiedTime(&fileModTime
);
4789 item
->mModTime
= fileModTime
;
4790 item
->mFilename
= filePath
;
4791 pluginFilesArray
.AppendElement(item
);
4793 } // end round of up of plugin files
4795 // now sort the array by file modification time or by filename, if equal
4796 // put newer plugins first to weed out dups and catch upgrades, see bug 119966
4797 pluginFilesArray
.Sort(ComparePluginFileInDirectory
, nsnull
);
4799 // finally, go through the array, looking at each entry and continue processing it
4800 for (PRInt32 i
= 0; i
< pluginFilesArray
.Count(); i
++) {
4801 pluginFileinDirectory
* pfd
= static_cast<pluginFileinDirectory
*>(pluginFilesArray
[i
]);
4802 nsCOMPtr
<nsIFile
> file
= do_CreateInstance("@mozilla.org/file/local;1");
4803 nsCOMPtr
<nsILocalFile
> localfile
= do_QueryInterface(file
);
4804 localfile
->InitWithPath(pfd
->mFilename
);
4805 PRInt64 fileModTime
= pfd
->mModTime
;
4807 // Look for it in our cache
4808 nsRefPtr
<nsPluginTag
> pluginTag
;
4809 RemoveCachedPluginsInfo(NS_ConvertUTF16toUTF8(pfd
->mFilename
).get(),
4810 getter_AddRefs(pluginTag
));
4812 PRBool enabled
= PR_TRUE
;
4813 PRBool seenBefore
= PR_FALSE
;
4815 seenBefore
= PR_TRUE
;
4816 // If plugin changed, delete cachedPluginTag and don't use cache
4817 if (LL_NE(fileModTime
, pluginTag
->mLastModifiedTime
)) {
4818 // Plugins has changed. Don't use cached plugin info.
4819 enabled
= (pluginTag
->Flags() & NS_PLUGIN_FLAG_ENABLED
) != 0;
4822 // plugin file changed, flag this fact
4823 *aPluginsChanged
= PR_TRUE
;
4826 // if it is unwanted plugin we are checking for, get it back to the cache info list
4827 // if this is a duplicate plugin, too place it back in the cache info list marking unwantedness
4828 if ((checkForUnwantedPlugins
&& isUnwantedPlugin(pluginTag
)) ||
4829 IsDuplicatePlugin(pluginTag
)) {
4830 if (!pluginTag
->HasFlag(NS_PLUGIN_FLAG_UNWANTED
)) {
4831 // Plugin switched from wanted to unwanted
4832 *aPluginsChanged
= PR_TRUE
;
4834 pluginTag
->Mark(NS_PLUGIN_FLAG_UNWANTED
);
4835 pluginTag
->mNext
= mCachedPlugins
;
4836 mCachedPlugins
= pluginTag
;
4837 } else if (pluginTag
->HasFlag(NS_PLUGIN_FLAG_UNWANTED
)) {
4838 pluginTag
->UnMark(NS_PLUGIN_FLAG_UNWANTED
);
4839 // Plugin switched from unwanted to wanted
4840 *aPluginsChanged
= PR_TRUE
;
4845 // plugin file was added, flag this fact
4846 *aPluginsChanged
= PR_TRUE
;
4849 // if we are not creating the list, just continue the loop
4850 // no need to proceed if changes are detected
4851 if (!aCreatePluginList
) {
4852 if (*aPluginsChanged
)
4858 // if it is not found in cache info list or has been changed, create a new one
4860 nsPluginFile
pluginFile(file
);
4861 PRLibrary
* pluginLibrary
= nsnull
;
4863 // load the plugin's library so we can ask it some questions, but not for Windows
4865 if (pluginFile
.LoadPlugin(pluginLibrary
) != NS_OK
|| pluginLibrary
== nsnull
)
4869 // create a tag describing this plugin.
4871 memset(&info
, 0, sizeof(info
));
4872 nsresult res
= pluginFile
.GetPluginInfo(info
);
4873 // if we don't have mime type don't proceed, this is not a plugin
4874 if (NS_FAILED(res
) || !info
.fMimeTypeArray
) {
4875 pluginFile
.FreePluginInfo(info
);
4879 // Check for any potential '*' mime type handlers which are not our
4880 // own default plugin and disable them as they will break the plugin
4881 // finder service, see Bugzilla bug 132430
4882 if (!mAllowAlienStarHandler
)
4883 FixUpPluginInfo(info
, pluginFile
);
4885 pluginTag
= new nsPluginTag(&info
);
4886 pluginFile
.FreePluginInfo(info
);
4888 if (pluginTag
== nsnull
)
4889 return NS_ERROR_OUT_OF_MEMORY
;
4891 pluginTag
->mLibrary
= pluginLibrary
;
4892 pluginTag
->mLastModifiedTime
= fileModTime
;
4894 nsCOMPtr
<nsIBlocklistService
> blocklist
= do_GetService("@mozilla.org/extensions/blocklist;1");
4897 rv
= blocklist
->GetPluginBlocklistState(pluginTag
, EmptyString(),
4898 EmptyString(), &state
);
4900 if (NS_SUCCEEDED(rv
)) {
4901 // If the blocklist says so then block the plugin. If the blocklist says
4902 // it is risky and we have never seen this plugin before then disable it
4903 if (state
== nsIBlocklistService::STATE_BLOCKED
)
4904 pluginTag
->Mark(NS_PLUGIN_FLAG_BLOCKLISTED
);
4905 else if (state
== nsIBlocklistService::STATE_SOFTBLOCKED
&& !seenBefore
)
4910 if (!enabled
|| (pluginTag
->mIsJavaPlugin
&& !mJavaEnabled
))
4911 pluginTag
->UnMark(NS_PLUGIN_FLAG_ENABLED
);
4913 // if this is unwanted plugin we are checkin for, or this is a duplicate plugin,
4914 // add it to our cache info list so we can cache the unwantedness of this plugin
4915 // when we sync cached plugins to registry
4916 NS_ASSERTION(!pluginTag
->HasFlag(NS_PLUGIN_FLAG_UNWANTED
),
4917 "Brand-new tags should not be unwanted");
4918 if ((checkForUnwantedPlugins
&& isUnwantedPlugin(pluginTag
)) ||
4919 IsDuplicatePlugin(pluginTag
)) {
4920 pluginTag
->Mark(NS_PLUGIN_FLAG_UNWANTED
);
4921 pluginTag
->mNext
= mCachedPlugins
;
4922 mCachedPlugins
= pluginTag
;
4926 // set the flag that we want to add this plugin to the list for now
4927 // and see if it remains after we check several reasons not to do so
4928 PRBool bAddIt
= PR_TRUE
;
4930 // check if this is a specific plugin we don't want
4931 if (checkForUnwantedPlugins
&& isUnwantedPlugin(pluginTag
))
4934 // check if we already have this plugin in the list which
4935 // is possible if we do refresh
4937 if (HaveSamePlugin(pluginTag
)) {
4938 // we cannot get here if the plugin has just been added
4939 // and thus |pluginTag| is not from cache, because otherwise
4940 // it would not be present in the list;
4941 // so there is no need to delete |pluginTag| -- it _is_ from the cache info list.
4946 // do it if we still want it
4948 pluginTag
->SetHost(this);
4949 pluginTag
->mNext
= mPlugins
;
4950 mPlugins
= pluginTag
;
4952 if (pluginTag
->IsEnabled())
4953 pluginTag
->RegisterWithCategoryManager(mOverrideInternalTypes
);
4955 else if (!pluginTag
->HasFlag(NS_PLUGIN_FLAG_UNWANTED
)) {
4956 // we don't need it, delete it;
4957 // but don't delete unwanted plugins since they are cached
4958 // in the cache info list and will be deleted later
4965 nsresult
nsPluginHostImpl::ScanPluginsDirectoryList(nsISimpleEnumerator
* dirEnum
,
4966 nsIComponentManager
* compManager
,
4967 PRBool aCreatePluginList
,
4968 PRBool
* aPluginsChanged
,
4969 PRBool checkForUnwantedPlugins
)
4972 while (NS_SUCCEEDED(dirEnum
->HasMoreElements(&hasMore
)) && hasMore
) {
4973 nsCOMPtr
<nsISupports
> supports
;
4974 nsresult rv
= dirEnum
->GetNext(getter_AddRefs(supports
));
4977 nsCOMPtr
<nsIFile
> nextDir(do_QueryInterface(supports
, &rv
));
4981 // don't pass aPluginsChanged directly to prevent it from been reset
4982 PRBool pluginschanged
= PR_FALSE
;
4983 ScanPluginsDirectory(nextDir
, compManager
, aCreatePluginList
, &pluginschanged
, checkForUnwantedPlugins
);
4986 *aPluginsChanged
= PR_TRUE
;
4988 // if changes are detected and we are not creating the list, do not proceed
4989 if (!aCreatePluginList
&& *aPluginsChanged
)
4995 NS_IMETHODIMP
nsPluginHostImpl::LoadPlugins()
4997 // do not do anything if it is already done
4998 // use ReloadPlugins() to enforce loading
5002 PRBool pluginschanged
;
5003 nsresult rv
= FindPlugins(PR_TRUE
, &pluginschanged
);
5007 // only if plugins have changed will we ask XPTI to refresh
5008 if (pluginschanged
) {
5009 // rescan XPTI to catch any newly installed interfaces
5010 nsCOMPtr
<nsIInterfaceInfoManager
>
5011 iim(do_GetService(NS_INTERFACEINFOMANAGER_SERVICE_CONTRACTID
));
5014 iim
->AutoRegisterInterfaces();
5016 nsCOMPtr
<nsIObserverService
>
5017 obsService(do_GetService("@mozilla.org/observer-service;1"));
5019 obsService
->NotifyObservers(nsnull
, "plugins-list-updated", nsnull
);
5025 #include "nsITimelineService.h"
5027 // if aCreatePluginList is false we will just scan for plugins
5028 // and see if any changes have been made to the plugins.
5029 // This is needed in ReloadPlugins to prevent possible recursive reloads
5030 nsresult
nsPluginHostImpl::FindPlugins(PRBool aCreatePluginList
, PRBool
* aPluginsChanged
)
5032 // let's start timing if we are only really creating the plugin list
5033 if (aCreatePluginList
) {
5034 NS_TIMELINE_START_TIMER("LoadPlugins");
5037 #ifdef CALL_SAFETY_ON
5038 // check preferences on whether or not we want to try safe calls to plugins
5039 NS_INIT_PLUGIN_SAFE_CALLS
;
5042 NS_ENSURE_ARG_POINTER(aPluginsChanged
);
5044 *aPluginsChanged
= PR_FALSE
;
5047 // Read cached plugins info
5050 nsCOMPtr
<nsIComponentManager
> compManager
;
5051 NS_GetComponentManager(getter_AddRefs(compManager
));
5053 LoadXPCOMPlugins(compManager
);
5056 // Failure here is not a show-stopper so just warn.
5057 rv
= EnsurePrivateDirServiceProvider();
5058 NS_ASSERTION(NS_SUCCEEDED(rv
), "Failed to register dir service provider.");
5061 nsCOMPtr
<nsIProperties
> dirService(do_GetService(kDirectoryServiceContractID
, &rv
));
5065 nsCOMPtr
<nsISimpleEnumerator
> dirList
;
5067 // Scan plugins directories;
5068 // don't pass aPluginsChanged directly, to prevent its
5069 // possible reset in subsequent ScanPluginsDirectory calls
5070 PRBool pluginschanged
= PR_FALSE
;
5072 // Scan the app-defined list of plugin dirs.
5073 rv
= dirService
->Get(NS_APP_PLUGINS_DIR_LIST
, NS_GET_IID(nsISimpleEnumerator
), getter_AddRefs(dirList
));
5074 if (NS_SUCCEEDED(rv
)) {
5075 ScanPluginsDirectoryList(dirList
, compManager
, aCreatePluginList
, &pluginschanged
);
5078 *aPluginsChanged
= PR_TRUE
;
5080 // if we are just looking for possible changes,
5081 // no need to proceed if changes are detected
5082 if (!aCreatePluginList
&& *aPluginsChanged
) {
5083 mCachedPlugins
= nsnull
;
5088 mPluginsLoaded
= PR_TRUE
; // at this point 'some' plugins have been loaded,
5089 // the rest is optional
5092 PRBool bScanPLIDs
= PR_FALSE
;
5095 mPrefService
->GetBoolPref("plugin.scan.plid.all", &bScanPLIDs
);
5097 // Now lets scan any PLID directories
5098 if (bScanPLIDs
&& mPrivateDirServiceProvider
) {
5099 rv
= mPrivateDirServiceProvider
->GetPLIDDirectories(getter_AddRefs(dirList
));
5100 if (NS_SUCCEEDED(rv
)) {
5101 ScanPluginsDirectoryList(dirList
, compManager
, aCreatePluginList
, &pluginschanged
);
5104 *aPluginsChanged
= PR_TRUE
;
5106 // if we are just looking for possible changes,
5107 // no need to proceed if changes are detected
5108 if (!aCreatePluginList
&& *aPluginsChanged
) {
5109 mCachedPlugins
= nsnull
;
5116 // Scan the installation paths of our popular plugins if the prefs are enabled
5118 // This table controls the order of scanning
5119 const char* const prefs
[] = {NS_WIN_JRE_SCAN_KEY
, nsnull
,
5120 NS_WIN_ACROBAT_SCAN_KEY
, nsnull
,
5121 NS_WIN_QUICKTIME_SCAN_KEY
, nsnull
,
5122 NS_WIN_WMP_SCAN_KEY
, nsnull
,
5123 NS_WIN_4DOTX_SCAN_KEY
, "1" /* second column is flag for 4.x folder */ };
5125 PRUint32 size
= sizeof(prefs
) / sizeof(prefs
[0]);
5127 for (PRUint32 i
= 0; i
< size
; i
+=2) {
5128 nsCOMPtr
<nsIFile
> dirToScan
;
5130 if (NS_SUCCEEDED(dirService
->Get(prefs
[i
], NS_GET_IID(nsIFile
), getter_AddRefs(dirToScan
))) &&
5132 NS_SUCCEEDED(dirToScan
->Exists(&bExists
)) &&
5135 PRBool bFilterUnwanted
= PR_FALSE
;
5137 // 4.x plugins folder stuff:
5138 // Normally we "filter" the 4.x folder through |IsUnwantedPlugin|
5139 // Check for a pref to see if we want to scan the entire 4.x plugins folder
5141 PRBool bScanEverything
;
5142 bFilterUnwanted
= PR_TRUE
; // default to filter 4.x folder
5144 NS_SUCCEEDED(mPrefService
->GetBoolPref(prefs
[i
], &bScanEverything
)) &&
5146 bFilterUnwanted
= PR_FALSE
;
5149 ScanPluginsDirectory(dirToScan
, compManager
, aCreatePluginList
, &pluginschanged
, bFilterUnwanted
);
5152 *aPluginsChanged
= PR_TRUE
;
5154 // if we are just looking for possible changes,
5155 // no need to proceed if changes are detected
5156 if (!aCreatePluginList
&& *aPluginsChanged
) {
5157 mCachedPlugins
= nsnull
;
5164 // if get to this point and did not detect changes in plugins
5165 // that means no plugins got updated or added
5166 // let's see if plugins have been removed
5167 if (!*aPluginsChanged
) {
5168 // count plugins remained in cache, if there are some, that means some plugins were removed;
5169 // while counting, we should ignore unwanted plugins which are also present in cache
5170 PRUint32 cachecount
= 0;
5171 for (nsPluginTag
* cachetag
= mCachedPlugins
; cachetag
; cachetag
= cachetag
->mNext
) {
5172 if (!cachetag
->HasFlag(NS_PLUGIN_FLAG_UNWANTED
))
5175 // if there is something left in cache, some plugins got removed from the directory
5176 // and therefor their info did not get removed from the cache info list during directory scan;
5179 *aPluginsChanged
= PR_TRUE
;
5182 // if we are not creating the list, there is no need to proceed
5183 if (!aCreatePluginList
) {
5184 mCachedPlugins
= nsnull
;
5188 // if we are creating the list, it is already done;
5189 // update the plugins info cache if changes are detected
5190 if (*aPluginsChanged
)
5193 // No more need for cached plugins. Clear it up.
5194 mCachedPlugins
= nsnull
;
5197 * XXX Big time hack alert!!!!
5198 * Because Real Player 8 installs in the components folder, we must have this one off
5199 * scan for nppl3260.dll because XPCOM has shut off nsGetFactory type plugins.
5200 * When we stop supporting Real 8 or they fix their installer, this can go away.
5202 if (aCreatePluginList
)
5203 ScanForRealInComponentsFolder(compManager
);
5205 // reverse our list of plugins
5206 nsRefPtr
<nsPluginTag
> next
;
5207 nsRefPtr
<nsPluginTag
> prev
;
5208 for (nsRefPtr
<nsPluginTag
> cur
= mPlugins
; cur
; cur
= next
) {
5216 NS_TIMELINE_STOP_TIMER("LoadPlugins");
5217 NS_TIMELINE_MARK_TIMER("LoadPlugins");
5223 nsPluginHostImpl::LoadXPCOMPlugins(nsIComponentManager
* aComponentManager
)
5225 // the component reg is a flat file now see 48888
5226 // we have to reimplement this method if we need it
5228 // The "new style" XPCOM plugins have their information stored in
5229 // the component registry, under the key
5231 // nsIRegistry::Common/software/plugins
5233 // Enumerate through that list now, creating an nsPluginTag for
5240 nsPluginHostImpl::UpdatePluginInfo(nsPluginTag
* aPluginTag
)
5244 mCachedPlugins
= nsnull
;
5246 if (!aPluginTag
|| aPluginTag
->IsEnabled())
5249 nsCOMPtr
<nsISupportsArray
> instsToReload
;
5250 NS_NewISupportsArray(getter_AddRefs(instsToReload
));
5251 mActivePluginList
.stopRunning(instsToReload
, aPluginTag
);
5252 mActivePluginList
.removeAllStopped();
5255 if (instsToReload
&& NS_SUCCEEDED(instsToReload
->Count(&c
)) && c
> 0) {
5256 nsCOMPtr
<nsIRunnable
> ev
= new nsPluginDocReframeEvent(instsToReload
);
5258 NS_DispatchToCurrentThread(ev
);
5265 nsPluginHostImpl::WritePluginInfo()
5268 nsresult rv
= NS_OK
;
5269 nsCOMPtr
<nsIProperties
> directoryService(do_GetService(NS_DIRECTORY_SERVICE_CONTRACTID
,&rv
));
5273 directoryService
->Get(NS_APP_USER_PROFILE_50_DIR
, NS_GET_IID(nsIFile
),
5274 getter_AddRefs(mPluginRegFile
));
5276 if (!mPluginRegFile
)
5277 return NS_ERROR_FAILURE
;
5279 PRFileDesc
* fd
= nsnull
;
5281 nsCOMPtr
<nsIFile
> pluginReg
;
5283 rv
= mPluginRegFile
->Clone(getter_AddRefs(pluginReg
));
5287 rv
= pluginReg
->AppendNative(kPluginRegistryFilename
);
5291 nsCOMPtr
<nsILocalFile
> localFile
= do_QueryInterface(pluginReg
, &rv
);
5295 rv
= localFile
->OpenNSPRFileDesc(PR_WRONLY
| PR_CREATE_FILE
| PR_TRUNCATE
, 0600, &fd
);
5299 PR_fprintf(fd
, "Generated File. Do not edit.\n");
5301 PR_fprintf(fd
, "\n[HEADER]\nVersion%c%s%c%c\n",
5302 PLUGIN_REGISTRY_FIELD_DELIMITER
,
5303 kPluginRegistryVersion
,
5304 PLUGIN_REGISTRY_FIELD_DELIMITER
,
5305 PLUGIN_REGISTRY_END_OF_LINE_MARKER
);
5307 // Store all plugins in the mPlugins list - all plugins currently in use.
5308 PR_fprintf(fd
, "\n[PLUGINS]\n");
5310 nsPluginTag
*taglist
[] = {mPlugins
, mCachedPlugins
};
5311 for (int i
=0; i
<(int)(sizeof(taglist
)/sizeof(nsPluginTag
*)); i
++) {
5312 for (nsPluginTag
*tag
= taglist
[i
]; tag
; tag
=tag
->mNext
) {
5313 // from mCachedPlugins list write down only unwanted plugins
5314 if ((taglist
[i
] == mCachedPlugins
) && !tag
->HasFlag(NS_PLUGIN_FLAG_UNWANTED
))
5316 // store each plugin info into the registry
5317 // filename & fullpath are on separate line
5318 // because they can contain field delimiter char
5319 PR_fprintf(fd
, "%s%c%c\n%s%c%c\n%s%c%c\n",
5320 (!tag
->mFileName
.IsEmpty() ? tag
->mFileName
.get() : ""),
5321 PLUGIN_REGISTRY_FIELD_DELIMITER
,
5322 PLUGIN_REGISTRY_END_OF_LINE_MARKER
,
5323 (!tag
->mFullPath
.IsEmpty() ? tag
->mFullPath
.get() : ""),
5324 PLUGIN_REGISTRY_FIELD_DELIMITER
,
5325 PLUGIN_REGISTRY_END_OF_LINE_MARKER
,
5326 (!tag
->mVersion
.IsEmpty() ? tag
->mVersion
.get() : ""),
5327 PLUGIN_REGISTRY_FIELD_DELIMITER
,
5328 PLUGIN_REGISTRY_END_OF_LINE_MARKER
);
5330 // lastModifiedTimeStamp|canUnload|tag->mFlags
5331 PR_fprintf(fd
, "%lld%c%d%c%lu%c%c\n",
5332 tag
->mLastModifiedTime
,
5333 PLUGIN_REGISTRY_FIELD_DELIMITER
,
5334 tag
->mCanUnloadLibrary
,
5335 PLUGIN_REGISTRY_FIELD_DELIMITER
,
5337 PLUGIN_REGISTRY_FIELD_DELIMITER
,
5338 PLUGIN_REGISTRY_END_OF_LINE_MARKER
);
5340 //description, name & mtypecount are on separate line
5341 PR_fprintf(fd
, "%s%c%c\n%s%c%c\n%d\n",
5342 (!tag
->mDescription
.IsEmpty() ? tag
->mDescription
.get() : ""),
5343 PLUGIN_REGISTRY_FIELD_DELIMITER
,
5344 PLUGIN_REGISTRY_END_OF_LINE_MARKER
,
5345 (!tag
->mName
.IsEmpty() ? tag
->mName
.get() : ""),
5346 PLUGIN_REGISTRY_FIELD_DELIMITER
,
5347 PLUGIN_REGISTRY_END_OF_LINE_MARKER
,
5348 tag
->mVariants
+ (tag
->mIsNPRuntimeEnabledJavaPlugin
? 1 : 0));
5350 // Add in each mimetype this plugin supports
5351 for (int i
=0; i
<tag
->mVariants
; i
++) {
5352 PR_fprintf(fd
, "%d%c%s%c%s%c%s%c%c\n",
5353 i
,PLUGIN_REGISTRY_FIELD_DELIMITER
,
5354 (tag
->mMimeTypeArray
&& tag
->mMimeTypeArray
[i
] ? tag
->mMimeTypeArray
[i
] : ""),
5355 PLUGIN_REGISTRY_FIELD_DELIMITER
,
5356 (!tag
->mMimeDescriptionArray
[i
].IsEmpty() ? tag
->mMimeDescriptionArray
[i
].get() : ""),
5357 PLUGIN_REGISTRY_FIELD_DELIMITER
,
5358 (tag
->mExtensionsArray
&& tag
->mExtensionsArray
[i
] ? tag
->mExtensionsArray
[i
] : ""),
5359 PLUGIN_REGISTRY_FIELD_DELIMITER
,
5360 PLUGIN_REGISTRY_END_OF_LINE_MARKER
);
5363 if (tag
->mIsNPRuntimeEnabledJavaPlugin
) {
5364 PR_fprintf(fd
, "%d%c%s%c%s%c%s%c%c\n",
5365 tag
->mVariants
, PLUGIN_REGISTRY_FIELD_DELIMITER
,
5366 "application/x-java-vm-npruntime",
5367 PLUGIN_REGISTRY_FIELD_DELIMITER
,
5369 PLUGIN_REGISTRY_FIELD_DELIMITER
,
5371 PLUGIN_REGISTRY_FIELD_DELIMITER
,
5372 PLUGIN_REGISTRY_END_OF_LINE_MARKER
);
5382 #define PLUGIN_REG_MIMETYPES_ARRAY_SIZE 12
5384 nsPluginHostImpl::ReadPluginInfo()
5388 nsCOMPtr
<nsIProperties
> directoryService(do_GetService(NS_DIRECTORY_SERVICE_CONTRACTID
,&rv
));
5392 directoryService
->Get(NS_APP_USER_PROFILE_50_DIR
, NS_GET_IID(nsIFile
),
5393 getter_AddRefs(mPluginRegFile
));
5395 if (!mPluginRegFile
)
5396 return NS_ERROR_FAILURE
;
5398 PRFileDesc
* fd
= nsnull
;
5400 nsCOMPtr
<nsIFile
> pluginReg
;
5402 rv
= mPluginRegFile
->Clone(getter_AddRefs(pluginReg
));
5406 rv
= pluginReg
->AppendNative(kPluginRegistryFilename
);
5410 nsCOMPtr
<nsILocalFile
> localFile
= do_QueryInterface(pluginReg
, &rv
);
5415 rv
= localFile
->GetFileSize(&fileSize
);
5419 PRInt32 flen
= nsInt64(fileSize
);
5421 NS_WARNING("Plugins Registry Empty!");
5422 return NS_OK
; // ERROR CONDITION
5425 nsPluginManifestLineReader reader
;
5426 char* registry
= reader
.Init(flen
);
5428 return NS_ERROR_OUT_OF_MEMORY
;
5430 rv
= localFile
->OpenNSPRFileDesc(PR_RDONLY
, 0444, &fd
);
5434 // set rv to return an error on goto out
5435 rv
= NS_ERROR_FAILURE
;
5437 PRInt32 bread
= PR_Read(fd
, registry
, flen
);
5443 if (!ReadSectionHeader(reader
, "HEADER"))
5446 if (!reader
.NextLine())
5451 // VersionLiteral, kPluginRegistryVersion
5452 if (2 != reader
.ParseLine(values
, 2))
5456 if (PL_strcmp(values
[0], "Version"))
5459 // kPluginRegistryVersion
5460 PRInt32 vdiff
= NS_CompareVersions(values
[1], kPluginRegistryVersion
);
5461 // If this is a registry from some future version then don't attempt to read it
5464 // If this is a registry from before the minimum then don't attempt to read it
5465 if (NS_CompareVersions(values
[1], kMinimumRegistryVersion
) < 0)
5468 // Registry v0.10 and upwards includes the plugin version field
5469 PRBool regHasVersion
= NS_CompareVersions(values
[1], "0.10") >= 0;
5471 if (!ReadSectionHeader(reader
, "PLUGINS"))
5474 while (reader
.NextLine()) {
5475 char *filename
= reader
.LinePtr();
5476 if (!reader
.NextLine())
5479 char *fullpath
= reader
.LinePtr();
5480 if (!reader
.NextLine())
5484 if (regHasVersion
) {
5485 version
= reader
.LinePtr();
5486 if (!reader
.NextLine())
5492 // lastModifiedTimeStamp|canUnload|tag.mFlag
5493 if (reader
.ParseLine(values
, 3) != 3)
5496 // If this is an old plugin registry mark this plugin tag to be refreshed
5497 PRInt64 lastmod
= vdiff
== 0 ? nsCRT::atoll(values
[0]) : -1;
5498 PRBool canunload
= atoi(values
[1]);
5499 PRUint32 tagflag
= atoi(values
[2]);
5500 if (!reader
.NextLine())
5503 char *description
= reader
.LinePtr();
5504 if (!reader
.NextLine())
5507 char *name
= reader
.LinePtr();
5508 if (!reader
.NextLine())
5511 int mimetypecount
= atoi(reader
.LinePtr());
5513 char *stackalloced
[PLUGIN_REG_MIMETYPES_ARRAY_SIZE
* 3];
5515 char **mimedescriptions
;
5517 char **heapalloced
= 0;
5518 if (mimetypecount
> PLUGIN_REG_MIMETYPES_ARRAY_SIZE
- 1) {
5519 heapalloced
= new char *[mimetypecount
* 3];
5520 mimetypes
= heapalloced
;
5522 mimetypes
= stackalloced
;
5524 mimedescriptions
= mimetypes
+ mimetypecount
;
5525 extensions
= mimedescriptions
+ mimetypecount
;
5527 int mtr
= 0; //mimetype read
5528 for (; mtr
< mimetypecount
; mtr
++) {
5529 if (!reader
.NextLine())
5532 //line number|mimetype|description|extension
5533 if (4 != reader
.ParseLine(values
, 4))
5535 int line
= atoi(values
[0]);
5538 mimetypes
[mtr
] = values
[1];
5539 mimedescriptions
[mtr
] = values
[2];
5540 extensions
[mtr
] = values
[3];
5543 if (mtr
!= mimetypecount
) {
5545 delete [] heapalloced
;
5550 nsRefPtr
<nsPluginTag
> tag
= new nsPluginTag(name
,
5553 (*fullpath
? fullpath
: 0), // we have to pass 0 prt if it's empty str
5555 (const char* const*)mimetypes
,
5556 (const char* const*)mimedescriptions
,
5557 (const char* const*)extensions
,
5558 mimetypecount
, lastmod
, canunload
, PR_TRUE
);
5560 delete [] heapalloced
;
5565 // Mark plugin as loaded from cache
5566 tag
->Mark(tagflag
| NS_PLUGIN_FLAG_FROMCACHE
);
5567 if (tag
->mIsJavaPlugin
) {
5569 tag
->Mark(NS_PLUGIN_FLAG_ENABLED
);
5571 tag
->UnMark(NS_PLUGIN_FLAG_ENABLED
);
5573 PR_LOG(nsPluginLogging::gPluginLog
, PLUGIN_LOG_BASIC
,
5574 ("LoadCachedPluginsInfo : Loading Cached plugininfo for %s\n", tag
->mFileName
.get()));
5575 tag
->mNext
= mCachedPlugins
;
5576 mCachedPlugins
= tag
;
5583 nsPluginHostImpl::RemoveCachedPluginsInfo(const char *filename
, nsPluginTag
**result
)
5585 nsRefPtr
<nsPluginTag
> prev
;
5586 nsRefPtr
<nsPluginTag
> tag
= mCachedPlugins
;
5589 // compare filename or else the mFullPath if it exists. Mac seems to use
5590 // mFullPath for fullpath and mFileName for just the leafname of fullpath.
5591 // On win and unix, mFullPath is never used and mFileName is contains the
5592 // full pathname. All this should move to using nsIFile.
5593 if (tag
->mFileName
.Equals(filename
) || tag
->mFullPath
.Equals(filename
)) {
5594 // Found it. Remove it from our list
5596 prev
->mNext
= tag
->mNext
;
5598 mCachedPlugins
= tag
->mNext
;
5599 tag
->mNext
= nsnull
;
5611 nsPluginHostImpl::EnsurePrivateDirServiceProvider()
5613 if (!mPrivateDirServiceProvider
) {
5615 mPrivateDirServiceProvider
= new nsPluginDirServiceProvider();
5616 if (!mPrivateDirServiceProvider
)
5617 return NS_ERROR_OUT_OF_MEMORY
;
5618 nsCOMPtr
<nsIDirectoryService
> dirService(do_GetService(kDirectoryServiceContractID
, &rv
));
5621 rv
= dirService
->RegisterProvider(mPrivateDirServiceProvider
);
5629 // Called by GetURL and PostURL
5630 NS_IMETHODIMP
nsPluginHostImpl::NewPluginURLStream(const nsString
& aURL
,
5631 nsIPluginInstance
*aInstance
,
5632 nsIPluginStreamListener
* aListener
,
5633 const char *aPostData
,
5635 PRUint32 aPostDataLen
,
5636 const char *aHeadersData
,
5637 PRUint32 aHeadersDataLen
)
5639 nsCOMPtr
<nsIURI
> url
;
5640 nsAutoString absUrl
;
5643 if (aURL
.Length() <= 0)
5646 // get the full URL of the document that the plugin is embedded
5647 // in to create an absolute url in case aURL is relative
5648 nsCOMPtr
<nsIDocument
> doc
;
5649 nsCOMPtr
<nsIPluginInstancePeer
> peer
;
5650 nsCOMPtr
<nsIPluginInstanceOwner
> owner
;
5651 rv
= aInstance
->GetPeer(getter_AddRefs(peer
));
5652 if (NS_SUCCEEDED(rv
) && peer
) {
5653 nsCOMPtr
<nsPIPluginInstancePeer
> privpeer(do_QueryInterface(peer
));
5654 rv
= privpeer
->GetOwner(getter_AddRefs(owner
));
5656 rv
= owner
->GetDocument(getter_AddRefs(doc
));
5657 if (NS_SUCCEEDED(rv
) && doc
) {
5658 // Create an absolute URL
5659 rv
= NS_MakeAbsoluteURI(absUrl
, aURL
, doc
->GetBaseURI());
5664 if (absUrl
.IsEmpty())
5665 absUrl
.Assign(aURL
);
5667 rv
= NS_NewURI(getter_AddRefs(url
), absUrl
);
5669 if (NS_SUCCEEDED(rv
)) {
5670 nsCOMPtr
<nsIPluginTagInfo2
> pti2
= do_QueryInterface(owner
);
5671 nsCOMPtr
<nsIDOMElement
> element
;
5673 pti2
->GetDOMElement(getter_AddRefs(element
));
5675 PRInt16 shouldLoad
= nsIContentPolicy::ACCEPT
;
5676 rv
= NS_CheckContentLoadPolicy(nsIContentPolicy::TYPE_OBJECT_SUBREQUEST
,
5678 (doc
? doc
->NodePrincipal() : nsnull
),
5680 EmptyCString(), //mime guess
5683 if (NS_FAILED(rv
)) return rv
;
5684 if (NS_CP_REJECTED(shouldLoad
)) {
5685 // Disallowed by content policy
5686 return NS_ERROR_CONTENT_BLOCKED
;
5689 nsPluginStreamListenerPeer
*listenerPeer
= new nsPluginStreamListenerPeer
;
5690 if (listenerPeer
== NULL
)
5691 return NS_ERROR_OUT_OF_MEMORY
;
5693 NS_ADDREF(listenerPeer
);
5694 rv
= listenerPeer
->Initialize(url
, aInstance
, aListener
);
5696 if (NS_SUCCEEDED(rv
)) {
5697 nsCOMPtr
<nsIInterfaceRequestor
> callbacks
;
5699 // Get the script global object owner and use that as the
5700 // notification callback.
5701 nsIScriptGlobalObject
* global
= doc
->GetScriptGlobalObject();
5703 nsCOMPtr
<nsIWebNavigation
> webNav
= do_GetInterface(global
);
5704 callbacks
= do_QueryInterface(webNav
);
5708 nsCOMPtr
<nsIChannel
> channel
;
5710 rv
= NS_NewChannel(getter_AddRefs(channel
), url
, nsnull
,
5711 nsnull
, /* do not add this internal plugin's channel
5712 on the load group otherwise this channel could be canceled
5713 form |nsWebShell::OnLinkClickSync| bug 166613 */
5719 // Set the owner of channel to the document principal...
5720 channel
->SetOwner(doc
->NodePrincipal());
5722 // And if it's a script allow it to execute against the
5723 // document's script context.
5724 nsCOMPtr
<nsIScriptChannel
> scriptChannel(do_QueryInterface(channel
));
5725 if (scriptChannel
) {
5726 scriptChannel
->SetExecutionPolicy(nsIScriptChannel::EXECUTE_NORMAL
);
5727 // Plug-ins seem to depend on javascript: URIs running synchronously
5728 scriptChannel
->SetExecuteAsync(PR_FALSE
);
5732 // deal with headers and post data
5733 nsCOMPtr
<nsIHttpChannel
> httpChannel(do_QueryInterface(channel
));
5737 nsCOMPtr
<nsIInputStream
> postDataStream
;
5738 rv
= NS_NewPluginPostDataStream(getter_AddRefs(postDataStream
), (const char*)aPostData
,
5739 aPostDataLen
, aIsFile
);
5741 if (!postDataStream
) {
5742 NS_RELEASE(aInstance
);
5743 return NS_ERROR_UNEXPECTED
;
5746 // XXX it's a bit of a hack to rewind the postdata stream
5747 // here but it has to be done in case the post data is
5748 // being reused multiple times.
5749 nsCOMPtr
<nsISeekableStream
>
5750 postDataSeekable(do_QueryInterface(postDataStream
));
5751 if (postDataSeekable
)
5752 postDataSeekable
->Seek(nsISeekableStream::NS_SEEK_SET
, 0);
5754 nsCOMPtr
<nsIUploadChannel
> uploadChannel(do_QueryInterface(httpChannel
));
5755 NS_ASSERTION(uploadChannel
, "http must support nsIUploadChannel");
5757 uploadChannel
->SetUploadStream(postDataStream
, EmptyCString(), -1);
5761 rv
= AddHeadersToChannel(aHeadersData
, aHeadersDataLen
, httpChannel
);
5763 rv
= channel
->AsyncOpen(listenerPeer
, nsnull
);
5765 NS_RELEASE(listenerPeer
);
5770 // Called by GetURL and PostURL
5772 nsPluginHostImpl::DoURLLoadSecurityCheck(nsIPluginInstance
*aInstance
,
5777 if (!aURL
|| *aURL
== '\0')
5780 // get the URL of the document that loaded the plugin
5781 nsCOMPtr
<nsIDocument
> doc
;
5782 nsCOMPtr
<nsIPluginInstancePeer
> peer
;
5783 rv
= aInstance
->GetPeer(getter_AddRefs(peer
));
5784 if (NS_FAILED(rv
) || !peer
)
5785 return NS_ERROR_FAILURE
;
5787 nsCOMPtr
<nsPIPluginInstancePeer
> privpeer(do_QueryInterface(peer
));
5788 nsCOMPtr
<nsIPluginInstanceOwner
> owner
;
5789 rv
= privpeer
->GetOwner(getter_AddRefs(owner
));
5791 return NS_ERROR_FAILURE
;
5793 rv
= owner
->GetDocument(getter_AddRefs(doc
));
5795 return NS_ERROR_FAILURE
;
5797 // Create an absolute URL for the target in case the target is relative
5798 nsCOMPtr
<nsIURI
> targetURL
;
5799 rv
= NS_NewURI(getter_AddRefs(targetURL
), aURL
, doc
->GetBaseURI());
5802 return NS_ERROR_FAILURE
;
5804 nsCOMPtr
<nsIScriptSecurityManager
> secMan(
5805 do_GetService(NS_SCRIPTSECURITYMANAGER_CONTRACTID
, &rv
));
5809 return secMan
->CheckLoadURIWithPrincipal(doc
->NodePrincipal(), targetURL
,
5810 nsIScriptSecurityManager::STANDARD
);
5815 nsPluginHostImpl::AddHeadersToChannel(const char *aHeadersData
,
5816 PRUint32 aHeadersDataLen
,
5817 nsIChannel
*aGenericChannel
)
5819 nsresult rv
= NS_OK
;
5821 nsCOMPtr
<nsIHttpChannel
> aChannel
= do_QueryInterface(aGenericChannel
);
5823 return NS_ERROR_NULL_POINTER
;
5826 // used during the manipulation of the String from the aHeadersData
5827 nsCAutoString headersString
;
5828 nsCAutoString oneHeader
;
5829 nsCAutoString headerName
;
5830 nsCAutoString headerValue
;
5834 // Turn the char * buffer into an nsString.
5835 headersString
= aHeadersData
;
5837 // Iterate over the nsString: for each "\r\n" delimited chunk,
5838 // add the value as a header to the nsIHTTPChannel
5840 crlf
= headersString
.Find("\r\n", PR_TRUE
);
5845 headersString
.Mid(oneHeader
, 0, crlf
);
5846 headersString
.Cut(0, crlf
+ 2);
5847 oneHeader
.StripWhitespace();
5848 colon
= oneHeader
.Find(":");
5850 rv
= NS_ERROR_NULL_POINTER
;
5853 oneHeader
.Left(headerName
, colon
);
5855 oneHeader
.Mid(headerValue
, colon
, oneHeader
.Length() - colon
);
5857 // FINALLY: we can set the header!
5859 rv
= aChannel
->SetRequestHeader(headerName
, headerValue
, PR_TRUE
);
5860 if (NS_FAILED(rv
)) {
5861 rv
= NS_ERROR_NULL_POINTER
;
5869 nsPluginHostImpl::StopPluginInstance(nsIPluginInstance
* aInstance
)
5871 if (PluginDestructionGuard::DelayDestroy(aInstance
)) {
5875 PLUGIN_LOG(PLUGIN_LOG_NORMAL
,
5876 ("nsPluginHostImpl::StopPluginInstance called instance=%p\n",aInstance
));
5878 nsActivePlugin
* plugin
= mActivePluginList
.find(aInstance
);
5881 plugin
->setStopped(PR_TRUE
); // be sure we set the "stop" bit
5883 // if the plugin does not want to be 'cached' just remove it
5884 PRBool doCache
= PR_TRUE
;
5885 aInstance
->GetValue(nsPluginInstanceVariable_DoCacheBool
, (void *) &doCache
);
5888 PRLibrary
* library
= nsnull
;
5889 if (plugin
->mPluginTag
)
5890 library
= plugin
->mPluginTag
->mLibrary
;
5892 mActivePluginList
.remove(plugin
);
5894 // if it is allowed to be cached simply stop it, but first we should check
5895 // if we haven't exceeded the maximum allowed number of cached instances
5897 // try to get the max cached plugins from a pref or use default
5899 nsresult rv
= NS_ERROR_FAILURE
;
5901 rv
= mPrefService
->GetIntPref(NS_PREF_MAX_NUM_CACHED_PLUGINS
, (int*)&max_num
);
5903 max_num
= DEFAULT_NUMBER_OF_STOPPED_PLUGINS
;
5905 if (mActivePluginList
.getStoppedCount() >= max_num
) {
5906 nsActivePlugin
* oldest
= mActivePluginList
.findOldestStopped();
5907 if (oldest
!= nsnull
)
5908 mActivePluginList
.remove(oldest
);
5915 nsresult
nsPluginHostImpl::NewEmbeddedPluginStreamListener(nsIURI
* aURL
,
5916 nsIPluginInstanceOwner
*aOwner
,
5917 nsIPluginInstance
* aInstance
,
5918 nsIStreamListener
** aListener
)
5923 nsRefPtr
<nsPluginStreamListenerPeer
> listener
=
5924 new nsPluginStreamListenerPeer();
5925 if (listener
== nsnull
)
5926 return NS_ERROR_OUT_OF_MEMORY
;
5930 // if we have an instance, everything has been set up
5931 // if we only have an owner, then we need to pass it in
5932 // so the listener can set up the instance later after
5933 // we've determined the mimetype of the stream
5934 if (aInstance
!= nsnull
)
5935 rv
= listener
->InitializeEmbedded(aURL
, aInstance
);
5936 else if (aOwner
!= nsnull
)
5937 rv
= listener
->InitializeEmbedded(aURL
, nsnull
, aOwner
, this);
5939 rv
= NS_ERROR_ILLEGAL_VALUE
;
5940 if (NS_SUCCEEDED(rv
))
5941 NS_ADDREF(*aListener
= listener
);
5946 // Called by InstantiateEmbeddedPlugin()
5947 nsresult
nsPluginHostImpl::NewEmbeddedPluginStream(nsIURI
* aURL
,
5948 nsIPluginInstanceOwner
*aOwner
,
5949 nsIPluginInstance
* aInstance
)
5951 nsCOMPtr
<nsIStreamListener
> listener
;
5952 nsresult rv
= NewEmbeddedPluginStreamListener(aURL
, aOwner
, aInstance
,
5953 getter_AddRefs(listener
));
5954 if (NS_SUCCEEDED(rv
)) {
5955 nsCOMPtr
<nsIDocument
> doc
;
5956 nsCOMPtr
<nsILoadGroup
> loadGroup
;
5958 rv
= aOwner
->GetDocument(getter_AddRefs(doc
));
5959 if (NS_SUCCEEDED(rv
) && doc
) {
5960 loadGroup
= doc
->GetDocumentLoadGroup();
5963 nsCOMPtr
<nsIChannel
> channel
;
5964 rv
= NS_NewChannel(getter_AddRefs(channel
), aURL
, nsnull
, loadGroup
, nsnull
);
5965 if (NS_SUCCEEDED(rv
)) {
5966 // if this is http channel, set referrer, some servers are configured
5967 // to reject requests without referrer set, see bug 157796
5968 nsCOMPtr
<nsIHttpChannel
> httpChannel(do_QueryInterface(channel
));
5969 if (httpChannel
&& doc
)
5970 httpChannel
->SetReferrer(doc
->GetDocumentURI());
5972 rv
= channel
->AsyncOpen(listener
, nsnull
);
5973 if (NS_SUCCEEDED(rv
))
5981 // Called by InstantiateFullPagePlugin()
5982 nsresult
nsPluginHostImpl::NewFullPagePluginStream(nsIStreamListener
*&aStreamListener
,
5983 nsIPluginInstance
*aInstance
)
5985 nsPluginStreamListenerPeer
*listener
= new nsPluginStreamListenerPeer();
5987 return NS_ERROR_OUT_OF_MEMORY
;
5991 rv
= listener
->InitializeFullPage(aInstance
);
5993 aStreamListener
= listener
;
5994 NS_ADDREF(listener
);
5996 // add peer to list of stream peers for this instance
5997 nsActivePlugin
* p
= mActivePluginList
.find(aInstance
);
5999 if (!p
->mStreams
&& (NS_FAILED(rv
= NS_NewISupportsArray(getter_AddRefs(p
->mStreams
)))))
6001 p
->mStreams
->AppendElement(aStreamListener
);
6008 // nsIFileUtilities interface
6009 NS_IMETHODIMP
nsPluginHostImpl::GetProgramPath(const char* *result
)
6012 NS_ENSURE_ARG_POINTER(result
);
6015 nsCOMPtr
<nsIProperties
> dirService(do_GetService(kDirectoryServiceContractID
, &rv
));
6018 nsCOMPtr
<nsILocalFile
> programDir
;
6019 rv
= dirService
->Get(NS_XPCOM_CURRENT_PROCESS_DIR
, NS_GET_IID(nsILocalFile
), getter_AddRefs(programDir
));
6024 rv
= programDir
->GetNativePath(temp
);
6025 *result
= ToNewCString(temp
);
6029 NS_IMETHODIMP
nsPluginHostImpl::GetTempDirPath(const char* *result
)
6032 NS_ENSURE_ARG_POINTER(result
);
6035 nsCOMPtr
<nsIProperties
> dirService(do_GetService(kDirectoryServiceContractID
, &rv
));
6038 nsCOMPtr
<nsILocalFile
> tempDir
;
6039 rv
= dirService
->Get(NS_OS_TEMP_DIR
, NS_GET_IID(nsILocalFile
), getter_AddRefs(tempDir
));
6044 rv
= tempDir
->GetNativePath(temp
);
6045 *result
= ToNewCString(temp
);
6049 NS_IMETHODIMP
nsPluginHostImpl::NewTempFileName(const char* prefix
, PRUint32 bufLen
, char* resultBuf
)
6051 return NS_ERROR_NOT_IMPLEMENTED
;
6054 // nsICookieStorage interface
6056 NS_IMETHODIMP
nsPluginHostImpl::GetCookie(const char* inCookieURL
, void* inOutCookieBuffer
, PRUint32
& inOutCookieSize
)
6058 nsresult rv
= NS_ERROR_NOT_IMPLEMENTED
;
6059 nsXPIDLCString cookieString
;
6060 PRUint32 cookieStringLen
= 0;
6061 nsCOMPtr
<nsIURI
> uriIn
;
6063 if (!inCookieURL
|| (0 >= inOutCookieSize
)) {
6064 return NS_ERROR_INVALID_ARG
;
6067 nsCOMPtr
<nsIIOService
> ioService(do_GetService(NS_IOSERVICE_CONTRACTID
, &rv
));
6069 if (NS_FAILED(rv
) || !ioService
)
6072 nsCOMPtr
<nsICookieService
> cookieService
=
6073 do_GetService(NS_COOKIESERVICE_CONTRACTID
, &rv
);
6075 if (NS_FAILED(rv
) || !cookieService
)
6076 return NS_ERROR_INVALID_ARG
;
6078 // make an nsURI from the argument url
6079 rv
= ioService
->NewURI(nsDependentCString(inCookieURL
), nsnull
, nsnull
, getter_AddRefs(uriIn
));
6083 rv
= cookieService
->GetCookieString(uriIn
, nsnull
, getter_Copies(cookieString
));
6085 if (NS_FAILED(rv
) || !cookieString
||
6086 (inOutCookieSize
<= (cookieStringLen
= PL_strlen(cookieString
.get())))) {
6087 return NS_ERROR_FAILURE
;
6090 PL_strcpy((char *) inOutCookieBuffer
, cookieString
.get());
6091 inOutCookieSize
= cookieStringLen
;
6097 NS_IMETHODIMP
nsPluginHostImpl::SetCookie(const char* inCookieURL
, const void* inCookieBuffer
, PRUint32 inCookieSize
)
6099 nsresult rv
= NS_ERROR_NOT_IMPLEMENTED
;
6100 nsCOMPtr
<nsIURI
> uriIn
;
6102 if (!inCookieURL
|| !inCookieBuffer
||
6103 (0 >= inCookieSize
)) {
6104 return NS_ERROR_INVALID_ARG
;
6107 nsCOMPtr
<nsIIOService
> ioService(do_GetService(NS_IOSERVICE_CONTRACTID
, &rv
));
6109 if (NS_FAILED(rv
) || !ioService
)
6112 nsCOMPtr
<nsICookieService
> cookieService
=
6113 do_GetService(NS_COOKIESERVICE_CONTRACTID
, &rv
);
6115 if (NS_FAILED(rv
) || !cookieService
)
6116 return NS_ERROR_FAILURE
;
6118 // make an nsURI from the argument url
6119 rv
= ioService
->NewURI(nsDependentCString(inCookieURL
), nsnull
, nsnull
, getter_AddRefs(uriIn
));
6121 return NS_ERROR_FAILURE
;
6123 nsCOMPtr
<nsIPrompt
> prompt
;
6124 GetPrompt(nsnull
, getter_AddRefs(prompt
));
6126 char * cookie
= (char *)inCookieBuffer
;
6127 char c
= cookie
[inCookieSize
];
6128 cookie
[inCookieSize
] = '\0';
6129 rv
= cookieService
->SetCookieString(uriIn
, prompt
, cookie
, nsnull
);
6130 cookie
[inCookieSize
] = c
;
6135 NS_IMETHODIMP
nsPluginHostImpl::Observe(nsISupports
*aSubject
,
6137 const PRUnichar
*someData
)
6139 if (!nsCRT::strcmp(NS_XPCOM_SHUTDOWN_OBSERVER_ID
, aTopic
)) {
6142 UnloadUnusedLibraries();
6145 if (!nsCRT::strcmp(NS_PREFBRANCH_PREFCHANGE_TOPIC_ID
, aTopic
)) {
6146 NS_ASSERTION(someData
&&
6147 nsDependentString(someData
).EqualsLiteral("security.enable_java"),
6149 nsCOMPtr
<nsIPrefBranch
> branch
= do_QueryInterface(aSubject
);
6150 NS_ASSERTION(branch
, "Not a pref branch?");
6152 if (NS_FAILED(branch
->GetBoolPref("security.enable_java", &enabled
)))
6155 if (enabled
!= mJavaEnabled
) {
6156 mJavaEnabled
= enabled
;
6157 // We want to keep the java PluginTag around so we'll know that it's
6158 // actually disabled, not just not present. So just manually mark it as
6159 // disabled so at least FindPluginForType/Extension doesn't return
6161 for (nsPluginTag
* cur
= mPlugins
; cur
; cur
= cur
->mNext
) {
6162 if (cur
->mIsJavaPlugin
)
6163 cur
->SetDisabled(!mJavaEnabled
);
6171 nsPluginHostImpl::HandleBadPlugin(PRLibrary
* aLibrary
, nsIPluginInstance
*aInstance
)
6173 // the |aLibrary| parameter is not needed anymore, after we added |aInstance| which
6174 // can also be used to look up the plugin name, but we cannot get rid of it because
6175 // the |nsIPluginHost| interface is deprecated which in fact means 'frozen'
6177 nsresult rv
= NS_OK
;
6179 NS_ASSERTION(PR_FALSE
, "Plugin performed illegal operation");
6181 if (mDontShowBadPluginMessage
)
6184 nsCOMPtr
<nsIPluginInstanceOwner
> owner
;
6187 nsCOMPtr
<nsIPluginInstancePeer
> peer
;
6188 rv
= aInstance
->GetPeer(getter_AddRefs(peer
));
6189 if (NS_SUCCEEDED(rv
) && peer
) {
6190 nsCOMPtr
<nsPIPluginInstancePeer
> privpeer(do_QueryInterface(peer
));
6191 privpeer
->GetOwner(getter_AddRefs(owner
));
6195 nsCOMPtr
<nsIPrompt
> prompt
;
6196 GetPrompt(owner
, getter_AddRefs(prompt
));
6198 nsCOMPtr
<nsIStringBundleService
> strings(do_GetService(NS_STRINGBUNDLE_CONTRACTID
, &rv
));
6202 nsCOMPtr
<nsIStringBundle
> bundle
;
6203 rv
= strings
->CreateBundle(BRAND_PROPERTIES_URL
, getter_AddRefs(bundle
));
6207 nsXPIDLString brandName
;
6208 if (NS_FAILED(rv
= bundle
->GetStringFromName(NS_LITERAL_STRING("brandShortName").get(),
6209 getter_Copies(brandName
))))
6212 rv
= strings
->CreateBundle(PLUGIN_PROPERTIES_URL
, getter_AddRefs(bundle
));
6216 nsXPIDLString title
, message
, checkboxMessage
;
6217 if (NS_FAILED(rv
= bundle
->GetStringFromName(NS_LITERAL_STRING("BadPluginTitle").get(),
6218 getter_Copies(title
))))
6221 const PRUnichar
*formatStrings
[] = { brandName
.get() };
6222 if (NS_FAILED(rv
= bundle
->FormatStringFromName(NS_LITERAL_STRING("BadPluginMessage").get(),
6223 formatStrings
, 1, getter_Copies(message
))))
6226 if (NS_FAILED(rv
= bundle
->GetStringFromName(NS_LITERAL_STRING("BadPluginCheckboxMessage").get(),
6227 getter_Copies(checkboxMessage
))))
6230 // add plugin name to the message
6231 nsCString pluginname
;
6232 nsActivePlugin
* p
= mActivePluginList
.find(aInstance
);
6234 nsPluginTag
* tag
= p
->mPluginTag
;
6236 if (!tag
->mName
.IsEmpty())
6237 pluginname
= tag
->mName
;
6239 pluginname
= tag
->mFileName
;
6243 NS_ConvertUTF8toUTF16
msg(pluginname
);
6244 msg
.AppendLiteral("\n\n");
6245 msg
.Append(message
);
6247 PRInt32 buttonPressed
;
6248 PRBool checkboxState
= PR_FALSE
;
6249 rv
= prompt
->ConfirmEx(title
, msg
.get(),
6250 nsIPrompt::BUTTON_TITLE_OK
* nsIPrompt::BUTTON_POS_0
,
6251 nsnull
, nsnull
, nsnull
,
6252 checkboxMessage
, &checkboxState
, &buttonPressed
);
6255 if (NS_SUCCEEDED(rv
) && checkboxState
)
6256 mDontShowBadPluginMessage
= PR_TRUE
;
6262 // nsPIPluginHost interface
6265 nsPluginHostImpl::SetIsScriptableInstance(nsIPluginInstance
* aPluginInstance
, PRBool aScriptable
)
6267 nsActivePlugin
* p
= mActivePluginList
.find(aPluginInstance
);
6269 return NS_ERROR_FAILURE
;
6271 p
->mXPConnected
= aScriptable
;
6273 p
->mPluginTag
->mXPConnected
= aScriptable
;
6279 nsPluginHostImpl::ParsePostBufferToFixHeaders(
6280 const char *inPostData
, PRUint32 inPostDataLen
,
6281 char **outPostData
, PRUint32
*outPostDataLen
)
6283 if (!inPostData
|| !outPostData
|| !outPostDataLen
)
6284 return NS_ERROR_NULL_POINTER
;
6287 *outPostDataLen
= 0;
6289 const char CR
= '\r';
6290 const char LF
= '\n';
6291 const char CRLFCRLF
[] = {CR
,LF
,CR
,LF
,'\0'}; // C string"\r\n\r\n"
6292 const char ContentLenHeader
[] = "Content-length";
6294 nsAutoVoidArray singleLF
;
6295 const char *pSCntlh
= 0;// pointer to start of ContentLenHeader in inPostData
6296 const char *pSod
= 0; // pointer to start of data in inPostData
6297 const char *pEoh
= 0; // pointer to end of headers in inPostData
6298 const char *pEod
= inPostData
+ inPostDataLen
; // pointer to end of inPostData
6299 if (*inPostData
== LF
) {
6300 // from 4.x spec http://developer.netscape.com/docs/manuals/communicator/plugin/pgfn2.htm#1007754
6301 // If no custom headers are required, simply add a blank
6302 // line ('\n') to the beginning of the file or buffer.
6303 // so *inPostData == '\n' is valid
6304 pSod
= inPostData
+ 1;
6306 const char *s
= inPostData
; //tmp pointer to sourse inPostData
6309 (*s
== 'C' || *s
== 'c') &&
6310 (s
+ sizeof(ContentLenHeader
) - 1 < pEod
) &&
6311 (!PL_strncasecmp(s
, ContentLenHeader
, sizeof(ContentLenHeader
) - 1)))
6313 // lets assume this is ContentLenHeader for now
6314 const char *p
= pSCntlh
= s
;
6315 p
+= sizeof(ContentLenHeader
) - 1;
6316 // search for first CR or LF == end of ContentLenHeader
6317 for (; p
< pEod
; p
++) {
6318 if (*p
== CR
|| *p
== LF
) {
6320 // one more check; if previous char is a digit
6321 // most likely pSCntlh points to the start of ContentLenHeader
6322 if (*(p
-1) >= '0' && *(p
-1) <= '9') {
6328 if (pSCntlh
== s
) { // curret ptr is the same
6329 pSCntlh
= 0; // that was not ContentLenHeader
6330 break; // there is nothing to parse, break *WHILE LOOP* here
6335 if (pSCntlh
&& // only if ContentLenHeader is found we are looking for end of headers
6336 ((s
+ sizeof(CRLFCRLF
)-1) <= pEod
) &&
6337 !memcmp(s
, CRLFCRLF
, sizeof(CRLFCRLF
)-1))
6339 s
+= sizeof(CRLFCRLF
)-1;
6340 pEoh
= pSod
= s
; // data stars here
6343 } else if (*s
== LF
) {
6345 singleLF
.AppendElement((void*)s
);
6347 if (pSCntlh
&& (s
+1 < pEod
) && (*(s
+1) == LF
)) {
6349 singleLF
.AppendElement((void*)s
);
6351 pEoh
= pSod
= s
; // data stars here
6359 // deal with output buffer
6360 if (!pSod
) { // lets assume whole buffer is a data
6364 PRUint32 newBufferLen
= 0;
6365 PRUint32 dataLen
= pEod
- pSod
;
6366 PRUint32 headersLen
= pEoh
? pSod
- inPostData
: 0;
6368 char *p
; // tmp ptr into new output buf
6369 if (headersLen
) { // we got a headers
6370 // this function does not make any assumption on correctness
6371 // of ContentLenHeader value in this case.
6373 newBufferLen
= dataLen
+ headersLen
;
6374 // in case there were single LFs in headers
6375 // reserve an extra space for CR will be added before each single LF
6376 int cntSingleLF
= singleLF
.Count();
6377 newBufferLen
+= cntSingleLF
;
6379 if (!(*outPostData
= p
= (char*)nsMemory::Alloc(newBufferLen
)))
6380 return NS_ERROR_OUT_OF_MEMORY
;
6382 // deal with single LF
6383 const char *s
= inPostData
;
6385 for (int i
=0; i
<cntSingleLF
; i
++) {
6386 const char *plf
= (const char*) singleLF
.ElementAt(i
); // ptr to single LF in headers
6387 int n
= plf
- s
; // bytes to copy
6388 if (n
) { // for '\n\n' there is nothing to memcpy
6397 // are we done with headers?
6398 headersLen
= pEoh
- s
;
6399 if (headersLen
) { // not yet
6400 memcpy(p
, s
, headersLen
); // copy the rest
6403 } else if (dataLen
) { // no ContentLenHeader is found but there is a data
6404 // make new output buffer big enough
6405 // to keep ContentLenHeader+value followed by data
6406 PRUint32 l
= sizeof(ContentLenHeader
) + sizeof(CRLFCRLF
) + 32;
6407 newBufferLen
= dataLen
+ l
;
6408 if (!(*outPostData
= p
= (char*)nsMemory::Alloc(newBufferLen
)))
6409 return NS_ERROR_OUT_OF_MEMORY
;
6410 headersLen
= PR_snprintf(p
, l
,"%s: %ld%s", ContentLenHeader
, dataLen
, CRLFCRLF
);
6411 if (headersLen
== l
) { // if PR_snprintf has ate all extra space consider this as an error
6414 return NS_ERROR_FAILURE
;
6417 newBufferLen
= headersLen
+ dataLen
;
6419 // at this point we've done with headers.
6420 // there is a possibility that input buffer has only headers info in it
6421 // which already parsed and copied into output buffer.
6424 memcpy(p
, pSod
, dataLen
);
6427 *outPostDataLen
= newBufferLen
;
6433 nsPluginHostImpl::CreateTmpFileToPost(const char *postDataURL
, char **pTmpFileName
)
6438 nsCAutoString filename
;
6440 // stat file == get size & convert file:///c:/ to c: if needed
6441 nsCOMPtr
<nsIFile
> inFile
;
6442 rv
= NS_GetFileFromURLSpec(nsDependentCString(postDataURL
),
6443 getter_AddRefs(inFile
));
6444 if (NS_FAILED(rv
)) {
6445 nsCOMPtr
<nsILocalFile
> localFile
;
6446 rv
= NS_NewNativeLocalFile(nsDependentCString(postDataURL
), PR_FALSE
,
6447 getter_AddRefs(localFile
));
6448 if (NS_FAILED(rv
)) return rv
;
6451 rv
= inFile
->GetFileSize(&fileSize
);
6452 if (NS_FAILED(rv
)) return rv
;
6453 rv
= inFile
->GetNativePath(filename
);
6454 if (NS_FAILED(rv
)) return rv
;
6456 if (!LL_IS_ZERO(fileSize
)) {
6457 nsCOMPtr
<nsIInputStream
> inStream
;
6458 rv
= NS_NewLocalFileInputStream(getter_AddRefs(inStream
), inFile
);
6459 if (NS_FAILED(rv
)) return rv
;
6461 // Create a temporary file to write the http Content-length:
6462 // %ld\r\n\" header and "\r\n" == end of headers for post data to
6464 nsCOMPtr
<nsIFile
> tempFile
;
6465 rv
= GetPluginTempDir(getter_AddRefs(tempFile
));
6469 nsCAutoString inFileName
;
6470 inFile
->GetNativeLeafName(inFileName
);
6471 // XXX hack around bug 70083
6472 inFileName
.Insert(NS_LITERAL_CSTRING("post-"), 0);
6473 rv
= tempFile
->AppendNative(inFileName
);
6478 // make it unique, and mode == 0600, not world-readable
6479 rv
= tempFile
->CreateUnique(nsIFile::NORMAL_FILE_TYPE
, 0600);
6483 nsCOMPtr
<nsIOutputStream
> outStream
;
6484 if (NS_SUCCEEDED(rv
)) {
6485 rv
= NS_NewLocalFileOutputStream(getter_AddRefs(outStream
),
6487 (PR_WRONLY
| PR_CREATE_FILE
| PR_TRUNCATE
),
6488 0600); // 600 so others can't read our form data
6490 NS_ASSERTION(NS_SUCCEEDED(rv
), "Post data file couldn't be created!");
6496 PRBool firstRead
= PR_TRUE
;
6498 // Read() mallocs if buffer is null
6499 rv
= inStream
->Read(buf
, 1024, &br
);
6500 if (NS_FAILED(rv
) || (PRInt32
)br
<= 0)
6503 // according to the 4.x spec
6504 // http://developer.netscape.com/docs/manuals/communicator/plugin/pgfn2.htm#1007707
6505 //"For protocols in which the headers must be distinguished from the body,
6506 // such as HTTP, the buffer or file should contain the headers, followed by
6507 // a blank line, then the body. If no custom headers are required, simply
6508 // add a blank line ('\n') to the beginning of the file or buffer.
6511 // assuming first 1K (or what we got) has all headers in,
6512 // lets parse it through nsPluginHostImpl::ParsePostBufferToFixHeaders()
6513 ParsePostBufferToFixHeaders((const char *)buf
, br
, &parsedBuf
, &bw
);
6514 rv
= outStream
->Write(parsedBuf
, bw
, &br
);
6515 nsMemory::Free(parsedBuf
);
6516 if (NS_FAILED(rv
) || (bw
!= br
))
6519 firstRead
= PR_FALSE
;
6523 rv
= outStream
->Write(buf
, bw
, &br
);
6524 if (NS_FAILED(rv
) || (bw
!= br
))
6530 if (NS_SUCCEEDED(rv
)) {
6532 if (NS_SUCCEEDED(tempFile
->GetNativePath(path
)))
6533 *pTmpFileName
= ToNewCString(path
);
6540 nsPluginHostImpl::NewPluginNativeWindow(nsPluginNativeWindow
** aPluginNativeWindow
)
6542 return PLUG_NewPluginNativeWindow(aPluginNativeWindow
);
6546 nsPluginHostImpl::DeletePluginNativeWindow(nsPluginNativeWindow
* aPluginNativeWindow
)
6548 return PLUG_DeletePluginNativeWindow(aPluginNativeWindow
);
6552 nsPluginHostImpl::InstantiateDummyJavaPlugin(nsIPluginInstanceOwner
*aOwner
)
6554 // Pass PR_FALSE as the second arg, we want the answer to be the
6555 // same here whether the Java plugin is enabled or not.
6556 nsPluginTag
*plugin
= FindPluginForType("application/x-java-vm", PR_FALSE
);
6558 if (!plugin
|| !plugin
->mIsNPRuntimeEnabledJavaPlugin
) {
6559 // No NPRuntime enabled Java plugin found, no point in
6560 // instantiating a dummy plugin then.
6565 nsresult rv
= SetUpPluginInstance("application/x-java-vm", nsnull
, aOwner
);
6566 NS_ENSURE_SUCCESS(rv
, rv
);
6568 nsCOMPtr
<nsIPluginInstance
> instance
;
6569 aOwner
->GetInstance(*getter_AddRefs(instance
));
6571 nsCOMPtr
<nsIPluginInstanceInternal
> plugin_internal
=
6572 do_QueryInterface(instance
);
6574 if (!plugin_internal
) {
6578 plugin_internal
->DefineJavaProperties();
6584 nsPluginHostImpl::GetPluginName(nsIPluginInstance
*aPluginInstance
,
6585 const char** aPluginName
)
6587 *aPluginName
= GetPluginName(aPluginInstance
);
6591 // end of nsPIPluginHost implementation
6594 nsPluginHostImpl::ScanForRealInComponentsFolder(nsIComponentManager
* aCompManager
)
6596 nsresult rv
= NS_OK
;
6600 // First, lets check if we already have Real. No point in doing this if it's installed correctly
6601 if (NS_SUCCEEDED(IsPluginEnabledForType("audio/x-pn-realaudio-plugin")))
6604 // Next, maybe the pref wants to override
6605 PRBool bSkipRealPlayerHack
= PR_FALSE
;
6606 if (!mPrefService
||
6607 (NS_SUCCEEDED(mPrefService
->GetBoolPref("plugin.skip_real_player_hack", &bSkipRealPlayerHack
)) &&
6608 bSkipRealPlayerHack
))
6611 // now we need the XPCOM components folder
6612 nsCOMPtr
<nsIFile
> RealPlugin
;
6613 if (NS_FAILED(NS_GetSpecialDirectory(NS_XPCOM_COMPONENT_DIR
, getter_AddRefs(RealPlugin
))) || !RealPlugin
)
6616 // make sure the file is actually there
6617 RealPlugin
->AppendNative(nsDependentCString("nppl3260.dll"));
6619 nsCAutoString filePath
;
6620 RealPlugin
->Exists(&exists
);
6621 if (!exists
|| NS_FAILED(RealPlugin
->GetNativePath(filePath
)))
6624 // now make sure it's a plugin
6625 nsCOMPtr
<nsILocalFile
> localfile
;
6626 NS_NewNativeLocalFile(filePath
,
6628 getter_AddRefs(localfile
));
6630 if (!nsPluginsDir::IsPluginFile(localfile
))
6633 // try to get the mime info and descriptions out of the plugin
6634 nsPluginFile
pluginFile(localfile
);
6636 memset(&info
, 0, sizeof(info
));
6637 if (NS_FAILED(pluginFile
.GetPluginInfo(info
)))
6640 nsCOMPtr
<nsIComponentManager
> compManager
;
6641 NS_GetComponentManager(getter_AddRefs(compManager
));
6643 // finally, create our "plugin tag" and add it to the list
6644 if (info
.fMimeTypeArray
) {
6645 nsRefPtr
<nsPluginTag
> pluginTag
= new nsPluginTag(&info
);
6647 pluginTag
->SetHost(this);
6648 pluginTag
->mNext
= mPlugins
;
6649 mPlugins
= pluginTag
;
6651 // last thing we need is to register this plugin with layout so it can be used in full-page mode
6652 if (pluginTag
->IsEnabled())
6653 pluginTag
->RegisterWithCategoryManager(mOverrideInternalTypes
);
6657 // free allocated strings in GetPluginInfo
6658 pluginFile
.FreePluginInfo(info
);
6665 nsresult
nsPluginHostImpl::AddUnusedLibrary(PRLibrary
* aLibrary
)
6667 if (mUnusedLibraries
.IndexOf(aLibrary
) == -1) // don't add duplicates
6668 mUnusedLibraries
.AppendElement(aLibrary
);
6673 nsresult
nsPluginHostImpl::AddPrefObserver()
6675 nsCOMPtr
<nsIPrefBranch2
> prefBranch(do_QueryInterface(mPrefService
));
6676 NS_ENSURE_TRUE(prefBranch
, NS_ERROR_UNEXPECTED
);
6678 return prefBranch
->AddObserver("security.enable_java", this, PR_TRUE
);
6681 nsresult
nsPluginStreamListenerPeer::ServeStreamAsFile(nsIRequest
*request
,
6682 nsISupports
* aContext
)
6685 return NS_ERROR_FAILURE
;
6687 // mInstance->Stop calls mPStreamListener->CleanUpStream(), so stream will be properly clean up
6690 nsCOMPtr
<nsIPluginInstancePeer
> peer
;
6691 mInstance
->GetPeer(getter_AddRefs(peer
));
6693 nsCOMPtr
<nsPIPluginInstancePeer
> privpeer(do_QueryInterface(peer
));
6694 nsCOMPtr
<nsIPluginInstanceOwner
> owner
;
6695 privpeer
->GetOwner(getter_AddRefs(owner
));
6697 nsPluginWindow
*window
= nsnull
;
6698 owner
->GetWindow(window
);
6699 #if defined (MOZ_WIDGET_GTK2)
6700 // Should call GetPluginPort() here.
6701 // This part is copied from nsPluginInstanceOwner::GetPluginPort().
6702 nsCOMPtr
<nsIWidget
> widget
;
6703 ((nsPluginNativeWindow
*)window
)->GetPluginWidget(getter_AddRefs(widget
));
6705 window
->window
= (nsPluginPort
*) widget
->GetNativeData(NS_NATIVE_PLUGIN_PORT
);
6710 nsCOMPtr
<nsIPluginInstance
> inst
= mInstance
;
6711 ((nsPluginNativeWindow
*)window
)->CallSetWindow(inst
);
6716 mPluginStreamInfo
->SetSeekable(0);
6717 mPStreamListener
->OnStartBinding(mPluginStreamInfo
);
6718 mPluginStreamInfo
->SetStreamOffset(0);
6720 // force the plugin use stream as file
6721 mStreamType
= nsPluginStreamType_AsFile
;
6723 // then check it out if browser cache is not available
6724 nsCOMPtr
<nsICachingChannel
> cacheChannel
= do_QueryInterface(request
);
6725 if (!(cacheChannel
&& (NS_SUCCEEDED(cacheChannel
->SetCacheAsFile(PR_TRUE
))))) {
6726 nsCOMPtr
<nsIChannel
> channel
= do_QueryInterface(request
);
6728 SetupPluginCacheFile(channel
);
6732 // unset mPendingRequests
6733 mPendingRequests
= 0;
6738 NS_IMPL_ISUPPORTS1(nsPluginByteRangeStreamListener
, nsIStreamListener
)
6739 nsPluginByteRangeStreamListener::nsPluginByteRangeStreamListener(nsIWeakReference
* aWeakPtr
)
6741 mWeakPtrPluginStreamListenerPeer
= aWeakPtr
;
6742 mRemoveMagicNumber
= PR_FALSE
;
6745 nsPluginByteRangeStreamListener::~nsPluginByteRangeStreamListener()
6747 mStreamConverter
= 0;
6748 mWeakPtrPluginStreamListenerPeer
= 0;
6752 nsPluginByteRangeStreamListener::OnStartRequest(nsIRequest
*request
, nsISupports
*ctxt
)
6756 nsCOMPtr
<nsIStreamListener
> finalStreamListener
= do_QueryReferent(mWeakPtrPluginStreamListenerPeer
);
6757 if (!finalStreamListener
)
6758 return NS_ERROR_FAILURE
;
6760 nsCOMPtr
<nsIStreamConverterService
> serv
= do_GetService(NS_STREAMCONVERTERSERVICE_CONTRACTID
, &rv
);
6761 if (NS_SUCCEEDED(rv
)) {
6762 rv
= serv
->AsyncConvertData(MULTIPART_BYTERANGES
,
6764 finalStreamListener
,
6766 getter_AddRefs(mStreamConverter
));
6767 if (NS_SUCCEEDED(rv
)) {
6768 rv
= mStreamConverter
->OnStartRequest(request
, ctxt
);
6769 if (NS_SUCCEEDED(rv
))
6773 mStreamConverter
= 0;
6775 nsCOMPtr
<nsIHttpChannel
> httpChannel(do_QueryInterface(request
));
6777 return NS_ERROR_FAILURE
;
6780 PRUint32 responseCode
= 0;
6781 rv
= httpChannel
->GetResponseStatus(&responseCode
);
6782 if (NS_FAILED(rv
)) {
6783 return NS_ERROR_FAILURE
;
6786 // get nsPluginStreamListenerPeer* ptr from finalStreamListener
6787 nsPluginStreamListenerPeer
*pslp
=
6788 reinterpret_cast<nsPluginStreamListenerPeer
*>(finalStreamListener
.get());
6790 if (responseCode
!= 200) {
6791 PRBool bWantsAllNetworkStreams
= PR_FALSE
;
6792 pslp
->GetPluginInstance()->
6793 GetValue(nsPluginInstanceVariable_WantsAllNetworkStreams
,
6794 (void *)&bWantsAllNetworkStreams
);
6795 if (!bWantsAllNetworkStreams
){
6796 return NS_ERROR_FAILURE
;
6800 // if server cannot continue with byte range (206 status) and sending us whole object (200 status)
6801 // reset this seekable stream & try serve it to plugin instance as a file
6802 mStreamConverter
= finalStreamListener
;
6803 mRemoveMagicNumber
= PR_TRUE
;
6805 rv
= pslp
->ServeStreamAsFile(request
, ctxt
);
6810 nsPluginByteRangeStreamListener::OnStopRequest(nsIRequest
*request
, nsISupports
*ctxt
,
6813 if (!mStreamConverter
)
6814 return NS_ERROR_FAILURE
;
6816 nsCOMPtr
<nsIStreamListener
> finalStreamListener
= do_QueryReferent(mWeakPtrPluginStreamListenerPeer
);
6817 if (!finalStreamListener
)
6818 return NS_ERROR_FAILURE
;
6820 if (mRemoveMagicNumber
) {
6821 // remove magic number from container
6822 nsCOMPtr
<nsISupportsPRUint32
> container
= do_QueryInterface(ctxt
);
6824 PRUint32 magicNumber
= 0;
6825 container
->GetData(&magicNumber
);
6826 if (magicNumber
== MAGIC_REQUEST_CONTEXT
) {
6827 // to allow properly finish nsPluginStreamListenerPeer->OnStopRequest()
6828 // set it to something that is not the magic number.
6829 container
->SetData(0);
6832 NS_WARNING("Bad state of nsPluginByteRangeStreamListener");
6836 return mStreamConverter
->OnStopRequest(request
, ctxt
, status
);
6840 nsPluginByteRangeStreamListener::OnDataAvailable(nsIRequest
*request
, nsISupports
*ctxt
,
6841 nsIInputStream
*inStr
, PRUint32 sourceOffset
, PRUint32 count
)
6843 if (!mStreamConverter
)
6844 return NS_ERROR_FAILURE
;
6846 nsCOMPtr
<nsIStreamListener
> finalStreamListener
= do_QueryReferent(mWeakPtrPluginStreamListenerPeer
);
6847 if (!finalStreamListener
)
6848 return NS_ERROR_FAILURE
;
6850 return mStreamConverter
->OnDataAvailable(request
, ctxt
, inStr
, sourceOffset
, count
);
6854 nsPluginStreamInfo::UseExistingPluginCacheFile(nsPluginStreamInfo
* psi
)
6857 NS_ENSURE_ARG_POINTER(psi
);
6859 if ( psi
->mLength
== mLength
&&
6860 psi
->mModified
== mModified
&&
6862 !PL_strcmp(psi
->mURL
, mURL
))
6870 nsPluginStreamInfo::SetStreamComplete(const PRBool complete
)
6872 mStreamComplete
= complete
;
6875 // We're done, release the request.
6880 // Runnable that does an async destroy of a plugin.
6882 class nsPluginDestroyRunnable
: public nsRunnable
,
6886 nsPluginDestroyRunnable(nsIPluginInstance
*aInstance
)
6887 : mInstance(aInstance
)
6889 PR_INIT_CLIST(this);
6890 PR_APPEND_LINK(this, &sRunnableListHead
);
6893 virtual ~nsPluginDestroyRunnable()
6895 PR_REMOVE_LINK(this);
6900 nsCOMPtr
<nsIPluginInstance
> instance
;
6902 // Null out mInstance to make sure this code in another runnable
6903 // will do the right thing even if someone was holding on to this
6904 // runnable longer than we expect.
6905 instance
.swap(mInstance
);
6907 if (PluginDestructionGuard::DelayDestroy(instance
)) {
6908 // It's still not safe to destroy the plugin, it's now up to the
6909 // outermost guard on the stack to take care of the destruction.
6913 nsPluginDestroyRunnable
*r
=
6914 static_cast<nsPluginDestroyRunnable
*>(PR_NEXT_LINK(&sRunnableListHead
));
6916 while (r
!= &sRunnableListHead
) {
6917 if (r
!= this && r
->mInstance
== instance
) {
6918 // There's another runnable scheduled to tear down
6919 // instance. Let it do the job.
6922 r
= static_cast<nsPluginDestroyRunnable
*>(PR_NEXT_LINK(r
));
6925 PLUGIN_LOG(PLUGIN_LOG_NORMAL
,
6926 ("Doing delayed destroy of instance %p\n", instance
.get()));
6930 nsRefPtr
<nsPluginHostImpl
> host
= nsPluginHostImpl::GetInst();
6933 host
->StopPluginInstance(instance
);
6935 PLUGIN_LOG(PLUGIN_LOG_NORMAL
,
6936 ("Done with delayed destroy of instance %p\n", instance
.get()));
6942 nsCOMPtr
<nsIPluginInstance
> mInstance
;
6944 static PRCList sRunnableListHead
;
6947 PRCList
nsPluginDestroyRunnable::sRunnableListHead
=
6948 PR_INIT_STATIC_CLIST(&nsPluginDestroyRunnable::sRunnableListHead
);
6950 PRCList
PluginDestructionGuard::sListHead
=
6951 PR_INIT_STATIC_CLIST(&PluginDestructionGuard::sListHead
);
6953 PluginDestructionGuard::~PluginDestructionGuard()
6955 NS_ASSERTION(NS_IsMainThread(), "Should be on the main thread");
6957 PR_REMOVE_LINK(this);
6959 if (mDelayedDestroy
) {
6960 // We've attempted to destroy the plugin instance we're holding on
6961 // to while we were guarding it. Do the actual destroy now, off of
6963 nsRefPtr
<nsPluginDestroyRunnable
> evt
=
6964 new nsPluginDestroyRunnable(mInstance
);
6966 NS_DispatchToMainThread(evt
);
6972 PluginDestructionGuard::DelayDestroy(nsIPluginInstance
*aInstance
)
6974 NS_ASSERTION(NS_IsMainThread(), "Should be on the main thread");
6975 NS_ASSERTION(aInstance
, "Uh, I need an instance!");
6977 // Find the first guard on the stack and make it do a delayed
6978 // destroy upon destruction.
6980 PluginDestructionGuard
*g
=
6981 static_cast<PluginDestructionGuard
*>(PR_LIST_HEAD(&sListHead
));
6983 while (g
!= &sListHead
) {
6984 if (g
->mInstance
== aInstance
) {
6985 g
->mDelayedDestroy
= PR_TRUE
;
6989 g
= static_cast<PluginDestructionGuard
*>(PR_NEXT_LINK(g
));