LCOV - code coverage report
Current view: directory - dom/plugins/base - nsPluginHost.cpp (source / functions) Found Hit Coverage
Test: app.info Lines: 1846 448 24.3 %
Date: 2012-06-02 Functions: 118 29 24.6 %

       1                 : /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
       2                 : /* ***** BEGIN LICENSE BLOCK *****
       3                 :  * Version: MPL 1.1/GPL 2.0/LGPL 2.1
       4                 :  *
       5                 :  * The contents of this file are subject to the Mozilla Public License Version
       6                 :  * 1.1 (the "License"); you may not use this file except in compliance with
       7                 :  * the License. You may obtain a copy of the License at
       8                 :  * http://www.mozilla.org/MPL/
       9                 :  *
      10                 :  * Software distributed under the License is distributed on an "AS IS" basis,
      11                 :  * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
      12                 :  * for the specific language governing rights and limitations under the
      13                 :  * License.
      14                 :  *
      15                 :  * The Original Code is mozilla.org code.
      16                 :  *
      17                 :  * The Initial Developer of the Original Code is
      18                 :  * Netscape Communications Corporation.
      19                 :  * Portions created by the Initial Developer are Copyright (C) 1998
      20                 :  * the Initial Developer. All Rights Reserved.
      21                 :  *
      22                 :  * Contributor(s):
      23                 :  *   Sean Echevarria <sean@beatnik.com>
      24                 :  *   HÃ¥kan Waara <hwaara@chello.se>
      25                 :  *   Josh Aas <josh@mozilla.com>
      26                 :  *
      27                 :  * Alternatively, the contents of this file may be used under the terms of
      28                 :  * either the GNU General Public License Version 2 or later (the "GPL"), or
      29                 :  * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
      30                 :  * in which case the provisions of the GPL or the LGPL are applicable instead
      31                 :  * of those above. If you wish to allow use of your version of this file only
      32                 :  * under the terms of either the GPL or the LGPL, and not to allow others to
      33                 :  * use your version of this file under the terms of the MPL, indicate your
      34                 :  * decision by deleting the provisions above and replace them with the notice
      35                 :  * and other provisions required by the GPL or the LGPL. If you do not delete
      36                 :  * the provisions above, a recipient may use your version of this file under
      37                 :  * the terms of any one of the MPL, the GPL or the LGPL.
      38                 :  *
      39                 :  * ***** END LICENSE BLOCK ***** */
      40                 : 
      41                 : /* nsPluginHost.cpp - top-level plugin management code */
      42                 : 
      43                 : #include "nscore.h"
      44                 : #include "nsPluginHost.h"
      45                 : 
      46                 : #include <stdio.h>
      47                 : #include "prio.h"
      48                 : #include "prmem.h"
      49                 : #include "nsIComponentManager.h"
      50                 : #include "nsNPAPIPlugin.h"
      51                 : #include "nsNPAPIPluginStreamListener.h"
      52                 : #include "nsNPAPIPluginInstance.h"
      53                 : #include "nsIPluginStreamListener.h"
      54                 : #include "nsIHTTPHeaderListener.h"
      55                 : #include "nsIHttpHeaderVisitor.h"
      56                 : #include "nsIObserverService.h"
      57                 : #include "nsIHttpProtocolHandler.h"
      58                 : #include "nsIHttpChannel.h"
      59                 : #include "nsIHttpChannelInternal.h"
      60                 : #include "nsIUploadChannel.h"
      61                 : #include "nsIByteRangeRequest.h"
      62                 : #include "nsIStreamListener.h"
      63                 : #include "nsIInputStream.h"
      64                 : #include "nsIOutputStream.h"
      65                 : #include "nsIURL.h"
      66                 : #include "nsXPIDLString.h"
      67                 : #include "nsReadableUtils.h"
      68                 : #include "nsIProtocolProxyService.h"
      69                 : #include "nsIStreamConverterService.h"
      70                 : #include "nsIFile.h"
      71                 : #if defined(XP_MACOSX)
      72                 : #include "nsILocalFileMac.h"
      73                 : #endif
      74                 : #include "nsIInputStream.h"
      75                 : #include "nsIIOService.h"
      76                 : #include "nsIURL.h"
      77                 : #include "nsIChannel.h"
      78                 : #include "nsISeekableStream.h"
      79                 : #include "nsNetUtil.h"
      80                 : #include "nsIProgressEventSink.h"
      81                 : #include "nsIDocument.h"
      82                 : #include "nsICachingChannel.h"
      83                 : #include "nsHashtable.h"
      84                 : #include "nsIProxyInfo.h"
      85                 : #include "nsPluginLogging.h"
      86                 : #include "nsIPrefBranch.h"
      87                 : #include "nsIScriptChannel.h"
      88                 : #include "nsIBlocklistService.h"
      89                 : #include "nsVersionComparator.h"
      90                 : #include "nsIPrivateBrowsingService.h"
      91                 : #include "nsIObjectLoadingContent.h"
      92                 : #include "nsIWritablePropertyBag2.h"
      93                 : #include "nsPluginStreamListenerPeer.h"
      94                 : 
      95                 : #include "nsEnumeratorUtils.h"
      96                 : #include "nsXPCOM.h"
      97                 : #include "nsXPCOMCID.h"
      98                 : #include "nsISupportsPrimitives.h"
      99                 : 
     100                 : #include "nsXULAppAPI.h"
     101                 : #include "nsIXULRuntime.h"
     102                 : 
     103                 : // for the dialog
     104                 : #include "nsIStringBundle.h"
     105                 : #include "nsIWindowWatcher.h"
     106                 : #include "nsPIDOMWindow.h"
     107                 : 
     108                 : #include "nsIScriptGlobalObject.h"
     109                 : #include "nsIScriptGlobalObjectOwner.h"
     110                 : #include "nsIPrincipal.h"
     111                 : 
     112                 : #include "nsNetCID.h"
     113                 : #include "nsIDOMPlugin.h"
     114                 : #include "nsIDOMMimeType.h"
     115                 : #include "nsMimeTypes.h"
     116                 : #include "prprf.h"
     117                 : #include "nsThreadUtils.h"
     118                 : #include "nsIInputStreamTee.h"
     119                 : #include "nsIInterfaceInfoManager.h"
     120                 : #include "xptinfo.h"
     121                 : 
     122                 : #include "nsIMIMEService.h"
     123                 : #include "nsCExternalHandlerService.h"
     124                 : #include "nsILocalFile.h"
     125                 : #include "nsIFileChannel.h"
     126                 : 
     127                 : #include "nsPluginSafety.h"
     128                 : 
     129                 : #include "nsICharsetConverterManager.h"
     130                 : #include "nsIPlatformCharset.h"
     131                 : 
     132                 : #include "nsIDirectoryService.h"
     133                 : #include "nsDirectoryServiceDefs.h"
     134                 : #include "nsXULAppAPI.h"
     135                 : #include "nsAppDirectoryServiceDefs.h"
     136                 : #include "nsIFile.h"
     137                 : #include "nsPluginDirServiceProvider.h"
     138                 : #include "nsPluginError.h"
     139                 : 
     140                 : #include "nsUnicharUtils.h"
     141                 : #include "nsPluginManifestLineReader.h"
     142                 : 
     143                 : #include "nsIWeakReferenceUtils.h"
     144                 : #include "nsIDOMElement.h"
     145                 : #include "nsIDOMHTMLObjectElement.h"
     146                 : #include "nsIDOMHTMLEmbedElement.h"
     147                 : #include "nsIPresShell.h"
     148                 : #include "nsIWebNavigation.h"
     149                 : #include "nsISupportsArray.h"
     150                 : #include "nsIDocShell.h"
     151                 : #include "nsPluginNativeWindow.h"
     152                 : #include "nsIScriptSecurityManager.h"
     153                 : #include "nsIContentPolicy.h"
     154                 : #include "nsContentPolicyUtils.h"
     155                 : #include "nsContentErrors.h"
     156                 : #include "mozilla/TimeStamp.h"
     157                 : #include "mozilla/Telemetry.h"
     158                 : #include "nsIImageLoadingContent.h"
     159                 : #include "mozilla/Preferences.h"
     160                 : 
     161                 : #if defined(XP_WIN)
     162                 : #include "nsIWindowMediator.h"
     163                 : #include "nsIBaseWindow.h"
     164                 : #include "windows.h"
     165                 : #include "winbase.h"
     166                 : #endif
     167                 : 
     168                 : #ifdef ANDROID
     169                 : #include <android/log.h>
     170                 : #define LOG(args...)  __android_log_print(ANDROID_LOG_INFO, "GeckoPlugins" , ## args)
     171                 : #endif
     172                 : 
     173                 : using namespace mozilla;
     174                 : using mozilla::TimeStamp;
     175                 : 
     176                 : // Null out a strong ref to a linked list iteratively to avoid
     177                 : // exhausting the stack (bug 486349).
     178                 : #define NS_ITERATIVE_UNREF_LIST(type_, list_, mNext_)                \
     179                 :   {                                                                  \
     180                 :     while (list_) {                                                  \
     181                 :       type_ temp = list_->mNext_;                                    \
     182                 :       list_->mNext_ = nsnull;                                        \
     183                 :       list_ = temp;                                                  \
     184                 :     }                                                                \
     185                 :   }
     186                 : 
     187                 : // this is the name of the directory which will be created
     188                 : // to cache temporary files.
     189                 : #define kPluginTmpDirName NS_LITERAL_CSTRING("plugtmp")
     190                 : 
     191                 : // Version of cached plugin info
     192                 : // 0.01 first implementation
     193                 : // 0.02 added caching of CanUnload to fix bug 105935
     194                 : // 0.03 changed name, description and mime desc from string to bytes, bug 108246
     195                 : // 0.04 added new mime entry point on Mac, bug 113464
     196                 : // 0.05 added new entry point check for the default plugin, bug 132430
     197                 : // 0.06 strip off suffixes in mime description strings, bug 53895
     198                 : // 0.07 changed nsIRegistry to flat file support for caching plugins info
     199                 : // 0.08 mime entry point on MachO, bug 137535
     200                 : // 0.09 the file encoding is changed to UTF-8, bug 420285
     201                 : // 0.10 added plugin versions on appropriate platforms, bug 427743
     202                 : // 0.11 file name and full path fields now store expected values on all platforms, bug 488181
     203                 : // 0.12 force refresh due to quicktime pdf claim fix, bug 611197
     204                 : // 0.13 add architecture and list of invalid plugins, bug 616271
     205                 : // 0.14 force refresh due to locale comparison fix, bug 611296
     206                 : // 0.15 force refresh due to bug in reading Java plist MIME data, bug 638171
     207                 : // The current plugin registry version (and the maximum version we know how to read)
     208                 : static const char *kPluginRegistryVersion = "0.15";
     209                 : // The minimum registry version we know how to read
     210                 : static const char *kMinimumRegistryVersion = "0.9";
     211                 : 
     212                 : static NS_DEFINE_IID(kIPluginTagInfoIID, NS_IPLUGINTAGINFO_IID);
     213                 : static const char kDirectoryServiceContractID[] = "@mozilla.org/file/directory_service;1";
     214                 : 
     215                 : // Registry keys for caching plugin info
     216                 : static const char kPluginsRootKey[] = "software/plugins";
     217                 : static const char kPluginsNameKey[] = "name";
     218                 : static const char kPluginsDescKey[] = "description";
     219                 : static const char kPluginsFilenameKey[] = "filename";
     220                 : static const char kPluginsFullpathKey[] = "fullpath";
     221                 : static const char kPluginsModTimeKey[] = "lastModTimeStamp";
     222                 : static const char kPluginsCanUnload[] = "canUnload";
     223                 : static const char kPluginsVersionKey[] = "version";
     224                 : static const char kPluginsMimeTypeKey[] = "mimetype";
     225                 : static const char kPluginsMimeDescKey[] = "description";
     226                 : static const char kPluginsMimeExtKey[] = "extension";
     227                 : 
     228                 : #define kPluginRegistryFilename NS_LITERAL_CSTRING("pluginreg.dat")
     229                 : 
     230                 : #ifdef PLUGIN_LOGGING
     231                 : PRLogModuleInfo* nsPluginLogging::gNPNLog = nsnull;
     232                 : PRLogModuleInfo* nsPluginLogging::gNPPLog = nsnull;
     233                 : PRLogModuleInfo* nsPluginLogging::gPluginLog = nsnull;
     234                 : #endif
     235                 : 
     236                 : #define BRAND_PROPERTIES_URL "chrome://branding/locale/brand.properties"
     237                 : #define PLUGIN_PROPERTIES_URL "chrome://global/locale/downloadProgress.properties"
     238                 : 
     239                 : // #defines for plugin cache and prefs
     240                 : #define NS_PREF_MAX_NUM_CACHED_INSTANCES "browser.plugins.max_num_cached_plugins"
     241                 : // Raise this from '10' to '50' to work around a bug in Apple's current Java
     242                 : // plugins on OS X Lion and SnowLeopard.  See bug 705931.
     243                 : #define DEFAULT_NUMBER_OF_STOPPED_INSTANCES 50
     244                 : 
     245                 : #ifdef CALL_SAFETY_ON
     246                 : // By default we run OOPP, so we don't want to cover up crashes.
     247                 : bool gSkipPluginSafeCalls = true;
     248                 : #endif
     249                 : 
     250                 : nsIFile *nsPluginHost::sPluginTempDir;
     251                 : nsPluginHost *nsPluginHost::sInst;
     252                 : 
     253               0 : NS_IMPL_ISUPPORTS0(nsInvalidPluginTag)
     254                 : 
     255               0 : nsInvalidPluginTag::nsInvalidPluginTag(const char* aFullPath, PRInt64 aLastModifiedTime)
     256                 : : mFullPath(aFullPath),
     257                 :   mLastModifiedTime(aLastModifiedTime),
     258               0 :   mSeen(false)
     259                 : {
     260                 :   
     261               0 : }
     262                 : 
     263               0 : nsInvalidPluginTag::~nsInvalidPluginTag()
     264                 : {
     265                 :   
     266               0 : }
     267                 : 
     268                 : // flat file reg funcs
     269                 : static
     270              29 : bool ReadSectionHeader(nsPluginManifestLineReader& reader, const char *token)
     271                 : {
     272              15 :   do {
     273              29 :     if (*reader.LinePtr() == '[') {
     274              14 :       char* p = reader.LinePtr() + (reader.LineLength() - 1);
     275              14 :       if (*p != ']')
     276               0 :         break;
     277              14 :       *p = 0;
     278                 : 
     279                 :       char* values[1];
     280              14 :       if (1 != reader.ParseLine(values, 1))
     281               0 :         break;
     282                 :       // ignore the leading '['
     283              14 :       if (PL_strcmp(values[0]+1, token)) {
     284               0 :         break; // it's wrong token
     285                 :       }
     286              14 :       return true;
     287                 :     }
     288                 :   } while (reader.NextLine());
     289               0 :   return false;
     290                 : }
     291                 : 
     292                 : // Little helper struct to asynchronously reframe any presentations (embedded)
     293                 : // or reload any documents (full-page), that contained plugins
     294                 : // which were shutdown as a result of a plugins.refresh(1)
     295               0 : class nsPluginDocReframeEvent: public nsRunnable {
     296                 : public:
     297               0 :   nsPluginDocReframeEvent(nsISupportsArray* aDocs) { mDocs = aDocs; }
     298                 : 
     299                 :   NS_DECL_NSIRUNNABLE
     300                 : 
     301                 :   nsCOMPtr<nsISupportsArray> mDocs;
     302                 : };
     303                 : 
     304               0 : NS_IMETHODIMP nsPluginDocReframeEvent::Run() {
     305               0 :   NS_ENSURE_TRUE(mDocs, NS_ERROR_FAILURE);
     306                 : 
     307                 :   PRUint32 c;
     308               0 :   mDocs->Count(&c);
     309                 : 
     310                 :   // for each document (which previously had a running instance), tell
     311                 :   // the frame constructor to rebuild
     312               0 :   for (PRUint32 i = 0; i < c; i++) {
     313               0 :     nsCOMPtr<nsIDocument> doc (do_QueryElementAt(mDocs, i));
     314               0 :     if (doc) {
     315               0 :       nsIPresShell *shell = doc->GetShell();
     316                 : 
     317                 :       // if this document has a presentation shell, then it has frames and can be reframed
     318               0 :       if (shell) {
     319                 :         /* A reframe will cause a fresh object frame, instance owner, and instance
     320                 :          * to be created. Reframing of the entire document is necessary as we may have
     321                 :          * recently found new plugins and we want a shot at trying to use them instead
     322                 :          * of leaving alternate renderings.
     323                 :          * We do not want to completely reload all the documents that had running plugins
     324                 :          * because we could possibly trigger a script to run in the unload event handler
     325                 :          * which may want to access our defunct plugin and cause us to crash.
     326                 :          */
     327                 : 
     328               0 :         shell->ReconstructFrames(); // causes reframe of document
     329                 :       } else {  // no pres shell --> full-page plugin
     330                 : 
     331               0 :         NS_NOTREACHED("all plugins should have a pres shell!");
     332                 : 
     333                 :       }
     334                 :     }
     335                 :   }
     336                 : 
     337               0 :   return mDocs->Clear();
     338                 : }
     339                 : 
     340             173 : static bool UnloadPluginsASAP()
     341                 : {
     342                 :   nsresult rv;
     343             346 :   nsCOMPtr<nsIPrefBranch> pref(do_GetService(NS_PREFSERVICE_CONTRACTID, &rv));
     344             173 :   if (NS_SUCCEEDED(rv)) {
     345             173 :     bool unloadPluginsASAP = false;
     346             173 :     rv = pref->GetBoolPref("dom.ipc.plugins.unloadASAP", &unloadPluginsASAP);
     347             173 :     if (NS_SUCCEEDED(rv)) {
     348               0 :       return unloadPluginsASAP;
     349                 :     }
     350                 :   }
     351                 : 
     352             173 :   return false;
     353                 : }
     354                 : 
     355             173 : nsPluginHost::nsPluginHost()
     356                 :   // No need to initialize members to nsnull, false etc because this class
     357                 :   // has a zeroing operator new.
     358                 : {
     359                 :   // check to see if pref is set at startup to let plugins take over in
     360                 :   // full page mode for certain image mime types that we handle internally
     361             173 :   mPrefService = do_GetService(NS_PREFSERVICE_CONTRACTID);
     362             173 :   if (mPrefService) {
     363                 :     bool tmp;
     364             173 :     nsresult rv = mPrefService->GetBoolPref("plugin.override_internal_types",
     365             173 :                                             &tmp);
     366             173 :     if (NS_SUCCEEDED(rv)) {
     367             173 :       mOverrideInternalTypes = tmp;
     368                 :     }
     369                 : 
     370             173 :     rv = mPrefService->GetBoolPref("plugin.disable", &tmp);
     371             173 :     if (NS_SUCCEEDED(rv)) {
     372               0 :       mPluginsDisabled = tmp;
     373                 :     }
     374                 :   }
     375                 : 
     376                 :   nsCOMPtr<nsIObserverService> obsService =
     377             346 :     mozilla::services::GetObserverService();
     378             173 :   if (obsService) {
     379             173 :     obsService->AddObserver(this, NS_XPCOM_SHUTDOWN_OBSERVER_ID, false);
     380             173 :     obsService->AddObserver(this, NS_PRIVATE_BROWSING_SWITCH_TOPIC, false);
     381                 : #ifdef MOZ_WIDGET_ANDROID
     382                 :     obsService->AddObserver(this, "application-foreground", false);
     383                 :     obsService->AddObserver(this, "application-background", false);
     384                 : #endif
     385                 :   }
     386                 : 
     387                 : #ifdef PLUGIN_LOGGING
     388             173 :   nsPluginLogging::gNPNLog = PR_NewLogModule(NPN_LOG_NAME);
     389             173 :   nsPluginLogging::gNPPLog = PR_NewLogModule(NPP_LOG_NAME);
     390             173 :   nsPluginLogging::gPluginLog = PR_NewLogModule(PLUGIN_LOG_NAME);
     391                 : 
     392             173 :   PR_LOG(nsPluginLogging::gNPNLog, PLUGIN_LOG_ALWAYS,("NPN Logging Active!\n"));
     393             173 :   PR_LOG(nsPluginLogging::gPluginLog, PLUGIN_LOG_ALWAYS,("General Plugin Logging Active! (nsPluginHost::ctor)\n"));
     394             173 :   PR_LOG(nsPluginLogging::gNPPLog, PLUGIN_LOG_ALWAYS,("NPP Logging Active!\n"));
     395                 : 
     396             173 :   PLUGIN_LOG(PLUGIN_LOG_ALWAYS,("nsPluginHost::ctor\n"));
     397             173 :   PR_LogFlush();
     398                 : #endif
     399                 : 
     400                 : #ifdef MAC_CARBON_PLUGINS
     401                 :   mVisiblePluginTimer = do_CreateInstance(NS_TIMER_CONTRACTID);
     402                 :   mHiddenPluginTimer = do_CreateInstance(NS_TIMER_CONTRACTID);
     403                 : #endif
     404             173 : }
     405                 : 
     406             519 : nsPluginHost::~nsPluginHost()
     407                 : {
     408             173 :   PLUGIN_LOG(PLUGIN_LOG_ALWAYS,("nsPluginHost::dtor\n"));
     409                 : 
     410             173 :   Destroy();
     411             173 :   sInst = nsnull;
     412             346 : }
     413                 : 
     414           12452 : NS_IMPL_ISUPPORTS4(nsPluginHost,
     415                 :                    nsIPluginHost,
     416                 :                    nsIObserver,
     417                 :                    nsITimerCallback,
     418                 :                    nsISupportsWeakReference)
     419                 : 
     420                 : nsPluginHost*
     421             173 : nsPluginHost::GetInst()
     422                 : {
     423             173 :   if (!sInst) {
     424             173 :     sInst = new nsPluginHost();
     425             173 :     if (!sInst)
     426               0 :       return nsnull;
     427             173 :     NS_ADDREF(sInst);
     428                 :   }
     429                 : 
     430             173 :   NS_ADDREF(sInst);
     431             173 :   return sInst;
     432                 : }
     433                 : 
     434               0 : bool nsPluginHost::IsRunningPlugin(nsPluginTag * plugin)
     435                 : {
     436               0 :   if (!plugin || !plugin->mEntryPoint) {
     437               0 :     return false;
     438                 :   }
     439                 : 
     440               0 :   for (PRUint32 i = 0; i < mInstances.Length(); i++) {
     441               0 :     nsNPAPIPluginInstance *instance = mInstances[i].get();
     442               0 :     if (instance &&
     443               0 :         instance->GetPlugin() == plugin->mEntryPoint &&
     444               0 :         instance->IsRunning()) {
     445               0 :       return true;
     446                 :     }
     447                 :   }
     448                 : 
     449               0 :   return false;
     450                 : }
     451                 : 
     452               0 : nsresult nsPluginHost::ReloadPlugins(bool reloadPages)
     453                 : {
     454               0 :   PLUGIN_LOG(PLUGIN_LOG_NORMAL,
     455                 :   ("nsPluginHost::ReloadPlugins Begin reloadPages=%d, active_instance_count=%d\n",
     456                 :   reloadPages, mInstances.Length()));
     457                 : 
     458               0 :   nsresult rv = NS_OK;
     459                 : 
     460                 :   // this will create the initial plugin list out of cache
     461                 :   // if it was not created yet
     462               0 :   if (!mPluginsLoaded)
     463               0 :     return LoadPlugins();
     464                 : 
     465                 :   // we are re-scanning plugins. New plugins may have been added, also some
     466                 :   // plugins may have been removed, so we should probably shut everything down
     467                 :   // but don't touch running (active and not stopped) plugins
     468                 : 
     469                 :   // check if plugins changed, no need to do anything else
     470                 :   // if no changes to plugins have been made
     471                 :   // false instructs not to touch the plugin list, just to
     472                 :   // look for possible changes
     473               0 :   bool pluginschanged = true;
     474               0 :   FindPlugins(false, &pluginschanged);
     475                 : 
     476                 :   // if no changed detected, return an appropriate error code
     477               0 :   if (!pluginschanged)
     478               0 :     return NS_ERROR_PLUGINS_PLUGINSNOTCHANGED;
     479                 : 
     480               0 :   nsCOMPtr<nsISupportsArray> instsToReload;
     481               0 :   if (reloadPages) {
     482               0 :     NS_NewISupportsArray(getter_AddRefs(instsToReload));
     483                 : 
     484                 :     // Then stop any running plugin instances but hold on to the documents in the array
     485                 :     // We are going to need to restart the instances in these documents later
     486               0 :     DestroyRunningInstances(instsToReload, nsnull);
     487                 :   }
     488                 : 
     489                 :   // shutdown plugins and kill the list if there are no running plugins
     490               0 :   nsRefPtr<nsPluginTag> prev;
     491               0 :   nsRefPtr<nsPluginTag> next;
     492                 : 
     493               0 :   for (nsRefPtr<nsPluginTag> p = mPlugins; p != nsnull;) {
     494               0 :     next = p->mNext;
     495                 : 
     496                 :     // only remove our plugin from the list if it's not running.
     497               0 :     if (!IsRunningPlugin(p)) {
     498               0 :       if (p == mPlugins)
     499               0 :         mPlugins = next;
     500                 :       else
     501               0 :         prev->mNext = next;
     502                 : 
     503               0 :       p->mNext = nsnull;
     504                 : 
     505                 :       // attempt to unload plugins whenever they are removed from the list
     506               0 :       p->TryUnloadPlugin(false);
     507                 : 
     508               0 :       p = next;
     509               0 :       continue;
     510                 :     }
     511                 : 
     512               0 :     prev = p;
     513               0 :     p = next;
     514                 :   }
     515                 : 
     516                 :   // set flags
     517               0 :   mPluginsLoaded = false;
     518                 : 
     519                 :   // load them again
     520               0 :   rv = LoadPlugins();
     521                 : 
     522                 :   // If we have shut down any plugin instances, we've now got to restart them.
     523                 :   // Post an event to do the rest as we are going to be destroying the frame tree and we also want
     524                 :   // any posted unload events to finish
     525                 :   PRUint32 c;
     526               0 :   if (reloadPages &&
     527               0 :       instsToReload &&
     528               0 :       NS_SUCCEEDED(instsToReload->Count(&c)) &&
     529                 :       c > 0) {
     530               0 :     nsCOMPtr<nsIRunnable> ev = new nsPluginDocReframeEvent(instsToReload);
     531               0 :     if (ev)
     532               0 :       NS_DispatchToCurrentThread(ev);
     533                 :   }
     534                 : 
     535               0 :   PLUGIN_LOG(PLUGIN_LOG_NORMAL,
     536                 :   ("nsPluginHost::ReloadPlugins End active_instance_count=%d\n",
     537                 :   mInstances.Length()));
     538                 : 
     539               0 :   return rv;
     540                 : }
     541                 : 
     542                 : #define NS_RETURN_UASTRING_SIZE 128
     543                 : 
     544               0 : nsresult nsPluginHost::UserAgent(const char **retstring)
     545                 : {
     546                 :   static char resultString[NS_RETURN_UASTRING_SIZE];
     547                 :   nsresult res;
     548                 : 
     549               0 :   nsCOMPtr<nsIHttpProtocolHandler> http = do_GetService(NS_NETWORK_PROTOCOL_CONTRACTID_PREFIX "http", &res);
     550               0 :   if (NS_FAILED(res))
     551               0 :     return res;
     552                 : 
     553               0 :   nsCAutoString uaString;
     554               0 :   res = http->GetUserAgent(uaString);
     555                 : 
     556               0 :   if (NS_SUCCEEDED(res)) {
     557               0 :     if (NS_RETURN_UASTRING_SIZE > uaString.Length()) {
     558               0 :       PL_strcpy(resultString, uaString.get());
     559                 :     } else {
     560                 :       // Copy as much of UA string as we can (terminate at right-most space).
     561               0 :       PL_strncpy(resultString, uaString.get(), NS_RETURN_UASTRING_SIZE);
     562               0 :       for (int i = NS_RETURN_UASTRING_SIZE - 1; i >= 0; i--) {
     563               0 :         if (i == 0) {
     564               0 :           resultString[NS_RETURN_UASTRING_SIZE - 1] = '\0';
     565                 :         }
     566               0 :         else if (resultString[i] == ' ') {
     567               0 :           resultString[i] = '\0';
     568               0 :           break;
     569                 :         }
     570                 :       }
     571                 :     }
     572               0 :     *retstring = resultString;
     573                 :   }
     574                 :   else {
     575               0 :     *retstring = nsnull;
     576                 :   }
     577                 : 
     578               0 :   PLUGIN_LOG(PLUGIN_LOG_NORMAL, ("nsPluginHost::UserAgent return=%s\n", *retstring));
     579                 : 
     580               0 :   return res;
     581                 : }
     582                 : 
     583               0 : nsresult nsPluginHost::GetPrompt(nsIPluginInstanceOwner *aOwner, nsIPrompt **aPrompt)
     584                 : {
     585                 :   nsresult rv;
     586               0 :   nsCOMPtr<nsIPrompt> prompt;
     587               0 :   nsCOMPtr<nsIWindowWatcher> wwatch = do_GetService(NS_WINDOWWATCHER_CONTRACTID, &rv);
     588                 : 
     589               0 :   if (wwatch) {
     590               0 :     nsCOMPtr<nsIDOMWindow> domWindow;
     591               0 :     if (aOwner) {
     592               0 :       nsCOMPtr<nsIDocument> document;
     593               0 :       aOwner->GetDocument(getter_AddRefs(document));
     594               0 :       if (document) {
     595               0 :         domWindow = document->GetWindow();
     596                 :       }
     597                 :     }
     598                 : 
     599               0 :     if (!domWindow) {
     600               0 :       wwatch->GetWindowByName(NS_LITERAL_STRING("_content").get(), nsnull, getter_AddRefs(domWindow));
     601                 :     }
     602               0 :     rv = wwatch->GetNewPrompter(domWindow, getter_AddRefs(prompt));
     603                 :   }
     604                 : 
     605               0 :   NS_IF_ADDREF(*aPrompt = prompt);
     606               0 :   return rv;
     607                 : }
     608                 : 
     609               0 : nsresult nsPluginHost::GetURL(nsISupports* pluginInst,
     610                 :                               const char* url,
     611                 :                               const char* target,
     612                 :                               nsIPluginStreamListener* streamListener,
     613                 :                               const char* altHost,
     614                 :                               const char* referrer,
     615                 :                               bool forceJSEnabled)
     616                 : {
     617                 :   return GetURLWithHeaders(static_cast<nsNPAPIPluginInstance*>(pluginInst),
     618                 :                            url, target, streamListener, altHost, referrer,
     619               0 :                            forceJSEnabled, nsnull, nsnull);
     620                 : }
     621                 : 
     622               0 : nsresult nsPluginHost::GetURLWithHeaders(nsNPAPIPluginInstance* pluginInst,
     623                 :                                          const char* url,
     624                 :                                          const char* target,
     625                 :                                          nsIPluginStreamListener* streamListener,
     626                 :                                          const char* altHost,
     627                 :                                          const char* referrer,
     628                 :                                          bool forceJSEnabled,
     629                 :                                          PRUint32 getHeadersLength,
     630                 :                                          const char* getHeaders)
     631                 : {
     632                 :   // we can only send a stream back to the plugin (as specified by a
     633                 :   // null target) if we also have a nsIPluginStreamListener to talk to
     634               0 :   if (!target && !streamListener)
     635               0 :     return NS_ERROR_ILLEGAL_VALUE;
     636                 : 
     637               0 :   nsresult rv = DoURLLoadSecurityCheck(pluginInst, url);
     638               0 :   if (NS_FAILED(rv))
     639               0 :     return rv;
     640                 : 
     641               0 :   if (target) {
     642               0 :     nsCOMPtr<nsIPluginInstanceOwner> owner;
     643               0 :     rv = pluginInst->GetOwner(getter_AddRefs(owner));
     644               0 :     if (owner) {
     645               0 :       if ((0 == PL_strcmp(target, "newwindow")) ||
     646               0 :           (0 == PL_strcmp(target, "_new")))
     647               0 :         target = "_blank";
     648               0 :       else if (0 == PL_strcmp(target, "_current"))
     649               0 :         target = "_self";
     650                 : 
     651               0 :       rv = owner->GetURL(url, target, nsnull, nsnull, 0);
     652                 :     }
     653                 :   }
     654                 : 
     655               0 :   if (streamListener)
     656               0 :     rv = NewPluginURLStream(NS_ConvertUTF8toUTF16(url), pluginInst,
     657                 :                             streamListener, nsnull,
     658               0 :                             getHeaders, getHeadersLength);
     659                 : 
     660               0 :   return rv;
     661                 : }
     662                 : 
     663               0 : nsresult nsPluginHost::PostURL(nsISupports* pluginInst,
     664                 :                                     const char* url,
     665                 :                                     PRUint32 postDataLen,
     666                 :                                     const char* postData,
     667                 :                                     bool isFile,
     668                 :                                     const char* target,
     669                 :                                     nsIPluginStreamListener* streamListener,
     670                 :                                     const char* altHost,
     671                 :                                     const char* referrer,
     672                 :                                     bool forceJSEnabled,
     673                 :                                     PRUint32 postHeadersLength,
     674                 :                                     const char* postHeaders)
     675                 : {
     676                 :   nsresult rv;
     677                 : 
     678                 :   // we can only send a stream back to the plugin (as specified
     679                 :   // by a null target) if we also have a nsIPluginStreamListener
     680                 :   // to talk to also
     681               0 :   if (!target && !streamListener)
     682               0 :     return NS_ERROR_ILLEGAL_VALUE;
     683                 : 
     684               0 :   nsNPAPIPluginInstance* instance = static_cast<nsNPAPIPluginInstance*>(pluginInst);
     685                 : 
     686               0 :   rv = DoURLLoadSecurityCheck(instance, url);
     687               0 :   if (NS_FAILED(rv))
     688               0 :     return rv;
     689                 : 
     690               0 :   nsCOMPtr<nsIInputStream> postStream;
     691               0 :   if (isFile) {
     692               0 :     nsCOMPtr<nsIFile> file;
     693               0 :     rv = CreateTempFileToPost(postData, getter_AddRefs(file));
     694               0 :     if (NS_FAILED(rv))
     695               0 :       return rv;
     696                 : 
     697               0 :     nsCOMPtr<nsIInputStream> fileStream;
     698               0 :     rv = NS_NewLocalFileInputStream(getter_AddRefs(fileStream),
     699                 :                                     file,
     700                 :                                     PR_RDONLY,
     701                 :                                     0600,
     702                 :                                     nsIFileInputStream::DELETE_ON_CLOSE |
     703               0 :                                     nsIFileInputStream::CLOSE_ON_EOF);
     704               0 :     if (NS_FAILED(rv))
     705               0 :       return rv;
     706                 : 
     707               0 :     rv = NS_NewBufferedInputStream(getter_AddRefs(postStream), fileStream, 8192);
     708               0 :     if (NS_FAILED(rv))
     709               0 :       return rv;
     710                 :   } else {
     711                 :     char *dataToPost;
     712                 :     PRUint32 newDataToPostLen;
     713               0 :     ParsePostBufferToFixHeaders(postData, postDataLen, &dataToPost, &newDataToPostLen);
     714               0 :     if (!dataToPost)
     715               0 :       return NS_ERROR_UNEXPECTED;
     716                 : 
     717               0 :     nsCOMPtr<nsIStringInputStream> sis = do_CreateInstance("@mozilla.org/io/string-input-stream;1", &rv);
     718               0 :     if (!sis) {
     719               0 :       NS_Free(dataToPost);
     720               0 :       return rv;
     721                 :     }
     722                 : 
     723                 :     // data allocated by ParsePostBufferToFixHeaders() is managed and
     724                 :     // freed by the string stream.
     725               0 :     postDataLen = newDataToPostLen;
     726               0 :     sis->AdoptData(dataToPost, postDataLen);
     727               0 :     postStream = sis;
     728                 :   }
     729                 : 
     730               0 :   if (target) {
     731               0 :     nsCOMPtr<nsIPluginInstanceOwner> owner;
     732               0 :     rv = instance->GetOwner(getter_AddRefs(owner));
     733               0 :     if (owner) {
     734               0 :       if ((0 == PL_strcmp(target, "newwindow")) ||
     735               0 :           (0 == PL_strcmp(target, "_new"))) {
     736               0 :         target = "_blank";
     737               0 :       } else if (0 == PL_strcmp(target, "_current")) {
     738               0 :         target = "_self";
     739                 :       }
     740               0 :       rv = owner->GetURL(url, target, postStream,
     741               0 :                          (void*)postHeaders, postHeadersLength);
     742                 :     }
     743                 :   }
     744                 : 
     745                 :   // if we don't have a target, just create a stream.  This does
     746                 :   // NS_OpenURI()!
     747               0 :   if (streamListener)
     748               0 :     rv = NewPluginURLStream(NS_ConvertUTF8toUTF16(url), instance,
     749                 :                             streamListener,
     750               0 :                             postStream, postHeaders, postHeadersLength);
     751                 : 
     752               0 :   return rv;
     753                 : }
     754                 : 
     755                 : /* This method queries the prefs for proxy information.
     756                 :  * It has been tested and is known to work in the following three cases
     757                 :  * when no proxy host or port is specified
     758                 :  * when only the proxy host is specified
     759                 :  * when only the proxy port is specified
     760                 :  * This method conforms to the return code specified in
     761                 :  * http://developer.netscape.com/docs/manuals/proxy/adminnt/autoconf.htm#1020923
     762                 :  * with the exception that multiple values are not implemented.
     763                 :  */
     764                 : 
     765               0 : nsresult nsPluginHost::FindProxyForURL(const char* url, char* *result)
     766                 : {
     767               0 :   if (!url || !result) {
     768               0 :     return NS_ERROR_INVALID_ARG;
     769                 :   }
     770                 :   nsresult res;
     771                 : 
     772               0 :   nsCOMPtr<nsIURI> uriIn;
     773               0 :   nsCOMPtr<nsIProtocolProxyService> proxyService;
     774               0 :   nsCOMPtr<nsIIOService> ioService;
     775                 : 
     776               0 :   proxyService = do_GetService(NS_PROTOCOLPROXYSERVICE_CONTRACTID, &res);
     777               0 :   if (NS_FAILED(res) || !proxyService)
     778               0 :     return res;
     779                 : 
     780               0 :   ioService = do_GetService(NS_IOSERVICE_CONTRACTID, &res);
     781               0 :   if (NS_FAILED(res) || !ioService)
     782               0 :     return res;
     783                 : 
     784                 :   // make an nsURI from the argument url
     785               0 :   res = ioService->NewURI(nsDependentCString(url), nsnull, nsnull, getter_AddRefs(uriIn));
     786               0 :   if (NS_FAILED(res))
     787               0 :     return res;
     788                 : 
     789               0 :   nsCOMPtr<nsIProxyInfo> pi;
     790                 : 
     791               0 :   res = proxyService->Resolve(uriIn, 0, getter_AddRefs(pi));
     792               0 :   if (NS_FAILED(res))
     793               0 :     return res;
     794                 : 
     795               0 :   nsCAutoString host, type;
     796               0 :   PRInt32 port = -1;
     797                 : 
     798                 :   // These won't fail, and even if they do... we'll be ok.
     799               0 :   if (pi) {
     800               0 :     pi->GetType(type);
     801               0 :     pi->GetHost(host);
     802               0 :     pi->GetPort(&port);
     803                 :   }
     804                 : 
     805               0 :   if (!pi || host.IsEmpty() || port <= 0 || host.EqualsLiteral("direct")) {
     806               0 :     *result = PL_strdup("DIRECT");
     807               0 :   } else if (type.EqualsLiteral("http")) {
     808               0 :     *result = PR_smprintf("PROXY %s:%d", host.get(), port);
     809               0 :   } else if (type.EqualsLiteral("socks4")) {
     810               0 :     *result = PR_smprintf("SOCKS %s:%d", host.get(), port);
     811               0 :   } else if (type.EqualsLiteral("socks")) {
     812                 :     // XXX - this is socks5, but there is no API for us to tell the
     813                 :     // plugin that fact. SOCKS for now, in case the proxy server
     814                 :     // speaks SOCKS4 as well. See bug 78176
     815                 :     // For a long time this was returning an http proxy type, so
     816                 :     // very little is probably broken by this
     817               0 :     *result = PR_smprintf("SOCKS %s:%d", host.get(), port);
     818                 :   } else {
     819               0 :     NS_ASSERTION(false, "Unknown proxy type!");
     820               0 :     *result = PL_strdup("DIRECT");
     821                 :   }
     822                 : 
     823               0 :   if (nsnull == *result)
     824               0 :     res = NS_ERROR_OUT_OF_MEMORY;
     825                 : 
     826               0 :   return res;
     827                 : }
     828                 : 
     829               0 : nsresult nsPluginHost::Init()
     830                 : {
     831               0 :   return NS_OK;
     832                 : }
     833                 : 
     834             346 : nsresult nsPluginHost::Destroy()
     835                 : {
     836             346 :   PLUGIN_LOG(PLUGIN_LOG_NORMAL, ("nsPluginHost::Destroy Called\n"));
     837                 : 
     838             346 :   if (mIsDestroyed)
     839             173 :     return NS_OK;
     840                 : 
     841             173 :   mIsDestroyed = true;
     842                 : 
     843                 :   // we should call nsIPluginInstance::Stop and nsIPluginInstance::SetWindow
     844                 :   // for those plugins who want it
     845             173 :   DestroyRunningInstances(nsnull, nsnull);
     846                 : 
     847                 :   nsPluginTag *pluginTag;
     848             346 :   for (pluginTag = mPlugins; pluginTag; pluginTag = pluginTag->mNext) {
     849             173 :     pluginTag->TryUnloadPlugin(true);
     850                 :   }
     851                 : 
     852             173 :   NS_ITERATIVE_UNREF_LIST(nsRefPtr<nsPluginTag>, mPlugins, mNext);
     853             173 :   NS_ITERATIVE_UNREF_LIST(nsRefPtr<nsPluginTag>, mCachedPlugins, mNext);
     854             173 :   NS_ITERATIVE_UNREF_LIST(nsRefPtr<nsInvalidPluginTag>, mInvalidPlugins, mNext);
     855                 : 
     856                 :   // Lets remove any of the temporary files that we created.
     857             173 :   if (sPluginTempDir) {
     858               0 :     sPluginTempDir->Remove(true);
     859               0 :     NS_RELEASE(sPluginTempDir);
     860                 :   }
     861                 : 
     862                 : #ifdef XP_WIN
     863                 :   if (mPrivateDirServiceProvider) {
     864                 :     nsCOMPtr<nsIDirectoryService> dirService =
     865                 :       do_GetService(kDirectoryServiceContractID);
     866                 :     if (dirService)
     867                 :       dirService->UnregisterProvider(mPrivateDirServiceProvider);
     868                 :     mPrivateDirServiceProvider = nsnull;
     869                 :   }
     870                 : #endif /* XP_WIN */
     871                 : 
     872             173 :   mPrefService = nsnull; // release prefs service to avoid leaks!
     873                 : 
     874             173 :   return NS_OK;
     875                 : }
     876                 : 
     877               0 : void nsPluginHost::OnPluginInstanceDestroyed(nsPluginTag* aPluginTag)
     878                 : {
     879               0 :   bool hasInstance = false;
     880               0 :   for (PRUint32 i = 0; i < mInstances.Length(); i++) {
     881               0 :     if (TagForPlugin(mInstances[i]->GetPlugin()) == aPluginTag) {
     882               0 :       hasInstance = true;
     883               0 :       break;
     884                 :     }
     885                 :   }
     886                 : 
     887                 :   // We have some options for unloading plugins if they have no instances.
     888                 :   //
     889                 :   // Unloading plugins immediately can be bad - some plugins retain state
     890                 :   // between instances even when there are none. This is largely limited to
     891                 :   // going from one page to another, so state is retained without an instance
     892                 :   // for only a very short period of time. In order to allow this to work
     893                 :   // we don't unload plugins immediately by default. This is supported
     894                 :   // via a hidden user pref though.
     895                 :   //
     896                 :   // Another reason not to unload immediately is that loading is expensive,
     897                 :   // and it is better to leave popular plugins loaded.
     898                 :   //
     899                 :   // Our default behavior is to try to unload a plugin three minutes after
     900                 :   // its last instance is destroyed. This seems like a reasonable compromise
     901                 :   // that allows us to reclaim memory while allowing short state retention
     902                 :   // and avoid perf hits for loading popular plugins.
     903               0 :   if (!hasInstance) {
     904               0 :     if (UnloadPluginsASAP()) {
     905               0 :       aPluginTag->TryUnloadPlugin(false);
     906                 :     } else {
     907               0 :       if (aPluginTag->mUnloadTimer) {
     908               0 :         aPluginTag->mUnloadTimer->Cancel();
     909                 :       } else {
     910               0 :         aPluginTag->mUnloadTimer = do_CreateInstance(NS_TIMER_CONTRACTID);
     911                 :       }
     912               0 :       aPluginTag->mUnloadTimer->InitWithCallback(this, 1000 * 60 * 3, nsITimer::TYPE_ONE_SHOT);
     913                 :     }
     914                 :   }
     915               0 : }
     916                 : 
     917                 : nsresult
     918               0 : nsPluginHost::GetPluginTempDir(nsIFile **aDir)
     919                 : {
     920               0 :   if (!sPluginTempDir) {
     921               0 :     nsCOMPtr<nsIFile> tmpDir;
     922                 :     nsresult rv = NS_GetSpecialDirectory(NS_OS_TEMP_DIR,
     923               0 :                                          getter_AddRefs(tmpDir));
     924               0 :     NS_ENSURE_SUCCESS(rv, rv);
     925                 : 
     926               0 :     rv = tmpDir->AppendNative(kPluginTmpDirName);
     927                 : 
     928                 :     // make it unique, and mode == 0700, not world-readable
     929               0 :     rv = tmpDir->CreateUnique(nsIFile::DIRECTORY_TYPE, 0700);
     930               0 :     NS_ENSURE_SUCCESS(rv, rv);
     931                 : 
     932               0 :     tmpDir.swap(sPluginTempDir);
     933                 :   }
     934                 : 
     935               0 :   return sPluginTempDir->Clone(aDir);
     936                 : }
     937                 : 
     938               0 : nsresult nsPluginHost::CreateListenerForChannel(nsIChannel* aChannel,
     939                 :                                                 nsObjectLoadingContent* aContent,
     940                 :                                                 nsIStreamListener** aListener)
     941                 : {
     942               0 :   NS_PRECONDITION(aChannel && aContent,
     943                 :                   "Invalid arguments to InstantiatePluginForChannel");
     944               0 :   nsCOMPtr<nsIURI> uri;
     945               0 :   nsresult rv = aChannel->GetURI(getter_AddRefs(uri));
     946               0 :   if (NS_FAILED(rv))
     947               0 :     return rv;
     948                 : 
     949                 : #ifdef PLUGIN_LOGGING
     950               0 :   if (PR_LOG_TEST(nsPluginLogging::gPluginLog, PLUGIN_LOG_NORMAL)) {
     951               0 :     nsCAutoString urlSpec;
     952               0 :     uri->GetAsciiSpec(urlSpec);
     953                 : 
     954               0 :     PR_LOG(nsPluginLogging::gPluginLog, PLUGIN_LOG_NORMAL,
     955                 :            ("nsPluginHost::InstantiatePluginForChannel Begin content=%p, url=%s\n",
     956                 :            aContent, urlSpec.get()));
     957                 : 
     958               0 :     PR_LogFlush();
     959                 :   }
     960                 : #endif
     961                 : 
     962                 :   // Note that we're not setting up a plugin instance here; the stream
     963                 :   // listener's OnStartRequest will handle doing that.
     964                 : 
     965               0 :   return NewEmbeddedPluginStreamListener(uri, aContent, nsnull, aListener);
     966                 : }
     967                 : 
     968                 : nsresult
     969               0 : nsPluginHost::InstantiateEmbeddedPlugin(const char *aMimeType, nsIURI* aURL,
     970                 :                                         nsObjectLoadingContent *aContent,
     971                 :                                         nsPluginInstanceOwner** aOwner)
     972                 : {
     973               0 :   NS_ENSURE_ARG_POINTER(aOwner);
     974                 : 
     975                 : #ifdef PLUGIN_LOGGING
     976               0 :   nsCAutoString urlSpec;
     977               0 :   if (aURL)
     978               0 :     aURL->GetAsciiSpec(urlSpec);
     979                 : 
     980               0 :   PR_LOG(nsPluginLogging::gPluginLog, PLUGIN_LOG_NORMAL,
     981                 :         ("nsPluginHost::InstantiateEmbeddedPlugin Begin mime=%s, url=%s\n",
     982                 :         aMimeType, urlSpec.get()));
     983                 : 
     984               0 :   PR_LogFlush();
     985                 : #endif
     986                 : 
     987               0 :   nsRefPtr<nsPluginInstanceOwner> instanceOwner = new nsPluginInstanceOwner();
     988               0 :   if (!instanceOwner) {
     989               0 :     return NS_ERROR_OUT_OF_MEMORY;
     990                 :   }
     991                 : 
     992               0 :   nsCOMPtr<nsIContent> ourContent = do_QueryInterface(static_cast<nsIImageLoadingContent*>(aContent));
     993               0 :   nsresult rv = instanceOwner->Init(ourContent);
     994               0 :   if (NS_FAILED(rv)) {
     995               0 :     return rv;
     996                 :   }
     997                 : 
     998               0 :   nsCOMPtr<nsIPluginTagInfo> pti;
     999               0 :   rv = instanceOwner->QueryInterface(kIPluginTagInfoIID, getter_AddRefs(pti));
    1000               0 :   if (NS_FAILED(rv)) {
    1001               0 :     return rv;
    1002                 :   }
    1003                 : 
    1004                 :   nsPluginTagType tagType;
    1005               0 :   rv = pti->GetTagType(&tagType);
    1006               0 :   if (NS_FAILED(rv)) {
    1007               0 :     return rv;
    1008                 :   }
    1009                 : 
    1010               0 :   if (tagType != nsPluginTagType_Embed &&
    1011                 :       tagType != nsPluginTagType_Applet &&
    1012                 :       tagType != nsPluginTagType_Object) {
    1013               0 :     return NS_ERROR_FAILURE;
    1014                 :   }
    1015                 : 
    1016                 :   // Security checks. Can't do security checks without a URI - hopefully the plugin
    1017                 :   // will take care of that.
    1018               0 :   if (aURL) {
    1019                 :     nsCOMPtr<nsIScriptSecurityManager> secMan =
    1020               0 :                     do_GetService(NS_SCRIPTSECURITYMANAGER_CONTRACTID, &rv);
    1021               0 :     if (NS_FAILED(rv))
    1022               0 :       return rv; // Better fail if we can't do security checks
    1023                 : 
    1024               0 :     nsCOMPtr<nsIDocument> doc;
    1025               0 :     instanceOwner->GetDocument(getter_AddRefs(doc));
    1026               0 :     if (!doc)
    1027               0 :       return NS_ERROR_NULL_POINTER;
    1028                 : 
    1029               0 :     rv = secMan->CheckLoadURIWithPrincipal(doc->NodePrincipal(), aURL, 0);
    1030               0 :     if (NS_FAILED(rv))
    1031               0 :       return rv;
    1032                 : 
    1033               0 :     nsCOMPtr<nsIDOMElement> elem;
    1034               0 :     pti->GetDOMElement(getter_AddRefs(elem));
    1035                 : 
    1036               0 :     PRInt16 shouldLoad = nsIContentPolicy::ACCEPT; // default permit
    1037                 :     nsresult rv =
    1038                 :       NS_CheckContentLoadPolicy(nsIContentPolicy::TYPE_OBJECT,
    1039                 :                                 aURL,
    1040               0 :                                 doc->NodePrincipal(),
    1041                 :                                 elem,
    1042               0 :                                 nsDependentCString(aMimeType ? aMimeType : ""),
    1043                 :                                 nsnull, //extra
    1044               0 :                                 &shouldLoad);
    1045               0 :     if (NS_FAILED(rv) || NS_CP_REJECTED(shouldLoad))
    1046               0 :       return NS_ERROR_CONTENT_BLOCKED_SHOW_ALT;
    1047                 :   }
    1048                 : 
    1049               0 :   bool isJava = false;
    1050               0 :   nsPluginTag* pluginTag = FindPluginForType(aMimeType, true);
    1051               0 :   if (pluginTag) {
    1052               0 :     isJava = pluginTag->mIsJavaPlugin;
    1053                 :   }
    1054                 : 
    1055                 :   // Determine if the scheme of this URL is one we can handle internally because we should
    1056                 :   // only open the initial stream if it's one that we can handle internally. Otherwise
    1057                 :   // |NS_OpenURI| in |InstantiateEmbeddedPlugin| may open up a OS protocal registered helper app
    1058                 :   // Also set bCanHandleInternally to true if aAllowOpeningStreams is
    1059                 :   // false; we don't want to do any network traffic in that case.
    1060               0 :   bool bCanHandleInternally = false;
    1061               0 :   nsCAutoString scheme;
    1062               0 :   if (aURL && NS_SUCCEEDED(aURL->GetScheme(scheme))) {
    1063               0 :       nsCAutoString contractID(NS_NETWORK_PROTOCOL_CONTRACTID_PREFIX);
    1064               0 :       contractID += scheme;
    1065               0 :       ToLowerCase(contractID);
    1066               0 :       nsCOMPtr<nsIProtocolHandler> handler = do_GetService(contractID.get());
    1067               0 :       if (handler)
    1068               0 :         bCanHandleInternally = true;
    1069                 :   }
    1070                 : 
    1071                 :   // if we don't have a MIME type at this point, we still have one more chance by
    1072                 :   // opening the stream and seeing if the server hands one back
    1073               0 :   if (!aMimeType) {
    1074               0 :     if (bCanHandleInternally && !aContent->SrcStreamLoading()) {
    1075               0 :       NewEmbeddedPluginStream(aURL, aContent, nsnull);
    1076                 :     }
    1077               0 :     return NS_ERROR_FAILURE;
    1078                 :   }
    1079                 : 
    1080               0 :   rv = SetUpPluginInstance(aMimeType, aURL, instanceOwner);
    1081               0 :   if (NS_FAILED(rv)) {
    1082               0 :     return NS_ERROR_FAILURE;
    1083                 :   }
    1084                 : 
    1085               0 :   nsRefPtr<nsNPAPIPluginInstance> instance;
    1086               0 :   rv = instanceOwner->GetInstance(getter_AddRefs(instance));
    1087               0 :   if (NS_FAILED(rv)) {
    1088               0 :     return rv;
    1089                 :   }
    1090                 : 
    1091               0 :   if (instance) {
    1092               0 :     instanceOwner->CreateWidget();
    1093                 : 
    1094                 :     // If we've got a native window, the let the plugin know about it.
    1095               0 :     instanceOwner->CallSetWindow();
    1096                 : 
    1097                 :     // create an initial stream with data
    1098                 :     // don't make the stream if it's a java applet or we don't have SRC or DATA attribute
    1099                 :     // no need to check for "data" as it would have been converted to "src"
    1100                 :     const char *value;
    1101               0 :     bool havedata = NS_SUCCEEDED(pti->GetAttribute("SRC", &value));
    1102               0 :     if (havedata && !isJava && bCanHandleInternally && !aContent->SrcStreamLoading()) {
    1103               0 :       NewEmbeddedPluginStream(aURL, aContent, instance.get());
    1104                 :     }
    1105                 :   }
    1106                 : 
    1107                 :   // At this point we consider instantiation to be successful. Do not return an error.
    1108               0 :   instanceOwner.forget(aOwner);
    1109                 : 
    1110                 : #ifdef PLUGIN_LOGGING
    1111               0 :   nsCAutoString urlSpec2;
    1112               0 :   if (aURL != nsnull) aURL->GetAsciiSpec(urlSpec2);
    1113                 : 
    1114               0 :   PR_LOG(nsPluginLogging::gPluginLog, PLUGIN_LOG_NORMAL,
    1115                 :         ("nsPluginHost::InstantiateEmbeddedPlugin Finished mime=%s, rv=%d, url=%s\n",
    1116                 :         aMimeType, rv, urlSpec2.get()));
    1117                 : 
    1118               0 :   PR_LogFlush();
    1119                 : #endif
    1120                 : 
    1121               0 :   return NS_OK;
    1122                 : }
    1123                 : 
    1124               0 : nsresult nsPluginHost::InstantiateFullPagePlugin(const char *aMimeType,
    1125                 :                                                  nsIURI* aURI,
    1126                 :                                                  nsObjectLoadingContent *aContent,
    1127                 :                                                  nsPluginInstanceOwner **aOwner,
    1128                 :                                                  nsIStreamListener **aStreamListener)
    1129                 : {
    1130                 : #ifdef PLUGIN_LOGGING
    1131               0 :   nsCAutoString urlSpec;
    1132               0 :   aURI->GetSpec(urlSpec);
    1133               0 :   PLUGIN_LOG(PLUGIN_LOG_NORMAL,
    1134                 :   ("nsPluginHost::InstantiateFullPagePlugin Begin mime=%s, url=%s\n",
    1135                 :   aMimeType, urlSpec.get()));
    1136                 : #endif
    1137                 : 
    1138               0 :   nsRefPtr<nsPluginInstanceOwner> instanceOwner = new nsPluginInstanceOwner();
    1139               0 :   if (!instanceOwner) {
    1140               0 :     return NS_ERROR_OUT_OF_MEMORY;
    1141                 :   }
    1142                 : 
    1143               0 :   nsCOMPtr<nsIContent> ourContent = do_QueryInterface(static_cast<nsIImageLoadingContent*>(aContent));
    1144               0 :   nsresult rv = instanceOwner->Init(ourContent);
    1145               0 :   if (NS_FAILED(rv)) {
    1146               0 :     return rv;
    1147                 :   }
    1148                 : 
    1149               0 :   rv = SetUpPluginInstance(aMimeType, aURI, instanceOwner);
    1150               0 :   if (NS_FAILED(rv)) {
    1151               0 :     return rv;
    1152                 :   }
    1153                 : 
    1154               0 :   nsRefPtr<nsNPAPIPluginInstance> instance;
    1155               0 :   instanceOwner->GetInstance(getter_AddRefs(instance));
    1156               0 :   if (!instance) {
    1157               0 :     return NS_ERROR_FAILURE;
    1158                 :   }
    1159                 : 
    1160               0 :   NPWindow* win = nsnull;
    1161               0 :   instanceOwner->GetWindow(win);
    1162               0 :   if (!win) {
    1163               0 :     return NS_ERROR_FAILURE;
    1164                 :   }
    1165                 : 
    1166                 :   // Set up any widget that might be required.
    1167               0 :   instanceOwner->CreateWidget();
    1168               0 :   instanceOwner->CallSetWindow();
    1169                 : 
    1170               0 :   rv = NewFullPagePluginStream(aURI, instance.get(), aStreamListener);
    1171               0 :   if (NS_FAILED(rv)) {
    1172               0 :     return rv;
    1173                 :   }
    1174                 : 
    1175                 :   // Call SetWindow again in case something changed.
    1176               0 :   instanceOwner->CallSetWindow();
    1177                 : 
    1178               0 :   instanceOwner.forget(aOwner);
    1179                 : 
    1180               0 :   PLUGIN_LOG(PLUGIN_LOG_NORMAL,
    1181                 :   ("nsPluginHost::InstantiateFullPagePlugin End mime=%s, rv=%d, url=%s\n",
    1182                 :   aMimeType, rv, urlSpec.get()));
    1183                 : 
    1184               0 :   return NS_OK;
    1185                 : }
    1186                 : 
    1187                 : nsPluginTag*
    1188               0 : nsPluginHost::FindTagForLibrary(PRLibrary* aLibrary)
    1189                 : {
    1190                 :   nsPluginTag* pluginTag;
    1191               0 :   for (pluginTag = mPlugins; pluginTag; pluginTag = pluginTag->mNext) {
    1192               0 :     if (pluginTag->mLibrary == aLibrary) {
    1193               0 :       return pluginTag;
    1194                 :     }
    1195                 :   }
    1196               0 :   return nsnull;
    1197                 : }
    1198                 : 
    1199                 : nsPluginTag*
    1200               0 : nsPluginHost::TagForPlugin(nsNPAPIPlugin* aPlugin)
    1201                 : {
    1202                 :   nsPluginTag* pluginTag;
    1203               0 :   for (pluginTag = mPlugins; pluginTag; pluginTag = pluginTag->mNext) {
    1204               0 :     if (pluginTag->mEntryPoint == aPlugin) {
    1205               0 :       return pluginTag;
    1206                 :     }
    1207                 :   }
    1208                 :   // a plugin should never exist without a corresponding tag
    1209               0 :   NS_ERROR("TagForPlugin has failed");
    1210               0 :   return nsnull;
    1211                 : }
    1212                 : 
    1213               0 : nsresult nsPluginHost::SetUpPluginInstance(const char *aMimeType,
    1214                 :                                            nsIURI *aURL,
    1215                 :                                            nsIPluginInstanceOwner *aOwner)
    1216                 : {
    1217               0 :   NS_ENSURE_ARG_POINTER(aOwner);
    1218                 : 
    1219               0 :   nsresult rv = NS_OK;
    1220                 : 
    1221               0 :   rv = TrySetUpPluginInstance(aMimeType, aURL, aOwner);
    1222                 : 
    1223                 :   // if we fail, refresh plugin list just in case the plugin has been
    1224                 :   // just added and try to instantiate plugin instance again, see bug 143178
    1225               0 :   if (NS_FAILED(rv)) {
    1226                 :     // we should also make sure not to do this more than once per page
    1227                 :     // so if there are a few embed tags with unknown plugins,
    1228                 :     // we don't get unnecessary overhead
    1229                 :     // let's cache document to decide whether this is the same page or not
    1230               0 :     nsCOMPtr<nsIDocument> document;
    1231               0 :     aOwner->GetDocument(getter_AddRefs(document));
    1232                 : 
    1233               0 :     nsCOMPtr<nsIDocument> currentdocument = do_QueryReferent(mCurrentDocument);
    1234               0 :     if (document == currentdocument)
    1235               0 :       return rv;
    1236                 : 
    1237               0 :     mCurrentDocument = do_GetWeakReference(document);
    1238                 : 
    1239                 :     // ReloadPlugins will do the job smartly: nothing will be done
    1240                 :     // if no changes detected, in such a case just return
    1241               0 :     if (NS_ERROR_PLUGINS_PLUGINSNOTCHANGED == ReloadPlugins(false))
    1242               0 :       return rv;
    1243                 : 
    1244                 :     // other failure return codes may be not fatal, so we can still try
    1245               0 :     aOwner->SetInstance(nsnull); // avoid assert about setting it twice
    1246               0 :     rv = TrySetUpPluginInstance(aMimeType, aURL, aOwner);
    1247                 :   }
    1248                 : 
    1249               0 :   return rv;
    1250                 : }
    1251                 : 
    1252                 : nsresult
    1253               0 : nsPluginHost::TrySetUpPluginInstance(const char *aMimeType,
    1254                 :                                      nsIURI *aURL,
    1255                 :                                      nsIPluginInstanceOwner *aOwner)
    1256                 : {
    1257                 : #ifdef PLUGIN_LOGGING
    1258               0 :   nsCAutoString urlSpec;
    1259               0 :   if (aURL != nsnull) aURL->GetSpec(urlSpec);
    1260                 : 
    1261               0 :   PR_LOG(nsPluginLogging::gPluginLog, PLUGIN_LOG_NORMAL,
    1262                 :         ("nsPluginHost::TrySetupPluginInstance Begin mime=%s, owner=%p, url=%s\n",
    1263                 :         aMimeType, aOwner, urlSpec.get()));
    1264                 : 
    1265               0 :   PR_LogFlush();
    1266                 : #endif
    1267                 : 
    1268               0 :   nsresult rv = NS_ERROR_FAILURE;
    1269                 :   
    1270               0 :   const char* mimetype = nsnull;
    1271                 : 
    1272                 :   // if don't have a mimetype or no plugin can handle this mimetype
    1273                 :   // check by file extension
    1274               0 :   nsPluginTag* pluginTag = FindPluginForType(aMimeType, true);
    1275               0 :   if (!pluginTag) {
    1276               0 :     nsCOMPtr<nsIURL> url = do_QueryInterface(aURL);
    1277               0 :     if (!url) return NS_ERROR_FAILURE;
    1278                 : 
    1279               0 :     nsCAutoString fileExtension;
    1280               0 :     url->GetFileExtension(fileExtension);
    1281                 : 
    1282                 :     // if we don't have an extension or no plugin for this extension,
    1283                 :     // return failure as there is nothing more we can do
    1284               0 :     if (fileExtension.IsEmpty() ||
    1285                 :         !(pluginTag = FindPluginEnabledForExtension(fileExtension.get(),
    1286               0 :                                                     mimetype))) {
    1287               0 :       return NS_ERROR_FAILURE;
    1288                 :     }
    1289                 :   }
    1290                 :   else {
    1291               0 :     mimetype = aMimeType;
    1292                 :   }
    1293                 : 
    1294               0 :   NS_ASSERTION(pluginTag, "Must have plugin tag here!");
    1295                 : 
    1296               0 :   nsRefPtr<nsNPAPIPlugin> plugin;
    1297               0 :   GetPlugin(mimetype, getter_AddRefs(plugin));
    1298                 : 
    1299               0 :   nsRefPtr<nsNPAPIPluginInstance> instance;
    1300                 : 
    1301               0 :   if (plugin) {
    1302                 : #if defined(XP_WIN)
    1303                 :     static BOOL firstJavaPlugin = FALSE;
    1304                 :     BOOL restoreOrigDir = FALSE;
    1305                 :     WCHAR origDir[_MAX_PATH];
    1306                 :     if (pluginTag->mIsJavaPlugin && !firstJavaPlugin) {
    1307                 :       DWORD dw = GetCurrentDirectoryW(_MAX_PATH, origDir);
    1308                 :       NS_ASSERTION(dw <= _MAX_PATH, "Failed to obtain the current directory, which may lead to incorrect class loading");
    1309                 :       nsCOMPtr<nsIFile> binDirectory;
    1310                 :       rv = NS_GetSpecialDirectory(NS_XPCOM_CURRENT_PROCESS_DIR,
    1311                 :                                   getter_AddRefs(binDirectory));
    1312                 : 
    1313                 :       if (NS_SUCCEEDED(rv)) {
    1314                 :         nsAutoString path;
    1315                 :         binDirectory->GetPath(path);
    1316                 :         restoreOrigDir = SetCurrentDirectoryW(path.get());
    1317                 :       }
    1318                 :     }
    1319                 : #endif
    1320                 : 
    1321               0 :     rv = plugin->CreatePluginInstance(getter_AddRefs(instance));
    1322                 : 
    1323                 : #if defined(XP_WIN)
    1324                 :     if (!firstJavaPlugin && restoreOrigDir) {
    1325                 :       BOOL bCheck = SetCurrentDirectoryW(origDir);
    1326                 :       NS_ASSERTION(bCheck, "Error restoring directory");
    1327                 :       firstJavaPlugin = TRUE;
    1328                 :     }
    1329                 : #endif
    1330                 :   }
    1331                 : 
    1332               0 :   if (NS_FAILED(rv))
    1333               0 :     return rv;
    1334                 : 
    1335                 :   // it is adreffed here
    1336               0 :   aOwner->SetInstance(instance.get());
    1337                 : 
    1338                 :   // this should not addref the instance or owner
    1339                 :   // except in some cases not Java, see bug 140931
    1340                 :   // our COM pointer will free the peer
    1341               0 :   rv = instance->Initialize(aOwner, mimetype);
    1342               0 :   if (NS_FAILED(rv)) {
    1343               0 :     aOwner->SetInstance(nsnull);
    1344               0 :     return rv;
    1345                 :   }
    1346                 : 
    1347                 :   // Cancel the plugin unload timer since we are creating
    1348                 :   // an instance for it.
    1349               0 :   if (pluginTag->mUnloadTimer) {
    1350               0 :     pluginTag->mUnloadTimer->Cancel();
    1351                 :   }
    1352                 : 
    1353               0 :   mInstances.AppendElement(instance.get());
    1354                 : 
    1355                 : #ifdef PLUGIN_LOGGING
    1356               0 :   nsCAutoString urlSpec2;
    1357               0 :   if (aURL)
    1358               0 :     aURL->GetSpec(urlSpec2);
    1359                 : 
    1360               0 :   PR_LOG(nsPluginLogging::gPluginLog, PLUGIN_LOG_BASIC,
    1361                 :         ("nsPluginHost::TrySetupPluginInstance Finished mime=%s, rv=%d, owner=%p, url=%s\n",
    1362                 :         aMimeType, rv, aOwner, urlSpec2.get()));
    1363                 : 
    1364               0 :   PR_LogFlush();
    1365                 : #endif
    1366                 : 
    1367               0 :   return rv;
    1368                 : }
    1369                 : 
    1370                 : nsresult
    1371               0 : nsPluginHost::IsPluginEnabledForType(const char* aMimeType)
    1372                 : {
    1373               0 :   nsPluginTag *plugin = FindPluginForType(aMimeType, true);
    1374               0 :   if (plugin)
    1375               0 :     return NS_OK;
    1376                 : 
    1377                 :   // Pass false as the second arg so we can return NS_ERROR_PLUGIN_DISABLED
    1378                 :   // for disabled plug-ins.
    1379               0 :   plugin = FindPluginForType(aMimeType, false);
    1380               0 :   if (!plugin)
    1381               0 :     return NS_ERROR_FAILURE;
    1382                 : 
    1383               0 :   if (!plugin->IsEnabled()) {
    1384               0 :     if (plugin->HasFlag(NS_PLUGIN_FLAG_BLOCKLISTED))
    1385               0 :       return NS_ERROR_PLUGIN_BLOCKLISTED;
    1386                 :     else
    1387               0 :       return NS_ERROR_PLUGIN_DISABLED;
    1388                 :   }
    1389                 : 
    1390               0 :   return NS_OK;
    1391                 : }
    1392                 : 
    1393                 : // check comma delimitered extensions
    1394              43 : static int CompareExtensions(const char *aExtensionList, const char *aExtension)
    1395                 : {
    1396              43 :   if (!aExtensionList || !aExtension)
    1397               0 :     return -1;
    1398                 : 
    1399              43 :   const char *pExt = aExtensionList;
    1400              43 :   const char *pComma = strchr(pExt, ',');
    1401              43 :   if (!pComma)
    1402              43 :     return PL_strcasecmp(pExt, aExtension);
    1403                 : 
    1404               0 :   int extlen = strlen(aExtension);
    1405               0 :   while (pComma) {
    1406               0 :     int length = pComma - pExt;
    1407               0 :     if (length == extlen && 0 == PL_strncasecmp(aExtension, pExt, length))
    1408               0 :       return 0;
    1409               0 :     pComma++;
    1410               0 :     pExt = pComma;
    1411               0 :     pComma = strchr(pExt, ',');
    1412                 :   }
    1413                 : 
    1414                 :   // the last one
    1415               0 :   return PL_strcasecmp(pExt, aExtension);
    1416                 : }
    1417                 : 
    1418                 : nsresult
    1419              43 : nsPluginHost::IsPluginEnabledForExtension(const char* aExtension,
    1420                 :                                           const char* &aMimeType)
    1421                 : {
    1422              43 :   nsPluginTag *plugin = FindPluginEnabledForExtension(aExtension, aMimeType);
    1423              43 :   if (plugin)
    1424               0 :     return NS_OK;
    1425                 : 
    1426              43 :   return NS_ERROR_FAILURE;
    1427                 : }
    1428                 : 
    1429                 : class DOMMimeTypeImpl : public nsIDOMMimeType {
    1430                 : public:
    1431                 :   NS_DECL_ISUPPORTS
    1432                 : 
    1433               0 :   DOMMimeTypeImpl(nsPluginTag* aTag, PRUint32 aMimeTypeIndex)
    1434               0 :   {
    1435               0 :     if (!aTag)
    1436               0 :       return;
    1437               0 :     CopyUTF8toUTF16(aTag->mMimeDescriptions[aMimeTypeIndex], mDescription);
    1438               0 :     CopyUTF8toUTF16(aTag->mExtensions[aMimeTypeIndex], mSuffixes);
    1439               0 :     CopyUTF8toUTF16(aTag->mMimeTypes[aMimeTypeIndex], mType);
    1440                 :   }
    1441                 : 
    1442               0 :   virtual ~DOMMimeTypeImpl() {
    1443               0 :   }
    1444                 : 
    1445               0 :   NS_METHOD GetDescription(nsAString& aDescription)
    1446                 :   {
    1447               0 :     aDescription.Assign(mDescription);
    1448               0 :     return NS_OK;
    1449                 :   }
    1450                 : 
    1451               0 :   NS_METHOD GetEnabledPlugin(nsIDOMPlugin** aEnabledPlugin)
    1452                 :   {
    1453                 :     // this has to be implemented by the DOM version.
    1454               0 :     *aEnabledPlugin = nsnull;
    1455               0 :     return NS_OK;
    1456                 :   }
    1457                 : 
    1458               0 :   NS_METHOD GetSuffixes(nsAString& aSuffixes)
    1459                 :   {
    1460               0 :     aSuffixes.Assign(mSuffixes);
    1461               0 :     return NS_OK;
    1462                 :   }
    1463                 : 
    1464               0 :   NS_METHOD GetType(nsAString& aType)
    1465                 :   {
    1466               0 :     aType.Assign(mType);
    1467               0 :     return NS_OK;
    1468                 :   }
    1469                 : 
    1470                 : private:
    1471                 :   nsString mDescription;
    1472                 :   nsString mSuffixes;
    1473                 :   nsString mType;
    1474                 : };
    1475                 : 
    1476               0 : NS_IMPL_ISUPPORTS1(DOMMimeTypeImpl, nsIDOMMimeType)
    1477                 : 
    1478                 : class DOMPluginImpl : public nsIDOMPlugin {
    1479                 : public:
    1480                 :   NS_DECL_ISUPPORTS
    1481                 : 
    1482               0 :   DOMPluginImpl(nsPluginTag* aPluginTag) : mPluginTag(aPluginTag)
    1483                 :   {
    1484               0 :   }
    1485                 : 
    1486               0 :   virtual ~DOMPluginImpl() {
    1487               0 :   }
    1488                 : 
    1489               0 :   NS_METHOD GetDescription(nsAString& aDescription)
    1490                 :   {
    1491               0 :     CopyUTF8toUTF16(mPluginTag.mDescription, aDescription);
    1492               0 :     return NS_OK;
    1493                 :   }
    1494                 : 
    1495               0 :   NS_METHOD GetFilename(nsAString& aFilename)
    1496                 :   {
    1497                 :     bool bShowPath;
    1498               0 :     nsCOMPtr<nsIPrefBranch> prefService = do_GetService(NS_PREFSERVICE_CONTRACTID);
    1499               0 :     if (prefService &&
    1500               0 :         NS_SUCCEEDED(prefService->GetBoolPref("plugin.expose_full_path", &bShowPath)) &&
    1501                 :         bShowPath) {
    1502               0 :       CopyUTF8toUTF16(mPluginTag.mFullPath, aFilename);
    1503                 :     } else {
    1504               0 :       CopyUTF8toUTF16(mPluginTag.mFileName, aFilename);
    1505                 :     }
    1506                 : 
    1507               0 :     return NS_OK;
    1508                 :   }
    1509                 : 
    1510               0 :   NS_METHOD GetVersion(nsAString& aVersion)
    1511                 :   {
    1512               0 :     CopyUTF8toUTF16(mPluginTag.mVersion, aVersion);
    1513               0 :     return NS_OK;
    1514                 :   }
    1515                 : 
    1516               0 :   NS_METHOD GetName(nsAString& aName)
    1517                 :   {
    1518               0 :     CopyUTF8toUTF16(mPluginTag.mName, aName);
    1519               0 :     return NS_OK;
    1520                 :   }
    1521                 : 
    1522               0 :   NS_METHOD GetLength(PRUint32* aLength)
    1523                 :   {
    1524               0 :     *aLength = mPluginTag.mMimeTypes.Length();
    1525               0 :     return NS_OK;
    1526                 :   }
    1527                 : 
    1528               0 :   NS_METHOD Item(PRUint32 aIndex, nsIDOMMimeType** aReturn)
    1529                 :   {
    1530               0 :     nsIDOMMimeType* mimeType = new DOMMimeTypeImpl(&mPluginTag, aIndex);
    1531               0 :     NS_IF_ADDREF(mimeType);
    1532               0 :     *aReturn = mimeType;
    1533               0 :     return NS_OK;
    1534                 :   }
    1535                 : 
    1536               0 :   NS_METHOD NamedItem(const nsAString& aName, nsIDOMMimeType** aReturn)
    1537                 :   {
    1538               0 :     for (int i = mPluginTag.mMimeTypes.Length() - 1; i >= 0; --i) {
    1539               0 :       if (aName.Equals(NS_ConvertUTF8toUTF16(mPluginTag.mMimeTypes[i])))
    1540               0 :         return Item(i, aReturn);
    1541                 :     }
    1542               0 :     return NS_OK;
    1543                 :   }
    1544                 : 
    1545                 : private:
    1546                 :   nsPluginTag mPluginTag;
    1547                 : };
    1548                 : 
    1549               0 : NS_IMPL_ISUPPORTS1(DOMPluginImpl, nsIDOMPlugin)
    1550                 : 
    1551                 : nsresult
    1552               0 : nsPluginHost::GetPluginCount(PRUint32* aPluginCount)
    1553                 : {
    1554               0 :   LoadPlugins();
    1555                 : 
    1556               0 :   PRUint32 count = 0;
    1557                 : 
    1558               0 :   nsPluginTag* plugin = mPlugins;
    1559               0 :   while (plugin != nsnull) {
    1560               0 :     if (plugin->IsEnabled()) {
    1561               0 :       ++count;
    1562                 :     }
    1563               0 :     plugin = plugin->mNext;
    1564                 :   }
    1565                 : 
    1566               0 :   *aPluginCount = count;
    1567                 : 
    1568               0 :   return NS_OK;
    1569                 : }
    1570                 : 
    1571                 : nsresult
    1572               0 : nsPluginHost::GetPlugins(PRUint32 aPluginCount, nsIDOMPlugin** aPluginArray)
    1573                 : {
    1574               0 :   LoadPlugins();
    1575                 : 
    1576               0 :   nsPluginTag* plugin = mPlugins;
    1577               0 :   for (PRUint32 i = 0; i < aPluginCount && plugin; plugin = plugin->mNext) {
    1578               0 :     if (plugin->IsEnabled()) {
    1579               0 :       nsIDOMPlugin* domPlugin = new DOMPluginImpl(plugin);
    1580               0 :       NS_IF_ADDREF(domPlugin);
    1581               0 :       aPluginArray[i++] = domPlugin;
    1582                 :     }
    1583                 :   }
    1584                 : 
    1585               0 :   return NS_OK;
    1586                 : }
    1587                 : 
    1588                 : NS_IMETHODIMP
    1589             815 : nsPluginHost::GetPluginTags(PRUint32* aPluginCount, nsIPluginTag*** aResults)
    1590                 : {
    1591             815 :   LoadPlugins();
    1592                 : 
    1593             815 :   PRUint32 count = 0;
    1594            1630 :   nsRefPtr<nsPluginTag> plugin = mPlugins;
    1595            2444 :   while (plugin != nsnull) {
    1596             814 :     count++;
    1597             814 :     plugin = plugin->mNext;
    1598                 :   }
    1599                 : 
    1600                 :   *aResults = static_cast<nsIPluginTag**>
    1601             815 :                          (nsMemory::Alloc(count * sizeof(**aResults)));
    1602             815 :   if (!*aResults)
    1603               0 :     return NS_ERROR_OUT_OF_MEMORY;
    1604                 : 
    1605             815 :   *aPluginCount = count;
    1606                 : 
    1607             815 :   plugin = mPlugins;
    1608            1629 :   for (PRUint32 i = 0; i < count; i++) {
    1609             814 :     (*aResults)[i] = plugin;
    1610             814 :     NS_ADDREF((*aResults)[i]);
    1611             814 :     plugin = plugin->mNext;
    1612                 :   }
    1613                 : 
    1614             815 :   return NS_OK;
    1615                 : }
    1616                 : 
    1617                 : nsPluginTag*
    1618               0 : nsPluginHost::FindPluginForType(const char* aMimeType,
    1619                 :                                 bool aCheckEnabled)
    1620                 : {
    1621               0 :   if (!aMimeType) {
    1622               0 :     return nsnull;
    1623                 :   }
    1624                 : 
    1625               0 :   LoadPlugins();
    1626                 : 
    1627               0 :   nsPluginTag *plugin = mPlugins;
    1628               0 :   while (plugin) {
    1629               0 :     if (!aCheckEnabled || plugin->IsEnabled()) {
    1630               0 :       PRInt32 mimeCount = plugin->mMimeTypes.Length();
    1631               0 :       for (PRInt32 i = 0; i < mimeCount; i++) {
    1632               0 :         if (0 == PL_strcasecmp(plugin->mMimeTypes[i].get(), aMimeType)) {
    1633               0 :           return plugin;
    1634                 :         }
    1635                 :       }
    1636                 :     }
    1637               0 :     plugin = plugin->mNext;
    1638                 :   }
    1639                 : 
    1640               0 :   return nsnull;
    1641                 : }
    1642                 : 
    1643                 : nsPluginTag*
    1644              43 : nsPluginHost::FindPluginEnabledForExtension(const char* aExtension,
    1645                 :                                             const char*& aMimeType)
    1646                 : {
    1647              43 :   if (!aExtension) {
    1648               0 :     return nsnull;
    1649                 :   }
    1650                 : 
    1651              43 :   LoadPlugins();
    1652                 : 
    1653              43 :   nsPluginTag *plugin = mPlugins;
    1654             129 :   while (plugin) {
    1655              43 :     if (plugin->IsEnabled()) {
    1656              43 :       PRInt32 variants = plugin->mExtensions.Length();
    1657              86 :       for (PRInt32 i = 0; i < variants; i++) {
    1658                 :         // mExtensionsArray[cnt] is a list of extensions separated by commas
    1659              43 :         if (0 == CompareExtensions(plugin->mExtensions[i].get(), aExtension)) {
    1660               0 :           aMimeType = plugin->mMimeTypes[i].get();
    1661               0 :           return plugin;
    1662                 :         }
    1663                 :       }
    1664                 :     }
    1665              43 :     plugin = plugin->mNext;
    1666                 :   }
    1667                 : 
    1668              43 :   return nsnull;
    1669                 : }
    1670                 : 
    1671               0 : static nsresult CreateNPAPIPlugin(nsPluginTag *aPluginTag,
    1672                 :                                   nsNPAPIPlugin **aOutNPAPIPlugin)
    1673                 : {
    1674                 :   // If this is an in-process plugin we'll need to load it here if we haven't already.
    1675               0 :   if (!nsNPAPIPlugin::RunPluginOOP(aPluginTag)) {
    1676               0 :     if (aPluginTag->mFullPath.IsEmpty())
    1677               0 :       return NS_ERROR_FAILURE;
    1678               0 :     nsCOMPtr<nsILocalFile> file = do_CreateInstance("@mozilla.org/file/local;1");
    1679               0 :     file->InitWithPath(NS_ConvertUTF8toUTF16(aPluginTag->mFullPath));
    1680               0 :     nsPluginFile pluginFile(file);
    1681               0 :     PRLibrary* pluginLibrary = NULL;
    1682                 : 
    1683               0 :     if (NS_FAILED(pluginFile.LoadPlugin(&pluginLibrary)) || !pluginLibrary)
    1684               0 :       return NS_ERROR_FAILURE;
    1685                 : 
    1686               0 :     aPluginTag->mLibrary = pluginLibrary;
    1687                 :   }
    1688                 : 
    1689                 :   nsresult rv;
    1690               0 :   rv = nsNPAPIPlugin::CreatePlugin(aPluginTag, aOutNPAPIPlugin);
    1691                 : 
    1692               0 :   return rv;
    1693                 : }
    1694                 : 
    1695               0 : nsresult nsPluginHost::EnsurePluginLoaded(nsPluginTag* plugin)
    1696                 : {
    1697               0 :   nsRefPtr<nsNPAPIPlugin> entrypoint = plugin->mEntryPoint;
    1698               0 :   if (!entrypoint) {
    1699               0 :     nsresult rv = CreateNPAPIPlugin(plugin, getter_AddRefs(entrypoint));
    1700               0 :     if (NS_FAILED(rv)) {
    1701               0 :       return rv;
    1702                 :     }
    1703               0 :     plugin->mEntryPoint = entrypoint;
    1704                 :   }
    1705               0 :   return NS_OK;
    1706                 : }
    1707                 : 
    1708               0 : nsresult nsPluginHost::GetPlugin(const char *aMimeType, nsNPAPIPlugin** aPlugin)
    1709                 : {
    1710               0 :   nsresult rv = NS_ERROR_FAILURE;
    1711               0 :   *aPlugin = NULL;
    1712                 : 
    1713               0 :   if (!aMimeType)
    1714               0 :     return NS_ERROR_ILLEGAL_VALUE;
    1715                 : 
    1716                 :   // If plugins haven't been scanned yet, do so now
    1717               0 :   LoadPlugins();
    1718                 : 
    1719               0 :   nsPluginTag* pluginTag = FindPluginForType(aMimeType, true);
    1720               0 :   if (pluginTag) {
    1721               0 :     rv = NS_OK;
    1722               0 :     PLUGIN_LOG(PLUGIN_LOG_BASIC,
    1723                 :     ("nsPluginHost::GetPlugin Begin mime=%s, plugin=%s\n",
    1724                 :     aMimeType, pluginTag->mFileName.get()));
    1725                 : 
    1726                 : #ifdef NS_DEBUG
    1727               0 :     if (aMimeType && !pluginTag->mFileName.IsEmpty())
    1728               0 :       printf("For %s found plugin %s\n", aMimeType, pluginTag->mFileName.get());
    1729                 : #endif
    1730                 : 
    1731               0 :     rv = EnsurePluginLoaded(pluginTag);
    1732               0 :     if (NS_FAILED(rv)) {
    1733               0 :       return rv;
    1734                 :     }
    1735                 : 
    1736               0 :     NS_ADDREF(*aPlugin = pluginTag->mEntryPoint);
    1737               0 :     return NS_OK;
    1738                 :   }
    1739                 : 
    1740               0 :   PLUGIN_LOG(PLUGIN_LOG_NORMAL,
    1741                 :   ("nsPluginHost::GetPlugin End mime=%s, rv=%d, plugin=%p name=%s\n",
    1742                 :   aMimeType, rv, *aPlugin,
    1743                 :   (pluginTag ? pluginTag->mFileName.get() : "(not found)")));
    1744                 : 
    1745               0 :   return rv;
    1746                 : }
    1747                 : 
    1748                 : // Normalize 'host' to ACE.
    1749                 : nsresult
    1750               0 : nsPluginHost::NormalizeHostname(nsCString& host)
    1751                 : {
    1752               0 :   if (IsASCII(host)) {
    1753               0 :     ToLowerCase(host);
    1754               0 :     return NS_OK;
    1755                 :   }
    1756                 : 
    1757               0 :   if (!mIDNService) {
    1758                 :     nsresult rv;
    1759               0 :     mIDNService = do_GetService(NS_IDNSERVICE_CONTRACTID, &rv);
    1760               0 :     NS_ENSURE_SUCCESS(rv, rv);
    1761                 :   }
    1762                 : 
    1763               0 :   return mIDNService->ConvertUTF8toACE(host, host);
    1764                 : }
    1765                 : 
    1766                 : // Enumerate a 'sites' array returned by GetSitesWithData and determine if
    1767                 : // any of them have a base domain in common with 'domain'; if so, append them
    1768                 : // to the 'result' array. If 'firstMatchOnly' is true, return after finding the
    1769                 : // first match.
    1770                 : nsresult
    1771               0 : nsPluginHost::EnumerateSiteData(const nsACString& domain,
    1772                 :                                 const nsTArray<nsCString>& sites,
    1773                 :                                 InfallibleTArray<nsCString>& result,
    1774                 :                                 bool firstMatchOnly)
    1775                 : {
    1776               0 :   NS_ASSERTION(!domain.IsVoid(), "null domain string");
    1777                 : 
    1778                 :   nsresult rv;
    1779               0 :   if (!mTLDService) {
    1780               0 :     mTLDService = do_GetService(NS_EFFECTIVETLDSERVICE_CONTRACTID, &rv);
    1781               0 :     NS_ENSURE_SUCCESS(rv, rv);
    1782                 :   }
    1783                 : 
    1784                 :   // Get the base domain from the domain.
    1785               0 :   nsCString baseDomain;
    1786               0 :   rv = mTLDService->GetBaseDomainFromHost(domain, 0, baseDomain);
    1787               0 :   bool isIP = rv == NS_ERROR_HOST_IS_IP_ADDRESS;
    1788               0 :   if (isIP || rv == NS_ERROR_INSUFFICIENT_DOMAIN_LEVELS) {
    1789                 :     // The base domain is the site itself. However, we must be careful to
    1790                 :     // normalize.
    1791               0 :     baseDomain = domain;
    1792               0 :     rv = NormalizeHostname(baseDomain);
    1793               0 :     NS_ENSURE_SUCCESS(rv, rv);
    1794               0 :   } else if (NS_FAILED(rv)) {
    1795               0 :     return rv;
    1796                 :   }
    1797                 : 
    1798                 :   // Enumerate the array of sites with data.
    1799               0 :   for (PRUint32 i = 0; i < sites.Length(); ++i) {
    1800               0 :     const nsCString& site = sites[i];
    1801                 : 
    1802                 :     // Check if the site is an IP address.
    1803                 :     bool siteIsIP =
    1804               0 :       site.Length() >= 2 && site.First() == '[' && site.Last() == ']';
    1805               0 :     if (siteIsIP != isIP)
    1806               0 :       continue;
    1807                 : 
    1808               0 :     nsCString siteBaseDomain;
    1809               0 :     if (siteIsIP) {
    1810                 :       // Strip the '[]'.
    1811               0 :       siteBaseDomain = Substring(site, 1, site.Length() - 2);
    1812                 :     } else {
    1813                 :       // Determine the base domain of the site.
    1814               0 :       rv = mTLDService->GetBaseDomainFromHost(site, 0, siteBaseDomain);
    1815               0 :       if (rv == NS_ERROR_INSUFFICIENT_DOMAIN_LEVELS) {
    1816                 :         // The base domain is the site itself. However, we must be careful to
    1817                 :         // normalize.
    1818               0 :         siteBaseDomain = site;
    1819               0 :         rv = NormalizeHostname(siteBaseDomain);
    1820               0 :         NS_ENSURE_SUCCESS(rv, rv);
    1821               0 :       } else if (NS_FAILED(rv)) {
    1822               0 :         return rv;
    1823                 :       }
    1824                 :     }
    1825                 : 
    1826                 :     // At this point, we can do an exact comparison of the two domains.
    1827               0 :     if (baseDomain != siteBaseDomain) {
    1828               0 :       continue;
    1829                 :     }
    1830                 : 
    1831                 :     // Append the site to the result array.
    1832               0 :     result.AppendElement(site);
    1833                 : 
    1834                 :     // If we're supposed to return early, do so.
    1835               0 :     if (firstMatchOnly) {
    1836                 :       break;
    1837                 :     }
    1838                 :   }
    1839                 : 
    1840               0 :   return NS_OK;
    1841                 : }
    1842                 : 
    1843                 : NS_IMETHODIMP
    1844              49 : nsPluginHost::ClearSiteData(nsIPluginTag* plugin, const nsACString& domain,
    1845                 :                             PRUint64 flags, PRInt64 maxAge)
    1846                 : {
    1847                 :   // maxAge must be either a nonnegative integer or -1.
    1848              49 :   NS_ENSURE_ARG(maxAge >= 0 || maxAge == -1);
    1849                 : 
    1850                 :   // Caller may give us a tag object that is no longer live.
    1851              49 :   if (!IsLiveTag(plugin)) {
    1852               0 :     return NS_ERROR_NOT_AVAILABLE;
    1853                 :   }
    1854                 : 
    1855              49 :   nsPluginTag* tag = static_cast<nsPluginTag*>(plugin);
    1856                 : 
    1857                 :   // We only ensure support for clearing Flash site data for now.
    1858                 :   // We will also attempt to clear data for any plugin that happens
    1859                 :   // to be loaded already.
    1860              49 :   if (!tag->mIsFlashPlugin && !tag->mEntryPoint) {
    1861              49 :     return NS_ERROR_FAILURE;
    1862                 :   }
    1863                 : 
    1864                 :   // Make sure the plugin is loaded.
    1865               0 :   nsresult rv = EnsurePluginLoaded(tag);
    1866               0 :   if (NS_FAILED(rv)) {
    1867               0 :     return rv;
    1868                 :   }
    1869                 : 
    1870               0 :   PluginLibrary* library = tag->mEntryPoint->GetLibrary();
    1871                 : 
    1872                 :   // If 'domain' is the null string, clear everything.
    1873               0 :   if (domain.IsVoid()) {
    1874               0 :     return library->NPP_ClearSiteData(NULL, flags, maxAge);
    1875                 :   }
    1876                 : 
    1877                 :   // Get the list of sites from the plugin.
    1878               0 :   InfallibleTArray<nsCString> sites;
    1879               0 :   rv = library->NPP_GetSitesWithData(sites);
    1880               0 :   NS_ENSURE_SUCCESS(rv, rv);
    1881                 : 
    1882                 :   // Enumerate the sites and build a list of matches.
    1883               0 :   InfallibleTArray<nsCString> matches;
    1884               0 :   rv = EnumerateSiteData(domain, sites, matches, false);
    1885               0 :   NS_ENSURE_SUCCESS(rv, rv);
    1886                 : 
    1887                 :   // Clear the matches.
    1888               0 :   for (PRUint32 i = 0; i < matches.Length(); ++i) {
    1889               0 :     const nsCString& match = matches[i];
    1890               0 :     rv = library->NPP_ClearSiteData(match.get(), flags, maxAge);
    1891               0 :     NS_ENSURE_SUCCESS(rv, rv);
    1892                 :   }
    1893                 : 
    1894               0 :   return NS_OK;
    1895                 : }
    1896                 : 
    1897                 : NS_IMETHODIMP
    1898               0 : nsPluginHost::SiteHasData(nsIPluginTag* plugin, const nsACString& domain,
    1899                 :                           bool* result)
    1900                 : {
    1901                 :   // Caller may give us a tag object that is no longer live.
    1902               0 :   if (!IsLiveTag(plugin)) {
    1903               0 :     return NS_ERROR_NOT_AVAILABLE;
    1904                 :   }
    1905                 : 
    1906               0 :   nsPluginTag* tag = static_cast<nsPluginTag*>(plugin);
    1907                 : 
    1908                 :   // We only ensure support for clearing Flash site data for now.
    1909                 :   // We will also attempt to clear data for any plugin that happens
    1910                 :   // to be loaded already.
    1911               0 :   if (!tag->mIsFlashPlugin && !tag->mEntryPoint) {
    1912               0 :     return NS_ERROR_FAILURE;
    1913                 :   }
    1914                 : 
    1915                 :   // Make sure the plugin is loaded.
    1916               0 :   nsresult rv = EnsurePluginLoaded(tag);
    1917               0 :   if (NS_FAILED(rv)) {
    1918               0 :     return rv;
    1919                 :   }
    1920                 : 
    1921               0 :   PluginLibrary* library = tag->mEntryPoint->GetLibrary();
    1922                 : 
    1923                 :   // Get the list of sites from the plugin.
    1924               0 :   InfallibleTArray<nsCString> sites;
    1925               0 :   rv = library->NPP_GetSitesWithData(sites);
    1926               0 :   NS_ENSURE_SUCCESS(rv, rv);
    1927                 : 
    1928                 :   // If there's no data, we're done.
    1929               0 :   if (sites.IsEmpty()) {
    1930               0 :     *result = false;
    1931               0 :     return NS_OK;
    1932                 :   }
    1933                 : 
    1934                 :   // If 'domain' is the null string, and there's data for at least one site,
    1935                 :   // we're done.
    1936               0 :   if (domain.IsVoid()) {
    1937               0 :     *result = true;
    1938               0 :     return NS_OK;
    1939                 :   }
    1940                 : 
    1941                 :   // Enumerate the sites and determine if there's a match.
    1942               0 :   InfallibleTArray<nsCString> matches;
    1943               0 :   rv = EnumerateSiteData(domain, sites, matches, true);
    1944               0 :   NS_ENSURE_SUCCESS(rv, rv);
    1945                 : 
    1946               0 :   *result = !matches.IsEmpty();
    1947               0 :   return NS_OK;
    1948                 : }
    1949                 : 
    1950             178 : bool nsPluginHost::IsJavaMIMEType(const char* aType)
    1951                 : {
    1952                 :   return aType &&
    1953                 :     ((0 == PL_strncasecmp(aType, "application/x-java-vm",
    1954             178 :                           sizeof("application/x-java-vm") - 1)) ||
    1955                 :      (0 == PL_strncasecmp(aType, "application/x-java-applet",
    1956             178 :                           sizeof("application/x-java-applet") - 1)) ||
    1957                 :      (0 == PL_strncasecmp(aType, "application/x-java-bean",
    1958             534 :                           sizeof("application/x-java-bean") - 1)));
    1959                 : }
    1960                 : 
    1961                 : // Check whether or not a tag is a live, valid tag, and that it's loaded.
    1962                 : bool
    1963              49 : nsPluginHost::IsLiveTag(nsIPluginTag* aPluginTag)
    1964                 : {
    1965                 :   nsPluginTag* tag;
    1966              49 :   for (tag = mPlugins; tag; tag = tag->mNext) {
    1967              49 :     if (tag == aPluginTag) {
    1968              49 :       return true;
    1969                 :     }
    1970                 :   }
    1971               0 :   return false;
    1972                 : }
    1973                 : 
    1974             346 : nsPluginTag * nsPluginHost::HaveSamePlugin(nsPluginTag * aPluginTag)
    1975                 : {
    1976             346 :   for (nsPluginTag* tag = mPlugins; tag; tag = tag->mNext) {
    1977               0 :     if (tag->Equals(aPluginTag))
    1978               0 :       return tag;
    1979                 :   }
    1980             346 :   return nsnull;
    1981                 : }
    1982                 : 
    1983             173 : bool nsPluginHost::IsDuplicatePlugin(nsPluginTag * aPluginTag)
    1984                 : {
    1985             173 :   nsPluginTag * tag = HaveSamePlugin(aPluginTag);
    1986             173 :   if (tag) {
    1987                 :     // if we got the same plugin, check the full path to see if this is a dup;
    1988                 : 
    1989                 :     // mFileName contains full path on Windows and Unix and leaf name on Mac
    1990                 :     // if those are not equal, we have the same plugin with  different path,
    1991                 :     // i.e. duplicate, return true
    1992               0 :     if (!tag->mFileName.Equals(aPluginTag->mFileName))
    1993               0 :       return true;
    1994                 : 
    1995                 :     // if they are equal, compare mFullPath fields just in case
    1996                 :     // mFileName contained leaf name only, and if not equal, return true
    1997               0 :     if (!tag->mFullPath.Equals(aPluginTag->mFullPath))
    1998               0 :       return true;
    1999                 :   }
    2000                 : 
    2001                 :   // we do not have it at all, return false
    2002             173 :   return false;
    2003                 : }
    2004                 : 
    2005                 : typedef NS_NPAPIPLUGIN_CALLBACK(char *, NP_GETMIMEDESCRIPTION)(void);
    2006                 : 
    2007             346 : nsresult nsPluginHost::ScanPluginsDirectory(nsIFile *pluginsDir,
    2008                 :                                             bool aCreatePluginList,
    2009                 :                                             bool *aPluginsChanged)
    2010                 : {
    2011             346 :   NS_ENSURE_ARG_POINTER(aPluginsChanged);
    2012                 :   nsresult rv;
    2013                 : 
    2014             346 :   *aPluginsChanged = false;
    2015                 : 
    2016                 : #ifdef PLUGIN_LOGGING
    2017             692 :   nsCAutoString dirPath;
    2018             346 :   pluginsDir->GetNativePath(dirPath);
    2019             346 :   PLUGIN_LOG(PLUGIN_LOG_BASIC,
    2020                 :   ("nsPluginHost::ScanPluginsDirectory dir=%s\n", dirPath.get()));
    2021                 : #endif
    2022                 : 
    2023             692 :   nsCOMPtr<nsISimpleEnumerator> iter;
    2024             346 :   rv = pluginsDir->GetDirectoryEntries(getter_AddRefs(iter));
    2025             346 :   if (NS_FAILED(rv))
    2026               0 :     return rv;
    2027                 : 
    2028             692 :   nsAutoTArray<nsCOMPtr<nsILocalFile>, 6> pluginFiles;
    2029                 : 
    2030                 :   bool hasMore;
    2031             865 :   while (NS_SUCCEEDED(iter->HasMoreElements(&hasMore)) && hasMore) {
    2032             346 :     nsCOMPtr<nsISupports> supports;
    2033             173 :     rv = iter->GetNext(getter_AddRefs(supports));
    2034             173 :     if (NS_FAILED(rv))
    2035               0 :       continue;
    2036             346 :     nsCOMPtr<nsILocalFile> dirEntry(do_QueryInterface(supports, &rv));
    2037             173 :     if (NS_FAILED(rv))
    2038               0 :       continue;
    2039                 : 
    2040                 :     // Sun's JRE 1.3.1 plugin must have symbolic links resolved or else it'll crash.
    2041                 :     // See bug 197855.
    2042             173 :     dirEntry->Normalize();
    2043                 : 
    2044             173 :     if (nsPluginsDir::IsPluginFile(dirEntry)) {
    2045             173 :       pluginFiles.AppendElement(dirEntry);
    2046                 :     }
    2047                 :   }
    2048                 : 
    2049             346 :   bool warnOutdated = false;
    2050                 : 
    2051             519 :   for (PRUint32 i = 0; i < pluginFiles.Length(); i++) {
    2052             173 :     nsCOMPtr<nsILocalFile>& localfile = pluginFiles[i];
    2053                 : 
    2054             346 :     nsString utf16FilePath;
    2055             173 :     rv = localfile->GetPath(utf16FilePath);
    2056             173 :     if (NS_FAILED(rv))
    2057               0 :       continue;
    2058                 : 
    2059             173 :     PRInt64 fileModTime = LL_ZERO;
    2060                 : #if defined(XP_MACOSX)
    2061                 :     // On OS X the date of a bundle's "contents" (i.e. of its Info.plist file)
    2062                 :     // is a much better guide to when it was last modified than the date of
    2063                 :     // its package directory.  See bug 313700.
    2064                 :     nsCOMPtr<nsILocalFileMac> localFileMac = do_QueryInterface(localfile);
    2065                 :     if (localFileMac) {
    2066                 :       localFileMac->GetBundleContentsLastModifiedTime(&fileModTime);
    2067                 :     } else {
    2068                 :       localfile->GetLastModifiedTime(&fileModTime);
    2069                 :     }
    2070                 : #else
    2071             173 :     localfile->GetLastModifiedTime(&fileModTime);
    2072                 : #endif
    2073                 : 
    2074                 :     // Look for it in our cache
    2075             346 :     NS_ConvertUTF16toUTF8 filePath(utf16FilePath);
    2076             346 :     nsRefPtr<nsPluginTag> pluginTag;
    2077                 :     RemoveCachedPluginsInfo(filePath.get(),
    2078             173 :                             getter_AddRefs(pluginTag));
    2079                 : 
    2080             173 :     bool enabled = true;
    2081             173 :     bool seenBefore = false;
    2082             173 :     if (pluginTag) {
    2083               1 :       seenBefore = true;
    2084                 :       // If plugin changed, delete cachedPluginTag and don't use cache
    2085               1 :       if (LL_NE(fileModTime, pluginTag->mLastModifiedTime)) {
    2086                 :         // Plugins has changed. Don't use cached plugin info.
    2087               1 :         enabled = (pluginTag->Flags() & NS_PLUGIN_FLAG_ENABLED) != 0;
    2088               1 :         pluginTag = nsnull;
    2089                 : 
    2090                 :         // plugin file changed, flag this fact
    2091               1 :         *aPluginsChanged = true;
    2092                 :       }
    2093                 :       else {
    2094                 :         // if it is unwanted plugin we are checking for, get it back to the cache info list
    2095                 :         // if this is a duplicate plugin, too place it back in the cache info list marking unwantedness
    2096               0 :         if (IsDuplicatePlugin(pluginTag)) {
    2097               0 :           if (!pluginTag->HasFlag(NS_PLUGIN_FLAG_UNWANTED)) {
    2098                 :             // Plugin switched from wanted to unwanted
    2099               0 :             *aPluginsChanged = true;
    2100                 :           }
    2101               0 :           pluginTag->Mark(NS_PLUGIN_FLAG_UNWANTED);
    2102               0 :           pluginTag->mNext = mCachedPlugins;
    2103               0 :           mCachedPlugins = pluginTag;
    2104               0 :         } else if (pluginTag->HasFlag(NS_PLUGIN_FLAG_UNWANTED)) {
    2105               0 :           pluginTag->UnMark(NS_PLUGIN_FLAG_UNWANTED);
    2106                 :           // Plugin switched from unwanted to wanted
    2107               0 :           *aPluginsChanged = true;
    2108                 :         }
    2109                 :       }
    2110                 : 
    2111                 :       // If we're not creating a list and we already know something changed then
    2112                 :       // we're done.
    2113               1 :       if (!aCreatePluginList) {
    2114               0 :         if (*aPluginsChanged) {
    2115               0 :           return NS_OK;
    2116                 :         }
    2117               0 :         continue;
    2118                 :       }
    2119                 :     }
    2120                 :     
    2121             173 :     bool isKnownInvalidPlugin = false;
    2122             346 :     for (nsRefPtr<nsInvalidPluginTag> invalidPlugins = mInvalidPlugins;
    2123             173 :          invalidPlugins; invalidPlugins = invalidPlugins->mNext) {
    2124                 :       // If already marked as invalid, ignore it
    2125               0 :       if (invalidPlugins->mFullPath.Equals(filePath.get()) &&
    2126               0 :           invalidPlugins->mLastModifiedTime == fileModTime) {
    2127               0 :         if (aCreatePluginList) {
    2128               0 :           invalidPlugins->mSeen = true;
    2129                 :         }
    2130               0 :         isKnownInvalidPlugin = true;
    2131               0 :         break;
    2132                 :       }
    2133                 :     }
    2134             173 :     if (isKnownInvalidPlugin) {
    2135               0 :       continue;
    2136                 :     }
    2137                 : 
    2138                 :     // if it is not found in cache info list or has been changed, create a new one
    2139             173 :     if (!pluginTag) {
    2140             346 :       nsPluginFile pluginFile(localfile);
    2141                 : 
    2142                 :       // create a tag describing this plugin.
    2143             173 :       PRLibrary *library = nsnull;
    2144                 :       nsPluginInfo info;
    2145             173 :       memset(&info, 0, sizeof(info));
    2146             173 :       nsresult res = pluginFile.GetPluginInfo(info, &library);
    2147                 :       // if we don't have mime type don't proceed, this is not a plugin
    2148             173 :       if (NS_FAILED(res) || !info.fMimeTypeArray) {
    2149                 :         nsRefPtr<nsInvalidPluginTag> invalidTag = new nsInvalidPluginTag(filePath.get(),
    2150               0 :                                                                          fileModTime);
    2151               0 :         pluginFile.FreePluginInfo(info);
    2152                 :         
    2153               0 :         if (aCreatePluginList) {
    2154               0 :           invalidTag->mSeen = true;
    2155                 :         }
    2156               0 :         invalidTag->mNext = mInvalidPlugins;
    2157               0 :         if (mInvalidPlugins) {
    2158               0 :           mInvalidPlugins->mPrev = invalidTag;
    2159                 :         }
    2160               0 :         mInvalidPlugins = invalidTag;
    2161                 :         
    2162                 :         // Mark aPluginsChanged so pluginreg is rewritten
    2163               0 :         *aPluginsChanged = true;
    2164               0 :         continue;
    2165                 :       }
    2166                 : 
    2167             173 :       pluginTag = new nsPluginTag(&info);
    2168             173 :       pluginFile.FreePluginInfo(info);
    2169             173 :       if (!pluginTag)
    2170               0 :         return NS_ERROR_OUT_OF_MEMORY;
    2171                 : 
    2172             173 :       pluginTag->mLibrary = library;
    2173             173 :       pluginTag->mLastModifiedTime = fileModTime;
    2174                 : 
    2175             519 :       nsCOMPtr<nsIBlocklistService> blocklist = do_GetService("@mozilla.org/extensions/blocklist;1");
    2176             173 :       if (blocklist) {
    2177                 :         PRUint32 state;
    2178             346 :         rv = blocklist->GetPluginBlocklistState(pluginTag, EmptyString(),
    2179             346 :                                                 EmptyString(), &state);
    2180                 : 
    2181             173 :         if (NS_SUCCEEDED(rv)) {
    2182                 :           // If the blocklist says so then block the plugin. If the blocklist says
    2183                 :           // it is risky and we have never seen this plugin before then disable it
    2184             151 :           if (state == nsIBlocklistService::STATE_BLOCKED)
    2185               0 :             pluginTag->Mark(NS_PLUGIN_FLAG_BLOCKLISTED);
    2186             151 :           else if (state == nsIBlocklistService::STATE_SOFTBLOCKED && !seenBefore)
    2187               0 :             enabled = false;
    2188             151 :           else if (state == nsIBlocklistService::STATE_OUTDATED && !seenBefore)
    2189               2 :             warnOutdated = true;
    2190                 :         }
    2191                 :       }
    2192                 : 
    2193             173 :       if (!enabled)
    2194               1 :         pluginTag->UnMark(NS_PLUGIN_FLAG_ENABLED);
    2195                 : 
    2196                 :       // if this is unwanted plugin we are checkin for, or this is a duplicate plugin,
    2197                 :       // add it to our cache info list so we can cache the unwantedness of this plugin
    2198                 :       // when we sync cached plugins to registry
    2199             173 :       NS_ASSERTION(!pluginTag->HasFlag(NS_PLUGIN_FLAG_UNWANTED),
    2200                 :                    "Brand-new tags should not be unwanted");
    2201             173 :       if (IsDuplicatePlugin(pluginTag)) {
    2202               0 :         pluginTag->Mark(NS_PLUGIN_FLAG_UNWANTED);
    2203               0 :         pluginTag->mNext = mCachedPlugins;
    2204               0 :         mCachedPlugins = pluginTag;
    2205                 :       }
    2206                 : 
    2207                 :       // Plugin unloading is tag-based. If we created a new tag and loaded
    2208                 :       // the library in the process then we want to attempt to unload it here.
    2209                 :       // Only do this if the pref is set for aggressive unloading.
    2210             173 :       if (UnloadPluginsASAP()) {
    2211               0 :         pluginTag->TryUnloadPlugin(false);
    2212                 :       }
    2213                 :     }
    2214                 : 
    2215                 :     // set the flag that we want to add this plugin to the list for now
    2216                 :     // and see if it remains after we check several reasons not to do so
    2217             173 :     bool bAddIt = true;
    2218                 :     
    2219             173 :     if (HaveSamePlugin(pluginTag)) {
    2220                 :       // we cannot get here if the plugin has just been added
    2221                 :       // and thus |pluginTag| is not from cache, because otherwise
    2222                 :       // it would not be present in the list;
    2223               0 :       bAddIt = false;
    2224                 :     }
    2225                 : 
    2226                 :     // do it if we still want it
    2227             173 :     if (bAddIt) {
    2228             173 :       if (!seenBefore) {
    2229                 :         // We have a valid new plugin so report that plugins have changed.
    2230             172 :         *aPluginsChanged = true;
    2231                 :       }
    2232                 : 
    2233                 :       // If we're not creating a plugin list, simply looking for changes,
    2234                 :       // then we're done.
    2235             173 :       if (!aCreatePluginList) {
    2236               0 :         return NS_OK;
    2237                 :       }
    2238                 : 
    2239             173 :       pluginTag->SetHost(this);
    2240                 : 
    2241                 :       // Add plugin tags such that the list is ordered by modification date,
    2242                 :       // newest to oldest. This is ugly, it'd be easier with just about anything
    2243                 :       // other than a single-directional linked list.
    2244             173 :       if (mPlugins) {
    2245               0 :         nsPluginTag *prev = nsnull;
    2246               0 :         nsPluginTag *next = mPlugins;
    2247               0 :         while (next) {
    2248               0 :           if (pluginTag->mLastModifiedTime >= next->mLastModifiedTime) {
    2249               0 :             pluginTag->mNext = next;
    2250               0 :             if (prev) {
    2251               0 :               prev->mNext = pluginTag;
    2252                 :             } else {
    2253               0 :               mPlugins = pluginTag;
    2254                 :             }
    2255               0 :             break;
    2256                 :           }
    2257               0 :           prev = next;
    2258               0 :           next = prev->mNext;
    2259               0 :           if (!next) {
    2260               0 :             prev->mNext = pluginTag;
    2261                 :           }
    2262                 :         }
    2263                 :       } else {
    2264             173 :         mPlugins = pluginTag;
    2265                 :       }
    2266                 : 
    2267             173 :       if (pluginTag->IsEnabled()) {
    2268             172 :         pluginTag->RegisterWithCategoryManager(mOverrideInternalTypes);
    2269                 :       }
    2270                 :     }
    2271                 :   }
    2272                 : 
    2273             346 :   if (warnOutdated) {
    2274               2 :     mPrefService->SetBoolPref("plugins.update.notifyUser", true);
    2275                 :   }
    2276                 : 
    2277             346 :   return NS_OK;
    2278                 : }
    2279                 : 
    2280             173 : nsresult nsPluginHost::ScanPluginsDirectoryList(nsISimpleEnumerator *dirEnum,
    2281                 :                                                 bool aCreatePluginList,
    2282                 :                                                 bool *aPluginsChanged)
    2283                 : {
    2284                 :     bool hasMore;
    2285             692 :     while (NS_SUCCEEDED(dirEnum->HasMoreElements(&hasMore)) && hasMore) {
    2286             692 :       nsCOMPtr<nsISupports> supports;
    2287             346 :       nsresult rv = dirEnum->GetNext(getter_AddRefs(supports));
    2288             346 :       if (NS_FAILED(rv))
    2289               0 :         continue;
    2290             692 :       nsCOMPtr<nsIFile> nextDir(do_QueryInterface(supports, &rv));
    2291             346 :       if (NS_FAILED(rv))
    2292               0 :         continue;
    2293                 :       
    2294                 :       // don't pass aPluginsChanged directly to prevent it from been reset
    2295             346 :       bool pluginschanged = false;
    2296             346 :       ScanPluginsDirectory(nextDir, aCreatePluginList, &pluginschanged);
    2297                 : 
    2298             346 :       if (pluginschanged)
    2299             173 :         *aPluginsChanged = true;
    2300                 : 
    2301                 :       // if changes are detected and we are not creating the list, do not proceed
    2302             346 :       if (!aCreatePluginList && *aPluginsChanged)
    2303                 :         break;
    2304                 :     }
    2305             173 :     return NS_OK;
    2306                 : }
    2307                 : 
    2308             858 : nsresult nsPluginHost::LoadPlugins()
    2309                 : {
    2310                 : #ifdef ANDROID
    2311                 :   if (XRE_GetProcessType() == GeckoProcessType_Content) {
    2312                 :     return NS_OK;
    2313                 :   }
    2314                 : #endif
    2315                 :   // do not do anything if it is already done
    2316                 :   // use ReloadPlugins() to enforce loading
    2317             858 :   if (mPluginsLoaded)
    2318             684 :     return NS_OK;
    2319                 : 
    2320             174 :   if (mPluginsDisabled)
    2321               0 :     return NS_OK;
    2322                 : 
    2323                 :   bool pluginschanged;
    2324             174 :   nsresult rv = FindPlugins(true, &pluginschanged);
    2325             174 :   if (NS_FAILED(rv))
    2326               0 :     return rv;
    2327                 : 
    2328                 :   // only if plugins have changed will we notify plugin-change observers
    2329             174 :   if (pluginschanged) {
    2330                 :     nsCOMPtr<nsIObserverService> obsService =
    2331             346 :       mozilla::services::GetObserverService();
    2332             173 :     if (obsService)
    2333             173 :       obsService->NotifyObservers(nsnull, "plugins-list-updated", nsnull);
    2334                 :   }
    2335                 : 
    2336             174 :   return NS_OK;
    2337                 : }
    2338                 : 
    2339                 : // if aCreatePluginList is false we will just scan for plugins
    2340                 : // and see if any changes have been made to the plugins.
    2341                 : // This is needed in ReloadPlugins to prevent possible recursive reloads
    2342             174 : nsresult nsPluginHost::FindPlugins(bool aCreatePluginList, bool * aPluginsChanged)
    2343                 : {
    2344             348 :   Telemetry::AutoTimer<Telemetry::FIND_PLUGINS> telemetry;
    2345                 : 
    2346                 : #ifdef CALL_SAFETY_ON
    2347                 :   // check preferences on whether or not we want to try safe calls to plugins
    2348                 :   NS_INIT_PLUGIN_SAFE_CALLS;
    2349                 : #endif
    2350                 : 
    2351             174 :   NS_ENSURE_ARG_POINTER(aPluginsChanged);
    2352                 : 
    2353             174 :   *aPluginsChanged = false;
    2354                 :   nsresult rv;
    2355                 : 
    2356                 :   // Read cached plugins info. If the profile isn't yet available then don't
    2357                 :   // scan for plugins
    2358             174 :   if (ReadPluginInfo() == NS_ERROR_NOT_AVAILABLE)
    2359               1 :     return NS_OK;
    2360                 : 
    2361                 : #ifdef XP_WIN
    2362                 :   // Failure here is not a show-stopper so just warn.
    2363                 :   rv = EnsurePrivateDirServiceProvider();
    2364                 :   NS_ASSERTION(NS_SUCCEEDED(rv), "Failed to register dir service provider.");
    2365                 : #endif /* XP_WIN */
    2366                 : 
    2367             346 :   nsCOMPtr<nsIProperties> dirService(do_GetService(kDirectoryServiceContractID, &rv));
    2368             173 :   if (NS_FAILED(rv))
    2369               0 :     return rv;
    2370                 : 
    2371             346 :   nsCOMPtr<nsISimpleEnumerator> dirList;
    2372                 : 
    2373                 :   // Scan plugins directories;
    2374                 :   // don't pass aPluginsChanged directly, to prevent its
    2375                 :   // possible reset in subsequent ScanPluginsDirectory calls
    2376             173 :   bool pluginschanged = false;
    2377                 : 
    2378                 :   // Scan the app-defined list of plugin dirs.
    2379             173 :   rv = dirService->Get(NS_APP_PLUGINS_DIR_LIST, NS_GET_IID(nsISimpleEnumerator), getter_AddRefs(dirList));
    2380             173 :   if (NS_SUCCEEDED(rv)) {
    2381             173 :     ScanPluginsDirectoryList(dirList, aCreatePluginList, &pluginschanged);
    2382                 : 
    2383             173 :     if (pluginschanged)
    2384             173 :       *aPluginsChanged = true;
    2385                 : 
    2386                 :     // if we are just looking for possible changes,
    2387                 :     // no need to proceed if changes are detected
    2388             173 :     if (!aCreatePluginList && *aPluginsChanged) {
    2389               0 :       NS_ITERATIVE_UNREF_LIST(nsRefPtr<nsPluginTag>, mCachedPlugins, mNext);
    2390               0 :       NS_ITERATIVE_UNREF_LIST(nsRefPtr<nsInvalidPluginTag>, mInvalidPlugins, mNext);
    2391               0 :       return NS_OK;
    2392                 :     }
    2393                 :   } else {
    2394                 : #ifdef ANDROID
    2395                 :     LOG("getting plugins dir failed");
    2396                 : #endif
    2397                 :   }
    2398                 : 
    2399             173 :   mPluginsLoaded = true; // at this point 'some' plugins have been loaded,
    2400                 :                             // the rest is optional
    2401                 : 
    2402                 : #ifdef XP_WIN
    2403                 :   bool bScanPLIDs = false;
    2404                 : 
    2405                 :   if (mPrefService)
    2406                 :     mPrefService->GetBoolPref("plugin.scan.plid.all", &bScanPLIDs);
    2407                 : 
    2408                 :     // Now lets scan any PLID directories
    2409                 :   if (bScanPLIDs && mPrivateDirServiceProvider) {
    2410                 :     rv = mPrivateDirServiceProvider->GetPLIDDirectories(getter_AddRefs(dirList));
    2411                 :     if (NS_SUCCEEDED(rv)) {
    2412                 :       ScanPluginsDirectoryList(dirList, aCreatePluginList, &pluginschanged);
    2413                 : 
    2414                 :       if (pluginschanged)
    2415                 :         *aPluginsChanged = true;
    2416                 : 
    2417                 :       // if we are just looking for possible changes,
    2418                 :       // no need to proceed if changes are detected
    2419                 :       if (!aCreatePluginList && *aPluginsChanged) {
    2420                 :         NS_ITERATIVE_UNREF_LIST(nsRefPtr<nsPluginTag>, mCachedPlugins, mNext);
    2421                 :         NS_ITERATIVE_UNREF_LIST(nsRefPtr<nsInvalidPluginTag>, mInvalidPlugins, mNext);
    2422                 :         return NS_OK;
    2423                 :       }
    2424                 :     }
    2425                 :   }
    2426                 : 
    2427                 : 
    2428                 :   // Scan the installation paths of our popular plugins if the prefs are enabled
    2429                 : 
    2430                 :   // This table controls the order of scanning
    2431                 :   const char* const prefs[] = {NS_WIN_JRE_SCAN_KEY,
    2432                 :                                NS_WIN_ACROBAT_SCAN_KEY,
    2433                 :                                NS_WIN_QUICKTIME_SCAN_KEY,
    2434                 :                                NS_WIN_WMP_SCAN_KEY};
    2435                 : 
    2436                 :   PRUint32 size = sizeof(prefs) / sizeof(prefs[0]);
    2437                 : 
    2438                 :   for (PRUint32 i = 0; i < size; i+=1) {
    2439                 :     nsCOMPtr<nsIFile> dirToScan;
    2440                 :     bool bExists;
    2441                 :     if (NS_SUCCEEDED(dirService->Get(prefs[i], NS_GET_IID(nsIFile), getter_AddRefs(dirToScan))) &&
    2442                 :         dirToScan &&
    2443                 :         NS_SUCCEEDED(dirToScan->Exists(&bExists)) &&
    2444                 :         bExists) {
    2445                 :       
    2446                 :       ScanPluginsDirectory(dirToScan, aCreatePluginList, &pluginschanged);
    2447                 : 
    2448                 :       if (pluginschanged)
    2449                 :         *aPluginsChanged = true;
    2450                 : 
    2451                 :       // if we are just looking for possible changes,
    2452                 :       // no need to proceed if changes are detected
    2453                 :       if (!aCreatePluginList && *aPluginsChanged) {
    2454                 :         NS_ITERATIVE_UNREF_LIST(nsRefPtr<nsPluginTag>, mCachedPlugins, mNext);
    2455                 :         NS_ITERATIVE_UNREF_LIST(nsRefPtr<nsInvalidPluginTag>, mInvalidPlugins, mNext);
    2456                 :         return NS_OK;
    2457                 :       }
    2458                 :     }
    2459                 :   }
    2460                 : #endif
    2461                 : 
    2462                 :   // if get to this point and did not detect changes in plugins
    2463                 :   // that means no plugins got updated or added
    2464                 :   // let's see if plugins have been removed
    2465             173 :   if (!*aPluginsChanged) {
    2466                 :     // count plugins remained in cache, if there are some, that means some plugins were removed;
    2467                 :     // while counting, we should ignore unwanted plugins which are also present in cache
    2468               0 :     PRUint32 cachecount = 0;
    2469               0 :     for (nsPluginTag * cachetag = mCachedPlugins; cachetag; cachetag = cachetag->mNext) {
    2470               0 :       if (!cachetag->HasFlag(NS_PLUGIN_FLAG_UNWANTED))
    2471               0 :         cachecount++;
    2472                 :     }
    2473                 :     // if there is something left in cache, some plugins got removed from the directory
    2474                 :     // and therefor their info did not get removed from the cache info list during directory scan;
    2475                 :     // flag this fact
    2476               0 :     if (cachecount > 0)
    2477               0 :       *aPluginsChanged = true;
    2478                 :   }
    2479                 :   
    2480                 :   // Remove unseen invalid plugins
    2481             346 :   nsRefPtr<nsInvalidPluginTag> invalidPlugins = mInvalidPlugins;
    2482             346 :   while (invalidPlugins) {
    2483               0 :     if (!invalidPlugins->mSeen) {
    2484               0 :       nsRefPtr<nsInvalidPluginTag> invalidPlugin = invalidPlugins;
    2485                 :       
    2486               0 :       if (invalidPlugin->mPrev) {
    2487               0 :         invalidPlugin->mPrev->mNext = invalidPlugin->mNext;
    2488                 :       }
    2489                 :       else {
    2490               0 :         mInvalidPlugins = invalidPlugin->mNext;
    2491                 :       }
    2492               0 :       if (invalidPlugin->mNext) {
    2493               0 :         invalidPlugin->mNext->mPrev = invalidPlugin->mPrev; 
    2494                 :       }
    2495                 :       
    2496               0 :       invalidPlugins = invalidPlugin->mNext;
    2497                 :       
    2498               0 :       invalidPlugin->mPrev = NULL;
    2499               0 :       invalidPlugin->mNext = NULL;
    2500                 :     }
    2501                 :     else {
    2502               0 :       invalidPlugins->mSeen = false;
    2503               0 :       invalidPlugins = invalidPlugins->mNext;
    2504                 :     }
    2505                 :   }
    2506                 : 
    2507                 :   // if we are not creating the list, there is no need to proceed
    2508             173 :   if (!aCreatePluginList) {
    2509               0 :     NS_ITERATIVE_UNREF_LIST(nsRefPtr<nsPluginTag>, mCachedPlugins, mNext);
    2510               0 :     NS_ITERATIVE_UNREF_LIST(nsRefPtr<nsInvalidPluginTag>, mInvalidPlugins, mNext);
    2511               0 :     return NS_OK;
    2512                 :   }
    2513                 : 
    2514                 :   // if we are creating the list, it is already done;
    2515                 :   // update the plugins info cache if changes are detected
    2516             173 :   if (*aPluginsChanged)
    2517             173 :     WritePluginInfo();
    2518                 : 
    2519                 :   // No more need for cached plugins. Clear it up.
    2520             173 :   NS_ITERATIVE_UNREF_LIST(nsRefPtr<nsPluginTag>, mCachedPlugins, mNext);
    2521             173 :   NS_ITERATIVE_UNREF_LIST(nsRefPtr<nsInvalidPluginTag>, mInvalidPlugins, mNext);
    2522                 : 
    2523             173 :   return NS_OK;
    2524                 : }
    2525                 : 
    2526                 : nsresult
    2527               4 : nsPluginHost::UpdatePluginInfo(nsPluginTag* aPluginTag)
    2528                 : {
    2529               4 :   ReadPluginInfo();
    2530               4 :   WritePluginInfo();
    2531               4 :   NS_ITERATIVE_UNREF_LIST(nsRefPtr<nsPluginTag>, mCachedPlugins, mNext);
    2532               4 :   NS_ITERATIVE_UNREF_LIST(nsRefPtr<nsInvalidPluginTag>, mInvalidPlugins, mNext);
    2533                 : 
    2534               4 :   if (!aPluginTag || aPluginTag->IsEnabled())
    2535               2 :     return NS_OK;
    2536                 : 
    2537               4 :   nsCOMPtr<nsISupportsArray> instsToReload;
    2538               2 :   NS_NewISupportsArray(getter_AddRefs(instsToReload));
    2539               2 :   DestroyRunningInstances(instsToReload, aPluginTag);
    2540                 :   
    2541                 :   PRUint32 c;
    2542               2 :   if (instsToReload && NS_SUCCEEDED(instsToReload->Count(&c)) && c > 0) {
    2543               0 :     nsCOMPtr<nsIRunnable> ev = new nsPluginDocReframeEvent(instsToReload);
    2544               0 :     if (ev)
    2545               0 :       NS_DispatchToCurrentThread(ev);
    2546                 :   }
    2547                 : 
    2548               2 :   return NS_OK;
    2549                 : }
    2550                 : 
    2551                 : nsresult
    2552             177 : nsPluginHost::WritePluginInfo()
    2553                 : {
    2554                 : 
    2555             177 :   nsresult rv = NS_OK;
    2556             354 :   nsCOMPtr<nsIProperties> directoryService(do_GetService(NS_DIRECTORY_SERVICE_CONTRACTID,&rv));
    2557             177 :   if (NS_FAILED(rv))
    2558               0 :     return rv;
    2559                 : 
    2560             177 :   directoryService->Get(NS_APP_USER_PROFILE_50_DIR, NS_GET_IID(nsIFile),
    2561             177 :                         getter_AddRefs(mPluginRegFile));
    2562                 : 
    2563             177 :   if (!mPluginRegFile)
    2564              15 :     return NS_ERROR_FAILURE;
    2565                 : 
    2566             162 :   PRFileDesc* fd = nsnull;
    2567                 : 
    2568             324 :   nsCOMPtr<nsIFile> pluginReg;
    2569                 : 
    2570             162 :   rv = mPluginRegFile->Clone(getter_AddRefs(pluginReg));
    2571             162 :   if (NS_FAILED(rv))
    2572               0 :     return rv;
    2573                 : 
    2574             324 :   nsCAutoString filename(kPluginRegistryFilename);
    2575             162 :   filename.Append(".tmp");
    2576             162 :   rv = pluginReg->AppendNative(filename);
    2577             162 :   if (NS_FAILED(rv))
    2578               0 :     return rv;
    2579                 : 
    2580             324 :   nsCOMPtr<nsILocalFile> localFile = do_QueryInterface(pluginReg, &rv);
    2581             162 :   if (NS_FAILED(rv))
    2582               0 :     return rv;
    2583                 : 
    2584             162 :   rv = localFile->OpenNSPRFileDesc(PR_WRONLY | PR_CREATE_FILE | PR_TRUNCATE, 0600, &fd);
    2585             162 :   if (NS_FAILED(rv))
    2586               0 :     return rv;
    2587                 : 
    2588             324 :   nsCOMPtr<nsIXULRuntime> runtime = do_GetService("@mozilla.org/xre/runtime;1");
    2589             162 :   if (!runtime) {
    2590               0 :     return NS_ERROR_FAILURE;
    2591                 :   }
    2592                 :     
    2593             324 :   nsCAutoString arch;
    2594             162 :   rv = runtime->GetXPCOMABI(arch);
    2595             162 :   if (NS_FAILED(rv)) {
    2596               0 :     return rv;
    2597                 :   }
    2598                 : 
    2599             162 :   PR_fprintf(fd, "Generated File. Do not edit.\n");
    2600                 : 
    2601                 :   PR_fprintf(fd, "\n[HEADER]\nVersion%c%s%c%c\nArch%c%s%c%c\n",
    2602                 :              PLUGIN_REGISTRY_FIELD_DELIMITER,
    2603                 :              kPluginRegistryVersion,
    2604                 :              PLUGIN_REGISTRY_FIELD_DELIMITER,
    2605                 :              PLUGIN_REGISTRY_END_OF_LINE_MARKER,
    2606                 :              PLUGIN_REGISTRY_FIELD_DELIMITER,
    2607                 :              arch.get(),
    2608                 :              PLUGIN_REGISTRY_FIELD_DELIMITER,
    2609             162 :              PLUGIN_REGISTRY_END_OF_LINE_MARKER);
    2610                 : 
    2611                 :   // Store all plugins in the mPlugins list - all plugins currently in use.
    2612             162 :   PR_fprintf(fd, "\n[PLUGINS]\n");
    2613                 : 
    2614             162 :   nsPluginTag *taglist[] = {mPlugins, mCachedPlugins};
    2615             486 :   for (int i=0; i<(int)(sizeof(taglist)/sizeof(nsPluginTag *)); i++) {
    2616             490 :     for (nsPluginTag *tag = taglist[i]; tag; tag=tag->mNext) {
    2617                 :       // from mCachedPlugins list write down only unwanted plugins
    2618             166 :       if ((taglist[i] == mCachedPlugins) && !tag->HasFlag(NS_PLUGIN_FLAG_UNWANTED))
    2619               4 :         continue;
    2620                 :       // store each plugin info into the registry
    2621                 :       // filename & fullpath are on separate line
    2622                 :       // because they can contain field delimiter char
    2623                 :       PR_fprintf(fd, "%s%c%c\n%s%c%c\n%s%c%c\n",
    2624                 :         (tag->mFileName.get()),
    2625                 :         PLUGIN_REGISTRY_FIELD_DELIMITER,
    2626                 :         PLUGIN_REGISTRY_END_OF_LINE_MARKER,
    2627                 :         (tag->mFullPath.get()),
    2628                 :         PLUGIN_REGISTRY_FIELD_DELIMITER,
    2629                 :         PLUGIN_REGISTRY_END_OF_LINE_MARKER,
    2630                 :         (tag->mVersion.get()),
    2631                 :         PLUGIN_REGISTRY_FIELD_DELIMITER,
    2632             162 :         PLUGIN_REGISTRY_END_OF_LINE_MARKER);
    2633                 : 
    2634                 :       // lastModifiedTimeStamp|canUnload|tag->mFlags
    2635                 :       PR_fprintf(fd, "%lld%c%d%c%lu%c%c\n",
    2636                 :         tag->mLastModifiedTime,
    2637                 :         PLUGIN_REGISTRY_FIELD_DELIMITER,
    2638                 :         false, // did store whether or not to unload in-process plugins
    2639                 :         PLUGIN_REGISTRY_FIELD_DELIMITER,
    2640                 :         tag->Flags(),
    2641                 :         PLUGIN_REGISTRY_FIELD_DELIMITER,
    2642             162 :         PLUGIN_REGISTRY_END_OF_LINE_MARKER);
    2643                 : 
    2644                 :       //description, name & mtypecount are on separate line
    2645                 :       PR_fprintf(fd, "%s%c%c\n%s%c%c\n%d\n",
    2646                 :         (tag->mDescription.get()),
    2647                 :         PLUGIN_REGISTRY_FIELD_DELIMITER,
    2648                 :         PLUGIN_REGISTRY_END_OF_LINE_MARKER,
    2649                 :         (tag->mName.get()),
    2650                 :         PLUGIN_REGISTRY_FIELD_DELIMITER,
    2651                 :         PLUGIN_REGISTRY_END_OF_LINE_MARKER,
    2652             162 :         tag->mMimeTypes.Length() + (tag->mIsNPRuntimeEnabledJavaPlugin ? 1 : 0));
    2653                 : 
    2654                 :       // Add in each mimetype this plugin supports
    2655             324 :       for (PRUint32 i = 0; i < tag->mMimeTypes.Length(); i++) {
    2656                 :         PR_fprintf(fd, "%d%c%s%c%s%c%s%c%c\n",
    2657                 :           i,PLUGIN_REGISTRY_FIELD_DELIMITER,
    2658             162 :           (tag->mMimeTypes[i].get()),
    2659                 :           PLUGIN_REGISTRY_FIELD_DELIMITER,
    2660             162 :           (tag->mMimeDescriptions[i].get()),
    2661                 :           PLUGIN_REGISTRY_FIELD_DELIMITER,
    2662             162 :           (tag->mExtensions[i].get()),
    2663                 :           PLUGIN_REGISTRY_FIELD_DELIMITER,
    2664             486 :           PLUGIN_REGISTRY_END_OF_LINE_MARKER);
    2665                 :       }
    2666                 : 
    2667             162 :       if (tag->mIsNPRuntimeEnabledJavaPlugin) {
    2668                 :         PR_fprintf(fd, "%d%c%s%c%s%c%s%c%c\n",
    2669                 :           tag->mMimeTypes.Length(), PLUGIN_REGISTRY_FIELD_DELIMITER,
    2670                 :           "application/x-java-vm-npruntime",
    2671                 :           PLUGIN_REGISTRY_FIELD_DELIMITER,
    2672                 :           "",
    2673                 :           PLUGIN_REGISTRY_FIELD_DELIMITER,
    2674                 :           "",
    2675                 :           PLUGIN_REGISTRY_FIELD_DELIMITER,
    2676               0 :           PLUGIN_REGISTRY_END_OF_LINE_MARKER);
    2677                 :       }
    2678                 :     }
    2679                 :   }
    2680                 :   
    2681             162 :   PR_fprintf(fd, "\n[INVALID]\n");
    2682                 :   
    2683             324 :   nsRefPtr<nsInvalidPluginTag> invalidPlugins = mInvalidPlugins;
    2684             324 :   while (invalidPlugins) {
    2685                 :     // fullPath
    2686                 :     PR_fprintf(fd, "%s%c%c\n",
    2687               0 :       (!invalidPlugins->mFullPath.IsEmpty() ? invalidPlugins->mFullPath.get() : ""),
    2688                 :       PLUGIN_REGISTRY_FIELD_DELIMITER,
    2689               0 :       PLUGIN_REGISTRY_END_OF_LINE_MARKER);
    2690                 : 
    2691                 :     // lastModifiedTimeStamp
    2692                 :     PR_fprintf(fd, "%lld%c%c\n",
    2693               0 :       invalidPlugins->mLastModifiedTime,
    2694                 :       PLUGIN_REGISTRY_FIELD_DELIMITER,
    2695               0 :       PLUGIN_REGISTRY_END_OF_LINE_MARKER);
    2696                 :     
    2697               0 :     invalidPlugins = invalidPlugins->mNext;
    2698                 :   }
    2699                 : 
    2700             162 :   PR_Close(fd);
    2701             324 :   nsCOMPtr<nsIFile> parent;
    2702             162 :   rv = localFile->GetParent(getter_AddRefs(parent));
    2703             162 :   NS_ENSURE_SUCCESS(rv, rv);
    2704             162 :   rv = localFile->MoveToNative(parent, kPluginRegistryFilename);
    2705             162 :   return rv;
    2706                 : }
    2707                 : 
    2708                 : #define PLUGIN_REG_MIMETYPES_ARRAY_SIZE 12
    2709                 : nsresult
    2710             178 : nsPluginHost::ReadPluginInfo()
    2711                 : {
    2712                 :   nsresult rv;
    2713                 : 
    2714             356 :   nsCOMPtr<nsIProperties> directoryService(do_GetService(NS_DIRECTORY_SERVICE_CONTRACTID,&rv));
    2715             178 :   if (NS_FAILED(rv))
    2716               0 :     return rv;
    2717                 : 
    2718             178 :   directoryService->Get(NS_APP_USER_PROFILE_50_DIR, NS_GET_IID(nsIFile),
    2719             178 :                         getter_AddRefs(mPluginRegFile));
    2720                 : 
    2721             178 :   if (!mPluginRegFile) {
    2722                 :     // There is no profile yet, this will tell us if there is going to be one
    2723                 :     // in the future.
    2724              16 :     directoryService->Get(NS_APP_PROFILE_DIR_STARTUP, NS_GET_IID(nsIFile),
    2725              16 :                           getter_AddRefs(mPluginRegFile));
    2726              16 :     if (!mPluginRegFile)
    2727              15 :       return NS_ERROR_FAILURE;
    2728                 :     else
    2729               1 :       return NS_ERROR_NOT_AVAILABLE;
    2730                 :   }
    2731                 : 
    2732             162 :   PRFileDesc* fd = nsnull;
    2733                 : 
    2734             324 :   nsCOMPtr<nsIFile> pluginReg;
    2735                 : 
    2736             162 :   rv = mPluginRegFile->Clone(getter_AddRefs(pluginReg));
    2737             162 :   if (NS_FAILED(rv))
    2738               0 :     return rv;
    2739                 : 
    2740             162 :   rv = pluginReg->AppendNative(kPluginRegistryFilename);
    2741             162 :   if (NS_FAILED(rv))
    2742               0 :     return rv;
    2743                 : 
    2744             324 :   nsCOMPtr<nsILocalFile> localFile = do_QueryInterface(pluginReg, &rv);
    2745             162 :   if (NS_FAILED(rv))
    2746               0 :     return rv;
    2747                 : 
    2748                 :   PRInt64 fileSize;
    2749             162 :   rv = localFile->GetFileSize(&fileSize);
    2750             162 :   if (NS_FAILED(rv))
    2751             157 :     return rv;
    2752                 : 
    2753               5 :   PRInt32 flen = PRInt64(fileSize);
    2754               5 :   if (flen == 0) {
    2755               0 :     NS_WARNING("Plugins Registry Empty!");
    2756               0 :     return NS_OK; // ERROR CONDITION
    2757                 :   }
    2758                 : 
    2759              10 :   nsPluginManifestLineReader reader;
    2760               5 :   char* registry = reader.Init(flen);
    2761               5 :   if (!registry)
    2762               0 :     return NS_ERROR_OUT_OF_MEMORY;
    2763                 : 
    2764               5 :   rv = localFile->OpenNSPRFileDesc(PR_RDONLY, 0444, &fd);
    2765               5 :   if (NS_FAILED(rv))
    2766               0 :     return rv;
    2767                 : 
    2768                 :   // set rv to return an error on goto out
    2769               5 :   rv = NS_ERROR_FAILURE;
    2770                 : 
    2771               5 :   PRInt32 bread = PR_Read(fd, registry, flen);
    2772               5 :   PR_Close(fd);
    2773                 : 
    2774               5 :   if (flen > bread)
    2775               0 :     return rv;
    2776                 : 
    2777               5 :   if (!ReadSectionHeader(reader, "HEADER"))
    2778               0 :     return rv;;
    2779                 : 
    2780               5 :   if (!reader.NextLine())
    2781               0 :     return rv;
    2782                 : 
    2783                 :   char* values[6];
    2784                 : 
    2785                 :   // VersionLiteral, kPluginRegistryVersion
    2786               5 :   if (2 != reader.ParseLine(values, 2))
    2787               0 :     return rv;
    2788                 : 
    2789                 :   // VersionLiteral
    2790               5 :   if (PL_strcmp(values[0], "Version"))
    2791               0 :     return rv;
    2792                 : 
    2793                 :   // kPluginRegistryVersion
    2794               5 :   PRInt32 vdiff = NS_CompareVersions(values[1], kPluginRegistryVersion);
    2795                 :   // If this is a registry from some future version then don't attempt to read it
    2796               5 :   if (vdiff > 0)
    2797               0 :     return rv;
    2798                 :   // If this is a registry from before the minimum then don't attempt to read it
    2799               5 :   if (NS_CompareVersions(values[1], kMinimumRegistryVersion) < 0)
    2800               0 :     return rv;
    2801                 : 
    2802                 :   // Registry v0.10 and upwards includes the plugin version field
    2803               5 :   bool regHasVersion = NS_CompareVersions(values[1], "0.10") >= 0;
    2804                 : 
    2805                 :   // Registry v0.13 and upwards includes the architecture
    2806               5 :   if (NS_CompareVersions(values[1], "0.13") >= 0) {
    2807                 :     char* archValues[6];
    2808                 :     
    2809               4 :     if (!reader.NextLine()) {
    2810               0 :       return rv;
    2811                 :     }
    2812                 :     
    2813                 :     // ArchLiteral, Architecture
    2814               4 :     if (2 != reader.ParseLine(archValues, 2)) {
    2815               0 :       return rv;
    2816                 :     }
    2817                 :       
    2818                 :     // ArchLiteral
    2819               4 :     if (PL_strcmp(archValues[0], "Arch")) {
    2820               0 :       return rv;
    2821                 :     }
    2822                 :       
    2823               8 :     nsCOMPtr<nsIXULRuntime> runtime = do_GetService("@mozilla.org/xre/runtime;1");
    2824               4 :     if (!runtime) {
    2825               0 :       return rv;
    2826                 :     }
    2827                 :       
    2828               8 :     nsCAutoString arch;
    2829               4 :     if (NS_FAILED(runtime->GetXPCOMABI(arch))) {
    2830               0 :       return rv;
    2831                 :     }
    2832                 :       
    2833                 :     // If this is a registry from a different architecture then don't attempt to read it
    2834               4 :     if (PL_strcmp(archValues[1], arch.get())) {
    2835               0 :       return rv;
    2836                 :     }
    2837                 :   }
    2838                 :   
    2839                 :   // Registry v0.13 and upwards includes the list of invalid plugins
    2840               5 :   bool hasInvalidPlugins = (NS_CompareVersions(values[1], "0.13") >= 0);
    2841                 : 
    2842               5 :   if (!ReadSectionHeader(reader, "PLUGINS"))
    2843               0 :     return rv;
    2844                 : 
    2845                 : #if defined(XP_MACOSX)
    2846                 :   bool hasFullPathInFileNameField = false;
    2847                 : #else
    2848               5 :   bool hasFullPathInFileNameField = (NS_CompareVersions(values[1], "0.11") < 0);
    2849                 : #endif
    2850                 : 
    2851              15 :   while (reader.NextLine()) {
    2852                 :     const char *filename;
    2853                 :     const char *fullpath;
    2854              18 :     nsCAutoString derivedFileName;
    2855                 :     
    2856               9 :     if (hasInvalidPlugins && *reader.LinePtr() == '[') {
    2857                 :       break;
    2858                 :     }
    2859                 :     
    2860               5 :     if (hasFullPathInFileNameField) {
    2861               1 :       fullpath = reader.LinePtr();
    2862               1 :       if (!reader.NextLine())
    2863               0 :         return rv;
    2864                 :       // try to derive a file name from the full path
    2865               1 :       if (fullpath) {
    2866               2 :         nsCOMPtr<nsILocalFile> file = do_CreateInstance("@mozilla.org/file/local;1");
    2867               1 :         file->InitWithNativePath(nsDependentCString(fullpath));
    2868               1 :         file->GetNativeLeafName(derivedFileName);
    2869               1 :         filename = derivedFileName.get();
    2870                 :       } else {
    2871               0 :         filename = NULL;
    2872                 :       }
    2873                 : 
    2874                 :       // skip the next line, useless in this version
    2875               1 :       if (!reader.NextLine())
    2876               0 :         return rv;
    2877                 :     } else {
    2878               4 :       filename = reader.LinePtr();
    2879               4 :       if (!reader.NextLine())
    2880               0 :         return rv;
    2881                 : 
    2882               4 :       fullpath = reader.LinePtr();
    2883               4 :       if (!reader.NextLine())
    2884               0 :         return rv;
    2885                 :     }
    2886                 : 
    2887                 :     const char *version;
    2888               5 :     if (regHasVersion) {
    2889               4 :       version = reader.LinePtr();
    2890               4 :       if (!reader.NextLine())
    2891               0 :         return rv;
    2892                 :     } else {
    2893               1 :       version = "0";
    2894                 :     }
    2895                 : 
    2896                 :     // lastModifiedTimeStamp|canUnload|tag.mFlag
    2897               5 :     if (reader.ParseLine(values, 3) != 3)
    2898               0 :       return rv;
    2899                 : 
    2900                 :     // If this is an old plugin registry mark this plugin tag to be refreshed
    2901               5 :     PRInt64 lastmod = (vdiff == 0) ? nsCRT::atoll(values[0]) : -1;
    2902               5 :     PRUint32 tagflag = atoi(values[2]);
    2903               5 :     if (!reader.NextLine())
    2904               0 :       return rv;
    2905                 : 
    2906               5 :     const char *description = reader.LinePtr();
    2907               5 :     if (!reader.NextLine())
    2908               0 :       return rv;
    2909                 : 
    2910               5 :     const char *name = reader.LinePtr();
    2911               5 :     if (!reader.NextLine())
    2912               0 :       return rv;
    2913                 : 
    2914               5 :     int mimetypecount = atoi(reader.LinePtr());
    2915                 : 
    2916                 :     char *stackalloced[PLUGIN_REG_MIMETYPES_ARRAY_SIZE * 3];
    2917                 :     char **mimetypes;
    2918                 :     char **mimedescriptions;
    2919                 :     char **extensions;
    2920               5 :     char **heapalloced = 0;
    2921               5 :     if (mimetypecount > PLUGIN_REG_MIMETYPES_ARRAY_SIZE - 1) {
    2922               0 :       heapalloced = new char *[mimetypecount * 3];
    2923               0 :       mimetypes = heapalloced;
    2924                 :     } else {
    2925               5 :       mimetypes = stackalloced;
    2926                 :     }
    2927               5 :     mimedescriptions = mimetypes + mimetypecount;
    2928               5 :     extensions = mimedescriptions + mimetypecount;
    2929                 : 
    2930               5 :     int mtr = 0; //mimetype read
    2931              10 :     for (; mtr < mimetypecount; mtr++) {
    2932               5 :       if (!reader.NextLine())
    2933               0 :         break;
    2934                 : 
    2935                 :       //line number|mimetype|description|extension
    2936               5 :       if (4 != reader.ParseLine(values, 4))
    2937               0 :         break;
    2938               5 :       int line = atoi(values[0]);
    2939               5 :       if (line != mtr)
    2940               0 :         break;
    2941               5 :       mimetypes[mtr] = values[1];
    2942               5 :       mimedescriptions[mtr] = values[2];
    2943               5 :       extensions[mtr] = values[3];
    2944                 :     }
    2945                 : 
    2946               5 :     if (mtr != mimetypecount) {
    2947               0 :       if (heapalloced) {
    2948               0 :         delete [] heapalloced;
    2949                 :       }
    2950               0 :       return rv;
    2951                 :     }
    2952                 : 
    2953                 :     nsRefPtr<nsPluginTag> tag = new nsPluginTag(name,
    2954                 :       description,
    2955                 :       filename,
    2956                 :       fullpath,
    2957                 :       version,
    2958                 :       (const char* const*)mimetypes,
    2959                 :       (const char* const*)mimedescriptions,
    2960                 :       (const char* const*)extensions,
    2961              10 :       mimetypecount, lastmod, true);
    2962               5 :     if (heapalloced)
    2963               0 :       delete [] heapalloced;
    2964                 : 
    2965               5 :     if (!tag)
    2966               0 :       continue;
    2967                 : 
    2968                 :     // Mark plugin as loaded from cache
    2969               5 :     tag->Mark(tagflag | NS_PLUGIN_FLAG_FROMCACHE);
    2970               5 :     PR_LOG(nsPluginLogging::gPluginLog, PLUGIN_LOG_BASIC,
    2971                 :       ("LoadCachedPluginsInfo : Loading Cached plugininfo for %s\n", tag->mFileName.get()));
    2972               5 :     tag->mNext = mCachedPlugins;
    2973              10 :     mCachedPlugins = tag;
    2974                 :   }
    2975                 :   
    2976               5 :   if (hasInvalidPlugins) {
    2977               4 :     if (!ReadSectionHeader(reader, "INVALID")) {
    2978               0 :       return rv;
    2979                 :     }
    2980                 : 
    2981               8 :     while (reader.NextLine()) {
    2982               0 :       const char *fullpath = reader.LinePtr();
    2983               0 :       if (!reader.NextLine()) {
    2984               0 :         return rv;
    2985                 :       }
    2986                 :       
    2987               0 :       const char *lastModifiedTimeStamp = reader.LinePtr();
    2988               0 :       PRInt64 lastmod = (vdiff == 0) ? nsCRT::atoll(lastModifiedTimeStamp) : -1;
    2989                 :       
    2990               0 :       nsRefPtr<nsInvalidPluginTag> invalidTag = new nsInvalidPluginTag(fullpath, lastmod);
    2991                 :       
    2992               0 :       invalidTag->mNext = mInvalidPlugins;
    2993               0 :       if (mInvalidPlugins) {
    2994               0 :         mInvalidPlugins->mPrev = invalidTag;
    2995                 :       }
    2996               0 :       mInvalidPlugins = invalidTag;
    2997                 :     }
    2998                 :   }
    2999               5 :   return NS_OK;
    3000                 : }
    3001                 : 
    3002                 : void
    3003             173 : nsPluginHost::RemoveCachedPluginsInfo(const char *filePath, nsPluginTag **result)
    3004                 : {
    3005             346 :   nsRefPtr<nsPluginTag> prev;
    3006             346 :   nsRefPtr<nsPluginTag> tag = mCachedPlugins;
    3007             346 :   while (tag)
    3008                 :   {
    3009               1 :     if (tag->mFullPath.Equals(filePath)) {
    3010                 :       // Found it. Remove it from our list
    3011               1 :       if (prev)
    3012               0 :         prev->mNext = tag->mNext;
    3013                 :       else
    3014               1 :         mCachedPlugins = tag->mNext;
    3015               1 :       tag->mNext = nsnull;
    3016               1 :       *result = tag;
    3017               1 :       NS_ADDREF(*result);
    3018               1 :       break;
    3019                 :     }
    3020               0 :     prev = tag;
    3021               0 :     tag = tag->mNext;
    3022                 :   }
    3023             173 : }
    3024                 : 
    3025                 : #ifdef XP_WIN
    3026                 : nsresult
    3027                 : nsPluginHost::EnsurePrivateDirServiceProvider()
    3028                 : {
    3029                 :   if (!mPrivateDirServiceProvider) {
    3030                 :     nsresult rv;
    3031                 :     mPrivateDirServiceProvider = new nsPluginDirServiceProvider();
    3032                 :     if (!mPrivateDirServiceProvider)
    3033                 :       return NS_ERROR_OUT_OF_MEMORY;
    3034                 :     nsCOMPtr<nsIDirectoryService> dirService(do_GetService(kDirectoryServiceContractID, &rv));
    3035                 :     if (NS_FAILED(rv))
    3036                 :       return rv;
    3037                 :     rv = dirService->RegisterProvider(mPrivateDirServiceProvider);
    3038                 :     if (NS_FAILED(rv))
    3039                 :       return rv;
    3040                 :   }
    3041                 :   return NS_OK;
    3042                 : }
    3043                 : #endif /* XP_WIN */
    3044                 : 
    3045               0 : nsresult nsPluginHost::NewPluginURLStream(const nsString& aURL,
    3046                 :                                           nsNPAPIPluginInstance *aInstance,
    3047                 :                                           nsIPluginStreamListener* aListener,
    3048                 :                                           nsIInputStream *aPostStream,
    3049                 :                                           const char *aHeadersData,
    3050                 :                                           PRUint32 aHeadersDataLen)
    3051                 : {
    3052               0 :   nsCOMPtr<nsIURI> url;
    3053               0 :   nsAutoString absUrl;
    3054                 :   nsresult rv;
    3055                 : 
    3056               0 :   if (aURL.Length() <= 0)
    3057               0 :     return NS_OK;
    3058                 : 
    3059                 :   // get the full URL of the document that the plugin is embedded
    3060                 :   //   in to create an absolute url in case aURL is relative
    3061               0 :   nsCOMPtr<nsIDocument> doc;
    3062               0 :   nsCOMPtr<nsIPluginInstanceOwner> owner;
    3063               0 :   aInstance->GetOwner(getter_AddRefs(owner));
    3064               0 :   if (owner) {
    3065               0 :     rv = owner->GetDocument(getter_AddRefs(doc));
    3066               0 :     if (NS_SUCCEEDED(rv) && doc) {
    3067                 :       // Create an absolute URL
    3068               0 :       rv = NS_MakeAbsoluteURI(absUrl, aURL, doc->GetDocBaseURI());
    3069                 :     }
    3070                 :   }
    3071                 : 
    3072               0 :   if (absUrl.IsEmpty())
    3073               0 :     absUrl.Assign(aURL);
    3074                 : 
    3075               0 :   rv = NS_NewURI(getter_AddRefs(url), absUrl);
    3076               0 :   if (NS_FAILED(rv))
    3077               0 :     return rv;
    3078                 : 
    3079               0 :   nsCOMPtr<nsIPluginTagInfo> pti = do_QueryInterface(owner);
    3080               0 :   nsCOMPtr<nsIDOMElement> element;
    3081               0 :   if (pti)
    3082               0 :     pti->GetDOMElement(getter_AddRefs(element));
    3083                 : 
    3084               0 :   PRInt16 shouldLoad = nsIContentPolicy::ACCEPT;
    3085                 :   rv = NS_CheckContentLoadPolicy(nsIContentPolicy::TYPE_OBJECT_SUBREQUEST,
    3086                 :                                  url,
    3087               0 :                                  (doc ? doc->NodePrincipal() : nsnull),
    3088                 :                                  element,
    3089               0 :                                  EmptyCString(), //mime guess
    3090                 :                                  nsnull,         //extra
    3091               0 :                                  &shouldLoad);
    3092               0 :   if (NS_FAILED(rv))
    3093               0 :     return rv;
    3094               0 :   if (NS_CP_REJECTED(shouldLoad)) {
    3095                 :     // Disallowed by content policy
    3096               0 :     return NS_ERROR_CONTENT_BLOCKED;
    3097                 :   }
    3098                 : 
    3099               0 :   nsRefPtr<nsPluginStreamListenerPeer> listenerPeer = new nsPluginStreamListenerPeer();
    3100               0 :   if (!listenerPeer)
    3101               0 :     return NS_ERROR_OUT_OF_MEMORY;
    3102                 : 
    3103               0 :   rv = listenerPeer->Initialize(url, aInstance, aListener);
    3104               0 :   if (NS_FAILED(rv))
    3105               0 :     return rv;
    3106                 : 
    3107               0 :   nsCOMPtr<nsIChannel> channel;
    3108               0 :   rv = NS_NewChannel(getter_AddRefs(channel), url, nsnull,
    3109                 :     nsnull, /* do not add this internal plugin's channel
    3110                 :             on the load group otherwise this channel could be canceled
    3111                 :             form |nsDocShell::OnLinkClickSync| bug 166613 */
    3112               0 :     listenerPeer);
    3113               0 :   if (NS_FAILED(rv))
    3114               0 :     return rv;
    3115                 : 
    3116               0 :   if (doc) {
    3117                 :     // Set the owner of channel to the document principal...
    3118               0 :     channel->SetOwner(doc->NodePrincipal());
    3119                 : 
    3120                 :     // And if it's a script allow it to execute against the
    3121                 :     // document's script context.
    3122               0 :     nsCOMPtr<nsIScriptChannel> scriptChannel(do_QueryInterface(channel));
    3123               0 :     if (scriptChannel) {
    3124               0 :       scriptChannel->SetExecutionPolicy(nsIScriptChannel::EXECUTE_NORMAL);
    3125                 :       // Plug-ins seem to depend on javascript: URIs running synchronously
    3126               0 :       scriptChannel->SetExecuteAsync(false);
    3127                 :     }
    3128                 :   }
    3129                 : 
    3130                 :   // deal with headers and post data
    3131               0 :   nsCOMPtr<nsIHttpChannel> httpChannel(do_QueryInterface(channel));
    3132               0 :   if (httpChannel) {
    3133               0 :     if (!aPostStream) {
    3134                 :       // Only set the Referer header for GET requests because IIS throws
    3135                 :       // errors about malformed requests if we include it in POSTs. See
    3136                 :       // bug 724465.
    3137               0 :       nsCOMPtr<nsIURI> referer;
    3138                 : 
    3139               0 :       nsCOMPtr<nsIObjectLoadingContent> olc = do_QueryInterface(element);
    3140               0 :       if (olc)
    3141               0 :         olc->GetSrcURI(getter_AddRefs(referer));
    3142                 : 
    3143                 : 
    3144               0 :       if (!referer)
    3145               0 :         referer = doc->GetDocumentURI();
    3146                 : 
    3147               0 :       rv = httpChannel->SetReferrer(referer);
    3148               0 :       NS_ENSURE_SUCCESS(rv,rv);
    3149                 :     }
    3150                 :       
    3151               0 :     if (aPostStream) {
    3152                 :       // XXX it's a bit of a hack to rewind the postdata stream
    3153                 :       // here but it has to be done in case the post data is
    3154                 :       // being reused multiple times.
    3155                 :       nsCOMPtr<nsISeekableStream>
    3156               0 :       postDataSeekable(do_QueryInterface(aPostStream));
    3157               0 :       if (postDataSeekable)
    3158               0 :         postDataSeekable->Seek(nsISeekableStream::NS_SEEK_SET, 0);
    3159                 : 
    3160               0 :       nsCOMPtr<nsIUploadChannel> uploadChannel(do_QueryInterface(httpChannel));
    3161               0 :       NS_ASSERTION(uploadChannel, "http must support nsIUploadChannel");
    3162                 : 
    3163               0 :       uploadChannel->SetUploadStream(aPostStream, EmptyCString(), -1);
    3164                 :     }
    3165                 : 
    3166               0 :     if (aHeadersData) {
    3167               0 :       rv = AddHeadersToChannel(aHeadersData, aHeadersDataLen, httpChannel);
    3168               0 :       NS_ENSURE_SUCCESS(rv,rv);
    3169                 :     }
    3170                 :   }
    3171               0 :   rv = channel->AsyncOpen(listenerPeer, nsnull);
    3172               0 :   if (NS_SUCCEEDED(rv))
    3173               0 :     listenerPeer->TrackRequest(channel);
    3174               0 :   return rv;
    3175                 : }
    3176                 : 
    3177                 : // Called by GetURL and PostURL
    3178                 : nsresult
    3179               0 : nsPluginHost::DoURLLoadSecurityCheck(nsNPAPIPluginInstance *aInstance,
    3180                 :                                      const char* aURL)
    3181                 : {
    3182               0 :   if (!aURL || *aURL == '\0')
    3183               0 :     return NS_OK;
    3184                 : 
    3185                 :   // get the URL of the document that loaded the plugin
    3186               0 :   nsCOMPtr<nsIPluginInstanceOwner> owner;
    3187               0 :   aInstance->GetOwner(getter_AddRefs(owner));
    3188               0 :   if (!owner)
    3189               0 :     return NS_ERROR_FAILURE;
    3190                 : 
    3191               0 :   nsCOMPtr<nsIDocument> doc;
    3192               0 :   owner->GetDocument(getter_AddRefs(doc));
    3193               0 :   if (!doc)
    3194               0 :     return NS_ERROR_FAILURE;
    3195                 : 
    3196                 :   // Create an absolute URL for the target in case the target is relative
    3197               0 :   nsCOMPtr<nsIURI> targetURL;
    3198               0 :   NS_NewURI(getter_AddRefs(targetURL), aURL, doc->GetDocBaseURI());
    3199               0 :   if (!targetURL)
    3200               0 :     return NS_ERROR_FAILURE;
    3201                 : 
    3202                 :   nsresult rv;
    3203                 :   nsCOMPtr<nsIScriptSecurityManager> secMan(
    3204               0 :     do_GetService(NS_SCRIPTSECURITYMANAGER_CONTRACTID, &rv));
    3205               0 :   if (NS_FAILED(rv))
    3206               0 :     return rv;
    3207                 : 
    3208               0 :   return secMan->CheckLoadURIWithPrincipal(doc->NodePrincipal(), targetURL,
    3209               0 :                                            nsIScriptSecurityManager::STANDARD);
    3210                 : 
    3211                 : }
    3212                 : 
    3213                 : nsresult
    3214               0 : nsPluginHost::AddHeadersToChannel(const char *aHeadersData,
    3215                 :                                   PRUint32 aHeadersDataLen,
    3216                 :                                   nsIChannel *aGenericChannel)
    3217                 : {
    3218               0 :   nsresult rv = NS_OK;
    3219                 : 
    3220               0 :   nsCOMPtr<nsIHttpChannel> aChannel = do_QueryInterface(aGenericChannel);
    3221               0 :   if (!aChannel) {
    3222               0 :     return NS_ERROR_NULL_POINTER;
    3223                 :   }
    3224                 : 
    3225                 :   // used during the manipulation of the String from the aHeadersData
    3226               0 :   nsCAutoString headersString;
    3227               0 :   nsCAutoString oneHeader;
    3228               0 :   nsCAutoString headerName;
    3229               0 :   nsCAutoString headerValue;
    3230               0 :   PRInt32 crlf = 0;
    3231               0 :   PRInt32 colon = 0;
    3232                 : 
    3233                 :   // Turn the char * buffer into an nsString.
    3234               0 :   headersString = aHeadersData;
    3235                 : 
    3236                 :   // Iterate over the nsString: for each "\r\n" delimited chunk,
    3237                 :   // add the value as a header to the nsIHTTPChannel
    3238               0 :   while (true) {
    3239               0 :     crlf = headersString.Find("\r\n", true);
    3240               0 :     if (-1 == crlf) {
    3241               0 :       rv = NS_OK;
    3242               0 :       return rv;
    3243                 :     }
    3244               0 :     headersString.Mid(oneHeader, 0, crlf);
    3245               0 :     headersString.Cut(0, crlf + 2);
    3246               0 :     oneHeader.StripWhitespace();
    3247               0 :     colon = oneHeader.Find(":");
    3248               0 :     if (-1 == colon) {
    3249               0 :       rv = NS_ERROR_NULL_POINTER;
    3250               0 :       return rv;
    3251                 :     }
    3252               0 :     oneHeader.Left(headerName, colon);
    3253               0 :     colon++;
    3254               0 :     oneHeader.Mid(headerValue, colon, oneHeader.Length() - colon);
    3255                 : 
    3256                 :     // FINALLY: we can set the header!
    3257                 : 
    3258               0 :     rv = aChannel->SetRequestHeader(headerName, headerValue, true);
    3259               0 :     if (NS_FAILED(rv)) {
    3260               0 :       rv = NS_ERROR_NULL_POINTER;
    3261               0 :       return rv;
    3262                 :     }
    3263                 :   }
    3264                 :   return rv;
    3265                 : }
    3266                 : 
    3267                 : nsresult
    3268               0 : nsPluginHost::StopPluginInstance(nsNPAPIPluginInstance* aInstance)
    3269                 : {
    3270               0 :   if (PluginDestructionGuard::DelayDestroy(aInstance)) {
    3271               0 :     return NS_OK;
    3272                 :   }
    3273                 : 
    3274               0 :   PLUGIN_LOG(PLUGIN_LOG_NORMAL,
    3275                 :   ("nsPluginHost::StopPluginInstance called instance=%p\n",aInstance));
    3276                 : 
    3277               0 :   if (aInstance->HasStartedDestroying()) {
    3278               0 :     return NS_OK;
    3279                 :   }
    3280                 : 
    3281               0 :   Telemetry::AutoTimer<Telemetry::PLUGIN_SHUTDOWN_MS> timer;
    3282               0 :   aInstance->Stop();
    3283                 : 
    3284                 :   // if the instance does not want to be 'cached' just remove it
    3285               0 :   bool doCache = aInstance->ShouldCache();
    3286               0 :   if (doCache) {
    3287                 :     // try to get the max cached instances from a pref or use default
    3288                 :     PRUint32 cachedInstanceLimit;
    3289               0 :     nsresult rv = NS_ERROR_FAILURE;
    3290               0 :     if (mPrefService)
    3291               0 :       rv = mPrefService->GetIntPref(NS_PREF_MAX_NUM_CACHED_INSTANCES, (int*)&cachedInstanceLimit);
    3292               0 :     if (NS_FAILED(rv))
    3293               0 :       cachedInstanceLimit = DEFAULT_NUMBER_OF_STOPPED_INSTANCES;
    3294                 :     
    3295               0 :     if (StoppedInstanceCount() >= cachedInstanceLimit) {
    3296               0 :       nsNPAPIPluginInstance *oldestInstance = FindOldestStoppedInstance();
    3297               0 :       if (oldestInstance) {
    3298               0 :         nsPluginTag* pluginTag = TagForPlugin(oldestInstance->GetPlugin());
    3299               0 :         oldestInstance->Destroy();
    3300               0 :         mInstances.RemoveElement(oldestInstance);
    3301               0 :         OnPluginInstanceDestroyed(pluginTag);
    3302                 :       }
    3303                 :     }
    3304                 :   } else {
    3305               0 :     nsPluginTag* pluginTag = TagForPlugin(aInstance->GetPlugin());
    3306               0 :     aInstance->Destroy();
    3307               0 :     mInstances.RemoveElement(aInstance);
    3308               0 :     OnPluginInstanceDestroyed(pluginTag);
    3309                 :   }
    3310                 : 
    3311               0 :   return NS_OK;
    3312                 : }
    3313                 : 
    3314               0 : nsresult nsPluginHost::NewEmbeddedPluginStreamListener(nsIURI* aURL,
    3315                 :                                                        nsObjectLoadingContent *aContent,
    3316                 :                                                        nsNPAPIPluginInstance* aInstance,
    3317                 :                                                        nsIStreamListener** aListener)
    3318                 : {
    3319               0 :   if (!aURL)
    3320               0 :     return NS_OK;
    3321                 : 
    3322               0 :   nsRefPtr<nsPluginStreamListenerPeer> listener = new nsPluginStreamListenerPeer();
    3323               0 :   if (!listener)
    3324               0 :     return NS_ERROR_OUT_OF_MEMORY;
    3325                 : 
    3326                 :   nsresult rv;
    3327                 : 
    3328                 :   // if we have an instance, everything has been set up
    3329                 :   // if we only have an owner, then we need to pass it in
    3330                 :   // so the listener can set up the instance later after
    3331                 :   // we've determined the mimetype of the stream
    3332               0 :   if (aInstance)
    3333               0 :     rv = listener->InitializeEmbedded(aURL, aInstance, nsnull);
    3334               0 :   else if (aContent)
    3335               0 :     rv = listener->InitializeEmbedded(aURL, nsnull, aContent);
    3336                 :   else
    3337               0 :     rv = NS_ERROR_ILLEGAL_VALUE;
    3338                 : 
    3339               0 :   if (NS_SUCCEEDED(rv))
    3340               0 :     NS_ADDREF(*aListener = listener);
    3341                 : 
    3342               0 :   return rv;
    3343                 : }
    3344                 : 
    3345                 : // Called by InstantiateEmbeddedPlugin()
    3346               0 : nsresult nsPluginHost::NewEmbeddedPluginStream(nsIURI* aURL,
    3347                 :                                                nsObjectLoadingContent *aContent,
    3348                 :                                                nsNPAPIPluginInstance* aInstance)
    3349                 : {
    3350               0 :   nsCOMPtr<nsIStreamListener> listener;
    3351                 :   nsresult rv = NewEmbeddedPluginStreamListener(aURL, aContent, aInstance,
    3352               0 :                                                 getter_AddRefs(listener));
    3353               0 :   if (NS_SUCCEEDED(rv)) {
    3354               0 :     nsCOMPtr<nsIDocument> doc;
    3355               0 :     nsCOMPtr<nsILoadGroup> loadGroup;
    3356               0 :     if (aContent) {
    3357               0 :       nsCOMPtr<nsIContent> aIContent = do_QueryInterface(static_cast<nsIImageLoadingContent*>(aContent));
    3358               0 :       doc = aIContent->GetDocument();
    3359               0 :       if (doc) {
    3360               0 :         loadGroup = doc->GetDocumentLoadGroup();
    3361                 :       }
    3362                 :     }
    3363               0 :     nsCOMPtr<nsIChannel> channel;
    3364               0 :     rv = NS_NewChannel(getter_AddRefs(channel), aURL, nsnull, loadGroup, nsnull);
    3365               0 :     if (NS_SUCCEEDED(rv)) {
    3366                 :       // if this is http channel, set referrer, some servers are configured
    3367                 :       // to reject requests without referrer set, see bug 157796
    3368               0 :       nsCOMPtr<nsIHttpChannel> httpChannel(do_QueryInterface(channel));
    3369               0 :       if (httpChannel && doc)
    3370               0 :         httpChannel->SetReferrer(doc->GetDocumentURI());
    3371                 : 
    3372               0 :       rv = channel->AsyncOpen(listener, nsnull);
    3373               0 :       if (NS_SUCCEEDED(rv))
    3374               0 :         return NS_OK;
    3375                 :     }
    3376                 :   }
    3377                 : 
    3378               0 :   return rv;
    3379                 : }
    3380                 : 
    3381                 : // Called by InstantiateFullPagePlugin()
    3382               0 : nsresult nsPluginHost::NewFullPagePluginStream(nsIURI* aURI,
    3383                 :                                                nsNPAPIPluginInstance *aInstance,
    3384                 :                                                nsIStreamListener **aStreamListener)
    3385                 : {
    3386               0 :   NS_ASSERTION(aStreamListener, "Stream listener out param cannot be null");
    3387                 : 
    3388               0 :   nsRefPtr<nsPluginStreamListenerPeer> listener = new nsPluginStreamListenerPeer();
    3389               0 :   if (!listener)
    3390               0 :     return NS_ERROR_OUT_OF_MEMORY;
    3391                 : 
    3392               0 :   nsresult rv = listener->InitializeFullPage(aURI, aInstance);
    3393               0 :   if (NS_FAILED(rv)) {
    3394               0 :     return rv;
    3395                 :   }
    3396                 : 
    3397               0 :   listener.forget(aStreamListener);
    3398                 : 
    3399               0 :   return NS_OK;
    3400                 : }
    3401                 : 
    3402             173 : NS_IMETHODIMP nsPluginHost::Observe(nsISupports *aSubject,
    3403                 :                                     const char *aTopic,
    3404                 :                                     const PRUnichar *someData)
    3405                 : {
    3406             173 :   if (!nsCRT::strcmp(NS_XPCOM_SHUTDOWN_OBSERVER_ID, aTopic)) {
    3407             173 :     OnShutdown();
    3408             173 :     Destroy();
    3409             173 :     sInst->Release();
    3410                 :   }
    3411             173 :   if (!nsCRT::strcmp(NS_PRIVATE_BROWSING_SWITCH_TOPIC, aTopic)) {
    3412                 :     // inform all active plugins of changed private mode state
    3413               0 :     for (PRUint32 i = 0; i < mInstances.Length(); i++) {
    3414               0 :       mInstances[i]->PrivateModeStateChanged();
    3415                 :     }
    3416                 :   }
    3417                 : #ifdef MOZ_WIDGET_ANDROID
    3418                 :   if (!nsCRT::strcmp("application-background", aTopic)) {
    3419                 :     for(PRUint32 i = 0; i < mInstances.Length(); i++) {
    3420                 :       mInstances[i]->NotifyForeground(false);
    3421                 :     }
    3422                 :   }
    3423                 :   if (!nsCRT::strcmp("application-foreground", aTopic)) {
    3424                 :     for(PRUint32 i = 0; i < mInstances.Length(); i++) {
    3425                 :       if (mInstances[i]->IsOnScreen())
    3426                 :         mInstances[i]->NotifyForeground(true);
    3427                 :     }
    3428                 :   }
    3429                 :   if (!nsCRT::strcmp("memory-pressure", aTopic)) {
    3430                 :     for(PRUint32 i = 0; i < mInstances.Length(); i++) {
    3431                 :       mInstances[i]->MemoryPressure();
    3432                 :     }
    3433                 :   }
    3434                 : #endif
    3435             173 :   return NS_OK;
    3436                 : }
    3437                 : 
    3438                 : nsresult
    3439               0 : nsPluginHost::HandleBadPlugin(PRLibrary* aLibrary, nsNPAPIPluginInstance *aInstance)
    3440                 : {
    3441                 :   // the |aLibrary| parameter is not needed anymore, after we added |aInstance| which
    3442                 :   // can also be used to look up the plugin name, but we cannot get rid of it because
    3443                 :   // the |nsIPluginHost| interface is deprecated which in fact means 'frozen'
    3444                 : 
    3445               0 :   NS_ERROR("Plugin performed illegal operation");
    3446               0 :   NS_ENSURE_ARG_POINTER(aInstance);
    3447                 : 
    3448               0 :   if (mDontShowBadPluginMessage)
    3449               0 :     return NS_OK;
    3450                 : 
    3451               0 :   nsCOMPtr<nsIPluginInstanceOwner> owner;
    3452               0 :   aInstance->GetOwner(getter_AddRefs(owner));
    3453                 : 
    3454               0 :   nsCOMPtr<nsIPrompt> prompt;
    3455               0 :   GetPrompt(owner, getter_AddRefs(prompt));
    3456               0 :   if (!prompt)
    3457               0 :     return NS_OK;
    3458                 : 
    3459                 :   nsCOMPtr<nsIStringBundleService> strings =
    3460               0 :     mozilla::services::GetStringBundleService();
    3461               0 :   if (!strings)
    3462               0 :     return NS_ERROR_FAILURE;
    3463                 : 
    3464               0 :   nsCOMPtr<nsIStringBundle> bundle;
    3465               0 :   nsresult rv = strings->CreateBundle(BRAND_PROPERTIES_URL, getter_AddRefs(bundle));
    3466               0 :   if (NS_FAILED(rv))
    3467               0 :     return rv;
    3468                 : 
    3469               0 :   nsXPIDLString brandName;
    3470               0 :   rv = bundle->GetStringFromName(NS_LITERAL_STRING("brandShortName").get(),
    3471               0 :                                  getter_Copies(brandName));
    3472               0 :   if (NS_FAILED(rv))
    3473               0 :     return rv;
    3474                 : 
    3475               0 :   rv = strings->CreateBundle(PLUGIN_PROPERTIES_URL, getter_AddRefs(bundle));
    3476               0 :   if (NS_FAILED(rv))
    3477               0 :     return rv;
    3478                 : 
    3479               0 :   nsXPIDLString title, message, checkboxMessage;
    3480               0 :   rv = bundle->GetStringFromName(NS_LITERAL_STRING("BadPluginTitle").get(),
    3481               0 :                                  getter_Copies(title));
    3482               0 :   if (NS_FAILED(rv))
    3483               0 :     return rv;
    3484                 : 
    3485               0 :   const PRUnichar *formatStrings[] = { brandName.get() };
    3486               0 :   if (NS_FAILED(rv = bundle->FormatStringFromName(NS_LITERAL_STRING("BadPluginMessage").get(),
    3487                 :                                formatStrings, 1, getter_Copies(message))))
    3488               0 :     return rv;
    3489                 : 
    3490               0 :   rv = bundle->GetStringFromName(NS_LITERAL_STRING("BadPluginCheckboxMessage").get(),
    3491               0 :                                  getter_Copies(checkboxMessage));
    3492               0 :   if (NS_FAILED(rv))
    3493               0 :     return rv;
    3494                 : 
    3495               0 :   nsNPAPIPlugin *plugin = aInstance->GetPlugin();
    3496               0 :   if (!plugin)
    3497               0 :     return NS_ERROR_FAILURE;
    3498                 : 
    3499               0 :   nsPluginTag *pluginTag = TagForPlugin(plugin);
    3500                 : 
    3501                 :   // add plugin name to the message
    3502               0 :   nsCString pluginname;
    3503               0 :   if (pluginTag) {
    3504               0 :     if (!pluginTag->mName.IsEmpty()) {
    3505               0 :       pluginname = pluginTag->mName;
    3506                 :     } else {
    3507               0 :       pluginname = pluginTag->mFileName;
    3508                 :     }
    3509                 :   } else {
    3510               0 :     pluginname.AppendLiteral("???");
    3511                 :   }
    3512                 : 
    3513               0 :   NS_ConvertUTF8toUTF16 msg(pluginname);
    3514               0 :   msg.AppendLiteral("\n\n");
    3515               0 :   msg.Append(message);
    3516                 : 
    3517                 :   PRInt32 buttonPressed;
    3518               0 :   bool checkboxState = false;
    3519               0 :   rv = prompt->ConfirmEx(title, msg.get(),
    3520                 :                        nsIPrompt::BUTTON_TITLE_OK * nsIPrompt::BUTTON_POS_0,
    3521                 :                        nsnull, nsnull, nsnull,
    3522               0 :                        checkboxMessage, &checkboxState, &buttonPressed);
    3523                 : 
    3524                 : 
    3525               0 :   if (NS_SUCCEEDED(rv) && checkboxState)
    3526               0 :     mDontShowBadPluginMessage = true;
    3527                 : 
    3528               0 :   return rv;
    3529                 : }
    3530                 : 
    3531                 : nsresult
    3532               0 : nsPluginHost::ParsePostBufferToFixHeaders(const char *inPostData, PRUint32 inPostDataLen,
    3533                 :                                           char **outPostData, PRUint32 *outPostDataLen)
    3534                 : {
    3535               0 :   if (!inPostData || !outPostData || !outPostDataLen)
    3536               0 :     return NS_ERROR_NULL_POINTER;
    3537                 : 
    3538               0 :   *outPostData = 0;
    3539               0 :   *outPostDataLen = 0;
    3540                 : 
    3541               0 :   const char CR = '\r';
    3542               0 :   const char LF = '\n';
    3543               0 :   const char CRLFCRLF[] = {CR,LF,CR,LF,'\0'}; // C string"\r\n\r\n"
    3544               0 :   const char ContentLenHeader[] = "Content-length";
    3545                 : 
    3546               0 :   nsAutoTArray<const char*, 8> singleLF;
    3547               0 :   const char *pSCntlh = 0;// pointer to start of ContentLenHeader in inPostData
    3548               0 :   const char *pSod = 0;   // pointer to start of data in inPostData
    3549               0 :   const char *pEoh = 0;   // pointer to end of headers in inPostData
    3550               0 :   const char *pEod = inPostData + inPostDataLen; // pointer to end of inPostData
    3551               0 :   if (*inPostData == LF) {
    3552                 :     // If no custom headers are required, simply add a blank
    3553                 :     // line ('\n') to the beginning of the file or buffer.
    3554                 :     // so *inPostData == '\n' is valid
    3555               0 :     pSod = inPostData + 1;
    3556                 :   } else {
    3557               0 :     const char *s = inPostData; //tmp pointer to sourse inPostData
    3558               0 :     while (s < pEod) {
    3559               0 :       if (!pSCntlh &&
    3560                 :           (*s == 'C' || *s == 'c') &&
    3561               0 :           (s + sizeof(ContentLenHeader) - 1 < pEod) &&
    3562               0 :           (!PL_strncasecmp(s, ContentLenHeader, sizeof(ContentLenHeader) - 1)))
    3563                 :       {
    3564                 :         // lets assume this is ContentLenHeader for now
    3565               0 :         const char *p = pSCntlh = s;
    3566               0 :         p += sizeof(ContentLenHeader) - 1;
    3567                 :         // search for first CR or LF == end of ContentLenHeader
    3568               0 :         for (; p < pEod; p++) {
    3569               0 :           if (*p == CR || *p == LF) {
    3570                 :             // got delimiter,
    3571                 :             // one more check; if previous char is a digit
    3572                 :             // most likely pSCntlh points to the start of ContentLenHeader
    3573               0 :             if (*(p-1) >= '0' && *(p-1) <= '9') {
    3574               0 :               s = p;
    3575                 :             }
    3576               0 :             break; //for loop
    3577                 :           }
    3578                 :         }
    3579               0 :         if (pSCntlh == s) { // curret ptr is the same
    3580               0 :           pSCntlh = 0; // that was not ContentLenHeader
    3581               0 :           break; // there is nothing to parse, break *WHILE LOOP* here
    3582                 :         }
    3583                 :       }
    3584                 : 
    3585               0 :       if (*s == CR) {
    3586               0 :         if (pSCntlh && // only if ContentLenHeader is found we are looking for end of headers
    3587               0 :             ((s + sizeof(CRLFCRLF)-1) <= pEod) &&
    3588               0 :             !memcmp(s, CRLFCRLF, sizeof(CRLFCRLF)-1))
    3589                 :         {
    3590               0 :           s += sizeof(CRLFCRLF)-1;
    3591               0 :           pEoh = pSod = s; // data stars here
    3592               0 :           break;
    3593                 :         }
    3594               0 :       } else if (*s == LF) {
    3595               0 :         if (*(s-1) != CR) {
    3596               0 :           singleLF.AppendElement(s);
    3597                 :         }
    3598               0 :         if (pSCntlh && (s+1 < pEod) && (*(s+1) == LF)) {
    3599               0 :           s++;
    3600               0 :           singleLF.AppendElement(s);
    3601               0 :           s++;
    3602               0 :           pEoh = pSod = s; // data stars here
    3603               0 :           break;
    3604                 :         }
    3605                 :       }
    3606               0 :       s++;
    3607                 :     }
    3608                 :   }
    3609                 : 
    3610                 :   // deal with output buffer
    3611               0 :   if (!pSod) { // lets assume whole buffer is a data
    3612               0 :     pSod = inPostData;
    3613                 :   }
    3614                 : 
    3615               0 :   PRUint32 newBufferLen = 0;
    3616               0 :   PRUint32 dataLen = pEod - pSod;
    3617               0 :   PRUint32 headersLen = pEoh ? pSod - inPostData : 0;
    3618                 : 
    3619                 :   char *p; // tmp ptr into new output buf
    3620               0 :   if (headersLen) { // we got a headers
    3621                 :     // this function does not make any assumption on correctness
    3622                 :     // of ContentLenHeader value in this case.
    3623                 : 
    3624               0 :     newBufferLen = dataLen + headersLen;
    3625                 :     // in case there were single LFs in headers
    3626                 :     // reserve an extra space for CR will be added before each single LF
    3627               0 :     int cntSingleLF = singleLF.Length();
    3628               0 :     newBufferLen += cntSingleLF;
    3629                 : 
    3630               0 :     if (!(*outPostData = p = (char*)nsMemory::Alloc(newBufferLen)))
    3631               0 :       return NS_ERROR_OUT_OF_MEMORY;
    3632                 : 
    3633                 :     // deal with single LF
    3634               0 :     const char *s = inPostData;
    3635               0 :     if (cntSingleLF) {
    3636               0 :       for (int i=0; i<cntSingleLF; i++) {
    3637               0 :         const char *plf = singleLF.ElementAt(i); // ptr to single LF in headers
    3638               0 :         int n = plf - s; // bytes to copy
    3639               0 :         if (n) { // for '\n\n' there is nothing to memcpy
    3640               0 :           memcpy(p, s, n);
    3641               0 :           p += n;
    3642                 :         }
    3643               0 :         *p++ = CR;
    3644               0 :         s = plf;
    3645               0 :         *p++ = *s++;
    3646                 :       }
    3647                 :     }
    3648                 :     // are we done with headers?
    3649               0 :     headersLen = pEoh - s;
    3650               0 :     if (headersLen) { // not yet
    3651               0 :       memcpy(p, s, headersLen); // copy the rest
    3652               0 :       p += headersLen;
    3653                 :     }
    3654               0 :   } else  if (dataLen) { // no ContentLenHeader is found but there is a data
    3655                 :     // make new output buffer big enough
    3656                 :     // to keep ContentLenHeader+value followed by data
    3657               0 :     PRUint32 l = sizeof(ContentLenHeader) + sizeof(CRLFCRLF) + 32;
    3658               0 :     newBufferLen = dataLen + l;
    3659               0 :     if (!(*outPostData = p = (char*)nsMemory::Alloc(newBufferLen)))
    3660               0 :       return NS_ERROR_OUT_OF_MEMORY;
    3661               0 :     headersLen = PR_snprintf(p, l,"%s: %ld%s", ContentLenHeader, dataLen, CRLFCRLF);
    3662               0 :     if (headersLen == l) { // if PR_snprintf has ate all extra space consider this as an error
    3663               0 :       nsMemory::Free(p);
    3664               0 :       *outPostData = 0;
    3665               0 :       return NS_ERROR_FAILURE;
    3666                 :     }
    3667               0 :     p += headersLen;
    3668               0 :     newBufferLen = headersLen + dataLen;
    3669                 :   }
    3670                 :   // at this point we've done with headers.
    3671                 :   // there is a possibility that input buffer has only headers info in it
    3672                 :   // which already parsed and copied into output buffer.
    3673                 :   // copy the data
    3674               0 :   if (dataLen) {
    3675               0 :     memcpy(p, pSod, dataLen);
    3676                 :   }
    3677                 : 
    3678               0 :   *outPostDataLen = newBufferLen;
    3679                 : 
    3680               0 :   return NS_OK;
    3681                 : }
    3682                 : 
    3683                 : nsresult
    3684               0 : nsPluginHost::CreateTempFileToPost(const char *aPostDataURL, nsIFile **aTmpFile)
    3685                 : {
    3686                 :   nsresult rv;
    3687                 :   PRInt64 fileSize;
    3688               0 :   nsCAutoString filename;
    3689                 : 
    3690                 :   // stat file == get size & convert file:///c:/ to c: if needed
    3691               0 :   nsCOMPtr<nsIFile> inFile;
    3692               0 :   rv = NS_GetFileFromURLSpec(nsDependentCString(aPostDataURL),
    3693               0 :                              getter_AddRefs(inFile));
    3694               0 :   if (NS_FAILED(rv)) {
    3695               0 :     nsCOMPtr<nsILocalFile> localFile;
    3696               0 :     rv = NS_NewNativeLocalFile(nsDependentCString(aPostDataURL), false,
    3697               0 :                                getter_AddRefs(localFile));
    3698               0 :     if (NS_FAILED(rv)) return rv;
    3699               0 :     inFile = localFile;
    3700                 :   }
    3701               0 :   rv = inFile->GetFileSize(&fileSize);
    3702               0 :   if (NS_FAILED(rv)) return rv;
    3703               0 :   rv = inFile->GetNativePath(filename);
    3704               0 :   if (NS_FAILED(rv)) return rv;
    3705                 : 
    3706               0 :   if (!LL_IS_ZERO(fileSize)) {
    3707               0 :     nsCOMPtr<nsIInputStream> inStream;
    3708               0 :     rv = NS_NewLocalFileInputStream(getter_AddRefs(inStream), inFile);
    3709               0 :     if (NS_FAILED(rv)) return rv;
    3710                 : 
    3711                 :     // Create a temporary file to write the http Content-length:
    3712                 :     // %ld\r\n\" header and "\r\n" == end of headers for post data to
    3713                 : 
    3714               0 :     nsCOMPtr<nsIFile> tempFile;
    3715               0 :     rv = GetPluginTempDir(getter_AddRefs(tempFile));
    3716               0 :     if (NS_FAILED(rv))
    3717               0 :       return rv;
    3718                 : 
    3719               0 :     nsCAutoString inFileName;
    3720               0 :     inFile->GetNativeLeafName(inFileName);
    3721                 :     // XXX hack around bug 70083
    3722               0 :     inFileName.Insert(NS_LITERAL_CSTRING("post-"), 0);
    3723               0 :     rv = tempFile->AppendNative(inFileName);
    3724                 : 
    3725               0 :     if (NS_FAILED(rv))
    3726               0 :       return rv;
    3727                 : 
    3728                 :     // make it unique, and mode == 0600, not world-readable
    3729               0 :     rv = tempFile->CreateUnique(nsIFile::NORMAL_FILE_TYPE, 0600);
    3730               0 :     if (NS_FAILED(rv))
    3731               0 :       return rv;
    3732                 : 
    3733               0 :     nsCOMPtr<nsIOutputStream> outStream;
    3734               0 :     if (NS_SUCCEEDED(rv)) {
    3735               0 :       rv = NS_NewLocalFileOutputStream(getter_AddRefs(outStream),
    3736                 :         tempFile,
    3737                 :         (PR_WRONLY | PR_CREATE_FILE | PR_TRUNCATE),
    3738               0 :         0600); // 600 so others can't read our form data
    3739                 :     }
    3740               0 :     NS_ASSERTION(NS_SUCCEEDED(rv), "Post data file couldn't be created!");
    3741               0 :     if (NS_FAILED(rv))
    3742               0 :       return rv;
    3743                 : 
    3744                 :     char buf[1024];
    3745                 :     PRUint32 br, bw;
    3746               0 :     bool firstRead = true;
    3747               0 :     while (1) {
    3748                 :       // Read() mallocs if buffer is null
    3749               0 :       rv = inStream->Read(buf, 1024, &br);
    3750               0 :       if (NS_FAILED(rv) || (PRInt32)br <= 0)
    3751               0 :         break;
    3752               0 :       if (firstRead) {
    3753                 :         //"For protocols in which the headers must be distinguished from the body,
    3754                 :         // such as HTTP, the buffer or file should contain the headers, followed by
    3755                 :         // a blank line, then the body. If no custom headers are required, simply
    3756                 :         // add a blank line ('\n') to the beginning of the file or buffer.
    3757                 : 
    3758                 :         char *parsedBuf;
    3759                 :         // assuming first 1K (or what we got) has all headers in,
    3760                 :         // lets parse it through nsPluginHost::ParsePostBufferToFixHeaders()
    3761               0 :         ParsePostBufferToFixHeaders((const char *)buf, br, &parsedBuf, &bw);
    3762               0 :         rv = outStream->Write(parsedBuf, bw, &br);
    3763               0 :         nsMemory::Free(parsedBuf);
    3764               0 :         if (NS_FAILED(rv) || (bw != br))
    3765               0 :           break;
    3766                 : 
    3767               0 :         firstRead = false;
    3768               0 :         continue;
    3769                 :       }
    3770               0 :       bw = br;
    3771               0 :       rv = outStream->Write(buf, bw, &br);
    3772               0 :       if (NS_FAILED(rv) || (bw != br))
    3773               0 :         break;
    3774                 :     }
    3775                 : 
    3776               0 :     inStream->Close();
    3777               0 :     outStream->Close();
    3778               0 :     if (NS_SUCCEEDED(rv))
    3779               0 :       *aTmpFile = tempFile.forget().get();
    3780                 :   }
    3781               0 :   return rv;
    3782                 : }
    3783                 : 
    3784                 : nsresult
    3785               0 : nsPluginHost::NewPluginNativeWindow(nsPluginNativeWindow ** aPluginNativeWindow)
    3786                 : {
    3787               0 :   return PLUG_NewPluginNativeWindow(aPluginNativeWindow);
    3788                 : }
    3789                 : 
    3790                 : nsresult
    3791               0 : nsPluginHost::InstantiateDummyJavaPlugin(nsIPluginInstanceOwner *aOwner)
    3792                 : {
    3793                 :   // Pass false as the second arg, we want the answer to be the
    3794                 :   // same here whether the Java plugin is enabled or not.
    3795               0 :   nsPluginTag *plugin = FindPluginForType("application/x-java-vm", false);
    3796                 : 
    3797               0 :   if (!plugin || !plugin->mIsNPRuntimeEnabledJavaPlugin) {
    3798                 :     // No NPRuntime enabled Java plugin found, no point in
    3799                 :     // instantiating a dummy plugin then.
    3800                 : 
    3801               0 :     return NS_OK;
    3802                 :   }
    3803                 : 
    3804               0 :   nsresult rv = SetUpPluginInstance("application/x-java-vm", nsnull, aOwner);
    3805               0 :   NS_ENSURE_SUCCESS(rv, rv);
    3806                 : 
    3807               0 :   nsRefPtr<nsNPAPIPluginInstance> instance;
    3808               0 :   aOwner->GetInstance(getter_AddRefs(instance));
    3809               0 :   if (!instance)
    3810               0 :     return NS_OK;
    3811                 : 
    3812               0 :   instance->DefineJavaProperties();
    3813                 : 
    3814               0 :   return NS_OK;
    3815                 : }
    3816                 : 
    3817                 : nsresult
    3818               0 : nsPluginHost::GetPluginName(nsNPAPIPluginInstance *aPluginInstance,
    3819                 :                             const char** aPluginName)
    3820                 : {
    3821               0 :   nsNPAPIPluginInstance *instance = static_cast<nsNPAPIPluginInstance*>(aPluginInstance);
    3822               0 :   if (!instance)
    3823               0 :     return NS_ERROR_FAILURE;
    3824                 : 
    3825               0 :   nsNPAPIPlugin* plugin = instance->GetPlugin();
    3826               0 :   if (!plugin)
    3827               0 :     return NS_ERROR_FAILURE;
    3828                 : 
    3829               0 :   *aPluginName = TagForPlugin(plugin)->mName.get();
    3830                 : 
    3831               0 :   return NS_OK;
    3832                 : }
    3833                 : 
    3834                 : nsresult
    3835               0 : nsPluginHost::GetPluginTagForInstance(nsNPAPIPluginInstance *aPluginInstance,
    3836                 :                                       nsIPluginTag **aPluginTag)
    3837                 : {
    3838               0 :   NS_ENSURE_ARG_POINTER(aPluginInstance);
    3839               0 :   NS_ENSURE_ARG_POINTER(aPluginTag);
    3840                 : 
    3841               0 :   nsNPAPIPlugin *plugin = aPluginInstance->GetPlugin();
    3842               0 :   if (!plugin)
    3843               0 :     return NS_ERROR_FAILURE;
    3844                 : 
    3845               0 :   *aPluginTag = TagForPlugin(plugin);
    3846                 : 
    3847               0 :   NS_ADDREF(*aPluginTag);
    3848               0 :   return NS_OK;
    3849                 : }
    3850                 : 
    3851                 : #ifdef MAC_CARBON_PLUGINS
    3852                 : // Flash requires a minimum of 8 events per second to avoid audio skipping.
    3853                 : // Since WebKit uses a hidden plugin event rate of 4 events per second Flash
    3854                 : // uses a Carbon timer for WebKit which fires at 8 events per second.
    3855                 : #define HIDDEN_PLUGIN_DELAY 125
    3856                 : #define VISIBLE_PLUGIN_DELAY 20
    3857                 : #endif
    3858                 : 
    3859               0 : void nsPluginHost::AddIdleTimeTarget(nsIPluginInstanceOwner* objectFrame, bool isVisible)
    3860                 : {
    3861                 : #ifdef MAC_CARBON_PLUGINS
    3862                 :   nsTObserverArray<nsIPluginInstanceOwner*> *targetArray;
    3863                 :   if (isVisible) {
    3864                 :     targetArray = &mVisibleTimerTargets;
    3865                 :   } else {
    3866                 :     targetArray = &mHiddenTimerTargets;
    3867                 :   }
    3868                 : 
    3869                 :   if (targetArray->Contains(objectFrame)) {
    3870                 :     return;
    3871                 :   }
    3872                 : 
    3873                 :   targetArray->AppendElement(objectFrame);
    3874                 :   if (targetArray->Length() == 1) {
    3875                 :     if (isVisible) {
    3876                 :       mVisiblePluginTimer->InitWithCallback(this, VISIBLE_PLUGIN_DELAY, nsITimer::TYPE_REPEATING_SLACK);
    3877                 :     } else {
    3878                 :       mHiddenPluginTimer->InitWithCallback(this, HIDDEN_PLUGIN_DELAY, nsITimer::TYPE_REPEATING_SLACK);
    3879                 :     }
    3880                 :   }
    3881                 : #endif
    3882               0 : }
    3883                 : 
    3884               0 : void nsPluginHost::RemoveIdleTimeTarget(nsIPluginInstanceOwner* objectFrame)
    3885                 : {
    3886                 : #ifdef MAC_CARBON_PLUGINS
    3887                 :   bool visibleRemoved = mVisibleTimerTargets.RemoveElement(objectFrame);
    3888                 :   if (visibleRemoved && mVisibleTimerTargets.IsEmpty()) {
    3889                 :     mVisiblePluginTimer->Cancel();
    3890                 :   }
    3891                 : 
    3892                 :   bool hiddenRemoved = mHiddenTimerTargets.RemoveElement(objectFrame);
    3893                 :   if (hiddenRemoved && mHiddenTimerTargets.IsEmpty()) {
    3894                 :     mHiddenPluginTimer->Cancel();
    3895                 :   }
    3896                 : 
    3897                 :   NS_ASSERTION(!(hiddenRemoved && visibleRemoved), "Plugin instance received visible and hidden idle event notifications");
    3898                 : #endif
    3899               0 : }
    3900                 : 
    3901               0 : NS_IMETHODIMP nsPluginHost::Notify(nsITimer* timer)
    3902                 : {
    3903                 : #ifdef MAC_CARBON_PLUGINS
    3904                 :   if (timer == mVisiblePluginTimer) {
    3905                 :     nsTObserverArray<nsIPluginInstanceOwner*>::ForwardIterator iter(mVisibleTimerTargets);
    3906                 :     while (iter.HasMore()) {
    3907                 :       iter.GetNext()->SendIdleEvent();
    3908                 :     }
    3909                 :     return NS_OK;
    3910                 :   } else if (timer == mHiddenPluginTimer) {
    3911                 :     nsTObserverArray<nsIPluginInstanceOwner*>::ForwardIterator iter(mHiddenTimerTargets);
    3912                 :     while (iter.HasMore()) {
    3913                 :       iter.GetNext()->SendIdleEvent();
    3914                 :     }
    3915                 :     return NS_OK;
    3916                 :   }
    3917                 : #endif
    3918                 : 
    3919               0 :   nsRefPtr<nsPluginTag> pluginTag = mPlugins;
    3920               0 :   while (pluginTag) {
    3921               0 :     if (pluginTag->mUnloadTimer == timer) {
    3922               0 :       if (!IsRunningPlugin(pluginTag)) {
    3923               0 :         pluginTag->TryUnloadPlugin(false);
    3924                 :       }
    3925               0 :       return NS_OK;
    3926                 :     }
    3927               0 :     pluginTag = pluginTag->mNext;
    3928                 :   }
    3929                 : 
    3930               0 :   return NS_ERROR_FAILURE;
    3931                 : }
    3932                 : 
    3933                 : #ifdef XP_WIN
    3934                 : // Re-enable any top level browser windows that were disabled by modal dialogs
    3935                 : // displayed by the crashed plugin.
    3936                 : static void
    3937                 : CheckForDisabledWindows()
    3938                 : {
    3939                 :   nsCOMPtr<nsIWindowMediator> wm(do_GetService(NS_WINDOWMEDIATOR_CONTRACTID));
    3940                 :   if (!wm)
    3941                 :     return;
    3942                 : 
    3943                 :   nsCOMPtr<nsISimpleEnumerator> windowList;
    3944                 :   wm->GetXULWindowEnumerator(nsnull, getter_AddRefs(windowList));
    3945                 :   if (!windowList)
    3946                 :     return;
    3947                 : 
    3948                 :   bool haveWindows;
    3949                 :   do {
    3950                 :     windowList->HasMoreElements(&haveWindows);
    3951                 :     if (!haveWindows)
    3952                 :       return;
    3953                 : 
    3954                 :     nsCOMPtr<nsISupports> supportsWindow;
    3955                 :     windowList->GetNext(getter_AddRefs(supportsWindow));
    3956                 :     nsCOMPtr<nsIBaseWindow> baseWin(do_QueryInterface(supportsWindow));
    3957                 :     if (baseWin) {
    3958                 :       bool aFlag;
    3959                 :       nsCOMPtr<nsIWidget> widget;
    3960                 :       baseWin->GetMainWidget(getter_AddRefs(widget));
    3961                 :       if (widget && !widget->GetParent() &&
    3962                 :           NS_SUCCEEDED(widget->IsVisible(aFlag)) && aFlag == true &&
    3963                 :           NS_SUCCEEDED(widget->IsEnabled(&aFlag)) && aFlag == false) {
    3964                 :         nsIWidget * child = widget->GetFirstChild();
    3965                 :         bool enable = true;
    3966                 :         while (child)  {
    3967                 :           nsWindowType aType;
    3968                 :           if (NS_SUCCEEDED(child->GetWindowType(aType)) &&
    3969                 :               aType == eWindowType_dialog) {
    3970                 :             enable = false;
    3971                 :             break;
    3972                 :           }
    3973                 :           child = child->GetNextSibling();
    3974                 :         }
    3975                 :         if (enable) {
    3976                 :           widget->Enable(true);
    3977                 :         }
    3978                 :       }
    3979                 :     }
    3980                 :   } while (haveWindows);
    3981                 : }
    3982                 : #endif
    3983                 : 
    3984                 : void
    3985               0 : nsPluginHost::PluginCrashed(nsNPAPIPlugin* aPlugin,
    3986                 :                             const nsAString& pluginDumpID,
    3987                 :                             const nsAString& browserDumpID)
    3988                 : {
    3989               0 :   nsPluginTag* crashedPluginTag = TagForPlugin(aPlugin);
    3990                 : 
    3991                 :   // Notify the app's observer that a plugin crashed so it can submit
    3992                 :   // a crashreport.
    3993               0 :   bool submittedCrashReport = false;
    3994                 :   nsCOMPtr<nsIObserverService> obsService =
    3995               0 :     mozilla::services::GetObserverService();
    3996                 :   nsCOMPtr<nsIWritablePropertyBag2> propbag =
    3997               0 :     do_CreateInstance("@mozilla.org/hash-property-bag;1");
    3998               0 :   if (obsService && propbag) {
    3999               0 :     propbag->SetPropertyAsAString(NS_LITERAL_STRING("pluginDumpID"),
    4000               0 :                                   pluginDumpID);
    4001               0 :     propbag->SetPropertyAsAString(NS_LITERAL_STRING("browserDumpID"),
    4002               0 :                                   browserDumpID);
    4003               0 :     propbag->SetPropertyAsBool(NS_LITERAL_STRING("submittedCrashReport"),
    4004               0 :                                submittedCrashReport);
    4005               0 :     obsService->NotifyObservers(propbag, "plugin-crashed", nsnull);
    4006                 :     // see if an observer submitted a crash report.
    4007               0 :     propbag->GetPropertyAsBool(NS_LITERAL_STRING("submittedCrashReport"),
    4008               0 :                                &submittedCrashReport);
    4009                 :   }
    4010                 : 
    4011                 :   // Invalidate each nsPluginInstanceTag for the crashed plugin
    4012                 : 
    4013               0 :   for (PRUint32 i = mInstances.Length(); i > 0; i--) {
    4014               0 :     nsNPAPIPluginInstance* instance = mInstances[i - 1];
    4015               0 :     if (instance->GetPlugin() == aPlugin) {
    4016                 :       // notify the content node (nsIObjectLoadingContent) that the
    4017                 :       // plugin has crashed
    4018               0 :       nsCOMPtr<nsIDOMElement> domElement;
    4019               0 :       instance->GetDOMElement(getter_AddRefs(domElement));
    4020               0 :       nsCOMPtr<nsIObjectLoadingContent> objectContent(do_QueryInterface(domElement));
    4021               0 :       if (objectContent) {
    4022               0 :         objectContent->PluginCrashed(crashedPluginTag, pluginDumpID, browserDumpID,
    4023               0 :                                      submittedCrashReport);
    4024                 :       }
    4025                 : 
    4026               0 :       instance->Destroy();
    4027               0 :       mInstances.RemoveElement(instance);
    4028               0 :       OnPluginInstanceDestroyed(crashedPluginTag);
    4029                 :     }
    4030                 :   }
    4031                 : 
    4032                 :   // Only after all instances have been invalidated is it safe to null
    4033                 :   // out nsPluginTag.mEntryPoint. The next time we try to create an
    4034                 :   // instance of this plugin we reload it (launch a new plugin process).
    4035                 : 
    4036               0 :   crashedPluginTag->mEntryPoint = nsnull;
    4037                 : 
    4038                 : #ifdef XP_WIN
    4039                 :   CheckForDisabledWindows();
    4040                 : #endif
    4041               0 : }
    4042                 : 
    4043                 : nsNPAPIPluginInstance*
    4044               0 : nsPluginHost::FindInstance(const char *mimetype)
    4045                 : {
    4046               0 :   for (PRUint32 i = 0; i < mInstances.Length(); i++) {
    4047               0 :     nsNPAPIPluginInstance* instance = mInstances[i];
    4048                 : 
    4049                 :     const char* mt;
    4050               0 :     nsresult rv = instance->GetMIMEType(&mt);
    4051               0 :     if (NS_FAILED(rv))
    4052               0 :       continue;
    4053                 : 
    4054               0 :     if (PL_strcasecmp(mt, mimetype) == 0)
    4055               0 :       return instance;
    4056                 :   }
    4057                 : 
    4058               0 :   return nsnull;
    4059                 : }
    4060                 : 
    4061                 : nsNPAPIPluginInstance*
    4062               0 : nsPluginHost::FindOldestStoppedInstance()
    4063                 : {
    4064               0 :   nsNPAPIPluginInstance *oldestInstance = nsnull;
    4065               0 :   TimeStamp oldestTime = TimeStamp::Now();
    4066               0 :   for (PRUint32 i = 0; i < mInstances.Length(); i++) {
    4067               0 :     nsNPAPIPluginInstance *instance = mInstances[i];
    4068               0 :     if (instance->IsRunning())
    4069               0 :       continue;
    4070                 : 
    4071               0 :     TimeStamp time = instance->StopTime();
    4072               0 :     if (time < oldestTime) {
    4073               0 :       oldestTime = time;
    4074               0 :       oldestInstance = instance;
    4075                 :     }
    4076                 :   }
    4077                 : 
    4078               0 :   return oldestInstance;
    4079                 : }
    4080                 : 
    4081                 : PRUint32
    4082               0 : nsPluginHost::StoppedInstanceCount()
    4083                 : {
    4084               0 :   PRUint32 stoppedCount = 0;
    4085               0 :   for (PRUint32 i = 0; i < mInstances.Length(); i++) {
    4086               0 :     nsNPAPIPluginInstance *instance = mInstances[i];
    4087               0 :     if (!instance->IsRunning())
    4088               0 :       stoppedCount++;
    4089                 :   }
    4090               0 :   return stoppedCount;
    4091                 : }
    4092                 : 
    4093                 : nsTArray< nsRefPtr<nsNPAPIPluginInstance> >*
    4094               0 : nsPluginHost::InstanceArray()
    4095                 : {
    4096               0 :   return &mInstances;
    4097                 : }
    4098                 : 
    4099                 : void 
    4100             175 : nsPluginHost::DestroyRunningInstances(nsISupportsArray* aReloadDocs, nsPluginTag* aPluginTag)
    4101                 : {
    4102             175 :   for (PRInt32 i = mInstances.Length(); i > 0; i--) {
    4103               0 :     nsNPAPIPluginInstance *instance = mInstances[i - 1];
    4104               0 :     if (instance->IsRunning() && (!aPluginTag || aPluginTag == TagForPlugin(instance->GetPlugin()))) {
    4105               0 :       instance->SetWindow(nsnull);
    4106               0 :       instance->Stop();
    4107                 : 
    4108                 :       // If we've been passed an array to return, lets collect all our documents,
    4109                 :       // removing duplicates. These will be reframed (embedded) or reloaded (full-page) later
    4110                 :       // to kickstart our instances.
    4111               0 :       if (aReloadDocs) {
    4112               0 :         nsCOMPtr<nsIPluginInstanceOwner> owner;
    4113               0 :         instance->GetOwner(getter_AddRefs(owner));
    4114               0 :         if (owner) {
    4115               0 :           nsCOMPtr<nsIDocument> doc;
    4116               0 :           owner->GetDocument(getter_AddRefs(doc));
    4117               0 :           if (doc && aReloadDocs->IndexOf(doc) == -1)  // don't allow for duplicates
    4118               0 :             aReloadDocs->AppendElement(doc);
    4119                 :         }
    4120                 :       }
    4121                 : 
    4122                 :       // Get rid of all the instances without the possibility of caching.
    4123               0 :       nsPluginTag* pluginTag = TagForPlugin(instance->GetPlugin());
    4124               0 :       instance->SetWindow(nsnull);
    4125               0 :       instance->Destroy();
    4126               0 :       mInstances.RemoveElement(instance);
    4127               0 :       OnPluginInstanceDestroyed(pluginTag);
    4128                 :     }
    4129                 :   }
    4130             175 : }
    4131                 : 
    4132                 : // Runnable that does an async destroy of a plugin.
    4133                 : 
    4134                 : class nsPluginDestroyRunnable : public nsRunnable,
    4135                 :                                 public PRCList
    4136                 : {
    4137                 : public:
    4138               0 :   nsPluginDestroyRunnable(nsNPAPIPluginInstance *aInstance)
    4139               0 :     : mInstance(aInstance)
    4140                 :   {
    4141               0 :     PR_INIT_CLIST(this);
    4142               0 :     PR_APPEND_LINK(this, &sRunnableListHead);
    4143               0 :   }
    4144                 : 
    4145               0 :   virtual ~nsPluginDestroyRunnable()
    4146               0 :   {
    4147               0 :     PR_REMOVE_LINK(this);
    4148               0 :   }
    4149                 : 
    4150               0 :   NS_IMETHOD Run()
    4151                 :   {
    4152               0 :     nsRefPtr<nsNPAPIPluginInstance> instance;
    4153                 : 
    4154                 :     // Null out mInstance to make sure this code in another runnable
    4155                 :     // will do the right thing even if someone was holding on to this
    4156                 :     // runnable longer than we expect.
    4157               0 :     instance.swap(mInstance);
    4158                 : 
    4159               0 :     if (PluginDestructionGuard::DelayDestroy(instance)) {
    4160                 :       // It's still not safe to destroy the plugin, it's now up to the
    4161                 :       // outermost guard on the stack to take care of the destruction.
    4162               0 :       return NS_OK;
    4163                 :     }
    4164                 : 
    4165                 :     nsPluginDestroyRunnable *r =
    4166               0 :       static_cast<nsPluginDestroyRunnable*>(PR_NEXT_LINK(&sRunnableListHead));
    4167                 : 
    4168               0 :     while (r != &sRunnableListHead) {
    4169               0 :       if (r != this && r->mInstance == instance) {
    4170                 :         // There's another runnable scheduled to tear down
    4171                 :         // instance. Let it do the job.
    4172               0 :         return NS_OK;
    4173                 :       }
    4174               0 :       r = static_cast<nsPluginDestroyRunnable*>(PR_NEXT_LINK(r));
    4175                 :     }
    4176                 : 
    4177               0 :     PLUGIN_LOG(PLUGIN_LOG_NORMAL,
    4178                 :                ("Doing delayed destroy of instance %p\n", instance.get()));
    4179                 : 
    4180               0 :     nsRefPtr<nsPluginHost> host = nsPluginHost::GetInst();
    4181               0 :     if (host)
    4182               0 :       host->StopPluginInstance(instance);
    4183                 : 
    4184               0 :     PLUGIN_LOG(PLUGIN_LOG_NORMAL,
    4185                 :                ("Done with delayed destroy of instance %p\n", instance.get()));
    4186                 : 
    4187               0 :     return NS_OK;
    4188                 :   }
    4189                 : 
    4190                 : protected:
    4191                 :   nsRefPtr<nsNPAPIPluginInstance> mInstance;
    4192                 : 
    4193                 :   static PRCList sRunnableListHead;
    4194                 : };
    4195                 : 
    4196                 : PRCList nsPluginDestroyRunnable::sRunnableListHead =
    4197                 :   PR_INIT_STATIC_CLIST(&nsPluginDestroyRunnable::sRunnableListHead);
    4198                 : 
    4199                 : PRCList PluginDestructionGuard::sListHead =
    4200                 :   PR_INIT_STATIC_CLIST(&PluginDestructionGuard::sListHead);
    4201                 : 
    4202               0 : PluginDestructionGuard::~PluginDestructionGuard()
    4203                 : {
    4204               0 :   NS_ASSERTION(NS_IsMainThread(), "Should be on the main thread");
    4205                 : 
    4206               0 :   PR_REMOVE_LINK(this);
    4207                 : 
    4208               0 :   if (mDelayedDestroy) {
    4209                 :     // We've attempted to destroy the plugin instance we're holding on
    4210                 :     // to while we were guarding it. Do the actual destroy now, off of
    4211                 :     // a runnable.
    4212                 :     nsRefPtr<nsPluginDestroyRunnable> evt =
    4213               0 :       new nsPluginDestroyRunnable(mInstance);
    4214                 : 
    4215               0 :     NS_DispatchToMainThread(evt);
    4216                 :   }
    4217               0 : }
    4218                 : 
    4219                 : // static
    4220                 : bool
    4221               0 : PluginDestructionGuard::DelayDestroy(nsNPAPIPluginInstance *aInstance)
    4222                 : {
    4223               0 :   NS_ASSERTION(NS_IsMainThread(), "Should be on the main thread");
    4224               0 :   NS_ASSERTION(aInstance, "Uh, I need an instance!");
    4225                 : 
    4226                 :   // Find the first guard on the stack and make it do a delayed
    4227                 :   // destroy upon destruction.
    4228                 : 
    4229                 :   PluginDestructionGuard *g =
    4230               0 :     static_cast<PluginDestructionGuard*>(PR_LIST_HEAD(&sListHead));
    4231                 : 
    4232               0 :   while (g != &sListHead) {
    4233               0 :     if (g->mInstance == aInstance) {
    4234               0 :       g->mDelayedDestroy = true;
    4235                 : 
    4236               0 :       return true;
    4237                 :     }
    4238               0 :     g = static_cast<PluginDestructionGuard*>(PR_NEXT_LINK(g));    
    4239                 :   }
    4240                 : 
    4241               0 :   return false;
    4242                 : }

Generated by: LCOV version 1.7