gecko-dev/modules/plugin/base/src/nsPluginHostImpl.cpp

5824 lines
170 KiB
C++
Raw Normal View History

/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* ***** BEGIN LICENSE BLOCK *****
* Version: NPL 1.1/GPL 2.0/LGPL 2.1
*
* The contents of this file are subject to the Netscape Public License
* Version 1.1 (the "License"); you may not use this file except in
* compliance with the License. You may obtain a copy of the License at
* http://www.mozilla.org/NPL/
*
* Software distributed under the License is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
* for the specific language governing rights and limitations under the
* License.
*
* The Original Code is mozilla.org code.
*
* The Initial Developer of the Original Code is
* Netscape Communications Corporation.
* Portions created by the Initial Developer are Copyright (C) 1998
* the Initial Developer. All Rights Reserved.
*
* Contributor(s):
* Sean Echevarria <sean@beatnik.com>
* H<EFBFBD>kan Waara <hwaara@chello.se>
*
* Alternatively, the contents of this file may be used under the terms of
* either the GNU General Public License Version 2 or later (the "GPL"), or
* the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
* in which case the provisions of the GPL or the LGPL are applicable instead
* of those above. If you wish to allow use of your version of this file only
* under the terms of either the GPL or the LGPL, and not to allow others to
* use your version of this file under the terms of the NPL, indicate your
* decision by deleting the provisions above and replace them with the notice
* and other provisions required by the GPL or the LGPL. If you do not delete
* the provisions above, a recipient may use your version of this file under
* the terms of any one of the NPL, the GPL or the LGPL.
*
* ***** END LICENSE BLOCK ***** */
/* nsPluginHostImpl.cpp - bulk of code for managing plugins */
/* XdpX Really really force prlogging*/
#define FORCE_PR_LOG /* Allow logging in the release build */
#define PR_LOGGING 1
#include "prlog.h"
#include "nscore.h"
#include "nsPluginHostImpl.h"
#include "nsPluginProxyImpl.h"
#include <stdio.h>
#include "prio.h"
#include "prmem.h"
#include "ns4xPlugin.h"
1998-08-01 05:46:47 +00:00
#include "nsPluginInstancePeer.h"
#include "nsIPlugin.h"
#include "nsIJVMPlugin.h"
#include "nsIJVMManager.h"
1999-01-25 08:05:00 +00:00
#include "nsIPluginStreamListener.h"
a=brendan,av r=av bug=50811 This bug fix was suggested by Stanley Ho <stanley.ho@eng.sun.com>. Stanley proposed we overload the meaning of the nsIPluginStreamListener argument to nsIPluginManager::{GetURL,PostURL}() so that it also may implement an interface for reading headers. Thus, the browser could QI the plugin's nsIPluginStreamListener instance to this headers reading interface and send the plugin the headers from the response. I have implemented Stanley's above proposal. I have defined a new interface, nsIHTTPHeaderListener.idl with one method: /** * Called for each HTTP Response header. * NOTE: You must copy the values of the params. */ void newResponseHeader(in string headerName, in string headerValue); To affect this fix, I have added a new private method nsPluginStreamListenerPeer:: ReadHeadersFromChannelAndPostToListener(nsIHTTPChannel *httpChannel, nsIHTTPHeaderListener *listener) Then, modified nsPluginStreamListenerPeer::OnDataAvailable() to call this method BEFORE reading the content data. However, this fix makes two important assumptions I would like to check out: * Assumption * By the time nsPluginStreamListenerPeer::OnDataAvailable() gets * called, all the headers have been read. * Assumption: * The return value from nsIHTTPHeader->{GetFieldName,GetValue}() * must be freed. The following files are included in this fix: A modules/plugin/public/nsIHTTPHeaderListener.idl A modules/plugin/public/makefile.win A modules/plugin/public/Makefile.in M modules/plugin/nglsrc/nsPluginHostImpl.cpp
2000-09-13 07:09:38 +00:00
#include "nsIHTTPHeaderListener.h"
#include "nsIObserverService.h"
#include "nsIHttpProtocolHandler.h"
#include "nsIHttpChannel.h"
#include "nsIUploadChannel.h"
#include "nsIByteRangeRequest.h"
#include "nsIStreamListener.h"
#include "nsIInputStream.h"
#include "nsIOutputStream.h"
#include "nsIPluginStreamListener2.h"
#include "nsIURL.h"
#include "nsXPIDLString.h"
#include "nsReadableUtils.h"
#include "nsIPref.h"
#include "nsIProtocolProxyService.h"
#include "nsIStreamConverterService.h"
#include "nsIFile.h"
#include "nsIInputStream.h"
#include "nsIIOService.h"
#include "nsIURL.h"
1999-06-25 01:41:26 +00:00
#include "nsIChannel.h"
#include "nsIFileStream.h" // for nsISeekableStream
#include "nsNetUtil.h"
#include "nsIProgressEventSink.h"
#include "nsIDocument.h"
#include "nsIScriptablePlugin.h"
#include "nsICachingChannel.h"
#include "nsHashtable.h"
#include "nsIProxyInfo.h"
#include "nsObsoleteModuleLoading.h"
#include "nsPluginLogging.h"
#include "nsDirectoryServiceDefs.h"
#include "nsAppDirectoryServiceDefs.h"
// Friggin' X11 has to "#define None". Lame!
#ifdef None
#undef None
#endif
#include "nsIRegistry.h"
#include "nsEnumeratorUtils.h"
#include "nsISupportsPrimitives.h"
// for the dialog
#include "nsIStringBundle.h"
#include "nsIPrompt.h"
#include "nsIWindowWatcher.h"
#include "nsIScriptGlobalObject.h"
#include "nsIScriptGlobalObjectOwner.h"
#include "nsIPrincipal.h"
#include "nsIServiceManager.h"
1999-03-20 23:11:25 +00:00
#include "nsICookieStorage.h"
#include "nsICookieService.h"
#include "nsIDOMPlugin.h"
#include "nsIDOMMimeType.h"
#include "nsMimeTypes.h"
1998-09-15 03:48:58 +00:00
#include "prprf.h"
#include "nsIInputStreamTee.h"
#if defined(XP_PC) && !defined(XP_OS2)
#include "windows.h"
1998-09-15 03:48:58 +00:00
#include "winbase.h"
#endif
1999-02-20 02:24:15 +00:00
#include "nsFileSpec.h"
#include "nsPluginDocLoaderFactory.h"
2000-07-07 00:10:54 +00:00
#include "nsIDocumentLoaderFactory.h"
#include "nsIMIMEService.h"
#include "nsCExternalHandlerService.h"
#include "nsILocalFile.h"
#include "nsIFileChannel.h"
#include "nsPluginSafety.h"
#include "nsICharsetConverterManager.h"
#include "nsIPlatformCharset.h"
#include "nsIDirectoryService.h"
#include "nsDirectoryServiceDefs.h"
#include "nsIFile.h"
#include "nsPluginDirServiceProvider.h"
#ifdef XP_UNIX
#if defined(MOZ_WIDGET_GTK)
#include <gdk/gdkx.h> // for GDK_DISPLAY()
#elif defined(MOZ_WIDGET_QT)
#include <qwindowdefs.h> // for qt_xdisplay()
#elif defined(MOZ_WIDGET_XLIB)
#include "xlibrgb.h" // for xlib_rgb_get_display()
#endif
#endif
#if defined(XP_MAC) && TARGET_CARBON
#include "nsIClassicPluginFactory.h"
#endif
#if defined(XP_MAC) && TARGET_CARBON
#include "nsIClassicPluginFactory.h"
#endif
// We need this hackery so that we can dynamically register doc
// loaders for the 4.x plugins that we discover.
#if defined(XP_PC)
#define PLUGIN_DLL "gkplugin.dll"
#elif defined(XP_UNIX) || defined(XP_BEOS)
#define PLUGIN_DLL "libgkplugin" MOZ_DLL_SUFFIX
#elif defined(XP_MAC)
#if defined(NS_DEBUG)
#define PLUGIN_DLL "pluginDebug.shlb"
#else
#define PLUGIN_DLL "plugin.shlb"
#endif // ifdef NS_DEBUG
#endif
#define REL_PLUGIN_DLL "rel:" PLUGIN_DLL
// this is the name of the directory which will be created
// to cache temporary files.
static const char *kPluginTmpDirName = "plugtmp";
// Version of cached plugin info
// 0.01 first implementation
// 0.02 added caching of CanUnload to fix bug 105935
// 0.03 changed name, description and mime desc from string to bytes, bug 108246
static const char *kPluginInfoVersion = "0.03";
////////////////////////////////////////////////////////////////////////
// CID's && IID's
static NS_DEFINE_IID(kIPluginInstanceIID, NS_IPLUGININSTANCE_IID);
static NS_DEFINE_IID(kIPluginInstancePeerIID, NS_IPLUGININSTANCEPEER_IID);
1999-01-25 08:05:00 +00:00
static NS_DEFINE_IID(kIPluginStreamInfoIID, NS_IPLUGINSTREAMINFO_IID);
static NS_DEFINE_CID(kPluginCID, NS_PLUGIN_CID);
static NS_DEFINE_IID(kIPluginTagInfo2IID, NS_IPLUGINTAGINFO2_IID);
static NS_DEFINE_CID(kPrefServiceCID, NS_PREF_CID);
static NS_DEFINE_CID(kProtocolProxyServiceCID, NS_PROTOCOLPROXYSERVICE_CID);
static NS_DEFINE_CID(kCookieServiceCID, NS_COOKIESERVICE_CID);
static NS_DEFINE_IID(kISupportsIID, NS_ISUPPORTS_IID);
static NS_DEFINE_IID(kIRequestObserverIID, NS_IREQUESTOBSERVER_IID);
static NS_DEFINE_CID(kIOServiceCID, NS_IOSERVICE_CID);
static NS_DEFINE_CID(kHttpHandlerCID, NS_HTTPPROTOCOLHANDLER_CID);
static NS_DEFINE_CID(kIHttpHeaderVisitorIID, NS_IHTTPHEADERVISITOR_IID);
static NS_DEFINE_CID(kStreamConverterServiceCID, NS_STREAMCONVERTERSERVICE_CID);
1999-01-25 08:05:00 +00:00
static NS_DEFINE_IID(kIFileUtilitiesIID, NS_IFILEUTILITIES_IID);
static NS_DEFINE_IID(kIOutputStreamIID, NS_IOUTPUTSTREAM_IID);
static NS_DEFINE_CID(kRegistryCID, NS_REGISTRY_CID);
static const char kDirectoryServiceContractID[] = "@mozilla.org/file/directory_service;1";
// for the dialog
static NS_DEFINE_IID(kStringBundleServiceCID, NS_STRINGBUNDLESERVICE_CID);
2000-07-07 00:10:54 +00:00
static NS_DEFINE_CID(kComponentManagerCID, NS_COMPONENTMANAGER_CID);
////////////////////////////////////////////////////////////////////////
// Registry keys for caching plugin info
static const char kPluginsRootKey[] = "software/plugins";
static const char kPluginsNameKey[] = "name";
static const char kPluginsDescKey[] = "description";
static const char kPluginsFilenameKey[] = "filename";
static const char kPluginsFullpathKey[] = "fullpath";
static const char kPluginsModTimeKey[] = "lastModTimeStamp";
static const char kPluginsCanUnload[] = "canUnload";
static const char kPluginsVersionKey[] = "version";
static const char kPluginsMimeTypeKey[] = "mimetype";
static const char kPluginsMimeDescKey[] = "description";
static const char kPluginsMimeExtKey[] = "extension";
#ifdef PLUGIN_LOGGING
PRLogModuleInfo* nsPluginLogging::gNPNLog = nsnull;
PRLogModuleInfo* nsPluginLogging::gNPPLog = nsnull;
PRLogModuleInfo* nsPluginLogging::gPluginLog = nsnull;
#endif
#define PLUGIN_PROPERTIES_URL "chrome://global/locale/downloadProgress.properties"
#define PLUGIN_REGIONAL_URL "chrome://global-region/locale/region.properties"
// #defines for reading prefs and extra search plugin paths from windows registry
#define _MAXKEYVALUE_ 8196
#define _NS_PREF_COMMON_PLUGIN_REG_KEY_ "browser.plugins.registry_plugins_folder_key_location"
#define _NS_COMMON_PLUGIN_KEY_NAME_ "Plugins Folders"
// #defines for plugin cache and prefs
#define NS_PREF_MAX_NUM_CACHED_PLUGINS "browser.plugins.max_num_cached_plugins"
#define DEFAULT_NUMBER_OF_STOPPED_PLUGINS 10
#define MAGIC_REQUEST_CONTEXT 0x01020304
void DisplayNoDefaultPluginDialog(const char *mimeType);
/**
* Used in DisplayNoDefaultPlugindialog to prevent showing the dialog twice
* for the same mimetype.
*/
static nsHashtable *mimeTypesSeen = nsnull;
/**
* placeholder value for mimeTypesSeen hashtable
*/
static const char *hashValue = "value";
/**
* Default number of entries in the mimeTypesSeen hashtable
*/
#define NS_MIME_TYPES_HASH_NUM (20)
////////////////////////////////////////////////////////////////////////
void DisplayNoDefaultPluginDialog(const char *mimeType)
{
nsresult rv;
if (nsnull == mimeTypesSeen) {
mimeTypesSeen = new nsHashtable(NS_MIME_TYPES_HASH_NUM);
}
if ((mimeTypesSeen != nsnull) && (mimeType != nsnull)) {
nsCStringKey key(mimeType);
// if we've seen this mimetype before
if (mimeTypesSeen->Get(&key)) {
// don't display the dialog
return;
}
else {
mimeTypesSeen->Put(&key, (void *) hashValue);
}
}
nsCOMPtr<nsIPref> prefs(do_GetService(kPrefServiceCID));
nsCOMPtr<nsIPrompt> prompt;
nsCOMPtr<nsIWindowWatcher> wwatch(do_GetService("@mozilla.org/embedcomp/window-watcher;1"));
if (wwatch)
wwatch->GetNewPrompter(0, getter_AddRefs(prompt));
nsCOMPtr<nsIIOService> io(do_GetService(kIOServiceCID));
nsCOMPtr<nsIStringBundleService> strings(do_GetService(kStringBundleServiceCID));
nsCOMPtr<nsIStringBundle> bundle;
nsCOMPtr<nsIStringBundle> regionalBundle;
nsCOMPtr<nsIURI> uri;
PRBool displayDialogPrefValue = PR_FALSE, checkboxState = PR_FALSE;
if (!prefs || !prompt || !io || !strings) {
return;
}
rv = prefs->GetBoolPref("plugin.display_plugin_downloader_dialog",
&displayDialogPrefValue);
if (NS_SUCCEEDED(rv)) {
// if the pref is false, don't display the dialog
if (!displayDialogPrefValue) {
return;
}
}
// Taken from mozilla\extensions\wallet\src\wallet.cpp
// WalletLocalize().
rv = strings->CreateBundle(PLUGIN_PROPERTIES_URL, getter_AddRefs(bundle));
if (NS_FAILED(rv)) {
return;
}
rv = strings->CreateBundle(PLUGIN_REGIONAL_URL,
getter_AddRefs(regionalBundle));
if (NS_FAILED(rv)) {
return;
}
PRUnichar *titleUni = nsnull;
PRUnichar *messageUni = nsnull;
PRUnichar *checkboxMessageUni = nsnull;
rv = bundle->GetStringFromName(NS_LITERAL_STRING("noDefaultPluginTitle").get(),
&titleUni);
if (NS_FAILED(rv)) {
goto EXIT_DNDPD;
}
rv = regionalBundle->GetStringFromName(NS_LITERAL_STRING("noDefaultPluginMessage").get(),
&messageUni);
if (NS_FAILED(rv)) {
goto EXIT_DNDPD;
}
rv = bundle->GetStringFromName(NS_LITERAL_STRING("noDefaultPluginCheckboxMessage").get(),
&checkboxMessageUni);
if (NS_FAILED(rv)) {
goto EXIT_DNDPD;
}
PRInt32 buttonPressed;
rv = prompt->ConfirmEx(titleUni, messageUni,
nsIPrompt::BUTTON_TITLE_OK * nsIPrompt::BUTTON_POS_0,
nsnull, nsnull, nsnull,
checkboxMessageUni, &checkboxState, &buttonPressed);
// if the user checked the checkbox, make it so the dialog doesn't
// display again.
if (checkboxState) {
prefs->SetBoolPref("plugin.display_plugin_downloader_dialog",
!checkboxState);
}
EXIT_DNDPD:
nsMemory::Free((void *)titleUni);
nsMemory::Free((void *)messageUni);
nsMemory::Free((void *)checkboxMessageUni);
return;
}
////////////////////////////////////////////////////////////////////////
nsActivePlugin::nsActivePlugin(nsPluginTag* aPluginTag,
nsIPluginInstance* aInstance,
char * url,
PRBool aDefaultPlugin)
{
mNext = nsnull;
mPeer = nsnull;
mPluginTag = aPluginTag;
mURL = PL_strdup(url);
mInstance = aInstance;
if(aInstance != nsnull)
{
aInstance->GetPeer(&mPeer);
NS_ADDREF(aInstance);
}
mXPConnected = PR_FALSE;
mDefaultPlugin = aDefaultPlugin;
mStopped = PR_FALSE;
mllStopTime = LL_ZERO;
mStreams = new nsVoidArray(); // create a new stream array
}
////////////////////////////////////////////////////////////////////////
nsActivePlugin::~nsActivePlugin()
{
mPluginTag = nsnull;
// free our streams array
if (mStreams)
{
delete mStreams;
mStreams = nsnull;
}
if(mInstance != nsnull)
{
if(mPeer)
{
nsresult rv = NS_OK;
nsPluginInstancePeerImpl * peer = (nsPluginInstancePeerImpl *)mPeer;
nsCOMPtr<nsIPluginInstanceOwner> owner;
rv = peer->GetOwner(*getter_AddRefs(owner));
owner->SetInstance(nsnull);
}
// now check for cached plugins because they haven't had nsIPluginInstance::Destroy()
// called yet. For non-cached plugins, nsIPluginInstance::Destroy() is called
// in either nsObjectFrame::Destroy() or nsActivePluginList::stopRunning()
PRBool doCache = PR_TRUE;
mInstance->GetValue(nsPluginInstanceVariable_DoCacheBool, (void *) &doCache);
if (doCache)
mInstance->Destroy();
NS_RELEASE(mInstance);
NS_RELEASE(mPeer);
}
PL_strfree(mURL);
}
////////////////////////////////////////////////////////////////////////
void nsActivePlugin::setStopped(PRBool stopped)
{
mStopped = stopped;
if(mStopped) // plugin instance is told to stop
{
mllStopTime = PR_Now();
// Since we are "stopped", we should clear our our streams array
if (mStreams)
while (mStreams->Count() > 0 ) // simple loop, always removing the first element
{
nsIStreamListener * s = (nsIStreamListener *) mStreams->ElementAt(0); // XXX nasty cast!
if (s)
{
NS_RELEASE(s); // should cause stream destructions (and prevent leaks!)
mStreams->RemoveElementAt(0);
}
}
}
else
mllStopTime = LL_ZERO;
}
////////////////////////////////////////////////////////////////////////
nsActivePluginList::nsActivePluginList()
{
mFirst = nsnull;
mLast = nsnull;
mCount = 0;
}
////////////////////////////////////////////////////////////////////////
nsActivePluginList::~nsActivePluginList()
{
if(mFirst == nsnull)
return;
shut();
}
////////////////////////////////////////////////////////////////////////
void nsActivePluginList::shut()
{
if(mFirst == nsnull)
return;
for(nsActivePlugin * plugin = mFirst; plugin != nsnull;)
{
nsActivePlugin * next = plugin->mNext;
PRBool unloadLibLater = PR_FALSE;
remove(plugin, &unloadLibLater);
NS_ASSERTION(!unloadLibLater, "Plugin doesn't want to be unloaded");
plugin = next;
}
mFirst = nsnull;
mLast = nsnull;
}
////////////////////////////////////////////////////////////////////////
PRInt32 nsActivePluginList::add(nsActivePlugin * plugin)
{
if (mFirst == nsnull)
{
mFirst = plugin;
mLast = plugin;
mFirst->mNext = nsnull;
}
else
{
mLast->mNext = plugin;
mLast = plugin;
}
mLast->mNext = nsnull;
mCount++;
return mCount;
}
////////////////////////////////////////////////////////////////////////
PRBool nsActivePluginList::IsLastInstance(nsActivePlugin * plugin)
{
if(!plugin)
return PR_FALSE;
if(!plugin->mPluginTag)
return PR_FALSE;
for(nsActivePlugin * p = mFirst; p != nsnull; p = p->mNext)
{
if((p->mPluginTag == plugin->mPluginTag) && (p != plugin))
return PR_FALSE;
}
return PR_TRUE;
}
////////////////////////////////////////////////////////////////////////
PRBool nsActivePluginList::remove(nsActivePlugin * plugin, PRBool * aUnloadLibraryLater)
{
if(mFirst == nsnull)
return PR_FALSE;
nsActivePlugin * prev = nsnull;
for(nsActivePlugin * p = mFirst; p != nsnull; p = p->mNext)
{
if(p == plugin)
{
PRBool lastInstance = IsLastInstance(p);
if(p == mFirst)
mFirst = p->mNext;
else
prev->mNext = p->mNext;
if((prev != nsnull) && (prev->mNext == nsnull))
mLast = prev;
// see if this is going to be the last instance of a plugin
// if so we should perform nsIPlugin::Shutdown and unload the library
// by calling nsPluginTag::TryUnloadPlugin()
if(lastInstance)
{
// cache some things as we are going to destroy it right now
nsPluginTag *pluginTag = p->mPluginTag;
delete p; // plugin instance is destroyed here
if(pluginTag)
{
// xpconnected plugins from the old world should postpone unloading library
// to avoid crash check, if so add library to the list of unloaded libraries
if(pluginTag->mXPConnected && (pluginTag->mFlags & NS_PLUGIN_FLAG_OLDSCHOOL))
{
pluginTag->mCanUnloadLibrary = PR_FALSE;
if(aUnloadLibraryLater)
*aUnloadLibraryLater = PR_TRUE;
}
pluginTag->TryUnloadPlugin();
}
else
NS_ASSERTION(pluginTag, "pluginTag was not set, plugin not shutdown");
}
else
delete p;
mCount--;
return PR_TRUE;
}
prev = p;
}
return PR_FALSE;
}
////////////////////////////////////////////////////////////////////////
void nsActivePluginList::stopRunning()
{
if(mFirst == nsnull)
return;
PRBool doCallSetWindowAfterDestroy = PR_FALSE;
for(nsActivePlugin * p = mFirst; p != nsnull; p = p->mNext)
{
if(!p->mStopped && p->mInstance)
{
// then determine if the plugin wants Destroy to be called after
// Set Window. This is for bug 50547.
p->mInstance->GetValue(nsPluginInstanceVariable_CallSetWindowAfterDestroyBool,
(void *) &doCallSetWindowAfterDestroy);
if (doCallSetWindowAfterDestroy) {
p->mInstance->Stop();
p->mInstance->Destroy();
p->mInstance->SetWindow(nsnull);
}
else {
p->mInstance->SetWindow(nsnull);
p->mInstance->Stop();
p->mInstance->Destroy();
}
doCallSetWindowAfterDestroy = PR_FALSE;
p->setStopped(PR_TRUE);
}
}
}
////////////////////////////////////////////////////////////////////////
void nsActivePluginList::removeAllStopped()
{
if(mFirst == nsnull)
return;
nsActivePlugin * next = nsnull;
for(nsActivePlugin * p = mFirst; p != nsnull;)
{
next = p->mNext;
if(p->mStopped)
{
// we don't care about unloading library problem for
// plugins that are already in the 'stop' state
PRBool unloadLibLater = PR_FALSE;
remove(p, &unloadLibLater);
}
p = next;
}
return;
}
////////////////////////////////////////////////////////////////////////
nsActivePlugin * nsActivePluginList::find(nsIPluginInstance* instance)
{
for(nsActivePlugin * p = mFirst; p != nsnull; p = p->mNext)
{
if(p->mInstance == instance)
{
#ifdef NS_DEBUG
PRBool doCache = PR_TRUE;
p->mInstance->GetValue(nsPluginInstanceVariable_DoCacheBool, (void *) &doCache);
NS_ASSERTION(!p->mStopped || doCache, "This plugin is not supposed to be cached!");
#endif
return p;
}
}
return nsnull;
}
nsActivePlugin * nsActivePluginList::find(char * mimetype)
{
PRBool defaultplugin = (PL_strcmp(mimetype, "*") == 0);
for(nsActivePlugin * p = mFirst; p != nsnull; p = p->mNext)
{
// give it some special treatment for the default plugin first
// because we cannot tell the default plugin by asking peer for a mime type
if(defaultplugin && p->mDefaultPlugin)
return p;
if(!p->mPeer)
continue;
nsMIMEType mt;
nsresult res = p->mPeer->GetMIMEType(&mt);
if(NS_FAILED(res))
continue;
if(PL_strcasecmp(mt, mimetype) == 0)
{
#ifdef NS_DEBUG
PRBool doCache = PR_TRUE;
p->mInstance->GetValue(nsPluginInstanceVariable_DoCacheBool, (void *) &doCache);
NS_ASSERTION(!p->mStopped || doCache, "This plugin is not supposed to be cached!");
#endif
return p;
}
}
return nsnull;
}
////////////////////////////////////////////////////////////////////////
nsActivePlugin * nsActivePluginList::findStopped(char * url)
{
for(nsActivePlugin * p = mFirst; p != nsnull; p = p->mNext)
{
if(!PL_strcmp(url, p->mURL) && p->mStopped)
{
#ifdef NS_DEBUG
PRBool doCache = PR_TRUE;
p->mInstance->GetValue(nsPluginInstanceVariable_DoCacheBool, (void *) &doCache);
NS_ASSERTION(doCache, "This plugin is not supposed to be cached!");
#endif
return p;
}
}
return nsnull;
}
////////////////////////////////////////////////////////////////////////
PRUint32 nsActivePluginList::getStoppedCount()
{
PRUint32 stoppedCount = 0;
for(nsActivePlugin * p = mFirst; p != nsnull; p = p->mNext)
{
if(p->mStopped)
stoppedCount++;
}
return stoppedCount;
}
////////////////////////////////////////////////////////////////////////
nsActivePlugin * nsActivePluginList::findOldestStopped()
{
nsActivePlugin * res = nsnull;
PRInt64 llTime = LL_MAXINT;
for(nsActivePlugin * p = mFirst; p != nsnull; p = p->mNext)
{
if(!p->mStopped)
continue;
if(LL_CMP(p->mllStopTime, <, llTime))
{
llTime = p->mllStopTime;
res = p;
}
}
#ifdef NS_DEBUG
if(res)
{
PRBool doCache = PR_TRUE;
res->mInstance->GetValue(nsPluginInstanceVariable_DoCacheBool, (void *) &doCache);
NS_ASSERTION(doCache, "This plugin is not supposed to be cached!");
}
#endif
return res;
}
////////////////////////////////////////////////////////////////////////
nsUnusedLibrary::nsUnusedLibrary(PRLibrary * aLibrary)
{
mLibrary = aLibrary;
}
////////////////////////////////////////////////////////////////////////
nsUnusedLibrary::~nsUnusedLibrary()
{
if(mLibrary)
PR_UnloadLibrary(mLibrary);
}
////////////////////////////////////////////////////////////////////////
nsPluginTag::nsPluginTag()
{
mNext = nsnull;
mName = nsnull;
mDescription = nsnull;
mVariants = 0;
mMimeTypeArray = nsnull;
mMimeDescriptionArray = nsnull;
mExtensionsArray = nsnull;
mLibrary = nsnull;
mCanUnloadLibrary = PR_TRUE;
mEntryPoint = nsnull;
mFlags = NS_PLUGIN_FLAG_ENABLED;
mXPConnected = PR_FALSE;
mFileName = nsnull;
mFullPath = nsnull;
}
////////////////////////////////////////////////////////////////////////
inline char* new_str(const char* str)
{
if(str == nsnull)
return nsnull;
char* result = new char[strlen(str) + 1];
if (result != nsnull)
return strcpy(result, str);
return result;
}
////////////////////////////////////////////////////////////////////////
nsPluginTag::nsPluginTag(nsPluginTag* aPluginTag)
{
mNext = nsnull;
mName = new_str(aPluginTag->mName);
mDescription = new_str(aPluginTag->mDescription);
mVariants = aPluginTag->mVariants;
mMimeTypeArray = nsnull;
mMimeDescriptionArray = nsnull;
mExtensionsArray = nsnull;
if(aPluginTag->mMimeTypeArray != nsnull)
{
mMimeTypeArray = new char*[mVariants];
for (int i = 0; i < mVariants; i++)
mMimeTypeArray[i] = new_str(aPluginTag->mMimeTypeArray[i]);
}
if(aPluginTag->mMimeDescriptionArray != nsnull)
{
mMimeDescriptionArray = new char*[mVariants];
for (int i = 0; i < mVariants; i++)
mMimeDescriptionArray[i] = new_str(aPluginTag->mMimeDescriptionArray[i]);
}
if(aPluginTag->mExtensionsArray != nsnull)
{
mExtensionsArray = new char*[mVariants];
for (int i = 0; i < mVariants; i++)
mExtensionsArray[i] = new_str(aPluginTag->mExtensionsArray[i]);
}
mLibrary = nsnull;
mCanUnloadLibrary = PR_TRUE;
mEntryPoint = nsnull;
mFlags = NS_PLUGIN_FLAG_ENABLED;
mXPConnected = PR_FALSE;
mFileName = new_str(aPluginTag->mFileName);
mFullPath = new_str(aPluginTag->mFullPath);
}
////////////////////////////////////////////////////////////////////////
nsPluginTag::nsPluginTag(nsPluginInfo* aPluginInfo)
{
mNext = nsnull;
mName = new_str(aPluginInfo->fName);
mDescription = new_str(aPluginInfo->fDescription);
mVariants = aPluginInfo->fVariantCount;
mMimeTypeArray = nsnull;
mMimeDescriptionArray = nsnull;
mExtensionsArray = nsnull;
2000-03-29 23:58:42 +00:00
if(aPluginInfo->fMimeTypeArray != nsnull)
{
mMimeTypeArray = new char*[mVariants];
for (int i = 0; i < mVariants; i++)
mMimeTypeArray[i] = new_str(aPluginInfo->fMimeTypeArray[i]);
2000-03-29 23:58:42 +00:00
}
if(aPluginInfo->fMimeDescriptionArray != nsnull)
{
mMimeDescriptionArray = new char*[mVariants];
for (int i = 0; i < mVariants; i++)
mMimeDescriptionArray[i] = new_str(aPluginInfo->fMimeDescriptionArray[i]);
2000-03-29 23:58:42 +00:00
}
if(aPluginInfo->fExtensionArray != nsnull)
{
mExtensionsArray = new char*[mVariants];
for (int i = 0; i < mVariants; i++)
mExtensionsArray[i] = new_str(aPluginInfo->fExtensionArray[i]);
}
mFileName = new_str(aPluginInfo->fFileName);
mFullPath = new_str(aPluginInfo->fFullPath);
mLibrary = nsnull;
mCanUnloadLibrary = PR_TRUE;
mEntryPoint = nsnull;
#if TARGET_CARBON
mCanUnloadLibrary = !aPluginInfo->fBundle;
#endif
mFlags = NS_PLUGIN_FLAG_ENABLED;
mXPConnected = PR_FALSE;
}
////////////////////////////////////////////////////////////////////////
nsPluginTag::nsPluginTag(const char* aName,
const char* aDescription,
const char* aFileName,
const char* aFullPath,
const char* const* aMimeTypes,
const char* const* aMimeDescriptions,
const char* const* aExtensions,
PRInt32 aVariants,
PRInt64 aLastModifiedTime,
PRBool aCanUnload)
: mNext(nsnull),
mVariants(aVariants),
mMimeTypeArray(nsnull),
mMimeDescriptionArray(nsnull),
mExtensionsArray(nsnull),
mLibrary(nsnull),
mCanUnloadLibrary(aCanUnload),
mEntryPoint(nsnull),
mFlags(0),
mXPConnected(PR_FALSE),
mLastModifiedTime(aLastModifiedTime)
{
mName = new_str(aName);
mDescription = new_str(aDescription);
mFileName = new_str(aFileName);
mFullPath = new_str(aFullPath);
if (mVariants) {
mMimeTypeArray = new char*[mVariants];
mMimeDescriptionArray = new char*[mVariants];
mExtensionsArray = new char*[mVariants];
for (PRInt32 i = 0; i < aVariants; ++i) {
mMimeTypeArray[i] = new_str(aMimeTypes[i]);
mMimeDescriptionArray[i] = new_str(aMimeDescriptions[i]);
mExtensionsArray[i] = new_str(aExtensions[i]);
}
}
}
nsPluginTag::~nsPluginTag()
{
TryUnloadPlugin(PR_TRUE);
1998-09-15 03:48:58 +00:00
if (nsnull != mName) {
delete[] (mName);
mName = nsnull;
}
if (nsnull != mDescription) {
delete[] (mDescription);
mDescription = nsnull;
}
if (nsnull != mMimeTypeArray) {
for (int i = 0; i < mVariants; i++)
delete[] mMimeTypeArray[i];
delete[] (mMimeTypeArray);
mMimeTypeArray = nsnull;
}
if (nsnull != mMimeDescriptionArray) {
for (int i = 0; i < mVariants; i++)
delete[] mMimeDescriptionArray[i];
delete[] (mMimeDescriptionArray);
mMimeDescriptionArray = nsnull;
}
if (nsnull != mExtensionsArray) {
for (int i = 0; i < mVariants; i++)
delete[] mExtensionsArray[i];
delete[] (mExtensionsArray);
mExtensionsArray = nsnull;
}
if(nsnull != mFileName)
{
delete [] mFileName;
mFileName = nsnull;
}
if(nsnull != mFullPath)
{
delete [] mFullPath;
mFullPath = nsnull;
}
}
////////////////////////////////////////////////////////////////////////
void nsPluginTag::TryUnloadPlugin(PRBool aForceShutdown)
{
2001-05-18 23:38:06 +00:00
PRBool isXPCOM = PR_FALSE;
if (!(mFlags & NS_PLUGIN_FLAG_OLDSCHOOL))
isXPCOM = PR_TRUE;
if (isXPCOM && !aForceShutdown) return;
if (mEntryPoint)
{
mEntryPoint->Shutdown();
mEntryPoint->Release();
mEntryPoint = nsnull;
}
// before we unload check if we are allowed to, see bug #61388
// also, never unload an XPCOM plugin library
if (mLibrary && mCanUnloadLibrary && !isXPCOM)
PR_UnloadLibrary(mLibrary);
// we should zero it anyway, it is going to be unloaded by
// CleanUnsedLibraries before we need to call the library
// again so the calling code should not be fooled and reload
// the library fresh
mLibrary = nsnull;
}
////////////////////////////////////////////////////////////////////////
PRBool nsPluginTag::Equals(nsPluginTag *aPluginTag)
{
NS_ENSURE_TRUE(aPluginTag, PR_FALSE);
if ( (PL_strcmp(mName, aPluginTag->mName) != 0) ||
(PL_strcmp(mDescription, aPluginTag->mDescription) != 0) ||
(mVariants != aPluginTag->mVariants) )
return PR_FALSE;
if (0 != mVariants && mMimeTypeArray && aPluginTag->mMimeTypeArray)
for (PRInt32 i = 0; i < mVariants; i++)
if (PL_strcmp(mMimeTypeArray[i], aPluginTag->mMimeTypeArray[i]) != 0)
return PR_FALSE;
return PR_TRUE;
}
////////////////////////////////////////////////////////////////////////
class nsPluginStreamListenerPeer;
1999-01-25 08:05:00 +00:00
class nsPluginStreamInfo : public nsIPluginStreamInfo
{
public:
nsPluginStreamInfo();
virtual ~nsPluginStreamInfo();
1999-01-25 08:05:00 +00:00
NS_DECL_ISUPPORTS
1999-01-25 08:05:00 +00:00
// nsIPluginStreamInfo interface
1999-01-25 08:05:00 +00:00
NS_IMETHOD
GetContentType(nsMIMEType* result);
1999-01-25 08:05:00 +00:00
NS_IMETHOD
IsSeekable(PRBool* result);
1999-01-25 08:05:00 +00:00
NS_IMETHOD
GetLength(PRUint32* result);
1999-01-25 08:05:00 +00:00
NS_IMETHOD
GetLastModified(PRUint32* result);
1999-01-25 08:05:00 +00:00
NS_IMETHOD
GetURL(const char** result);
NS_IMETHOD
RequestRead(nsByteRange* rangeList);
1999-01-25 08:05:00 +00:00
// local methods
1999-01-25 08:05:00 +00:00
void
SetContentType(const nsMIMEType contentType);
1999-01-25 08:05:00 +00:00
void
SetSeekable(const PRBool seekable);
1999-01-25 08:05:00 +00:00
void
SetLength(const PRUint32 length);
1999-01-25 08:05:00 +00:00
void
SetLastModified(const PRUint32 modified);
void
SetURL(const char* url);
1999-01-25 08:05:00 +00:00
void
SetPluginInstance(nsIPluginInstance * aPluginInstance);
void
SetPluginStreamListenerPeer(nsPluginStreamListenerPeer * aPluginStreamListenerPeer);
void
MakeByteRangeString(nsByteRange* aRangeList, char** string, PRInt32 *numRequests);
void
SetLocalCachedFile(const char* path);
void
GetLocalCachedFile(char** path);
void
SetLocalCachedFileStream(nsIOutputStream *stream);
void
GetLocalCachedFileStream(nsIOutputStream **stream);
1999-01-25 08:05:00 +00:00
private:
char* mContentType;
char* mURL;
char* mFilePath;
PRBool mSeekable;
PRUint32 mLength;
PRUint32 mModified;
nsIPluginInstance * mPluginInstance;
nsPluginStreamListenerPeer * mPluginStreamListenerPeer;
nsCOMPtr<nsIOutputStream> mFileCacheOutputStream;
PRBool mLocallyCached;
};
///////////////////////////////////////////////////////////////////////////////////////////////////
class nsPluginStreamListenerPeer : public nsIStreamListener,
public nsIProgressEventSink,
public nsIHttpHeaderVisitor
{
public:
nsPluginStreamListenerPeer();
virtual ~nsPluginStreamListenerPeer();
NS_DECL_ISUPPORTS
NS_DECL_NSIPROGRESSEVENTSINK
NS_DECL_NSIREQUESTOBSERVER
NS_DECL_NSISTREAMLISTENER
NS_DECL_NSIHTTPHEADERVISITOR
// Called by GetURL and PostURL (via NewStream)
nsresult Initialize(nsIURI *aURL,
nsIPluginInstance *aInstance,
nsIPluginStreamListener *aListener,
PRInt32 requestCount = 1);
nsresult InitializeEmbeded(nsIURI *aURL,
nsIPluginInstance* aInstance,
nsIPluginInstanceOwner *aOwner = nsnull,
nsIPluginHost *aHost = nsnull);
nsresult InitializeFullPage(nsIPluginInstance *aInstance);
nsresult OnFileAvailable(const char* aFilename);
nsILoadGroup* GetLoadGroup();
nsresult SetLocalFile(const char* aFilename);
private:
nsresult SetUpCache(nsIURI* aURL); // todo: see about removing this...
nsresult SetUpStreamListener(nsIRequest* request, nsIURI* aURL);
nsresult SetupPluginCacheFile(nsIChannel* channel);
nsIURI *mURL;
nsIPluginInstanceOwner *mOwner;
nsIPluginInstance *mInstance;
nsIPluginStreamListener *mPStreamListener;
nsPluginStreamInfo *mPluginStreamInfo;
PRBool mSetUpListener;
/*
* Set to PR_TRUE after nsIPluginInstancePeer::OnStartBinding() has
* been called. Checked in ::OnStopRequest so we can call the
* plugin's OnStartBinding if, for some reason, it has not already
* been called.
*/
PRPackedBool mStartBinding;
PRPackedBool mHaveFiredOnStartRequest;
// these get passed to the plugin stream listener
char *mMIMEType;
PRUint32 mLength;
nsPluginStreamType mStreamType;
nsIPluginHost *mHost;
// local file which was used to post data and which should be deleted after that
char *mLocalFile;
nsHashtable *mDataForwardToRequest;
public:
PRBool mAbort;
PRInt32 mPendingRequests;
1999-01-25 08:05:00 +00:00
};
////////////////////////////////////////////////////////////////////////
1999-01-25 08:05:00 +00:00
nsPluginStreamInfo::nsPluginStreamInfo()
{
NS_INIT_REFCNT();
mPluginInstance = nsnull;
mPluginStreamListenerPeer = nsnull;
mContentType = nsnull;
mURL = nsnull;
mFilePath = nsnull;
mSeekable = PR_FALSE;
mLength = 0;
mModified = 0;
mLocallyCached = PR_FALSE;
1999-01-25 08:05:00 +00:00
}
////////////////////////////////////////////////////////////////////////
1999-01-25 08:05:00 +00:00
nsPluginStreamInfo::~nsPluginStreamInfo()
{
if(mContentType != nsnull)
PL_strfree(mContentType);
if(mURL != nsnull)
PL_strfree(mURL);
// ONLY delete our cached file if we created it
if(mLocallyCached && mFilePath)
{
nsCOMPtr<nsILocalFile> localFile;
nsresult res = NS_NewLocalFile(mFilePath,
PR_FALSE,
getter_AddRefs(localFile));
if(NS_SUCCEEDED(res))
localFile->Remove(PR_FALSE);
}
if (mFilePath)
PL_strfree(mFilePath);
NS_IF_RELEASE(mPluginInstance);
1999-01-25 08:05:00 +00:00
}
////////////////////////////////////////////////////////////////////////
1999-01-25 08:05:00 +00:00
NS_IMPL_ADDREF(nsPluginStreamInfo)
NS_IMPL_RELEASE(nsPluginStreamInfo)
////////////////////////////////////////////////////////////////////////
1999-01-25 08:05:00 +00:00
nsresult nsPluginStreamInfo::QueryInterface(const nsIID& aIID,
void** aInstancePtrResult)
{
NS_PRECONDITION(nsnull != aInstancePtrResult, "null pointer");
if (nsnull == aInstancePtrResult)
return NS_ERROR_NULL_POINTER;
if (aIID.Equals(kIPluginStreamInfoIID))
{
*aInstancePtrResult = (void *)((nsIPluginStreamInfo *)this);
AddRef();
return NS_OK;
}
if (aIID.Equals(kISupportsIID))
{
*aInstancePtrResult = (void *)((nsISupports *)((nsIStreamListener *)this));
AddRef();
return NS_OK;
}
return NS_NOINTERFACE;
}
////////////////////////////////////////////////////////////////////////
1999-01-25 08:05:00 +00:00
NS_IMETHODIMP
nsPluginStreamInfo::GetContentType(nsMIMEType* result)
{
*result = mContentType;
return NS_OK;
1999-01-25 08:05:00 +00:00
}
////////////////////////////////////////////////////////////////////////
1999-01-25 08:05:00 +00:00
NS_IMETHODIMP
nsPluginStreamInfo::IsSeekable(PRBool* result)
{
*result = mSeekable;
return NS_OK;
1999-01-25 08:05:00 +00:00
}
////////////////////////////////////////////////////////////////////////
1999-01-25 08:05:00 +00:00
NS_IMETHODIMP
nsPluginStreamInfo::GetLength(PRUint32* result)
{
*result = mLength;
return NS_OK;
1999-01-25 08:05:00 +00:00
}
////////////////////////////////////////////////////////////////////////
1999-01-25 08:05:00 +00:00
NS_IMETHODIMP
nsPluginStreamInfo::GetLastModified(PRUint32* result)
{
*result = mModified;
return NS_OK;
1999-01-25 08:05:00 +00:00
}
////////////////////////////////////////////////////////////////////////
NS_IMETHODIMP
nsPluginStreamInfo::GetURL(const char** result)
{
*result = mURL;
return NS_OK;
}
////////////////////////////////////////////////////////////////////////
void
nsPluginStreamInfo::MakeByteRangeString(nsByteRange* aRangeList, char** rangeRequest, PRInt32 *numRequests)
{
*rangeRequest = nsnull;
*numRequests = 0;
//the string should look like this: bytes=500-700,601-999
if(!aRangeList)
return;
PRInt32 requestCnt = 0;
nsCAutoString string("bytes=");
for(nsByteRange * range = aRangeList; range != nsnull; range = range->next)
{
// XXX zero length?
if(!range->length)
continue;
// XXX needs to be fixed for negative offsets
string.AppendInt(range->offset);
string.Append("-");
string.AppendInt(range->offset + range->length - 1);
if(range->next)
string += ",";
requestCnt++;
}
// get rid of possible trailing comma
string.Trim(",", PR_FALSE);
*rangeRequest = ToNewCString(string);
*numRequests = requestCnt;
return;
}
////////////////////////////////////////////////////////////////////////
1999-01-25 08:05:00 +00:00
NS_IMETHODIMP
nsPluginStreamInfo::RequestRead(nsByteRange* rangeList)
{
mPluginStreamListenerPeer->mAbort = PR_TRUE;
nsresult rv = NS_OK;
nsCOMPtr<nsIURI> url;
rv = NS_NewURI(getter_AddRefs(url), mURL);
nsCOMPtr<nsIChannel> channel;
rv = NS_OpenURI(getter_AddRefs(channel), url, nsnull, nsnull, nsnull);
if (NS_FAILED(rv))
return rv;
nsCOMPtr<nsIHttpChannel> httpChannel(do_QueryInterface(channel));
if(!httpChannel)
return NS_ERROR_FAILURE;
char *rangeString;
PRInt32 numRequests;
MakeByteRangeString(rangeList, &rangeString, &numRequests);
if(!rangeString)
return NS_ERROR_FAILURE;
httpChannel->SetRequestHeader("Range", rangeString);
nsMemory::Free(rangeString);
// instruct old stream listener to cancel the request on the next
// attempt to write.
nsCOMPtr<nsIStreamListener> converter = mPluginStreamListenerPeer;
if (numRequests > 1) {
nsCOMPtr<nsIStreamConverterService> serv = do_GetService(kStreamConverterServiceCID, &rv);
if (NS_FAILED(rv))
return rv;
rv = serv->AsyncConvertData(NS_LITERAL_STRING(MULTIPART_BYTERANGES).get(),
NS_LITERAL_STRING("*/*").get(),
mPluginStreamListenerPeer,
nsnull,
getter_AddRefs(converter));
if (NS_FAILED(rv))
return rv;
}
mPluginStreamListenerPeer->mPendingRequests += numRequests;
nsCOMPtr<nsISupportsPRUint32> container = do_CreateInstance(NS_SUPPORTS_PRUINT32_CONTRACTID, &rv);
if (NS_FAILED(rv)) return rv;
rv = container->SetData(MAGIC_REQUEST_CONTEXT);
if (NS_FAILED(rv)) return rv;
return channel->AsyncOpen(converter, container);
1999-01-25 08:05:00 +00:00
}
////////////////////////////////////////////////////////////////////////
1999-01-25 08:05:00 +00:00
void
nsPluginStreamInfo::SetContentType(const nsMIMEType contentType)
{
if(mContentType != nsnull)
PL_strfree(mContentType);
1999-01-25 08:05:00 +00:00
mContentType = PL_strdup(contentType);
1999-01-25 08:05:00 +00:00
}
////////////////////////////////////////////////////////////////////////
1999-01-25 08:05:00 +00:00
void
nsPluginStreamInfo::SetSeekable(const PRBool seekable)
{
mSeekable = seekable;
1999-01-25 08:05:00 +00:00
}
////////////////////////////////////////////////////////////////////////
1999-01-25 08:05:00 +00:00
void
nsPluginStreamInfo::SetLength(const PRUint32 length)
{
mLength = length;
1999-01-25 08:05:00 +00:00
}
////////////////////////////////////////////////////////////////////////
1999-01-25 08:05:00 +00:00
void
nsPluginStreamInfo::SetLastModified(const PRUint32 modified)
{
mModified = modified;
1999-01-25 08:05:00 +00:00
}
////////////////////////////////////////////////////////////////////////
void
nsPluginStreamInfo::SetURL(const char* url)
{
if(mURL != nsnull)
PL_strfree(mURL);
mURL = PL_strdup(url);
}
1999-06-25 00:03:22 +00:00
////////////////////////////////////////////////////////////////////////
void
nsPluginStreamInfo::SetLocalCachedFile(const char* path)
{
if(mFilePath != nsnull)
PL_strfree(mFilePath);
mFilePath = PL_strdup(path);
}
////////////////////////////////////////////////////////////////////////
void
nsPluginStreamInfo::GetLocalCachedFile(char** path)
{
*path = PL_strdup(mFilePath);
}
1999-01-25 08:05:00 +00:00
////////////////////////////////////////////////////////////////////////
void
nsPluginStreamInfo::SetLocalCachedFileStream(nsIOutputStream *stream)
{
mFileCacheOutputStream = stream;
mLocallyCached = PR_TRUE;
}
////////////////////////////////////////////////////////////////////////
void
nsPluginStreamInfo::GetLocalCachedFileStream(nsIOutputStream **stream)
{
if (!stream) return;
NS_IF_ADDREF(*stream = mFileCacheOutputStream);
}
////////////////////////////////////////////////////////////////////////
void
nsPluginStreamInfo::SetPluginInstance(nsIPluginInstance * aPluginInstance)
{
NS_IF_ADDREF(mPluginInstance = aPluginInstance);
}
////////////////////////////////////////////////////////////////////////
void
nsPluginStreamInfo::SetPluginStreamListenerPeer(nsPluginStreamListenerPeer * aPluginStreamListenerPeer)
{
// not addref'd - nsPluginStreamInfo is owned by mPluginStreamListenerPeer
mPluginStreamListenerPeer = aPluginStreamListenerPeer;
}
///////////////////////////////////////////////////////////////////////////////////////////////////
class nsPluginCacheListener : public nsIStreamListener
{
public:
nsPluginCacheListener(nsPluginStreamListenerPeer* aListener);
virtual ~nsPluginCacheListener();
NS_DECL_ISUPPORTS
NS_DECL_NSIREQUESTOBSERVER
NS_DECL_NSISTREAMLISTENER
1999-06-25 00:03:22 +00:00
private:
nsPluginStreamListenerPeer* mListener;
};
////////////////////////////////////////////////////////////////////////
nsPluginCacheListener::nsPluginCacheListener(nsPluginStreamListenerPeer* aListener)
{
NS_INIT_REFCNT();
mListener = aListener;
NS_ADDREF(mListener);
}
////////////////////////////////////////////////////////////////////////
nsPluginCacheListener::~nsPluginCacheListener()
{
NS_IF_RELEASE(mListener);
}
////////////////////////////////////////////////////////////////////////
NS_IMPL_ISUPPORTS1(nsPluginCacheListener, nsIStreamListener)
////////////////////////////////////////////////////////////////////////
1999-06-25 00:03:22 +00:00
NS_IMETHODIMP
nsPluginCacheListener::OnStartRequest(nsIRequest *request, nsISupports* ctxt)
1999-06-25 00:03:22 +00:00
{
return NS_OK;
1999-06-25 00:03:22 +00:00
}
////////////////////////////////////////////////////////////////////////
NS_IMETHODIMP
nsPluginCacheListener::OnDataAvailable(nsIRequest *request, nsISupports* ctxt,
nsIInputStream* aIStream,
PRUint32 sourceOffset,
PRUint32 aLength)
{
1999-06-25 00:03:22 +00:00
PRUint32 readlen;
char* buffer = (char*) PR_Malloc(aLength);
// if we don't read from the stream, OnStopRequest will never be called
if(!buffer)
return NS_ERROR_OUT_OF_MEMORY;
nsresult rv = aIStream->Read(buffer, aLength, &readlen);
NS_ASSERTION(aLength == readlen, "nsCacheListener->OnDataAvailable: "
"readlen != aLength");
PR_Free(buffer);
return rv;
}
////////////////////////////////////////////////////////////////////////
NS_IMETHODIMP
nsPluginCacheListener::OnStopRequest(nsIRequest *request,
nsISupports* aContext,
nsresult aStatus)
{
return NS_OK;
}
///////////////////////////////////////////////////////////////////////////////////////////////////////
nsPluginStreamListenerPeer::nsPluginStreamListenerPeer()
{
1998-09-15 03:48:58 +00:00
NS_INIT_REFCNT();
mURL = nsnull;
1998-09-15 03:48:58 +00:00
mOwner = nsnull;
mInstance = nsnull;
1999-01-25 08:05:00 +00:00
mPStreamListener = nsnull;
mPluginStreamInfo = nsnull;
mSetUpListener = PR_FALSE;
mHost = nsnull;
mStreamType = nsPluginStreamType_Normal;
mStartBinding = PR_FALSE;
mLocalFile = nsnull;
mAbort = PR_FALSE;
mPendingRequests = 0;
mHaveFiredOnStartRequest = PR_FALSE;
mDataForwardToRequest = nsnull;
}
////////////////////////////////////////////////////////////////////////
nsPluginStreamListenerPeer::~nsPluginStreamListenerPeer()
{
#ifdef PLUGIN_LOGGING
char* urlSpec = nsnull;
if(mURL != nsnull) (void)mURL->GetSpec(&urlSpec);
PR_LOG(nsPluginLogging::gPluginLog, PLUGIN_LOG_NORMAL,
("nsPluginStreamListenerPeer::dtor url=%s, POST_file=%s\n", urlSpec, mLocalFile));
PR_LogFlush();
if (urlSpec) nsCRT::free(urlSpec);
1998-09-15 03:48:58 +00:00
#endif
1999-01-25 08:05:00 +00:00
NS_IF_RELEASE(mURL);
1998-09-15 03:48:58 +00:00
NS_IF_RELEASE(mOwner);
NS_IF_RELEASE(mInstance);
1999-01-25 08:05:00 +00:00
NS_IF_RELEASE(mPStreamListener);
NS_IF_RELEASE(mHost);
NS_IF_RELEASE(mPluginStreamInfo);
// if we have mLocalFile (temp file used to post data) it should be
// safe to delete it now, and hopefully the owner doesn't hold it.
if(mLocalFile)
{
nsCOMPtr<nsILocalFile> localFile;
nsresult res = NS_NewLocalFile(mLocalFile, PR_FALSE, getter_AddRefs(localFile));
if(NS_SUCCEEDED(res))
localFile->Remove(PR_FALSE);
delete [] mLocalFile;
}
delete mDataForwardToRequest;
}
////////////////////////////////////////////////////////////////////////
NS_IMPL_ISUPPORTS3(nsPluginStreamListenerPeer,
nsIStreamListener,
nsIRequestObserver,
nsIHttpHeaderVisitor)
////////////////////////////////////////////////////////////////////////
1999-01-25 08:05:00 +00:00
/* Called as a result of GetURL and PostURL */
////////////////////////////////////////////////////////////////////////
nsresult nsPluginStreamListenerPeer::Initialize(nsIURI *aURL,
nsIPluginInstance *aInstance,
nsIPluginStreamListener* aListener,
PRInt32 requestCount)
1999-01-25 08:05:00 +00:00
{
#ifdef PLUGIN_LOGGING
char* urlSpec = nsnull;
if(aURL != nsnull) (void)aURL->GetSpec(&urlSpec);
PR_LOG(nsPluginLogging::gPluginLog, PLUGIN_LOG_NORMAL,
("nsPluginStreamListenerPeer::Initialize instance=%p, url=%s\n", aInstance, urlSpec));
PR_LogFlush();
if (urlSpec) nsCRT::free(urlSpec);
1999-01-25 08:05:00 +00:00
#endif
mURL = aURL;
NS_ADDREF(mURL);
mInstance = aInstance;
NS_ADDREF(mInstance);
mPStreamListener = aListener;
NS_ADDREF(mPStreamListener);
mPluginStreamInfo = new nsPluginStreamInfo();
if (!mPluginStreamInfo)
return NS_ERROR_OUT_OF_MEMORY;
NS_ADDREF(mPluginStreamInfo);
mPluginStreamInfo->SetPluginInstance(aInstance);
mPluginStreamInfo->SetPluginStreamListenerPeer(this);
mPendingRequests = requestCount;
mDataForwardToRequest = new nsHashtable(16, PR_FALSE);
if (!mDataForwardToRequest)
return NS_ERROR_FAILURE;
return NS_OK;
}
1999-01-25 08:05:00 +00:00
/*
Called by NewEmbededPluginStream() - if this is called, we weren't
able to load the plugin, so we need to load it later once we figure
out the mimetype. In order to load it later, we need the plugin
host and instance owner.
1999-01-25 08:05:00 +00:00
*/
////////////////////////////////////////////////////////////////////////
nsresult nsPluginStreamListenerPeer::InitializeEmbeded(nsIURI *aURL,
nsIPluginInstance* aInstance,
nsIPluginInstanceOwner *aOwner,
nsIPluginHost *aHost)
{
#ifdef PLUGIN_LOGGING
char* urlSpec = nsnull;
if(aURL != nsnull) (void)aURL->GetSpec(&urlSpec);
PR_LOG(nsPluginLogging::gPluginLog, PLUGIN_LOG_NORMAL,
("nsPluginStreamListenerPeer::InitializeEmbeded url=%s\n", urlSpec));
PR_LogFlush();
if (urlSpec) nsCRT::free(urlSpec);
1998-09-15 03:48:58 +00:00
#endif
1999-01-25 08:05:00 +00:00
mURL = aURL;
NS_ADDREF(mURL);
if(aInstance != nsnull) {
NS_ASSERTION(mInstance == nsnull, "nsPluginStreamListenerPeer::InitializeEmbeded mInstance != nsnull");
mInstance = aInstance;
NS_ADDREF(mInstance);
} else {
mOwner = aOwner;
NS_IF_ADDREF(mOwner);
1999-01-25 08:05:00 +00:00
mHost = aHost;
NS_IF_ADDREF(mHost);
1999-01-25 08:05:00 +00:00
}
1999-01-25 08:05:00 +00:00
mPluginStreamInfo = new nsPluginStreamInfo();
if (!mPluginStreamInfo)
return NS_ERROR_OUT_OF_MEMORY;
NS_ADDREF(mPluginStreamInfo);
mPluginStreamInfo->SetPluginInstance(aInstance);
mPluginStreamInfo->SetPluginStreamListenerPeer(this);
mDataForwardToRequest = new nsHashtable(16, PR_FALSE);
if (!mDataForwardToRequest)
return NS_ERROR_FAILURE;
return NS_OK;
}
1999-01-25 08:05:00 +00:00
/* Called by NewFullPagePluginStream() */
////////////////////////////////////////////////////////////////////////
nsresult nsPluginStreamListenerPeer::InitializeFullPage(nsIPluginInstance *aInstance)
1998-09-15 03:48:58 +00:00
{
PLUGIN_LOG(PLUGIN_LOG_NORMAL,
("nsPluginStreamListenerPeer::InitializeFullPage instance=%p\n",aInstance));
NS_ASSERTION(mInstance == nsnull, "nsPluginStreamListenerPeer::InitializeFullPage mInstance != nsnull");
1998-09-15 03:48:58 +00:00
mInstance = aInstance;
NS_ADDREF(mInstance);
1999-01-25 08:05:00 +00:00
mPluginStreamInfo = new nsPluginStreamInfo();
if (!mPluginStreamInfo)
return NS_ERROR_OUT_OF_MEMORY;
1998-09-15 03:48:58 +00:00
NS_ADDREF(mPluginStreamInfo);
mPluginStreamInfo->SetPluginInstance(aInstance);
mPluginStreamInfo->SetPluginStreamListenerPeer(this);
mDataForwardToRequest = new nsHashtable(16, PR_FALSE);
if (!mDataForwardToRequest)
return NS_ERROR_FAILURE;
1998-09-15 03:48:58 +00:00
return NS_OK;
}
1999-01-25 08:05:00 +00:00
////////////////////////////////////////////////////////////////////////
// SetupPluginCacheFile is called if we have to save the stream to disk.
// the most likely cause for this is either there is no disk cache available
// or the stream is coming from a https server.
//
// These files will be deleted when the host is destroyed.
//
// TODO? What if we fill up the the dest dir?
nsresult
nsPluginStreamListenerPeer::SetupPluginCacheFile(nsIChannel* channel)
{
nsresult rv;
// Is this the best place to put this temp file?
nsCOMPtr<nsIFile> pluginTmp;
rv = NS_GetSpecialDirectory(NS_OS_TEMP_DIR, getter_AddRefs(pluginTmp));
if (NS_FAILED(rv)) return rv;
rv = pluginTmp->Append(kPluginTmpDirName);
if (NS_FAILED(rv)) return rv;
(void) pluginTmp->Create(nsIFile::DIRECTORY_TYPE,0777);
// Get the filename from the channel
nsCOMPtr<nsIURI> uri;
rv = channel->GetURI(getter_AddRefs(uri));
if (NS_FAILED(rv)) return rv;
nsCOMPtr<nsIURL> url(do_QueryInterface(uri));
if(!url)
return NS_ERROR_FAILURE;
nsXPIDLCString filename;
url->GetFileName(getter_Copies(filename));
if (NS_FAILED(rv)) return rv;
// Create a file to save our stream into. Should we scramble the name?
rv = pluginTmp->Append(filename);
if (NS_FAILED(rv)) return rv;
// Yes, make it unique.
rv = pluginTmp->CreateUnique(nsIFile::NORMAL_FILE_TYPE, 0777);
if (NS_FAILED(rv)) return rv;
// save the file path off.
nsXPIDLCString saveToFilename;
(void) pluginTmp->GetPath(getter_Copies(saveToFilename));
mPluginStreamInfo->SetLocalCachedFile(saveToFilename);
// create a file output stream to write to...
nsCOMPtr<nsIOutputStream> outstream;
rv = NS_NewLocalFileOutputStream(getter_AddRefs(outstream), pluginTmp, -1, 00600);
if (NS_FAILED(rv)) return rv;
mPluginStreamInfo->SetLocalCachedFileStream(outstream);
return NS_OK;
}
////////////////////////////////////////////////////////////////////////
NS_IMETHODIMP
nsPluginStreamListenerPeer::OnStartRequest(nsIRequest *request, nsISupports* aContext)
{
nsresult rv = NS_OK;
if (mHaveFiredOnStartRequest) {
return NS_OK;
}
mHaveFiredOnStartRequest = PR_TRUE;
// do a little sanity check to make sure our frame isn't gone
// by getting the tag type and checking for an error, we can determine if
// the frame is gone
if (mOwner) {
nsCOMPtr<nsIPluginTagInfo2> pti2 = do_QueryInterface(mOwner);
NS_ENSURE_TRUE(pti2, NS_ERROR_FAILURE);
nsPluginTagType tagType;
if (NS_FAILED(pti2->GetTagType(&tagType)))
return NS_ERROR_FAILURE; // something happened to our object frame, so bail!
}
nsCOMPtr<nsIChannel> channel = do_QueryInterface(request);
NS_ENSURE_TRUE(channel, NS_ERROR_FAILURE);
nsCOMPtr<nsICachingChannel> cacheChannel = do_QueryInterface(channel, &rv);
if (cacheChannel)
rv = cacheChannel->SetCacheAsFile(PR_TRUE);
if (NS_FAILED(rv)) {
// The channel doesn't want to do our bidding, lets cache it to disk ourselves
rv = SetupPluginCacheFile(channel);
if (NS_FAILED(rv))
NS_WARNING("No Cache Aval. Some plugins wont work OR we don't have a URL");
}
char* aContentType = nsnull;
rv = channel->GetContentType(&aContentType);
if (NS_FAILED(rv)) return rv;
nsCOMPtr<nsIURI> aURL;
rv = channel->GetURI(getter_AddRefs(aURL));
if (NS_FAILED(rv)) return rv;
1999-06-25 00:03:22 +00:00
if (nsnull != aContentType)
mPluginStreamInfo->SetContentType(aContentType);
#ifdef PLUGIN_LOGGING
char* urlSpec = nsnull;
if(aURL != nsnull) (void)aURL->GetSpec(&urlSpec);
PR_LOG(nsPluginLogging::gPluginLog, PLUGIN_LOG_NOISY,
("nsPluginStreamListenerPeer::OnStartRequest request=%p mime=%s, url=%s\n",
request, aContentType, urlSpec));
PR_LogFlush();
if (urlSpec) nsCRT::free(urlSpec);
#endif
1998-09-15 03:48:58 +00:00
nsPluginWindow *window = nsnull;
1999-01-25 08:05:00 +00:00
// if we don't have an nsIPluginInstance (mInstance), it means
// we weren't able to load a plugin previously because we
// didn't have the mimetype. Now that we do (aContentType),
// we'll try again with SetUpPluginInstance()
// which is called by InstantiateEmbededPlugin()
// NOTE: we don't want to try again if we didn't get the MIME type this time
1999-01-25 08:05:00 +00:00
if ((nsnull == mInstance) && (nsnull != mOwner) && (nsnull != aContentType))
{
1999-01-25 08:05:00 +00:00
mOwner->GetInstance(mInstance);
1998-09-15 03:48:58 +00:00
mOwner->GetWindow(window);
1999-01-25 08:05:00 +00:00
if ((nsnull == mInstance) && (nsnull != mHost) && (nsnull != window))
{
// determine if we need to try embedded again. FullPage takes a different code path
nsPluginMode mode;
mOwner->GetMode(&mode);
if (mode == nsPluginMode_Embedded)
rv = mHost->InstantiateEmbededPlugin(aContentType, aURL, mOwner);
else
rv = mHost->SetUpPluginInstance(aContentType, aURL, mOwner);
1998-09-15 03:48:58 +00:00
if (NS_OK == rv)
{
// GetInstance() adds a ref
1999-01-25 08:05:00 +00:00
mOwner->GetInstance(mInstance);
1999-01-25 08:05:00 +00:00
if (nsnull != mInstance)
1998-09-15 03:48:58 +00:00
{
1999-01-25 08:05:00 +00:00
mInstance->Start();
1998-09-15 03:48:58 +00:00
mOwner->CreateWidget();
// If we've got a native window, the let the plugin know
// about it.
if (window->window)
mInstance->SetWindow(window);
1998-09-15 03:48:58 +00:00
}
}
}
}
1998-09-15 03:48:58 +00:00
nsCRT::free(aContentType);
//
// Set up the stream listener...
//
PRInt32 length;
rv = channel->GetContentLength(&length);
// it's possible for the server to not send a Content-Length. We should
// still work in this case.
if (NS_FAILED(rv)) {
mPluginStreamInfo->SetLength(-1);
}
else {
mPluginStreamInfo->SetLength(length);
}
rv = SetUpStreamListener(request, aURL);
if (NS_FAILED(rv)) return rv;
return rv;
}
1999-01-25 08:05:00 +00:00
////////////////////////////////////////////////////////////////////////
NS_IMETHODIMP nsPluginStreamListenerPeer::OnProgress(nsIRequest *request,
nsISupports* aContext,
PRUint32 aProgress,
PRUint32 aProgressMax)
{
nsresult rv = NS_OK;
return rv;
}
////////////////////////////////////////////////////////////////////////
NS_IMETHODIMP nsPluginStreamListenerPeer::OnStatus(nsIRequest *request,
nsISupports* aContext,
nsresult aStatus,
const PRUnichar* aStatusArg)
1999-01-25 08:05:00 +00:00
{
return NS_OK;
}
1999-06-25 00:03:22 +00:00
////////////////////////////////////////////////////////////////////////
class nsPRUintKey : public nsHashKey {
protected:
PRUint32 mKey;
public:
nsPRUintKey(PRUint32 key) : mKey(key) {}
PRUint32 HashCode(void) const {
return mKey;
}
PRBool Equals(const nsHashKey *aKey) const {
return mKey == ((const nsPRUintKey *) aKey)->mKey;
}
nsHashKey *Clone() const {
return new nsPRUintKey(mKey);
}
PRUint32 GetValue() { return mKey; }
};
////////////////////////////////////////////////////////////////////////
NS_IMETHODIMP nsPluginStreamListenerPeer::OnDataAvailable(nsIRequest *request,
nsISupports* aContext,
nsIInputStream *aIStream,
PRUint32 sourceOffset,
PRUint32 aLength)
{
if(mAbort)
{
PRUint32 magicNumber = 0; // set it to something that is not the magic number.
nsCOMPtr<nsISupportsPRUint32> container = do_QueryInterface(aContext);
if (container)
container->GetData(&magicNumber);
if (magicNumber != MAGIC_REQUEST_CONTEXT)
{
// this is not one of our range requests
mAbort = PR_FALSE;
return NS_BINDING_ABORTED;
}
}
nsresult rv = NS_OK;
nsCOMPtr<nsIURI> aURL;
nsCOMPtr<nsIChannel> channel = do_QueryInterface(request);
if (!channel)
return NS_ERROR_FAILURE;
rv = channel->GetURI(getter_AddRefs(aURL));
if (NS_FAILED(rv))
return rv;
if(!mPStreamListener)
return NS_ERROR_FAILURE;
1999-01-25 08:05:00 +00:00
char* urlString;
aURL->GetSpec(&urlString);
mPluginStreamInfo->SetURL(urlString);
PLUGIN_LOG(PLUGIN_LOG_NOISY,
("nsPluginStreamListenerPeer::OnDataAvailable request=%p, offset=%d, length=%d, url=%s\n",
request, sourceOffset, aLength, urlString));
nsCRT::free(urlString);
// if the plugin has requested an AsFileOnly stream, then don't
// call OnDataAvailable
if(mStreamType != nsPluginStreamType_AsFileOnly)
{
// get the absolute offset of the request, if one exists.
nsCOMPtr<nsIByteRangeRequest> brr = do_QueryInterface(request);
PRInt32 absoluteOffset = 0;
PRInt32 amtForwardToPlugin = 0;
if (brr) {
brr->GetStartRange(&absoluteOffset);
// we need to track how much data we have forward on to the plugin.
nsPRUintKey key(absoluteOffset);
if (!mDataForwardToRequest)
return NS_ERROR_FAILURE;
if (mDataForwardToRequest->Exists(&key))
amtForwardToPlugin = NS_PTR_TO_INT32(mDataForwardToRequest->Remove(&key));
mDataForwardToRequest->Put(&key, (void*) (amtForwardToPlugin+aLength));
}
nsCOMPtr<nsIInputStream> stream = aIStream;
// if we are caching the file ourselves to disk, we want to 'tee' off
// the data as the plugin read from the stream. We do this by the magic
// of an input stream tee.
nsCOMPtr<nsIOutputStream> outStream;
mPluginStreamInfo->GetLocalCachedFileStream(getter_AddRefs(outStream));
if (outStream) {
rv = NS_NewInputStreamTee(getter_AddRefs(stream), aIStream, outStream);
if (NS_FAILED(rv))
return rv;
}
nsCOMPtr<nsIPluginStreamListener2> PStreamListener2 = do_QueryInterface(mPStreamListener);
if (PStreamListener2 && brr)
rv = PStreamListener2->OnDataAvailable((nsIPluginStreamInfo*)mPluginStreamInfo,
stream,
absoluteOffset+amtForwardToPlugin,
aLength);
else
rv = mPStreamListener->OnDataAvailable((nsIPluginStreamInfo*)mPluginStreamInfo,
stream,
aLength);
// if a plugin returns an error, the peer must kill the stream
// else the stream and PluginStreamListener leak
if (NS_FAILED(rv))
request->Cancel(rv);
1999-04-06 01:53:37 +00:00
}
else
{
// if we don't read from the stream, OnStopRequest will never be called
1999-04-06 01:53:37 +00:00
char* buffer = new char[aLength];
PRUint32 amountRead, amountWrote = 0;
1999-04-06 01:53:37 +00:00
rv = aIStream->Read(buffer, aLength, &amountRead);
// if we are caching this to disk ourselves, lets write the bytes out.
nsCOMPtr<nsIOutputStream> outStream;
mPluginStreamInfo->GetLocalCachedFileStream(getter_AddRefs(outStream));
while (outStream && amountWrote < amountRead && NS_SUCCEEDED(rv))
rv = outStream->Write(buffer, amountRead, &amountWrote);
1999-04-06 01:53:37 +00:00
delete [] buffer;
}
return rv;
}
////////////////////////////////////////////////////////////////////////
NS_IMETHODIMP nsPluginStreamListenerPeer::OnStopRequest(nsIRequest *request,
nsISupports* aContext,
nsresult aStatus)
{
nsresult rv = NS_OK;
nsCOMPtr<nsICachingChannel> cacheChannel = do_QueryInterface(request);
nsCOMPtr<nsIFile> localFile;
nsXPIDLCString pathAndFilename;
// doing multiple requests, the main url load (the cacheable entry) could come
// out of order. Here we will check to see if the request is main url load.
if (cacheChannel) {
rv = cacheChannel->GetCacheFile(getter_AddRefs(localFile));
if (NS_SUCCEEDED(rv)) {
localFile->GetPath(getter_Copies(pathAndFilename));
mPluginStreamInfo->SetLocalCachedFile(pathAndFilename);
}
}
PLUGIN_LOG(PLUGIN_LOG_NOISY,
("nsPluginStreamListenerPeer::OnStopAvailable request=%p, cachefile=%s\n",
request, pathAndFilename.get()));
// If we are writting the stream to disk ourselves, lets close it
nsCOMPtr<nsIOutputStream> outStream;
mPluginStreamInfo->GetLocalCachedFileStream(getter_AddRefs(outStream));
if (outStream) {
outStream->Close();
}
// remove the request from our data forwarding count hash.
nsCOMPtr<nsIByteRangeRequest> brr = do_QueryInterface(request);
if (brr) {
PRInt32 absoluteOffset = 0;
brr->GetStartRange(&absoluteOffset);
nsPRUintKey key(absoluteOffset);
if (!mDataForwardToRequest)
return NS_ERROR_FAILURE;
(void) mDataForwardToRequest->Remove(&key);
}
// if we still have pending stuff to do, lets not close the plugin socket.
if (--mPendingRequests > 0)
return NS_OK;
// we keep our connections around...
PRUint32 magicNumber = 0; // set it to something that is not the magic number.
nsCOMPtr<nsISupportsPRUint32> container = do_QueryInterface(aContext);
if (container)
container->GetData(&magicNumber);
if (magicNumber == MAGIC_REQUEST_CONTEXT)
{
// this is one of our range requests
return NS_OK;
}
if(!mPStreamListener)
return NS_ERROR_FAILURE;
if (!pathAndFilename)
mPluginStreamInfo->GetLocalCachedFile(getter_Copies(pathAndFilename));
if (!pathAndFilename || 0 == *pathAndFilename) {
// see if it is a file channel.
nsCOMPtr<nsIFileChannel> fileChannel = do_QueryInterface(request);
if (fileChannel)
fileChannel->GetFile(getter_AddRefs(localFile));
if (localFile)
localFile->GetPath(getter_Copies(pathAndFilename));
mPluginStreamInfo->SetLocalCachedFile(pathAndFilename);
}
if (pathAndFilename)
OnFileAvailable(pathAndFilename);
nsCOMPtr<nsIURI> aURL;
nsCOMPtr<nsIChannel> channel = do_QueryInterface(request);
if (!channel)
return NS_ERROR_FAILURE;
rv = channel->GetURI(getter_AddRefs(aURL));
if (NS_FAILED(rv))
return rv;
nsXPIDLCString urlString;
rv = aURL->GetSpec(getter_Copies(urlString));
if (NS_SUCCEEDED(rv))
mPluginStreamInfo->SetURL(urlString);
// Set the content type to ensure we don't pass null to the plugin
nsXPIDLCString aContentType;
rv = channel->GetContentType(getter_Copies(aContentType));
if (NS_FAILED(rv))
return rv;
1998-09-15 03:48:58 +00:00
if (aContentType)
mPluginStreamInfo->SetContentType(aContentType);
if (mStartBinding)
{
// On start binding has been called
mPStreamListener->OnStopBinding((nsIPluginStreamInfo*)mPluginStreamInfo, aStatus);
}
else
{
// OnStartBinding hasn't been called, so complete the action.
mPStreamListener->OnStartBinding((nsIPluginStreamInfo*)mPluginStreamInfo);
mPStreamListener->OnStopBinding((nsIPluginStreamInfo*)mPluginStreamInfo, aStatus);
}
return NS_OK;
}
////////////////////////////////////////////////////////////////////////
// private methods for nsPluginStreamListenerPeer
nsresult nsPluginStreamListenerPeer::SetUpCache(nsIURI* aURL)
1999-01-25 08:05:00 +00:00
{
nsPluginCacheListener* cacheListener = new nsPluginCacheListener(this);
// XXX: Null LoadGroup?
return NS_OpenURI(cacheListener, nsnull, aURL, nsnull);
1999-01-25 08:05:00 +00:00
}
////////////////////////////////////////////////////////////////////////
nsresult nsPluginStreamListenerPeer::SetUpStreamListener(nsIRequest *request,
nsIURI* aURL)
1999-01-25 08:05:00 +00:00
{
nsresult rv = NS_OK;
1999-01-25 08:05:00 +00:00
// If we don't yet have a stream listener, we need to get
// one from the plugin.
// NOTE: this should only happen when a stream was NOT created
// with GetURL or PostURL (i.e. it's the initial stream we
// send to the plugin as determined by the SRC or DATA attribute)
1999-01-25 08:05:00 +00:00
if(mPStreamListener == nsnull && mInstance != nsnull)
rv = mInstance->NewStream(&mPStreamListener);
1999-01-25 08:05:00 +00:00
if(rv != NS_OK)
return rv;
1999-01-25 08:05:00 +00:00
if(mPStreamListener == nsnull)
return NS_ERROR_NULL_POINTER;
// get httpChannel to retrieve some info we need for nsIPluginStreamInfo setup
nsCOMPtr<nsIChannel> channel = do_QueryInterface(request);
nsCOMPtr<nsIHttpChannel> httpChannel = do_QueryInterface(channel);
/*
* Assumption
* By the time nsPluginStreamListenerPeer::OnDataAvailable() gets
* called, all the headers have been read.
*/
if (httpChannel)
httpChannel->VisitResponseHeaders(this);
mSetUpListener = PR_TRUE;
// set seekability (seekable if the stream has a known length and if the
// http server accepts byte ranges).
PRBool bSeekable = PR_FALSE;
PRUint32 length = -1;
mPluginStreamInfo->GetLength(&length);
if ((length != -1) && httpChannel)
{
nsXPIDLCString range;
if(NS_SUCCEEDED(httpChannel->GetResponseHeader("accept-ranges", getter_Copies(range))))
{
if (0 == PL_strcasecmp(range.get(), "bytes"))
bSeekable = PR_TRUE;
}
}
mPluginStreamInfo->SetSeekable(bSeekable);
2001-07-17 01:19:19 +00:00
// we require a content len
// get Last-Modified header for plugin info
if (httpChannel)
{
char * lastModified = nsnull;
if (NS_SUCCEEDED(httpChannel->GetResponseHeader("last-modified", &lastModified)) &&
lastModified)
{
PRTime time64;
PR_ParseTimeString(lastModified, PR_TRUE, &time64); //convert string time to interger time
// Convert PRTime to unix-style time_t, i.e. seconds since the epoch
double fpTime;
LL_L2D(fpTime, time64);
mPluginStreamInfo->SetLastModified((PRUint32)(fpTime * 1e-6 + 0.5));
nsCRT::free(lastModified);
}
}
1999-01-25 08:05:00 +00:00
char* urlString;
aURL->GetSpec(&urlString);
mPluginStreamInfo->SetURL(urlString);
nsCRT::free(urlString);
rv = mPStreamListener->OnStartBinding((nsIPluginStreamInfo*)mPluginStreamInfo);
mStartBinding = PR_TRUE;
if (NS_SUCCEEDED(rv)) {
mPStreamListener->GetStreamType(&mStreamType);
}
return rv;
}
////////////////////////////////////////////////////////////////////////
nsresult
nsPluginStreamListenerPeer::OnFileAvailable(const char* aFilename)
{
nsresult rv;
if (!mPStreamListener)
return NS_ERROR_FAILURE;
rv = mPStreamListener->OnFileAvailable((nsIPluginStreamInfo*)mPluginStreamInfo, aFilename);
return rv;
}
////////////////////////////////////////////////////////////////////////
nsILoadGroup*
nsPluginStreamListenerPeer::GetLoadGroup()
{
nsILoadGroup* loadGroup = nsnull;
nsIDocument* doc;
nsresult rv = mOwner->GetDocument(&doc);
if (NS_SUCCEEDED(rv)) {
doc->GetDocumentLoadGroup(&loadGroup);
NS_RELEASE(doc);
}
return loadGroup;
}
////////////////////////////////////////////////////////////////////////
a=brendan,av r=av bug=50811 This bug fix was suggested by Stanley Ho <stanley.ho@eng.sun.com>. Stanley proposed we overload the meaning of the nsIPluginStreamListener argument to nsIPluginManager::{GetURL,PostURL}() so that it also may implement an interface for reading headers. Thus, the browser could QI the plugin's nsIPluginStreamListener instance to this headers reading interface and send the plugin the headers from the response. I have implemented Stanley's above proposal. I have defined a new interface, nsIHTTPHeaderListener.idl with one method: /** * Called for each HTTP Response header. * NOTE: You must copy the values of the params. */ void newResponseHeader(in string headerName, in string headerValue); To affect this fix, I have added a new private method nsPluginStreamListenerPeer:: ReadHeadersFromChannelAndPostToListener(nsIHTTPChannel *httpChannel, nsIHTTPHeaderListener *listener) Then, modified nsPluginStreamListenerPeer::OnDataAvailable() to call this method BEFORE reading the content data. However, this fix makes two important assumptions I would like to check out: * Assumption * By the time nsPluginStreamListenerPeer::OnDataAvailable() gets * called, all the headers have been read. * Assumption: * The return value from nsIHTTPHeader->{GetFieldName,GetValue}() * must be freed. The following files are included in this fix: A modules/plugin/public/nsIHTTPHeaderListener.idl A modules/plugin/public/makefile.win A modules/plugin/public/Makefile.in M modules/plugin/nglsrc/nsPluginHostImpl.cpp
2000-09-13 07:09:38 +00:00
NS_IMETHODIMP
nsPluginStreamListenerPeer::VisitHeader(const char *header, const char *value)
a=brendan,av r=av bug=50811 This bug fix was suggested by Stanley Ho <stanley.ho@eng.sun.com>. Stanley proposed we overload the meaning of the nsIPluginStreamListener argument to nsIPluginManager::{GetURL,PostURL}() so that it also may implement an interface for reading headers. Thus, the browser could QI the plugin's nsIPluginStreamListener instance to this headers reading interface and send the plugin the headers from the response. I have implemented Stanley's above proposal. I have defined a new interface, nsIHTTPHeaderListener.idl with one method: /** * Called for each HTTP Response header. * NOTE: You must copy the values of the params. */ void newResponseHeader(in string headerName, in string headerValue); To affect this fix, I have added a new private method nsPluginStreamListenerPeer:: ReadHeadersFromChannelAndPostToListener(nsIHTTPChannel *httpChannel, nsIHTTPHeaderListener *listener) Then, modified nsPluginStreamListenerPeer::OnDataAvailable() to call this method BEFORE reading the content data. However, this fix makes two important assumptions I would like to check out: * Assumption * By the time nsPluginStreamListenerPeer::OnDataAvailable() gets * called, all the headers have been read. * Assumption: * The return value from nsIHTTPHeader->{GetFieldName,GetValue}() * must be freed. The following files are included in this fix: A modules/plugin/public/nsIHTTPHeaderListener.idl A modules/plugin/public/makefile.win A modules/plugin/public/Makefile.in M modules/plugin/nglsrc/nsPluginHostImpl.cpp
2000-09-13 07:09:38 +00:00
{
nsCOMPtr<nsIHTTPHeaderListener> listener = do_QueryInterface(mPStreamListener);
if (!listener)
return NS_ERROR_FAILURE;
a=brendan,av r=av bug=50811 This bug fix was suggested by Stanley Ho <stanley.ho@eng.sun.com>. Stanley proposed we overload the meaning of the nsIPluginStreamListener argument to nsIPluginManager::{GetURL,PostURL}() so that it also may implement an interface for reading headers. Thus, the browser could QI the plugin's nsIPluginStreamListener instance to this headers reading interface and send the plugin the headers from the response. I have implemented Stanley's above proposal. I have defined a new interface, nsIHTTPHeaderListener.idl with one method: /** * Called for each HTTP Response header. * NOTE: You must copy the values of the params. */ void newResponseHeader(in string headerName, in string headerValue); To affect this fix, I have added a new private method nsPluginStreamListenerPeer:: ReadHeadersFromChannelAndPostToListener(nsIHTTPChannel *httpChannel, nsIHTTPHeaderListener *listener) Then, modified nsPluginStreamListenerPeer::OnDataAvailable() to call this method BEFORE reading the content data. However, this fix makes two important assumptions I would like to check out: * Assumption * By the time nsPluginStreamListenerPeer::OnDataAvailable() gets * called, all the headers have been read. * Assumption: * The return value from nsIHTTPHeader->{GetFieldName,GetValue}() * must be freed. The following files are included in this fix: A modules/plugin/public/nsIHTTPHeaderListener.idl A modules/plugin/public/makefile.win A modules/plugin/public/Makefile.in M modules/plugin/nglsrc/nsPluginHostImpl.cpp
2000-09-13 07:09:38 +00:00
return listener->NewResponseHeader(header, value);
a=brendan,av r=av bug=50811 This bug fix was suggested by Stanley Ho <stanley.ho@eng.sun.com>. Stanley proposed we overload the meaning of the nsIPluginStreamListener argument to nsIPluginManager::{GetURL,PostURL}() so that it also may implement an interface for reading headers. Thus, the browser could QI the plugin's nsIPluginStreamListener instance to this headers reading interface and send the plugin the headers from the response. I have implemented Stanley's above proposal. I have defined a new interface, nsIHTTPHeaderListener.idl with one method: /** * Called for each HTTP Response header. * NOTE: You must copy the values of the params. */ void newResponseHeader(in string headerName, in string headerValue); To affect this fix, I have added a new private method nsPluginStreamListenerPeer:: ReadHeadersFromChannelAndPostToListener(nsIHTTPChannel *httpChannel, nsIHTTPHeaderListener *listener) Then, modified nsPluginStreamListenerPeer::OnDataAvailable() to call this method BEFORE reading the content data. However, this fix makes two important assumptions I would like to check out: * Assumption * By the time nsPluginStreamListenerPeer::OnDataAvailable() gets * called, all the headers have been read. * Assumption: * The return value from nsIHTTPHeader->{GetFieldName,GetValue}() * must be freed. The following files are included in this fix: A modules/plugin/public/nsIHTTPHeaderListener.idl A modules/plugin/public/makefile.win A modules/plugin/public/Makefile.in M modules/plugin/nglsrc/nsPluginHostImpl.cpp
2000-09-13 07:09:38 +00:00
}
////////////////////////////////////////////////////////////////////////
nsresult nsPluginStreamListenerPeer::SetLocalFile(const char* aFilename)
{
NS_ENSURE_ARG_POINTER(aFilename);
nsresult rv = NS_OK;
if(mLocalFile)
{
NS_ASSERTION(!mLocalFile, "nsPluginStreamListenerPeer::SetLocalFile -- path already set, cleaning...");
delete [] mLocalFile;
mLocalFile = nsnull;
}
mLocalFile = new char[PL_strlen(aFilename) + 1];
if(!mLocalFile)
return NS_ERROR_OUT_OF_MEMORY;
PL_strcpy(mLocalFile, aFilename);
return rv;
}
/////////////////////////////////////////////////////////////////////////
1999-01-25 08:05:00 +00:00
nsPluginHostImpl::nsPluginHostImpl()
{
1998-09-15 03:48:58 +00:00
NS_INIT_REFCNT();
1999-01-25 08:05:00 +00:00
mPluginsLoaded = PR_FALSE;
mDontShowBadPluginMessage = PR_FALSE;
mIsDestroyed = PR_FALSE;
mUnusedLibraries = nsnull;
nsCOMPtr<nsIObserverService> obsService = do_GetService("@mozilla.org/observer-service;1");
if (obsService)
{
obsService->AddObserver(this, "quit-application", PR_FALSE);
obsService->AddObserver(this, NS_XPCOM_SHUTDOWN_OBSERVER_ID, PR_FALSE);
}
#ifdef PLUGIN_LOGGING
nsPluginLogging::gNPNLog = PR_NewLogModule(NPN_LOG_NAME);
nsPluginLogging::gNPPLog = PR_NewLogModule(NPP_LOG_NAME);
nsPluginLogging::gPluginLog = PR_NewLogModule(PLUGIN_LOG_NAME);
PR_LOG(nsPluginLogging::gNPNLog, PLUGIN_LOG_ALWAYS,("NPN Logging Active!\n"));
PR_LOG(nsPluginLogging::gPluginLog, PLUGIN_LOG_ALWAYS,("General Plugin Logging Active! (nsPluginHostImpl::ctor)\n"));
PR_LOG(nsPluginLogging::gNPPLog, PLUGIN_LOG_ALWAYS,("NPP Logging Active!\n"));
PLUGIN_LOG(PLUGIN_LOG_ALWAYS,("nsPluginHostImpl::ctor\n"));
PR_LogFlush();
#endif
mCachedPlugins = nsnull;
mSyncCachedPlugins = PR_FALSE;
}
////////////////////////////////////////////////////////////////////////
nsPluginHostImpl::~nsPluginHostImpl()
{
PLUGIN_LOG(PLUGIN_LOG_ALWAYS,("nsPluginHostImpl::dtor\n"));
1998-09-15 03:48:58 +00:00
#ifdef NS_DEBUG
printf("nsPluginHostImpl dtor\n");
1998-09-15 03:48:58 +00:00
#endif
Destroy();
}
////////////////////////////////////////////////////////////////////////
NS_IMPL_ISUPPORTS7(nsPluginHostImpl,
nsIPluginManager,
nsIPluginManager2,
nsIPluginHost,
nsIFileUtilities,
nsICookieStorage,
nsIObserver,
nsPIPluginHost);
////////////////////////////////////////////////////////////////////////
NS_METHOD
nsPluginHostImpl::Create(nsISupports* aOuter, REFNSIID aIID, void** aResult)
{
NS_PRECONDITION(aOuter == nsnull, "no aggregation");
if (aOuter)
return NS_ERROR_NO_AGGREGATION;
nsPluginHostImpl* host = new nsPluginHostImpl();
if (! host)
return NS_ERROR_OUT_OF_MEMORY;
nsresult rv;
NS_ADDREF(host);
rv = host->QueryInterface(aIID, aResult);
NS_RELEASE(host);
return rv;
}
////////////////////////////////////////////////////////////////////////
NS_IMETHODIMP nsPluginHostImpl::GetValue(nsPluginManagerVariable aVariable, void *aValue)
{
nsresult rv = NS_OK;
NS_ENSURE_ARG_POINTER(aValue);
#if defined(XP_UNIX) && !defined(XP_MACOSX) && !defined(NO_X11)
if (nsPluginManagerVariable_XDisplay == aVariable) {
Display** value = NS_REINTERPRET_CAST(Display**, aValue);
#if defined(MOZ_WIDGET_GTK)
*value = GDK_DISPLAY();
#elif defined(MOZ_WIDGET_QT)
*value = qt_xdisplay();
#elif defined(MOZ_WIDGET_XLIB)
*value = xxlib_rgb_get_display(xxlib_find_handle(XXLIBRGB_DEFAULT_HANDLE));
#endif
if (!(*value)) {
return NS_ERROR_FAILURE;
}
}
#endif
return rv;
}
////////////////////////////////////////////////////////////////////////
PRBool nsPluginHostImpl::IsRunningPlugin(nsPluginTag * plugin)
{
if(!plugin)
return PR_FALSE;
// we can check for mLibrary to be non-zero and then querry nsIPluginInstancePeer
// in nsActivePluginList to see if plugin with matching mime type is not stopped
if(!plugin->mLibrary)
return PR_FALSE;
for(int i = 0; i < plugin->mVariants; i++)
{
nsActivePlugin * p = mActivePluginList.find(plugin->mMimeTypeArray[i]);
if(p && !p->mStopped)
return PR_TRUE;
}
return PR_FALSE;
}
////////////////////////////////////////////////////////////////////////
void nsPluginHostImpl::AddToUnusedLibraryList(PRLibrary * aLibrary)
{
NS_ASSERTION(aLibrary, "nsPluginHostImpl::AddToUnusedLibraryList: Nothing to add");
if(!aLibrary)
return;
nsUnusedLibrary * unusedLibrary = new nsUnusedLibrary(aLibrary);
if(unusedLibrary)
{
unusedLibrary->mNext = mUnusedLibraries;
mUnusedLibraries = unusedLibrary;
}
}
////////////////////////////////////////////////////////////////////////
// this will unload loaded but no longer needed libs which are
// gathered in mUnusedLibraries list, see bug #61388
void nsPluginHostImpl::CleanUnusedLibraries()
{
if(!mUnusedLibraries)
return;
while (nsnull != mUnusedLibraries)
{
nsUnusedLibrary *temp = mUnusedLibraries->mNext;
delete mUnusedLibraries;
mUnusedLibraries = temp;
}
}
////////////////////////////////////////////////////////////////////////
nsresult nsPluginHostImpl::ReloadPlugins(PRBool reloadPages)
{
PLUGIN_LOG(PLUGIN_LOG_NORMAL,
("nsPluginHostImpl::ReloadPlugins Begin reloadPages=%d, active_instance_count=%d\n",
reloadPages, mActivePluginList.mCount));
// we are re-scanning plugins. New plugins may have been added, also some
// plugins may have been removed, so we should probably shut everything down
// but don't touch running (active and not stopped) plugins
if(reloadPages)
{
// if we have currently running plugins we should set a flag not to
// unload them from memory, see bug #61388
// and form a list of libs to be unloaded later
for(nsPluginTag * p = mPlugins; p != nsnull; p = p->mNext)
{
if(IsRunningPlugin(p) && (p->mFlags & NS_PLUGIN_FLAG_OLDSCHOOL))
{
p->mCanUnloadLibrary = PR_FALSE;
AddToUnusedLibraryList(p->mLibrary);
}
}
// then stop any running plugins
mActivePluginList.stopRunning();
}
// clean active plugin list
mActivePluginList.removeAllStopped();
// shutdown plugins and kill the list if there are no running plugins
nsPluginTag * prev = nsnull;
nsPluginTag * next = nsnull;
for(nsPluginTag * p = mPlugins; p != nsnull;)
{
next = p->mNext;
// XXX only remove our plugin from the list if it's not running and not
// an XPCOM plugin. XPCOM plugins do not get a call to nsIPlugin::Shutdown
// if plugins are reloaded. This also fixes a crash on UNIX where the call
// to shutdown would break the ProxyJNI connection to the JRE after a reload.
// see bug 86591
if(!IsRunningPlugin(p) && (!p->mEntryPoint || (p->mFlags & NS_PLUGIN_FLAG_OLDSCHOOL)))
{
if(p == mPlugins)
mPlugins = next;
else
prev->mNext = next;
delete p;
p = next;
continue;
}
prev = p;
p = next;
}
// set flags
mPluginsLoaded = PR_FALSE;
//refresh the component registry first
nsComponentManager::AutoRegister(nsIComponentManagerObsolete::NS_Startup, nsnull);
// load them again
nsresult rv = LoadPlugins();
PLUGIN_LOG(PLUGIN_LOG_NORMAL,
("nsPluginHostImpl::ReloadPlugins End active_instance_count=%d\n",
mActivePluginList.mCount));
return rv;
}
#define NS_RETURN_UASTRING_SIZE 128
////////////////////////////////////////////////////////////////////////
nsresult nsPluginHostImpl::UserAgent(const char **retstring)
{
static char resultString[NS_RETURN_UASTRING_SIZE];
1998-11-22 00:22:35 +00:00
nsresult res;
nsCOMPtr<nsIHttpProtocolHandler> http = do_GetService(kHttpHandlerCID, &res);
if (NS_FAILED(res))
return res;
nsXPIDLCString uaString;
res = http->GetUserAgent(getter_Copies(uaString));
if (NS_SUCCEEDED(res))
1998-11-22 00:22:35 +00:00
{
if(NS_RETURN_UASTRING_SIZE > PL_strlen(uaString))
{
PL_strcpy(resultString, uaString);
*retstring = resultString;
}
1998-11-22 00:22:35 +00:00
else
{
1998-11-22 00:22:35 +00:00
*retstring = nsnull;
res = NS_ERROR_OUT_OF_MEMORY;
}
}
else
*retstring = nsnull;
1998-11-22 00:22:35 +00:00
PLUGIN_LOG(PLUGIN_LOG_NORMAL, ("nsPluginHostImpl::UserAgent return=%s\n", *retstring));
return res;
}
////////////////////////////////////////////////////////////////////////
1999-01-25 08:05:00 +00:00
NS_IMETHODIMP nsPluginHostImpl::GetURL(nsISupports* pluginInst,
const char* url,
const char* target,
nsIPluginStreamListener* streamListener,
const char* altHost,
const char* referrer,
PRBool forceJSEnabled)
{
return GetURLWithHeaders(pluginInst, url, target, streamListener,
altHost, referrer, forceJSEnabled, nsnull, nsnull);
}
////////////////////////////////////////////////////////////////////////
NS_IMETHODIMP nsPluginHostImpl::GetURLWithHeaders(nsISupports* pluginInst,
const char* url,
const char* target,
nsIPluginStreamListener* streamListener,
const char* altHost,
const char* referrer,
PRBool forceJSEnabled,
PRUint32 getHeadersLength,
const char* getHeaders)
1999-01-25 08:05:00 +00:00
{
2000-04-03 09:20:26 +00:00
nsAutoString string; string.AssignWithConversion(url);
1999-01-25 08:05:00 +00:00
nsIPluginInstance *instance;
nsresult rv;
// we can only send a stream back to the plugin (as specified by a
// null target) if we also have a nsIPluginStreamListener to talk to also
1999-01-25 08:05:00 +00:00
if(target == nsnull && streamListener == nsnull)
return NS_ERROR_ILLEGAL_VALUE;
1999-01-25 08:05:00 +00:00
rv = pluginInst->QueryInterface(kIPluginInstanceIID, (void **)&instance);
if (NS_SUCCEEDED(rv))
1999-01-25 08:05:00 +00:00
{
if (nsnull != target)
{
nsPluginInstancePeerImpl *peer;
rv = instance->GetPeer(NS_REINTERPRET_CAST(nsIPluginInstancePeer **, &peer));
1999-01-25 08:05:00 +00:00
if (NS_SUCCEEDED(rv))
1999-01-25 08:05:00 +00:00
{
nsCOMPtr<nsIPluginInstanceOwner> owner;
1999-01-25 08:05:00 +00:00
rv = peer->GetOwner(*getter_AddRefs(owner));
1999-01-25 08:05:00 +00:00
if (NS_SUCCEEDED(rv))
1999-01-25 08:05:00 +00:00
{
if ((0 == PL_strcmp(target, "newwindow")) ||
(0 == PL_strcmp(target, "_new")))
target = "_blank";
else if (0 == PL_strcmp(target, "_current"))
target = "_self";
rv = owner->GetURL(url, target, nsnull, 0, (void *) getHeaders,
getHeadersLength);
1999-01-25 08:05:00 +00:00
}
NS_RELEASE(peer);
}
}
if (nsnull != streamListener)
rv = NewPluginURLStream(string, instance, streamListener, nsnull,
PR_FALSE, nsnull, getHeaders, getHeadersLength);
1999-01-25 08:05:00 +00:00
NS_RELEASE(instance);
}
return rv;
}
////////////////////////////////////////////////////////////////////////
1999-01-25 08:05:00 +00:00
NS_IMETHODIMP nsPluginHostImpl::PostURL(nsISupports* pluginInst,
const char* url,
PRUint32 postDataLen,
const char* postData,
PRBool isFile,
const char* target,
nsIPluginStreamListener* streamListener,
const char* altHost,
const char* referrer,
PRBool forceJSEnabled,
PRUint32 postHeadersLength,
const char* postHeaders)
1999-01-25 08:05:00 +00:00
{
2000-04-03 09:20:26 +00:00
nsAutoString string; string.AssignWithConversion(url);
1999-01-25 08:05:00 +00:00
nsIPluginInstance *instance;
nsresult rv;
// we can only send a stream back to the plugin (as specified
// by a null target) if we also have a nsIPluginStreamListener
// to talk to also
1999-01-25 08:05:00 +00:00
if(target == nsnull && streamListener == nsnull)
return NS_ERROR_ILLEGAL_VALUE;
1999-01-25 08:05:00 +00:00
rv = pluginInst->QueryInterface(kIPluginInstanceIID, (void **)&instance);
if (NS_SUCCEEDED(rv))
1999-01-25 08:05:00 +00:00
{
nsPluginInstancePeerImpl *peer;
if (nsnull != target)
{
rv = instance->GetPeer(NS_REINTERPRET_CAST(nsIPluginInstancePeer **, &peer));
if (NS_SUCCEEDED(rv))
{
nsCOMPtr<nsIPluginInstanceOwner> owner;
rv = peer->GetOwner(*getter_AddRefs(owner));
if (NS_SUCCEEDED(rv))
{
if (!target) {
target = "_self";
}
else {
if ((0 == PL_strcmp(target, "newwindow")) ||
(0 == PL_strcmp(target, "_new")))
target = "_blank";
else if (0 == PL_strcmp(target, "_current"))
target = "_self";
}
rv = owner->GetURL(url, target, (void*)postData, postDataLen,
(void*) postHeaders, postHeadersLength, isFile);
}
NS_RELEASE(peer);
}
}
// if we don't have a target, just create a stream. This does
// NS_OpenURI()!
if (streamListener != nsnull)
rv = NewPluginURLStream(string, instance, streamListener,
postData, isFile, postDataLen,
postHeaders, postHeadersLength);
NS_RELEASE(instance);
1999-01-25 08:05:00 +00:00
}
1999-01-25 08:05:00 +00:00
return rv;
}
////////////////////////////////////////////////////////////////////////
NS_IMETHODIMP nsPluginHostImpl::RegisterPlugin(REFNSIID aCID,
const char* aPluginName,
const char* aDescription,
const char** aMimeTypes,
const char** aMimeDescriptions,
const char** aFileExtensions,
PRInt32 aCount)
{
PLUGIN_LOG(PLUGIN_LOG_NORMAL, ("nsPluginHostImpl::RegisterPlugin name=%s\n",aPluginName));
nsCOMPtr<nsIRegistry> registry = do_CreateInstance(kRegistryCID);
if (! registry)
return NS_ERROR_FAILURE;
nsresult rv;
rv = registry->OpenWellKnownRegistry(nsIRegistry::ApplicationComponentRegistry);
if (NS_FAILED(rv)) return rv;
nsCAutoString path(kPluginsRootKey);
char* cid = aCID.ToString();
if (! cid)
return NS_ERROR_OUT_OF_MEMORY;
path += '/';
path += cid;
nsMemory::Free(cid);
nsRegistryKey pluginKey;
rv = registry->AddSubtree(nsIRegistry::Common, path.get(), &pluginKey);
if (NS_FAILED(rv)) return rv;
// we use SetBytes instead of SetString to address special character issue, see Mozilla bug 108246
if(aPluginName)
registry->SetBytesUTF8(pluginKey, kPluginsNameKey, nsCRT::strlen(aPluginName) + 1, (PRUint8 *)aPluginName);
if(aDescription)
registry->SetBytesUTF8(pluginKey, kPluginsDescKey, nsCRT::strlen(aDescription) + 1, (PRUint8 *)aDescription);
for (PRInt32 i = 0; i < aCount; ++i) {
nsCAutoString mimepath;
mimepath.AppendInt(i);
nsRegistryKey key;
registry->AddSubtree(pluginKey, mimepath.get(), &key);
registry->SetStringUTF8(key, kPluginsMimeTypeKey, aMimeTypes[i]);
if(aMimeDescriptions && aMimeDescriptions[i])
registry->SetBytesUTF8(key, kPluginsMimeDescKey,
nsCRT::strlen(aMimeDescriptions[i]) + 1,
(PRUint8 *)aMimeDescriptions[i]);
registry->SetStringUTF8(key, kPluginsMimeExtKey, aFileExtensions[i]);
}
return NS_OK;
}
////////////////////////////////////////////////////////////////////////
NS_IMETHODIMP nsPluginHostImpl::UnregisterPlugin(REFNSIID aCID)
{
nsCOMPtr<nsIRegistry> registry = do_CreateInstance(kRegistryCID);
if (! registry)
return NS_ERROR_FAILURE;
nsresult rv;
rv = registry->OpenWellKnownRegistry(nsIRegistry::ApplicationComponentRegistry);
if (NS_FAILED(rv)) return rv;
nsCAutoString path("software/plugins/");
char* cid = aCID.ToString();
if (! cid)
return NS_ERROR_OUT_OF_MEMORY;
path += cid;
nsMemory::Free(cid);
return registry->RemoveSubtree(nsIRegistry::Common, path.get());
}
////////////////////////////////////////////////////////////////////////
NS_IMETHODIMP nsPluginHostImpl::BeginWaitCursor(void)
{
return NS_ERROR_NOT_IMPLEMENTED;
}
////////////////////////////////////////////////////////////////////////
NS_IMETHODIMP nsPluginHostImpl::EndWaitCursor(void)
{
return NS_ERROR_NOT_IMPLEMENTED;
}
////////////////////////////////////////////////////////////////////////
NS_IMETHODIMP nsPluginHostImpl::SupportsURLProtocol(const char* protocol, PRBool *result)
{
return NS_ERROR_NOT_IMPLEMENTED;
}
////////////////////////////////////////////////////////////////////////
NS_IMETHODIMP nsPluginHostImpl::NotifyStatusChange(nsIPlugin* plugin, nsresult errorStatus)
{
1998-09-01 00:17:25 +00:00
return NS_ERROR_NOT_IMPLEMENTED;
}
/*////////////////////////////////////////////////////////////////////////
* This method queries the prefs for proxy information.
* It has been tested and is known to work in the following three cases
* when no proxy host or port is specified
* when only the proxy host is specified
* when only the proxy port is specified
* This method conforms to the return code specified in
* http://developer.netscape.com/docs/manuals/proxy/adminnt/autoconf.htm#1020923
* with the exception that multiple values are not implemented.
*/
NS_IMETHODIMP nsPluginHostImpl::FindProxyForURL(const char* url, char* *result)
1998-09-01 00:17:25 +00:00
{
if (!url || !result) {
return NS_ERROR_INVALID_ARG;
}
nsresult res;
nsCOMPtr<nsIURI> uriIn;
nsCOMPtr<nsIProtocolProxyService> proxyService;
nsCOMPtr<nsIIOService> ioService;
PRBool isProxyEnabled;
proxyService = do_GetService(kProtocolProxyServiceCID, &res);
if (NS_FAILED(res) || !proxyService) {
return res;
}
if (NS_FAILED(proxyService->GetProxyEnabled(&isProxyEnabled))) {
return res;
}
if (!isProxyEnabled) {
*result = PL_strdup("DIRECT");
if (nsnull == *result) {
res = NS_ERROR_OUT_OF_MEMORY;
}
return res;
}
ioService = do_GetService(kIOServiceCID, &res);
if (NS_FAILED(res) || !ioService) {
return res;
}
// make an nsURI from the argument url
res = ioService->NewURI(url, nsnull, getter_AddRefs(uriIn));
if (NS_FAILED(res)) {
return res;
}
nsCOMPtr<nsIProxyInfo> pi;
res = proxyService->ExamineForProxy(uriIn,
getter_AddRefs(pi));
if (NS_FAILED(res)) {
return res;
}
if (!pi || !pi->Host() || pi->Port() <= 0) {
*result = PL_strdup("DIRECT");
} else if (!nsCRT::strcasecmp(pi->Type(), "http")) {
*result = PR_smprintf("PROXY %s:%d", pi->Host(), pi->Port());
} else if (!nsCRT::strcasecmp(pi->Type(), "socks4")) {
*result = PR_smprintf("SOCKS %s:%d", pi->Host(), pi->Port());
} else if (!nsCRT::strcasecmp(pi->Type(), "socks")) {
// XXX - this is socks5, but there is no API for us to tell the
// plugin that fact. SOCKS for now, in case the proxy server
// speaks SOCKS4 as well. See bug 78176
// For a long time this was returning an http proxy type, so
// very little is probably broken by this
*result = PR_smprintf("SOCKS %s:%d", pi->Host(), pi->Port());
} else {
NS_ASSERTION(PR_FALSE, "Unknown proxy type!");
*result = PL_strdup("DIRECT");
}
if (nsnull == *result) {
res = NS_ERROR_OUT_OF_MEMORY;
}
return res;
}
////////////////////////////////////////////////////////////////////////
NS_IMETHODIMP nsPluginHostImpl::RegisterWindow(nsIEventHandler* handler, nsPluginPlatformWindowRef window)
{
return NS_ERROR_NOT_IMPLEMENTED;
}
////////////////////////////////////////////////////////////////////////
NS_IMETHODIMP nsPluginHostImpl::UnregisterWindow(nsIEventHandler* handler, nsPluginPlatformWindowRef window)
{
return NS_ERROR_NOT_IMPLEMENTED;
}
////////////////////////////////////////////////////////////////////////
NS_IMETHODIMP nsPluginHostImpl::AllocateMenuID(nsIEventHandler* handler, PRBool isSubmenu, PRInt16 *result)
{
return NS_ERROR_NOT_IMPLEMENTED;
}
////////////////////////////////////////////////////////////////////////
NS_IMETHODIMP nsPluginHostImpl::DeallocateMenuID(nsIEventHandler* handler, PRInt16 menuID)
{
return NS_ERROR_NOT_IMPLEMENTED;
}
////////////////////////////////////////////////////////////////////////
NS_IMETHODIMP nsPluginHostImpl::HasAllocatedMenuID(nsIEventHandler* handler, PRInt16 menuID, PRBool *result)
{
return NS_ERROR_NOT_IMPLEMENTED;
}
////////////////////////////////////////////////////////////////////////
NS_IMETHODIMP nsPluginHostImpl::ProcessNextEvent(PRBool *bEventHandled)
{
1998-09-01 00:17:25 +00:00
return NS_ERROR_NOT_IMPLEMENTED;
1998-08-01 05:46:47 +00:00
}
////////////////////////////////////////////////////////////////////////
NS_IMETHODIMP nsPluginHostImpl::CreateInstance(nsISupports *aOuter,
REFNSIID aIID,
void **aResult)
{
NS_NOTREACHED("how'd I get here?");
return NS_ERROR_UNEXPECTED;
}
////////////////////////////////////////////////////////////////////////
NS_IMETHODIMP nsPluginHostImpl::LockFactory(PRBool aLock)
{
NS_NOTREACHED("how'd I get here?");
return NS_ERROR_UNEXPECTED;
}
////////////////////////////////////////////////////////////////////////
NS_IMETHODIMP nsPluginHostImpl::Init(void)
{
1999-03-02 22:33:32 +00:00
return NS_OK;
}
////////////////////////////////////////////////////////////////////////
NS_IMETHODIMP nsPluginHostImpl::Destroy(void)
1998-09-15 03:48:58 +00:00
{
PLUGIN_LOG(PLUGIN_LOG_NORMAL, ("nsPluginHostImpl::Destroy Called\n"));
if (mIsDestroyed)
return NS_OK;
1999-05-17 21:26:48 +00:00
mIsDestroyed = PR_TRUE;
1998-09-15 03:48:58 +00:00
// we should call nsIPluginInstance::Stop and nsIPluginInstance::SetWindow
// for those plugins who want it
mActivePluginList.stopRunning();
// at this point nsIPlugin::Shutdown calls will be performed if needed
mActivePluginList.shut();
1998-09-15 03:48:58 +00:00
if (nsnull != mPluginPath)
{
PR_Free(mPluginPath);
mPluginPath = nsnull;
}
while (nsnull != mPlugins)
{
nsPluginTag *temp = mPlugins->mNext;
// while walking through the list of the plugins see if we still have anything
// to shutdown some plugins may have never created an instance but still expect
// the shutdown call see bugzilla bug 73071
// with current logic, no need to do anything special as nsIPlugin::Shutdown
// will be performed in the destructor
delete mPlugins;
mPlugins = temp;
}
// Delete any remaining cached plugins list
while (mCachedPlugins)
{
nsPluginTag *next = mCachedPlugins->mNext;
delete mCachedPlugins;
mCachedPlugins = next;
}
CleanUnusedLibraries();
// Lets remove any of the temporary files that we created.
nsCOMPtr<nsIFile> pluginTmp;
nsresult rv = NS_GetSpecialDirectory(NS_OS_TEMP_DIR, getter_AddRefs(pluginTmp));
if (NS_FAILED(rv)) return rv;
rv = pluginTmp->Append(kPluginTmpDirName);
if (NS_FAILED(rv)) return rv;
pluginTmp->Remove(PR_TRUE);
if (mPrivateDirServiceProvider)
{
nsCOMPtr<nsIDirectoryService> dirService(do_GetService(kDirectoryServiceContractID, &rv));
if (NS_SUCCEEDED(rv))
dirService->UnregisterProvider(mPrivateDirServiceProvider);
mPrivateDirServiceProvider = nsnull;
}
1998-09-15 03:48:58 +00:00
return NS_OK;
}
////////////////////////////////////////////////////////////////////////
1999-01-25 08:05:00 +00:00
/* Called by nsPluginInstanceOwner (nsObjectFrame.cpp - embeded case) */
NS_IMETHODIMP nsPluginHostImpl::InstantiateEmbededPlugin(const char *aMimeType,
nsIURI* aURL,
nsIPluginInstanceOwner *aOwner)
1999-01-25 08:05:00 +00:00
{
#ifdef PLUGIN_LOGGING
char* urlSpec = nsnull;
if(aURL != nsnull) (void)aURL->GetSpec(&urlSpec);
PR_LOG(nsPluginLogging::gPluginLog, PLUGIN_LOG_NORMAL,
("nsPluginHostImpl::InstatiateEmbededPlugin Begin mime=%s, owner=%p, url=%s\n",
aMimeType, aOwner, urlSpec));
PR_LogFlush();
if (urlSpec) nsCRT::free(urlSpec);
#endif
1999-01-25 08:05:00 +00:00
nsresult rv;
nsIPluginInstance *instance = nsnull;
nsCOMPtr<nsIPluginTagInfo2> pti2;
nsPluginTagType tagType;
PRBool isJavaEnabled = PR_TRUE;
rv = aOwner->QueryInterface(kIPluginTagInfo2IID, getter_AddRefs(pti2));
if(rv != NS_OK) {
return rv;
}
rv = pti2->GetTagType(&tagType);
if((rv != NS_OK) || !((tagType == nsPluginTagType_Embed)
2000-06-22 23:17:50 +00:00
|| (tagType == nsPluginTagType_Applet)
|| (tagType == nsPluginTagType_Object)))
{
return rv;
}
1998-08-21 01:12:53 +00:00
if (tagType == nsPluginTagType_Applet) {
nsCOMPtr<nsIPref> prefs(do_GetService(kPrefServiceCID));
// see if java is enabled
if (prefs) {
rv = prefs->GetBoolPref("security.enable_java", &isJavaEnabled);
if (NS_SUCCEEDED(rv)) {
// if not, don't show this plugin
if (!isJavaEnabled) {
return NS_ERROR_FAILURE;
}
}
else {
// if we were unable to get the pref, assume java is enabled
// and rely on the "find the plugin or not" logic.
// make sure the value wasn't modified in GetBoolPref
isJavaEnabled = PR_TRUE;
}
}
}
if(FindStoppedPluginForURL(aURL, aOwner) == NS_OK) {
PLUGIN_LOG(PLUGIN_LOG_NOISY,
("nsPluginHostImpl::InstatiateEmbededPlugin FoundStopped mime=%s\n", aMimeType));
aOwner->GetInstance(instance);
if(!aMimeType || PL_strcasecmp(aMimeType, "application/x-java-vm"))
rv = NewEmbededPluginStream(aURL, nsnull, instance);
// notify Java DOM component
nsresult res;
nsCOMPtr<nsIPluginInstanceOwner> javaDOM =
do_GetService("@mozilla.org/blackwood/java-dom;1", &res);
if (NS_SUCCEEDED(res) && javaDOM)
javaDOM->SetInstance(instance);
NS_IF_RELEASE(instance);
return NS_OK;
}
// if we don't have a MIME type at this point, we still have one more chance by
// opening the stream and seeing if the server hands one back
if (!aMimeType)
if (aURL)
{
rv = NewEmbededPluginStream(aURL, aOwner, nsnull);
return rv;
} else
return NS_ERROR_FAILURE;
rv = SetUpPluginInstance(aMimeType, aURL, aOwner);
if(rv == NS_OK)
rv = aOwner->GetInstance(instance);
else
{
// We have the mime type either supplied in source or from the header.
// Let's try to render the default plugin. See bug 41197
2000-05-06 06:00:48 +00:00
// We were unable to find a plug-in yet we
// really do have mime type. Return the error
// so that the nsObjectFrame can render any
// alternate content.
// but try to load the default plugin first. We need to do this
// for <embed> tag leaving <object> to play with its alt content.
// but before we return an error let's see if this is an <embed>
// tag and try to launch the default plugin
2000-06-22 23:17:50 +00:00
// but to comply with the spec don't do it for <object> tag
if(tagType == nsPluginTagType_Object)
return rv;
nsresult result;
result = SetUpDefaultPluginInstance(aMimeType, aURL, aOwner);
if(result == NS_OK)
result = aOwner->GetInstance(instance);
if(result != NS_OK) {
DisplayNoDefaultPluginDialog(aMimeType);
return NS_ERROR_FAILURE;
}
rv = NS_OK;
}
1998-08-21 01:12:53 +00:00
// if we have a failure error, it means we found a plugin for the mimetype,
// but we had a problem with the entry point
if(rv == NS_ERROR_FAILURE)
return rv;
// if we are here then we have loaded a plugin for this mimetype
// and it could be the Default plugin
nsPluginWindow *window = nsnull;
1998-08-21 01:12:53 +00:00
//we got a plugin built, now stream
aOwner->GetWindow(window);
1998-08-21 01:12:53 +00:00
if (nsnull != instance)
{
instance->Start();
aOwner->CreateWidget();
// If we've got a native window, the let the plugin know about it.
if (window->window)
instance->SetWindow(window);
// create an initial stream with data
// don't make the stream if it's a java applet or we don't have SRC or DATA attribute
PRBool applet = (PL_strcasecmp(aMimeType, "application/x-java-vm") == 0 ||
PL_strcasecmp(aMimeType, "application/x-java-applet") == 0);
PRBool havedata = PR_FALSE;
nsCOMPtr<nsIPluginTagInfo> pti(do_QueryInterface(aOwner, &rv));
if(pti) {
const char *value;
if(tagType == nsPluginTagType_Embed)
havedata = NS_SUCCEEDED(pti->GetAttribute("SRC", &value));
if(tagType == nsPluginTagType_Object)
havedata = NS_SUCCEEDED(pti->GetAttribute("DATA", &value));
1999-01-25 08:05:00 +00:00
}
1998-08-21 01:12:53 +00:00
if(havedata && !applet)
rv = NewEmbededPluginStream(aURL, nsnull, instance);
// notify Java DOM component
nsresult res;
nsCOMPtr<nsIPluginInstanceOwner> javaDOM =
do_GetService("@mozilla.org/blackwood/java-dom;1", &res);
if (NS_SUCCEEDED(res) && javaDOM)
javaDOM->SetInstance(instance);
NS_RELEASE(instance);
}
#ifdef PLUGIN_LOGGING
char* urlSpec2 = nsnull;
if(aURL != nsnull) (void)aURL->GetSpec(&urlSpec2);
PR_LOG(nsPluginLogging::gPluginLog, PLUGIN_LOG_NORMAL,
("nsPluginHostImpl::InstatiateEmbededPlugin Finished mime=%s, rv=%d, owner=%p, url=%s\n",
aMimeType, rv, aOwner, urlSpec2));
PR_LogFlush();
if (urlSpec2) nsCRT::free(urlSpec2);
#endif
1999-01-25 08:05:00 +00:00
return rv;
}
1998-08-21 01:12:53 +00:00
////////////////////////////////////////////////////////////////////////
/* Called by nsPluginViewer.cpp (full-page case) */
NS_IMETHODIMP nsPluginHostImpl::InstantiateFullPagePlugin(const char *aMimeType,
nsString& aURLSpec,
nsIStreamListener *&aStreamListener,
nsIPluginInstanceOwner *aOwner)
1999-01-25 08:05:00 +00:00
{
PLUGIN_LOG(PLUGIN_LOG_NORMAL,
("nsPluginHostImpl::InstatiateFullPagePlugin Begin mime=%s, owner=%p, url=%s\n",
aMimeType, aOwner, NS_LossyConvertUCS2toASCII(aURLSpec).get()));
1999-01-25 08:05:00 +00:00
nsresult rv;
nsIURI *url;
1999-01-25 08:05:00 +00:00
//create a URL so that the instantiator can do file ext.
//based plugin lookups...
rv = NS_NewURI(&url, aURLSpec);
1999-01-25 08:05:00 +00:00
if (rv != NS_OK)
url = nsnull;
if(FindStoppedPluginForURL(url, aOwner) == NS_OK) {
PLUGIN_LOG(PLUGIN_LOG_NOISY,
("nsPluginHostImpl::InstatiateFullPagePlugin FoundStopped mime=%s\n",aMimeType));
nsIPluginInstance* instance;
aOwner->GetInstance(instance);
if(!aMimeType || PL_strcasecmp(aMimeType, "application/x-java-vm"))
rv = NewFullPagePluginStream(aStreamListener, instance);
NS_IF_RELEASE(instance);
return NS_OK;
}
1999-01-25 08:05:00 +00:00
rv = SetUpPluginInstance(aMimeType, url, aOwner);
NS_IF_RELEASE(url);
if (NS_OK == rv)
{
nsIPluginInstance *instance = nsnull;
nsPluginWindow *window = nsnull;
aOwner->GetInstance(instance);
aOwner->GetWindow(window);
if (nsnull != instance)
{
instance->Start();
aOwner->CreateWidget();
// If we've got a native window, the let the plugin know about it.
if (window->window)
instance->SetWindow(window);
1999-01-25 08:05:00 +00:00
rv = NewFullPagePluginStream(aStreamListener, instance);
// If we've got a native window, the let the plugin know about it.
if (window->window)
instance->SetWindow(window);
1999-01-25 08:05:00 +00:00
NS_RELEASE(instance);
}
}
PLUGIN_LOG(PLUGIN_LOG_NORMAL,
("nsPluginHostImpl::InstatiateFullPagePlugin End mime=%s, rv=%d, owner=%p, url=%s\n",
aMimeType, rv, aOwner, NS_LossyConvertUCS2toASCII(aURLSpec).get()));
1999-01-25 08:05:00 +00:00
return rv;
}
////////////////////////////////////////////////////////////////////////
nsresult nsPluginHostImpl::FindStoppedPluginForURL(nsIURI* aURL,
nsIPluginInstanceOwner *aOwner)
{
char* url;
1999-05-17 21:26:48 +00:00
if(!aURL)
return NS_ERROR_FAILURE;
(void)aURL->GetSpec(&url);
nsActivePlugin * plugin = mActivePluginList.findStopped(url);
if((plugin != nsnull) && (plugin->mStopped))
{
nsIPluginInstance* instance = plugin->mInstance;
nsPluginWindow *window = nsnull;
aOwner->GetWindow(window);
aOwner->SetInstance(instance);
// we have to reset the owner and instance in the plugin instance peer
//instance->GetPeer(&peer);
((nsPluginInstancePeerImpl*)plugin->mPeer)->SetOwner(aOwner);
instance->Start();
aOwner->CreateWidget();
// If we've got a native window, the let the plugin know about it.
if (window->window)
instance->SetWindow(window);
plugin->setStopped(PR_FALSE);
nsCRT::free(url);
return NS_OK;
}
nsCRT::free(url);
return NS_ERROR_FAILURE;
}
////////////////////////////////////////////////////////////////////////
void nsPluginHostImpl::AddInstanceToActiveList(nsCOMPtr<nsIPlugin> aPlugin,
nsIPluginInstance* aInstance,
nsIURI* aURL,
PRBool aDefaultPlugin)
{
char* url;
1999-11-02 23:34:03 +00:00
1999-05-17 21:26:48 +00:00
if(!aURL)
return;
(void)aURL->GetSpec(&url);
// find corresponding plugin tag
// this is legal for xpcom plugins not to have nsIPlugin implemented
nsPluginTag * pluginTag = nsnull;
if(aPlugin)
{
for(pluginTag = mPlugins; pluginTag != nsnull; pluginTag = pluginTag->mNext)
{
if(pluginTag->mEntryPoint == aPlugin)
break;
}
NS_ASSERTION(pluginTag, "Plugin tag not found");
}
else
{
// we don't need it for xpcom plugins because the only purpose to have it
// is to be able to postpone unloading library dll in some circumstances
// which we don't do for xpcom plugins. In case we need it in the future
// we can probably use the following
/*
FindPluginEnabledForType(mimetype, pluginTag);
*/
}
nsActivePlugin * plugin = new nsActivePlugin(pluginTag, aInstance, url, aDefaultPlugin);
if(plugin == nsnull)
return;
mActivePluginList.add(plugin);
nsCRT::free(url);
}
////////////////////////////////////////////////////////////////////////
2000-07-07 00:10:54 +00:00
nsresult nsPluginHostImpl::RegisterPluginMimeTypesWithLayout(nsPluginTag * pluginTag,
nsIComponentManager * compManager,
nsIFile * path)
2000-07-07 00:10:54 +00:00
{
NS_ENSURE_ARG_POINTER(pluginTag);
NS_ENSURE_ARG_POINTER(pluginTag->mMimeTypeArray);
NS_ENSURE_ARG_POINTER(compManager);
PLUGIN_LOG(PLUGIN_LOG_NORMAL,
("nsPluginHostImpl::RegisterPluginMimeTypesWithLayout plugin=%s\n",
pluginTag->mFileName));
2000-07-07 00:10:54 +00:00
nsresult rv = NS_OK;
// what I want to do here is QI for a Component Registration Manager. Since this
// has not been invented yet, QI to the obsolete manager. Kids, don't do this at home.
nsCOMPtr<nsIComponentManagerObsolete> obsoleteManager = do_QueryInterface(compManager, &rv);
if (!obsoleteManager)
return rv;
2000-07-07 00:10:54 +00:00
for(int i = 0; i < pluginTag->mVariants; i++)
{
static NS_DEFINE_CID(kPluginDocLoaderFactoryCID, NS_PLUGINDOCLOADERFACTORY_CID);
nsCAutoString contractid(NS_DOCUMENT_LOADER_FACTORY_CONTRACTID_PREFIX "view;1?type=");
contractid += pluginTag->mMimeTypeArray[i];
rv = obsoleteManager->RegisterComponentSpec(kPluginDocLoaderFactoryCID,
"Plugin Loader Stub",
contractid.get(),
path,
PR_TRUE,
PR_FALSE);
PLUGIN_LOG(PLUGIN_LOG_NOISY,
("nsPluginHostImpl::RegisterPluginMimeTypesWithLayout mime=%s, plugin=%s\n",
pluginTag->mMimeTypeArray[i], pluginTag->mFileName));
2000-07-07 00:10:54 +00:00
}
return rv;
}
////////////////////////////////////////////////////////////////////////
NS_IMETHODIMP nsPluginHostImpl::SetUpPluginInstance(const char *aMimeType,
nsIURI *aURL,
nsIPluginInstanceOwner *aOwner)
{
#ifdef PLUGIN_LOGGING
char* urlSpec = nsnull;
if(aURL != nsnull) (void)aURL->GetSpec(&urlSpec);
PR_LOG(nsPluginLogging::gPluginLog, PLUGIN_LOG_NORMAL,
("nsPluginHostImpl::SetupPluginInstance Begin mime=%s, owner=%p, url=%s\n",
aMimeType, aOwner, urlSpec));
PR_LogFlush();
if (urlSpec) nsCRT::free(urlSpec);
#endif
nsresult result = NS_ERROR_FAILURE;
nsIPluginInstance* instance = NULL;
nsCOMPtr<nsIPlugin> plugin;
const char* mimetype;
if(!aURL)
return NS_ERROR_FAILURE;
1999-05-17 21:26:48 +00:00
// if don't have a mimetype, check by file extension
if(!aMimeType)
{
char* extension;
char* filename;
aURL->GetPath(&filename);
extension = PL_strrchr(filename, '.');
if(extension)
++extension;
else
return NS_ERROR_FAILURE;
if(IsPluginEnabledForExtension(extension, mimetype) != NS_OK)
{
nsCRT::free(filename);
return NS_ERROR_FAILURE;
}
nsCRT::free(filename);
}
else
mimetype = aMimeType;
PRBool isJavaPlugin = PR_FALSE;
if (aMimeType &&
(PL_strcasecmp(aMimeType, "application/x-java-vm") == 0 ||
PL_strcasecmp(aMimeType, "application/x-java-applet") == 0))
{
isJavaPlugin = PR_TRUE;
}
#if defined(XP_UNIX) || defined(XP_OS2)
// This is a work-around on Unix for a LiveConnect problem (bug 83698).
// The problem:
// The proxy JNI needs to be created by the browser. If it is created by
// someone else (e.g., a plugin) on a different thread, the proxy JNI will
// not work, and break LiveConnect.
// Currently, on Unix, when instantiating a Java plugin instance (by calling
// InstantiateEmbededPlugin() next), Java plugin will create the proxy JNI
// if it is not created yet. If that happens, LiveConnect will be broken.
// Before lazy start JVM was implemented, since at this point the browser
// already created the proxy JNI buring startup, the problem did not happen.
// But after the lazy start was implemented, at this point the proxy JNI was
// not created yet, so the Java plugin created the proxy JNI, and broke
// liveConnect.
// On Windows and Mac, Java plugin does not create the proxy JNI, but lets
// the browser to create it. Hence this is a Unix-only problem.
//
// The work-around:
// The root cause of the problem is in Java plugin's Unix implementation,
// which should not create the proxy JNI.
// As a work-around, here we make sure the proxy JNI has been created by the
// browser, before plugin gets a chance.
//
if (isJavaPlugin) {
// If Java is installed, get proxy JNI.
nsCOMPtr<nsIJVMManager> jvmManager = do_GetService(nsIJVMManager::GetCID(),
&result);
if (NS_SUCCEEDED(result)) {
JNIEnv* proxyEnv;
// Get proxy JNI, if not created yet, create it.
jvmManager->GetProxyJNI(&proxyEnv);
}
}
#endif
nsCAutoString contractID(
NS_LITERAL_CSTRING(NS_INLINE_PLUGIN_CONTRACTID_PREFIX) +
nsDependentCString(mimetype));
GetPluginFactory(mimetype, getter_AddRefs(plugin));
result = CallCreateInstance(contractID.get(), &instance);
// couldn't create an XPCOM plugin, try to create wrapper for a legacy plugin
if (NS_FAILED(result))
{
if(plugin)
{
#ifdef XP_WIN
static BOOL firstJavaPlugin = FALSE;
BOOL restoreOrigDir = FALSE;
char origDir[_MAX_PATH];
if (isJavaPlugin && !firstJavaPlugin)
{
DWORD dw = ::GetCurrentDirectory(_MAX_PATH, origDir);
NS_ASSERTION(dw <= _MAX_PATH, "Falied to obtain the current directory, which may leads to incorrect class laoding");
nsCOMPtr<nsIFile> binDirectory;
result = NS_GetSpecialDirectory(NS_XPCOM_CURRENT_PROCESS_DIR,
getter_AddRefs(binDirectory));
if (NS_SUCCEEDED(result))
{
nsXPIDLCString path;
binDirectory->GetPath(getter_Copies(path));
restoreOrigDir = ::SetCurrentDirectory(path);
}
}
#endif
this->PostStartupMessageForType(aMimeType, aOwner);
result = plugin->CreateInstance(NULL, kIPluginInstanceIID, (void **)&instance);
#ifdef XP_WIN
if (!firstJavaPlugin && restoreOrigDir)
{
BOOL bCheck = :: SetCurrentDirectory(origDir);
NS_ASSERTION(bCheck, " Error restoring driectoy");
firstJavaPlugin = TRUE;
}
#endif
}
if (NS_FAILED(result))
{
nsCOMPtr<nsIPlugin> bwPlugin =
do_GetService("@mozilla.org/blackwood/pluglet-engine;1", &result);
if (NS_SUCCEEDED(result))
{
result = bwPlugin->CreatePluginInstance(NULL,
kIPluginInstanceIID,
aMimeType,
(void **)&instance);
}
}
}
// neither an XPCOM or legacy plugin could be instantiated,
// so return the failure
if (NS_FAILED(result))
return result;
// it is adreffed here
aOwner->SetInstance(instance);
nsPluginInstancePeerImpl *peer = new nsPluginInstancePeerImpl();
1999-07-30 23:51:53 +00:00
if(peer == nsnull)
return NS_ERROR_OUT_OF_MEMORY;
// set up the peer for the instance
peer->Initialize(aOwner, mimetype);
nsIPluginInstancePeer *pi;
result = peer->QueryInterface(kIPluginInstancePeerIID, (void **)&pi);
if(result != NS_OK)
return result;
// tell the plugin instance to initialize itself and pass in the peer.
instance->Initialize(pi); // this will not add a ref to the instance (or owner). MMP
NS_RELEASE(pi);
// we should addref here
AddInstanceToActiveList(plugin, instance, aURL, PR_FALSE);
//release what was addreffed in Create(Plugin)Instance
NS_RELEASE(instance);
#ifdef PLUGIN_LOGGING
char* urlSpec2 = nsnull;
if(aURL != nsnull) (void)aURL->GetSpec(&urlSpec2);
PR_LOG(nsPluginLogging::gPluginLog, PLUGIN_LOG_BASIC,
("nsPluginHostImpl::SetupPluginInstance Finished mime=%s, rv=%d, owner=%p, url=%s\n",
aMimeType, result, aOwner, urlSpec2));
PR_LogFlush();
if (urlSpec2) nsCRT::free(urlSpec2);
#endif
return NS_OK;
}
////////////////////////////////////////////////////////////////////////
nsresult nsPluginHostImpl::SetUpDefaultPluginInstance(const char *aMimeType, nsIURI *aURL,
nsIPluginInstanceOwner *aOwner)
{
nsresult result = NS_ERROR_FAILURE;
nsIPluginInstance* instance = NULL;
nsCOMPtr<nsIPlugin> plugin = NULL;
const char* mimetype;
if(!aURL)
return NS_ERROR_FAILURE;
mimetype = aMimeType;
GetPluginFactory("*", getter_AddRefs(plugin));
result = CallCreateInstance(NS_INLINE_PLUGIN_CONTRACTID_PREFIX "*",
&instance);
// couldn't create an XPCOM plugin, try to create wrapper for a legacy plugin
if (NS_FAILED(result))
{
if(plugin)
result = plugin->CreateInstance(NULL, kIPluginInstanceIID, (void **)&instance);
}
// neither an XPCOM or legacy plugin could be instantiated, so return the failure
if(NS_FAILED(result))
return result;
// it is adreffed here
aOwner->SetInstance(instance);
nsPluginInstancePeerImpl *peer = new nsPluginInstancePeerImpl();
if(peer == nsnull)
return NS_ERROR_OUT_OF_MEMORY;
// if we don't have a mimetype, check by file extension
nsXPIDLCString mt;
if(mimetype == nsnull)
{
nsresult res = NS_OK;
nsCOMPtr<nsIURL> url = do_QueryInterface(aURL);
if(url)
{
nsXPIDLCString extension;
url->GetFileExtension(getter_Copies(extension));
if(extension)
{
nsCOMPtr<nsIMIMEService> ms (do_GetService(NS_MIMESERVICE_CONTRACTID, &res));
if(NS_SUCCEEDED(res) && ms)
{
res = ms->GetTypeFromExtension(extension, getter_Copies(mt));
if(NS_SUCCEEDED(res))
mimetype = mt;
}
}
}
}
// set up the peer for the instance
peer->Initialize(aOwner, mimetype);
nsIPluginInstancePeer *pi;
result = peer->QueryInterface(kIPluginInstancePeerIID, (void **)&pi);
if(result != NS_OK)
return result;
// tell the plugin instance to initialize itself and pass in the peer.
instance->Initialize(pi); // this will not add a ref to the instance (or owner). MMP
NS_RELEASE(pi);
// we should addref here
AddInstanceToActiveList(plugin, instance, aURL, PR_TRUE);
//release what was addreffed in Create(Plugin)Instance
NS_RELEASE(instance);
return NS_OK;
}
////////////////////////////////////////////////////////////////////////
NS_IMETHODIMP
nsPluginHostImpl::IsPluginEnabledForType(const char* aMimeType)
1999-01-25 08:05:00 +00:00
{
nsPluginTag *plugins = nsnull;
PRInt32 variants, cnt;
2000-08-17 19:26:15 +00:00
LoadPlugins();
1999-01-25 08:05:00 +00:00
// if we have a mimetype passed in, search the mPlugins linked
// list for a match
1999-01-25 08:05:00 +00:00
if (nsnull != aMimeType)
{
plugins = mPlugins;
while (nsnull != plugins)
{
variants = plugins->mVariants;
for (cnt = 0; cnt < variants; cnt++)
if (plugins->mMimeTypeArray[cnt] && (0 == PL_strcasecmp(plugins->mMimeTypeArray[cnt], aMimeType)))
return NS_OK;
1999-01-25 08:05:00 +00:00
if (cnt < variants)
break;
plugins = plugins->mNext;
}
}
return NS_ERROR_FAILURE;
1999-01-25 08:05:00 +00:00
}
////////////////////////////////////////////////////////////////////////
// check comma delimitered extensions
1999-09-01 19:58:22 +00:00
static int CompareExtensions(const char *aExtensionList, const char *aExtension)
{
if((aExtensionList == nsnull) || (aExtension == nsnull))
return -1;
const char *pExt = aExtensionList;
const char *pComma = strchr(pExt, ',');
1999-09-01 19:58:22 +00:00
if(pComma == nsnull)
return PL_strcasecmp(pExt, aExtension);
1999-09-01 19:58:22 +00:00
while(pComma != nsnull)
{
int length = pComma - pExt;
if(0 == PL_strncasecmp(pExt, aExtension, length))
1999-09-01 19:58:22 +00:00
return 0;
pComma++;
pExt = pComma;
pComma = strchr(pExt, ',');
}
// the last one
return PL_strcasecmp(pExt, aExtension);
1999-09-01 19:58:22 +00:00
}
////////////////////////////////////////////////////////////////////////
NS_IMETHODIMP
nsPluginHostImpl::IsPluginEnabledForExtension(const char* aExtension,
const char* &aMimeType)
{
nsPluginTag *plugins = nsnull;
PRInt32 variants, cnt;
2000-08-17 19:26:15 +00:00
LoadPlugins();
// if we have a mimetype passed in, search the mPlugins linked
// list for a match
if (nsnull != aExtension)
{
plugins = mPlugins;
while (nsnull != plugins)
{
variants = plugins->mVariants;
for (cnt = 0; cnt < variants; cnt++)
{
1999-09-01 19:58:22 +00:00
//if (0 == strcmp(plugins->mExtensionsArray[cnt], aExtension))
// mExtensionsArray[cnt] could be not a single extension but
// rather a list separated by commas
1999-09-01 19:58:22 +00:00
if (0 == CompareExtensions(plugins->mExtensionsArray[cnt], aExtension))
{
aMimeType = plugins->mMimeTypeArray[cnt];
return NS_OK;
}
}
if (cnt < variants)
break;
plugins = plugins->mNext;
}
}
return NS_ERROR_FAILURE;
}
////////////////////////////////////////////////////////////////////////
// Utility functions for a charset convertor
// which converts platform charset to unicode.
static nsresult CreateUnicodeDecoder(nsIUnicodeDecoder **aUnicodeDecoder)
{
nsresult rv;
// get the charset
nsAutoString platformCharset;
nsCOMPtr <nsIPlatformCharset> platformCharsetService = do_GetService(NS_PLATFORMCHARSET_CONTRACTID, &rv);
NS_ENSURE_SUCCESS(rv, rv);
rv = platformCharsetService->GetCharset(kPlatformCharsetSel_FileName, platformCharset);
NS_ENSURE_SUCCESS(rv, rv);
// get the decoder
nsCOMPtr<nsICharsetConverterManager> ccm = do_GetService(NS_CHARSETCONVERTERMANAGER_CONTRACTID, &rv);
NS_ENSURE_SUCCESS(rv, rv);
rv = ccm->GetUnicodeDecoder(&platformCharset, aUnicodeDecoder);
return rv;
}
static nsresult DoCharsetConversion(nsIUnicodeDecoder *aUnicodeDecoder,
const char* aANSIString, nsAWritableString& aUnicodeString)
{
NS_ENSURE_TRUE(aUnicodeDecoder, NS_ERROR_FAILURE);
NS_ENSURE_TRUE(aANSIString, NS_ERROR_FAILURE);
nsresult rv;
PRInt32 numberOfBytes = nsCRT::strlen(aANSIString);
PRInt32 outUnicodeLen;
nsAutoString buffer;
rv = aUnicodeDecoder->GetMaxLength(aANSIString, numberOfBytes, &outUnicodeLen);
NS_ENSURE_SUCCESS(rv, rv);
buffer.SetCapacity(outUnicodeLen);
rv = aUnicodeDecoder->Convert(aANSIString, &numberOfBytes, (PRUnichar*) buffer.get(), &outUnicodeLen);
NS_ENSURE_SUCCESS(rv, rv);
buffer.SetLength(outUnicodeLen);
aUnicodeString = buffer;
return rv;
}
////////////////////////////////////////////////////////////////////////
class DOMMimeTypeImpl : public nsIDOMMimeType {
public:
NS_DECL_ISUPPORTS
DOMMimeTypeImpl(nsPluginTag* aPluginTag, PRUint32 aMimeTypeIndex)
{
NS_INIT_ISUPPORTS();
(void) CreateUnicodeDecoder(getter_AddRefs(mUnicodeDecoder));
if (aPluginTag) {
if (aPluginTag->mMimeDescriptionArray)
(void) DoCharsetConversion(mUnicodeDecoder,
aPluginTag->mMimeDescriptionArray[aMimeTypeIndex], mDescription);
if (aPluginTag->mExtensionsArray)
mSuffixes.AssignWithConversion(aPluginTag->mExtensionsArray[aMimeTypeIndex]);
if (aPluginTag->mMimeTypeArray)
mType.AssignWithConversion(aPluginTag->mMimeTypeArray[aMimeTypeIndex]);
}
}
virtual ~DOMMimeTypeImpl() {
}
NS_METHOD GetDescription(nsAWritableString& aDescription)
{
aDescription.Assign(mDescription);
return NS_OK;
}
NS_METHOD GetEnabledPlugin(nsIDOMPlugin** aEnabledPlugin)
{
// this has to be implemented by the DOM version.
*aEnabledPlugin = nsnull;
return NS_OK;
}
NS_METHOD GetSuffixes(nsAWritableString& aSuffixes)
{
aSuffixes.Assign(mSuffixes);
return NS_OK;
}
NS_METHOD GetType(nsAWritableString& aType)
{
aType.Assign(mType);
return NS_OK;
}
private:
nsString mDescription;
nsString mSuffixes;
nsString mType;
nsCOMPtr<nsIUnicodeDecoder> mUnicodeDecoder;
};
////////////////////////////////////////////////////////////////////////
NS_IMPL_ISUPPORTS1(DOMMimeTypeImpl, nsIDOMMimeType)
////////////////////////////////////////////////////////////////////////
class DOMPluginImpl : public nsIDOMPlugin {
public:
NS_DECL_ISUPPORTS
DOMPluginImpl(nsPluginTag* aPluginTag) : mPluginTag(aPluginTag)
{
NS_INIT_ISUPPORTS();
(void) CreateUnicodeDecoder(getter_AddRefs(mUnicodeDecoder));
}
virtual ~DOMPluginImpl() {
}
NS_METHOD GetDescription(nsAWritableString& aDescription)
{
return DoCharsetConversion(mUnicodeDecoder, mPluginTag.mDescription, aDescription);
}
NS_METHOD GetFilename(nsAWritableString& aFilename)
{
#ifdef XP_MAC
return DoCharsetConversion(mUnicodeDecoder, mPluginTag.mFullPath, aFilename);
#else
return DoCharsetConversion(mUnicodeDecoder, mPluginTag.mFileName, aFilename);
#endif
}
NS_METHOD GetName(nsAWritableString& aName)
{
return DoCharsetConversion(mUnicodeDecoder, mPluginTag.mName, aName);
}
NS_METHOD GetLength(PRUint32* aLength)
{
*aLength = mPluginTag.mVariants;
return NS_OK;
}
NS_METHOD Item(PRUint32 aIndex, nsIDOMMimeType** aReturn)
{
nsIDOMMimeType* mimeType = new DOMMimeTypeImpl(&mPluginTag, aIndex);
NS_IF_ADDREF(mimeType);
*aReturn = mimeType;
return NS_OK;
}
NS_METHOD NamedItem(const nsAReadableString& aName, nsIDOMMimeType** aReturn)
{
for (int index = mPluginTag.mVariants - 1; index >= 0; --index) {
if (aName.Equals(NS_ConvertASCIItoUCS2(mPluginTag.mMimeTypeArray[index])))
return Item(index, aReturn);
}
return NS_OK;
}
private:
nsPluginTag mPluginTag;
nsCOMPtr<nsIUnicodeDecoder> mUnicodeDecoder;
};
////////////////////////////////////////////////////////////////////////
NS_IMPL_ISUPPORTS1(DOMPluginImpl, nsIDOMPlugin)
////////////////////////////////////////////////////////////////////////
NS_IMETHODIMP
nsPluginHostImpl::GetPluginCount(PRUint32* aPluginCount)
{
2000-08-17 19:26:15 +00:00
LoadPlugins();
PRUint32 count = 0;
nsPluginTag* plugin = mPlugins;
while (plugin != nsnull) {
++count;
plugin = plugin->mNext;
}
*aPluginCount = count;
return NS_OK;
}
////////////////////////////////////////////////////////////////////////
NS_IMETHODIMP
nsPluginHostImpl::GetPlugins(PRUint32 aPluginCount,
nsIDOMPlugin* aPluginArray[])
{
2000-08-17 19:26:15 +00:00
LoadPlugins();
nsPluginTag* plugin = mPlugins;
for (PRUint32 i = 0; i < aPluginCount && plugin != nsnull;
i++, plugin = plugin->mNext) {
nsIDOMPlugin* domPlugin = new DOMPluginImpl(plugin);
NS_IF_ADDREF(domPlugin);
aPluginArray[i] = domPlugin;
}
return NS_OK;
}
////////////////////////////////////////////////////////////////////////
nsresult
nsPluginHostImpl::FindPluginEnabledForType(const char* aMimeType,
nsPluginTag* &aPlugin)
{
nsPluginTag *plugins = nsnull;
PRInt32 variants, cnt;
aPlugin = nsnull;
2000-08-17 19:26:15 +00:00
LoadPlugins();
// if we have a mimetype passed in, search the mPlugins
// linked list for a match
if (nsnull != aMimeType) {
plugins = mPlugins;
while (nsnull != plugins) {
variants = plugins->mVariants;
for (cnt = 0; cnt < variants; cnt++) {
if (plugins->mMimeTypeArray[cnt] && (0 == PL_strcasecmp(plugins->mMimeTypeArray[cnt], aMimeType))) {
aPlugin = plugins;
return NS_OK;
}
}
if (cnt < variants)
break;
plugins = plugins->mNext;
}
}
return NS_ERROR_FAILURE;
}
nsresult
nsPluginHostImpl::PostStartupMessageForType(const char* aMimeType,
nsIPluginInstanceOwner* aOwner)
{
nsresult rv;
NS_ASSERTION(aOwner && aMimeType,
"PostStartupMessageForType: invalid arguments");
PRUnichar *messageUni = nsnull;
nsAutoString msg;
nsCOMPtr<nsIStringBundle> regionalBundle;
nsCOMPtr<nsIStringBundleService> strings(do_GetService(kStringBundleServiceCID,
&rv));
if (!strings) {
return rv;
}
rv = strings->CreateBundle(PLUGIN_REGIONAL_URL,
getter_AddRefs(regionalBundle));
if (NS_FAILED(rv)) {
return rv;
}
rv = regionalBundle->GetStringFromName(NS_LITERAL_STRING("pluginStartupMessage").get(),
&messageUni);
if (NS_FAILED(rv)){
return rv;
}
msg = messageUni;
nsMemory::Free((void *)messageUni);
msg.Append(PRUnichar(' '));
msg.AppendWithConversion(aMimeType, PL_strlen(aMimeType));
#ifdef PLUGIN_LOGGING
PR_LOG(nsPluginLogging::gPluginLog, PLUGIN_LOG_ALWAYS,
("nsPluginHostImpl::PostStartupMessageForType(aMimeType=%s)\n",
aMimeType));
PR_LogFlush();
#endif
rv = aOwner->ShowStatus(msg.get());
return rv;
}
////////////////////////////////////////////////////////////////////////
NS_IMETHODIMP nsPluginHostImpl::GetPluginFactory(const char *aMimeType, nsIPlugin** aPlugin)
1999-02-20 02:24:15 +00:00
{
nsresult rv = NS_ERROR_FAILURE;
*aPlugin = NULL;
if(!aMimeType)
return NS_ERROR_ILLEGAL_VALUE;
// unload any libs that can remain after plugins.refresh(1), see #61388
CleanUnusedLibraries();
// If plugins haven't been scanned yet, do so now
2000-08-17 19:26:15 +00:00
LoadPlugins();
nsPluginTag* pluginTag;
if((rv = FindPluginEnabledForType(aMimeType, pluginTag)) == NS_OK)
{
PLUGIN_LOG(PLUGIN_LOG_BASIC,
("nsPluginHostImpl::GetPluginFactory Begin mime=%s, plugin=%s\n",
aMimeType, pluginTag->mFileName));
#ifdef NS_DEBUG
if(aMimeType && pluginTag->mFileName)
printf("For %s found plugin %s\n", aMimeType, pluginTag->mFileName);
#endif
if (nsnull == pluginTag->mLibrary) // if we haven't done this yet
{
#ifndef XP_MAC
nsFileSpec file(pluginTag->mFileName);
#else
if (nsnull == pluginTag->mFullPath)
return NS_ERROR_FAILURE;
nsFileSpec file(pluginTag->mFullPath);
#endif
nsPluginFile pluginFile(file);
PRLibrary* pluginLibrary = NULL;
if (pluginFile.LoadPlugin(pluginLibrary) != NS_OK || pluginLibrary == NULL)
return NS_ERROR_FAILURE;
pluginTag->mLibrary = pluginLibrary;
}
nsIPlugin* plugin = pluginTag->mEntryPoint;
if(plugin == NULL)
{
// nsIPlugin* of xpcom plugins can be found thru a call to
// nsComponentManager::GetClassObject()
nsCID clsid;
nsCAutoString contractID(
NS_LITERAL_CSTRING(NS_INLINE_PLUGIN_CONTRACTID_PREFIX) +
nsDependentCString(aMimeType));
nsresult rv =
nsComponentManager::ContractIDToClassID(contractID.get(), &clsid);
if (NS_SUCCEEDED(rv))
{
rv = nsComponentManager::GetClassObject(clsid, nsIPlugin::GetIID(), (void**)&plugin);
if (NS_SUCCEEDED(rv) && plugin)
{
// plugin was addref'd by nsComponentManager::GetClassObject
pluginTag->mEntryPoint = plugin;
plugin->Initialize();
}
}
}
if (plugin == NULL)
{
// No, this is not a leak. GetGlobalServiceManager() doesn't
// addref the pointer on the way out. It probably should.
nsIServiceManagerObsolete* serviceManager;
nsServiceManager::GetGlobalServiceManager((nsIServiceManager**)&serviceManager);
// need to get the plugin factory from this plugin.
nsFactoryProc nsGetFactory = nsnull;
nsGetFactory = (nsFactoryProc) PR_FindSymbol(pluginTag->mLibrary, "NSGetFactory");
if(nsGetFactory != nsnull)
{
rv = nsGetFactory(serviceManager, kPluginCID, nsnull, nsnull, // XXX fix ClassName/ContractID
(nsIFactory**)&pluginTag->mEntryPoint);
plugin = pluginTag->mEntryPoint;
if (plugin != NULL)
plugin->Initialize();
}
else
{
// Now lets try to get the entry point from a 4.x plugin
rv = NS_ERROR_FAILURE;
#if defined(XP_MAC) && TARGET_CARBON
// on Carbon, first let's see if this is a Classic plugin
// should we also look for a 'carb' resource?
if (PR_FindSymbol(pluginTag->mLibrary, "mainRD") != NULL)
{
nsCOMPtr<nsIClassicPluginFactory> factory =
do_GetService(NS_CLASSIC_PLUGIN_FACTORY_CONTRACTID, &rv);
if (NS_SUCCEEDED(rv))
rv = factory->CreatePlugin(serviceManager,
pluginTag->mFileName,
2002-01-09 02:15:50 +00:00
pluginTag->mFullPath,
pluginTag->mLibrary,
&pluginTag->mEntryPoint);
if (!pluginTag->mEntryPoint) // plugin wasn't found
rv = NS_ERROR_FAILURE; // setup failure to try normal loading next
}
#endif
if (NS_FAILED(rv))
rv = ns4xPlugin::CreatePlugin(serviceManager,
pluginTag->mFileName,
pluginTag->mFullPath,
pluginTag->mLibrary,
&pluginTag->mEntryPoint);
plugin = pluginTag->mEntryPoint;
pluginTag->mFlags |= NS_PLUGIN_FLAG_OLDSCHOOL;
// no need to initialize, already done by CreatePlugin()
}
}
1999-02-20 02:24:15 +00:00
if (plugin != nsnull)
{
*aPlugin = plugin;
plugin->AddRef();
return NS_OK;
}
}
1999-02-20 02:24:15 +00:00
PLUGIN_LOG(PLUGIN_LOG_NORMAL,
("nsPluginHostImpl::GetPluginFactory End mime=%s, rv=%d, plugin=%p name=%s\n",
aMimeType, rv, *aPlugin, (pluginTag ? pluginTag->mFileName : "(not found)")));
return rv;
}
1999-02-20 02:24:15 +00:00
////////////////////////////////////////////////////////////////////////
// XXX called from ScanPluginsDirectory only when told to filter
// currently 'unwanted' plugins are Java, and all other plugins except
// Acrobat, Flash, Quicktime and Shockwave
static PRBool isUnwantedPlugin(nsPluginTag * tag)
{
if(tag->mFileName == nsnull)
return PR_TRUE;
for (PRInt32 i = 0; i < tag->mVariants; ++i) {
if(nsnull == PL_strcasecmp(tag->mMimeTypeArray[i], "application/pdf"))
return PR_FALSE;
if(nsnull == PL_strcasecmp(tag->mMimeTypeArray[i], "application/x-shockwave-flash"))
return PR_FALSE;
if(nsnull == PL_strcasecmp(tag->mMimeTypeArray[i],"application/x-director"))
return PR_FALSE;
}
// On Windows, we also want to include the Quicktime plugin from the 4.x directory
// But because it spans several DLL's, the best check for now is by filename
if (nsnull != PL_strcasestr(tag->mFileName,"npqtplugin"))
return PR_FALSE;
return PR_TRUE;
}
////////////////////////////////////////////////////////////////////////
nsresult nsPluginHostImpl::ScanPluginsDirectory(nsIFile * pluginsDir,
nsIComponentManager * compManager,
nsIFile * layoutPath,
PRBool checkForUnwantedPlugins)
{
nsresult rv;
#ifdef PLUGIN_LOGGING
nsXPIDLCString dirPath;
pluginsDir->GetPath(getter_Copies(dirPath));
PLUGIN_LOG(PLUGIN_LOG_BASIC,
("nsPluginHostImpl::ScanPluginsDirectory dir=%s\n", dirPath.get()));
#endif
nsCOMPtr<nsISimpleEnumerator> iter;
rv = pluginsDir->GetDirectoryEntries(getter_AddRefs(iter));
if (NS_FAILED(rv))
return rv;
PRBool hasMore;
while (NS_SUCCEEDED(iter->HasMoreElements(&hasMore)) && hasMore)
{
nsCOMPtr<nsISupports> supports;
rv = iter->GetNext(getter_AddRefs(supports));
if (NS_FAILED(rv))
continue;
nsCOMPtr<nsIFile> dirEntry(do_QueryInterface(supports, &rv));
if (NS_FAILED(rv))
continue;
nsXPIDLCString filePath;
rv = dirEntry->GetPath(getter_Copies(filePath));
if (NS_FAILED(rv))
continue;
nsFileSpec file(filePath);
PRBool wasSymlink;
file.ResolveSymlink(wasSymlink);
if (nsPluginsDir::IsPluginFile(file))
{
// Look for it in our cache
nsPluginTag *pluginTag = RemoveCachedPluginsInfo(file.GetCString());
// Get file mod time
PRInt64 fileModTime;
LL_I2L(fileModTime, 0);
dirEntry->GetLastModifiedTime(&fileModTime);
if (pluginTag) {
PR_LOG(nsPluginLogging::gPluginLog, PLUGIN_LOG_BASIC,
("ScanPluginsDirectory : Found plugin in cache : %s\n", pluginTag->mFileName));
// If plugin changed, delete cachedPluginTag and dont use cache
if (LL_NE(fileModTime, pluginTag->mLastModifiedTime)) {
// Plugins has changed. Dont use cached plugin info.
PR_LOG(nsPluginLogging::gPluginLog, PLUGIN_LOG_BASIC,
("ScanPluginsDirectory : timestamp check failed. Reloading plugin : %s\n", pluginTag->mFileName));
delete pluginTag;
pluginTag = nsnull;
}
}
else {
PR_LOG(nsPluginLogging::gPluginLog, PLUGIN_LOG_BASIC,
("ScanPluginsDirectory : Plugin NOT found in cache : %s\n", filePath.get()));
}
if (!pluginTag) {
nsPluginFile pluginFile(file);
PRLibrary* pluginLibrary = nsnull;
// load the plugin's library so we can ask it some questions, but not for Windows
#ifndef XP_WIN
if (pluginFile.LoadPlugin(pluginLibrary) != NS_OK || pluginLibrary == nsnull)
continue;
#endif
// create a tag describing this plugin.
nsPluginInfo info = { sizeof(info) };
nsresult res = pluginFile.GetPluginInfo(info);
if(NS_FAILED(res))
continue;
// if we don't have mime type -- don't proceed, this is not a plugin
if(!info.fMimeTypeArray) {
pluginFile.FreePluginInfo(info);
continue;
}
pluginTag = new nsPluginTag(&info);
pluginFile.FreePluginInfo(info);
if(pluginTag == nsnull)
return NS_ERROR_OUT_OF_MEMORY;
pluginTag->mLibrary = pluginLibrary;
pluginTag->mLastModifiedTime = fileModTime;
}
PRBool bAddIt = PR_TRUE;
// check if there are specific plugins we don't want
if(checkForUnwantedPlugins)
{
if(isUnwantedPlugin(pluginTag)) {
bAddIt = PR_FALSE;
pluginTag->Mark(NS_PLUGIN_FLAG_UNWANTED);
// Add it to our cached plugins so we can cache the unwantedness of
// this plugin when we sync cached plugins to registry
pluginTag->mNext = mCachedPlugins;
mCachedPlugins = pluginTag;
// If this plugin wasn't from our cache, we need to sync plugin info
// to registry
if (!(pluginTag->mFlags & NS_PLUGIN_FLAG_FROMCACHE))
mSyncCachedPlugins = PR_TRUE;
// Clear plugintag so it wont get deleted
pluginTag = nsnull;
}
}
// check if we already have this plugin in the list which
// is possible if we do refresh
if(bAddIt)
{
for(nsPluginTag* tag = mPlugins; tag != nsnull; tag = tag->mNext)
{
if(tag->Equals(pluginTag))
{
bAddIt = PR_FALSE;
break;
}
}
}
// so if we still want it -- do it
if(bAddIt)
{
pluginTag->mNext = mPlugins;
mPlugins = pluginTag;
if(layoutPath)
RegisterPluginMimeTypesWithLayout(pluginTag, compManager, layoutPath);
// Finally see if this was a plugin that was not in cache. If so,
// we need to sync our cache
if (!(pluginTag->mFlags & NS_PLUGIN_FLAG_FROMCACHE)) {
mSyncCachedPlugins = PR_TRUE;
}
}
else {
delete pluginTag;
}
}
}
return NS_OK;
}
nsresult nsPluginHostImpl::ScanPluginsDirectoryList(nsISimpleEnumerator * dirEnum,
nsIComponentManager * compManager,
nsIFile * layoutPath,
PRBool checkForUnwantedPlugins)
{
PRBool hasMore;
while (NS_SUCCEEDED(dirEnum->HasMoreElements(&hasMore)) && hasMore) {
nsCOMPtr<nsISupports> supports;
nsresult rv = dirEnum->GetNext(getter_AddRefs(supports));
if (NS_FAILED(rv))
continue;
nsCOMPtr<nsIFile> nextDir(do_QueryInterface(supports, &rv));
if (NS_FAILED(rv))
continue;
ScanPluginsDirectory(nextDir, compManager, layoutPath, checkForUnwantedPlugins);
}
return NS_OK;
}
////////////////////////////////////////////////////////////////////////
#include "nsITimelineService.h"
NS_IMETHODIMP nsPluginHostImpl::LoadPlugins()
{
// do not do anything if it is already done
// use nsPluginHostImpl::ReloadPlugins to enforce loading
if(mPluginsLoaded)
return NS_OK;
NS_TIMELINE_START_TIMER("LoadPlugins");
2001-10-11 05:40:00 +00:00
#ifdef CALL_SAFETY_ON
// check preferences on whether or not we want to try safe calls to plugins
NS_INIT_PLUGIN_SAFE_CALLS;
2001-10-11 05:40:00 +00:00
#endif
nsresult rv;
// If the create instance failed, then it automatically disables all
// our caching functions and we will just end up loading the plugins
// on startup.
nsCOMPtr<nsIRegistry> registry = do_CreateInstance(kRegistryCID);
if (registry) {
rv = registry->OpenWellKnownRegistry(nsIRegistry::ApplicationRegistry);
if (NS_FAILED(rv)) {
registry = nsnull;
}
}
// Load cached plugins info
LoadCachedPluginsInfo(registry);
// retrieve a path for layout module. Needed for plugin mime types registration
nsCOMPtr<nsIFile> layoutPath;
nsCOMPtr<nsIComponentManager> compManager = do_GetService(kComponentManagerCID, &rv);
// what I want to do here is QI for a Component Registration Manager. Since this
// has not been invented yet, QI to the obsolete manager. Kids, don't do this at home.
nsCOMPtr<nsIComponentManagerObsolete> obsoleteManager = do_QueryInterface(compManager);
if (NS_SUCCEEDED(rv) && compManager && obsoleteManager)
{
2001-12-11 19:28:57 +00:00
PRBool gotLayoutPath;
if (NS_SUCCEEDED(obsoleteManager->SpecForRegistryLocation(REL_PLUGIN_DLL, getter_AddRefs(layoutPath))))
2001-12-11 19:28:57 +00:00
gotLayoutPath = PR_TRUE;
else
gotLayoutPath = PR_FALSE;
rv = LoadXPCOMPlugins(compManager, layoutPath);
if (!gotLayoutPath)
layoutPath = nsnull;
}
// Failure here is not a show-stopper so just warn.
rv = EnsurePrivateDirServiceProvider();
NS_WARN_IF_FALSE(NS_SUCCEEDED(rv), "Failed to register dir service provider.");
nsCOMPtr<nsIProperties> dirService(do_GetService(kDirectoryServiceContractID, &rv));
if (NS_FAILED(rv))
return rv;
nsCOMPtr<nsISimpleEnumerator> dirList;
// 1. Scan the app-defined list of plugin dirs.
rv = dirService->Get(NS_APP_PLUGINS_DIR_LIST, NS_GET_IID(nsISimpleEnumerator), getter_AddRefs(dirList));
if (NS_SUCCEEDED(rv))
ScanPluginsDirectoryList(dirList, compManager, layoutPath);
// 2. Scan the system-defined list of plugin dirs
rv = dirService->Get(NS_OS_PLUGINS_DIR_LIST, NS_GET_IID(nsISimpleEnumerator), getter_AddRefs(dirList));
if (NS_SUCCEEDED(rv))
ScanPluginsDirectoryList(dirList, compManager, layoutPath);
2000-09-22 01:48:05 +00:00
mPluginsLoaded = PR_TRUE; // at this point 'some' plugins have been loaded,
// the rest is optional
#if defined (XP_WIN)
nsCOMPtr<nsIFile> dirToScan;
// Scan 4.x plugins location.
// Specifying PR_TRUE for the last param to ScanPluginsDirectory, we make sure that:
// 1. we search for a match in the list of MOZ_LOCAL plugins, ignore if found,
// add if not found (check for dups)
// 2. we ignore 4.x Java plugins no matter what and other
// unwanted plugins as per temporary decision described in bug #23856
rv = dirService->Get("NS_4DOTX_PLUGINS_DIR", NS_GET_IID(nsIFile), getter_AddRefs(dirToScan));
if (NS_SUCCEEDED(rv))
ScanPluginsDirectory(dirToScan, compManager, layoutPath, PR_TRUE);
// Scan the installation path of Sun's JRE if the prefs are enabled
nsCOMPtr<nsIPref> prefService = do_GetService(NS_PREF_CONTRACTID);
if (prefService) // we got the pref service
{
PRBool javaEnabled = PR_FALSE; // don't bother the scan if java is OFF
PRBool doJREPluginScan = PR_FALSE;
if (NS_SUCCEEDED(prefService->GetBoolPref("security.enable_java",&javaEnabled)) &&
NS_SUCCEEDED(prefService->GetBoolPref("plugin.do_JRE_Plugin_Scan",&doJREPluginScan)) &&
javaEnabled && doJREPluginScan)
{
rv = dirService->Get("NS_WIN_JAVA_JRE_DIR", NS_GET_IID(nsIFile), getter_AddRefs(dirToScan));
if (NS_SUCCEEDED(rv))
ScanPluginsDirectory(dirToScan, compManager, layoutPath);
}
}
#endif
// Update the plugins info cache
if (mSyncCachedPlugins) {
mSyncCachedPlugins = PR_FALSE;
CachePluginsInfo(registry);
}
// No more need for cached plugins. Clear it up.
while (mCachedPlugins) {
nsPluginTag *next = mCachedPlugins->mNext;
delete mCachedPlugins;
mCachedPlugins = next;
}
// reverse our list of plugins
nsPluginTag *next,*prev = nsnull;
for (nsPluginTag *cur = mPlugins; cur; cur = next) {
next = cur->mNext;
cur->mNext = prev;
prev = cur;
}
mPlugins = prev;
NS_TIMELINE_STOP_TIMER("LoadPlugins");
NS_TIMELINE_MARK_TIMER("LoadPlugins");
return NS_OK;
}
////////////////////////////////////////////////////////////////////////
static nsresult
cidToDllname(nsIComponentManager* aComponentManager, nsIRegistry* aRegistry,
const char *aCID, char **dllName)
{
NS_ENSURE_ARG_POINTER(dllName);
// To figure out the filename of the plugin, we'll need to get the
// plugin's CID, and then navigate through the XPCOM registry to
// pull out the DLL name to which the CID is registered.
nsAutoString path(NS_LITERAL_STRING("software/mozilla/XPCOM/classID/") + NS_ConvertASCIItoUCS2(aCID));
nsRegistryKey cidKey;
nsresult rv = aRegistry->GetKey(nsIRegistry::Common, path.get(), &cidKey);
if (NS_SUCCEEDED(rv)) {
PRUint8* library;
PRUint32 count;
// XXX Good grief, what does "GetBytesUTF8()" mean? They're bytes!
rv = aRegistry->GetBytesUTF8(cidKey, "InprocServer", &count, &library);
if (NS_SUCCEEDED(rv)) {
nsCOMPtr<nsIFile> file;
// what I want to do here is QI for a Component Registration Manager. Since this
// has not been invented yet, QI to the obsolete manager. Kids, don't do this at home.
nsCOMPtr<nsIComponentManagerObsolete> obsoleteManager = do_QueryInterface(aComponentManager, &rv);
if (obsoleteManager)
rv = obsoleteManager->SpecForRegistryLocation(NS_REINTERPRET_CAST(const char*, library),
getter_AddRefs(file));
if (NS_SUCCEEDED(rv)) {
file->GetPath(dllName);
}
nsCRT::free(NS_REINTERPRET_CAST(char*, library));
}
}
return rv;
}
static nsresult
LoadXPCOMPlugin(nsIRegistry* aRegistry,
const char* aFilename,
nsRegistryKey aPluginKey,
nsPluginTag** aResult)
{
nsresult rv;
// The name, description, MIME types, MIME descriptions, and
// supported file extensions will all hang off of the plugin's key
// in the registry. Pull these out now.
PRUint8 * name=nsnull;
PRUint32 length;
aRegistry->GetBytesUTF8(aPluginKey, kPluginsNameKey, &length, &name);
PRUint8 * description=nsnull;
aRegistry->GetBytesUTF8(aPluginKey, kPluginsDescKey, &length, &description);
nsXPIDLCString filename;
nsXPIDLCString fullpath;
if (!aFilename) {
// Look for a filename key
aRegistry->GetStringUTF8(aPluginKey, kPluginsFilenameKey, getter_Copies(filename));
aRegistry->GetStringUTF8(aPluginKey, kPluginsFullpathKey, getter_Copies(fullpath));
}
PRInt64 lastmod = LL_ZERO;
aRegistry->GetLongLong(aPluginKey, kPluginsModTimeKey, &lastmod);
PRInt32 intval = 1; // Default for canunload is PR_TRUE
aRegistry->GetInt(aPluginKey, kPluginsCanUnload, &intval);
PRBool canunload = (intval > 0);
nsCOMPtr<nsIEnumerator> enumerator;
rv = aRegistry->EnumerateAllSubtrees(aPluginKey, getter_AddRefs(enumerator));
if (NS_FAILED(rv)) return rv;
nsCOMPtr<nsISimpleEnumerator> subtrees;
rv = NS_NewAdapterEnumerator(getter_AddRefs(subtrees), enumerator);
if (NS_FAILED(rv)) return rv;
char** mimetypes = nsnull;
char** mimedescriptions = nsnull;
char** extensions = nsnull;
PRInt32 count = 0;
PRInt32 capacity = 0;
for (;;) {
PRBool hasmore;
subtrees->HasMoreElements(&hasmore);
if (! hasmore)
break;
nsCOMPtr<nsISupports> isupports;
subtrees->GetNext(getter_AddRefs(isupports));
nsCOMPtr<nsIRegistryNode> node = do_QueryInterface(isupports);
NS_ASSERTION(node != nsnull, "not an nsIRegistryNode");
if (! node)
continue;
nsRegistryKey key;
node->GetKey(&key);
if (count >= capacity) {
capacity += capacity ? capacity : 4;
char** newmimetypes = new char*[capacity];
char** newmimedescriptions = new char*[capacity];
char** newextensions = new char*[capacity];
if (!newmimetypes || !newmimedescriptions || !newextensions) {
rv = NS_ERROR_OUT_OF_MEMORY;
delete[] newmimetypes;
delete[] newmimedescriptions;
delete[] newextensions;
break;
}
for (PRInt32 i = 0; i < count; ++i) {
newmimetypes[i] = mimetypes[i];
newmimedescriptions[i] = mimedescriptions[i];
newextensions[i] = extensions[i];
}
delete[] mimetypes;
delete[] mimedescriptions;
delete[] extensions;
mimetypes = newmimetypes;
mimedescriptions = newmimedescriptions;
extensions = newextensions;
}
aRegistry->GetStringUTF8(key, kPluginsMimeTypeKey, &mimetypes[count]);
PRUint8 * md;
aRegistry->GetBytesUTF8(key, kPluginsMimeDescKey, &length, &md);
mimedescriptions[count] = NS_REINTERPRET_CAST(char *, md);
aRegistry->GetStringUTF8(key, kPluginsMimeExtKey, &extensions[count]);
++count;
}
if (NS_SUCCEEDED(rv)) {
// All done! Create the new nsPluginTag info and send it back.
nsPluginTag* tag
= new nsPluginTag(NS_REINTERPRET_CAST(const char *, name),
NS_REINTERPRET_CAST(const char *, description),
aFilename ? aFilename : filename.get(),
fullpath.get(),
(const char* const*)mimetypes,
(const char* const*)mimedescriptions,
(const char* const*)extensions,
count, lastmod, canunload);
if (! tag)
rv = NS_ERROR_OUT_OF_MEMORY;
*aResult = tag;
}
for (PRInt32 i = 0; i < count; ++i) {
CRTFREEIF(mimetypes[i]);
CRTFREEIF(mimedescriptions[i]);
CRTFREEIF(extensions[i]);
}
delete[] mimetypes;
delete[] mimedescriptions;
delete[] extensions;
PR_FREEIF(name);
PR_FREEIF(description);
return rv;
}
static nsresult
AddPluginInfoToRegistry(nsIRegistry* registry, nsRegistryKey top,
nsPluginTag *tag, const char *keyname)
{
NS_ENSURE_ARG_POINTER(tag);
nsRegistryKey pluginKey;
nsresult rv = registry->AddSubtree(top, keyname, &pluginKey);
if (NS_FAILED(rv)) return rv;
// Add filename, name and description
registry->SetStringUTF8(pluginKey, kPluginsFilenameKey, tag->mFileName);
if (tag->mFullPath)
registry->SetStringUTF8(pluginKey, kPluginsFullpathKey, tag->mFullPath);
// we use SetBytes instead of SetString to address special character issue, see Mozilla bug 108246
if(tag->mName)
registry->SetBytesUTF8(pluginKey, kPluginsNameKey, nsCRT::strlen(tag->mName) + 1, (PRUint8 *)tag->mName);
if(tag->mDescription)
registry->SetBytesUTF8(pluginKey, kPluginsDescKey, nsCRT::strlen(tag->mDescription) + 1, (PRUint8 *)tag->mDescription);
registry->SetLongLong(pluginKey, kPluginsModTimeKey, &(tag->mLastModifiedTime));
registry->SetInt(pluginKey, kPluginsCanUnload, tag->mCanUnloadLibrary);
// Add in each mimetype this plugin supports
for (int i=0; i<tag->mVariants; i++) {
char mimetypeKeyName[16];
nsRegistryKey mimetypeKey;
PR_snprintf(mimetypeKeyName, sizeof (mimetypeKeyName), "mimetype-%d", i);
rv = registry->AddSubtree(pluginKey, mimetypeKeyName, &mimetypeKey);
if (NS_FAILED(rv))
break;
registry->SetStringUTF8(mimetypeKey, kPluginsMimeTypeKey, tag->mMimeTypeArray[i]);
if(tag->mMimeDescriptionArray && tag->mMimeDescriptionArray[i])
registry->SetBytesUTF8(mimetypeKey, kPluginsMimeDescKey,
nsCRT::strlen(tag->mMimeDescriptionArray[i]) + 1,
(PRUint8 *)tag->mMimeDescriptionArray[i]);
registry->SetStringUTF8(mimetypeKey, kPluginsMimeExtKey, tag->mExtensionsArray[i]);
}
if (NS_FAILED(rv))
rv = registry->RemoveSubtree(top, keyname);
return rv;
}
////////////////////////////////////////////////////////////////////////
nsresult
nsPluginHostImpl::LoadXPCOMPlugins(nsIComponentManager* aComponentManager, nsIFile* aPath)
{
// The "new style" XPCOM plugins have their information stored in
// the component registry, under the key
//
// nsIRegistry::Common/software/plugins
//
// Enumerate through that list now, creating an nsPluginTag for
// each.
nsCOMPtr<nsIRegistry> registry = do_CreateInstance(kRegistryCID);
if (! registry)
return NS_ERROR_FAILURE;
nsresult rv;
rv = registry->OpenWellKnownRegistry(nsIRegistry::ApplicationComponentRegistry);
if (NS_FAILED(rv)) return rv;
nsRegistryKey pluginsKey;
rv = registry->GetSubtree(nsIRegistry::Common, kPluginsRootKey, &pluginsKey);
if (NS_FAILED(rv)) return rv;
// XXX get rid nsIEnumerator someday!
nsCOMPtr<nsIEnumerator> enumerator;
rv = registry->EnumerateSubtrees(pluginsKey, getter_AddRefs(enumerator));
if (NS_FAILED(rv)) return rv;
nsCOMPtr<nsISimpleEnumerator> plugins;
rv = NS_NewAdapterEnumerator(getter_AddRefs(plugins), enumerator);
if (NS_FAILED(rv)) return rv;
for (;;) {
PRBool hasMore;
plugins->HasMoreElements(&hasMore);
if (! hasMore)
break;
nsCOMPtr<nsISupports> isupports;
plugins->GetNext(getter_AddRefs(isupports));
nsCOMPtr<nsIRegistryNode> node = do_QueryInterface(isupports);
NS_ASSERTION(node != nsnull, "not an nsIRegistryNode");
if (! node)
continue;
// Pull out the information for an individual plugin, and link it
// in to the mPlugins list.
nsXPIDLCString cid;
node->GetNameUTF8(getter_Copies(cid));
nsRegistryKey key;
node->GetKey(&key);
nsXPIDLCString filename;
rv = cidToDllname(aComponentManager, registry, cid, getter_Copies(filename));
if (NS_FAILED(rv))
continue;
nsPluginTag* tag = nsnull;
rv = LoadXPCOMPlugin(registry, filename, key, &tag);
if (NS_FAILED(rv))
continue;
// skip it if we already have it
PRBool bAddIt = PR_TRUE;
for(nsPluginTag* existingtag = mPlugins; existingtag != nsnull; existingtag = existingtag->mNext)
{
if(tag->Equals(existingtag))
{
bAddIt = PR_FALSE;
break;
}
}
if(!bAddIt)
{
if(tag)
delete tag;
continue;
}
tag->mNext = mPlugins;
mPlugins = tag;
// Create an nsIDocumentLoaderFactory wrapper in case we ever see
// any naked streams.
RegisterPluginMimeTypesWithLayout(tag, aComponentManager, aPath);
}
return NS_OK;
}
1998-09-15 03:48:58 +00:00
nsresult
nsPluginHostImpl::LoadCachedPluginsInfo(nsIRegistry* registry)
{
// Loads cached plugin info from registry
//
// Enumerate through that list now, creating an nsPluginTag for
// each.
if (! registry)
return NS_ERROR_FAILURE;
nsRegistryKey pluginsKey;
nsresult rv = registry->GetSubtree(nsIRegistry::Common, kPluginsRootKey, &pluginsKey);
if (NS_FAILED(rv)) return rv;
// Make sure we are dealing with the same version number of the plugin info
nsXPIDLCString version;
rv = registry->GetStringUTF8(pluginsKey, kPluginsVersionKey, getter_Copies(version));
if (NS_FAILED(rv) || PL_strcmp(version.get(), kPluginInfoVersion)) {
// Version mismatch
// Nuke the subtree
registry->RemoveSubtree(nsIRegistry::Common, kPluginsRootKey);
PR_LOG(nsPluginLogging::gPluginLog, PLUGIN_LOG_BASIC,
("LoadCachedPluginsInfo : Version %s mismatch - Expected %s. Nuking cached info.\n",
version.get(), kPluginInfoVersion));
return NS_ERROR_FAILURE;
}
// XXX get rid nsIEnumerator someday!
nsCOMPtr<nsIEnumerator> enumerator;
rv = registry->EnumerateSubtrees(pluginsKey, getter_AddRefs(enumerator));
if (NS_FAILED(rv)) return rv;
nsCOMPtr<nsISimpleEnumerator> plugins;
rv = NS_NewAdapterEnumerator(getter_AddRefs(plugins), enumerator);
if (NS_FAILED(rv)) return rv;
for (;;) {
PRBool hasMore;
plugins->HasMoreElements(&hasMore);
if (! hasMore)
break;
nsCOMPtr<nsISupports> isupports;
plugins->GetNext(getter_AddRefs(isupports));
nsCOMPtr<nsIRegistryNode> node = do_QueryInterface(isupports);
NS_ASSERTION(node != nsnull, "not an nsIRegistryNode");
if (! node)
continue;
// Pull out the information for an individual plugin, and link it
// in to the mCachedPlugins list.
nsRegistryKey key;
node->GetKey(&key);
nsPluginTag* tag = nsnull;
rv = LoadXPCOMPlugin(registry, nsnull, key, &tag);
if (NS_FAILED(rv))
continue;
// Mark plugin as loaded from cache
tag->Mark(NS_PLUGIN_FLAG_FROMCACHE);
PR_LOG(nsPluginLogging::gPluginLog, PLUGIN_LOG_BASIC,
("LoadCachedPluginsInfo : Loading Cached plugininfo for %s\n", tag->mFileName));
tag->mNext = mCachedPlugins;
mCachedPlugins = tag;
}
return NS_OK;
}
nsresult
nsPluginHostImpl::CachePluginsInfo(nsIRegistry* registry)
{
// Save plugin info from registry
if (! registry)
return NS_ERROR_FAILURE;
// We dont want any old plugins that dont exist anymore hanging around
// So remove and re-add the root of the plugins info
nsresult rv = registry->RemoveSubtree(nsIRegistry::Common, kPluginsRootKey);
nsRegistryKey pluginsSubtreeKey;
rv = registry->AddSubtree(nsIRegistry::Common, kPluginsRootKey, &pluginsSubtreeKey);
if (NS_FAILED(rv)) return rv;
rv = registry->SetStringUTF8(pluginsSubtreeKey, kPluginsVersionKey, kPluginInfoVersion);
if (NS_FAILED(rv)) return rv;
int count = 0;
// Store all plugins in the mPlugins list - all plugins currently in use.
char pluginKeyName[64];
nsPluginTag *tag;
for(tag=mPlugins; tag; tag=tag->mNext) {
// store each plugin info into the registry
PR_LOG(nsPluginLogging::gPluginLog, PLUGIN_LOG_BASIC,
("CachePluginsInfo : Caching plugininfo in registry for %s\n", tag->mFileName));
PR_snprintf(pluginKeyName, sizeof(pluginKeyName), "plugin-%d", ++count);
AddPluginInfoToRegistry(registry, pluginsSubtreeKey, tag, pluginKeyName);
}
// Store any unwanted plugins info so that we wont have to load
// them again the next time around
tag = mCachedPlugins;
for(tag=mCachedPlugins; tag; tag=tag->mNext) {
// Look for unwanted plugins
if (!(tag->mFlags & NS_PLUGIN_FLAG_UNWANTED))
continue;
// store each plugin info into the registry
PR_LOG(nsPluginLogging::gPluginLog, PLUGIN_LOG_BASIC,
("CachePluginsInfo : Caching unwanted plugininfo in registry for %s\n", tag->mFileName));
PR_snprintf(pluginKeyName, sizeof(pluginKeyName), "plugin-%d", ++count);
AddPluginInfoToRegistry(registry, pluginsSubtreeKey, tag, pluginKeyName);
}
return NS_OK;
}
nsPluginTag *
nsPluginHostImpl::RemoveCachedPluginsInfo(const char *filename)
{
nsPluginTag **link = &mCachedPlugins;
for (nsPluginTag *tag = *link; tag; link = &tag->mNext, tag = *link)
{
// compare filename or else the mFullPath if it exists. Mac seems to use
// mFullPath for fullpath and mFileName for just the leafname of fullpath.
// On win and unix, mFullPath is never used and mFileName is contains the
// full pathname. All this should move to using nsIFile.
if (!PL_strcmp(tag->mFileName, filename) ||
(tag->mFullPath && !PL_strcmp(tag->mFullPath, filename)))
{
// Found it. Remove it from our list
*link = tag->mNext;
return tag;
}
}
return nsnull;
}
nsresult
nsPluginHostImpl::EnsurePrivateDirServiceProvider()
{
if (!mPrivateDirServiceProvider)
{
nsresult rv;
nsCOMPtr<nsIDirectoryServiceProvider> provider = new nsPluginDirServiceProvider;
if (!provider)
return NS_ERROR_OUT_OF_MEMORY;
nsCOMPtr<nsIDirectoryService> dirService(do_GetService(kDirectoryServiceContractID, &rv));
if (NS_FAILED(rv))
return rv;
rv = dirService->RegisterProvider(provider);
if (NS_FAILED(rv))
return rv;
mPrivateDirServiceProvider = provider;
}
return NS_OK;
}
////////////////////////////////////////////////////////////////////////
/* Called by GetURL and PostURL */
NS_IMETHODIMP nsPluginHostImpl::NewPluginURLStream(const nsString& aURL,
nsIPluginInstance *aInstance,
nsIPluginStreamListener* aListener,
const char *aPostData,
PRBool aIsFile,
PRUint32 aPostDataLen,
const char *aHeadersData,
PRUint32 aHeadersDataLen)
1998-09-15 03:48:58 +00:00
{
nsCOMPtr<nsIURI> url;
nsAutoString absUrl;
nsresult rv;
char *newPostData = nsnull;
PRUint32 newPostDataLen = 0;
1999-01-25 08:05:00 +00:00
if (aURL.Length() <= 0)
return NS_OK;
1998-09-15 03:48:58 +00:00
// get the full URL of the document that the plugin is embedded
// in to create an absolute url in case aURL is relative
nsCOMPtr<nsIDocument> doc;
nsPluginInstancePeerImpl *peer;
rv = aInstance->GetPeer(NS_REINTERPRET_CAST(nsIPluginInstancePeer **, &peer));
if (NS_SUCCEEDED(rv) && peer)
{
nsCOMPtr<nsIPluginInstanceOwner> owner;
rv = peer->GetOwner(*getter_AddRefs(owner));
if (NS_SUCCEEDED(rv) && owner)
{
rv = owner->GetDocument(getter_AddRefs(doc));
if (NS_SUCCEEDED(rv) && doc)
{
nsCOMPtr<nsIURI> docURL;
doc->GetDocumentURL(getter_AddRefs(docURL));
// Create an absolute URL
rv = NS_MakeAbsoluteURI(absUrl, aURL, docURL);
}
}
NS_RELEASE(peer);
}
1998-09-15 03:48:58 +00:00
if (absUrl.IsEmpty())
absUrl.Assign(aURL);
rv = NS_NewURI(getter_AddRefs(url), absUrl);
if (NS_SUCCEEDED(rv))
1998-09-15 03:48:58 +00:00
{
nsPluginStreamListenerPeer *listenerPeer = new nsPluginStreamListenerPeer;
if (listenerPeer == NULL)
return NS_ERROR_OUT_OF_MEMORY;
NS_ADDREF(listenerPeer);
1999-01-25 08:05:00 +00:00
rv = listenerPeer->Initialize(url, aInstance, aListener);
1998-09-15 03:48:58 +00:00
if (NS_SUCCEEDED(rv))
{
nsCOMPtr<nsIInterfaceRequestor> callbacks;
if (doc)
{
// Get the script global object owner and use that as the notification callback
nsCOMPtr<nsIScriptGlobalObject> global;
doc->GetScriptGlobalObject(getter_AddRefs(global));
if (global)
{
nsCOMPtr<nsIScriptGlobalObjectOwner> owner;
global->GetGlobalObjectOwner(getter_AddRefs(owner));
callbacks = do_QueryInterface(owner);
}
}
nsCOMPtr<nsIChannel> channel;
1999-08-26 22:45:55 +00:00
// XXX: Null LoadGroup?
rv = NS_OpenURI(getter_AddRefs(channel), url, nsnull, nsnull, callbacks);
if (NS_FAILED(rv))
return rv;
if (doc)
{
// Set the owner of channel to the document principal...
nsCOMPtr<nsIPrincipal> principal;
doc->GetPrincipal(getter_AddRefs(principal));
channel->SetOwner(principal);
}
// deal with headers and post data
nsCOMPtr<nsIHttpChannel> httpChannel(do_QueryInterface(channel));
if(httpChannel) {
if (aPostData) {
nsCOMPtr<nsIInputStream> postDataStream;
const char * dataToPost = aPostData;
nsXPIDLCString filename;
if (aIsFile) {
// convert file:///c:/ to c:
nsCOMPtr<nsILocalFile> aFile = do_CreateInstance(NS_LOCAL_FILE_CONTRACTID);
if (NS_SUCCEEDED(NS_InitFileFromURLSpec(aFile,dataToPost)))
if (NS_SUCCEEDED(aFile->GetPath(getter_Copies(filename)))) {
// tell the listener about it so it will delete the file later
listenerPeer->SetLocalFile(filename);
dataToPost = filename;
}
}
rv = NS_NewPluginPostDataStream(getter_AddRefs(postDataStream), dataToPost,
aPostDataLen, aIsFile);
if (!postDataStream)
{
NS_RELEASE(aInstance);
return NS_ERROR_UNEXPECTED;
}
// XXX it's a bit of a hack to rewind the postdata stream
// here but it has to be done in case the post data is
// being reused multiple times.
nsCOMPtr<nsISeekableStream>
postDataSeekable(do_QueryInterface(postDataStream));
if (postDataSeekable)
postDataSeekable->Seek(nsISeekableStream::NS_SEEK_SET, 0);
nsCOMPtr<nsIUploadChannel> uploadChannel(do_QueryInterface(httpChannel));
NS_ASSERTION(uploadChannel, "http must support nsIUploadChannel");
uploadChannel->SetUploadStream(postDataStream, nsnull, -1);
if (newPostData)
{
delete [] (char *)newPostData;
newPostData = nsnull;
}
}
if (aHeadersData)
rv = AddHeadersToChannel(aHeadersData, aHeadersDataLen, httpChannel);
}
rv = channel->AsyncOpen(listenerPeer, nsnull);
}
NS_RELEASE(listenerPeer);
}
return rv;
}
////////////////////////////////////////////////////////////////////////
NS_IMETHODIMP
nsPluginHostImpl::AddHeadersToChannel(const char *aHeadersData,
PRUint32 aHeadersDataLen,
nsIChannel *aGenericChannel)
{
nsresult rv = NS_OK;
nsCOMPtr<nsIHttpChannel> aChannel = do_QueryInterface(aGenericChannel);
if (!aChannel) {
return NS_ERROR_NULL_POINTER;
}
// used during the manipulation of the String from the aHeadersData
nsCAutoString headersString;
nsCAutoString oneHeader;
nsCAutoString headerName;
nsCAutoString headerValue;
PRInt32 crlf = 0;
PRInt32 colon = 0;
//
// Turn the char * buffer into an nsString.
//
headersString = aHeadersData;
//
// Iterate over the nsString: for each "\r\n" delimeted chunk,
// add the value as a header to the nsIHTTPChannel
//
while (PR_TRUE) {
crlf = headersString.Find("\r\n", PR_TRUE);
if (-1 == crlf) {
rv = NS_OK;
return rv;
}
headersString.Mid(oneHeader, 0, crlf);
headersString.Cut(0, crlf + 2);
oneHeader.StripWhitespace();
colon = oneHeader.Find(":");
if (-1 == colon) {
rv = NS_ERROR_NULL_POINTER;
return rv;
}
oneHeader.Left(headerName, colon);
colon++;
oneHeader.Mid(headerValue, colon, oneHeader.Length() - colon);
//
// FINALLY: we can set the header!
//
rv =aChannel->SetRequestHeader(headerName.get(), headerValue.get());
if (NS_FAILED(rv)) {
rv = NS_ERROR_NULL_POINTER;
return rv;
}
}
return rv;
}
////////////////////////////////////////////////////////////////////////
NS_IMETHODIMP
nsPluginHostImpl::StopPluginInstance(nsIPluginInstance* aInstance)
{
PLUGIN_LOG(PLUGIN_LOG_NORMAL,
("nsPluginHostImpl::StopPluginInstance called instance=%p\n",aInstance));
nsActivePlugin * plugin = mActivePluginList.find(aInstance);
if(plugin != nsnull)
{
plugin->setStopped(PR_TRUE); // be sure we set the "stop" bit
// if the plugin does not want to be 'cached' just remove it
PRBool doCache = PR_TRUE;
aInstance->GetValue(nsPluginInstanceVariable_DoCacheBool, (void *) &doCache);
// we also do that for 4x plugin, shall we? Let's see if it is
PRBool oldSchool = PR_TRUE;
if(plugin->mPluginTag)
oldSchool = plugin->mPluginTag->mFlags & NS_PLUGIN_FLAG_OLDSCHOOL ? PR_TRUE : PR_FALSE;
if (!doCache || oldSchool)
{
PRLibrary * library = nsnull;
if(plugin->mPluginTag)
library = plugin->mPluginTag->mLibrary;
PRBool unloadLibLater = PR_FALSE;
mActivePluginList.remove(plugin, &unloadLibLater);
if(unloadLibLater)
AddToUnusedLibraryList(library);
}
else
{
// if it is allowed to be cached simply stop it, but first we should check
// if we haven't exceeded the maximum allowed number of cached instances
// try to get the max cached plugins from a pref or use default
PRUint32 max_num;
nsresult rv;
nsCOMPtr<nsIPref> prefs = do_GetService(NS_PREF_CONTRACTID);
if (prefs) rv = prefs->GetIntPref(NS_PREF_MAX_NUM_CACHED_PLUGINS,(int *)&max_num);
if (NS_FAILED(rv)) max_num = DEFAULT_NUMBER_OF_STOPPED_PLUGINS;
if(mActivePluginList.getStoppedCount() >= max_num)
{
nsActivePlugin * oldest = mActivePluginList.findOldestStopped();
if(oldest != nsnull)
{
PRLibrary * library = oldest->mPluginTag->mLibrary;
PRBool unloadLibLater = PR_FALSE;
mActivePluginList.remove(oldest, &unloadLibLater);
if(unloadLibLater)
AddToUnusedLibraryList(library);
}
}
}
}
return NS_OK;
}
1999-01-25 08:05:00 +00:00
////////////////////////////////////////////////////////////////////////
/* Called by InstantiateEmbededPlugin() */
nsresult nsPluginHostImpl::NewEmbededPluginStream(nsIURI* aURL,
1998-09-15 03:48:58 +00:00
nsIPluginInstanceOwner *aOwner,
nsIPluginInstance* aInstance)
{
nsPluginStreamListenerPeer *listener = (nsPluginStreamListenerPeer *)new nsPluginStreamListenerPeer();
1999-07-30 23:51:53 +00:00
if (listener == nsnull)
return NS_ERROR_OUT_OF_MEMORY;
nsresult rv;
1998-09-15 03:48:58 +00:00
if (!aURL)
return NS_OK;
// if we have an instance, everything has been set up
// if we only have an owner, then we need to pass it in
// so the listener can set up the instance later after
// we've determined the mimetype of the stream
if(aInstance != nsnull)
rv = listener->InitializeEmbeded(aURL, aInstance);
else if(aOwner != nsnull)
rv = listener->InitializeEmbeded(aURL, nsnull, aOwner, (nsIPluginHost *)this);
else
rv = NS_ERROR_ILLEGAL_VALUE;
1998-09-15 03:48:58 +00:00
if (NS_OK == rv) {
// XXX: Null LoadGroup?
rv = NS_OpenURI(listener, nsnull, aURL, nsnull);
}
1998-09-15 03:48:58 +00:00
//NS_RELEASE(aURL);
return rv;
1998-09-15 03:48:58 +00:00
}
1999-01-25 08:05:00 +00:00
////////////////////////////////////////////////////////////////////////
/* Called by InstantiateFullPagePlugin() */
nsresult nsPluginHostImpl::NewFullPagePluginStream(nsIStreamListener *&aStreamListener,
nsIPluginInstance *aInstance)
1998-09-15 03:48:58 +00:00
{
1999-01-25 08:05:00 +00:00
nsPluginStreamListenerPeer *listener = (nsPluginStreamListenerPeer *)new nsPluginStreamListenerPeer();
1999-07-30 23:51:53 +00:00
if (listener == nsnull)
return NS_ERROR_OUT_OF_MEMORY;
nsresult rv;
1998-09-15 03:48:58 +00:00
1999-01-25 08:05:00 +00:00
rv = listener->InitializeFullPage(aInstance);
1998-09-15 03:48:58 +00:00
aStreamListener = (nsIStreamListener *)listener;
NS_IF_ADDREF(listener);
// add peer to list of stream peers for this instance
nsActivePlugin * p = mActivePluginList.find(aInstance);
if (p && p->mStreams)
{
p->mStreams->AppendElement((void *)aStreamListener);
NS_ADDREF(listener);
}
1998-09-15 03:48:58 +00:00
return rv;
}
1999-01-25 08:05:00 +00:00
// nsIFileUtilities interface
////////////////////////////////////////////////////////////////////////
1999-01-25 08:05:00 +00:00
NS_IMETHODIMP nsPluginHostImpl::GetProgramPath(const char* *result)
{
nsresult rv;
NS_ENSURE_ARG_POINTER(result);
*result = nsnull;
nsCOMPtr<nsIProperties> dirService(do_GetService(kDirectoryServiceContractID, &rv));
if (NS_FAILED(rv))
return rv;
nsCOMPtr<nsIFile> programDir;
rv = dirService->Get(NS_XPCOM_CURRENT_PROCESS_DIR, NS_GET_IID(nsIFile), getter_AddRefs(programDir));
if (NS_FAILED(rv))
return rv;
char *temp;
rv = programDir->GetPath(&temp);
*result = temp;
return rv;
1999-01-25 08:05:00 +00:00
}
////////////////////////////////////////////////////////////////////////
1999-01-25 08:05:00 +00:00
NS_IMETHODIMP nsPluginHostImpl::GetTempDirPath(const char* *result)
{
nsresult rv;
NS_ENSURE_ARG_POINTER(result);
*result = nsnull;
nsCOMPtr<nsIProperties> dirService(do_GetService(kDirectoryServiceContractID, &rv));
if (NS_FAILED(rv))
return rv;
nsCOMPtr<nsIFile> tempDir;
rv = dirService->Get(NS_OS_TEMP_DIR, NS_GET_IID(nsIFile), getter_AddRefs(tempDir));
if (NS_FAILED(rv))
return rv;
char *temp;
rv = tempDir->GetPath(&temp);
*result = temp;
return rv;
1999-01-25 08:05:00 +00:00
}
////////////////////////////////////////////////////////////////////////
1999-01-25 08:05:00 +00:00
NS_IMETHODIMP nsPluginHostImpl::NewTempFileName(const char* prefix, PRUint32 bufLen, char* resultBuf)
{
return NS_ERROR_NOT_IMPLEMENTED;
1999-03-20 23:11:25 +00:00
}
1999-03-20 23:11:25 +00:00
// nsICookieStorage interface
////////////////////////////////////////////////////////////////////////
1999-03-20 23:11:25 +00:00
NS_IMETHODIMP nsPluginHostImpl::GetCookie(const char* inCookieURL, void* inOutCookieBuffer, PRUint32& inOutCookieSize)
{
nsresult rv = NS_ERROR_NOT_IMPLEMENTED;
nsXPIDLCString cookieString;
PRUint32 cookieStringLen = 0;
nsCOMPtr<nsIURI> uriIn;
if ((nsnull == inCookieURL) || (0 >= inOutCookieSize)) {
return NS_ERROR_INVALID_ARG;
}
nsCOMPtr<nsIIOService> ioService(do_GetService(kIOServiceCID, &rv));
if (NS_FAILED(rv) || (nsnull == ioService)) {
return rv;
}
nsCOMPtr<nsICookieService> cookieService =
do_GetService(kCookieServiceCID, &rv);
if (NS_FAILED(rv) || (nsnull == cookieService)) {
return NS_ERROR_INVALID_ARG;
}
// make an nsURI from the argument url
rv = ioService->NewURI(inCookieURL, nsnull, getter_AddRefs(uriIn));
if (NS_FAILED(rv)) {
return rv;
}
rv = cookieService->GetCookieString(uriIn, getter_Copies(cookieString));
if (NS_FAILED(rv) || (!cookieString) ||
(inOutCookieSize <= (cookieStringLen = PL_strlen(cookieString.get())))) {
return NS_ERROR_FAILURE;
}
PL_strcpy((char *) inOutCookieBuffer, cookieString.get());
inOutCookieSize = cookieStringLen;
rv = NS_OK;
return rv;
1999-03-20 23:11:25 +00:00
}
////////////////////////////////////////////////////////////////////////
1999-03-20 23:11:25 +00:00
NS_IMETHODIMP nsPluginHostImpl::SetCookie(const char* inCookieURL, const void* inCookieBuffer, PRUint32 inCookieSize)
{
nsresult rv = NS_ERROR_NOT_IMPLEMENTED;
nsCOMPtr<nsIURI> uriIn;
if ((nsnull == inCookieURL) || (nsnull == inCookieBuffer) ||
(0 >= inCookieSize)) {
return NS_ERROR_INVALID_ARG;
}
nsCOMPtr<nsIIOService> ioService(do_GetService(kIOServiceCID, &rv));
if (NS_FAILED(rv) || (nsnull == ioService)) {
return rv;
}
nsCOMPtr<nsICookieService> cookieService =
do_GetService(kCookieServiceCID, &rv);
if (NS_FAILED(rv) || (nsnull == cookieService)) {
return NS_ERROR_FAILURE;
}
// make an nsURI from the argument url
rv = ioService->NewURI(inCookieURL, nsnull, getter_AddRefs(uriIn));
if (NS_FAILED(rv)) {
return NS_ERROR_FAILURE;
}
char * cookie = (char *)inCookieBuffer;
char c = cookie[inCookieSize];
cookie[inCookieSize] = '\0';
rv = cookieService->SetCookieString(uriIn, nsnull, cookie,0); // needs an nsIPrompt parameter
cookie[inCookieSize] = c;
return rv;
1999-01-25 08:05:00 +00:00
}
////////////////////////////////////////////////////////////////////////
NS_IMETHODIMP nsPluginHostImpl::Observe(nsISupports *aSubject,
const char *aTopic,
const PRUnichar *someData)
{
#ifdef NS_DEBUG
printf("nsPluginHostImpl::Observe \"%s\"\n", aTopic ? aTopic : "");
#endif
if (!nsCRT::strcmp(NS_XPCOM_SHUTDOWN_OBSERVER_ID, aTopic) ||
!nsCRT::strcmp("quit-application", aTopic))
{
Destroy();
}
return NS_OK;
}
////////////////////////////////////////////////////////////////////////
NS_IMETHODIMP
nsPluginHostImpl::SetIsScriptableInstance(nsCOMPtr<nsIPluginInstance> aPluginInstance,
PRBool aScriptable)
{
nsActivePlugin * p = mActivePluginList.find(aPluginInstance.get());
if(p == nsnull)
return NS_ERROR_FAILURE;
p->mXPConnected = aScriptable;
if(p->mPluginTag)
p->mPluginTag->mXPConnected = aScriptable;
return NS_OK;
}
////////////////////////////////////////////////////////////////////////
NS_IMETHODIMP nsPluginHostImpl::HandleBadPlugin(PRLibrary* aLibrary)
{
nsresult rv = NS_OK;
NS_ASSERTION(PR_FALSE, "Plugin performed illegal operation");
if(mDontShowBadPluginMessage)
return rv;
nsCOMPtr<nsIPrompt> prompt;
nsCOMPtr<nsIWindowWatcher> wwatch(do_GetService("@mozilla.org/embedcomp/window-watcher;1"));
if (wwatch)
wwatch->GetNewPrompter(0, getter_AddRefs(prompt));
nsCOMPtr<nsIIOService> io(do_GetService(kIOServiceCID));
nsCOMPtr<nsIStringBundleService> strings(do_GetService(kStringBundleServiceCID));
if (!prompt || !io || !strings)
return NS_ERROR_FAILURE;
nsCOMPtr<nsIStringBundle> bundle;
nsCOMPtr<nsIURI> uri;
char *spec = nsnull;
PRInt32 buttonPressed;
PRBool checkboxState = PR_FALSE;
rv = io->NewURI(PLUGIN_PROPERTIES_URL, nsnull, getter_AddRefs(uri));
if (NS_FAILED(rv))
return rv;
rv = uri->GetSpec(&spec);
if (NS_FAILED(rv))
{
nsCRT::free(spec);
return rv;
}
rv = strings->CreateBundle(spec, getter_AddRefs(bundle));
nsCRT::free(spec);
if (NS_FAILED(rv))
return rv;
PRUnichar *title = nsnull;
PRUnichar *message = nsnull;
PRUnichar *checkboxMessage = nsnull;
rv = bundle->GetStringFromName(NS_LITERAL_STRING("BadPluginTitle").get(),
&title);
if (NS_FAILED(rv))
return rv;
rv = bundle->GetStringFromName(NS_LITERAL_STRING("BadPluginMessage").get(),
&message);
if (NS_FAILED(rv))
{
nsMemory::Free((void *)title);
return rv;
}
rv = bundle->GetStringFromName(NS_LITERAL_STRING("BadPluginCheckboxMessage").get(),
&checkboxMessage);
if (NS_FAILED(rv))
{
nsMemory::Free((void *)title);
nsMemory::Free((void *)message);
return rv;
}
rv = prompt->ConfirmEx(title, message,
nsIPrompt::BUTTON_TITLE_OK * nsIPrompt::BUTTON_POS_0,
nsnull, nsnull, nsnull,
checkboxMessage, &checkboxState, &buttonPressed);
if (checkboxState)
mDontShowBadPluginMessage = PR_TRUE;
nsMemory::Free((void *)title);
nsMemory::Free((void *)message);
nsMemory::Free((void *)checkboxMessage);
return rv;
}