Back to index

lightning-sunbird  0.9+nobinonly
nsPluginHostImpl.cpp
Go to the documentation of this file.
00001 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
00002 /* ***** BEGIN LICENSE BLOCK *****
00003  * Version: MPL 1.1/GPL 2.0/LGPL 2.1
00004  *
00005  * The contents of this file are subject to the Mozilla Public License Version
00006  * 1.1 (the "License"); you may not use this file except in compliance with
00007  * the License. You may obtain a copy of the License at
00008  * http://www.mozilla.org/MPL/
00009  *
00010  * Software distributed under the License is distributed on an "AS IS" basis,
00011  * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
00012  * for the specific language governing rights and limitations under the
00013  * License.
00014  *
00015  * The Original Code is mozilla.org code.
00016  *
00017  * The Initial Developer of the Original Code is
00018  * Netscape Communications Corporation.
00019  * Portions created by the Initial Developer are Copyright (C) 1998
00020  * the Initial Developer. All Rights Reserved.
00021  *
00022  * Contributor(s):
00023  *   Sean Echevarria <sean@beatnik.com>
00024  *   Håkan Waara <hwaara@chello.se>
00025  *   Josh Aas <josh@mozillafoundation.org>
00026  *
00027  * Alternatively, the contents of this file may be used under the terms of
00028  * either the GNU General Public License Version 2 or later (the "GPL"), or
00029  * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
00030  * in which case the provisions of the GPL or the LGPL are applicable instead
00031  * of those above. If you wish to allow use of your version of this file only
00032  * under the terms of either the GPL or the LGPL, and not to allow others to
00033  * use your version of this file under the terms of the MPL, indicate your
00034  * decision by deleting the provisions above and replace them with the notice
00035  * and other provisions required by the GPL or the LGPL. If you do not delete
00036  * the provisions above, a recipient may use your version of this file under
00037  * the terms of any one of the MPL, the GPL or the LGPL.
00038  *
00039  * ***** END LICENSE BLOCK ***** */
00040 
00041 /* nsPluginHostImpl.cpp - bulk of code for managing plugins */
00042 
00043 #include "nscore.h"
00044 #include "nsPluginHostImpl.h"
00045 
00046 #include <stdio.h>
00047 #include "prio.h"
00048 #include "prmem.h"
00049 #include "ns4xPlugin.h"
00050 #include "ns4xPluginStreamListener.h"
00051 #include "nsPluginInstancePeer.h"
00052 #include "nsIPlugin.h"
00053 #ifdef OJI
00054 #include "nsIJVMPlugin.h"
00055 #include "nsIJVMPluginInstance.h"
00056 #include "nsIJVMManager.h"
00057 #endif
00058 #include "nsIPluginStreamListener.h"
00059 #include "nsIHTTPHeaderListener.h"
00060 #include "nsIHttpHeaderVisitor.h"
00061 #include "nsIObserverService.h"
00062 #include "nsIHttpProtocolHandler.h"
00063 #include "nsIHttpChannel.h"
00064 #include "nsIHttpChannelInternal.h"
00065 #include "nsIUploadChannel.h"
00066 #include "nsIByteRangeRequest.h"
00067 #include "nsIStreamListener.h"
00068 #include "nsIInputStream.h"
00069 #include "nsIOutputStream.h"
00070 #include "nsIURL.h"
00071 #include "nsXPIDLString.h"
00072 #include "nsReadableUtils.h"
00073 #include "nsIProtocolProxyService.h"
00074 #include "nsIStreamConverterService.h"
00075 #include "nsIFile.h"
00076 #include "nsIInputStream.h"
00077 #include "nsIIOService.h"
00078 #include "nsIURL.h"
00079 #include "nsIChannel.h"
00080 #include "nsISeekableStream.h"
00081 #include "nsNetUtil.h"
00082 #include "nsIProgressEventSink.h"
00083 #include "nsIDocument.h"
00084 #include "nsIScriptablePlugin.h"
00085 #include "nsICachingChannel.h"
00086 #include "nsHashtable.h"
00087 #include "nsIProxyInfo.h"
00088 #include "nsObsoleteModuleLoading.h"
00089 #include "nsIComponentRegistrar.h"
00090 #include "nsPluginLogging.h"
00091 #include "nsPrintfCString.h"
00092 
00093 // Friggin' X11 has to "#define None". Lame!
00094 #ifdef None
00095 #undef None
00096 #endif
00097 
00098 #ifdef CursorShape
00099 #undef CursorShape /*X.h defines it as 0,
00100                      qnamespace.h makes an enum type by that name
00101                    */
00102 #endif
00103 
00104 //#include "nsIRegistry.h"
00105 #include "nsEnumeratorUtils.h"
00106 #include "nsXPCOM.h"
00107 #include "nsXPCOMCID.h"
00108 #include "nsICategoryManager.h"
00109 #include "nsISupportsPrimitives.h"
00110 // for the dialog
00111 #include "nsIStringBundle.h"
00112 #include "nsIWindowWatcher.h"
00113 #include "nsPIDOMWindow.h"
00114 
00115 #include "nsIScriptGlobalObject.h"
00116 #include "nsIScriptGlobalObjectOwner.h"
00117 #include "nsIPrincipal.h"
00118 
00119 #include "nsIServiceManager.h"
00120 #include "nsNetCID.h"
00121 #include "nsICookieService.h"
00122 #include "nsIDOMPlugin.h"
00123 #include "nsIDOMMimeType.h"
00124 #include "nsMimeTypes.h"
00125 #include "prprf.h"
00126 #include "plevent.h"
00127 #include "nsIEventQueueService.h"
00128 #include "nsIEventQueue.h"
00129 #include "nsIInputStreamTee.h"
00130 #include "nsIInterfaceInfoManager.h"
00131 #include "xptinfo.h"
00132 
00133 #if defined(XP_WIN)
00134 #include "windows.h"
00135 #include "winbase.h"
00136 #endif
00137 
00138 #include "nsIMIMEService.h"
00139 #include "nsCExternalHandlerService.h"
00140 #include "nsILocalFile.h"
00141 #include "nsIFileChannel.h"
00142 
00143 #include "nsPluginSafety.h"
00144 
00145 #include "nsICharsetConverterManager.h"
00146 #include "nsIPlatformCharset.h"
00147 
00148 #include "nsIDirectoryService.h"
00149 #include "nsDirectoryServiceDefs.h"
00150 #include "nsAppDirectoryServiceDefs.h"
00151 #include "nsIFile.h"
00152 #include "nsPluginDirServiceProvider.h"
00153 #include "nsInt64.h"
00154 #include "nsPluginError.h"
00155 
00156 #include "nsUnicharUtils.h"
00157 #include "nsPluginManifestLineReader.h"
00158 
00159 #include "imgILoader.h"
00160 #include "nsDefaultPlugin.h"
00161 #include "nsWeakReference.h"
00162 #include "nsIDOMElement.h"
00163 #include "nsIDOMHTMLObjectElement.h"
00164 #include "nsIDOMHTMLEmbedElement.h"
00165 #include "nsIPresShell.h"
00166 #include "nsPresContext.h"
00167 #include "nsIWebNavigation.h"
00168 #include "nsISupportsArray.h"
00169 #include "nsIDocShell.h"
00170 #include "nsPluginNativeWindow.h"
00171 #include "nsIScriptSecurityManager.h"
00172 #include "nsIContentPolicy.h"
00173 #include "nsContentPolicyUtils.h"
00174 #include "nsContentErrors.h"
00175 
00176 #ifdef XP_UNIX
00177 #if defined(MOZ_WIDGET_GTK) || defined (MOZ_WIDGET_GTK2)
00178 #include <gdk/gdkx.h> // for GDK_DISPLAY()
00179 #elif defined(MOZ_WIDGET_QT)
00180 #include <qwindowdefs.h> // for qt_xdisplay()
00181 #elif defined(MOZ_WIDGET_XLIB)
00182 #include "xlibrgb.h" // for xlib_rgb_get_display()
00183 #endif
00184 #endif
00185 
00186 #ifdef XP_MACOSX
00187 #include <Carbon/Carbon.h> // for ::UseInputWindow()
00188 #include <mach-o/loader.h>
00189 #include <mach-o/fat.h>
00190 #endif
00191 
00192 #ifdef XP_OS2
00193 #include "nsILegacyPluginWrapperOS2.h"
00194 #endif
00195 
00196 // this is the name of the directory which will be created
00197 // to cache temporary files.
00198 #define kPluginTmpDirName NS_LITERAL_CSTRING("plugtmp")
00199 
00200 // Version of cached plugin info
00201 // 0.01 first implementation
00202 // 0.02 added caching of CanUnload to fix bug 105935
00203 // 0.03 changed name, description and mime desc from string to bytes, bug 108246
00204 // 0.04 added new mime entry point on Mac, bug 113464
00205 // 0.05 added new entry point check for the default plugin, bug 132430
00206 // 0.06 strip off suffixes in mime description strings, bug 53895
00207 // 0.07 changed nsIRegistry to flat file support for caching plugins info
00208 // 0.08 mime entry point on MachO, bug 137535
00209 static const char *kPluginRegistryVersion = "0.08";
00211 // CID's && IID's
00212 static NS_DEFINE_IID(kIPluginInstanceIID, NS_IPLUGININSTANCE_IID);
00213 static NS_DEFINE_IID(kIPluginInstancePeerIID, NS_IPLUGININSTANCEPEER_IID);
00214 static NS_DEFINE_IID(kIPluginStreamInfoIID, NS_IPLUGINSTREAMINFO_IID);
00215 static NS_DEFINE_CID(kPluginCID, NS_PLUGIN_CID);
00216 static NS_DEFINE_IID(kIPluginTagInfo2IID, NS_IPLUGINTAGINFO2_IID);
00217 static NS_DEFINE_CID(kProtocolProxyServiceCID, NS_PROTOCOLPROXYSERVICE_CID);
00218 static NS_DEFINE_CID(kCookieServiceCID, NS_COOKIESERVICE_CID);
00219 static NS_DEFINE_IID(kISupportsIID, NS_ISUPPORTS_IID);
00220 static NS_DEFINE_CID(kIOServiceCID, NS_IOSERVICE_CID);
00221 static NS_DEFINE_CID(kHttpHandlerCID, NS_HTTPPROTOCOLHANDLER_CID);
00222 static NS_DEFINE_CID(kStreamConverterServiceCID, NS_STREAMCONVERTERSERVICE_CID);
00223 static const char kDirectoryServiceContractID[] = "@mozilla.org/file/directory_service;1";
00224 // for the dialog
00225 static NS_DEFINE_IID(kStringBundleServiceCID, NS_STRINGBUNDLESERVICE_CID);
00226 static NS_DEFINE_CID(kEventQueueServiceCID, NS_EVENTQUEUESERVICE_CID);
00227 static NS_DEFINE_CID(kCPluginManagerCID, NS_PLUGINMANAGER_CID); // needed for NS_TRY_SAFE_CALL
00228 
00230 // Registry keys for caching plugin info
00231 static const char kPluginsRootKey[] = "software/plugins";
00232 static const char kPluginsNameKey[] = "name";
00233 static const char kPluginsDescKey[] = "description";
00234 static const char kPluginsFilenameKey[] = "filename";
00235 static const char kPluginsFullpathKey[] = "fullpath";
00236 static const char kPluginsModTimeKey[] = "lastModTimeStamp";
00237 static const char kPluginsCanUnload[] = "canUnload";
00238 static const char kPluginsVersionKey[] = "version";
00239 static const char kPluginsMimeTypeKey[] = "mimetype";
00240 static const char kPluginsMimeDescKey[] = "description";
00241 static const char kPluginsMimeExtKey[] = "extension";
00242 
00243 #define kPluginRegistryFilename NS_LITERAL_CSTRING("pluginreg.dat")
00244 
00245 #ifdef PLUGIN_LOGGING
00246 PRLogModuleInfo* nsPluginLogging::gNPNLog = nsnull;
00247 PRLogModuleInfo* nsPluginLogging::gNPPLog = nsnull;
00248 PRLogModuleInfo* nsPluginLogging::gPluginLog = nsnull;
00249 #endif
00250 
00251 #define BRAND_PROPERTIES_URL "chrome://branding/locale/brand.properties"
00252 #define PLUGIN_PROPERTIES_URL "chrome://global/locale/downloadProgress.properties"
00253 #define PLUGIN_REGIONAL_URL "chrome://global-region/locale/region.properties"
00254 
00255 // #defines for reading prefs and extra search plugin paths from windows registry
00256 #define _MAXKEYVALUE_ 8196
00257 #define _NS_PREF_COMMON_PLUGIN_REG_KEY_ "browser.plugins.registry_plugins_folder_key_location"
00258 #define _NS_COMMON_PLUGIN_KEY_NAME_ "Plugins Folders"
00259 
00260 // #defines for plugin cache and prefs
00261 #define NS_PREF_MAX_NUM_CACHED_PLUGINS "browser.plugins.max_num_cached_plugins"
00262 #define DEFAULT_NUMBER_OF_STOPPED_PLUGINS 10
00263 
00264 #define MAGIC_REQUEST_CONTEXT 0x01020304
00265 
00266 nsresult PostPluginUnloadEvent(PRLibrary * aLibrary);
00267 
00268 static nsActivePluginList *gActivePluginList;
00269 
00270 #ifdef CALL_SAFETY_ON
00271 PRBool gSkipPluginSafeCalls = PR_FALSE;
00272 #endif
00273 
00274 nsIFile *nsPluginHostImpl::sPluginTempDir;
00275 
00277 // flat file reg funcs
00278 static
00279 PRBool ReadSectionHeader(nsPluginManifestLineReader& reader, const char *token)
00280 {
00281   do {
00282     if (*reader.LinePtr() == '[') {
00283       char* p = reader.LinePtr() + (reader.LineLength() - 1);
00284       if (*p != ']')
00285         break;
00286       *p = 0;
00287 
00288       char* values[1];
00289       if (1 != reader.ParseLine(values, 1))
00290         break;
00291       // ignore the leading '['
00292       if (PL_strcmp(values[0]+1, token)) {
00293         break; // it's wrong token
00294       }
00295       return PR_TRUE;
00296     }
00297   } while (reader.NextLine());
00298   return PR_FALSE;
00299 }
00300 
00302 // Little helper struct to asynchronously reframe any presentations (embedded)
00303 // or reload any documents (full-page), that contained plugins
00304 // which were shutdown as a result of a plugins.refresh(1)
00305 struct nsPluginDocReframeEvent: public PLEvent {
00306   nsPluginDocReframeEvent (nsISupportsArray* aDocs)  { mDocs = aDocs; }
00307   nsresult HandlePluginDocReframeEvent();
00308   nsCOMPtr<nsISupportsArray> mDocs;
00309 };
00310 
00311 nsresult nsPluginDocReframeEvent::HandlePluginDocReframeEvent() {
00312   NS_ENSURE_TRUE(mDocs, NS_ERROR_FAILURE);
00313 
00314   PRUint32 c;
00315   mDocs->Count(&c);
00316 
00317   // for each document (which previously had a running instance), tell
00318   // the frame constructor to rebuild
00319   for (PRUint32 i = 0; i < c; i++) {
00320     nsCOMPtr<nsIDocument> doc (do_QueryElementAt(mDocs, i));
00321     if (doc) {
00322       nsIPresShell *shell = doc->GetShellAt(0);
00323 
00324       // if this document has a presentation shell, then it has frames and can be reframed
00325       if (shell) {
00336         shell->ReconstructFrames(); // causes reframe of document
00337       } else {  // no pres shell --> full-page plugin
00338 
00339         NS_NOTREACHED("all plugins should have a pres shell!");
00340 
00341       }
00342     }
00343   }
00344 
00345   return mDocs->Clear();
00346 }
00347 
00348 
00349 
00350 
00351 //----------------------------------------------------------------------
00352 static void* PR_CALLBACK HandlePluginDocReframePLEvent(PLEvent* aEvent)
00353 {
00354   nsPluginDocReframeEvent* event = NS_REINTERPRET_CAST(nsPluginDocReframeEvent*, aEvent);
00355   event->HandlePluginDocReframeEvent();
00356   return nsnull;
00357 }
00358 static void PR_CALLBACK DestroyPluginDocReframePLEvent(PLEvent* aEvent)
00359 {
00360   delete aEvent;
00361 }
00362 
00363 
00365 nsActivePlugin::nsActivePlugin(nsPluginTag* aPluginTag,
00366                                nsIPluginInstance* aInstance,
00367                                const char * url,
00368                                PRBool aDefaultPlugin,
00369                                nsIPluginInstancePeer* peer)
00370 {
00371   mNext = nsnull;
00372   mPeer = nsnull;
00373   mPluginTag = aPluginTag;
00374 
00375   mURL = PL_strdup(url);
00376   mInstance = aInstance;
00377   if(aInstance && peer)
00378   {
00379     mPeer = peer;
00380     NS_ADDREF(mPeer);
00381     NS_ADDREF(aInstance);
00382   }
00383   mXPConnected = PR_FALSE;
00384   mDefaultPlugin = aDefaultPlugin;
00385   mStopped = PR_FALSE;
00386   mllStopTime = LL_ZERO;
00387 }
00388 
00389 
00391 nsActivePlugin::~nsActivePlugin()
00392 {
00393   mPluginTag = nsnull;
00394   if(mInstance != nsnull)
00395   {
00396     if(mPeer)
00397     {
00398       nsresult rv = NS_OK;
00399       nsCOMPtr<nsPIPluginInstancePeer> peer(do_QueryInterface(mPeer));
00400       nsCOMPtr<nsIPluginInstanceOwner> owner;
00401       rv = peer->GetOwner(getter_AddRefs(owner));
00402       if (owner)
00403         owner->SetInstance(nsnull);
00404     }
00405 
00406     // now check for cached plugins because they haven't had nsIPluginInstance::Destroy()
00407     // called yet. For non-cached plugins, nsIPluginInstance::Destroy() is called
00408     // in either nsObjectFrame::Destroy() or nsActivePluginList::stopRunning()
00409     PRBool doCache = PR_TRUE;
00410     mInstance->GetValue(nsPluginInstanceVariable_DoCacheBool, (void *) &doCache);
00411     if (doCache)
00412       mInstance->Destroy();
00413 
00414     NS_RELEASE(mInstance);
00415     NS_RELEASE(mPeer);
00416   }
00417   PL_strfree(mURL);
00418 }
00419 
00420 
00422 void nsActivePlugin::setStopped(PRBool stopped)
00423 {
00424   mStopped = stopped;
00425   if(mStopped) // plugin instance is told to stop
00426     mllStopTime = PR_Now();
00427   else
00428     mllStopTime = LL_ZERO;
00429 }
00430 
00431 
00433 nsActivePluginList::nsActivePluginList()
00434 {
00435   mFirst = nsnull;
00436   mLast = nsnull;
00437   mCount = 0;
00438 }
00439 
00440 
00442 nsActivePluginList::~nsActivePluginList()
00443 {
00444   if(mFirst == nsnull)
00445     return;
00446   shut();
00447 }
00448 
00449 
00451 void nsActivePluginList::shut()
00452 {
00453   if(mFirst == nsnull)
00454     return;
00455 
00456   for(nsActivePlugin * plugin = mFirst; plugin != nsnull;)
00457   {
00458     nsActivePlugin * next = plugin->mNext;
00459     remove(plugin);
00460     plugin = next;
00461   }
00462   mFirst = nsnull;
00463   mLast = nsnull;
00464 }
00465 
00466 
00468 PRInt32 nsActivePluginList::add(nsActivePlugin * plugin)
00469 {
00470   if (mFirst == nsnull)
00471   {
00472     mFirst = plugin;
00473     mLast = plugin;
00474     mFirst->mNext = nsnull;
00475   }
00476   else
00477   {
00478     mLast->mNext = plugin;
00479     mLast = plugin;
00480   }
00481   mLast->mNext = nsnull;
00482   mCount++;
00483   return mCount;
00484 }
00485 
00486 
00488 PRBool nsActivePluginList::IsLastInstance(nsActivePlugin * plugin)
00489 {
00490   if(!plugin)
00491     return PR_FALSE;
00492 
00493   if(!plugin->mPluginTag)
00494     return PR_FALSE;
00495 
00496   for(nsActivePlugin * p = mFirst; p != nsnull; p = p->mNext)
00497   {
00498     if((p->mPluginTag == plugin->mPluginTag) && (p != plugin))
00499       return PR_FALSE;
00500   }
00501   return PR_TRUE;
00502 }
00503 
00504 
00506 PRBool nsActivePluginList::remove(nsActivePlugin * plugin)
00507 {
00508   if(mFirst == nsnull)
00509     return PR_FALSE;
00510 
00511   nsActivePlugin * prev = nsnull;
00512   for(nsActivePlugin * p = mFirst; p != nsnull; p = p->mNext)
00513   {
00514     if(p == plugin)
00515     {
00516       PRBool lastInstance = IsLastInstance(p);
00517 
00518       if(p == mFirst)
00519         mFirst = p->mNext;
00520       else
00521         prev->mNext = p->mNext;
00522 
00523       if((prev != nsnull) && (prev->mNext == nsnull))
00524         mLast = prev;
00525 
00526       // see if this is going to be the last instance of a plugin
00527       // if so we should perform nsIPlugin::Shutdown and unload the library
00528       // by calling nsPluginTag::TryUnloadPlugin()
00529       if(lastInstance)
00530       {
00531         // cache some things as we are going to destroy it right now
00532         nsPluginTag *pluginTag = p->mPluginTag;
00533 
00534         delete p; // plugin instance is destroyed here
00535 
00536         if(pluginTag)
00537           pluginTag->TryUnloadPlugin();
00538         else
00539           NS_ASSERTION(pluginTag, "pluginTag was not set, plugin not shutdown");
00540 
00541       }
00542       else
00543         delete p;
00544 
00545       mCount--;
00546       return PR_TRUE;
00547     }
00548     prev = p;
00549   }
00550   return PR_FALSE;
00551 }
00552 
00553 
00555 // This method terminates all running instances of plugins and collects their
00556 // documents to be returned through an array. This method is used
00557 // when we are shutting down or when a plugins.refresh(1) happens.
00558 void nsActivePluginList::stopRunning(nsISupportsArray* aReloadDocs)
00559 {
00560   if(mFirst == nsnull)
00561     return;
00562 
00563   PRBool doCallSetWindowAfterDestroy = PR_FALSE;
00564 
00565   for(nsActivePlugin * p = mFirst; p != nsnull; p = p->mNext)
00566   {
00567     if(!p->mStopped && p->mInstance)
00568     {
00569       // then determine if the plugin wants Destroy to be called after
00570       // Set Window.  This is for bug 50547.
00571       p->mInstance->GetValue(nsPluginInstanceVariable_CallSetWindowAfterDestroyBool,
00572                              (void *) &doCallSetWindowAfterDestroy);
00573       if (doCallSetWindowAfterDestroy) {
00574         p->mInstance->Stop();
00575         p->mInstance->Destroy();
00576         p->mInstance->SetWindow(nsnull);
00577       }
00578       else {
00579         p->mInstance->SetWindow(nsnull);
00580         p->mInstance->Stop();
00581         p->mInstance->Destroy();
00582       }
00583       doCallSetWindowAfterDestroy = PR_FALSE;
00584       p->setStopped(PR_TRUE);
00585 
00586       // If we've been passed an array to return, lets collect all our documents,
00587       // removing duplicates. These will be reframed (embedded) or reloaded (full-page) later
00588       // to kickstart our instances.
00589       if (aReloadDocs && p->mPeer) {
00590         nsCOMPtr<nsPIPluginInstancePeer> peer(do_QueryInterface(p->mPeer));
00591         nsCOMPtr<nsIPluginInstanceOwner> owner;
00592         peer->GetOwner(getter_AddRefs(owner));
00593         if (owner) {
00594           nsCOMPtr<nsIDocument> doc;
00595           owner->GetDocument(getter_AddRefs(doc));
00596           if (doc && aReloadDocs->IndexOf(doc) == -1)  // don't allow for duplicates
00597             aReloadDocs->AppendElement(doc);
00598         }
00599       }
00600     }
00601   }
00602 }
00603 
00604 
00606 void nsActivePluginList::removeAllStopped()
00607 {
00608   if(mFirst == nsnull)
00609     return;
00610 
00611   nsActivePlugin * next = nsnull;
00612 
00613   for(nsActivePlugin * p = mFirst; p != nsnull;)
00614   {
00615     next = p->mNext;
00616 
00617     if(p->mStopped)
00618       remove(p);
00619 
00620     p = next;
00621   }
00622   return;
00623 }
00624 
00625 
00627 nsActivePlugin * nsActivePluginList::find(nsIPluginInstance* instance)
00628 {
00629   for(nsActivePlugin * p = mFirst; p != nsnull; p = p->mNext)
00630   {
00631     if(p->mInstance == instance)
00632     {
00633 #ifdef NS_DEBUG
00634       PRBool doCache = PR_TRUE;
00635       p->mInstance->GetValue(nsPluginInstanceVariable_DoCacheBool, (void *) &doCache);
00636       NS_ASSERTION(!p->mStopped || doCache, "This plugin is not supposed to be cached!");
00637 #endif
00638       return p;
00639     }
00640   }
00641   return nsnull;
00642 }
00643 
00644 nsActivePlugin * nsActivePluginList::find(const char * mimetype)
00645 {
00646   PRBool defaultplugin = (PL_strcmp(mimetype, "*") == 0);
00647 
00648   for(nsActivePlugin * p = mFirst; p != nsnull; p = p->mNext)
00649   {
00650     // give it some special treatment for the default plugin first
00651     // because we cannot tell the default plugin by asking peer for a mime type
00652     if(defaultplugin && p->mDefaultPlugin)
00653       return p;
00654 
00655     if(!p->mPeer)
00656       continue;
00657 
00658     nsMIMEType mt;
00659 
00660     nsresult res = p->mPeer->GetMIMEType(&mt);
00661 
00662     if(NS_FAILED(res))
00663       continue;
00664 
00665     if(PL_strcasecmp(mt, mimetype) == 0)
00666     {
00667 #ifdef NS_DEBUG
00668       PRBool doCache = PR_TRUE;
00669       p->mInstance->GetValue(nsPluginInstanceVariable_DoCacheBool, (void *) &doCache);
00670       NS_ASSERTION(!p->mStopped || doCache, "This plugin is not supposed to be cached!");
00671 #endif
00672        return p;
00673     }
00674   }
00675   return nsnull;
00676 }
00677 
00678 
00680 nsActivePlugin * nsActivePluginList::findStopped(const char * url)
00681 {
00682   for(nsActivePlugin * p = mFirst; p != nsnull; p = p->mNext)
00683   {
00684     if(!PL_strcmp(url, p->mURL) && p->mStopped)
00685     {
00686 #ifdef NS_DEBUG
00687       PRBool doCache = PR_TRUE;
00688       p->mInstance->GetValue(nsPluginInstanceVariable_DoCacheBool, (void *) &doCache);
00689       NS_ASSERTION(doCache, "This plugin is not supposed to be cached!");
00690 #endif
00691        return p;
00692     }
00693   }
00694   return nsnull;
00695 }
00696 
00697 
00699 PRUint32 nsActivePluginList::getStoppedCount()
00700 {
00701   PRUint32 stoppedCount = 0;
00702   for(nsActivePlugin * p = mFirst; p != nsnull; p = p->mNext)
00703   {
00704     if(p->mStopped)
00705       stoppedCount++;
00706   }
00707   return stoppedCount;
00708 }
00709 
00710 
00712 nsActivePlugin * nsActivePluginList::findOldestStopped()
00713 {
00714   nsActivePlugin * res = nsnull;
00715   PRInt64 llTime = LL_MAXINT;
00716   for(nsActivePlugin * p = mFirst; p != nsnull; p = p->mNext)
00717   {
00718     if(!p->mStopped)
00719       continue;
00720 
00721     if(LL_CMP(p->mllStopTime, <, llTime))
00722     {
00723       llTime = p->mllStopTime;
00724       res = p;
00725     }
00726   }
00727 
00728 #ifdef NS_DEBUG
00729   if(res)
00730   {
00731     PRBool doCache = PR_TRUE;
00732     res->mInstance->GetValue(nsPluginInstanceVariable_DoCacheBool, (void *) &doCache);
00733     NS_ASSERTION(doCache, "This plugin is not supposed to be cached!");
00734   }
00735 #endif
00736 
00737   return res;
00738 }
00739 
00741 nsPluginTag::nsPluginTag()
00742 {
00743   mPluginHost = nsnull;
00744   mNext = nsnull;
00745   mName = nsnull;
00746   mDescription = nsnull;
00747   mVariants = 0;
00748   mMimeTypeArray = nsnull;
00749   mMimeDescriptionArray = nsnull;
00750   mExtensionsArray = nsnull;
00751   mLibrary = nsnull;
00752   mCanUnloadLibrary = PR_TRUE;
00753   mEntryPoint = nsnull;
00754   mFlags = NS_PLUGIN_FLAG_ENABLED;
00755   mXPConnected = PR_FALSE;
00756   mFileName = nsnull;
00757   mFullPath = nsnull;
00758 }
00759 
00760 
00762 inline char* new_str(const char* str)
00763 {
00764   if(str == nsnull)
00765     return nsnull;
00766 
00767   char* result = new char[strlen(str) + 1];
00768   if (result != nsnull)
00769     return strcpy(result, str);
00770   return result;
00771 }
00772 
00773 
00775 nsPluginTag::nsPluginTag(nsPluginTag* aPluginTag)
00776 {
00777   mPluginHost = nsnull;
00778   mNext = nsnull;
00779   mName = new_str(aPluginTag->mName);
00780   mDescription = new_str(aPluginTag->mDescription);
00781   mVariants = aPluginTag->mVariants;
00782 
00783   mMimeTypeArray = nsnull;
00784   mMimeDescriptionArray = nsnull;
00785   mExtensionsArray = nsnull;
00786 
00787   if(aPluginTag->mMimeTypeArray != nsnull)
00788   {
00789     mMimeTypeArray = new char*[mVariants];
00790     for (int i = 0; i < mVariants; i++)
00791       mMimeTypeArray[i] = new_str(aPluginTag->mMimeTypeArray[i]);
00792   }
00793 
00794   if(aPluginTag->mMimeDescriptionArray != nsnull)
00795   {
00796     mMimeDescriptionArray = new char*[mVariants];
00797     for (int i = 0; i < mVariants; i++)
00798       mMimeDescriptionArray[i] = new_str(aPluginTag->mMimeDescriptionArray[i]);
00799   }
00800 
00801   if(aPluginTag->mExtensionsArray != nsnull)
00802   {
00803     mExtensionsArray = new char*[mVariants];
00804     for (int i = 0; i < mVariants; i++)
00805       mExtensionsArray[i] = new_str(aPluginTag->mExtensionsArray[i]);
00806   }
00807 
00808   mLibrary = nsnull;
00809   mCanUnloadLibrary = PR_TRUE;
00810   mEntryPoint = nsnull;
00811   mFlags = NS_PLUGIN_FLAG_ENABLED;
00812   mXPConnected = PR_FALSE;
00813   mFileName = new_str(aPluginTag->mFileName);
00814   mFullPath = new_str(aPluginTag->mFullPath);
00815 }
00816 
00817 
00819 nsPluginTag::nsPluginTag(nsPluginInfo* aPluginInfo)
00820 {
00821   mPluginHost = nsnull;
00822   mNext = nsnull;
00823   mName = new_str(aPluginInfo->fName);
00824   mDescription = new_str(aPluginInfo->fDescription);
00825   mVariants = aPluginInfo->fVariantCount;
00826 
00827   mMimeTypeArray = nsnull;
00828   mMimeDescriptionArray = nsnull;
00829   mExtensionsArray = nsnull;
00830 
00831   if(aPluginInfo->fMimeTypeArray != nsnull)
00832   {
00833     mMimeTypeArray = new char*[mVariants];
00834     for (int i = 0; i < mVariants; i++)
00835       mMimeTypeArray[i] = new_str(aPluginInfo->fMimeTypeArray[i]);
00836   }
00837 
00838   if(aPluginInfo->fMimeDescriptionArray != nsnull)
00839   {
00840     mMimeDescriptionArray = new char*[mVariants];
00841     for (int i = 0; i < mVariants; i++) {
00842       // we should cut off the list of suffixes which the mime
00843       // description string may have, see bug 53895
00844       // it is usually in form "some description (*.sf1, *.sf2)"
00845       // so we can search for the opening round bracket
00846       char cur = '\0';
00847       char pre = '\0';
00848       char * p = PL_strrchr(aPluginInfo->fMimeDescriptionArray[i], '(');
00849       if (p && (p != aPluginInfo->fMimeDescriptionArray[i])) {
00850         if ((p - 1) && *(p - 1) == ' ') {
00851           pre = *(p - 1);
00852           *(p - 1) = '\0';
00853         } else {
00854           cur = *p;
00855           *p = '\0';
00856         }
00857 
00858       }
00859       mMimeDescriptionArray[i] = new_str(aPluginInfo->fMimeDescriptionArray[i]);
00860       // restore the original string
00861       if (cur != '\0')
00862         *p = cur;
00863       if (pre != '\0')
00864         *(p - 1) = pre;
00865     }
00866   }
00867 
00868   if(aPluginInfo->fExtensionArray != nsnull)
00869   {
00870     mExtensionsArray = new char*[mVariants];
00871     for (int i = 0; i < mVariants; i++)
00872       mExtensionsArray[i] = new_str(aPluginInfo->fExtensionArray[i]);
00873   }
00874 
00875   mFileName = new_str(aPluginInfo->fFileName);
00876   mFullPath = new_str(aPluginInfo->fFullPath);
00877 
00878   mLibrary = nsnull;
00879   mCanUnloadLibrary = PR_TRUE;
00880   mEntryPoint = nsnull;
00881 #ifdef XP_MACOSX
00882   mCanUnloadLibrary = !aPluginInfo->fBundle;
00883 #endif
00884   mFlags = NS_PLUGIN_FLAG_ENABLED;
00885   mXPConnected = PR_FALSE;
00886 }
00887 
00888 
00889 
00891 nsPluginTag::nsPluginTag(const char* aName,
00892                          const char* aDescription,
00893                          const char* aFileName,
00894                          const char* aFullPath,
00895                          const char* const* aMimeTypes,
00896                          const char* const* aMimeDescriptions,
00897                          const char* const* aExtensions,
00898                          PRInt32 aVariants,
00899                          PRInt64 aLastModifiedTime,
00900                          PRBool aCanUnload)
00901   : mNext(nsnull),
00902     mVariants(aVariants),
00903     mMimeTypeArray(nsnull),
00904     mMimeDescriptionArray(nsnull),
00905     mExtensionsArray(nsnull),
00906     mLibrary(nsnull),
00907     mEntryPoint(nsnull),
00908     mFlags(0),
00909     mCanUnloadLibrary(aCanUnload),
00910     mXPConnected(PR_FALSE),
00911     mLastModifiedTime(aLastModifiedTime)
00912 {
00913   mPluginHost = nsnull;
00914   mName            = new_str(aName);
00915   mDescription     = new_str(aDescription);
00916   mFileName        = new_str(aFileName);
00917   mFullPath        = new_str(aFullPath);
00918 
00919   if (mVariants) {
00920     mMimeTypeArray        = new char*[mVariants];
00921     mMimeDescriptionArray = new char*[mVariants];
00922     mExtensionsArray      = new char*[mVariants];
00923 
00924     for (PRInt32 i = 0; i < aVariants; ++i) {
00925       mMimeTypeArray[i]        = new_str(aMimeTypes[i]);
00926       mMimeDescriptionArray[i] = new_str(aMimeDescriptions[i]);
00927       mExtensionsArray[i]      = new_str(aExtensions[i]);
00928     }
00929   }
00930 }
00931 
00932 nsPluginTag::~nsPluginTag()
00933 {
00934   TryUnloadPlugin(PR_TRUE);
00935 
00936   // Remove mime types added to the catagory manager
00937   // only if we were made 'active' by setting the host
00938   if (mPluginHost) {
00939     RegisterWithCategoryManager(PR_FALSE, nsPluginTag::ePluginUnregister);
00940   }
00941 
00942   if (nsnull != mName) {
00943     delete[] (mName);
00944     mName = nsnull;
00945   }
00946 
00947   if (nsnull != mDescription) {
00948     delete[] (mDescription);
00949     mDescription = nsnull;
00950   }
00951 
00952   if (nsnull != mMimeTypeArray) {
00953     for (int i = 0; i < mVariants; i++)
00954       delete[] mMimeTypeArray[i];
00955 
00956     delete[] (mMimeTypeArray);
00957     mMimeTypeArray = nsnull;
00958   }
00959 
00960   if (nsnull != mMimeDescriptionArray) {
00961     for (int i = 0; i < mVariants; i++)
00962       delete[] mMimeDescriptionArray[i];
00963 
00964     delete[] (mMimeDescriptionArray);
00965     mMimeDescriptionArray = nsnull;
00966   }
00967 
00968   if (nsnull != mExtensionsArray) {
00969     for (int i = 0; i < mVariants; i++)
00970       delete[] mExtensionsArray[i];
00971 
00972     delete[] (mExtensionsArray);
00973     mExtensionsArray = nsnull;
00974   }
00975 
00976   if(nsnull != mFileName)
00977   {
00978     delete [] mFileName;
00979     mFileName = nsnull;
00980   }
00981 
00982   if(nsnull != mFullPath)
00983   {
00984     delete [] mFullPath;
00985     mFullPath = nsnull;
00986   }
00987 
00988 }
00989 
00990 void nsPluginTag::SetHost(nsPluginHostImpl * aHost)
00991 {
00992   mPluginHost = aHost;
00993 }
00994 
00995 //----------------------------------------------------------------------
00996 // helper struct for asynchronous handeling of plugin unloading
00997 struct nsPluginUnloadEvent: public PLEvent {
00998   nsPluginUnloadEvent (PRLibrary* aLibrary);
00999 
01000   void HandleEvent() {
01001     if (mLibrary)
01002       NS_TRY_SAFE_CALL_VOID(PR_UnloadLibrary(mLibrary), nsnull, nsnull);  // put our unload call in a saftey wrapper
01003     else
01004       NS_WARNING("missing library from nsPluginUnloadEvent");
01005   }
01006 
01007   PRLibrary* mLibrary;
01008 };
01009 nsPluginUnloadEvent::nsPluginUnloadEvent (PRLibrary* aLibrary)
01010 {
01011   mLibrary = aLibrary;
01012 }
01013 //----------------------------------------------------------------------
01014 // helper static callback functions for plugin unloading PLEvents
01015 static void PR_CALLBACK HandlePluginUnloadPLEvent(nsPluginUnloadEvent* aEvent)
01016 {
01017   aEvent->HandleEvent();
01018 }
01019 static void PR_CALLBACK DestroyPluginUnloadPLEvent(nsPluginUnloadEvent* aEvent)
01020 {
01021   delete aEvent;
01022 }
01023 
01024 // unload plugin asynchronously if possible, otherwise just unload now
01025 nsresult PostPluginUnloadEvent (PRLibrary* aLibrary)
01026 {
01027   nsCOMPtr<nsIEventQueueService> eventService(do_GetService(kEventQueueServiceCID));
01028   if (eventService) {
01029     nsCOMPtr<nsIEventQueue> eventQueue;
01030     eventService->GetThreadEventQueue(PR_GetCurrentThread(), getter_AddRefs(eventQueue));
01031     if (eventQueue) {
01032       nsPluginUnloadEvent * ev = new nsPluginUnloadEvent(aLibrary);
01033       if (ev) {
01034 
01035         PL_InitEvent(ev, nsnull, (PLHandleEventProc) ::HandlePluginUnloadPLEvent, (PLDestroyEventProc) ::DestroyPluginUnloadPLEvent);
01036         if (NS_SUCCEEDED(eventQueue->PostEvent(ev)))
01037           return NS_OK;
01038         else NS_WARNING("failed to post event onto queue");
01039 
01040       } else NS_WARNING("not able to create plugin unload event");
01041     } else NS_WARNING("couldn't get event queue");
01042   } else NS_WARNING("couldn't get event queue service");
01043 
01044   // failure case
01045   NS_TRY_SAFE_CALL_VOID(PR_UnloadLibrary(aLibrary), nsnull, nsnull);
01046 
01047   return NS_ERROR_FAILURE;
01048 }
01049 
01050 
01052 void nsPluginTag::TryUnloadPlugin(PRBool aForceShutdown)
01053 {
01054   PRBool isXPCOM = PR_FALSE;
01055   if (!(mFlags & NS_PLUGIN_FLAG_OLDSCHOOL))
01056     isXPCOM = PR_TRUE;
01057 
01058   if (isXPCOM && !aForceShutdown) return;
01059 
01060   if (mEntryPoint)
01061   {
01062     mEntryPoint->Shutdown();
01063     mEntryPoint->Release();
01064     mEntryPoint = nsnull;
01065   }
01066 
01067   // before we unload check if we are allowed to, see bug #61388
01068   // also, never unload an XPCOM plugin library
01069   if (mLibrary && mCanUnloadLibrary && !isXPCOM) {
01070     // NPAPI plugins can be unloaded now if they don't use XPConnect
01071     if (!mXPConnected)
01072       // unload the plugin asynchronously by posting a PLEvent
01073       PostPluginUnloadEvent(mLibrary);
01074     else {
01075       // add library to the unused library list to handle it later
01076       if (mPluginHost)
01077         mPluginHost->AddUnusedLibrary(mLibrary);
01078     }
01079   }
01080 
01081   // we should zero it anyway, it is going to be unloaded by
01082   // CleanUnsedLibraries before we need to call the library
01083   // again so the calling code should not be fooled and reload
01084   // the library fresh
01085   mLibrary = nsnull;
01086 }
01087 
01089 PRBool nsPluginTag::Equals(nsPluginTag *aPluginTag)
01090 {
01091   NS_ENSURE_TRUE(aPluginTag, PR_FALSE);
01092 
01093   if ( (PL_strcmp(mName, aPluginTag->mName) != 0) ||
01094        (PL_strcmp(mDescription, aPluginTag->mDescription) != 0) ||
01095        (mVariants != aPluginTag->mVariants) )
01096     return PR_FALSE;
01097 
01098   if (mVariants && mMimeTypeArray && aPluginTag->mMimeTypeArray) {
01099     for (PRInt32 i = 0; i < mVariants; i++) {
01100       if (PL_strcmp(mMimeTypeArray[i], aPluginTag->mMimeTypeArray[i]) != 0)
01101         return PR_FALSE;
01102     }
01103   }
01104   return PR_TRUE;
01105 }
01106 
01108 class nsPluginStreamListenerPeer;
01109 
01110 class nsPluginStreamInfo : public nsI4xPluginStreamInfo
01111 {
01112 public:
01113   nsPluginStreamInfo();
01114   virtual ~nsPluginStreamInfo();
01115 
01116   NS_DECL_ISUPPORTS
01117 
01118   // nsIPluginStreamInfo interface
01119 
01120   NS_IMETHOD
01121   GetContentType(nsMIMEType* result);
01122 
01123   NS_IMETHOD
01124   IsSeekable(PRBool* result);
01125 
01126   NS_IMETHOD
01127   GetLength(PRUint32* result);
01128 
01129   NS_IMETHOD
01130   GetLastModified(PRUint32* result);
01131 
01132   NS_IMETHOD
01133   GetURL(const char** result);
01134 
01135   NS_IMETHOD
01136   RequestRead(nsByteRange* rangeList);
01137 
01138   NS_IMETHOD
01139   GetStreamOffset(PRInt32 *result);
01140 
01141   NS_IMETHOD
01142   SetStreamOffset(PRInt32 result);
01143 
01144   // local methods
01145 
01146   void
01147   SetContentType(const nsMIMEType contentType);
01148 
01149   void
01150   SetSeekable(const PRBool seekable);
01151 
01152   void
01153   SetLength(const PRUint32 length);
01154 
01155   void
01156   SetLastModified(const PRUint32 modified);
01157 
01158   void
01159   SetURL(const char* url);
01160 
01161   void
01162   SetPluginInstance(nsIPluginInstance * aPluginInstance);
01163 
01164   void
01165   SetPluginStreamListenerPeer(nsPluginStreamListenerPeer * aPluginStreamListenerPeer);
01166 
01167   void
01168   MakeByteRangeString(nsByteRange* aRangeList, nsACString &string, PRInt32 *numRequests);
01169 
01170   PRBool
01171   UseExistingPluginCacheFile(nsPluginStreamInfo* psi);
01172 
01173   void
01174   SetStreamComplete(const PRBool complete);
01175 
01176   void
01177   SetRequest(nsIRequest *request)
01178   {
01179     mRequest = request;
01180   }
01181 
01182 private:
01183 
01184   char* mContentType;
01185   char* mURL;
01186   PRBool mSeekable;
01187   PRUint32 mLength;
01188   PRUint32 mModified;
01189   nsIPluginInstance * mPluginInstance;
01190   nsPluginStreamListenerPeer * mPluginStreamListenerPeer;
01191   PRInt32 mStreamOffset;
01192   PRBool mStreamComplete;
01193 };
01194 
01195 
01197 
01198 class nsPluginStreamListenerPeer : public nsIStreamListener,
01199                                    public nsIProgressEventSink,
01200                                    public nsIHttpHeaderVisitor,
01201                                    public nsSupportsWeakReference
01202 {
01203 public:
01204   nsPluginStreamListenerPeer();
01205   virtual ~nsPluginStreamListenerPeer();
01206 
01207   NS_DECL_ISUPPORTS
01208   NS_DECL_NSIPROGRESSEVENTSINK
01209   NS_DECL_NSIREQUESTOBSERVER
01210   NS_DECL_NSISTREAMLISTENER
01211   NS_DECL_NSIHTTPHEADERVISITOR
01212 
01213   // Called by GetURL and PostURL (via NewStream)
01214   nsresult Initialize(nsIURI *aURL,
01215                       nsIPluginInstance *aInstance,
01216                       nsIPluginStreamListener *aListener,
01217                       PRInt32 requestCount = 1);
01218 
01219   nsresult InitializeEmbedded(nsIURI *aURL,
01220                              nsIPluginInstance* aInstance,
01221                              nsIPluginInstanceOwner *aOwner = nsnull,
01222                              nsIPluginHost *aHost = nsnull);
01223 
01224   nsresult InitializeFullPage(nsIPluginInstance *aInstance);
01225 
01226   nsresult OnFileAvailable(nsIFile* aFile);
01227 
01228   nsresult ServeStreamAsFile(nsIRequest *request, nsISupports *ctxt);
01229 
01230 private:
01231   nsresult SetUpCache(nsIURI* aURL); // todo: see about removing this...
01232   nsresult SetUpStreamListener(nsIRequest* request, nsIURI* aURL);
01233   nsresult SetupPluginCacheFile(nsIChannel* channel);
01234 
01235   nsIURI                  *mURL;
01236   nsIPluginInstanceOwner  *mOwner;
01237   nsIPluginInstance       *mInstance;
01238   nsIPluginStreamListener *mPStreamListener;
01239   nsRefPtr<nsPluginStreamInfo> mPluginStreamInfo;
01240 
01241   // Set to PR_TRUE if we request failed (like with a HTTP response of 404)
01242   PRPackedBool            mRequestFailed;
01243 
01244   /*
01245    * Set to PR_TRUE after nsIPluginInstancePeer::OnStartBinding() has
01246    * been called.  Checked in ::OnStopRequest so we can call the
01247    * plugin's OnStartBinding if, for some reason, it has not already
01248    * been called.
01249    */
01250   PRPackedBool      mStartBinding;
01251   PRPackedBool      mHaveFiredOnStartRequest;
01252   // these get passed to the plugin stream listener
01253   char                    *mMIMEType;
01254   PRUint32                mLength;
01255   nsPluginStreamType      mStreamType;
01256   nsIPluginHost           *mHost;
01257 
01258   // local cached file, we save the content into local cache if browser cache is not available,
01259   // or plugin asks stream as file and it expects file extension until bug 90558 got fixed
01260   nsIFile                 *mLocalCachedFile;
01261   nsCOMPtr<nsIOutputStream> mFileCacheOutputStream;
01262   nsHashtable             *mDataForwardToRequest;
01263 
01264 public:
01265   PRBool                  mAbort;
01266   PRInt32                 mPendingRequests;
01267   nsWeakPtr               mWeakPtrChannelCallbacks;
01268   nsWeakPtr               mWeakPtrChannelLoadGroup;
01269 };
01270 
01272 class nsPluginByteRangeStreamListener : public nsIStreamListener {
01273 public:
01274   nsPluginByteRangeStreamListener(nsIWeakReference* aWeakPtr);
01275   virtual ~nsPluginByteRangeStreamListener();
01276 
01277   // nsISupports
01278   NS_DECL_ISUPPORTS
01279 
01280   // nsIRequestObserver methods:
01281   NS_DECL_NSIREQUESTOBSERVER
01282 
01283   // nsIStreamListener methods:
01284   NS_DECL_NSISTREAMLISTENER
01285 
01286 private:
01287   nsCOMPtr<nsIStreamListener> mStreamConverter;
01288   nsWeakPtr mWeakPtrPluginStreamListenerPeer;
01289   PRBool mRemoveMagicNumber;
01290 };
01291 
01293 nsPluginStreamInfo::nsPluginStreamInfo()
01294 {
01295   mPluginInstance = nsnull;
01296   mPluginStreamListenerPeer = nsnull;
01297 
01298   mContentType = nsnull;
01299   mURL = nsnull;
01300   mSeekable = PR_FALSE;
01301   mLength = 0;
01302   mModified = 0;
01303   mStreamOffset = 0;
01304   mStreamComplete = PR_FALSE;
01305 }
01306 
01307 
01309 nsPluginStreamInfo::~nsPluginStreamInfo()
01310 {
01311   if(mContentType != nsnull)
01312   PL_strfree(mContentType);
01313   if(mURL != nsnull)
01314     PL_strfree(mURL);
01315 
01316   NS_IF_RELEASE(mPluginInstance);
01317 }
01318 
01320 NS_IMPL_ISUPPORTS2(nsPluginStreamInfo, nsIPluginStreamInfo,
01321                    nsI4xPluginStreamInfo)
01323 
01324 NS_IMETHODIMP
01325 nsPluginStreamInfo::GetContentType(nsMIMEType* result)
01326 {
01327   *result = mContentType;
01328   return NS_OK;
01329 }
01330 
01331 NS_IMETHODIMP
01332 nsPluginStreamInfo::IsSeekable(PRBool* result)
01333 {
01334   *result = mSeekable;
01335   return NS_OK;
01336 }
01337 
01338 NS_IMETHODIMP
01339 nsPluginStreamInfo::GetLength(PRUint32* result)
01340 {
01341   *result = mLength;
01342   return NS_OK;
01343 }
01344 
01345 NS_IMETHODIMP
01346 nsPluginStreamInfo::GetLastModified(PRUint32* result)
01347 {
01348   *result = mModified;
01349   return NS_OK;
01350 }
01351 
01352 NS_IMETHODIMP
01353 nsPluginStreamInfo::GetURL(const char** result)
01354 {
01355   *result = mURL;
01356   return NS_OK;
01357 }
01358 
01359 void
01360 nsPluginStreamInfo::MakeByteRangeString(nsByteRange* aRangeList, nsACString &rangeRequest, PRInt32 *numRequests)
01361 {
01362   rangeRequest.Truncate();
01363   *numRequests  = 0;
01364   //the string should look like this: bytes=500-700,601-999
01365   if(!aRangeList)
01366     return;
01367 
01368   PRInt32 requestCnt = 0;
01369   nsCAutoString string("bytes=");
01370 
01371   for(nsByteRange * range = aRangeList; range != nsnull; range = range->next)
01372   {
01373     // XXX zero length?
01374     if(!range->length)
01375       continue;
01376 
01377     // XXX needs to be fixed for negative offsets
01378     string.AppendInt(range->offset);
01379     string.Append("-");
01380     string.AppendInt(range->offset + range->length - 1);
01381     if(range->next)
01382       string += ",";
01383 
01384     requestCnt++;
01385   }
01386 
01387   // get rid of possible trailing comma
01388   string.Trim(",", PR_FALSE);
01389 
01390   rangeRequest = string;
01391   *numRequests  = requestCnt;
01392   return;
01393 }
01394 
01395 
01397 NS_IMETHODIMP
01398 nsPluginStreamInfo::RequestRead(nsByteRange* rangeList)
01399 {
01400   nsCAutoString rangeString;
01401   PRInt32 numRequests;
01402 
01403   //first of all lets see if mPluginStreamListenerPeer is still alive
01404   nsCOMPtr<nsISupportsWeakReference> suppWeakRef(
01405     do_QueryInterface((nsISupportsWeakReference *)(mPluginStreamListenerPeer)));
01406   if (!suppWeakRef)
01407     return NS_ERROR_FAILURE;
01408 
01409   nsCOMPtr<nsIWeakReference> pWeakRefPluginStreamListenerPeer =
01410            do_GetWeakReference(suppWeakRef);
01411   if (!pWeakRefPluginStreamListenerPeer)
01412     return NS_ERROR_FAILURE;
01413 
01414   MakeByteRangeString(rangeList, rangeString, &numRequests);
01415 
01416   if(numRequests == 0)
01417     return NS_ERROR_FAILURE;
01418 
01419   nsresult rv = NS_OK;
01420   nsCOMPtr<nsIURI> url;
01421 
01422   rv = NS_NewURI(getter_AddRefs(url), nsDependentCString(mURL));
01423 
01424   nsCOMPtr<nsIInterfaceRequestor> callbacks = do_QueryReferent(mPluginStreamListenerPeer->mWeakPtrChannelCallbacks);
01425   nsCOMPtr<nsILoadGroup> loadGroup = do_QueryReferent(mPluginStreamListenerPeer->mWeakPtrChannelLoadGroup);
01426   nsCOMPtr<nsIChannel> channel;
01427   rv = NS_NewChannel(getter_AddRefs(channel), url, nsnull, loadGroup, callbacks);
01428   if (NS_FAILED(rv))
01429     return rv;
01430 
01431   nsCOMPtr<nsIHttpChannel> httpChannel(do_QueryInterface(channel));
01432   if(!httpChannel)
01433     return NS_ERROR_FAILURE;
01434 
01435   httpChannel->SetRequestHeader(NS_LITERAL_CSTRING("Range"), rangeString, PR_FALSE);
01436 
01437   mPluginStreamListenerPeer->mAbort = PR_TRUE; // instruct old stream listener to cancel
01438                                                // the request on the next ODA.
01439 
01440   nsCOMPtr<nsIStreamListener> converter;
01441 
01442   if (numRequests == 1) {
01443     converter = mPluginStreamListenerPeer;
01444 
01445     // set current stream offset equal to the first offset in the range list
01446     // it will work for single byte range request
01447     // for multy range we'll reset it in ODA
01448     SetStreamOffset(rangeList->offset);
01449   } else {
01450     nsPluginByteRangeStreamListener *brrListener =
01451       new nsPluginByteRangeStreamListener(pWeakRefPluginStreamListenerPeer);
01452     if (brrListener)
01453       converter = brrListener;
01454     else
01455       return NS_ERROR_OUT_OF_MEMORY;
01456   }
01457 
01458   mPluginStreamListenerPeer->mPendingRequests += numRequests;
01459 
01460   nsCOMPtr<nsISupportsPRUint32> container = do_CreateInstance(NS_SUPPORTS_PRUINT32_CONTRACTID, &rv);
01461   if (NS_FAILED(rv))
01462     return rv;
01463   rv = container->SetData(MAGIC_REQUEST_CONTEXT);
01464   if (NS_FAILED(rv))
01465     return rv;
01466 
01467   return channel->AsyncOpen(converter, container);
01468 }
01469 
01470 NS_IMETHODIMP
01471 nsPluginStreamInfo::GetStreamOffset(PRInt32 *result)
01472 {
01473   *result = mStreamOffset;
01474   return NS_OK;
01475 }
01476 
01478 NS_IMETHODIMP
01479 nsPluginStreamInfo::SetStreamOffset(PRInt32 offset)
01480 {
01481   mStreamOffset = offset;
01482   return NS_OK;
01483 }
01484 
01486 void
01487 nsPluginStreamInfo::SetContentType(const nsMIMEType contentType)
01488 {
01489   if(mContentType != nsnull)
01490     PL_strfree(mContentType);
01491 
01492   mContentType = PL_strdup(contentType);
01493 }
01494 
01495 
01497 void
01498 nsPluginStreamInfo::SetSeekable(const PRBool seekable)
01499 {
01500   mSeekable = seekable;
01501 }
01502 
01503 
01505 void
01506 nsPluginStreamInfo::SetLength(const PRUint32 length)
01507 {
01508   mLength = length;
01509 }
01510 
01511 
01513 void
01514 nsPluginStreamInfo::SetLastModified(const PRUint32 modified)
01515 {
01516   mModified = modified;
01517 }
01518 
01519 
01521 void
01522 nsPluginStreamInfo::SetURL(const char* url)
01523 {
01524   if(mURL != nsnull)
01525     PL_strfree(mURL);
01526 
01527   mURL = PL_strdup(url);
01528 }
01529 
01531 void
01532 nsPluginStreamInfo::SetPluginInstance(nsIPluginInstance * aPluginInstance)
01533 {
01534     NS_IF_ADDREF(mPluginInstance = aPluginInstance);
01535 }
01536 
01537 
01539 void
01540 nsPluginStreamInfo::SetPluginStreamListenerPeer(nsPluginStreamListenerPeer * aPluginStreamListenerPeer)
01541 {
01542     // not addref'd - nsPluginStreamInfo is owned by mPluginStreamListenerPeer
01543     mPluginStreamListenerPeer = aPluginStreamListenerPeer;
01544 }
01545 
01546 
01548 
01549 class nsPluginCacheListener : public nsIStreamListener
01550 {
01551 public:
01552   nsPluginCacheListener(nsPluginStreamListenerPeer* aListener);
01553   virtual ~nsPluginCacheListener();
01554 
01555   NS_DECL_ISUPPORTS
01556 
01557   NS_DECL_NSIREQUESTOBSERVER
01558   NS_DECL_NSISTREAMLISTENER
01559 
01560 private:
01561   nsPluginStreamListenerPeer* mListener;
01562 };
01563 
01564 
01566 nsPluginCacheListener::nsPluginCacheListener(nsPluginStreamListenerPeer* aListener)
01567 {
01568   mListener = aListener;
01569   NS_ADDREF(mListener);
01570 }
01571 
01572 
01574 nsPluginCacheListener::~nsPluginCacheListener()
01575 {
01576   NS_IF_RELEASE(mListener);
01577 }
01578 
01579 
01581 NS_IMPL_ISUPPORTS1(nsPluginCacheListener, nsIStreamListener)
01583 NS_IMETHODIMP
01584 nsPluginCacheListener::OnStartRequest(nsIRequest *request, nsISupports* ctxt)
01585 {
01586   return NS_OK;
01587 }
01588 
01589 
01591 NS_IMETHODIMP
01592 nsPluginCacheListener::OnDataAvailable(nsIRequest *request, nsISupports* ctxt,
01593                                        nsIInputStream* aIStream,
01594                                        PRUint32 sourceOffset,
01595                                        PRUint32 aLength)
01596 {
01597 
01598   PRUint32 readlen;
01599   char* buffer = (char*) PR_Malloc(aLength);
01600 
01601   // if we don't read from the stream, OnStopRequest will never be called
01602   if(!buffer)
01603     return NS_ERROR_OUT_OF_MEMORY;
01604 
01605   nsresult rv = aIStream->Read(buffer, aLength, &readlen);
01606 
01607   NS_ASSERTION(aLength == readlen, "nsCacheListener->OnDataAvailable: "
01608                "readlen != aLength");
01609 
01610   PR_Free(buffer);
01611   return rv;
01612 }
01613 
01614 
01616 NS_IMETHODIMP
01617 nsPluginCacheListener::OnStopRequest(nsIRequest *request,
01618                                      nsISupports* aContext,
01619                                      nsresult aStatus)
01620 {
01621   return NS_OK;
01622 }
01623 
01625 
01626 nsPluginStreamListenerPeer::nsPluginStreamListenerPeer()
01627 {
01628   mURL = nsnull;
01629   mOwner = nsnull;
01630   mInstance = nsnull;
01631   mPStreamListener = nsnull;
01632   mHost = nsnull;
01633   mStreamType = nsPluginStreamType_Normal;
01634   mStartBinding = PR_FALSE;
01635   mAbort = PR_FALSE;
01636   mRequestFailed = PR_FALSE;
01637 
01638   mPendingRequests = 0;
01639   mHaveFiredOnStartRequest = PR_FALSE;
01640   mDataForwardToRequest = nsnull;
01641   mLocalCachedFile = nsnull;
01642 }
01643 
01644 
01646 nsPluginStreamListenerPeer::~nsPluginStreamListenerPeer()
01647 {
01648 #ifdef PLUGIN_LOGGING
01649   nsCAutoString urlSpec;
01650   if(mURL != nsnull) (void)mURL->GetSpec(urlSpec);
01651 
01652   PR_LOG(nsPluginLogging::gPluginLog, PLUGIN_LOG_NORMAL,
01653     ("nsPluginStreamListenerPeer::dtor this=%p, url=%s%c",this, urlSpec.get(), mLocalCachedFile?',':'\n'));
01654 #endif
01655 
01656   NS_IF_RELEASE(mURL);
01657   NS_IF_RELEASE(mOwner);
01658   NS_IF_RELEASE(mInstance);
01659   NS_IF_RELEASE(mPStreamListener);
01660   NS_IF_RELEASE(mHost);
01661 
01662   // close FD of mFileCacheOutputStream if it's still open
01663   // or we won't be able to remove the cache file
01664   if (mFileCacheOutputStream)
01665     mFileCacheOutputStream = nsnull;
01666 
01667   // if we have mLocalCachedFile lets release it
01668   // and it'll be fiscally remove if refcnt == 1
01669   if (mLocalCachedFile) {
01670     nsrefcnt refcnt;
01671     NS_RELEASE2(mLocalCachedFile, refcnt);
01672 
01673 #ifdef PLUGIN_LOGGING
01674     nsCAutoString filePath;
01675     mLocalCachedFile->GetNativePath(filePath);
01676 
01677     PR_LOG(nsPluginLogging::gPluginLog, PLUGIN_LOG_NORMAL,
01678       ("LocalyCachedFile=%s has %d refcnt and will %s be deleted now\n",filePath.get(),refcnt,refcnt==1?"":"NOT"));
01679 #endif
01680 
01681     if (refcnt == 1) {
01682       mLocalCachedFile->Remove(PR_FALSE);
01683       NS_RELEASE(mLocalCachedFile);
01684     }
01685   }
01686 
01687   delete mDataForwardToRequest;
01688 }
01689 
01690 
01692 NS_IMPL_ISUPPORTS4(nsPluginStreamListenerPeer,
01693                    nsIStreamListener,
01694                    nsIRequestObserver,
01695                    nsIHttpHeaderVisitor,
01696                    nsISupportsWeakReference)
01698 
01699 
01700 /* Called as a result of GetURL and PostURL */
01702 nsresult nsPluginStreamListenerPeer::Initialize(nsIURI *aURL,
01703                                                 nsIPluginInstance *aInstance,
01704                                                 nsIPluginStreamListener* aListener,
01705                                                 PRInt32 requestCount)
01706 {
01707 #ifdef PLUGIN_LOGGING
01708   nsCAutoString urlSpec;
01709   if(aURL != nsnull) (void)aURL->GetAsciiSpec(urlSpec);
01710 
01711   PR_LOG(nsPluginLogging::gPluginLog, PLUGIN_LOG_NORMAL,
01712         ("nsPluginStreamListenerPeer::Initialize instance=%p, url=%s\n", aInstance, urlSpec.get()));
01713 
01714   PR_LogFlush();
01715 #endif
01716 
01717   mURL = aURL;
01718   NS_ADDREF(mURL);
01719 
01720   mInstance = aInstance;
01721   NS_ADDREF(mInstance);
01722 
01723   mPStreamListener = aListener;
01724   NS_ADDREF(mPStreamListener);
01725 
01726   mPluginStreamInfo = new nsPluginStreamInfo();
01727   if (!mPluginStreamInfo)
01728     return NS_ERROR_OUT_OF_MEMORY;
01729 
01730   mPluginStreamInfo->SetPluginInstance(aInstance);
01731   mPluginStreamInfo->SetPluginStreamListenerPeer(this);
01732 
01733   mPendingRequests = requestCount;
01734 
01735   mDataForwardToRequest = new nsHashtable(16, PR_FALSE);
01736   if (!mDataForwardToRequest)
01737       return NS_ERROR_FAILURE;
01738 
01739   return NS_OK;
01740 }
01741 
01742 
01743 /*
01744     Called by NewEmbeddedPluginStream() - if this is called, we weren't
01745     able to load the plugin, so we need to load it later once we figure
01746     out the mimetype.  In order to load it later, we need the plugin
01747     host and instance owner.
01748 */
01750 nsresult nsPluginStreamListenerPeer::InitializeEmbedded(nsIURI *aURL,
01751                                                         nsIPluginInstance* aInstance,
01752                                                         nsIPluginInstanceOwner *aOwner,
01753                                                         nsIPluginHost *aHost)
01754 {
01755 #ifdef PLUGIN_LOGGING
01756   nsCAutoString urlSpec;
01757   if(aURL != nsnull) (void)aURL->GetSpec(urlSpec);
01758 
01759   PR_LOG(nsPluginLogging::gPluginLog, PLUGIN_LOG_NORMAL,
01760         ("nsPluginStreamListenerPeer::InitializeEmbedded url=%s\n", urlSpec.get()));
01761 
01762   PR_LogFlush();
01763 #endif
01764 
01765   mURL = aURL;
01766   NS_ADDREF(mURL);
01767 
01768   if(aInstance != nsnull) {
01769     NS_ASSERTION(mInstance == nsnull, "nsPluginStreamListenerPeer::InitializeEmbedded mInstance != nsnull");
01770     mInstance = aInstance;
01771     NS_ADDREF(mInstance);
01772   } else {
01773     mOwner = aOwner;
01774     NS_IF_ADDREF(mOwner);
01775 
01776     mHost = aHost;
01777     NS_IF_ADDREF(mHost);
01778   }
01779 
01780   mPluginStreamInfo = new nsPluginStreamInfo();
01781   if (!mPluginStreamInfo)
01782     return NS_ERROR_OUT_OF_MEMORY;
01783 
01784   mPluginStreamInfo->SetPluginInstance(aInstance);
01785   mPluginStreamInfo->SetPluginStreamListenerPeer(this);
01786 
01787   mDataForwardToRequest = new nsHashtable(16, PR_FALSE);
01788   if (!mDataForwardToRequest)
01789       return NS_ERROR_FAILURE;
01790 
01791   return NS_OK;
01792 }
01793 
01794 
01795 /* Called by NewFullPagePluginStream() */
01797 nsresult nsPluginStreamListenerPeer::InitializeFullPage(nsIPluginInstance *aInstance)
01798 {
01799   PLUGIN_LOG(PLUGIN_LOG_NORMAL,
01800   ("nsPluginStreamListenerPeer::InitializeFullPage instance=%p\n",aInstance));
01801 
01802   NS_ASSERTION(mInstance == nsnull, "nsPluginStreamListenerPeer::InitializeFullPage mInstance != nsnull");
01803   mInstance = aInstance;
01804   NS_ADDREF(mInstance);
01805 
01806   mPluginStreamInfo = new nsPluginStreamInfo();
01807   if (!mPluginStreamInfo)
01808     return NS_ERROR_OUT_OF_MEMORY;
01809 
01810   mPluginStreamInfo->SetPluginInstance(aInstance);
01811   mPluginStreamInfo->SetPluginStreamListenerPeer(this);
01812 
01813   mDataForwardToRequest = new nsHashtable(16, PR_FALSE);
01814   if (!mDataForwardToRequest)
01815       return NS_ERROR_FAILURE;
01816 
01817   return NS_OK;
01818 }
01819 
01820 
01822 // SetupPluginCacheFile is called if we have to save the stream to disk.
01823 // the most likely cause for this is either there is no disk cache available
01824 // or the stream is coming from a https server.
01825 //
01826 // These files will be deleted when the host is destroyed.
01827 //
01828 // TODO? What if we fill up the the dest dir?
01829 nsresult
01830 nsPluginStreamListenerPeer::SetupPluginCacheFile(nsIChannel* channel)
01831 {
01832   nsresult rv = NS_OK;
01833   // lets try to reused a file if we already have in the local plugin cache
01834   // we loop through all of active plugins
01835   // and call |nsPluginStreamInfo::UseExistingPluginCacheFile()| on opened stream
01836   // will return RP_TRUE if file exisrs
01837   // and some conditions are matched, in this case that file will be use
01838   // in |::OnFileAvailable()| calls w/o rewriting the file again.
01839   // The file will be deleted in |nsPluginStreamListenerPeer::~nsPluginStreamListenerPeer|
01840   PRBool useExistingCacheFile = PR_FALSE;
01841   nsActivePlugin *pActivePlugins = gActivePluginList->mFirst;
01842   while (pActivePlugins && pActivePlugins->mStreams && !useExistingCacheFile) {
01843     // most recent streams are at the end of list
01844     PRInt32 cnt;
01845     pActivePlugins->mStreams->Count((PRUint32*)&cnt);
01846     while (--cnt >= 0 && !useExistingCacheFile) {
01847       nsPluginStreamListenerPeer *lp =
01848         NS_REINTERPRET_CAST(nsPluginStreamListenerPeer *, pActivePlugins->mStreams->ElementAt(cnt));
01849       if (lp) {
01850         if (lp->mLocalCachedFile &&
01851             lp->mPluginStreamInfo &&
01852             (useExistingCacheFile =
01853              lp->mPluginStreamInfo->UseExistingPluginCacheFile(mPluginStreamInfo)))
01854         {
01855             NS_ADDREF(mLocalCachedFile = lp->mLocalCachedFile);
01856         }
01857         NS_RELEASE(lp);
01858       }
01859     }
01860     pActivePlugins = pActivePlugins->mNext;
01861   }
01862 
01863   if (!useExistingCacheFile) {
01864     nsCOMPtr<nsIFile> pluginTmp;
01865     rv = nsPluginHostImpl::GetPluginTempDir(getter_AddRefs(pluginTmp));
01866     if (NS_FAILED(rv)) {
01867       return rv;
01868     }
01869 
01870     // Get the filename from the channel
01871     nsCOMPtr<nsIURI> uri;
01872     rv = channel->GetURI(getter_AddRefs(uri));
01873     if (NS_FAILED(rv)) return rv;
01874 
01875     nsCOMPtr<nsIURL> url(do_QueryInterface(uri));
01876     if(!url)
01877       return NS_ERROR_FAILURE;
01878 
01879     nsCAutoString filename;
01880     url->GetFileName(filename);
01881     if (NS_FAILED(rv))
01882       return rv;
01883 
01884     // Create a file to save our stream into. Should we scramble the name?
01885     filename.Insert(NS_LITERAL_CSTRING("plugin-"), 0);
01886     rv = pluginTmp->AppendNative(filename);
01887     if (NS_FAILED(rv))
01888       return rv;
01889 
01890     // Yes, make it unique.
01891     rv = pluginTmp->CreateUnique(nsIFile::NORMAL_FILE_TYPE, 0600);
01892     if (NS_FAILED(rv))
01893       return rv;
01894 
01895     // create a file output stream to write to...
01896     nsCOMPtr<nsIOutputStream> outstream;
01897     rv = NS_NewLocalFileOutputStream(getter_AddRefs(mFileCacheOutputStream), pluginTmp, -1, 00600);
01898     if (NS_FAILED(rv))
01899       return rv;
01900 
01901     // save the file.
01902     CallQueryInterface(pluginTmp, &mLocalCachedFile); // no need to check return value, just addref
01903     // add one extra refcnt, we can use NS_RELEASE2(mLocalCachedFile...) in dtor
01904     // to remove this file when refcnt == 1
01905     NS_ADDREF(mLocalCachedFile);
01906   }
01907 
01908   // add this listenerPeer to list of stream peers for this instance
01909   // it'll delay release of listenerPeer until nsActivePlugin::~nsActivePlugin
01910   // and the temp file is going to stay alive until then
01911   pActivePlugins = gActivePluginList->find(mInstance);
01912   if (pActivePlugins) {
01913     if (!pActivePlugins->mStreams &&
01914        (NS_FAILED(rv = NS_NewISupportsArray(getter_AddRefs(pActivePlugins->mStreams))))) {
01915       return rv;
01916     }
01917 
01918     nsISupports* supports = NS_STATIC_CAST(nsISupports*, (NS_STATIC_CAST(nsIStreamListener*, this)));
01919     pActivePlugins->mStreams->AppendElement(supports);
01920   }
01921 
01922   return rv;
01923 }
01924 
01925 
01927 NS_IMETHODIMP
01928 nsPluginStreamListenerPeer::OnStartRequest(nsIRequest *request,
01929                                            nsISupports* aContext)
01930 {
01931   nsresult  rv = NS_OK;
01932 
01933   if (mHaveFiredOnStartRequest) {
01934       return NS_OK;
01935   }
01936 
01937   mHaveFiredOnStartRequest = PR_TRUE;
01938 
01939   nsCOMPtr<nsIChannel> channel = do_QueryInterface(request);
01940   NS_ENSURE_TRUE(channel, NS_ERROR_FAILURE);
01941 
01942   // deal with 404 (Not Found) HTTP response,
01943   // just return, this causes the request to be ignored.
01944   nsCOMPtr<nsIHttpChannel> httpChannel(do_QueryInterface(channel));
01945   if (httpChannel) {
01946     PRUint32 responseCode = 0;
01947     rv = httpChannel->GetResponseStatus(&responseCode);
01948     if (NS_FAILED(rv) || responseCode > 206) { // not normal
01949       // NPP_Notify() will be called from OnStopRequest
01950       // in ns4xPluginStreamListener::CleanUpStream
01951       // return error will cancel this request
01952       // ...and we also need to tell the plugin that
01953       mRequestFailed = PR_TRUE;
01954       return NS_ERROR_FAILURE;
01955     }
01956   }
01957 
01958   nsCAutoString contentType;
01959   rv = channel->GetContentType(contentType);
01960   if (NS_FAILED(rv)) 
01961     return rv;
01962 
01963   // do a little sanity check to make sure our frame isn't gone
01964   // by getting the tag type and checking for an error, we can determine if
01965   // the frame is gone
01966   if (mOwner) {
01967     nsCOMPtr<nsIPluginTagInfo2> pti2 = do_QueryInterface(mOwner);
01968     NS_ENSURE_TRUE(pti2, NS_ERROR_FAILURE);
01969     nsPluginTagType tagType;
01970     if (NS_FAILED(pti2->GetTagType(&tagType)))
01971       return NS_ERROR_FAILURE;  // something happened to our object frame, so bail!
01972 
01973     // Now that we know the content type, tell the DOM element.
01974     nsCOMPtr<nsIDOMElement> element;
01975     pti2->GetDOMElement(getter_AddRefs(element));
01976 
01977     nsCOMPtr<nsIDOMHTMLObjectElement> object(do_QueryInterface(element));
01978     if (object) {
01979       object->SetType(NS_ConvertASCIItoUTF16(contentType));
01980     } else {
01981       nsCOMPtr<nsIDOMHTMLEmbedElement> embed(do_QueryInterface(element));
01982       if (embed) {
01983         embed->SetType(NS_ConvertASCIItoUTF16(contentType));
01984       }
01985     }
01986   }
01987 
01988   // Get the notification callbacks from the channel and save it as
01989   // week ref we'll use it in nsPluginStreamInfo::RequestRead() when
01990   // we'll create channel for byte range request.
01991   nsCOMPtr<nsIInterfaceRequestor> callbacks;
01992   channel->GetNotificationCallbacks(getter_AddRefs(callbacks));
01993   if (callbacks)
01994     mWeakPtrChannelCallbacks = do_GetWeakReference(callbacks);
01995 
01996   nsCOMPtr<nsILoadGroup> loadGroup;
01997   channel->GetLoadGroup(getter_AddRefs(loadGroup));
01998   if (loadGroup)
01999     mWeakPtrChannelLoadGroup = do_GetWeakReference(loadGroup);
02000 
02001   PRInt32 length;
02002   rv = channel->GetContentLength(&length);
02003 
02004   // it's possible for the server to not send a Content-Length.
02005   // we should still work in this case.
02006   if (NS_FAILED(rv) || length == -1) {
02007     // check out if this is file channel
02008     nsCOMPtr<nsIFileChannel> fileChannel = do_QueryInterface(channel);
02009     if (fileChannel) {
02010       // file does not exist
02011       mRequestFailed = PR_TRUE;
02012       return NS_ERROR_FAILURE;
02013     }
02014     mPluginStreamInfo->SetLength(PRUint32(0));
02015   }
02016   else {
02017     mPluginStreamInfo->SetLength(length);
02018   }
02019 
02020   mPluginStreamInfo->SetRequest(request);
02021 
02022   nsCAutoString aContentType;
02023   rv = channel->GetContentType(aContentType);
02024   if (NS_FAILED(rv))
02025     return rv;
02026 
02027   nsCOMPtr<nsIURI> aURL;
02028   rv = channel->GetURI(getter_AddRefs(aURL));
02029   if (NS_FAILED(rv))
02030     return rv;
02031 
02032   nsCAutoString urlSpec;
02033   aURL->GetSpec(urlSpec);
02034   mPluginStreamInfo->SetURL(urlSpec.get());
02035 
02036   if (!aContentType.IsEmpty())
02037     mPluginStreamInfo->SetContentType(aContentType.get());
02038 
02039 #ifdef PLUGIN_LOGGING
02040   PR_LOG(nsPluginLogging::gPluginLog, PLUGIN_LOG_NOISY,
02041   ("nsPluginStreamListenerPeer::OnStartRequest this=%p request=%p mime=%s, url=%s\n",
02042   this, request, aContentType.get(), urlSpec.get()));
02043 
02044   PR_LogFlush();
02045 #endif
02046 
02047   nsPluginWindow    *window = nsnull;
02048 
02049   // if we don't have an nsIPluginInstance (mInstance), it means
02050   // we weren't able to load a plugin previously because we
02051   // didn't have the mimetype.  Now that we do (aContentType),
02052   // we'll try again with SetUpPluginInstance()
02053   // which is called by InstantiateEmbeddedPlugin()
02054   // NOTE: we don't want to try again if we didn't get the MIME type this time
02055 
02056   if ((nsnull == mInstance) && (nsnull != mOwner) && (!aContentType.IsEmpty()))
02057   {
02058     mOwner->GetInstance(mInstance);
02059     mOwner->GetWindow(window);
02060 
02061     if ((nsnull == mInstance) && (nsnull != mHost) && (nsnull != window))
02062     {
02063       // determine if we need to try embedded again. FullPage takes a different code path
02064       nsPluginMode mode;
02065       mOwner->GetMode(&mode);
02066       if (mode == nsPluginMode_Embedded)
02067         rv = mHost->InstantiateEmbeddedPlugin(aContentType.get(), aURL, mOwner);
02068       else
02069         rv = mHost->SetUpPluginInstance(aContentType.get(), aURL, mOwner);
02070 
02071       if (NS_OK == rv)
02072       {
02073         // GetInstance() adds a ref
02074         mOwner->GetInstance(mInstance);
02075 
02076         if (nsnull != mInstance)
02077         {
02078           mInstance->Start();
02079           mOwner->CreateWidget();
02080 
02081           // If we've got a native window, the let the plugin know
02082           // about it.
02083           if (window->window)
02084           {
02085             nsCOMPtr<nsIPluginInstance> inst = mInstance;
02086             ((nsPluginNativeWindow*)window)->CallSetWindow(inst);
02087           }
02088         }
02089       }
02090     }
02091   }
02092 
02093   //
02094   // Set up the stream listener...
02095   //
02096   rv = SetUpStreamListener(request, aURL);
02097   if (NS_FAILED(rv)) return rv;
02098 
02099   return rv;
02100 }
02101 
02102 
02104 NS_IMETHODIMP nsPluginStreamListenerPeer::OnProgress(nsIRequest *request,
02105                                                      nsISupports* aContext,
02106                                                      PRUint64 aProgress,
02107                                                      PRUint64 aProgressMax)
02108 {
02109   nsresult rv = NS_OK;
02110   return rv;
02111 }
02112 
02113 
02115 NS_IMETHODIMP nsPluginStreamListenerPeer::OnStatus(nsIRequest *request,
02116                                                    nsISupports* aContext,
02117                                                    nsresult aStatus,
02118                                                    const PRUnichar* aStatusArg)
02119 {
02120   return NS_OK;
02121 }
02122 
02123 
02125 class nsPRUintKey : public nsHashKey {
02126 protected:
02127     PRUint32 mKey;
02128 public:
02129     nsPRUintKey(PRUint32 key) : mKey(key) {}
02130 
02131     PRUint32 HashCode(void) const {
02132         return mKey;
02133     }
02134 
02135     PRBool Equals(const nsHashKey *aKey) const {
02136         return mKey == ((const nsPRUintKey *) aKey)->mKey;
02137     }
02138     nsHashKey *Clone() const {
02139         return new nsPRUintKey(mKey);
02140     }
02141     PRUint32 GetValue() { return mKey; }
02142 };
02143 
02144 
02146 NS_IMETHODIMP nsPluginStreamListenerPeer::OnDataAvailable(nsIRequest *request,
02147                                                           nsISupports* aContext,
02148                                                           nsIInputStream *aIStream,
02149                                                           PRUint32 sourceOffset,
02150                                                           PRUint32 aLength)
02151 {
02152   if (mRequestFailed)
02153     return NS_ERROR_FAILURE;
02154 
02155   if(mAbort)
02156   {
02157       PRUint32 magicNumber = 0;  // set it to something that is not the magic number.
02158       nsCOMPtr<nsISupportsPRUint32> container = do_QueryInterface(aContext);
02159       if (container)
02160         container->GetData(&magicNumber);
02161 
02162       if (magicNumber != MAGIC_REQUEST_CONTEXT)
02163       {
02164         // this is not one of our range requests
02165         mAbort = PR_FALSE;
02166         return NS_BINDING_ABORTED;
02167       }
02168   }
02169 
02170   nsresult rv = NS_OK;
02171 
02172   if(!mPStreamListener || !mPluginStreamInfo)
02173     return NS_ERROR_FAILURE;
02174 
02175   mPluginStreamInfo->SetRequest(request);
02176 
02177   const char * url = nsnull;
02178   mPluginStreamInfo->GetURL(&url);
02179 
02180   PLUGIN_LOG(PLUGIN_LOG_NOISY,
02181   ("nsPluginStreamListenerPeer::OnDataAvailable this=%p request=%p, offset=%d, length=%d, url=%s\n",
02182   this, request, sourceOffset, aLength, url ? url : "no url set"));
02183 
02184   // if the plugin has requested an AsFileOnly stream, then don't
02185   // call OnDataAvailable
02186   if(mStreamType != nsPluginStreamType_AsFileOnly)
02187   {
02188     // get the absolute offset of the request, if one exists.
02189     nsCOMPtr<nsIByteRangeRequest> brr = do_QueryInterface(request);
02190     if (brr) {
02191       if (!mDataForwardToRequest)
02192         return NS_ERROR_FAILURE;
02193 
02194       PRInt64 absoluteOffset64 = LL_ZERO;
02195       brr->GetStartRange(&absoluteOffset64);
02196 
02197       // XXX handle 64-bit for real
02198       PRInt32 absoluteOffset = (PRInt32)nsInt64(absoluteOffset64);
02199 
02200       // we need to track how much data we have forwarded to the
02201       // plugin.
02202 
02203       // FIXME: http://bugzilla.mozilla.org/show_bug.cgi?id=240130
02204       //
02205       // Why couldn't this be tracked on the plugin info, and not in a
02206       // *hash table*?
02207       nsPRUintKey key(absoluteOffset);
02208       PRInt32 amtForwardToPlugin =
02209         NS_PTR_TO_INT32(mDataForwardToRequest->Get(&key));
02210       mDataForwardToRequest->Put(&key, NS_INT32_TO_PTR(amtForwardToPlugin + aLength));
02211 
02212       mPluginStreamInfo->SetStreamOffset(absoluteOffset + amtForwardToPlugin);
02213     }
02214 
02215     nsCOMPtr<nsIInputStream> stream = aIStream;
02216 
02217     // if we are caching the file ourselves to disk, we want to 'tee' off
02218     // the data as the plugin read from the stream.  We do this by the magic
02219     // of an input stream tee.
02220 
02221     if (mFileCacheOutputStream) {
02222         rv = NS_NewInputStreamTee(getter_AddRefs(stream), aIStream, mFileCacheOutputStream);
02223         if (NS_FAILED(rv))
02224             return rv;
02225     }
02226 
02227     rv =  mPStreamListener->OnDataAvailable(mPluginStreamInfo,
02228                                             stream,
02229                                             aLength);
02230 
02231     // if a plugin returns an error, the peer must kill the stream
02232     //   else the stream and PluginStreamListener leak
02233     if (NS_FAILED(rv))
02234       request->Cancel(rv);
02235   }
02236   else
02237   {
02238     // if we don't read from the stream, OnStopRequest will never be called
02239     char* buffer = new char[aLength];
02240     PRUint32 amountRead, amountWrote = 0;
02241     rv = aIStream->Read(buffer, aLength, &amountRead);
02242 
02243     // if we are caching this to disk ourselves, lets write the bytes out.
02244     if (mFileCacheOutputStream) {
02245       while (amountWrote < amountRead && NS_SUCCEEDED(rv)) {
02246         rv = mFileCacheOutputStream->Write(buffer, amountRead, &amountWrote);
02247       }
02248     }
02249     delete [] buffer;
02250   }
02251   return rv;
02252 }
02253 
02254 
02256 NS_IMETHODIMP nsPluginStreamListenerPeer::OnStopRequest(nsIRequest *request,
02257                                                         nsISupports* aContext,
02258                                                         nsresult aStatus)
02259 {
02260   nsresult rv = NS_OK;
02261 
02262   PLUGIN_LOG(PLUGIN_LOG_NOISY,
02263   ("nsPluginStreamListenerPeer::OnStopRequest this=%p aStatus=%d request=%p\n",
02264   this, aStatus, request));
02265 
02266   // for ByteRangeRequest we're just updating the mDataForwardToRequest hash and return.
02267   nsCOMPtr<nsIByteRangeRequest> brr = do_QueryInterface(request);
02268   if (brr) {
02269     PRInt64 absoluteOffset64 = LL_ZERO;
02270     brr->GetStartRange(&absoluteOffset64);
02271     // XXX support 64-bit offsets
02272     PRInt32 absoluteOffset = (PRInt32)nsInt64(absoluteOffset64);
02273 
02274     nsPRUintKey key(absoluteOffset);
02275 
02276     // remove the request from our data forwarding count hash.
02277     (void) mDataForwardToRequest->Remove(&key);
02278 
02279 
02280     PLUGIN_LOG(PLUGIN_LOG_NOISY,
02281     ("                          ::OnStopRequest for ByteRangeRequest Started=%d\n",
02282     absoluteOffset));
02283   } else {
02284     // if this is not byte range request and
02285     // if we are writting the stream to disk ourselves,
02286     // close & tear it down here
02287     mFileCacheOutputStream = nsnull;
02288   }
02289 
02290   // if we still have pending stuff to do, lets not close the plugin socket.
02291   if (--mPendingRequests > 0)
02292       return NS_OK;
02293 
02294   // we keep our connections around...
02295   nsCOMPtr<nsISupportsPRUint32> container = do_QueryInterface(aContext);
02296   if (container) {
02297     PRUint32 magicNumber = 0;  // set it to something that is not the magic number.
02298     container->GetData(&magicNumber);
02299     if (magicNumber == MAGIC_REQUEST_CONTEXT) {
02300       // this is one of our range requests
02301       return NS_OK;
02302     }
02303   }
02304 
02305   if(!mPStreamListener)
02306       return NS_ERROR_FAILURE;
02307 
02308   nsCOMPtr<nsIChannel> channel = do_QueryInterface(request);
02309   if (!channel)
02310     return NS_ERROR_FAILURE;
02311   // Set the content type to ensure we don't pass null to the plugin
02312   nsCAutoString aContentType;
02313   rv = channel->GetContentType(aContentType);
02314   if (NS_FAILED(rv))
02315     return rv;
02316 
02317   if (!aContentType.IsEmpty())
02318     mPluginStreamInfo->SetContentType(aContentType.get());
02319 
02320   // set error status if stream failed so we notify the plugin
02321   if (mRequestFailed)
02322     aStatus = NS_ERROR_FAILURE;
02323 
02324   if (NS_FAILED(aStatus)) {
02325     // on error status cleanup the stream
02326     // and return w/o OnFileAvailable()
02327     mPStreamListener->OnStopBinding(mPluginStreamInfo, aStatus);
02328     return NS_OK;
02329   }
02330 
02331   // call OnFileAvailable if plugin requests stream type StreamType_AsFile or StreamType_AsFileOnly
02332   if (mStreamType >= nsPluginStreamType_AsFile) {
02333     nsCOMPtr<nsIFile> localFile = do_QueryInterface(mLocalCachedFile);
02334     if (!localFile) {
02335       nsCOMPtr<nsICachingChannel> cacheChannel = do_QueryInterface(request);
02336       if (cacheChannel) {
02337         cacheChannel->GetCacheFile(getter_AddRefs(localFile));
02338       } else {
02339         // see if it is a file channel.
02340         nsCOMPtr<nsIFileChannel> fileChannel = do_QueryInterface(request);
02341         if (fileChannel) {
02342           fileChannel->GetFile(getter_AddRefs(localFile));
02343         }
02344       }
02345     }
02346 
02347     if (localFile) {
02348       OnFileAvailable(localFile);
02349     }
02350   }
02351 
02352   if (mStartBinding)
02353   {
02354     // On start binding has been called
02355     mPStreamListener->OnStopBinding(mPluginStreamInfo, aStatus);
02356   }
02357   else
02358   {
02359     // OnStartBinding hasn't been called, so complete the action.
02360     mPStreamListener->OnStartBinding(mPluginStreamInfo);
02361     mPStreamListener->OnStopBinding(mPluginStreamInfo, aStatus);
02362   }
02363 
02364   if (NS_SUCCEEDED(aStatus))
02365     mPluginStreamInfo->SetStreamComplete(PR_TRUE);
02366 
02367   return NS_OK;
02368 }
02369 
02370 
02372 // private methods for nsPluginStreamListenerPeer
02373 nsresult nsPluginStreamListenerPeer::SetUpCache(nsIURI* aURL)
02374 {
02375   nsPluginCacheListener* cacheListener = new nsPluginCacheListener(this);
02376   // XXX: Null LoadGroup?
02377   return NS_OpenURI(cacheListener, nsnull, aURL, nsnull);
02378 }
02379 
02380 
02382 nsresult nsPluginStreamListenerPeer::SetUpStreamListener(nsIRequest *request,
02383                                                          nsIURI* aURL)
02384 {
02385   nsresult rv = NS_OK;
02386 
02387   // If we don't yet have a stream listener, we need to get
02388   // one from the plugin.
02389   // NOTE: this should only happen when a stream was NOT created
02390   // with GetURL or PostURL (i.e. it's the initial stream we
02391   // send to the plugin as determined by the SRC or DATA attribute)
02392   if(mPStreamListener == nsnull && mInstance != nsnull)
02393     rv = mInstance->NewStream(&mPStreamListener);
02394 
02395   if(rv != NS_OK)
02396     return rv;
02397 
02398   if(mPStreamListener == nsnull)
02399     return NS_ERROR_NULL_POINTER;
02400 
02401   PRBool useLocalCache = PR_FALSE;
02402 
02403   // get httpChannel to retrieve some info we need for nsIPluginStreamInfo setup
02404   nsCOMPtr<nsIChannel> channel = do_QueryInterface(request);
02405   nsCOMPtr<nsIHttpChannel> httpChannel = do_QueryInterface(channel);
02406 
02407   /*
02408    * Assumption
02409    * By the time nsPluginStreamListenerPeer::OnDataAvailable() gets
02410    * called, all the headers have been read.
02411    */
02412   if (httpChannel) {
02413     // Reassemble the HTTP response status line and provide it to our
02414     // listener.  Would be nice if we could get the raw status line,
02415     // but nsIHttpChannel doesn't currently provide that.
02416     nsCOMPtr<nsIHTTPHeaderListener_MOZILLA_1_8_BRANCH> listener =
02417       do_QueryInterface(mPStreamListener);
02418     if (listener) {
02419       // Status code: required; the status line isn't useful without it.
02420       PRUint32 statusNum;
02421       if (NS_SUCCEEDED(httpChannel->GetResponseStatus(&statusNum)) &&
02422           statusNum < 1000) {
02423         // HTTP version: provide if available.  Defaults to empty string.
02424         nsCString ver;
02425         nsCOMPtr<nsIHttpChannelInternal> httpChannelInternal =
02426           do_QueryInterface(channel);
02427         if (httpChannelInternal) {
02428           PRUint32 major, minor;
02429           if (NS_SUCCEEDED(httpChannelInternal->GetResponseVersion(&major,
02430                                                                    &minor))) {
02431             ver = nsPrintfCString("/%lu.%lu", major, minor);
02432           }
02433         }
02434 
02435         // Status text: provide if available.  Defaults to "OK".
02436         nsCString statusText;
02437         if (!NS_SUCCEEDED(httpChannel->GetResponseStatusText(statusText))) {
02438           statusText = "OK";
02439         }
02440 
02441         // Assemble everything and pass to listener.
02442         nsPrintfCString status(100, "HTTP%s %lu %s", ver.get(), statusNum,
02443                                statusText.get());
02444         listener->StatusLine(status.get());
02445       }
02446     }
02447 
02448     // Also provide all HTTP response headers to our listener.
02449     httpChannel->VisitResponseHeaders(this);
02450 
02451     PRBool bSeekable = PR_FALSE;
02452     // first we look for a content-encoding header. If we find one, we tell the
02453     // plugin that stream is not seekable, because the plugin always sees
02454     // uncompressed data, so it can't make meaningful range requests on a
02455     // compressed entity.  Also, we force the plugin to use
02456     // nsPluginStreamType_AsFile stream type and we have to save decompressed
02457     // file into local plugin cache, because necko cache contains original
02458     // compressed file.
02459     nsCAutoString contentEncoding;
02460     if (NS_SUCCEEDED(httpChannel->GetResponseHeader(NS_LITERAL_CSTRING("Content-Encoding"),
02461                                                     contentEncoding))) {
02462       useLocalCache = PR_TRUE;
02463     } else {
02464       // set seekability (seekable if the stream has a known length and if the
02465       // http server accepts byte ranges).
02466       PRUint32 length;
02467       mPluginStreamInfo->GetLength(&length);
02468       if (length) {
02469         nsCAutoString range;
02470         if (NS_SUCCEEDED(httpChannel->GetResponseHeader(NS_LITERAL_CSTRING("accept-ranges"), range)) &&
02471           range.Equals(NS_LITERAL_CSTRING("bytes"), nsCaseInsensitiveCStringComparator())) {
02472           bSeekable = PR_TRUE;
02473           // nsPluginStreamInfo.mSeekable intitialized by PR_FALSE in ctor of nsPluginStreamInfo
02474           // so we reset it only here.
02475           mPluginStreamInfo->SetSeekable(bSeekable);
02476         }
02477       }
02478     }
02479 
02480     // we require a content len
02481     // get Last-Modified header for plugin info
02482     nsCAutoString lastModified;
02483     if (NS_SUCCEEDED(httpChannel->GetResponseHeader(NS_LITERAL_CSTRING("last-modified"), lastModified)) &&
02484         !lastModified.IsEmpty())
02485     {
02486       PRTime time64;
02487       PR_ParseTimeString(lastModified.get(), PR_TRUE, &time64);  //convert string time to interger time
02488 
02489       // Convert PRTime to unix-style time_t, i.e. seconds since the epoch
02490       double fpTime;
02491       LL_L2D(fpTime, time64);
02492       mPluginStreamInfo->SetLastModified((PRUint32)(fpTime * 1e-6 + 0.5));
02493     }
02494   }
02495 
02496   rv = mPStreamListener->OnStartBinding(mPluginStreamInfo);
02497 
02498   mStartBinding = PR_TRUE;
02499 
02500   if (NS_FAILED(rv))
02501     return rv;
02502 
02503   mPStreamListener->GetStreamType(&mStreamType);
02504 
02505   if (!useLocalCache && mStreamType >= nsPluginStreamType_AsFile) {
02506     // check it out if this is not a file channel.
02507     nsCOMPtr<nsIFileChannel> fileChannel = do_QueryInterface(request);
02508     if (!fileChannel) {
02509       // and browser cache is not available
02510       nsCOMPtr<nsICachingChannel> cacheChannel = do_QueryInterface(request);
02511       if (!(cacheChannel && (NS_SUCCEEDED(cacheChannel->SetCacheAsFile(PR_TRUE))))) {
02512         useLocalCache = PR_TRUE;
02513       }
02514     }
02515   }
02516 
02517   if (useLocalCache) {
02518     SetupPluginCacheFile(channel);
02519   }
02520 
02521   return NS_OK;
02522 }
02523 
02524 
02526 nsresult
02527 nsPluginStreamListenerPeer::OnFileAvailable(nsIFile* aFile)
02528 {
02529   nsresult rv;
02530   if (!mPStreamListener)
02531     return NS_ERROR_FAILURE;
02532 
02533   nsCAutoString path;
02534   rv = aFile->GetNativePath(path);
02535   if (NS_FAILED(rv)) return rv;
02536 
02537   if (path.IsEmpty()) {
02538     NS_WARNING("empty path");
02539     return NS_OK;
02540   }
02541 
02542   rv = mPStreamListener->OnFileAvailable(mPluginStreamInfo, path.get());
02543   return rv;
02544 }
02545 
02546 
02548 NS_IMETHODIMP
02549 nsPluginStreamListenerPeer::VisitHeader(const nsACString &header, const nsACString &value)
02550 {
02551   nsCOMPtr<nsIHTTPHeaderListener> listener = do_QueryInterface(mPStreamListener);
02552   if (!listener)
02553     return NS_ERROR_FAILURE;
02554 
02555   return listener->NewResponseHeader(PromiseFlatCString(header).get(),
02556                                      PromiseFlatCString(value).get());
02557 }
02558 
02560 
02561 nsPluginHostImpl::nsPluginHostImpl()
02562 {
02563   mPluginsLoaded = PR_FALSE;
02564   mDontShowBadPluginMessage = PR_FALSE;
02565   mIsDestroyed = PR_FALSE;
02566   mOverrideInternalTypes = PR_FALSE;
02567   mAllowAlienStarHandler = PR_FALSE;
02568   mUnusedLibraries.Clear();
02569   mDefaultPluginDisabled = PR_FALSE;
02570 
02571   gActivePluginList = &mActivePluginList;
02572 
02573   // check to see if pref is set at startup to let plugins take over in
02574   // full page mode for certain image mime types that we handle internally
02575   mPrefService = do_GetService(NS_PREFSERVICE_CONTRACTID);
02576   if (mPrefService) {
02577     PRBool tmp;
02578     mPrefService->GetBoolPref("plugin.override_internal_types", &tmp);
02579     mOverrideInternalTypes = tmp;
02580 
02581     mPrefService->GetBoolPref("plugin.allow_alien_star_handler", &tmp);
02582     mAllowAlienStarHandler = tmp;
02583 
02584     mPrefService->GetBoolPref("plugin.default_plugin_disabled", &tmp);
02585     mDefaultPluginDisabled = tmp;
02586 
02587 #ifdef WINCE
02588     mDefaultPluginDisabled = PR_TRUE;
02589 #endif
02590   }
02591 
02592   nsCOMPtr<nsIObserverService> obsService = do_GetService("@mozilla.org/observer-service;1");
02593   if (obsService)
02594   {
02595     obsService->AddObserver(this, NS_XPCOM_SHUTDOWN_OBSERVER_ID, PR_FALSE);
02596   }
02597 
02598 #ifdef PLUGIN_LOGGING
02599   nsPluginLogging::gNPNLog = PR_NewLogModule(NPN_LOG_NAME);
02600   nsPluginLogging::gNPPLog = PR_NewLogModule(NPP_LOG_NAME);
02601   nsPluginLogging::gPluginLog = PR_NewLogModule(PLUGIN_LOG_NAME);
02602 
02603   PR_LOG(nsPluginLogging::gNPNLog, PLUGIN_LOG_ALWAYS,("NPN Logging Active!\n"));
02604   PR_LOG(nsPluginLogging::gPluginLog, PLUGIN_LOG_ALWAYS,("General Plugin Logging Active! (nsPluginHostImpl::ctor)\n"));
02605   PR_LOG(nsPluginLogging::gNPPLog, PLUGIN_LOG_ALWAYS,("NPP Logging Active!\n"));
02606 
02607   PLUGIN_LOG(PLUGIN_LOG_ALWAYS,("nsPluginHostImpl::ctor\n"));
02608   PR_LogFlush();
02609 #endif
02610   mCachedPlugins = nsnull;
02611 }
02612 
02613 // static
02614 const char *
02615 nsPluginHostImpl::GetPluginName(nsIPluginInstance *aPluginInstance)
02616 {
02617   nsActivePlugin *plugin =
02618     gActivePluginList ? gActivePluginList->find(aPluginInstance) : nsnull;
02619 
02620   if (plugin && plugin->mPluginTag) {
02621     return plugin->mPluginTag->mName;
02622   }
02623 
02624   return nsnull;
02625 }
02626 
02627 
02629 nsPluginHostImpl::~nsPluginHostImpl()
02630 {
02631   PLUGIN_LOG(PLUGIN_LOG_ALWAYS,("nsPluginHostImpl::dtor\n"));
02632 
02633 #ifdef NS_DEBUG
02634   printf("nsPluginHostImpl dtor\n");
02635 #endif
02636   Destroy();
02637 }
02638 
02640 NS_IMPL_ISUPPORTS7(nsPluginHostImpl,
02641                    nsIPluginManager,
02642                    nsIPluginManager2,
02643                    nsIPluginHost,
02644                    nsIFileUtilities,
02645                    nsICookieStorage,
02646                    nsIObserver,
02647                    nsPIPluginHost)
02649 NS_METHOD
02650 nsPluginHostImpl::Create(nsISupports* aOuter, REFNSIID aIID, void** aResult)
02651 {
02652   NS_PRECONDITION(aOuter == nsnull, "no aggregation");
02653   if (aOuter)
02654     return NS_ERROR_NO_AGGREGATION;
02655 
02656   nsPluginHostImpl* host = new nsPluginHostImpl();
02657   if (! host)
02658     return NS_ERROR_OUT_OF_MEMORY;
02659 
02660   nsresult rv;
02661   NS_ADDREF(host);
02662   rv = host->QueryInterface(aIID, aResult);
02663   NS_RELEASE(host);
02664   return rv;
02665 }
02666 
02667 
02669 NS_IMETHODIMP nsPluginHostImpl::GetValue(nsPluginManagerVariable aVariable, void *aValue)
02670 {
02671   nsresult rv = NS_OK;
02672 
02673   NS_ENSURE_ARG_POINTER(aValue);
02674 
02675 #if defined(XP_UNIX) && !defined(XP_MACOSX) && defined(MOZ_X11)
02676   if (nsPluginManagerVariable_XDisplay == aVariable) {
02677     Display** value = NS_REINTERPRET_CAST(Display**, aValue);
02678 #if defined(MOZ_WIDGET_GTK) || defined (MOZ_WIDGET_GTK2)
02679     *value = GDK_DISPLAY();
02680 #elif defined(MOZ_WIDGET_QT)
02681     *value = qt_xdisplay();
02682 #elif defined(MOZ_WIDGET_XLIB)
02683     *value = xxlib_rgb_get_display(xxlib_find_handle(XXLIBRGB_DEFAULT_HANDLE));
02684 #endif
02685     if (!(*value)) {
02686       return NS_ERROR_FAILURE;
02687     }
02688   }
02689 #endif
02690   if (nsPluginManagerVariable_SupportsXEmbed == aVariable) {
02691 #ifdef MOZ_WIDGET_GTK2
02692     *(NPBool*)aValue = PR_TRUE;
02693 #else
02694     *(NPBool*)aValue = PR_FALSE;
02695 #endif
02696   }
02697   return rv;
02698 }
02699 
02700 
02702 PRBool nsPluginHostImpl::IsRunningPlugin(nsPluginTag * plugin)
02703 {
02704   if(!plugin)
02705     return PR_FALSE;
02706 
02707   // we can check for mLibrary to be non-zero and then querry nsIPluginInstancePeer
02708   // in nsActivePluginList to see if plugin with matching mime type is not stopped
02709   if(!plugin->mLibrary)
02710     return PR_FALSE;
02711 
02712   for(int i = 0; i < plugin->mVariants; i++) {
02713     nsActivePlugin * p = mActivePluginList.find(plugin->mMimeTypeArray[i]);
02714     if(p && !p->mStopped)
02715       return PR_TRUE;
02716   }
02717 
02718   return PR_FALSE;
02719 }
02720 
02722 nsresult nsPluginHostImpl::ReloadPlugins(PRBool reloadPages)
02723 {
02724   PLUGIN_LOG(PLUGIN_LOG_NORMAL,
02725   ("nsPluginHostImpl::ReloadPlugins Begin reloadPages=%d, active_instance_count=%d\n",
02726   reloadPages, mActivePluginList.mCount));
02727 
02728   nsresult rv = NS_OK;
02729 
02730   // this will create the initial plugin list out of cache
02731   // if it was not created yet
02732   if (!mPluginsLoaded)
02733     return LoadPlugins();
02734 
02735   // we are re-scanning plugins. New plugins may have been added, also some
02736   // plugins may have been removed, so we should probably shut everything down
02737   // but don't touch running (active and  not stopped) plugins
02738 
02739   // check if plugins changed, no need to do anything else
02740   // if no changes to plugins have been made
02741   // PR_FALSE instructs not to touch the plugin list, just to
02742   // look for possible changes
02743   PRBool pluginschanged = PR_TRUE;
02744   FindPlugins(PR_FALSE, &pluginschanged);
02745 
02746   // if no changed detected, return an appropriate error code
02747   if (!pluginschanged)
02748     return NS_ERROR_PLUGINS_PLUGINSNOTCHANGED;
02749 
02750   nsCOMPtr<nsISupportsArray> instsToReload;
02751 
02752   if(reloadPages) {
02753     NS_NewISupportsArray(getter_AddRefs(instsToReload));
02754 
02755     // Then stop any running plugin instances but hold on to the documents in the array
02756     // We are going to need to restart the instances in these documents later
02757     mActivePluginList.stopRunning(instsToReload);
02758   }
02759 
02760   // clean active plugin list
02761   mActivePluginList.removeAllStopped();
02762 
02763   // shutdown plugins and kill the list if there are no running plugins
02764   nsPluginTag * prev = nsnull;
02765   nsPluginTag * next = nsnull;
02766 
02767   for(nsPluginTag * p = mPlugins; p != nsnull;) {
02768     next = p->mNext;
02769 
02770     // XXX only remove our plugin from the list if it's not running and not
02771     // an XPCOM plugin. XPCOM plugins do not get a call to nsIPlugin::Shutdown
02772     // if plugins are reloaded. This also fixes a crash on UNIX where the call
02773     // to shutdown would break the ProxyJNI connection to the JRE after a reload.
02774     // see bug 86591
02775     if(!IsRunningPlugin(p) && (!p->mEntryPoint || (p->mFlags & NS_PLUGIN_FLAG_OLDSCHOOL))) {
02776       if(p == mPlugins)
02777         mPlugins = next;
02778       else
02779         prev->mNext = next;
02780 
02781       delete p;
02782       p = next;
02783       continue;
02784     }
02785 
02786     prev = p;
02787     p = next;
02788   }
02789 
02790   // set flags
02791   mPluginsLoaded = PR_FALSE;
02792 
02793   // load them again
02794   rv = LoadPlugins();
02795 
02796   // If we have shut down any plugin instances, we've now got to restart them.
02797   // Post an event to do the rest as we are going to be destroying the frame tree and we also want
02798   // any posted unload events to finish
02799   PRUint32 c;
02800   if (reloadPages &&
02801       instsToReload &&
02802       NS_SUCCEEDED(instsToReload->Count(&c)) &&
02803       c > 0) {
02804     nsCOMPtr<nsIEventQueueService> eventService(do_GetService(kEventQueueServiceCID));
02805     if (eventService) {
02806       nsCOMPtr<nsIEventQueue> eventQueue;
02807       eventService->GetThreadEventQueue(PR_GetCurrentThread(), getter_AddRefs(eventQueue));
02808       if (eventQueue) {
02809         nsPluginDocReframeEvent * ev = new nsPluginDocReframeEvent(instsToReload);
02810         if (ev) {
02811           PL_InitEvent(ev, nsnull, HandlePluginDocReframePLEvent, DestroyPluginDocReframePLEvent);
02812           eventQueue->PostEvent(ev);
02813         }
02814       }
02815     }
02816 
02817   }
02818 
02819   PLUGIN_LOG(PLUGIN_LOG_NORMAL,
02820   ("nsPluginHostImpl::ReloadPlugins End active_instance_count=%d\n",
02821   mActivePluginList.mCount));
02822 
02823   return rv;
02824 }
02825 
02826 #define NS_RETURN_UASTRING_SIZE 128
02827 
02828 
02830 nsresult nsPluginHostImpl::UserAgent(const char **retstring)
02831 {
02832   static char resultString[NS_RETURN_UASTRING_SIZE];
02833   nsresult res;
02834 
02835   nsCOMPtr<nsIHttpProtocolHandler> http = do_GetService(kHttpHandlerCID, &res);
02836   if (NS_FAILED(res))
02837     return res;
02838 
02839   nsCAutoString uaString;
02840   res = http->GetUserAgent(uaString);
02841 
02842   if (NS_SUCCEEDED(res))
02843   {
02844     if(NS_RETURN_UASTRING_SIZE > uaString.Length())
02845     {
02846       PL_strcpy(resultString, uaString.get());
02847       *retstring = resultString;
02848     }
02849     else
02850     {
02851       *retstring = nsnull;
02852       res = NS_ERROR_OUT_OF_MEMORY;
02853     }
02854   }
02855   else
02856     *retstring = nsnull;
02857 
02858   PLUGIN_LOG(PLUGIN_LOG_NORMAL, ("nsPluginHostImpl::UserAgent return=%s\n", *retstring));
02859 
02860   return res;
02861 }
02862 
02863 nsresult nsPluginHostImpl:: GetPrompt(nsIPluginInstanceOwner *aOwner, nsIPrompt **aPrompt)
02864 {
02865   nsresult rv;
02866   nsCOMPtr<nsIPrompt> prompt;
02867   nsCOMPtr<nsIWindowWatcher> wwatch = do_GetService(NS_WINDOWWATCHER_CONTRACTID, &rv);
02868 
02869   if (wwatch) {
02870     nsCOMPtr<nsIDOMWindow> domWindow;
02871     if (aOwner) {
02872       nsCOMPtr<nsIDocument> document;
02873       aOwner->GetDocument(getter_AddRefs(document));
02874       if (document) {
02875         domWindow = document->GetWindow();
02876       }
02877     }
02878 
02879     if (!domWindow) {
02880       wwatch->GetWindowByName(NS_LITERAL_STRING("_content").get(), nsnull, getter_AddRefs(domWindow));
02881     }
02882     rv = wwatch->GetNewPrompter(domWindow, getter_AddRefs(prompt));
02883   }
02884 
02885   NS_IF_ADDREF(*aPrompt = prompt);
02886   return rv;
02887 }
02888 
02890 NS_IMETHODIMP nsPluginHostImpl::GetURL(nsISupports* pluginInst,
02891                      const char* url,
02892                      const char* target,
02893                      nsIPluginStreamListener* streamListener,
02894                      const char* altHost,
02895                      const char* referrer,
02896                      PRBool forceJSEnabled)
02897 {
02898   return GetURLWithHeaders(pluginInst, url, target, streamListener,
02899                            altHost, referrer, forceJSEnabled, nsnull, nsnull);
02900 }
02901 
02902 
02904 NS_IMETHODIMP nsPluginHostImpl::GetURLWithHeaders(nsISupports* pluginInst,
02905                      const char* url,
02906                      const char* target,
02907                      nsIPluginStreamListener* streamListener,
02908                      const char* altHost,
02909                      const char* referrer,
02910                      PRBool forceJSEnabled,
02911                      PRUint32 getHeadersLength,
02912                      const char* getHeaders)
02913 {
02914   nsAutoString      string; string.AssignWithConversion(url);
02915   nsresult          rv;
02916 
02917   // we can only send a stream back to the plugin (as specified by a
02918   // null target) if we also have a nsIPluginStreamListener to talk to
02919   if(target == nsnull && streamListener == nsnull)
02920    return NS_ERROR_ILLEGAL_VALUE;
02921 
02922   nsCOMPtr<nsIPluginInstance> instance = do_QueryInterface(pluginInst, &rv);
02923 
02924   if (NS_SUCCEEDED(rv))
02925   {
02926     rv = DoURLLoadSecurityCheck(instance, url);
02927   }
02928 
02929   if (NS_SUCCEEDED(rv))
02930   {
02931     if (nsnull != target)
02932     {
02933       nsCOMPtr<nsIPluginInstancePeer> peer;
02934       rv = instance->GetPeer(getter_AddRefs(peer));
02935       if (NS_SUCCEEDED(rv) && peer)
02936       {
02937         nsCOMPtr<nsPIPluginInstancePeer> privpeer(do_QueryInterface(peer));
02938         nsCOMPtr<nsIPluginInstanceOwner> owner;
02939         rv = privpeer->GetOwner(getter_AddRefs(owner));
02940         if (owner)
02941         {
02942           if ((0 == PL_strcmp(target, "newwindow")) ||
02943               (0 == PL_strcmp(target, "_new")))
02944             target = "_blank";
02945           else if (0 == PL_strcmp(target, "_current"))
02946             target = "_self";
02947 
02948           rv = owner->GetURL(url, target, nsnull, 0, (void *) getHeaders, getHeadersLength);
02949         }
02950       }
02951     }
02952 
02953     if (nsnull != streamListener)
02954       rv = NewPluginURLStream(string, instance, streamListener, nsnull,
02955                               PR_FALSE, nsnull, getHeaders, getHeadersLength);
02956   }
02957 
02958   return rv;
02959 }
02960 
02961 
02963 NS_IMETHODIMP nsPluginHostImpl::PostURL(nsISupports* pluginInst,
02964                     const char* url,
02965                     PRUint32 postDataLen,
02966                     const char* postData,
02967                     PRBool isFile,
02968                     const char* target,
02969                     nsIPluginStreamListener* streamListener,
02970                     const char* altHost,
02971                     const char* referrer,
02972                     PRBool forceJSEnabled,
02973                     PRUint32 postHeadersLength,
02974                     const char* postHeaders)
02975 {
02976   nsAutoString      string; string.AssignWithConversion(url);
02977   nsresult          rv;
02978 
02979   // we can only send a stream back to the plugin (as specified
02980   // by a null target) if we also have a nsIPluginStreamListener
02981   // to talk to also
02982   if(target == nsnull && streamListener == nsnull)
02983    return NS_ERROR_ILLEGAL_VALUE;
02984 
02985   nsCOMPtr<nsIPluginInstance> instance = do_QueryInterface(pluginInst, &rv);
02986 
02987   if (NS_SUCCEEDED(rv))
02988   {
02989     rv = DoURLLoadSecurityCheck(instance, url);
02990   }
02991 
02992   if (NS_SUCCEEDED(rv))
02993   {
02994       char *dataToPost;
02995       if (isFile) {
02996         rv = CreateTmpFileToPost(postData, &dataToPost);
02997         if (NS_FAILED(rv) || !dataToPost) return rv;
02998 
02999       } else {
03000         PRUint32 newDataToPostLen;
03001         ParsePostBufferToFixHeaders(postData, postDataLen, &dataToPost, &newDataToPostLen);
03002         if (!dataToPost)
03003           return NS_ERROR_UNEXPECTED;
03004 
03005         // we use nsIStringInputStream::adoptDataa()
03006         // in NS_NewPluginPostDataStream to set the stream
03007         // all new data alloced in  ParsePostBufferToFixHeaders()
03008         // well be nsMemory::Free()d on destroy the stream
03009         postDataLen = newDataToPostLen;
03010       }
03011 
03012       if (nsnull != target)
03013         {
03014           nsCOMPtr<nsIPluginInstancePeer> peer;
03015           rv = instance->GetPeer(getter_AddRefs(peer));
03016 
03017           if (NS_SUCCEEDED(rv) && peer)
03018             {
03019               nsCOMPtr<nsPIPluginInstancePeer> privpeer(do_QueryInterface(peer));
03020               nsCOMPtr<nsIPluginInstanceOwner> owner;
03021               rv = privpeer->GetOwner(getter_AddRefs(owner));
03022               if (owner)
03023                 {
03024                   if (!target) {
03025                     target = "_self";
03026                   }
03027                   else {
03028                     if ((0 == PL_strcmp(target, "newwindow")) ||
03029                         (0 == PL_strcmp(target, "_new")))
03030                       target = "_blank";
03031                     else if (0 == PL_strcmp(target, "_current"))
03032                       target = "_self";
03033                   }
03034 
03035                   rv = owner->GetURL(url, target, (void*)dataToPost, postDataLen,
03036                                      (void*) postHeaders, postHeadersLength, isFile);
03037                 }
03038             }
03039         }
03040 
03041       // if we don't have a target, just create a stream.  This does
03042       // NS_OpenURI()!
03043       if (streamListener != nsnull)
03044         rv = NewPluginURLStream(string, instance, streamListener,
03045                                 (const char*)dataToPost, isFile, postDataLen,
03046                                 postHeaders, postHeadersLength);
03047       if (isFile) {
03048         NS_Free(dataToPost);
03049       }
03050   }
03051 
03052   return rv;
03053 }
03054 
03055 
03057 NS_IMETHODIMP nsPluginHostImpl::RegisterPlugin(REFNSIID aCID,
03058                                                const char* aPluginName,
03059                                                const char* aDescription,
03060                                                const char** aMimeTypes,
03061                                                const char** aMimeDescriptions,
03062                                                const char** aFileExtensions,
03063                                                PRInt32 aCount)
03064 {
03065   return NS_ERROR_NOT_IMPLEMENTED;
03066 }
03067 
03068 
03070 NS_IMETHODIMP nsPluginHostImpl::UnregisterPlugin(REFNSIID aCID)
03071 {
03072   return NS_ERROR_NOT_IMPLEMENTED;
03073 }
03074 
03075 
03077 NS_IMETHODIMP nsPluginHostImpl::BeginWaitCursor(void)
03078 {
03079   return NS_ERROR_NOT_IMPLEMENTED;
03080 }
03081 
03082 
03084 NS_IMETHODIMP nsPluginHostImpl::EndWaitCursor(void)
03085 {
03086   return NS_ERROR_NOT_IMPLEMENTED;
03087 }
03088 
03089 
03091 NS_IMETHODIMP nsPluginHostImpl::SupportsURLProtocol(const char* protocol, PRBool *result)
03092 {
03093   return NS_ERROR_NOT_IMPLEMENTED;
03094 }
03095 
03096 
03098 NS_IMETHODIMP nsPluginHostImpl::NotifyStatusChange(nsIPlugin* plugin, nsresult errorStatus)
03099 {
03100   return NS_ERROR_NOT_IMPLEMENTED;
03101 }
03102 
03103 
03104 /*////////////////////////////////////////////////////////////////////////
03105  * This method queries the prefs for proxy information.
03106  * It has been tested and is known to work in the following three cases
03107  * when no proxy host or port is specified
03108  * when only the proxy host is specified
03109  * when only the proxy port is specified
03110  * This method conforms to the return code specified in
03111  * http://developer.netscape.com/docs/manuals/proxy/adminnt/autoconf.htm#1020923
03112  * with the exception that multiple values are not implemented.
03113  */
03114 
03115 NS_IMETHODIMP nsPluginHostImpl::FindProxyForURL(const char* url, char* *result)
03116 {
03117   if (!url || !result) {
03118     return NS_ERROR_INVALID_ARG;
03119   }
03120   nsresult res;
03121 
03122   nsCOMPtr<nsIURI> uriIn;
03123   nsCOMPtr<nsIProtocolProxyService> proxyService;
03124   nsCOMPtr<nsIIOService> ioService;
03125 
03126   proxyService = do_GetService(kProtocolProxyServiceCID, &res);
03127   if (NS_FAILED(res) || !proxyService) {
03128     return res;
03129   }
03130 
03131   ioService = do_GetService(kIOServiceCID, &res);
03132   if (NS_FAILED(res) || !ioService) {
03133     return res;
03134   }
03135 
03136   // make an nsURI from the argument url
03137   res = ioService->NewURI(nsDependentCString(url), nsnull, nsnull, getter_AddRefs(uriIn));
03138   if (NS_FAILED(res)) {
03139     return res;
03140   }
03141 
03142   nsCOMPtr<nsIProxyInfo> pi;
03143 
03144   res = proxyService->Resolve(uriIn, 0, getter_AddRefs(pi));
03145   if (NS_FAILED(res)) {
03146     return res;
03147   }
03148 
03149   nsCAutoString host, type;
03150   PRInt32 port = -1;
03151 
03152   // These won't fail, and even if they do... we'll be ok.
03153   if (pi) {
03154     pi->GetType(type);
03155     pi->GetHost(host);
03156     pi->GetPort(&port);
03157   }
03158 
03159   if (!pi || host.IsEmpty() || port <= 0 || host.EqualsLiteral("direct")) {
03160     *result = PL_strdup("DIRECT");
03161   } else if (type.EqualsLiteral("http")) {
03162     *result = PR_smprintf("PROXY %s:%d", host.get(), port);
03163   } else if (type.EqualsLiteral("socks4")) {
03164     *result = PR_smprintf("SOCKS %s:%d", host.get(), port);
03165   } else if (type.EqualsLiteral("socks")) {
03166     // XXX - this is socks5, but there is no API for us to tell the
03167     // plugin that fact. SOCKS for now, in case the proxy server
03168     // speaks SOCKS4 as well. See bug 78176
03169     // For a long time this was returning an http proxy type, so
03170     // very little is probably broken by this
03171     *result = PR_smprintf("SOCKS %s:%d", host.get(), port);
03172   } else {
03173     NS_ASSERTION(PR_FALSE, "Unknown proxy type!");
03174     *result = PL_strdup("DIRECT");
03175   }
03176 
03177   if (nsnull == *result) {
03178     res = NS_ERROR_OUT_OF_MEMORY;
03179   }
03180 
03181   return res;
03182 }
03183 
03184 
03186 NS_IMETHODIMP nsPluginHostImpl::RegisterWindow(nsIEventHandler* handler, nsPluginPlatformWindowRef window)
03187 {
03188   return NS_ERROR_NOT_IMPLEMENTED;
03189 }
03190 
03191 
03193 NS_IMETHODIMP nsPluginHostImpl::UnregisterWindow(nsIEventHandler* handler, nsPluginPlatformWindowRef window)
03194 {
03195   return NS_ERROR_NOT_IMPLEMENTED;
03196 }
03197 
03198 
03200 NS_IMETHODIMP nsPluginHostImpl::AllocateMenuID(nsIEventHandler* handler, PRBool isSubmenu, PRInt16 *result)
03201 {
03202   return NS_ERROR_NOT_IMPLEMENTED;
03203 }
03204 
03205 
03207 NS_IMETHODIMP nsPluginHostImpl::DeallocateMenuID(nsIEventHandler* handler, PRInt16 menuID)
03208 {
03209   return NS_ERROR_NOT_IMPLEMENTED;
03210 }
03211 
03212 
03214 NS_IMETHODIMP nsPluginHostImpl::HasAllocatedMenuID(nsIEventHandler* handler, PRInt16 menuID, PRBool *result)
03215 {
03216   return NS_ERROR_NOT_IMPLEMENTED;
03217 }
03218 
03219 
03221 NS_IMETHODIMP nsPluginHostImpl::ProcessNextEvent(PRBool *bEventHandled)
03222 {
03223   return NS_ERROR_NOT_IMPLEMENTED;
03224 }
03225 
03226 
03228 NS_IMETHODIMP nsPluginHostImpl::CreateInstance(nsISupports *aOuter,
03229                                                REFNSIID aIID,
03230                                                void **aResult)
03231 {
03232   NS_NOTREACHED("how'd I get here?");
03233   return NS_ERROR_UNEXPECTED;
03234 }
03235 
03236 
03238 NS_IMETHODIMP nsPluginHostImpl::LockFactory(PRBool aLock)
03239 {
03240   NS_NOTREACHED("how'd I get here?");
03241   return NS_ERROR_UNEXPECTED;
03242 }
03243 
03244 
03246 NS_IMETHODIMP nsPluginHostImpl::Init(void)
03247 {
03248   return NS_OK;
03249 }
03250 
03251 
03253 NS_IMETHODIMP nsPluginHostImpl::Destroy(void)
03254 {
03255   PLUGIN_LOG(PLUGIN_LOG_NORMAL, ("nsPluginHostImpl::Destroy Called\n"));
03256 
03257   if (mIsDestroyed)
03258     return NS_OK;
03259 
03260   mIsDestroyed = PR_TRUE;
03261 
03262   // we should call nsIPluginInstance::Stop and nsIPluginInstance::SetWindow
03263   // for those plugins who want it
03264   mActivePluginList.stopRunning(nsnull);
03265 
03266   // at this point nsIPlugin::Shutdown calls will be performed if needed
03267   mActivePluginList.shut();
03268 
03269   if (nsnull != mPluginPath)
03270   {
03271     PR_Free(mPluginPath);
03272     mPluginPath = nsnull;
03273   }
03274 
03275   while (nsnull != mPlugins)
03276   {
03277     nsPluginTag *temp = mPlugins->mNext;
03278 
03279     // while walking through the list of the plugins see if we still have anything
03280     // to shutdown some plugins may have never created an instance but still expect
03281     // the shutdown call see bugzilla bug 73071
03282     // with current logic, no need to do anything special as nsIPlugin::Shutdown
03283     // will be performed in the destructor
03284 
03285     delete mPlugins;
03286     mPlugins = temp;
03287   }
03288 
03289   // Delete any remaining cached plugins list
03290   while (mCachedPlugins)
03291   {
03292     nsPluginTag *next = mCachedPlugins->mNext;
03293     delete mCachedPlugins;
03294     mCachedPlugins = next;
03295   }
03296 
03297   // Lets remove any of the temporary files that we created.
03298   if (sPluginTempDir) {
03299     sPluginTempDir->Remove(PR_TRUE);
03300 
03301     NS_RELEASE(sPluginTempDir);
03302   }
03303 
03304   if (mPrivateDirServiceProvider)
03305   {
03306     nsCOMPtr<nsIDirectoryService> dirService =
03307       do_GetService(kDirectoryServiceContractID);
03308     if (dirService)
03309       dirService->UnregisterProvider(mPrivateDirServiceProvider);
03310     mPrivateDirServiceProvider = nsnull;
03311   }
03312 
03313   mPrefService = nsnull; // release prefs service to avoid leaks!
03314 
03315   return NS_OK;
03316 }
03317 
03318 void nsPluginHostImpl::UnloadUnusedLibraries()
03319 {
03320   // unload any remaining plugin libraries from memory
03321   for (PRInt32 i = 0; i < mUnusedLibraries.Count(); i++) {
03322     PRLibrary * library = (PRLibrary *)mUnusedLibraries[i];
03323     if (library)
03324       PostPluginUnloadEvent(library);
03325   }
03326   mUnusedLibraries.Clear();
03327 }
03328 
03329 nsresult
03330 nsPluginHostImpl::GetPluginTempDir(nsIFile **aDir)
03331 {
03332   if (!sPluginTempDir) {
03333     nsCOMPtr<nsIFile> tmpDir;
03334     nsresult rv = NS_GetSpecialDirectory(NS_OS_TEMP_DIR,
03335                                          getter_AddRefs(tmpDir));
03336     NS_ENSURE_SUCCESS(rv, rv);
03337 
03338     rv = tmpDir->AppendNative(kPluginTmpDirName);
03339 
03340     // make it unique, and mode == 0700, not world-readable
03341     rv = tmpDir->CreateUnique(nsIFile::DIRECTORY_TYPE, 0700);
03342     NS_ENSURE_SUCCESS(rv, rv);
03343 
03344     tmpDir.swap(sPluginTempDir);
03345   }
03346 
03347   return sPluginTempDir->Clone(aDir);
03348 }
03349 
03350 
03352 /* Called by nsPluginInstanceOwner (nsObjectFrame.cpp - embedded case) */
03353 NS_IMETHODIMP nsPluginHostImpl::InstantiateEmbeddedPlugin(const char *aMimeType,
03354                                                          nsIURI* aURL,
03355                                                          nsIPluginInstanceOwner *aOwner)
03356 {
03357 #ifdef PLUGIN_LOGGING
03358   nsCAutoString urlSpec;
03359   if(aURL != nsnull) (void)aURL->GetAsciiSpec(urlSpec);
03360 
03361   PR_LOG(nsPluginLogging::gPluginLog, PLUGIN_LOG_NORMAL,
03362         ("nsPluginHostImpl::InstatiateEmbeddedPlugin Begin mime=%s, owner=%p, url=%s\n",
03363         aMimeType, aOwner, urlSpec.get()));
03364 
03365   PR_LogFlush();
03366 #endif
03367 
03368   nsresult  rv;
03369   nsIPluginInstance *instance = nsnull;
03370   nsCOMPtr<nsIPluginTagInfo2> pti2;
03371   nsPluginTagType tagType;
03372   PRBool isJavaEnabled = PR_TRUE;
03373   PRBool isJava = PR_FALSE;
03374 
03375   rv = aOwner->QueryInterface(kIPluginTagInfo2IID, getter_AddRefs(pti2));
03376 
03377   if(rv != NS_OK) {
03378     return rv;
03379   }
03380 
03381   rv = pti2->GetTagType(&tagType);
03382 
03383   if((rv != NS_OK) || !((tagType == nsPluginTagType_Embed)
03384                         || (tagType == nsPluginTagType_Applet)
03385                         || (tagType == nsPluginTagType_Object)))
03386   {
03387     return rv;
03388   }
03389 
03390   // Security checks
03391   // Can't do security checks without a URI - hopefully the plugin will take
03392   // care of that
03393   if (aURL) {
03394     nsCOMPtr<nsIScriptSecurityManager> secMan =
03395                     do_GetService(NS_SCRIPTSECURITYMANAGER_CONTRACTID, &rv);
03396     if (NS_FAILED(rv))
03397       return rv; // Better fail if we can't do security checks
03398 
03399     nsCOMPtr<nsIDocument> doc;
03400     if (aOwner)
03401       aOwner->GetDocument(getter_AddRefs(doc));
03402     if (!doc)
03403       return NS_ERROR_NULL_POINTER;
03404 
03405     rv = secMan->CheckLoadURIWithPrincipal(doc->GetPrincipal(), aURL, 0);
03406     if (NS_FAILED(rv))
03407       return rv;
03408 
03409     nsCOMPtr<nsIDOMElement> elem;
03410     pti2->GetDOMElement(getter_AddRefs(elem));
03411 
03412     PRInt16 shouldLoad = nsIContentPolicy::ACCEPT; // default permit
03413     nsresult rv =
03414       NS_CheckContentLoadPolicy(nsIContentPolicy::TYPE_OBJECT,
03415                                 aURL,
03416                                 doc->GetDocumentURI(),
03417                                 elem,
03418                                 nsDependentCString(aMimeType ? aMimeType : ""),
03419                                 nsnull, //extra
03420                                 &shouldLoad);
03421     if (NS_FAILED(rv) || NS_CP_REJECTED(shouldLoad))
03422       return NS_ERROR_CONTENT_BLOCKED_SHOW_ALT;
03423   }
03424 
03425 
03426 
03427   if (tagType == nsPluginTagType_Applet ||
03428       PL_strncasecmp(aMimeType, "application/x-java-vm", 21) == 0 ||
03429       PL_strncasecmp(aMimeType, "application/x-java-applet", 25) == 0) {
03430 #ifdef OJI
03431     isJava = PR_TRUE;
03432     // see if java is enabled
03433     if (mPrefService) {
03434       rv = mPrefService->GetBoolPref("security.enable_java", &isJavaEnabled);
03435       if (NS_SUCCEEDED(rv)) {
03436         // if not, don't show this plugin
03437         if (!isJavaEnabled) {
03438           return NS_ERROR_FAILURE;
03439         }
03440       }
03441       else {
03442         // if we were unable to get the pref, assume java is enabled
03443         // and rely on the "find the plugin or not" logic.
03444 
03445         // make sure the value wasn't modified in GetBoolPref
03446         isJavaEnabled = PR_TRUE;
03447       }
03448     }
03449 #else
03450     isJavaEnabled = PR_FALSE;
03451     return NS_ERROR_FAILURE;
03452 #endif
03453   }
03454 
03455   // Determine if the scheme of this URL is one we can handle internaly because we should
03456   // only open the initial stream if it's one that we can handle internally. Otherwise
03457   // |NS_OpenURI| in |InstantiateEmbeddedPlugin| may open up a OS protocal registered helper app
03458   PRBool bCanHandleInternally = PR_FALSE;
03459   nsCAutoString scheme;
03460   if (aURL && NS_SUCCEEDED(aURL->GetScheme(scheme))) {
03461       nsCAutoString contractID(NS_NETWORK_PROTOCOL_CONTRACTID_PREFIX);
03462       contractID += scheme;
03463       ToLowerCase(contractID);
03464       nsCOMPtr<nsIProtocolHandler> handler = do_GetService(contractID.get());
03465       if (handler)
03466         bCanHandleInternally = PR_TRUE;
03467   }
03468 
03469   if(FindStoppedPluginForURL(aURL, aOwner) == NS_OK) {
03470 
03471     PLUGIN_LOG(PLUGIN_LOG_NOISY,
03472     ("nsPluginHostImpl::InstatiateEmbeddedPlugin FoundStopped mime=%s\n", aMimeType));
03473 
03474     aOwner->GetInstance(instance);
03475     if((!aMimeType || !isJava) && bCanHandleInternally)
03476       rv = NewEmbeddedPluginStream(aURL, aOwner, instance);
03477 
03478     // notify Java DOM component
03479     nsresult res;
03480     nsCOMPtr<nsIPluginInstanceOwner> javaDOM =
03481              do_GetService("@mozilla.org/blackwood/java-dom;1", &res);
03482     if (NS_SUCCEEDED(res) && javaDOM)
03483       javaDOM->SetInstance(instance);
03484 
03485     NS_IF_RELEASE(instance);
03486     return NS_OK;
03487   }
03488 
03489   // if we don't have a MIME type at this point, we still have one more chance by
03490   // opening the stream and seeing if the server hands one back
03491   if (!aMimeType)
03492     return bCanHandleInternally ? NewEmbeddedPluginStream(aURL, aOwner, nsnull) : NS_ERROR_FAILURE;
03493 
03494   rv = SetUpPluginInstance(aMimeType, aURL, aOwner);
03495 
03496   if(rv == NS_OK)
03497     rv = aOwner->GetInstance(instance);
03498   else
03499   {
03500    /*
03501     * If we are here, it's time to either show the default plugin
03502     * or return failure so layout will replace us.
03503     *
03504     * Currently, the default plugin is shown for all EMBED and APPLET
03505     * tags and also any OBJECT tag that has a PLUGINURL PARAM tag name.
03506     */
03507 
03508     PRBool bHasPluginURL = PR_FALSE;
03509     nsCOMPtr<nsIPluginTagInfo2> pti2(do_QueryInterface(aOwner));
03510 
03511     if(pti2) {
03512       const char *value;
03513       bHasPluginURL = NS_SUCCEEDED(pti2->GetParameter("PLUGINURL", &value));
03514     }
03515 
03516     // if we didn't find a pluginURL param on the object tag,
03517     // there's nothing more to do here
03518     if(nsPluginTagType_Object == tagType && !bHasPluginURL)
03519       return rv;
03520 
03521     if(NS_FAILED(SetUpDefaultPluginInstance(aMimeType, aURL, aOwner)))
03522       return NS_ERROR_FAILURE;
03523 
03524     if(NS_FAILED(aOwner->GetInstance(instance)))
03525       return NS_ERROR_FAILURE;
03526 
03527     rv = NS_OK;
03528   }
03529 
03530   // if we have a failure error, it means we found a plugin for the mimetype,
03531   // but we had a problem with the entry point
03532   if(rv == NS_ERROR_FAILURE)
03533     return rv;
03534 
03535   // if we are here then we have loaded a plugin for this mimetype
03536   // and it could be the Default plugin
03537 
03538   nsPluginWindow    *window = nsnull;
03539 
03540   //we got a plugin built, now stream
03541   aOwner->GetWindow(window);
03542 
03543   if (nsnull != instance)
03544   {
03545     instance->Start();
03546     aOwner->CreateWidget();
03547 
03548     // If we've got a native window, the let the plugin know about it.
03549     if (window->window)
03550     {
03551       nsCOMPtr<nsIPluginInstance> inst = instance;
03552       ((nsPluginNativeWindow*)window)->CallSetWindow(inst);
03553     }
03554 
03555     // create an initial stream with data
03556     // don't make the stream if it's a java applet or we don't have SRC or DATA attribute
03557     PRBool havedata = PR_FALSE;
03558 
03559     nsCOMPtr<nsIPluginTagInfo> pti(do_QueryInterface(aOwner, &rv));
03560 
03561     if(pti) {
03562       const char *value;
03563       havedata = NS_SUCCEEDED(pti->GetAttribute("SRC", &value));
03564       // no need to check for "data" as it would have been converted to "src"
03565     }
03566 
03567     if(havedata && !isJava && bCanHandleInternally)
03568       rv = NewEmbeddedPluginStream(aURL, aOwner, instance);
03569 
03570     // notify Java DOM component
03571     nsresult res;
03572     nsCOMPtr<nsIPluginInstanceOwner> javaDOM =
03573              do_GetService("@mozilla.org/blackwood/java-dom;1", &res);
03574     if (NS_SUCCEEDED(res) && javaDOM)
03575       javaDOM->SetInstance(instance);
03576 
03577     NS_RELEASE(instance);
03578   }
03579 
03580 #ifdef PLUGIN_LOGGING
03581   nsCAutoString urlSpec2;
03582   if(aURL != nsnull) (void)aURL->GetAsciiSpec(urlSpec2);
03583 
03584   PR_LOG(nsPluginLogging::gPluginLog, PLUGIN_LOG_NORMAL,
03585         ("nsPluginHostImpl::InstatiateEmbeddedPlugin Finished mime=%s, rv=%d, owner=%p, url=%s\n",
03586         aMimeType, rv, aOwner, urlSpec2.get()));
03587 
03588   PR_LogFlush();
03589 #endif
03590 
03591   return rv;
03592 }
03593 
03594 
03596 /* Called by full-page case */
03597 NS_IMETHODIMP nsPluginHostImpl::InstantiateFullPagePlugin(const char *aMimeType,
03598                                                           nsIURI* aURI,
03599                                                           nsIStreamListener *&aStreamListener,
03600                                                           nsIPluginInstanceOwner *aOwner)
03601 {
03602 #ifdef PLUGIN_LOGGING
03603   nsCAutoString urlSpec;
03604   aURI->GetSpec(urlSpec);
03605   PLUGIN_LOG(PLUGIN_LOG_NORMAL,
03606   ("nsPluginHostImpl::InstatiateFullPagePlugin Begin mime=%s, owner=%p, url=%s\n",
03607   aMimeType, aOwner, urlSpec.get()));
03608 #endif
03609 
03610   if(FindStoppedPluginForURL(aURI, aOwner) == NS_OK) {
03611     PLUGIN_LOG(PLUGIN_LOG_NOISY,
03612     ("nsPluginHostImpl::InstatiateFullPagePlugin FoundStopped mime=%s\n",aMimeType));
03613 
03614     nsIPluginInstance* instance;
03615     aOwner->GetInstance(instance);
03616     if(!aMimeType || PL_strncasecmp(aMimeType, "application/x-java-vm", 21))
03617       NewFullPagePluginStream(aStreamListener, instance);
03618     NS_IF_RELEASE(instance);
03619     return NS_OK;
03620   }
03621 
03622   nsresult rv = SetUpPluginInstance(aMimeType, aURI, aOwner);
03623 
03624   if (NS_OK == rv)
03625   {
03626     nsCOMPtr<nsIPluginInstance> instance;
03627     nsPluginWindow * win = nsnull;
03628 
03629     aOwner->GetInstance(*getter_AddRefs(instance));
03630     aOwner->GetWindow(win);
03631 
03632     if (win && instance)
03633     {
03634       instance->Start();
03635       aOwner->CreateWidget();
03636 
03637       // If we've got a native window, the let the plugin know about it.
03638       nsPluginNativeWindow * window = (nsPluginNativeWindow *)win;
03639       if (window->window)
03640         window->CallSetWindow(instance);
03641 
03642       rv = NewFullPagePluginStream(aStreamListener, instance);
03643 
03644       // If we've got a native window, the let the plugin know about it.
03645       if (window->window)
03646         window->CallSetWindow(instance);
03647     }
03648   }
03649 
03650   PLUGIN_LOG(PLUGIN_LOG_NORMAL,
03651   ("nsPluginHostImpl::InstatiateFullPagePlugin End mime=%s, rv=%d, owner=%p, url=%s\n",
03652   aMimeType, rv, aOwner, urlSpec.get()));
03653 
03654   return rv;
03655 }
03656 
03657 
03659 nsresult nsPluginHostImpl::FindStoppedPluginForURL(nsIURI* aURL,
03660                                                    nsIPluginInstanceOwner *aOwner)
03661 {
03662   nsCAutoString url;
03663   if(!aURL)
03664     return NS_ERROR_FAILURE;
03665 
03666   (void)aURL->GetAsciiSpec(url);
03667 
03668   nsActivePlugin * plugin = mActivePluginList.findStopped(url.get());
03669 
03670   if((plugin != nsnull) && (plugin->mStopped))
03671   {
03672     nsIPluginInstance* instance = plugin->mInstance;
03673     nsPluginWindow    *window = nsnull;
03674     aOwner->GetWindow(window);
03675 
03676     aOwner->SetInstance(instance);
03677 
03678     // we have to reset the owner and instance in the plugin instance peer
03679     //instance->GetPeer(&peer);
03680     ((nsPluginInstancePeerImpl*)plugin->mPeer)->SetOwner(aOwner);
03681 
03682     instance->Start();
03683     aOwner->CreateWidget();
03684 
03685     // If we've got a native window, the let the plugin know about it.
03686     if (window->window)
03687     {
03688       nsCOMPtr<nsIPluginInstance> inst = instance;
03689       ((nsPluginNativeWindow*)window)->CallSetWindow(inst);
03690     }
03691 
03692     plugin->setStopped(PR_FALSE);
03693     return NS_OK;
03694   }
03695   return NS_ERROR_FAILURE;
03696 }
03697 
03698 
03700 nsresult nsPluginHostImpl::AddInstanceToActiveList(nsCOMPtr<nsIPlugin> aPlugin,
03701                                                nsIPluginInstance* aInstance,
03702                                                nsIURI* aURL,
03703                                                PRBool aDefaultPlugin,
03704                                                nsIPluginInstancePeer* peer)
03705 
03706 {
03707   NS_ENSURE_ARG_POINTER(aURL);
03708 
03709   nsCAutoString url;
03710   (void)aURL->GetSpec(url);
03711 
03712   // let's find the corresponding plugin tag by matching nsIPlugin pointer
03713   // it's legal for XPCOM plugins not to have nsIPlugin implemented but
03714   // this is OK, we don't need the plugin tag for XPCOM plugins. It is going
03715   // to be used later when we decide whether or not we should delay unloading
03716   // NPAPI dll from memory, and XPCOM dlls will stay in memory anyway.
03717   nsPluginTag * pluginTag = nsnull;
03718   if(aPlugin) {
03719     for(pluginTag = mPlugins; pluginTag != nsnull; pluginTag = pluginTag->mNext) {
03720       if(pluginTag->mEntryPoint == aPlugin)
03721         break;
03722     }
03723     NS_ASSERTION(pluginTag, "Plugin tag not found");
03724   }
03725 
03726   nsActivePlugin * plugin = new nsActivePlugin(pluginTag, aInstance, url.get(), aDefaultPlugin, peer);
03727 
03728   if(!plugin)
03729     return NS_ERROR_OUT_OF_MEMORY;
03730 
03731   mActivePluginList.add(plugin);
03732   return NS_OK;
03733 }
03734 
03735 
03737 void
03738 nsPluginTag::RegisterWithCategoryManager(PRBool aOverrideInternalTypes,
03739                                          nsPluginTag::nsRegisterType aType)
03740 {
03741   if (!mMimeTypeArray)
03742     return;
03743 
03744   PLUGIN_LOG(PLUGIN_LOG_NORMAL,
03745   ("nsPluginTag::RegisterWithCategoryManager plugin=%s, removing = %s\n",
03746   mFileName, aType == ePluginUnregister ? "yes" : "no"));
03747 
03748   nsCOMPtr<nsICategoryManager> catMan = do_GetService(NS_CATEGORYMANAGER_CONTRACTID);
03749   if (!catMan)
03750     return;
03751 
03752   const char *contractId = "@mozilla.org/content/plugin/document-loader-factory;1";
03753 
03754   nsCOMPtr<nsIPrefBranch> psvc(do_GetService(NS_PREFSERVICE_CONTRACTID));
03755   if (!psvc)
03756     return; // NS_ERROR_OUT_OF_MEMORY
03757 
03758   // A preference controls whether or not the full page plugin is disabled for
03759   // a particular type. The string must be in the form:
03760   //   type1,type2,type3,type4
03761   // Note: need an actual interface to control this and subsequent disabling 
03762   // (and other plugin host settings) so applications can reliably disable 
03763   // plugins - without relying on implementation details such as prefs/category
03764   // manager entries.
03765   nsXPIDLCString overrideTypes;
03766   psvc->GetCharPref("plugin.disable_full_page_plugin_for_types", getter_Copies(overrideTypes));
03767   nsCAutoString overrideTypesFormatted;
03768   overrideTypesFormatted.Assign(',');
03769   overrideTypesFormatted += overrideTypes;
03770   overrideTypesFormatted.Append(',');
03771 
03772   nsACString::const_iterator start, end;
03773   for(int i = 0; i < mVariants; i++) {
03774     if (aType == ePluginUnregister) {
03775       nsXPIDLCString value;
03776       if (NS_SUCCEEDED(catMan->GetCategoryEntry("Gecko-Content-Viewers",
03777                                                 mMimeTypeArray[i],
03778                                                 getter_Copies(value)))) {
03779         // Only delete the entry if a plugin registered for it
03780         if (strcmp(value, contractId) == 0) {
03781           catMan->DeleteCategoryEntry("Gecko-Content-Viewers",
03782                                       mMimeTypeArray[i],
03783                                       PR_TRUE);
03784         }
03785       }
03786     } else {
03787       overrideTypesFormatted.BeginReading(start);
03788       overrideTypesFormatted.EndReading(end);
03789       
03790       nsDependentCString mimeType(mMimeTypeArray[i]);
03791       nsCAutoString commaSeparated; 
03792       commaSeparated.Assign(',');
03793       commaSeparated += mimeType;
03794       commaSeparated.Append(',');
03795       if (!FindInReadable(commaSeparated, start, end)) {
03796         catMan->AddCategoryEntry("Gecko-Content-Viewers",
03797                                  mMimeTypeArray[i],
03798                                  contractId,
03799                                  PR_FALSE, /* persist: broken by bug 193031 */
03800                                  aOverrideInternalTypes, /* replace if we're told to */
03801                                  nsnull);
03802       }
03803     }
03804 
03805     PLUGIN_LOG(PLUGIN_LOG_NOISY,
03806     ("nsPluginTag::RegisterWithCategoryManager mime=%s, plugin=%s\n",
03807     mMimeTypeArray[i], mFileName));
03808   }
03809 }
03810 
03811 
03813 NS_IMETHODIMP nsPluginHostImpl::SetUpPluginInstance(const char *aMimeType,
03814                                                     nsIURI *aURL,
03815                                                     nsIPluginInstanceOwner *aOwner)
03816 {
03817   nsresult rv = NS_OK;
03818 
03819   rv = TrySetUpPluginInstance(aMimeType, aURL, aOwner);
03820 
03821   // if we fail, refresh plugin list just in case the plugin has been
03822   // just added and try to instantiate plugin instance again, see bug 143178
03823   if (NS_FAILED(rv)) {
03824     // we should also make sure not to do this more than once per page
03825     // so if there are a few embed tags with unknown plugins,
03826     // we don't get unnecessary overhead
03827     // let's cache document to decide whether this is the same page or not
03828     nsCOMPtr<nsIDocument> document;
03829     if (aOwner)
03830       aOwner->GetDocument(getter_AddRefs(document));
03831 
03832     nsCOMPtr<nsIDocument> currentdocument = do_QueryReferent(mCurrentDocument);
03833     if (document == currentdocument)
03834       return rv;
03835 
03836     mCurrentDocument = do_GetWeakReference(document);
03837 
03838     // ReloadPlugins will do the job smartly: nothing will be done
03839     // if no changes detected, in such a case just return
03840     if (NS_ERROR_PLUGINS_PLUGINSNOTCHANGED == ReloadPlugins(PR_FALSE))
03841       return rv;
03842 
03843     // other failure return codes may be not fatal, so we can still try
03844     rv = TrySetUpPluginInstance(aMimeType, aURL, aOwner);
03845   }
03846 
03847   return rv;
03848 }
03849 
03850 NS_IMETHODIMP nsPluginHostImpl::TrySetUpPluginInstance(const char *aMimeType,
03851                                                        nsIURI *aURL,
03852                                                        nsIPluginInstanceOwner *aOwner)
03853 {
03854 #ifdef PLUGIN_LOGGING
03855   nsCAutoString urlSpec;
03856   if(aURL != nsnull) (void)aURL->GetSpec(urlSpec);
03857 
03858   PR_LOG(nsPluginLogging::gPluginLog, PLUGIN_LOG_NORMAL,
03859         ("nsPluginHostImpl::TrySetupPluginInstance Begin mime=%s, owner=%p, url=%s\n",
03860         aMimeType, aOwner, urlSpec.get()));
03861 
03862   PR_LogFlush();
03863 #endif
03864 
03865 
03866   nsresult result = NS_ERROR_FAILURE;
03867   nsCOMPtr<nsIPluginInstance> instance;
03868   nsCOMPtr<nsIPlugin> plugin;
03869   const char* mimetype = nsnull;
03870 
03871   if(!aURL)
03872     return NS_ERROR_FAILURE;
03873 
03874   // if don't have a mimetype or no plugin can handle this mimetype
03875   // check by file extension
03876   if(!aMimeType || NS_FAILED(IsPluginEnabledForType(aMimeType))) {
03877     nsCOMPtr<nsIURL> url = do_QueryInterface(aURL);
03878     if (!url) return NS_ERROR_FAILURE;
03879 
03880     nsCAutoString fileExtension;
03881     url->GetFileExtension(fileExtension);
03882 
03883     // if we don't have an extension or no plugin for this extension,
03884     // return failure as there is nothing more we can do
03885     if (fileExtension.IsEmpty() ||
03886         NS_FAILED(IsPluginEnabledForExtension(fileExtension.get(),
03887                                               mimetype))) {
03888 
03889       if (mDefaultPluginDisabled) {
03890         aOwner->PluginNotAvailable(aMimeType ? aMimeType : mimetype);
03891       }
03892 
03893       return NS_ERROR_FAILURE;
03894     }
03895   }
03896   else
03897     mimetype = aMimeType;
03898 
03899   PRBool isJavaPlugin = PR_FALSE;
03900   if (aMimeType &&
03901       (PL_strncasecmp(aMimeType, "application/x-java-vm", 21) == 0 ||
03902          PL_strncasecmp(aMimeType, "application/x-java-applet", 25) == 0))
03903   {
03904     isJavaPlugin = PR_TRUE;
03905   }
03906 
03907 #if defined(OJI) && ((defined(XP_UNIX) && !defined(XP_MACOSX)) || defined(XP_OS2))
03908   // This is a work-around on Unix for a LiveConnect problem (bug 83698).
03909   // The problem:
03910   // The proxy JNI needs to be created by the browser. If it is created by
03911   // someone else (e.g., a plugin) on a different thread, the proxy JNI will
03912   // not work, and break LiveConnect.
03913   // Currently, on Unix, when instantiating a Java plugin instance (by calling
03914   // InstantiateEmbeddedPlugin() next), Java plugin will create the proxy JNI
03915   // if it is not created yet. If that happens, LiveConnect will be broken.
03916   // Before lazy start JVM was implemented, since at this point the browser
03917   // already created the proxy JNI buring startup, the problem did not happen.
03918   // But after the lazy start was implemented, at this point the proxy JNI was
03919   // not created yet, so the Java plugin created the proxy JNI, and broke
03920   // liveConnect.
03921   // On Windows and Mac, Java plugin does not create the proxy JNI, but lets
03922   // the browser to create it. Hence this is a Unix-only problem.
03923   //
03924   // The work-around:
03925   // The root cause of the problem is in Java plugin's Unix implementation,
03926   // which should not create the proxy JNI.
03927   // As a work-around, here we make sure the proxy JNI has been created by the
03928   // browser, before plugin gets a chance.
03929   //
03930 
03931   if (isJavaPlugin) {
03932     // If Java is installed, get proxy JNI.
03933     nsCOMPtr<nsIJVMManager> jvmManager = do_GetService(nsIJVMManager::GetCID(),
03934                                                      &result);
03935     if (NS_SUCCEEDED(result)) {
03936       JNIEnv* proxyEnv;
03937       // Get proxy JNI, if not created yet, create it.
03938       jvmManager->GetProxyJNI(&proxyEnv);
03939     }
03940   }
03941 #endif
03942 
03943   nsCAutoString contractID(
03944           NS_LITERAL_CSTRING(NS_INLINE_PLUGIN_CONTRACTID_PREFIX) +
03945           nsDependentCString(mimetype));
03946 
03947   GetPluginFactory(mimetype, getter_AddRefs(plugin));
03948 
03949   instance = do_CreateInstance(contractID.get(), &result);
03950 
03951   // couldn't create an XPCOM plugin, try to create wrapper for a
03952   // legacy plugin
03953   if (NS_FAILED(result)) {
03954     if(plugin) {
03955 #ifdef XP_WIN
03956       static BOOL firstJavaPlugin = FALSE;
03957       BOOL restoreOrigDir = FALSE;
03958       char origDir[_MAX_PATH];
03959       if (isJavaPlugin && !firstJavaPlugin) {
03960         DWORD dw = ::GetCurrentDirectory(_MAX_PATH, origDir);
03961         NS_ASSERTION(dw <= _MAX_PATH, "Falied to obtain the current directory, which may leads to incorrect class laoding");
03962         nsCOMPtr<nsIFile> binDirectory;
03963         result = NS_GetSpecialDirectory(NS_XPCOM_CURRENT_PROCESS_DIR,
03964                                         getter_AddRefs(binDirectory));
03965 
03966         if (NS_SUCCEEDED(result)) {
03967           nsCAutoString path;
03968           binDirectory->GetNativePath(path);
03969           restoreOrigDir = ::SetCurrentDirectory(path.get());
03970         }
03971       }
03972 #endif
03973       result = plugin->CreateInstance(NULL, kIPluginInstanceIID, (void **)getter_AddRefs(instance));
03974 
03975 #ifdef XP_WIN
03976       if (!firstJavaPlugin && restoreOrigDir) {
03977         BOOL bCheck = :: SetCurrentDirectory(origDir);
03978         NS_ASSERTION(bCheck, " Error restoring driectoy");
03979         firstJavaPlugin = TRUE;
03980       }
03981 #endif
03982     }
03983 
03984     if (NS_FAILED(result)) {
03985       nsCOMPtr<nsIPlugin> bwPlugin =
03986         do_GetService("@mozilla.org/blackwood/pluglet-engine;1", &result);
03987       if (NS_SUCCEEDED(result)) {
03988         result = bwPlugin->CreatePluginInstance(NULL,
03989                                                 kIPluginInstanceIID,
03990                                                 aMimeType,
03991                                                 (void **)getter_AddRefs(instance));
03992       }
03993     }
03994   }
03995 
03996   // neither an XPCOM or legacy plugin could be instantiated,
03997   // so return the failure
03998   if (NS_FAILED(result))
03999     return result;
04000 
04001   // it is adreffed here
04002   aOwner->SetInstance(instance);
04003 
04004   nsRefPtr<nsPluginInstancePeerImpl> peer = new nsPluginInstancePeerImpl();
04005   if (!peer)
04006     return NS_ERROR_OUT_OF_MEMORY;
04007 
04008   // set up the peer for the instance
04009   peer->Initialize(aOwner, mimetype);
04010 
04011   result = instance->Initialize(peer);  // this should addref the peer but not the instance or owner
04012   if (NS_FAILED(result))                 // except in some cases not Java, see bug 140931
04013     return result;       // our COM pointer will free the peer
04014 
04015   // instance and peer will be addreffed here
04016   result = AddInstanceToActiveList(plugin, instance, aURL, PR_FALSE, peer);
04017 
04018 #ifdef PLUGIN_LOGGING
04019   nsCAutoString urlSpec2;
04020   if (aURL)
04021     aURL->GetSpec(urlSpec2);
04022 
04023   PR_LOG(nsPluginLogging::gPluginLog, PLUGIN_LOG_BASIC,
04024         ("nsPluginHostImpl::TrySetupPluginInstance Finished mime=%s, rv=%d, owner=%p, url=%s\n",
04025         aMimeType, result, aOwner, urlSpec2.get()));
04026 
04027   PR_LogFlush();
04028 #endif
04029 
04030   return result;
04031 }
04032 
04033 
04035 nsresult
04036 nsPluginHostImpl::SetUpDefaultPluginInstance(const char *aMimeType,
04037                                              nsIURI *aURL,
04038                                              nsIPluginInstanceOwner *aOwner)
04039 {
04040   if (mDefaultPluginDisabled) {
04041     // The default plugin is disabled, don't load it.
04042 
04043     return NS_OK;
04044   }
04045 
04046   nsCOMPtr<nsIPluginInstance> instance;
04047   nsCOMPtr<nsIPlugin> plugin = NULL;
04048   const char* mimetype = aMimeType;
04049 
04050   if(!aURL)
04051     return NS_ERROR_FAILURE;
04052 
04053   GetPluginFactory("*", getter_AddRefs(plugin));
04054 
04055   nsresult result;
04056   instance = do_CreateInstance(NS_INLINE_PLUGIN_CONTRACTID_PREFIX "*",
04057                                &result);
04058 
04059   // couldn't create an XPCOM plugin, try to create wrapper for a
04060   // legacy plugin
04061   if (NS_FAILED(result))
04062   {
04063     if(plugin)
04064       result = plugin->CreateInstance(NULL, kIPluginInstanceIID,
04065                                       getter_AddRefs(instance));
04066   }
04067 
04068   // neither an XPCOM or legacy plugin could be instantiated, so
04069   // return the failure
04070   if(NS_FAILED(result))
04071     return result;
04072 
04073   // it is adreffed here
04074   aOwner->SetInstance(instance);
04075 
04076   nsRefPtr<nsPluginInstancePeerImpl> peer = new nsPluginInstancePeerImpl();
04077   if (!peer)
04078     return NS_ERROR_OUT_OF_MEMORY;
04079 
04080   // if we don't have a mimetype, check by file extension
04081   nsXPIDLCString mt;
04082   if (!mimetype || !*mimetype)
04083   {
04084     nsresult res = NS_OK;
04085     nsCOMPtr<nsIMIMEService> ms (do_GetService(NS_MIMESERVICE_CONTRACTID, &res));
04086     if(NS_SUCCEEDED(res))
04087     {
04088       res = ms->GetTypeFromURI(aURL, mt);
04089       if(NS_SUCCEEDED(res))
04090         mimetype = mt.get();
04091     }
04092   }
04093 
04094   // set up the peer for the instance
04095   peer->Initialize(aOwner, mimetype);
04096 
04097   // this should addref the peer but not the instance or owner except
04098   // in some cases not Java, see bug 140931 our COM pointer will free
04099   // the peer
04100   result = instance->Initialize(peer);
04101   if (NS_FAILED(result))
04102     return result;
04103 
04104   // instance and peer will be addreffed here
04105   result = AddInstanceToActiveList(plugin, instance, aURL, PR_TRUE, peer);
04106 
04107   return result;
04108 }
04109 
04110 
04112 NS_IMETHODIMP
04113 nsPluginHostImpl::IsPluginEnabledForType(const char* aMimeType)
04114 {
04115   nsPluginTag *plugins = nsnull;
04116   PRInt32     variants, cnt;
04117 
04118   LoadPlugins();
04119 
04120   // if we have a mimetype passed in, search the mPlugins linked
04121   // list for a match
04122   if (nsnull != aMimeType)
04123   {
04124     plugins = mPlugins;
04125 
04126     while (nsnull != plugins)
04127     {
04128       variants = plugins->mVariants;
04129 
04130       for (cnt = 0; cnt < variants; cnt++)
04131         if (plugins->mMimeTypeArray[cnt] && (0 == PL_strcasecmp(plugins->mMimeTypeArray[cnt], aMimeType)))
04132           return NS_OK;
04133 
04134       if (cnt < variants)
04135         break;
04136 
04137       plugins = plugins->mNext;
04138     }
04139   }
04140 
04141   return NS_ERROR_FAILURE;
04142 }
04143 
04144 
04146 // check comma delimitered extensions
04147 static int CompareExtensions(const char *aExtensionList, const char *aExtension)
04148 {
04149   if((aExtensionList == nsnull) || (aExtension == nsnull))
04150     return -1;
04151 
04152   const char *pExt = aExtensionList;
04153   const char *pComma = strchr(pExt, ',');
04154 
04155   if(pComma == nsnull)
04156     return PL_strcasecmp(pExt, aExtension);
04157 
04158   int extlen = strlen(aExtension);
04159   while(pComma != nsnull)
04160   {
04161     int length = pComma - pExt;
04162     if(length == extlen && 0 == PL_strncasecmp(aExtension, pExt, length))
04163       return 0;
04164 
04165     pComma++;
04166     pExt = pComma;
04167     pComma = strchr(pExt, ',');
04168   }
04169 
04170   // the last one
04171   return PL_strcasecmp(pExt, aExtension);
04172 }
04173 
04174 
04176 NS_IMETHODIMP
04177 nsPluginHostImpl::IsPluginEnabledForExtension(const char* aExtension,
04178                                               const char* &aMimeType)
04179 {
04180   nsPluginTag *plugins = nsnull;
04181   PRInt32     variants, cnt;
04182 
04183   LoadPlugins();
04184 
04185   // if we have a mimetype passed in, search the mPlugins linked
04186   // list for a match
04187   if (nsnull != aExtension)
04188   {
04189     plugins = mPlugins;
04190 
04191     while (nsnull != plugins)
04192     {
04193       variants = plugins->mVariants;
04194 
04195       if (plugins->mExtensionsArray)
04196       {
04197         for (cnt = 0; cnt < variants; cnt++)
04198         {
04199           // mExtensionsArray[cnt] is a list of extensions separated
04200           // by commas
04201           if (0 == CompareExtensions(plugins->mExtensionsArray[cnt], aExtension))
04202           {
04203             aMimeType = plugins->mMimeTypeArray[cnt];
04204             return NS_OK;
04205           }
04206         }
04207 
04208         if (cnt < variants)
04209           break;
04210       }
04211 
04212       plugins = plugins->mNext;
04213     }
04214   }
04215 
04216   return NS_ERROR_FAILURE;
04217 }
04218 
04219 
04221 // Utility functions for a charset convertor
04222 // which converts platform charset to unicode.
04223 
04224 static nsresult CreateUnicodeDecoder(nsIUnicodeDecoder **aUnicodeDecoder)
04225 {
04226   nsresult rv;
04227   // get the charset
04228   nsCAutoString platformCharset;
04229   nsCOMPtr <nsIPlatformCharset> platformCharsetService = do_GetService(NS_PLATFORMCHARSET_CONTRACTID, &rv);
04230   NS_ENSURE_SUCCESS(rv, rv);
04231   rv = platformCharsetService->GetCharset(kPlatformCharsetSel_FileName, platformCharset);
04232   NS_ENSURE_SUCCESS(rv, rv);
04233 
04234   // get the decoder
04235   nsCOMPtr<nsICharsetConverterManager> ccm = do_GetService(NS_CHARSETCONVERTERMANAGER_CONTRACTID, &rv);
04236   NS_ENSURE_SUCCESS(rv, rv);
04237   rv = ccm->GetUnicodeDecoderRaw(platformCharset.get(),
04238                                  aUnicodeDecoder);
04239 
04240   return rv;
04241 }
04242 
04243 static nsresult DoCharsetConversion(nsIUnicodeDecoder *aUnicodeDecoder,
04244                                      const char* aANSIString, nsAString& aUnicodeString)
04245 {
04246   NS_ENSURE_TRUE(aUnicodeDecoder, NS_ERROR_FAILURE);
04247   NS_ENSURE_TRUE(aANSIString, NS_ERROR_FAILURE);
04248   nsresult rv;
04249 
04250   PRInt32 numberOfBytes = strlen(aANSIString);
04251   PRInt32 outUnicodeLen;
04252   nsAutoString buffer;
04253   rv = aUnicodeDecoder->GetMaxLength(aANSIString, numberOfBytes, &outUnicodeLen);
04254   NS_ENSURE_SUCCESS(rv, rv);
04255   if (!EnsureStringLength(buffer, outUnicodeLen))
04256     return NS_ERROR_OUT_OF_MEMORY;
04257   rv = aUnicodeDecoder->Convert(aANSIString, &numberOfBytes, buffer.BeginWriting(), &outUnicodeLen);
04258   NS_ENSURE_SUCCESS(rv, rv);
04259   buffer.SetLength(outUnicodeLen);
04260   aUnicodeString = buffer;
04261 
04262   return rv;
04263 }
04264 
04266 
04267 class DOMMimeTypeImpl : public nsIDOMMimeType {
04268 public:
04269   NS_DECL_ISUPPORTS
04270 
04271   DOMMimeTypeImpl(nsPluginTag* aPluginTag, PRUint32 aMimeTypeIndex)
04272   {
04273     (void) CreateUnicodeDecoder(getter_AddRefs(mUnicodeDecoder));
04274     if (aPluginTag) {
04275       if (aPluginTag->mMimeDescriptionArray)
04276         (void) DoCharsetConversion(mUnicodeDecoder,
04277                                    aPluginTag->mMimeDescriptionArray[aMimeTypeIndex], mDescription);
04278       if (aPluginTag->mExtensionsArray)
04279         mSuffixes.AssignWithConversion(aPluginTag->mExtensionsArray[aMimeTypeIndex]);
04280       if (aPluginTag->mMimeTypeArray)
04281         mType.AssignWithConversion(aPluginTag->mMimeTypeArray[aMimeTypeIndex]);
04282     }
04283   }
04284 
04285   virtual ~DOMMimeTypeImpl() {
04286   }
04287 
04288   NS_METHOD GetDescription(nsAString& aDescription)
04289   {
04290     aDescription.Assign(mDescription);
04291     return NS_OK;
04292   }
04293 
04294   NS_METHOD GetEnabledPlugin(nsIDOMPlugin** aEnabledPlugin)
04295   {
04296     // this has to be implemented by the DOM version.
04297     *aEnabledPlugin = nsnull;
04298     return NS_OK;
04299   }
04300 
04301   NS_METHOD GetSuffixes(nsAString& aSuffixes)
04302   {
04303     aSuffixes.Assign(mSuffixes);
04304     return NS_OK;
04305   }
04306 
04307   NS_METHOD GetType(nsAString& aType)
04308   {
04309     aType.Assign(mType);
04310     return NS_OK;
04311   }
04312 
04313 private:
04314   nsString mDescription;
04315   nsString mSuffixes;
04316   nsString mType;
04317   nsCOMPtr<nsIUnicodeDecoder> mUnicodeDecoder;
04318 };
04319 
04320 
04322 NS_IMPL_ISUPPORTS1(DOMMimeTypeImpl, nsIDOMMimeType)
04324 class DOMPluginImpl : public nsIDOMPlugin {
04325 public:
04326   NS_DECL_ISUPPORTS
04327 
04328   DOMPluginImpl(nsPluginTag* aPluginTag) : mPluginTag(aPluginTag)
04329   {
04330     (void) CreateUnicodeDecoder(getter_AddRefs(mUnicodeDecoder));
04331   }
04332 
04333   virtual ~DOMPluginImpl() {
04334   }
04335 
04336   NS_METHOD GetDescription(nsAString& aDescription)
04337   {
04338     DoCharsetConversion(mUnicodeDecoder, mPluginTag.mDescription, aDescription);
04339     return NS_OK;
04340   }
04341 
04342   NS_METHOD GetFilename(nsAString& aFilename)
04343   {
04344     PRBool bShowPath;
04345     nsCOMPtr<nsIPrefBranch> prefService = do_GetService(NS_PREFSERVICE_CONTRACTID);
04346     if (prefService &&
04347         NS_SUCCEEDED(prefService->GetBoolPref("plugin.expose_full_path",&bShowPath)) &&
04348         bShowPath)
04349     {
04350       // only show the full path if people have set the pref,
04351       // the default should not reveal path information (bug 88183)
04352 #if defined(XP_MACOSX)
04353       return DoCharsetConversion(mUnicodeDecoder, mPluginTag.mFullPath, aFilename);
04354 #else
04355       return DoCharsetConversion(mUnicodeDecoder, mPluginTag.mFileName, aFilename);
04356 #endif
04357     }
04358 
04359     const char* spec;
04360     if (mPluginTag.mFullPath)
04361     {
04362 #if !defined(XP_MACOSX)
04363       NS_ERROR("Only MAC should be using nsPluginTag::mFullPath!");
04364 #endif
04365       spec = mPluginTag.mFullPath;
04366     }
04367     else
04368     {
04369       spec = mPluginTag.mFileName;
04370     }
04371 
04372     nsCString leafName;
04373     nsCOMPtr<nsILocalFile> pluginPath;
04374     NS_NewNativeLocalFile(nsDependentCString(spec), PR_TRUE,
04375                           getter_AddRefs(pluginPath));
04376 
04377     pluginPath->GetNativeLeafName(leafName);
04378 
04379     nsresult rv = DoCharsetConversion(mUnicodeDecoder, leafName.get(), aFilename);
04380     return rv;
04381   }
04382 
04383   NS_METHOD GetName(nsAString& aName)
04384   {
04385     DoCharsetConversion(mUnicodeDecoder, mPluginTag.mName, aName);
04386     return NS_OK;
04387   }
04388 
04389   NS_METHOD GetLength(PRUint32* aLength)
04390   {
04391     *aLength = mPluginTag.mVariants;
04392     return NS_OK;
04393   }
04394 
04395   NS_METHOD Item(PRUint32 aIndex, nsIDOMMimeType** aReturn)
04396   {
04397     nsIDOMMimeType* mimeType = new DOMMimeTypeImpl(&mPluginTag, aIndex);
04398     NS_IF_ADDREF(mimeType);
04399     *aReturn = mimeType;
04400     return NS_OK;
04401   }
04402 
04403   NS_METHOD NamedItem(const nsAString& aName, nsIDOMMimeType** aReturn)
04404   {
04405     for (int index = mPluginTag.mVariants - 1; index >= 0; --index) {
04406       if (aName.Equals(NS_ConvertASCIItoUCS2(mPluginTag.mMimeTypeArray[index])))
04407         return Item(index, aReturn);
04408     }
04409     return NS_OK;
04410   }
04411 
04412 private:
04413   nsPluginTag mPluginTag;
04414   nsCOMPtr<nsIUnicodeDecoder> mUnicodeDecoder;
04415 };
04416 
04418 NS_IMPL_ISUPPORTS1(DOMPluginImpl, nsIDOMPlugin)
04420 
04421 
04422 NS_IMETHODIMP
04423 nsPluginHostImpl::GetPluginCount(PRUint32* aPluginCount)
04424 {
04425   LoadPlugins();
04426 
04427   PRUint32 count = 0;
04428 
04429   nsPluginTag* plugin = mPlugins;
04430   while (plugin != nsnull) {
04431     ++count;
04432     plugin = plugin->mNext;
04433   }
04434 
04435   *aPluginCount = count;
04436 
04437   return NS_OK;
04438 }
04439 
04440 
04442 NS_IMETHODIMP
04443 nsPluginHostImpl::GetPlugins(PRUint32 aPluginCount, nsIDOMPlugin** aPluginArray)
04444 {
04445   LoadPlugins();
04446 
04447   nsPluginTag* plugin = mPlugins;
04448   for (PRUint32 i = 0; i < aPluginCount && plugin != nsnull;
04449        i++, plugin = plugin->mNext) {
04450     nsIDOMPlugin* domPlugin = new DOMPluginImpl(plugin);
04451     NS_IF_ADDREF(domPlugin);
04452     aPluginArray[i] = domPlugin;
04453   }
04454 
04455   return NS_OK;
04456 }
04457 
04458 
04460 nsresult
04461 nsPluginHostImpl::FindPluginEnabledForType(const char* aMimeType,
04462                                            nsPluginTag* &aPlugin)
04463 {
04464   nsPluginTag *plugins = nsnull;
04465   PRInt32     variants, cnt;
04466 
04467   aPlugin = nsnull;
04468 
04469   LoadPlugins();
04470 
04471   // if we have a mimetype passed in, search the mPlugins
04472   // linked list for a match
04473   if (nsnull != aMimeType) {
04474     plugins = mPlugins;
04475 
04476     while (nsnull != plugins) {
04477       variants = plugins->mVariants;
04478 
04479       for (cnt = 0; cnt < variants; cnt++) {
04480         if (plugins->mMimeTypeArray[cnt] && (0 == PL_strcasecmp(plugins->mMimeTypeArray[cnt], aMimeType))) {
04481           aPlugin = plugins;
04482           return NS_OK;
04483         }
04484       }
04485 
04486       if (cnt < variants)
04487         break;
04488 
04489       plugins = plugins->mNext;
04490     }
04491   }
04492 
04493   return NS_ERROR_FAILURE;
04494 }
04495 
04496 #if defined(XP_MACOSX)
04497 
04502 #include <sys/stat.h>
04503 #include <sys/fcntl.h>
04504 #include <unistd.h>
04505 
04506 static inline PRBool is_directory(const char* path)
04507 {
04508   struct stat sb;
04509   return ::stat(path, &sb) == 0 && S_ISDIR(sb.st_mode);
04510 }
04511 
04512 static inline PRBool is_symbolic_link(const char* path)
04513 {
04514   struct stat sb;
04515   return ::lstat(path, &sb) == 0 && S_ISLNK(sb.st_mode);
04516 }
04517 
04518 static int open_executable(const char* path)
04519 {
04520   int fd = 0;
04521   char resolvedPath[PATH_MAX] = "\0";
04522 
04523   // If the root of the bundle as referred to by path is a symbolic link,
04524   // CFBundleCopyExecutableURL will not return an absolute URL, but will
04525   // instead only return the executable name, such as "MRJPlugin".  Work
04526   // around that by always using a fully-resolved absolute pathname.
04527   if (is_symbolic_link(path)) {
04528     path = realpath(path, resolvedPath);
04529     if (!path)
04530       return fd;
04531   }
04532 
04533   // if this is a directory, it must be a bundle, so get the true path using CFBundle...
04534   if (is_directory(path)) {
04535     CFBundleRef bundle = NULL;
04536     CFStringRef pathRef = CFStringCreateWithCString(NULL, path, kCFStringEncodingUTF8);
04537     if (pathRef) {
04538       CFURLRef bundleURL = CFURLCreateWithFileSystemPath(NULL, pathRef, kCFURLPOSIXPathStyle, true);
04539       CFRelease(pathRef);
04540       if (bundleURL != NULL) {
04541         bundle = CFBundleCreate(NULL, bundleURL);
04542         CFRelease(bundleURL);
04543         if (bundle) {
04544           CFURLRef executableURL = CFBundleCopyExecutableURL(bundle);
04545           if (executableURL) {
04546             pathRef = CFURLCopyFileSystemPath(executableURL, kCFURLPOSIXPathStyle);
04547             CFRelease(executableURL);
04548             if (pathRef) {
04549               CFIndex bufferSize = CFStringGetMaximumSizeForEncoding(CFStringGetLength(pathRef), kCFStringEncodingUTF8) + 1;
04550               char* executablePath = new char[bufferSize];
04551               if (executablePath && CFStringGetCString(pathRef, executablePath, bufferSize, kCFStringEncodingUTF8)) {
04552                 fd = open(executablePath, O_RDONLY, 0);
04553                 delete[] executablePath;
04554                             }
04555               CFRelease(pathRef);
04556             }
04557           }
04558           CFRelease(bundle);
04559         }
04560       }
04561     }
04562   } else {
04563     fd = open(path, O_RDONLY, 0);
04564   }
04565   return fd;
04566 }
04567 
04568 static PRBool IsCompatibleExecutable(const char* path)
04569 {
04570   int fd = open_executable(path);
04571   if (fd > 0) {
04572     // Check the executable header to see if it is something we can use. Currently
04573     // we can only use 32-bit mach-o and FAT binaries (FAT headers are always big
04574     // endian, so we do network-to-host swap on the bytes from disk).
04575     // Note: We assume FAT binaries contain the right arch. Maybe fix that later.
04576     UInt32 magic;
04577     ssize_t n = read(fd, &magic, sizeof(magic));
04578     close(fd);
04579     if (n == sizeof(magic)) {
04580       if ((magic == MH_MAGIC) || (PR_ntohl(magic) == FAT_MAGIC))
04581         return PR_TRUE;
04582     }
04583   }
04584   return PR_FALSE;
04585 }
04586 
04587 #else
04588 
04589 inline PRBool IsCompatibleExecutable(const char* path) { return PR_TRUE; }
04590 
04591 #endif
04592 
04593 
04595 NS_IMETHODIMP nsPluginHostImpl::GetPluginFactory(const char *aMimeType, nsIPlugin** aPlugin)
04596 {
04597   nsresult rv = NS_ERROR_FAILURE;
04598   *aPlugin = NULL;
04599 
04600   if(!aMimeType)
04601     return NS_ERROR_ILLEGAL_VALUE;
04602 
04603   // If plugins haven't been scanned yet, do so now
04604   LoadPlugins();
04605 
04606   nsPluginTag* pluginTag;
04607   if((rv = FindPluginEnabledForType(aMimeType, pluginTag)) == NS_OK)
04608   {
04609     PLUGIN_LOG(PLUGIN_LOG_BASIC,
04610     ("nsPluginHostImpl::GetPluginFactory Begin mime=%s, plugin=%s\n",
04611     aMimeType, pluginTag->mFileName));
04612 
04613 #ifdef NS_DEBUG
04614     if(aMimeType && pluginTag->mFileName)
04615       printf("For %s found plugin %s\n", aMimeType, pluginTag->mFileName);
04616 #endif
04617 
04618     if (nsnull == pluginTag->mLibrary)  // if we haven't done this yet
04619     {
04620 
04621      nsCOMPtr<nsILocalFile> file = do_CreateInstance("@mozilla.org/file/local;1");
04622 #if !defined(XP_MACOSX)
04623       file->InitWithNativePath(nsDependentCString(pluginTag->mFileName));
04624 #else
04625       if (nsnull == pluginTag->mFullPath)
04626         return NS_ERROR_FAILURE;
04627       file->InitWithNativePath(nsDependentCString(pluginTag->mFullPath));
04628 #endif
04629       nsPluginFile pluginFile(file);
04630       PRLibrary* pluginLibrary = NULL;
04631 
04632       if (pluginFile.LoadPlugin(pluginLibrary) != NS_OK || pluginLibrary == NULL)
04633         return NS_ERROR_FAILURE;
04634 
04635       // remove from unused lib list, if it is there
04636       if (mUnusedLibraries.IndexOf(pluginLibrary) > -1)
04637         mUnusedLibraries.RemoveElement(pluginLibrary);
04638 
04639       pluginTag->mLibrary = pluginLibrary;
04640     }
04641 
04642     nsIPlugin* plugin = pluginTag->mEntryPoint;
04643     if(plugin == NULL)
04644     {
04645       // nsIPlugin* of xpcom plugins can be found thru a call to
04646       // nsIComponentManager::GetClassObjectByContractID()
04647       nsCAutoString contractID(
04648               NS_LITERAL_CSTRING(NS_INLINE_PLUGIN_CONTRACTID_PREFIX) +
04649               nsDependentCString(aMimeType));
04650       nsresult rv = CallGetClassObject(contractID.get(), &plugin);
04651       if (NS_SUCCEEDED(rv) && plugin)
04652       {
04653         // plugin is already addref'd
04654         pluginTag->mEntryPoint = plugin;
04655         plugin->Initialize();
04656       }
04657     }
04658 
04659     if (plugin == NULL)
04660     {
04661       // No, this is not a leak. GetGlobalServiceManager() doesn't
04662       // addref the pointer on the way out. It probably should.
04663       nsIServiceManagerObsolete* serviceManager;
04664       nsServiceManager::GetGlobalServiceManager((nsIServiceManager**)&serviceManager);
04665 
04666       // need to get the plugin factory from this plugin.
04667       nsFactoryProc nsGetFactory = nsnull;
04668 #ifdef XP_OS2
04669       nsGetFactory = (nsFactoryProc) PR_FindSymbol(pluginTag->mLibrary, "_NSGetFactory");
04670 #else
04671       nsGetFactory = (nsFactoryProc) PR_FindSymbol(pluginTag->mLibrary, "NSGetFactory");
04672 #endif
04673       if(nsGetFactory != nsnull && IsCompatibleExecutable(pluginTag->mFullPath))
04674       {
04675 // XPCOM-style plugins (or at least the OJI one) cause crashes on
04676 // on windows GCC builds, so we're just turning them off for now.
04677 #if !defined(XP_WIN) || !defined(__GNUC__)
04678         rv = nsGetFactory(serviceManager, kPluginCID, nsnull, nsnull,    // XXX fix ClassName/ContractID
04679                           (nsIFactory**)&pluginTag->mEntryPoint);
04680         plugin = pluginTag->mEntryPoint;
04681         if (plugin != NULL)
04682           plugin->Initialize();
04683 #endif
04684       }
04685 #ifdef XP_OS2
04686       // on OS2, first check if this might be legacy XPCOM module.
04687       else if (PR_FindSymbol(pluginTag->mLibrary, "NSGetFactory") &&
04688                IsCompatibleExecutable(pluginTag->mFullPath))
04689       {
04690         // Possibly a legacy XPCOM module. We'll need to create a calling
04691         // vtable/calling convention wrapper for it.
04692         nsCOMPtr<nsILegacyPluginWrapperOS2> wrapper =
04693                        do_GetService(NS_LEGACY_PLUGIN_WRAPPER_CONTRACTID, &rv);
04694         if (NS_SUCCEEDED(rv))
04695         {
04696           rv = wrapper->GetFactory(serviceManager, kPluginCID, nsnull, nsnull,
04697                                    pluginTag->mLibrary, &pluginTag->mEntryPoint);
04698           plugin = pluginTag->mEntryPoint;
04699           if (plugin != NULL)
04700             plugin->Initialize();
04701         }
04702       }
04703 #endif
04704       else
04705       {
04706        // Now lets try to get the entry point from a 4.x plugin
04707        rv = NS_ERROR_FAILURE;
04708        if (NS_FAILED(rv))
04709          rv = ns4xPlugin::CreatePlugin(serviceManager,
04710                                        pluginTag->mFileName,
04711                                        pluginTag->mFullPath,
04712                                        pluginTag->mLibrary,
04713                                        &pluginTag->mEntryPoint);
04714 
04715         plugin = pluginTag->mEntryPoint;
04716         pluginTag->mFlags |= NS_PLUGIN_FLAG_OLDSCHOOL;
04717         // no need to initialize, already done by CreatePlugin()
04718       }
04719     }
04720 
04721 #if defined (XP_MACOSX)
04722    /* Flash 6.0 r50 and older on Mac has a bug which calls ::UseInputWindow(NULL, true)
04723       which turn off all our inline IME. Turn it back after the plugin
04724       initializtion and hope that future versions will be fixed. See bug 159016
04725    */
04726     if (pluginTag->mDescription &&
04727        !PL_strncasecmp(pluginTag->mDescription, "Shockwave Flash 6.0", 19)) {
04728        int ver = atoi(pluginTag->mDescription + 21);
04729        if  (ver && ver <= 50) {
04730          ::UseInputWindow(NULL, false);
04731        }
04732     }
04733 #endif
04734 
04735     if (plugin != nsnull)
04736     {
04737       *aPlugin = plugin;
04738       plugin->AddRef();
04739       return NS_OK;
04740     }
04741   }
04742 
04743   PLUGIN_LOG(PLUGIN_LOG_NORMAL,
04744   ("nsPluginHostImpl::GetPluginFactory End mime=%s, rv=%d, plugin=%p name=%s\n",
04745   aMimeType, rv, *aPlugin, (pluginTag ? pluginTag->mFileName : "(not found)")));
04746 
04747   return rv;
04748 }
04749 
04750 
04752 // XXX called from ScanPluginsDirectory only when told to filter
04753 // currently 'unwanted' plugins are Java, and all other plugins except
04754 // Acrobat, Flash, Quicktime and Shockwave
04755 static PRBool isUnwantedPlugin(nsPluginTag * tag)
04756 {
04757   if(tag->mFileName == nsnull)
04758     return PR_TRUE;
04759 
04760   for (PRInt32 i = 0; i < tag->mVariants; ++i) {
04761     if(nsnull == PL_strcasecmp(tag->mMimeTypeArray[i], "application/pdf"))
04762       return PR_FALSE;
04763 
04764     if(nsnull == PL_strcasecmp(tag->mMimeTypeArray[i], "application/x-shockwave-flash"))
04765       return PR_FALSE;
04766 
04767     if(nsnull == PL_strcasecmp(tag->mMimeTypeArray[i],"application/x-director"))
04768       return PR_FALSE;
04769   }
04770 
04771   // On Windows, we also want to include the Quicktime plugin from the 4.x directory
04772   // But because it spans several DLL's, the best check for now is by filename
04773   if (nsnull != PL_strcasestr(tag->mFileName,"npqtplugin"))
04774     return PR_FALSE;
04775 
04776   return PR_TRUE;
04777 }
04778 
04780 // XXX quick helper function to check for java plugin
04781 static PRBool isUnwantedJavaPlugin(nsPluginTag * tag) {
04782 #ifndef OJI
04783   for (PRInt32 i = 0; i < tag->mVariants; ++i) {
04784     if ((0 == PL_strncasecmp(tag->mMimeTypeArray[i], "application/x-java-vm", 21)) ||
04785         (0 == PL_strncasecmp(tag->mMimeTypeArray[i], "application/x-java-applet", 25)) ||
04786         (0 == PL_strncasecmp(tag->mMimeTypeArray[i], "application/x-java-bean", 23)))
04787       return PR_TRUE;
04788   }
04789 #endif /* OJI */
04790   return PR_FALSE;
04791 }
04792 
04793 nsPluginTag * nsPluginHostImpl::HaveSamePlugin(nsPluginTag * aPluginTag)
04794 {
04795   for(nsPluginTag* tag = mPlugins; tag; tag = tag->mNext) {
04796     if(tag->Equals(aPluginTag))
04797       return tag;
04798   }
04799   return nsnull;
04800 }
04801 
04802 PRBool nsPluginHostImpl::IsDuplicatePlugin(nsPluginTag * aPluginTag)
04803 {
04804   nsPluginTag * tag = HaveSamePlugin(aPluginTag);
04805   if (tag) {
04806     // if we got the same plugin, check the full path to see if this is a dup;
04807 
04808     // mFileName contains full path on Windows and Unix and leaf name on Mac
04809     // if those are not equal, we have the same plugin with  different path,
04810     // i.e. duplicate, return true
04811     if (PL_strcmp(tag->mFileName, aPluginTag->mFileName))
04812       return PR_TRUE;
04813 
04814     // if they are equal, compare mFullPath fields just in case
04815     // mFileName contained leaf name only, and if not equal, return true
04816     if (tag->mFullPath && aPluginTag->mFullPath && PL_strcmp(tag->mFullPath, aPluginTag->mFullPath))
04817       return PR_TRUE;
04818   }
04819 
04820   // we do not have it at all, return false
04821   return PR_FALSE;
04822 }
04823 
04824 // Structure for collecting plugin files found during directory scanning
04825 struct pluginFileinDirectory
04826 {
04827   nsString mFilename;
04828   PRInt64  mModTime;
04829 
04830   pluginFileinDirectory()
04831   {
04832     mModTime = LL_ZERO;
04833   }
04834 };
04835 
04836 // QuickSort callback for comparing the modification time of two files
04837 // if the times are the same, compare the filenames
04838 static int PR_CALLBACK ComparePluginFileInDirectory (const void *v1, const void *v2, void *)
04839 {
04840   const pluginFileinDirectory* pfd1 = NS_STATIC_CAST(const pluginFileinDirectory*, v1);
04841   const pluginFileinDirectory* pfd2 = NS_STATIC_CAST(const pluginFileinDirectory*, v2);
04842 
04843   PRInt32 result = 0;
04844   if (LL_EQ(pfd1->mModTime, pfd2->mModTime))
04845     result = Compare(pfd1->mFilename, pfd2->mFilename, nsCaseInsensitiveStringComparator());
04846   else if (LL_CMP(pfd1->mModTime, >, pfd2->mModTime))
04847     result = -1;
04848   else
04849     result = 1;
04850 
04851   return result;
04852 }
04853 
04854 typedef NS_4XPLUGIN_CALLBACK(char *, NP_GETMIMEDESCRIPTION)(void);
04855 
04856 static nsresult FixUpPluginInfo(nsPluginInfo &aInfo, nsPluginFile &aPluginFile)
04857 {
04858 #ifndef XP_WIN
04859   return NS_OK;
04860 #endif
04861 
04862   for (PRUint32 i = 0; i < aInfo.fVariantCount; i++) {
04863     if (PL_strcmp(aInfo.fMimeTypeArray[i], "*"))
04864       continue;
04865 
04866     // we got "*" type
04867     // check if this is an alien plugin (not our default plugin)
04868     // by trying to find a special entry point
04869     PRLibrary *library = nsnull;
04870     if (NS_FAILED(aPluginFile.LoadPlugin(library)) || !library)
04871       return NS_ERROR_FAILURE;
04872 
04873     NP_GETMIMEDESCRIPTION pf = (NP_GETMIMEDESCRIPTION)PR_FindSymbol(library, "NP_GetMIMEDescription");
04874 
04875     if (pf) {
04876       // if we found it, this is the default plugin, return
04877       char * mimedescription = pf();
04878       if (!PL_strncmp(mimedescription, NS_PLUGIN_DEFAULT_MIME_DESCRIPTION, 1))
04879         return NS_OK;
04880     }
04881 
04882     // if we are here that means we have an alien plugin
04883     // which wants to take over "*" type
04884 
04885     // change its "*" mime type to "[*]"
04886     PL_strfree(aInfo.fMimeTypeArray[i]);
04887     aInfo.fMimeTypeArray[i] = PL_strdup("[*]");
04888 
04889     // continue the loop?
04890   }
04891   return NS_OK;
04892 }
04893 
04895 nsresult nsPluginHostImpl::ScanPluginsDirectory(nsIFile * pluginsDir,
04896                                                 nsIComponentManager * compManager,
04897                                                 PRBool aCreatePluginList,
04898                                                 PRBool * aPluginsChanged,
04899                                                 PRBool checkForUnwantedPlugins)
04900 {
04901   NS_ENSURE_ARG_POINTER(aPluginsChanged);
04902   nsresult rv;
04903 
04904   *aPluginsChanged = PR_FALSE;
04905 
04906 #ifdef PLUGIN_LOGGING
04907   nsCAutoString dirPath;
04908   pluginsDir->GetNativePath(dirPath);
04909   PLUGIN_LOG(PLUGIN_LOG_BASIC,
04910   ("nsPluginHostImpl::ScanPluginsDirectory dir=%s\n", dirPath.get()));
04911 #endif
04912 
04913   nsCOMPtr<nsISimpleEnumerator> iter;
04914   rv = pluginsDir->GetDirectoryEntries(getter_AddRefs(iter));
04915   if (NS_FAILED(rv))
04916     return rv;
04917 
04918   // Collect all the files in this directory in a void array we can sort later
04919   nsAutoVoidArray pluginFilesArray;  // array for sorting files in this directory
04920   PRBool hasMore;
04921   while (NS_SUCCEEDED(iter->HasMoreElements(&hasMore)) && hasMore) {
04922     nsCOMPtr<nsISupports> supports;
04923     rv = iter->GetNext(getter_AddRefs(supports));
04924     if (NS_FAILED(rv))
04925       continue;
04926     nsCOMPtr<nsILocalFile> dirEntry(do_QueryInterface(supports, &rv));
04927     if (NS_FAILED(rv))
04928       continue;
04929 
04930     // Sun's JRE 1.3.1 plugin must have symbolic links resolved or else it'll crash.
04931     // See bug 197855.
04932     dirEntry->Normalize();
04933 
04934     nsAutoString filePath;
04935     rv = dirEntry->GetPath(filePath);
04936     if (NS_FAILED(rv))
04937       continue;
04938 
04939     if (nsPluginsDir::IsPluginFile(dirEntry)) {
04940       pluginFileinDirectory * item = new pluginFileinDirectory();
04941       if (!item)
04942         return NS_ERROR_OUT_OF_MEMORY;
04943       
04944       // Get file mod time
04945       PRInt64 fileModTime = LL_ZERO;
04946       dirEntry->GetLastModifiedTime(&fileModTime);
04947       
04948       item->mModTime = fileModTime;
04949       item->mFilename = filePath;
04950       pluginFilesArray.AppendElement(item);
04951     }
04952   } // end round of up of plugin files
04953 
04954   // now sort the array by file modification time or by filename, if equal
04955   // put newer plugins first to weed out dups and catch upgrades, see bug 119966
04956   pluginFilesArray.Sort(ComparePluginFileInDirectory, nsnull);
04957 
04958   // finally, go through the array, looking at each entry and continue processing it
04959   for (PRInt32 i = 0; i < pluginFilesArray.Count(); i++) {
04960     pluginFileinDirectory* pfd = NS_STATIC_CAST(pluginFileinDirectory*, pluginFilesArray[i]);
04961     nsCOMPtr <nsIFile> file = do_CreateInstance("@mozilla.org/file/local;1");
04962     nsCOMPtr <nsILocalFile> localfile = do_QueryInterface(file);
04963     localfile->InitWithPath(pfd->mFilename);
04964     PRInt64 fileModTime = pfd->mModTime;
04965 
04966     // Look for it in our cache
04967     nsPluginTag *pluginTag = RemoveCachedPluginsInfo(NS_ConvertUCS2toUTF8(pfd->mFilename).get());
04968 
04969     delete pfd;
04970     if (pluginTag) {
04971       // If plugin changed, delete cachedPluginTag and dont use cache
04972       if (LL_NE(fileModTime, pluginTag->mLastModifiedTime)) {
04973         // Plugins has changed. Dont use cached plugin info.
04974         delete pluginTag;
04975         pluginTag = nsnull;
04976 
04977         // plugin file changed, flag this fact
04978         *aPluginsChanged = PR_TRUE;
04979       }
04980       else {
04981         // if it is unwanted plugin we are checking for, get it back to the cache info list
04982         // if this is a duplicate plugin, too place it back in the cache info list marking unwantedness
04983         if((checkForUnwantedPlugins && isUnwantedPlugin(pluginTag)) || IsDuplicatePlugin(pluginTag) || isUnwantedJavaPlugin(pluginTag)) {
04984           pluginTag->Mark(NS_PLUGIN_FLAG_UNWANTED);
04985           pluginTag->mNext = mCachedPlugins;
04986           mCachedPlugins = pluginTag;
04987         }
04988       }
04989     }
04990     else {
04991       // plugin file was added, flag this fact
04992       *aPluginsChanged = PR_TRUE;
04993     }
04994 
04995     // if we are not creating the list, just continue the loop
04996     // no need to proceed if changes are detected
04997     if (!aCreatePluginList) {
04998       if (*aPluginsChanged)
04999         return NS_OK;
05000       else
05001         continue;
05002     }
05003 
05004     // if it is not found in cache info list or has been changed, create a new one
05005     if (!pluginTag) {
05006       nsPluginFile pluginFile(file);
05007       PRLibrary* pluginLibrary = nsnull;
05008 
05009       // load the plugin's library so we can ask it some questions, but not for Windows
05010 #ifndef XP_WIN
05011       if (pluginFile.LoadPlugin(pluginLibrary) != NS_OK || pluginLibrary == nsnull)
05012         continue;
05013 #endif
05014 
05015       // create a tag describing this plugin.
05016       nsPluginInfo info = { sizeof(info) };
05017       nsresult res = pluginFile.GetPluginInfo(info);
05018       if(NS_FAILED(res))
05019         continue;
05020 
05021       // if we don't have mime type -- don't proceed, this is not a plugin
05022       if(!info.fMimeTypeArray) {
05023         pluginFile.FreePluginInfo(info);
05024         continue;
05025       }
05026 
05027       // Check for any potential '*' mime type handlers which are not our
05028       // own default plugin and disable them as they will break the plugin
05029       // finder service, see Bugzilla bug 132430
05030       if (!mAllowAlienStarHandler)
05031         FixUpPluginInfo(info, pluginFile);
05032 
05033       pluginTag = new nsPluginTag(&info);
05034       pluginFile.FreePluginInfo(info);
05035 
05036       if(pluginTag == nsnull)
05037         return NS_ERROR_OUT_OF_MEMORY;
05038 
05039       pluginTag->mLibrary = pluginLibrary;
05040       pluginTag->mLastModifiedTime = fileModTime;
05041 
05042       // if this is unwanted plugin we are checkin for, or this is a duplicate plugin,
05043       // add it to our cache info list so we can cache the unwantedness of this plugin
05044       // when we sync cached plugins to registry
05045       if((checkForUnwantedPlugins && isUnwantedPlugin(pluginTag)) || IsDuplicatePlugin(pluginTag) || isUnwantedJavaPlugin(pluginTag)) {
05046         pluginTag->Mark(NS_PLUGIN_FLAG_UNWANTED);
05047         pluginTag->mNext = mCachedPlugins;
05048         mCachedPlugins = pluginTag;
05049       }
05050     }
05051 
05052     // set the flag that we want to add this plugin to the list for now
05053     // and see if it remains after we check several reasons not to do so
05054     PRBool bAddIt = PR_TRUE;
05055 
05056     // check if this is a specific plugin we don't want
05057     if((checkForUnwantedPlugins && isUnwantedPlugin(pluginTag)) ||
05058        isUnwantedJavaPlugin(pluginTag))
05059       bAddIt = PR_FALSE;
05060 
05061     // check if we already have this plugin in the list which
05062     // is possible if we do refresh
05063     if(bAddIt) {
05064       if (HaveSamePlugin(pluginTag)) {
05065         // we cannot get here if the plugin has just been added
05066         // and thus |pluginTag| is not from cache, because otherwise
05067         // it would not be present in the list;
05068         // so there is no need to delete |pluginTag| -- it _is_ from the cache info list.
05069         bAddIt = PR_FALSE;
05070       }
05071     }
05072 
05073     // so if we still want it -- do it
05074     if(bAddIt) {
05075       pluginTag->SetHost(this);
05076       pluginTag->mNext = mPlugins;
05077       mPlugins = pluginTag;
05078 
05079       pluginTag->RegisterWithCategoryManager(mOverrideInternalTypes);
05080     }
05081     else if (!(pluginTag->mFlags & NS_PLUGIN_FLAG_UNWANTED)) {
05082       // we don't need it, delete it;
05083       // but don't delete unwanted plugins since they are cached
05084       // in the cache info list and will be deleted later
05085       delete pluginTag;
05086     }
05087   }
05088   return NS_OK;
05089 }
05090 
05091 nsresult nsPluginHostImpl::ScanPluginsDirectoryList(nsISimpleEnumerator * dirEnum,
05092                                                     nsIComponentManager * compManager,
05093                                                     PRBool aCreatePluginList,
05094                                                     PRBool * aPluginsChanged,
05095                                                     PRBool checkForUnwantedPlugins)
05096 {
05097     PRBool hasMore;
05098     while (NS_SUCCEEDED(dirEnum->HasMoreElements(&hasMore)) && hasMore) {
05099       nsCOMPtr<nsISupports> supports;
05100       nsresult rv = dirEnum->GetNext(getter_AddRefs(supports));
05101       if (NS_FAILED(rv))
05102         continue;
05103       nsCOMPtr<nsIFile> nextDir(do_QueryInterface(supports, &rv));
05104       if (NS_FAILED(rv))
05105         continue;
05106 
05107       // don't pass aPluginsChanged directly to prevent it from been reset
05108       PRBool pluginschanged = PR_FALSE;
05109       ScanPluginsDirectory(nextDir, compManager, aCreatePluginList, &pluginschanged, checkForUnwantedPlugins);
05110 
05111       if (pluginschanged)
05112         *aPluginsChanged = PR_TRUE;
05113 
05114       // if changes are detected and we are not creating the list, do not proceed
05115       if (!aCreatePluginList && *aPluginsChanged)
05116         break;
05117     }
05118     return NS_OK;
05119 }
05120 
05121 NS_IMETHODIMP nsPluginHostImpl::LoadPlugins()
05122 {
05123   // do not do anything if it is already done
05124   // use ReloadPlugins() to enforce loading
05125   if(mPluginsLoaded)
05126     return NS_OK;
05127 
05128   PRBool pluginschanged;
05129   nsresult rv = FindPlugins(PR_TRUE, &pluginschanged);
05130   if (NS_FAILED(rv))
05131     return rv;
05132 
05133   // only if plugins have changed will we ask XPTI to refresh
05134   if (pluginschanged) {
05135     // rescan XPTI to catch any newly installed interfaces
05136     nsCOMPtr<nsIInterfaceInfoManager> iim (dont_AddRef(XPTI_GetInterfaceInfoManager()));
05137     if (iim)
05138       iim->AutoRegisterInterfaces();
05139   }
05140 
05141   return NS_OK;
05142 }
05143 
05144 #include "nsITimelineService.h"
05145 
05146 // if aCreatePluginList is false we will just scan for plugins
05147 // and see if any changes have been made to the plugins.
05148 // This is needed in ReloadPlugins to prevent possible recursive reloads
05149 nsresult nsPluginHostImpl::FindPlugins(PRBool aCreatePluginList, PRBool * aPluginsChanged)
05150 {
05151   // let's start timing if we are only really creating the plugin list
05152   if (aCreatePluginList) {
05153     NS_TIMELINE_START_TIMER("LoadPlugins");
05154   }
05155 
05156 #ifdef CALL_SAFETY_ON
05157   // check preferences on whether or not we want to try safe calls to plugins
05158   NS_INIT_PLUGIN_SAFE_CALLS;
05159 #endif
05160 
05161   NS_ENSURE_ARG_POINTER(aPluginsChanged);
05162 
05163   *aPluginsChanged = PR_FALSE;
05164   nsresult rv;
05165 
05166   // Read cached plugins info
05167   ReadPluginInfo();
05168 
05169   nsCOMPtr<nsIComponentManager> compManager;
05170   NS_GetComponentManager(getter_AddRefs(compManager));
05171   if (compManager)
05172     LoadXPCOMPlugins(compManager);
05173 
05174   // Failure here is not a show-stopper so just warn.
05175   rv = EnsurePrivateDirServiceProvider();
05176   NS_WARN_IF_FALSE(NS_SUCCEEDED(rv), "Failed to register dir service provider.");
05177 
05178   nsCOMPtr<nsIProperties> dirService(do_GetService(kDirectoryServiceContractID, &rv));
05179   if (NS_FAILED(rv))
05180     return rv;
05181 
05182   nsCOMPtr<nsISimpleEnumerator> dirList;
05183 
05184   // Scan plugins directories;
05185   // don't pass aPluginsChanged directly, to prevent its
05186   // possible reset in subsequent ScanPluginsDirectory calls
05187   PRBool pluginschanged = PR_FALSE;
05188 
05189   // Scan the app-defined list of plugin dirs.
05190   rv = dirService->Get(NS_APP_PLUGINS_DIR_LIST, NS_GET_IID(nsISimpleEnumerator), getter_AddRefs(dirList));
05191   if (NS_SUCCEEDED(rv)) {
05192     ScanPluginsDirectoryList(dirList, compManager, aCreatePluginList, &pluginschanged);
05193 
05194     if (pluginschanged)
05195       *aPluginsChanged = PR_TRUE;
05196 
05197     // if we are just looking for possible changes,
05198     // no need to proceed if changes are detected
05199     if (!aCreatePluginList && *aPluginsChanged) {
05200       ClearCachedPluginInfoList();
05201       return NS_OK;
05202     }
05203   }
05204 
05205   mPluginsLoaded = PR_TRUE; // at this point 'some' plugins have been loaded,
05206                             // the rest is optional
05207 
05208 #if defined (XP_WIN)
05209 
05210   PRBool bScanPLIDs = PR_FALSE;
05211 
05212   if (mPrefService)
05213     mPrefService->GetBoolPref("plugin.scan.plid.all", &bScanPLIDs);
05214 
05215     // Now lets scan any PLID directories
05216   if (bScanPLIDs && mPrivateDirServiceProvider) {
05217     rv = mPrivateDirServiceProvider->GetPLIDDirectories(getter_AddRefs(dirList));
05218     if (NS_SUCCEEDED(rv)) {
05219       ScanPluginsDirectoryList(dirList, compManager, aCreatePluginList, &pluginschanged);
05220 
05221       if (pluginschanged)
05222         *aPluginsChanged = PR_TRUE;
05223 
05224       // if we are just looking for possible changes,
05225       // no need to proceed if changes are detected
05226       if (!aCreatePluginList && *aPluginsChanged) {
05227         ClearCachedPluginInfoList();
05228         return NS_OK;
05229       }
05230     }
05231   }
05232 
05233 
05234   // Scan the installation paths of our popular plugins if the prefs are enabled
05235 
05236   // This table controls the order of scanning
05237   const char* const prefs[] = {NS_WIN_JRE_SCAN_KEY,         nsnull,
05238                                NS_WIN_ACROBAT_SCAN_KEY,     nsnull,
05239                                NS_WIN_QUICKTIME_SCAN_KEY,   nsnull,
05240                                NS_WIN_WMP_SCAN_KEY,         nsnull,
05241                                NS_WIN_4DOTX_SCAN_KEY,       "1"  /*  second column is flag for 4.x folder */ };
05242 
05243   PRUint32 size = sizeof(prefs) / sizeof(prefs[0]);
05244 
05245   for (PRUint32 i = 0; i < size; i+=2) {
05246     nsCOMPtr<nsIFile> dirToScan;
05247     PRBool bExists;
05248     if (NS_SUCCEEDED(dirService->Get(prefs[i], NS_GET_IID(nsIFile), getter_AddRefs(dirToScan))) &&
05249         dirToScan &&
05250         NS_SUCCEEDED(dirToScan->Exists(&bExists)) &&
05251         bExists) {
05252 
05253       PRBool bFilterUnwanted = PR_FALSE;
05254 
05255       // 4.x plugins folder stuff:
05256       // Normally we "filter" the 4.x folder through |IsUnwantedPlugin|
05257       // Check for a pref to see if we want to scan the entire 4.x plugins folder
05258       if (prefs[i+1]) {
05259         PRBool bScanEverything;
05260         bFilterUnwanted = PR_TRUE;  // default to filter 4.x folder
05261         if (mPrefService &&
05262             NS_SUCCEEDED(mPrefService->GetBoolPref(prefs[i], &bScanEverything)) &&
05263             bScanEverything)
05264           bFilterUnwanted = PR_FALSE;
05265 
05266       }
05267       ScanPluginsDirectory(dirToScan, compManager, aCreatePluginList, &pluginschanged, bFilterUnwanted);
05268 
05269       if (pluginschanged)
05270         *aPluginsChanged = PR_TRUE;
05271 
05272       // if we are just looking for possible changes,
05273       // no need to proceed if changes are detected
05274       if (!aCreatePluginList && *aPluginsChanged) {
05275         ClearCachedPluginInfoList();
05276         return NS_OK;
05277       }
05278     }
05279   }
05280 
05281 #endif
05282 
05283   // if get to this point and did not detect changes in plugins
05284   // that means no plugins got updated or added
05285   // let's see if plugins have been removed
05286   if (!*aPluginsChanged) {
05287     // count plugins remained in cache, if there are some, that means some plugins were removed;
05288     // while counting, we should ignore unwanted plugins which are also present in cache
05289     PRUint32 cachecount = 0;
05290     for (nsPluginTag * cachetag = mCachedPlugins; cachetag; cachetag = cachetag->mNext) {
05291       if (!(cachetag->mFlags & NS_PLUGIN_FLAG_UNWANTED))
05292         cachecount++;
05293     }
05294     // if there is something left in cache, some plugins got removed from the directory
05295     // and therefor their info did not get removed from the cache info list during directory scan;
05296     // flag this fact
05297     if (cachecount > 0)
05298       *aPluginsChanged = PR_TRUE;
05299   }
05300 
05301   // if we are not creating the list, there is no need to proceed
05302   if (!aCreatePluginList) {
05303     ClearCachedPluginInfoList();
05304     return NS_OK;
05305   }
05306 
05307   // if we are creating the list, it is already done;
05308   // update the plugins info cache if changes are detected
05309   if (*aPluginsChanged)
05310     WritePluginInfo();
05311 
05312   // No more need for cached plugins. Clear it up.
05313   ClearCachedPluginInfoList();
05314 
05315   /*
05316    * XXX Big time hack alert!!!!
05317    *     Because Real Player 8 installs in the components folder, we must have this one off
05318    *     scan for nppl3260.dll because XPCOM has shut off nsGetFactory type plugins.
05319    *     When we stop supporting Real 8 or they fix their installer, this can go away.
05320    */
05321   if (aCreatePluginList)
05322     ScanForRealInComponentsFolder(compManager);
05323 
05324   // reverse our list of plugins
05325   nsPluginTag *next,*prev = nsnull;
05326   for (nsPluginTag *cur = mPlugins; cur; cur = next) {
05327     next = cur->mNext;
05328     cur->mNext = prev;
05329     prev = cur;
05330   }
05331 
05332   mPlugins = prev;
05333 
05334   NS_TIMELINE_STOP_TIMER("LoadPlugins");
05335   NS_TIMELINE_MARK_TIMER("LoadPlugins");
05336 
05337   return NS_OK;
05338 }
05339 
05340 void nsPluginHostImpl::ClearCachedPluginInfoList()
05341 {
05342   while (mCachedPlugins) {
05343     nsPluginTag *next = mCachedPlugins->mNext;
05344     delete mCachedPlugins;
05345     mCachedPlugins = next;
05346   }
05347 }
05348 
05350 nsresult
05351 nsPluginHostImpl::LoadXPCOMPlugins(nsIComponentManager* aComponentManager)
05352 {
05353   // the component reg is a flat file now see 48888
05354   // we have to reimplement this method if we need it
05355 
05356   // The "new style" XPCOM plugins have their information stored in
05357   // the component registry, under the key
05358   //
05359   //   nsIRegistry::Common/software/plugins
05360   //
05361   // Enumerate through that list now, creating an nsPluginTag for
05362   // each.
05363 
05364   return NS_OK;
05365 }
05366 
05367 nsresult
05368 nsPluginHostImpl::WritePluginInfo()
05369 {
05370 
05371   nsresult rv = NS_OK;
05372   nsCOMPtr<nsIProperties> directoryService(do_GetService(NS_DIRECTORY_SERVICE_CONTRACTID,&rv));
05373   if (NS_FAILED(rv))
05374     return rv;
05375 
05376   directoryService->Get(NS_APP_APPLICATION_REGISTRY_DIR, NS_GET_IID(nsIFile),
05377                         getter_AddRefs(mPluginRegFile));
05378 
05379   if (!mPluginRegFile)
05380     return NS_ERROR_FAILURE;
05381 
05382   PRFileDesc* fd = nsnull;
05383 
05384   nsCOMPtr<nsIFile> pluginReg;
05385 
05386   rv = mPluginRegFile->Clone(getter_AddRefs(pluginReg));
05387   if (NS_FAILED(rv))
05388     return rv;
05389 
05390   rv = pluginReg->AppendNative(kPluginRegistryFilename);
05391   if (NS_FAILED(rv))
05392     return rv;
05393 
05394   nsCOMPtr<nsILocalFile> localFile = do_QueryInterface(pluginReg, &rv);
05395   if (NS_FAILED(rv))
05396     return rv;
05397 
05398   rv = localFile->OpenNSPRFileDesc(PR_WRONLY | PR_CREATE_FILE | PR_TRUNCATE, 0600, &fd);
05399   if (NS_FAILED(rv))
05400     return rv;
05401 
05402   PR_fprintf(fd, "Generated File. Do not edit.\n");
05403 
05404   PR_fprintf(fd, "\n[HEADER]\nVersion%c%s%c%c\n",
05405              PLUGIN_REGISTRY_FIELD_DELIMITER,
05406              kPluginRegistryVersion,
05407              PLUGIN_REGISTRY_FIELD_DELIMITER,
05408              PLUGIN_REGISTRY_END_OF_LINE_MARKER);
05409 
05410   // Store all plugins in the mPlugins list - all plugins currently in use.
05411   PR_fprintf(fd, "\n[PLUGINS]\n");
05412 
05413   nsPluginTag *taglist[] = {mPlugins, mCachedPlugins};
05414   for (int i=0; i<(int)(sizeof(taglist)/sizeof(nsPluginTag *)); i++) {
05415     for (nsPluginTag *tag = taglist[i]; tag; tag=tag->mNext) {
05416       // from mCachedPlugins list write down only unwanted plugins
05417       if ((taglist[i] == mCachedPlugins) && !(tag->mFlags & NS_PLUGIN_FLAG_UNWANTED))
05418         continue;
05419       // store each plugin info into the registry
05420       // filename & fullpath are on separate line
05421       // because they can contain field delimiter char
05422       PR_fprintf(fd, "%s%c%c\n%s%c%c\n",
05423         (tag->mFileName ? tag->mFileName : ""),
05424         PLUGIN_REGISTRY_FIELD_DELIMITER,
05425         PLUGIN_REGISTRY_END_OF_LINE_MARKER,
05426         (tag->mFullPath ? tag->mFullPath : ""),
05427         PLUGIN_REGISTRY_FIELD_DELIMITER,
05428         PLUGIN_REGISTRY_END_OF_LINE_MARKER);
05429 
05430       // lastModifiedTimeStamp|canUnload|tag->mFlags
05431       PR_fprintf(fd, "%lld%c%d%c%lu%c%c\n",
05432         tag->mLastModifiedTime,
05433         PLUGIN_REGISTRY_FIELD_DELIMITER,
05434         tag->mCanUnloadLibrary,
05435         PLUGIN_REGISTRY_FIELD_DELIMITER,
05436         tag->mFlags,
05437         PLUGIN_REGISTRY_FIELD_DELIMITER,
05438         PLUGIN_REGISTRY_END_OF_LINE_MARKER);
05439 
05440       //description, name & mtypecount are on separate line
05441       PR_fprintf(fd, "%s%c%c\n%s%c%c\n%d\n",
05442         (tag->mDescription ? tag->mDescription : ""),
05443         PLUGIN_REGISTRY_FIELD_DELIMITER,
05444         PLUGIN_REGISTRY_END_OF_LINE_MARKER,
05445         (tag->mName ? tag->mName : ""),
05446         PLUGIN_REGISTRY_FIELD_DELIMITER,
05447         PLUGIN_REGISTRY_END_OF_LINE_MARKER,
05448         tag->mVariants);
05449 
05450       // Add in each mimetype this plugin supports
05451       for (int i=0; i<tag->mVariants; i++) {
05452         PR_fprintf(fd, "%d%c%s%c%s%c%s%c%c\n",
05453           i,PLUGIN_REGISTRY_FIELD_DELIMITER,
05454           (tag->mMimeTypeArray && tag->mMimeTypeArray[i] ? tag->mMimeTypeArray[i] : ""),
05455           PLUGIN_REGISTRY_FIELD_DELIMITER,
05456           (tag->mMimeDescriptionArray && tag->mMimeDescriptionArray[i] ? tag->mMimeDescriptionArray[i] : ""),
05457           PLUGIN_REGISTRY_FIELD_DELIMITER,
05458           (tag->mExtensionsArray && tag->mExtensionsArray[i] ? tag->mExtensionsArray[i] : ""),
05459           PLUGIN_REGISTRY_FIELD_DELIMITER,
05460           PLUGIN_REGISTRY_END_OF_LINE_MARKER);
05461       }
05462     }
05463   }
05464 
05465   if (fd)
05466     PR_Close(fd);
05467   return NS_OK;
05468 }
05469 
05470 #define PLUGIN_REG_MIMETYPES_ARRAY_SIZE 12
05471 nsresult
05472 nsPluginHostImpl::ReadPluginInfo()
05473 {
05474   nsresult rv;
05475 
05476   nsCOMPtr<nsIProperties> directoryService(do_GetService(NS_DIRECTORY_SERVICE_CONTRACTID,&rv));
05477   if (NS_FAILED(rv))
05478     return rv;
05479 
05480   directoryService->Get(NS_APP_APPLICATION_REGISTRY_DIR, NS_GET_IID(nsIFile),
05481                         getter_AddRefs(mPluginRegFile));
05482 
05483   if (!mPluginRegFile)
05484     return NS_ERROR_FAILURE;
05485 
05486   PRFileDesc* fd = nsnull;
05487 
05488   nsCOMPtr<nsIFile> pluginReg;
05489 
05490   rv = mPluginRegFile->Clone(getter_AddRefs(pluginReg));
05491   if (NS_FAILED(rv))
05492     return rv;
05493 
05494   rv = pluginReg->AppendNative(kPluginRegistryFilename);
05495   if (NS_FAILED(rv))
05496     return rv;
05497 
05498   nsCOMPtr<nsILocalFile> localFile = do_QueryInterface(pluginReg, &rv);
05499   if (NS_FAILED(rv))
05500     return rv;
05501 
05502   PRInt64 fileSize;
05503   rv = localFile->GetFileSize(&fileSize);
05504   if (NS_FAILED(rv)) {
05505     return rv;
05506   }
05507 
05508   PRInt32 flen = nsInt64(fileSize);
05509   if (flen == 0) {
05510     NS_WARNING("Plugins Registry Empty!");
05511     return NS_OK; // ERROR CONDITION
05512   }
05513 
05514   nsPluginManifestLineReader reader;
05515   char* registry = reader.Init(flen);
05516   if (!registry) {
05517     return NS_ERROR_OUT_OF_MEMORY;
05518   }
05519 
05520   rv = localFile->OpenNSPRFileDesc(PR_RDONLY, 0444, &fd);
05521   if (NS_FAILED(rv))
05522     return rv;
05523 
05524   // set rv to return an error on goto out
05525   rv = NS_ERROR_FAILURE;
05526 
05527   PRInt32 bread = PR_Read(fd, registry, flen);
05528   PR_Close(fd);
05529 
05530   if (flen > bread)
05531     return rv;
05532 
05533   if (!ReadSectionHeader(reader, "HEADER")) {
05534     return rv;;
05535   }
05536 
05537   if (!reader.NextLine()) {
05538     return rv;
05539   }
05540 
05541   char* values[6];
05542 
05543   // VersionLiteral, kPluginRegistryVersion
05544   if (2 != reader.ParseLine(values, 2)) {
05545     return rv;
05546   }
05547 
05548   // VersionLiteral
05549   if (PL_strcmp(values[0], "Version")) {
05550     return rv;
05551   }
05552 
05553   // kPluginRegistryVersion
05554   if (PL_strcmp(values[1], kPluginRegistryVersion)) {
05555     return rv;
05556   }
05557 
05558   if (!ReadSectionHeader(reader, "PLUGINS")) {
05559     return rv;
05560   }
05561 
05562   while (reader.NextLine()) {
05563     char *filename = reader.LinePtr();
05564     if (!reader.NextLine())
05565       return rv;
05566 
05567     char *fullpath = reader.LinePtr();
05568     if (!reader.NextLine())
05569       return rv;
05570 
05571     // lastModifiedTimeStamp|canUnload|tag.mFlag
05572     if (3 != reader.ParseLine(values, 3))
05573       return rv;
05574 
05575     PRInt64 lastmod = nsCRT::atoll(values[0]);
05576     PRBool canunload = atoi(values[1]);
05577     PRUint32 tagflag = atoi(values[2]);
05578     if (!reader.NextLine())
05579       return rv;
05580 
05581     char *description = reader.LinePtr();
05582     if (!reader.NextLine())
05583       return rv;
05584 
05585     char *name = reader.LinePtr();
05586     if (!reader.NextLine())
05587       return rv;
05588 
05589     int mimetypecount = atoi(reader.LinePtr());
05590 
05591     char *stackalloced[PLUGIN_REG_MIMETYPES_ARRAY_SIZE * 3];
05592     char **mimetypes;
05593     char **mimedescriptions;
05594     char **extensions;
05595     char **heapalloced = 0;
05596     if (mimetypecount > PLUGIN_REG_MIMETYPES_ARRAY_SIZE - 1) {
05597       heapalloced = new char *[mimetypecount * 3];
05598       mimetypes = heapalloced;
05599     } else {
05600       mimetypes = stackalloced;
05601     }
05602     mimedescriptions = mimetypes + mimetypecount;
05603     extensions = mimedescriptions + mimetypecount;
05604 
05605     int mtr = 0; //mimetype read
05606     for (; mtr < mimetypecount; mtr++) {
05607       if (!reader.NextLine())
05608         break;
05609 
05610       //line number|mimetype|description|extension
05611       if (4 != reader.ParseLine(values, 4))
05612         break;
05613       int line = atoi(values[0]);
05614       if (line != mtr)
05615         break;
05616       mimetypes[mtr] = values[1];
05617       mimedescriptions[mtr] = values[2];
05618       extensions[mtr] = values[3];
05619     }
05620 
05621     if (mtr != mimetypecount) {
05622       if (heapalloced) {
05623         delete [] heapalloced;
05624       }
05625       return rv;
05626     }
05627 
05628     nsPluginTag* tag = new nsPluginTag(name,
05629       description,
05630       filename,
05631       (*fullpath ? fullpath : 0), // we have to pass 0 prt if it's empty str
05632       (const char* const*)mimetypes,
05633       (const char* const*)mimedescriptions,
05634       (const char* const*)extensions,
05635       mimetypecount, lastmod, canunload);
05636     if (heapalloced) {
05637       delete [] heapalloced;
05638     }
05639 
05640     if (!tag) {
05641       continue;
05642     }
05643 
05644     // Mark plugin as loaded from cache
05645     tag->Mark(tagflag | NS_PLUGIN_FLAG_FROMCACHE);
05646     PR_LOG(nsPluginLogging::gPluginLog, PLUGIN_LOG_BASIC,
05647       ("LoadCachedPluginsInfo : Loading Cached plugininfo for %s\n", tag->mFileName));
05648     tag->mNext = mCachedPlugins;
05649     mCachedPlugins = tag;
05650 
05651   }
05652   return NS_OK;
05653 }
05654 
05655 nsPluginTag *
05656 nsPluginHostImpl::RemoveCachedPluginsInfo(const char *filename)
05657 {
05658   nsPluginTag **link = &mCachedPlugins;
05659   for (nsPluginTag *tag = *link; tag; link = &tag->mNext, tag = *link)
05660   {
05661     // compare filename or else the mFullPath if it exists. Mac seems to use
05662     // mFullPath for fullpath and mFileName for just the leafname of fullpath.
05663     // On win and unix, mFullPath is never used and mFileName is contains the
05664     // full pathname. All this should move to using nsIFile.
05665     if (!PL_strcmp(tag->mFileName, filename) ||
05666         (tag->mFullPath && !PL_strcmp(tag->mFullPath, filename)))
05667     {
05668       // Found it. Remove it from our list
05669       *link = tag->mNext;
05670       return tag;
05671     }
05672   }
05673   return nsnull;
05674 }
05675 
05676 nsresult
05677 nsPluginHostImpl::EnsurePrivateDirServiceProvider()
05678 {
05679   if (!mPrivateDirServiceProvider)
05680   {
05681     nsresult rv;
05682     mPrivateDirServiceProvider = new nsPluginDirServiceProvider();
05683     if (!mPrivateDirServiceProvider)
05684       return NS_ERROR_OUT_OF_MEMORY;
05685     nsCOMPtr<nsIDirectoryService> dirService(do_GetService(kDirectoryServiceContractID, &rv));
05686     if (NS_FAILED(rv))
05687       return rv;
05688     rv = dirService->RegisterProvider(mPrivateDirServiceProvider);
05689     if (NS_FAILED(rv))
05690       return rv;
05691   }
05692   return NS_OK;
05693 }
05694 
05696 /* Called by GetURL and PostURL */
05697 NS_IMETHODIMP nsPluginHostImpl::NewPluginURLStream(const nsString& aURL,
05698                                                    nsIPluginInstance *aInstance,
05699                                                    nsIPluginStreamListener* aListener,
05700                                                    const char *aPostData,
05701                                                    PRBool aIsFile,
05702                                                    PRUint32 aPostDataLen,
05703                                                    const char *aHeadersData,
05704                                                    PRUint32 aHeadersDataLen)
05705 {
05706   nsCOMPtr<nsIURI> url;
05707   nsAutoString absUrl;
05708   nsresult rv;
05709 
05710   if (aURL.Length() <= 0)
05711     return NS_OK;
05712 
05713   // get the full URL of the document that the plugin is embedded
05714   //   in to create an absolute url in case aURL is relative
05715   nsCOMPtr<nsIDocument> doc;
05716   nsCOMPtr<nsIPluginInstancePeer> peer;
05717   nsCOMPtr<nsIPluginInstanceOwner> owner;
05718   rv = aInstance->GetPeer(getter_AddRefs(peer));
05719   if (NS_SUCCEEDED(rv) && peer)
05720   {
05721     nsCOMPtr<nsPIPluginInstancePeer> privpeer(do_QueryInterface(peer));
05722     rv = privpeer->GetOwner(getter_AddRefs(owner));
05723     if (owner)
05724     {
05725       rv = owner->GetDocument(getter_AddRefs(doc));
05726       if (NS_SUCCEEDED(rv) && doc)
05727       {
05728         // Create an absolute URL
05729         rv = NS_MakeAbsoluteURI(absUrl, aURL, doc->GetBaseURI());
05730       }
05731     }
05732   }
05733 
05734   if (absUrl.IsEmpty())
05735     absUrl.Assign(aURL);
05736 
05737   rv = NS_NewURI(getter_AddRefs(url), absUrl);
05738 
05739   if (NS_SUCCEEDED(rv))
05740   {
05741     nsCOMPtr<nsIPluginTagInfo2> pti2 = do_QueryInterface(owner);
05742     nsCOMPtr<nsIDOMElement> element;
05743     if (pti2)
05744       pti2->GetDOMElement(getter_AddRefs(element));
05745 
05746     PRInt16 shouldLoad = nsIContentPolicy::ACCEPT;
05747     rv = NS_CheckContentLoadPolicy(nsIContentPolicy::TYPE_OTHER,
05748                                    url,
05749                                    (doc ? doc->GetDocumentURI() : nsnull),
05750                                    element,
05751                                    EmptyCString(), //mime guess
05752                                    nsnull,         //extra
05753                                    &shouldLoad);
05754     if (NS_FAILED(rv)) return rv;
05755     if (NS_CP_REJECTED(shouldLoad)) {
05756       // Disallowed by content policy
05757       return NS_ERROR_CONTENT_BLOCKED;
05758     }
05759 
05760     nsPluginStreamListenerPeer *listenerPeer = new nsPluginStreamListenerPeer;
05761     if (listenerPeer == NULL)
05762       return NS_ERROR_OUT_OF_MEMORY;
05763 
05764     NS_ADDREF(listenerPeer);
05765     rv = listenerPeer->Initialize(url, aInstance, aListener);
05766 
05767     if (NS_SUCCEEDED(rv))
05768     {
05769       nsCOMPtr<nsIInterfaceRequestor> callbacks;
05770 
05771       if (doc)
05772       {
05773         // Get the script global object owner and use that as the notification callback
05774         nsIScriptGlobalObject* global = doc->GetScriptGlobalObject();
05775 
05776         if (global)
05777         {
05778           callbacks = do_QueryInterface(global->GetGlobalObjectOwner());
05779         }
05780       }
05781 
05782       nsCOMPtr<nsIChannel> channel;
05783 
05784       rv = NS_NewChannel(getter_AddRefs(channel), url, nsnull,
05785         nsnull, /* do not add this internal plugin's channel
05786                 on the load group otherwise this channel could be canceled
05787                 form |nsWebShell::OnLinkClickSync| bug 166613 */
05788         callbacks);
05789       if (NS_FAILED(rv))
05790         return rv;
05791 
05792       if (doc)
05793       {
05794         // Set the owner of channel to the document principal...
05795         channel->SetOwner(doc->GetPrincipal());
05796       }
05797 
05798       // deal with headers and post data
05799       nsCOMPtr<nsIHttpChannel> httpChannel(do_QueryInterface(channel));
05800       if(httpChannel) {
05801         if (aPostData) {
05802 
05803           nsCOMPtr<nsIInputStream> postDataStream;
05804           rv = NS_NewPluginPostDataStream(getter_AddRefs(postDataStream), (const char*)aPostData,
05805                                           aPostDataLen, aIsFile);
05806 
05807           if (!postDataStream)
05808           {
05809             NS_RELEASE(aInstance);
05810             return NS_ERROR_UNEXPECTED;
05811           }
05812 
05813           // XXX it's a bit of a hack to rewind the postdata stream
05814           // here but it has to be done in case the post data is
05815           // being reused multiple times.
05816           nsCOMPtr<nsISeekableStream>
05817           postDataSeekable(do_QueryInterface(postDataStream));
05818           if (postDataSeekable)
05819             postDataSeekable->Seek(nsISeekableStream::NS_SEEK_SET, 0);
05820 
05821           nsCOMPtr<nsIUploadChannel> uploadChannel(do_QueryInterface(httpChannel));
05822           NS_ASSERTION(uploadChannel, "http must support nsIUploadChannel");
05823 
05824           uploadChannel->SetUploadStream(postDataStream, EmptyCString(), -1);
05825         }
05826 
05827         if (aHeadersData)
05828           rv = AddHeadersToChannel(aHeadersData, aHeadersDataLen, httpChannel);
05829       }
05830       rv = channel->AsyncOpen(listenerPeer, nsnull);
05831     }
05832     NS_RELEASE(listenerPeer);
05833   }
05834   return rv;
05835 }
05836 
05838 /* Called by GetURL and PostURL */
05839 nsresult
05840 nsPluginHostImpl::DoURLLoadSecurityCheck(nsIPluginInstance *aInstance,
05841                                          const char* aURL)
05842 {
05843   nsresult rv;
05844 
05845   if (!aURL || *aURL == '\0')
05846     return NS_OK;
05847 
05848   // get the URL of the document that loaded the plugin
05849   nsCOMPtr<nsIDocument> doc;
05850   nsCOMPtr<nsIPluginInstancePeer> peer;
05851   rv = aInstance->GetPeer(getter_AddRefs(peer));
05852   if (NS_FAILED(rv) || !peer)
05853     return NS_ERROR_FAILURE;
05854 
05855   nsCOMPtr<nsPIPluginInstancePeer> privpeer(do_QueryInterface(peer));
05856   nsCOMPtr<nsIPluginInstanceOwner> owner;
05857   rv = privpeer->GetOwner(getter_AddRefs(owner));
05858   if (!owner)
05859     return NS_ERROR_FAILURE;
05860 
05861   rv = owner->GetDocument(getter_AddRefs(doc));
05862   if (!doc)
05863     return NS_ERROR_FAILURE;
05864 
05865   // Create an absolute URL for the target in case the target is relative
05866   nsCOMPtr<nsIURI> targetURL;
05867   rv = NS_NewURI(getter_AddRefs(targetURL), aURL, doc->GetBaseURI());
05868 
05869   if (!targetURL)
05870     return NS_ERROR_FAILURE;
05871 
05872   nsCOMPtr<nsIScriptSecurityManager> secMan(
05873     do_GetService(NS_SCRIPTSECURITYMANAGER_CONTRACTID, &rv));
05874   if (NS_FAILED(rv))
05875     return rv;
05876 
05877   return secMan->CheckLoadURIWithPrincipal(doc->GetPrincipal(), targetURL,
05878                                            nsIScriptSecurityManager::STANDARD);
05879 
05880 }
05881 
05882 
05884 NS_IMETHODIMP
05885 nsPluginHostImpl::AddHeadersToChannel(const char *aHeadersData,
05886                                       PRUint32 aHeadersDataLen,
05887                                       nsIChannel *aGenericChannel)
05888 {
05889   nsresult rv = NS_OK;
05890 
05891   nsCOMPtr<nsIHttpChannel> aChannel = do_QueryInterface(aGenericChannel);
05892   if (!aChannel) {
05893     return NS_ERROR_NULL_POINTER;
05894   }
05895 
05896   // used during the manipulation of the String from the aHeadersData
05897   nsCAutoString headersString;
05898   nsCAutoString oneHeader;
05899   nsCAutoString headerName;
05900   nsCAutoString headerValue;
05901   PRInt32 crlf = 0;
05902   PRInt32 colon = 0;
05903 
05904   //
05905   // Turn the char * buffer into an nsString.
05906   //
05907   headersString = aHeadersData;
05908 
05909   //
05910   // Iterate over the nsString: for each "\r\n" delimited chunk,
05911   // add the value as a header to the nsIHTTPChannel
05912   //
05913 
05914   while (PR_TRUE) {
05915     crlf = headersString.Find("\r\n", PR_TRUE);
05916     if (-1 == crlf) {
05917       rv = NS_OK;
05918       return rv;
05919     }
05920     headersString.Mid(oneHeader, 0, crlf);
05921     headersString.Cut(0, crlf + 2);
05922     oneHeader.StripWhitespace();
05923     colon = oneHeader.Find(":");
05924     if (-1 == colon) {
05925       rv = NS_ERROR_NULL_POINTER;
05926       return rv;
05927     }
05928     oneHeader.Left(headerName, colon);
05929     colon++;
05930     oneHeader.Mid(headerValue, colon, oneHeader.Length() - colon);
05931 
05932     //
05933     // FINALLY: we can set the header!
05934     //
05935 
05936     rv = aChannel->SetRequestHeader(headerName, headerValue, PR_TRUE);
05937     if (NS_FAILED(rv)) {
05938       rv = NS_ERROR_NULL_POINTER;
05939       return rv;
05940     }
05941   }
05942   return rv;
05943 }
05944 
05945 
05947 NS_IMETHODIMP
05948 nsPluginHostImpl::StopPluginInstance(nsIPluginInstance* aInstance)
05949 {
05950   PLUGIN_LOG(PLUGIN_LOG_NORMAL,
05951   ("nsPluginHostImpl::StopPluginInstance called instance=%p\n",aInstance));
05952 
05953   nsActivePlugin * plugin = mActivePluginList.find(aInstance);
05954 
05955   if(plugin != nsnull) {
05956     plugin->setStopped(PR_TRUE);  // be sure we set the "stop" bit
05957 
05958     // if the plugin does not want to be 'cached' just remove it
05959     PRBool doCache = PR_TRUE;
05960     aInstance->GetValue(nsPluginInstanceVariable_DoCacheBool, (void *) &doCache);
05961 
05962     if (!doCache) {
05963       PRLibrary * library = nsnull;
05964       if(plugin->mPluginTag)
05965         library = plugin->mPluginTag->mLibrary;
05966 
05967       mActivePluginList.remove(plugin);
05968     }
05969     else {
05970       // if it is allowed to be cached simply stop it, but first we should check
05971       // if we haven't exceeded the maximum allowed number of cached instances
05972 
05973       // try to get the max cached plugins from a pref or use default
05974       PRUint32 max_num;
05975       nsresult rv = NS_ERROR_FAILURE;
05976       if (mPrefService) {
05977         rv = mPrefService->GetIntPref(NS_PREF_MAX_NUM_CACHED_PLUGINS, (int*)&max_num);
05978       }
05979       if (NS_FAILED(rv)) max_num = DEFAULT_NUMBER_OF_STOPPED_PLUGINS;
05980 
05981       if(mActivePluginList.getStoppedCount() >= max_num) {
05982         nsActivePlugin * oldest = mActivePluginList.findOldestStopped();
05983         if(oldest != nsnull)
05984           mActivePluginList.remove(oldest);
05985       }
05986     }
05987   }
05988   return NS_OK;
05989 }
05990 
05992 /* Called by InstantiateEmbeddedPlugin() */
05993 nsresult nsPluginHostImpl::NewEmbeddedPluginStream(nsIURI* aURL,
05994                                                    nsIPluginInstanceOwner *aOwner,
05995                                                    nsIPluginInstance* aInstance)
05996 {
05997   if (!aURL)
05998     return NS_OK;
05999 
06000   nsPluginStreamListenerPeer  *listener = new nsPluginStreamListenerPeer();
06001   if (listener == nsnull)
06002     return NS_ERROR_OUT_OF_MEMORY;
06003 
06004   nsresult rv;
06005 
06006   // if we have an instance, everything has been set up
06007   // if we only have an owner, then we need to pass it in
06008   // so the listener can set up the instance later after
06009   // we've determined the mimetype of the stream
06010   if(aInstance != nsnull)
06011     rv = listener->InitializeEmbedded(aURL, aInstance);
06012   else if(aOwner != nsnull)
06013     rv = listener->InitializeEmbedded(aURL, nsnull, aOwner, this);
06014   else
06015     rv = NS_ERROR_ILLEGAL_VALUE;
06016 
06017   if (NS_SUCCEEDED(rv)) {
06018     nsCOMPtr<nsIDocument> doc;
06019     nsCOMPtr<nsILoadGroup> loadGroup;
06020 
06021     if (aOwner) {
06022       rv = aOwner->GetDocument(getter_AddRefs(doc));
06023       if (NS_SUCCEEDED(rv) && doc) {
06024         loadGroup = doc->GetDocumentLoadGroup();
06025       }
06026     }
06027 
06028     nsCOMPtr<nsIChannel> channel;
06029 
06030     rv = NS_NewChannel(getter_AddRefs(channel), aURL, nsnull, loadGroup, nsnull);
06031     if (NS_SUCCEEDED(rv)) {
06032       // if this is http channel, set referrer, some servers are configured
06033       // to reject requests without referrer set, see bug 157796
06034       nsCOMPtr<nsIHttpChannel> httpChannel(do_QueryInterface(channel));
06035       if (httpChannel && doc)
06036         httpChannel->SetReferrer(doc->GetDocumentURI());
06037 
06038       rv = channel->AsyncOpen(listener, nsnull);
06039       if (NS_SUCCEEDED(rv))
06040         return NS_OK;
06041     }
06042   }
06043 
06044   delete listener;
06045   return rv;
06046 }
06047 
06049 /* Called by InstantiateFullPagePlugin() */
06050 nsresult nsPluginHostImpl::NewFullPagePluginStream(nsIStreamListener *&aStreamListener,
06051                                                    nsIPluginInstance *aInstance)
06052 {
06053   nsPluginStreamListenerPeer  *listener = new nsPluginStreamListenerPeer();
06054   if (listener == nsnull)
06055     return NS_ERROR_OUT_OF_MEMORY;
06056 
06057   nsresult rv;
06058 
06059   rv = listener->InitializeFullPage(aInstance);
06060 
06061   aStreamListener = listener;
06062   NS_ADDREF(listener);
06063 
06064   // add peer to list of stream peers for this instance
06065   nsActivePlugin * p = mActivePluginList.find(aInstance);
06066   if (p) {
06067     if (!p->mStreams && (NS_FAILED(rv = NS_NewISupportsArray(getter_AddRefs(p->mStreams)))))
06068       return rv;
06069     p->mStreams->AppendElement(aStreamListener);
06070   }
06071 
06072   return rv;
06073 }
06074 
06075 
06076 // nsIFileUtilities interface
06078 NS_IMETHODIMP nsPluginHostImpl::GetProgramPath(const char* *result)
06079 {
06080   nsresult rv;
06081   NS_ENSURE_ARG_POINTER(result);
06082   *result = nsnull;
06083 
06084   nsCOMPtr<nsIProperties> dirService(do_GetService(kDirectoryServiceContractID, &rv));
06085   if (NS_FAILED(rv))
06086     return rv;
06087   nsCOMPtr<nsILocalFile> programDir;
06088   rv = dirService->Get(NS_XPCOM_CURRENT_PROCESS_DIR, NS_GET_IID(nsILocalFile), getter_AddRefs(programDir));
06089   if (NS_FAILED(rv))
06090     return rv;
06091 
06092   nsCAutoString temp;
06093   rv = programDir->GetNativePath(temp);
06094   *result = ToNewCString(temp);
06095   return rv;
06096 }
06097 
06098 
06100 NS_IMETHODIMP nsPluginHostImpl::GetTempDirPath(const char* *result)
06101 {
06102   nsresult rv;
06103   NS_ENSURE_ARG_POINTER(result);
06104   *result = nsnull;
06105 
06106   nsCOMPtr<nsIProperties> dirService(do_GetService(kDirectoryServiceContractID, &rv));
06107   if (NS_FAILED(rv))
06108     return rv;
06109   nsCOMPtr<nsILocalFile> tempDir;
06110   rv = dirService->Get(NS_OS_TEMP_DIR, NS_GET_IID(nsILocalFile), getter_AddRefs(tempDir));
06111   if (NS_FAILED(rv))
06112     return rv;
06113 
06114   nsCAutoString temp;
06115   rv = tempDir->GetNativePath(temp);
06116   *result = ToNewCString(temp);
06117   return rv;
06118 }
06119 
06120 
06122 NS_IMETHODIMP nsPluginHostImpl::NewTempFileName(const char* prefix, PRUint32 bufLen, char* resultBuf)
06123 {
06124   return NS_ERROR_NOT_IMPLEMENTED;
06125 }
06126 
06127 
06128 // nsICookieStorage interface
06129 
06131 NS_IMETHODIMP nsPluginHostImpl::GetCookie(const char* inCookieURL, void* inOutCookieBuffer, PRUint32& inOutCookieSize)
06132 {
06133   nsresult rv = NS_ERROR_NOT_IMPLEMENTED;
06134   nsXPIDLCString cookieString;
06135   PRUint32 cookieStringLen = 0;
06136   nsCOMPtr<nsIURI> uriIn;
06137 
06138   if ((nsnull == inCookieURL) || (0 >= inOutCookieSize)) {
06139     return NS_ERROR_INVALID_ARG;
06140   }
06141 
06142   nsCOMPtr<nsIIOService> ioService(do_GetService(kIOServiceCID, &rv));
06143 
06144   if (NS_FAILED(rv) || (nsnull == ioService)) {
06145     return rv;
06146   }
06147 
06148   nsCOMPtr<nsICookieService> cookieService =
06149            do_GetService(kCookieServiceCID, &rv);
06150 
06151   if (NS_FAILED(rv) || (nsnull == cookieService)) {
06152     return NS_ERROR_INVALID_ARG;
06153   }
06154 
06155   // make an nsURI from the argument url
06156   rv = ioService->NewURI(nsDependentCString(inCookieURL), nsnull, nsnull, getter_AddRefs(uriIn));
06157   if (NS_FAILED(rv)) {
06158     return rv;
06159   }
06160 
06161   rv = cookieService->GetCookieString(uriIn, nsnull, getter_Copies(cookieString));
06162 
06163   if (NS_FAILED(rv) || (!cookieString) ||
06164       (inOutCookieSize <= (cookieStringLen = PL_strlen(cookieString.get())))) {
06165     return NS_ERROR_FAILURE;
06166   }
06167 
06168   PL_strcpy((char *) inOutCookieBuffer, cookieString.get());
06169   inOutCookieSize = cookieStringLen;
06170   rv = NS_OK;
06171 
06172   return rv;
06173 }
06174 
06175 
06177 NS_IMETHODIMP nsPluginHostImpl::SetCookie(const char* inCookieURL, const void* inCookieBuffer, PRUint32 inCookieSize)
06178 {
06179   nsresult rv = NS_ERROR_NOT_IMPLEMENTED;
06180   nsCOMPtr<nsIURI> uriIn;
06181 
06182   if ((nsnull == inCookieURL) || (nsnull == inCookieBuffer) ||
06183       (0 >= inCookieSize)) {
06184     return NS_ERROR_INVALID_ARG;
06185   }
06186 
06187   nsCOMPtr<nsIIOService> ioService(do_GetService(kIOServiceCID, &rv));
06188 
06189   if (NS_FAILED(rv) || (nsnull == ioService)) {
06190     return rv;
06191   }
06192 
06193   nsCOMPtr<nsICookieService> cookieService =
06194            do_GetService(kCookieServiceCID, &rv);
06195 
06196   if (NS_FAILED(rv) || (nsnull == cookieService)) {
06197     return NS_ERROR_FAILURE;
06198   }
06199 
06200   // make an nsURI from the argument url
06201   rv = ioService->NewURI(nsDependentCString(inCookieURL), nsnull, nsnull, getter_AddRefs(uriIn));
06202   if (NS_FAILED(rv)) {
06203     return NS_ERROR_FAILURE;
06204   }
06205 
06206   nsCOMPtr<nsIPrompt> prompt;
06207   GetPrompt(nsnull, getter_AddRefs(prompt));
06208 
06209   char * cookie = (char *)inCookieBuffer;
06210   char c = cookie[inCookieSize];
06211   cookie[inCookieSize] = '\0';
06212   rv = cookieService->SetCookieString(uriIn, prompt, cookie, nsnull);
06213   cookie[inCookieSize] = c;
06214 
06215   return rv;
06216 }
06217 
06218 
06220 NS_IMETHODIMP nsPluginHostImpl::Observe(nsISupports *aSubject,
06221                                         const char *aTopic,
06222                                         const PRUnichar *someData)
06223 {
06224 #ifdef NS_DEBUG
06225   printf("nsPluginHostImpl::Observe \"%s\"\n", aTopic ? aTopic : "");
06226 #endif
06227   if (!nsCRT::strcmp(NS_XPCOM_SHUTDOWN_OBSERVER_ID, aTopic))
06228   {
06229     Destroy();
06230     UnloadUnusedLibraries();
06231   }
06232   return NS_OK;
06233 }
06234 
06236 NS_IMETHODIMP
06237 nsPluginHostImpl::HandleBadPlugin(PRLibrary* aLibrary, nsIPluginInstance *aInstance)
06238 {
06239   // the |aLibrary| parameter is not needed anymore, after we added |aInstance| which
06240   // can also be used to look up the plugin name, but we cannot get rid of it because
06241   // the |nsIPluginHost| interface is deprecated which in fact means 'frozen'
06242 
06243   nsresult rv = NS_OK;
06244 
06245   NS_ASSERTION(PR_FALSE, "Plugin performed illegal operation");
06246 
06247   if(mDontShowBadPluginMessage)
06248     return rv;
06249 
06250   nsCOMPtr<nsIPluginInstanceOwner> owner;
06251 
06252   if (aInstance) {
06253     nsCOMPtr<nsIPluginInstancePeer> peer;
06254     rv = aInstance->GetPeer(getter_AddRefs(peer));
06255     if (NS_SUCCEEDED(rv) && peer) {
06256       nsCOMPtr<nsPIPluginInstancePeer> privpeer(do_QueryInterface(peer));
06257       privpeer->GetOwner(getter_AddRefs(owner));
06258     }
06259   }
06260 
06261   nsCOMPtr<nsIPrompt> prompt;
06262   GetPrompt(owner, getter_AddRefs(prompt));
06263   if (prompt) {
06264     nsCOMPtr<nsIStringBundleService> strings(do_GetService(kStringBundleServiceCID, &rv));
06265     if (NS_FAILED(rv))
06266       return rv;
06267 
06268     nsCOMPtr<nsIStringBundle> bundle;
06269     rv = strings->CreateBundle(BRAND_PROPERTIES_URL, getter_AddRefs(bundle));
06270     if (NS_FAILED(rv))
06271       return rv;
06272 
06273     nsXPIDLString brandName;
06274     if (NS_FAILED(rv = bundle->GetStringFromName(NS_LITERAL_STRING("brandShortName").get(),
06275                                  getter_Copies(brandName))))
06276       return rv;
06277 
06278     rv = strings->CreateBundle(PLUGIN_PROPERTIES_URL, getter_AddRefs(bundle));
06279     if (NS_FAILED(rv))
06280       return rv;
06281 
06282     nsXPIDLString title, message, checkboxMessage;
06283     if (NS_FAILED(rv = bundle->GetStringFromName(NS_LITERAL_STRING("BadPluginTitle").get(),
06284                                  getter_Copies(title))))
06285       return rv;
06286 
06287     const PRUnichar *formatStrings[] = { brandName.get() };
06288     if (NS_FAILED(rv = bundle->FormatStringFromName(NS_LITERAL_STRING("BadPluginMessage").get(),
06289                                  formatStrings, 1, getter_Copies(message))))
06290       return rv;
06291 
06292     if (NS_FAILED(rv = bundle->GetStringFromName(NS_LITERAL_STRING("BadPluginCheckboxMessage").get(),
06293                                  getter_Copies(checkboxMessage))))
06294       return rv;
06295 
06296     // add plugin name to the message
06297     char * pluginname = nsnull;
06298     nsActivePlugin * p = mActivePluginList.find(aInstance);
06299     if (p) {
06300       nsPluginTag * tag = p->mPluginTag;
06301       if (tag) {
06302         if (tag->mName)
06303           pluginname = tag->mName;
06304         else
06305           pluginname = tag->mFileName;
06306       }
06307     }
06308 
06309     nsAutoString msg;
06310     msg.AssignWithConversion(pluginname);
06311     msg.AppendLiteral("\n\n");
06312     msg.Append(message);
06313 
06314     PRInt32 buttonPressed;
06315     PRBool checkboxState = PR_FALSE;
06316     rv = prompt->ConfirmEx(title, msg.get(),
06317                          nsIPrompt::BUTTON_TITLE_OK * nsIPrompt::BUTTON_POS_0,
06318                          nsnull, nsnull, nsnull,
06319                          checkboxMessage, &checkboxState, &buttonPressed);
06320 
06321 
06322     if (NS_SUCCEEDED(rv) && checkboxState)
06323       mDontShowBadPluginMessage = PR_TRUE;
06324   }
06325 
06326   return rv;
06327 }
06328 
06333 NS_IMETHODIMP
06334 nsPluginHostImpl::SetIsScriptableInstance(nsIPluginInstance * aPluginInstance, PRBool aScriptable)
06335 {
06336   nsActivePlugin * p = mActivePluginList.find(aPluginInstance);
06337   if(p == nsnull)
06338     return NS_ERROR_FAILURE;
06339 
06340   p->mXPConnected = aScriptable;
06341   if(p->mPluginTag)
06342     p->mPluginTag->mXPConnected = aScriptable;
06343 
06344   return NS_OK;
06345 }
06346 
06347 NS_IMETHODIMP
06348 nsPluginHostImpl::ParsePostBufferToFixHeaders(
06349                             const char *inPostData, PRUint32 inPostDataLen,
06350                             char **outPostData, PRUint32 *outPostDataLen)
06351 {
06352   if (!inPostData || !outPostData || !outPostDataLen)
06353     return NS_ERROR_NULL_POINTER;
06354 
06355   *outPostData = 0;
06356   *outPostDataLen = 0;
06357 
06358   const char CR = '\r';
06359   const char LF = '\n';
06360   const char CRLFCRLF[] = {CR,LF,CR,LF,'\0'}; // C string"\r\n\r\n"
06361   const char ContentLenHeader[] = "Content-length";
06362 
06363   nsAutoVoidArray singleLF;
06364   const char *pSCntlh = 0;// pointer to start of ContentLenHeader in inPostData
06365   const char *pSod = 0;   // pointer to start of data in inPostData
06366   const char *pEoh = 0;   // pointer to end of headers in inPostData
06367   const char *pEod = inPostData + inPostDataLen; // pointer to end of inPostData
06368   if (*inPostData == LF) {
06369     // from 4.x spec http://developer.netscape.com/docs/manuals/communicator/plugin/pgfn2.htm#1007754
06370     // If no custom headers are required, simply add a blank
06371     // line ('\n') to the beginning of the file or buffer.
06372     // so *inPostData == '\n' is valid
06373     pSod = inPostData + 1;
06374   } else {
06375     const char *s = inPostData; //tmp pointer to sourse inPostData
06376     while (s < pEod) {
06377       if (!pSCntlh &&
06378           (*s == 'C' || *s == 'c') &&
06379           (s + sizeof(ContentLenHeader) - 1 < pEod) &&
06380           (!PL_strncasecmp(s, ContentLenHeader, sizeof(ContentLenHeader) - 1)))
06381       {
06382         // lets assume this is ContentLenHeader for now
06383         const char *p = pSCntlh = s;
06384         p += sizeof(ContentLenHeader) - 1;
06385         // search for first CR or LF == end of ContentLenHeader
06386         for (; p < pEod; p++) {
06387           if (*p == CR || *p == LF) {
06388             // got delimiter,
06389             // one more check; if previous char is a digit
06390             // most likely pSCntlh points to the start of ContentLenHeader
06391             if (*(p-1) >= '0' && *(p-1) <= '9') {
06392               s = p;
06393             }
06394             break; //for loop
06395           }
06396         }
06397         if (pSCntlh == s) { // curret ptr is the same
06398           pSCntlh = 0; // that was not ContentLenHeader
06399           break; // there is nothing to parse, break *WHILE LOOP* here
06400         }
06401       }
06402 
06403       if (*s == CR) {
06404         if (pSCntlh && // only if ContentLenHeader is found we are looking for end of headers
06405             ((s + sizeof(CRLFCRLF)-1) <= pEod) &&
06406             !memcmp(s, CRLFCRLF, sizeof(CRLFCRLF)-1))
06407         {
06408           s += sizeof(CRLFCRLF)-1;
06409           pEoh = pSod = s; // data stars here
06410           break;
06411         }
06412       } else if (*s == LF) {
06413         if (*(s-1) != CR) {
06414           singleLF.AppendElement((void*)s);
06415         }
06416         if (pSCntlh && (s+1 < pEod) && (*(s+1) == LF)) {
06417           s++;
06418           singleLF.AppendElement((void*)s);
06419           s++;
06420           pEoh = pSod = s; // data stars here
06421           break;
06422         }
06423       }
06424       s++;
06425     }
06426   }
06427 
06428   // deal with output buffer
06429   if (!pSod) { // lets assume whole buffer is a data
06430     pSod = inPostData;
06431   }
06432 
06433   PRUint32 newBufferLen = 0;
06434   PRUint32 dataLen = pEod - pSod;
06435   PRUint32 headersLen = pEoh ? pSod - inPostData : 0;
06436 
06437   char *p; // tmp ptr into new output buf
06438   if (headersLen) { // we got a headers
06439     // this function does not make any assumption on correctness
06440     // of ContentLenHeader value in this case.
06441 
06442     newBufferLen = dataLen + headersLen;
06443     // in case there were single LFs in headers
06444     // reserve an extra space for CR will be added before each single LF
06445     int cntSingleLF = singleLF.Count();
06446     newBufferLen += cntSingleLF;
06447 
06448     if (!(*outPostData = p = (char*)nsMemory::Alloc(newBufferLen)))
06449       return NS_ERROR_OUT_OF_MEMORY;
06450 
06451     // deal with single LF
06452     const char *s = inPostData;
06453     if (cntSingleLF) {
06454       for (int i=0; i<cntSingleLF; i++) {
06455         const char *plf = (const char*) singleLF.ElementAt(i); // ptr to single LF in headers
06456         int n = plf - s; // bytes to copy
06457         if (n) { // for '\n\n' there is nothing to memcpy
06458           memcpy(p, s, n);
06459           p += n;
06460         }
06461         *p++ = CR;
06462         s = plf;
06463         *p++ = *s++;
06464       }
06465     }
06466     // are we done with headers?
06467     headersLen = pEoh - s;
06468     if (headersLen) { // not yet
06469       memcpy(p, s, headersLen); // copy the rest
06470       p += headersLen;
06471     }
06472   } else  if (dataLen) { // no ContentLenHeader is found but there is a data
06473     // make new output buffer big enough
06474     // to keep ContentLenHeader+value followed by data
06475     PRUint32 l = sizeof(ContentLenHeader) + sizeof(CRLFCRLF) + 32;
06476     newBufferLen = dataLen + l;
06477     if (!(*outPostData = p = (char*)nsMemory::Alloc(newBufferLen)))
06478       return NS_ERROR_OUT_OF_MEMORY;
06479     headersLen = PR_snprintf(p, l,"%s: %ld%s", ContentLenHeader, dataLen, CRLFCRLF);
06480     if (headersLen == l) { // if PR_snprintf has ate all extra space consider this as an error
06481       nsMemory::Free(p);
06482       *outPostData = 0;
06483       return NS_ERROR_FAILURE;
06484     }
06485     p += headersLen;
06486     newBufferLen = headersLen + dataLen;
06487   }
06488   // at this point we've done with headers.
06489   // there is a possibility that input buffer has only headers info in it
06490   // which already parsed and copied into output buffer.
06491   // copy the data
06492   if (dataLen) {
06493     memcpy(p, pSod, dataLen);
06494   }
06495 
06496   *outPostDataLen = newBufferLen;
06497 
06498   return NS_OK;
06499 }
06500 
06501 NS_IMETHODIMP
06502 nsPluginHostImpl::CreateTmpFileToPost(const char *postDataURL, char **pTmpFileName)
06503 {
06504   *pTmpFileName = 0;
06505   nsresult rv;
06506   PRInt64 fileSize;
06507   nsCAutoString filename;
06508 
06509   // stat file == get size & convert file:///c:/ to c: if needed
06510   nsCOMPtr<nsIFile> inFile;
06511   rv = NS_GetFileFromURLSpec(nsDependentCString(postDataURL),
06512                              getter_AddRefs(inFile));
06513   if (NS_FAILED(rv)) {
06514     nsCOMPtr<nsILocalFile> localFile;
06515     rv = NS_NewNativeLocalFile(nsDependentCString(postDataURL), PR_FALSE,
06516                                getter_AddRefs(localFile));
06517     if (NS_FAILED(rv)) return rv;
06518     inFile = localFile;
06519   }
06520   rv = inFile->GetFileSize(&fileSize);
06521   if (NS_FAILED(rv)) return rv;
06522   rv = inFile->GetNativePath(filename);
06523   if (NS_FAILED(rv)) return rv;
06524 
06525   if (!LL_IS_ZERO(fileSize)) {
06526     nsCOMPtr<nsIInputStream> inStream;
06527     rv = NS_NewLocalFileInputStream(getter_AddRefs(inStream), inFile);
06528     if (NS_FAILED(rv)) return rv;
06529 
06530     // Create a temporary file to write the http Content-length:
06531     // %ld\r\n\" header and "\r\n" == end of headers for post data to
06532 
06533     nsCOMPtr<nsIFile> tempFile;
06534     rv = GetPluginTempDir(getter_AddRefs(tempFile));
06535     if (NS_FAILED(rv))
06536       return rv;
06537 
06538     nsCAutoString inFileName;
06539     inFile->GetNativeLeafName(inFileName);
06540     // XXX hack around bug 70083
06541     inFileName.Insert(NS_LITERAL_CSTRING("post-"), 0);
06542     rv = tempFile->AppendNative(inFileName);
06543 
06544     if (NS_FAILED(rv))
06545       return rv;
06546 
06547     // make it unique, and mode == 0600, not world-readable
06548     rv = tempFile->CreateUnique(nsIFile::NORMAL_FILE_TYPE, 0600);
06549     if (NS_FAILED(rv))
06550       return rv;
06551 
06552     nsCOMPtr<nsIOutputStream> outStream;
06553     if (NS_SUCCEEDED(rv)) {
06554       rv = NS_NewLocalFileOutputStream(getter_AddRefs(outStream),
06555         tempFile,
06556         (PR_WRONLY | PR_CREATE_FILE | PR_TRUNCATE),
06557         0600); // 600 so others can't read our form data
06558     }
06559     NS_ASSERTION(NS_SUCCEEDED(rv), "Post data file couldn't be created!");
06560     if (NS_FAILED(rv))
06561       return rv;
06562 
06563     char buf[1024];
06564     PRUint32 br, bw;
06565     PRBool firstRead = PR_TRUE;
06566     while (1) {
06567       // Read() mallocs if buffer is null
06568       rv = inStream->Read(buf, 1024, &br);
06569       if (NS_FAILED(rv) || (PRInt32)br <= 0)
06570         break;
06571       if (firstRead) {
06572         // according to the 4.x spec
06573         // http://developer.netscape.com/docs/manuals/communicator/plugin/pgfn2.htm#1007707
06574         //"For protocols in which the headers must be distinguished from the body,
06575         // such as HTTP, the buffer or file should contain the headers, followed by
06576         // a blank line, then the body. If no custom headers are required, simply
06577         // add a blank line ('\n') to the beginning of the file or buffer.
06578 
06579         char *parsedBuf;
06580         // assuming first 1K (or what we got) has all headers in,
06581         // lets parse it through nsPluginHostImpl::ParsePostBufferToFixHeaders()
06582         ParsePostBufferToFixHeaders((const char *)buf, br, &parsedBuf, &bw);
06583         rv = outStream->Write(parsedBuf, bw, &br);
06584         nsMemory::Free(parsedBuf);
06585         if (NS_FAILED(rv) || (bw != br))
06586           break;
06587 
06588         firstRead = PR_FALSE;
06589         continue;
06590       }
06591       bw = br;
06592       rv = outStream->Write(buf, bw, &br);
06593       if (NS_FAILED(rv) || (bw != br))
06594         break;
06595     }
06596 
06597     inStream->Close();
06598     outStream->Close();
06599     if (NS_SUCCEEDED(rv)) {
06600       nsCAutoString path;
06601       if (NS_SUCCEEDED(tempFile->GetNativePath(path)))
06602         *pTmpFileName = ToNewCString(path);
06603     }
06604   }
06605   return rv;
06606 }
06607 
06608 NS_IMETHODIMP
06609 nsPluginHostImpl::NewPluginNativeWindow(nsPluginNativeWindow ** aPluginNativeWindow)
06610 {
06611   return PLUG_NewPluginNativeWindow(aPluginNativeWindow);
06612 }
06613 
06614 NS_IMETHODIMP
06615 nsPluginHostImpl::DeletePluginNativeWindow(nsPluginNativeWindow * aPluginNativeWindow)
06616 {
06617   return PLUG_DeletePluginNativeWindow(aPluginNativeWindow);
06618 }
06619 
06620 /* ----- end of nsPIPluginHost implementation ----- */
06621 
06622 nsresult
06623 nsPluginHostImpl::ScanForRealInComponentsFolder(nsIComponentManager * aCompManager)
06624 {
06625   nsresult rv = NS_OK;
06626 
06627 #ifdef XP_WIN
06628 
06629   // First, lets check if we already have Real. No point in doing this if it's installed correctly
06630   if (NS_SUCCEEDED(IsPluginEnabledForType("audio/x-pn-realaudio-plugin")))
06631     return rv;
06632 
06633   // Next, maybe the pref wants to override
06634   PRBool bSkipRealPlayerHack = PR_FALSE;
06635   if (!mPrefService ||
06636      (NS_SUCCEEDED(mPrefService->GetBoolPref("plugin.skip_real_player_hack", &bSkipRealPlayerHack)) &&
06637      bSkipRealPlayerHack))
06638   return rv;
06639 
06640   // now we need the XPCOM components folder
06641   nsCOMPtr<nsIFile> RealPlugin;
06642   if (NS_FAILED(NS_GetSpecialDirectory(NS_XPCOM_COMPONENT_DIR, getter_AddRefs(RealPlugin))) || !RealPlugin)
06643     return rv;
06644 
06645   // make sure the file is actually there
06646   RealPlugin->AppendNative(nsDependentCString("nppl3260.dll"));
06647   PRBool exists;
06648   nsCAutoString filePath;
06649   RealPlugin->Exists(&exists);
06650   if (!exists || NS_FAILED(RealPlugin->GetNativePath(filePath)))
06651     return rv;
06652 
06653   // now make sure it's a plugin
06654   nsCOMPtr<nsILocalFile> localfile;
06655   NS_NewNativeLocalFile(filePath,
06656                         PR_TRUE,
06657                         getter_AddRefs(localfile));
06658 
06659   if (!nsPluginsDir::IsPluginFile(localfile))
06660     return rv;
06661 
06662   // try to get the mime info and descriptions out of the plugin
06663   nsPluginFile pluginFile(localfile);
06664   nsPluginInfo info = { sizeof(info) };
06665   if (NS_FAILED(pluginFile.GetPluginInfo(info)))
06666     return rv;
06667 
06668   nsCOMPtr<nsIComponentManager> compManager;
06669   NS_GetComponentManager(getter_AddRefs(compManager));
06670 
06671   // finally, create our "plugin tag" and add it to the list
06672   if (info.fMimeTypeArray) {
06673     nsPluginTag *pluginTag = new nsPluginTag(&info);
06674     if (pluginTag) {
06675       pluginTag->SetHost(this);
06676       pluginTag->mNext = mPlugins;
06677       mPlugins = pluginTag;
06678 
06679       // last thing we need is to register this plugin with layout so it can be used in full-page mode
06680       pluginTag->RegisterWithCategoryManager(mOverrideInternalTypes);
06681     }
06682   }
06683 
06684   // free allocated strings in GetPluginInfo
06685   pluginFile.FreePluginInfo(info);
06686 
06687 #endif
06688 
06689   return rv;
06690 }
06691 
06692 nsresult nsPluginHostImpl::AddUnusedLibrary(PRLibrary * aLibrary)
06693 {
06694   if (mUnusedLibraries.IndexOf(aLibrary) == -1) // don't add duplicates
06695     mUnusedLibraries.AppendElement(aLibrary);
06696 
06697   return NS_OK;
06698 }
06699 
06701 nsresult nsPluginStreamListenerPeer::ServeStreamAsFile(nsIRequest *request,
06702                                                         nsISupports* aContext)
06703 {
06704   if (!mInstance)
06705     return NS_ERROR_FAILURE;
06706 
06707   // mInstance->Stop calls mPStreamListener->CleanUpStream(), so stream will be properly clean up
06708   mInstance->Stop();
06709   mInstance->Start();
06710   nsCOMPtr<nsIPluginInstancePeer> peer;
06711   mInstance->GetPeer(getter_AddRefs(peer));
06712   if (peer) {
06713     nsCOMPtr<nsPIPluginInstancePeer> privpeer(do_QueryInterface(peer));
06714     nsCOMPtr<nsIPluginInstanceOwner> owner;
06715     privpeer->GetOwner(getter_AddRefs(owner));
06716     if (owner) {
06717       nsPluginWindow    *window = nsnull;
06718       owner->GetWindow(window);
06719       if (window->window)
06720       {
06721         nsCOMPtr<nsIPluginInstance> inst = mInstance;
06722         ((nsPluginNativeWindow*)window)->CallSetWindow(inst);
06723       }
06724     }
06725   }
06726 
06727   mPluginStreamInfo->SetSeekable(0);
06728   mPStreamListener->OnStartBinding(mPluginStreamInfo);
06729   mPluginStreamInfo->SetStreamOffset(0);
06730 
06731   // force the plugin use stream as file
06732   mStreamType = nsPluginStreamType_AsFile;
06733 
06734   // then check it out if browser cache is not available
06735   nsCOMPtr<nsICachingChannel> cacheChannel = do_QueryInterface(request);
06736   if (!(cacheChannel && (NS_SUCCEEDED(cacheChannel->SetCacheAsFile(PR_TRUE))))) {
06737       nsCOMPtr<nsIChannel> channel = do_QueryInterface(request);
06738       if (channel) {
06739         SetupPluginCacheFile(channel);
06740       }
06741   }
06742 
06743   // unset mPendingRequests
06744   mPendingRequests = 0;
06745 
06746   return NS_OK;
06747 }
06748 
06750 NS_IMPL_ISUPPORTS1(nsPluginByteRangeStreamListener, nsIStreamListener)
06751 nsPluginByteRangeStreamListener::nsPluginByteRangeStreamListener(nsIWeakReference* aWeakPtr)
06752 {
06753   mWeakPtrPluginStreamListenerPeer = aWeakPtr;
06754   mRemoveMagicNumber = PR_FALSE;
06755 }
06756 
06757 nsPluginByteRangeStreamListener::~nsPluginByteRangeStreamListener()
06758 {
06759   mStreamConverter = 0;
06760   mWeakPtrPluginStreamListenerPeer = 0;
06761 }
06762 
06763 NS_IMETHODIMP
06764 nsPluginByteRangeStreamListener::OnStartRequest(nsIRequest *request, nsISupports *ctxt)
06765 {
06766   nsresult rv;
06767 
06768   nsCOMPtr<nsIStreamListener> finalStreamListener = do_QueryReferent(mWeakPtrPluginStreamListenerPeer);
06769   if (!finalStreamListener)
06770      return NS_ERROR_FAILURE;
06771 
06772   nsCOMPtr<nsIStreamConverterService> serv = do_GetService(kStreamConverterServiceCID, &rv);
06773   if (NS_SUCCEEDED(rv)) {
06774     rv = serv->AsyncConvertData(MULTIPART_BYTERANGES,
06775                                 "*/*",
06776                                 finalStreamListener,
06777                                 nsnull,
06778                                 getter_AddRefs(mStreamConverter));
06779     if (NS_SUCCEEDED(rv)) {
06780       rv = mStreamConverter->OnStartRequest(request, ctxt);
06781       if (NS_SUCCEEDED(rv))
06782         return rv;
06783     }
06784   }
06785   mStreamConverter = 0;
06786 
06787   nsCOMPtr<nsIHttpChannel> httpChannel(do_QueryInterface(request));
06788   if (!httpChannel) {
06789     return NS_ERROR_FAILURE;
06790   }
06791 
06792   PRUint32 responseCode = 0;
06793   rv = httpChannel->GetResponseStatus(&responseCode);
06794   if (NS_FAILED(rv) || responseCode != 200) {
06795     return NS_ERROR_FAILURE;
06796   }
06797 
06798   // if server cannot continue with byte range (206 status) and sending us whole object (200 status)
06799   // reset this seekable stream & try serve it to plugin instance as a file
06800   mStreamConverter = finalStreamListener;
06801   mRemoveMagicNumber = PR_TRUE;
06802 
06803   //get nsPluginStreamListenerPeer* ptr from finalStreamListener
06804   nsPluginStreamListenerPeer *pslp = NS_REINTERPRET_CAST(nsPluginStreamListenerPeer*,
06805                                                          finalStreamListener.get());
06806   rv = pslp->ServeStreamAsFile(request, ctxt);
06807   return rv;
06808 }
06809 
06810 NS_IMETHODIMP
06811 nsPluginByteRangeStreamListener::OnStopRequest(nsIRequest *request, nsISupports *ctxt,
06812                               nsresult status)
06813 {
06814   if (!mStreamConverter)
06815     return NS_ERROR_FAILURE;
06816 
06817   nsCOMPtr<nsIStreamListener> finalStreamListener = do_QueryReferent(mWeakPtrPluginStreamListenerPeer);
06818   if (!finalStreamListener)
06819     return NS_ERROR_FAILURE;
06820 
06821   if (mRemoveMagicNumber) {
06822     // remove magic number from container
06823     nsCOMPtr<nsISupportsPRUint32> container = do_QueryInterface(ctxt);
06824     if (container) {
06825       PRUint32 magicNumber = 0;
06826       container->GetData(&magicNumber);
06827       if (magicNumber == MAGIC_REQUEST_CONTEXT) {
06828         // to allow properly finish nsPluginStreamListenerPeer->OnStopRequest()
06829         // set it to something that is not the magic number.
06830         container->SetData(0);
06831       }
06832     } else {
06833       NS_WARNING("Bad state of nsPluginByteRangeStreamListener");
06834     }
06835   }
06836 
06837   return mStreamConverter->OnStopRequest(request, ctxt, status);
06838 }
06839 
06840 NS_IMETHODIMP
06841 nsPluginByteRangeStreamListener::OnDataAvailable(nsIRequest *request, nsISupports *ctxt,
06842                                 nsIInputStream *inStr, PRUint32 sourceOffset, PRUint32 count)
06843 {
06844   if (!mStreamConverter)
06845     return NS_ERROR_FAILURE;
06846 
06847   nsCOMPtr<nsIStreamListener> finalStreamListener = do_QueryReferent(mWeakPtrPluginStreamListenerPeer);
06848   if (!finalStreamListener)
06849     return NS_ERROR_FAILURE;
06850 
06851   return mStreamConverter->OnDataAvailable(request, ctxt, inStr, sourceOffset, count);
06852 }
06853 
06854 PRBool
06855 nsPluginStreamInfo::UseExistingPluginCacheFile(nsPluginStreamInfo* psi)
06856 {
06857 
06858   NS_ENSURE_ARG_POINTER(psi);
06859 
06860  if ( psi->mLength == mLength &&
06861       psi->mModified == mModified &&
06862       mStreamComplete &&
06863       !PL_strcmp(psi->mURL, mURL))
06864   {
06865     return PR_TRUE;
06866   }
06867   return PR_FALSE;
06868 }
06869 
06870 void
06871 nsPluginStreamInfo::SetStreamComplete(const PRBool complete)
06872 {
06873   mStreamComplete = complete;
06874 
06875   if (complete) {
06876     // We're done, release the request.
06877 
06878     SetRequest(nsnull);
06879   }
06880 }