LCOV - code coverage report
Current view: directory - dom/plugins/base - nsPluginStreamListenerPeer.cpp (source / functions) Found Hit Coverage
Test: app.info Lines: 628 0 0.0 %
Date: 2012-06-02 Functions: 60 0 0.0 %

       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                 : #include "nsPluginStreamListenerPeer.h"
      42                 : #include "nsIStreamConverterService.h"
      43                 : #include "nsIHttpChannel.h"
      44                 : #include "nsIHttpChannelInternal.h"
      45                 : #include "nsIFileChannel.h"
      46                 : #include "nsICachingChannel.h"
      47                 : #include "nsMimeTypes.h"
      48                 : #include "nsISupportsPrimitives.h"
      49                 : #include "nsNetCID.h"
      50                 : #include "nsPluginLogging.h"
      51                 : #include "nsIURI.h"
      52                 : #include "nsIURL.h"
      53                 : #include "nsPluginHost.h"
      54                 : #include "nsIByteRangeRequest.h"
      55                 : #include "nsIMultiPartChannel.h"
      56                 : #include "nsIInputStreamTee.h"
      57                 : #include "nsPrintfCString.h"
      58                 : #include "nsIScriptGlobalObject.h"
      59                 : #include "nsIDocument.h"
      60                 : #include "nsIWebNavigation.h"
      61                 : #include "nsContentUtils.h"
      62                 : #include "nsNetUtil.h"
      63                 : #include "nsPluginNativeWindow.h"
      64                 : #include "sampler.h"
      65                 : 
      66                 : #define MAGIC_REQUEST_CONTEXT 0x01020304
      67                 : 
      68                 : // nsPluginByteRangeStreamListener
      69                 : 
      70                 : class nsPluginByteRangeStreamListener
      71                 :   : public nsIStreamListener
      72                 :   , public nsIInterfaceRequestor
      73                 : {
      74                 : public:
      75                 :   nsPluginByteRangeStreamListener(nsIWeakReference* aWeakPtr);
      76                 :   virtual ~nsPluginByteRangeStreamListener();
      77                 :   
      78                 :   NS_DECL_ISUPPORTS
      79                 :   NS_DECL_NSIREQUESTOBSERVER
      80                 :   NS_DECL_NSISTREAMLISTENER
      81                 :   NS_DECL_NSIINTERFACEREQUESTOR
      82                 :   
      83                 : private:
      84                 :   nsCOMPtr<nsIStreamListener> mStreamConverter;
      85                 :   nsWeakPtr mWeakPtrPluginStreamListenerPeer;
      86                 :   bool mRemoveMagicNumber;
      87                 : };
      88                 : 
      89               0 : NS_IMPL_ISUPPORTS3(nsPluginByteRangeStreamListener,
      90                 :                    nsIRequestObserver,
      91                 :                    nsIStreamListener,
      92                 :                    nsIInterfaceRequestor)
      93                 : 
      94               0 : nsPluginByteRangeStreamListener::nsPluginByteRangeStreamListener(nsIWeakReference* aWeakPtr)
      95                 : {
      96               0 :   mWeakPtrPluginStreamListenerPeer = aWeakPtr;
      97               0 :   mRemoveMagicNumber = false;
      98               0 : }
      99                 : 
     100               0 : nsPluginByteRangeStreamListener::~nsPluginByteRangeStreamListener()
     101                 : {
     102               0 :   mStreamConverter = 0;
     103               0 :   mWeakPtrPluginStreamListenerPeer = 0;
     104               0 : }
     105                 : 
     106                 : /**
     107                 :  * Unwrap any byte-range requests so that we can check whether the base channel
     108                 :  * is being tracked properly.
     109                 :  */
     110                 : static nsCOMPtr<nsIRequest>
     111               0 : GetBaseRequest(nsIRequest* r)
     112                 : {
     113               0 :   nsCOMPtr<nsIMultiPartChannel> mp = do_QueryInterface(r);
     114               0 :   if (!mp)
     115               0 :     return r;
     116                 : 
     117               0 :   nsCOMPtr<nsIChannel> base;
     118               0 :   mp->GetBaseChannel(getter_AddRefs(base));
     119               0 :   return already_AddRefed<nsIRequest>(base.forget());
     120                 : }
     121                 : 
     122                 : NS_IMETHODIMP
     123               0 : nsPluginByteRangeStreamListener::OnStartRequest(nsIRequest *request, nsISupports *ctxt)
     124                 : {
     125                 :   nsresult rv;
     126                 :   
     127               0 :   nsCOMPtr<nsIStreamListener> finalStreamListener = do_QueryReferent(mWeakPtrPluginStreamListenerPeer);
     128               0 :   if (!finalStreamListener)
     129               0 :     return NS_ERROR_FAILURE;
     130                 :   
     131                 :   nsPluginStreamListenerPeer *pslp =
     132               0 :     static_cast<nsPluginStreamListenerPeer*>(finalStreamListener.get());
     133                 : 
     134               0 :   NS_ASSERTION(pslp->mRequests.IndexOfObject(GetBaseRequest(request)) != -1,
     135                 :                "Untracked byte-range request?");
     136                 :   
     137               0 :   nsCOMPtr<nsIStreamConverterService> serv = do_GetService(NS_STREAMCONVERTERSERVICE_CONTRACTID, &rv);
     138               0 :   if (NS_SUCCEEDED(rv)) {
     139               0 :     rv = serv->AsyncConvertData(MULTIPART_BYTERANGES,
     140                 :                                 "*/*",
     141                 :                                 finalStreamListener,
     142                 :                                 nsnull,
     143               0 :                                 getter_AddRefs(mStreamConverter));
     144               0 :     if (NS_SUCCEEDED(rv)) {
     145               0 :       rv = mStreamConverter->OnStartRequest(request, ctxt);
     146               0 :       if (NS_SUCCEEDED(rv))
     147               0 :         return rv;
     148                 :     }
     149                 :   }
     150               0 :   mStreamConverter = 0;
     151                 :   
     152               0 :   nsCOMPtr<nsIHttpChannel> httpChannel(do_QueryInterface(request));
     153               0 :   if (!httpChannel) {
     154               0 :     return NS_ERROR_FAILURE;
     155                 :   }
     156                 :   
     157               0 :   PRUint32 responseCode = 0;
     158               0 :   rv = httpChannel->GetResponseStatus(&responseCode);
     159               0 :   if (NS_FAILED(rv)) {
     160               0 :     return NS_ERROR_FAILURE;
     161                 :   }
     162                 :   
     163               0 :   if (responseCode != 200) {
     164               0 :     bool bWantsAllNetworkStreams = false;
     165                 :     rv = pslp->GetPluginInstance()->GetValueFromPlugin(NPPVpluginWantsAllNetworkStreams,
     166               0 :                                                        &bWantsAllNetworkStreams);
     167                 :     // If the call returned an error code make sure we still use our default value.
     168               0 :     if (NS_FAILED(rv)) {
     169               0 :       bWantsAllNetworkStreams = false;
     170                 :     }
     171                 : 
     172               0 :     if (!bWantsAllNetworkStreams){
     173               0 :       return NS_ERROR_FAILURE;
     174                 :     }
     175                 :   }
     176                 :   
     177                 :   // if server cannot continue with byte range (206 status) and sending us whole object (200 status)
     178                 :   // reset this seekable stream & try serve it to plugin instance as a file
     179               0 :   mStreamConverter = finalStreamListener;
     180               0 :   mRemoveMagicNumber = true;
     181                 :   
     182               0 :   rv = pslp->ServeStreamAsFile(request, ctxt);
     183               0 :   return rv;
     184                 : }
     185                 : 
     186                 : NS_IMETHODIMP
     187               0 : nsPluginByteRangeStreamListener::OnStopRequest(nsIRequest *request, nsISupports *ctxt,
     188                 :                                                nsresult status)
     189                 : {
     190               0 :   if (!mStreamConverter)
     191               0 :     return NS_ERROR_FAILURE;
     192                 :   
     193               0 :   nsCOMPtr<nsIStreamListener> finalStreamListener = do_QueryReferent(mWeakPtrPluginStreamListenerPeer);
     194               0 :   if (!finalStreamListener)
     195               0 :     return NS_ERROR_FAILURE;
     196                 :   
     197                 :   nsPluginStreamListenerPeer *pslp =
     198               0 :     static_cast<nsPluginStreamListenerPeer*>(finalStreamListener.get());
     199               0 :   bool found = pslp->mRequests.RemoveObject(request);
     200               0 :   if (!found) {
     201               0 :     NS_ERROR("OnStopRequest received for untracked byte-range request!");
     202                 :   }
     203                 : 
     204               0 :   if (mRemoveMagicNumber) {
     205                 :     // remove magic number from container
     206               0 :     nsCOMPtr<nsISupportsPRUint32> container = do_QueryInterface(ctxt);
     207               0 :     if (container) {
     208               0 :       PRUint32 magicNumber = 0;
     209               0 :       container->GetData(&magicNumber);
     210               0 :       if (magicNumber == MAGIC_REQUEST_CONTEXT) {
     211                 :         // to allow properly finish nsPluginStreamListenerPeer->OnStopRequest()
     212                 :         // set it to something that is not the magic number.
     213               0 :         container->SetData(0);
     214                 :       }
     215                 :     } else {
     216               0 :       NS_WARNING("Bad state of nsPluginByteRangeStreamListener");
     217                 :     }
     218                 :   }
     219                 :   
     220               0 :   return mStreamConverter->OnStopRequest(request, ctxt, status);
     221                 : }
     222                 : 
     223                 : // CachedFileHolder
     224                 : 
     225               0 : CachedFileHolder::CachedFileHolder(nsIFile* cacheFile)
     226               0 : : mFile(cacheFile)
     227                 : {
     228               0 :   NS_ASSERTION(mFile, "Empty CachedFileHolder");
     229               0 : }
     230                 : 
     231               0 : CachedFileHolder::~CachedFileHolder()
     232                 : {
     233               0 :   mFile->Remove(false);
     234               0 : }
     235                 : 
     236                 : void
     237               0 : CachedFileHolder::AddRef()
     238                 : {
     239               0 :   ++mRefCnt;
     240               0 :   NS_LOG_ADDREF(this, mRefCnt, "CachedFileHolder", sizeof(*this));
     241               0 : }
     242                 : 
     243                 : void
     244               0 : CachedFileHolder::Release()
     245                 : {
     246               0 :   --mRefCnt;
     247               0 :   NS_LOG_RELEASE(this, mRefCnt, "CachedFileHolder");
     248               0 :   if (0 == mRefCnt)
     249               0 :     delete this;
     250               0 : }
     251                 : 
     252                 : 
     253                 : NS_IMETHODIMP
     254               0 : nsPluginByteRangeStreamListener::OnDataAvailable(nsIRequest *request, nsISupports *ctxt,
     255                 :                                                  nsIInputStream *inStr, PRUint32 sourceOffset, PRUint32 count)
     256                 : {
     257               0 :   if (!mStreamConverter)
     258               0 :     return NS_ERROR_FAILURE;
     259                 :   
     260               0 :   nsCOMPtr<nsIStreamListener> finalStreamListener = do_QueryReferent(mWeakPtrPluginStreamListenerPeer);
     261               0 :   if (!finalStreamListener)
     262               0 :     return NS_ERROR_FAILURE;
     263                 :   
     264               0 :   return mStreamConverter->OnDataAvailable(request, ctxt, inStr, sourceOffset, count);
     265                 : }
     266                 : 
     267                 : NS_IMETHODIMP
     268               0 : nsPluginByteRangeStreamListener::GetInterface(const nsIID& aIID, void** result)
     269                 : {
     270                 :   // Forward interface requests to our parent
     271               0 :   nsCOMPtr<nsIInterfaceRequestor> finalStreamListener = do_QueryReferent(mWeakPtrPluginStreamListenerPeer);
     272               0 :   if (!finalStreamListener)
     273               0 :     return NS_ERROR_FAILURE;
     274                 : 
     275               0 :   return finalStreamListener->GetInterface(aIID, result);
     276                 : }
     277                 :     
     278                 : 
     279                 : // nsPRUintKey
     280                 : 
     281               0 : class nsPRUintKey : public nsHashKey {
     282                 : protected:
     283                 :   PRUint32 mKey;
     284                 : public:
     285               0 :   nsPRUintKey(PRUint32 key) : mKey(key) {}
     286                 :   
     287               0 :   PRUint32 HashCode() const {
     288               0 :     return mKey;
     289                 :   }
     290                 :   
     291               0 :   bool Equals(const nsHashKey *aKey) const {
     292               0 :     return mKey == ((const nsPRUintKey*)aKey)->mKey;
     293                 :   }
     294               0 :   nsHashKey *Clone() const {
     295               0 :     return new nsPRUintKey(mKey);
     296                 :   }
     297                 :   PRUint32 GetValue() { return mKey; }
     298                 : };
     299                 : 
     300                 : // nsPluginStreamListenerPeer
     301                 : 
     302               0 : NS_IMPL_ISUPPORTS8(nsPluginStreamListenerPeer,
     303                 :                    nsIStreamListener,
     304                 :                    nsIRequestObserver,
     305                 :                    nsIHttpHeaderVisitor,
     306                 :                    nsISupportsWeakReference,
     307                 :                    nsIPluginStreamInfo,
     308                 :                    nsINPAPIPluginStreamInfo,
     309                 :                    nsIInterfaceRequestor,
     310                 :                    nsIChannelEventSink)
     311                 : 
     312               0 : nsPluginStreamListenerPeer::nsPluginStreamListenerPeer()
     313                 : {
     314               0 :   mStreamType = NP_NORMAL;
     315               0 :   mStartBinding = false;
     316               0 :   mAbort = false;
     317               0 :   mRequestFailed = false;
     318                 :   
     319               0 :   mPendingRequests = 0;
     320               0 :   mHaveFiredOnStartRequest = false;
     321               0 :   mDataForwardToRequest = nsnull;
     322                 :   
     323               0 :   mSeekable = false;
     324               0 :   mModified = 0;
     325               0 :   mStreamOffset = 0;
     326               0 :   mStreamComplete = 0;
     327               0 : }
     328                 : 
     329               0 : nsPluginStreamListenerPeer::~nsPluginStreamListenerPeer()
     330                 : {
     331                 : #ifdef PLUGIN_LOGGING
     332               0 :   PR_LOG(nsPluginLogging::gPluginLog, PLUGIN_LOG_NORMAL,
     333                 :          ("nsPluginStreamListenerPeer::dtor this=%p, url=%s\n",this, mURLSpec.get()));
     334                 : #endif
     335                 : 
     336               0 :   if (mPStreamListener) {
     337               0 :     mPStreamListener->SetStreamListenerPeer(this);
     338                 :   }
     339                 : 
     340                 :   // close FD of mFileCacheOutputStream if it's still open
     341                 :   // or we won't be able to remove the cache file
     342               0 :   if (mFileCacheOutputStream)
     343               0 :     mFileCacheOutputStream = nsnull;
     344                 :   
     345               0 :   delete mDataForwardToRequest;
     346                 : 
     347               0 :   if (mPluginInstance)
     348               0 :     mPluginInstance->FileCachedStreamListeners()->RemoveElement(this);
     349               0 : }
     350                 : 
     351                 : // Called as a result of GetURL and PostURL
     352               0 : nsresult nsPluginStreamListenerPeer::Initialize(nsIURI *aURL,
     353                 :                                                 nsNPAPIPluginInstance *aInstance,
     354                 :                                                 nsIPluginStreamListener* aListener)
     355                 : {
     356                 : #ifdef PLUGIN_LOGGING
     357               0 :   nsCAutoString urlSpec;
     358               0 :   if (aURL != nsnull) aURL->GetAsciiSpec(urlSpec);
     359                 :   
     360               0 :   PR_LOG(nsPluginLogging::gPluginLog, PLUGIN_LOG_NORMAL,
     361                 :          ("nsPluginStreamListenerPeer::Initialize instance=%p, url=%s\n", aInstance, urlSpec.get()));
     362                 :   
     363               0 :   PR_LogFlush();
     364                 : #endif
     365                 :   
     366               0 :   mURL = aURL;
     367                 :   
     368               0 :   mPluginInstance = aInstance;
     369                 : 
     370               0 :   mPStreamListener = static_cast<nsNPAPIPluginStreamListener*>(aListener);
     371               0 :   mPStreamListener->SetStreamListenerPeer(this);
     372                 : 
     373               0 :   mPendingRequests = 1;
     374                 :   
     375               0 :   mDataForwardToRequest = new nsHashtable(16, false);
     376               0 :   if (!mDataForwardToRequest)
     377               0 :     return NS_ERROR_FAILURE;
     378                 :   
     379               0 :   return NS_OK;
     380                 : }
     381                 : 
     382                 : /* Called by NewEmbeddedPluginStream() - if this is called, we weren't
     383                 :  * able to load the plugin, so we need to load it later once we figure
     384                 :  * out the mimetype.  In order to load it later, we need the plugin
     385                 :  * instance owner.
     386                 :  */
     387               0 : nsresult nsPluginStreamListenerPeer::InitializeEmbedded(nsIURI *aURL,
     388                 :                                                         nsNPAPIPluginInstance* aInstance,
     389                 :                                                         nsObjectLoadingContent *aContent)
     390                 : {
     391                 : #ifdef PLUGIN_LOGGING
     392               0 :   nsCAutoString urlSpec;
     393               0 :   aURL->GetSpec(urlSpec);
     394                 :   
     395               0 :   PR_LOG(nsPluginLogging::gPluginLog, PLUGIN_LOG_NORMAL,
     396                 :          ("nsPluginStreamListenerPeer::InitializeEmbedded url=%s\n", urlSpec.get()));
     397                 :   
     398               0 :   PR_LogFlush();
     399                 : #endif
     400                 :   
     401               0 :   mURL = aURL;
     402                 :   
     403               0 :   if (aInstance) {
     404               0 :     NS_ASSERTION(mPluginInstance == nsnull, "nsPluginStreamListenerPeer::InitializeEmbedded mPluginInstance != nsnull");
     405               0 :     mPluginInstance = aInstance;
     406                 :   } else {
     407               0 :     mContent = aContent;
     408                 :   }
     409                 :   
     410               0 :   mPendingRequests = 1;
     411                 :   
     412               0 :   mDataForwardToRequest = new nsHashtable(16, false);
     413               0 :   if (!mDataForwardToRequest)
     414               0 :     return NS_ERROR_FAILURE;
     415                 :   
     416               0 :   return NS_OK;
     417                 : }
     418                 : 
     419                 : // Called by NewFullPagePluginStream()
     420               0 : nsresult nsPluginStreamListenerPeer::InitializeFullPage(nsIURI* aURL, nsNPAPIPluginInstance *aInstance)
     421                 : {
     422               0 :   PLUGIN_LOG(PLUGIN_LOG_NORMAL,
     423                 :              ("nsPluginStreamListenerPeer::InitializeFullPage instance=%p\n",aInstance));
     424                 :   
     425               0 :   NS_ASSERTION(mPluginInstance == nsnull, "nsPluginStreamListenerPeer::InitializeFullPage mPluginInstance != nsnull");
     426               0 :   mPluginInstance = aInstance;
     427                 :   
     428               0 :   mURL = aURL;
     429                 :   
     430               0 :   mDataForwardToRequest = new nsHashtable(16, false);
     431               0 :   if (!mDataForwardToRequest)
     432               0 :     return NS_ERROR_FAILURE;
     433                 : 
     434               0 :   mPendingRequests = 1;
     435                 :   
     436               0 :   return NS_OK;
     437                 : }
     438                 : 
     439                 : // SetupPluginCacheFile is called if we have to save the stream to disk.
     440                 : // the most likely cause for this is either there is no disk cache available
     441                 : // or the stream is coming from a https server.
     442                 : //
     443                 : // These files will be deleted when the host is destroyed.
     444                 : //
     445                 : // TODO? What if we fill up the the dest dir?
     446                 : nsresult
     447               0 : nsPluginStreamListenerPeer::SetupPluginCacheFile(nsIChannel* channel)
     448                 : {
     449               0 :   nsresult rv = NS_OK;
     450                 :   
     451               0 :   bool useExistingCacheFile = false;
     452               0 :   nsRefPtr<nsPluginHost> pluginHost = dont_AddRef(nsPluginHost::GetInst());
     453                 : 
     454                 :   // Look for an existing cache file for the URI.
     455               0 :   nsTArray< nsRefPtr<nsNPAPIPluginInstance> > *instances = pluginHost->InstanceArray();
     456               0 :   for (PRUint32 i = 0; i < instances->Length(); i++) {
     457                 :     // most recent streams are at the end of list
     458               0 :     nsTArray<nsPluginStreamListenerPeer*> *streamListeners = instances->ElementAt(i)->FileCachedStreamListeners();
     459               0 :     for (PRInt32 i = streamListeners->Length() - 1; i >= 0; --i) {
     460               0 :       nsPluginStreamListenerPeer *lp = streamListeners->ElementAt(i);
     461               0 :       if (lp && lp->mLocalCachedFileHolder) {
     462               0 :         useExistingCacheFile = lp->UseExistingPluginCacheFile(this);
     463               0 :         if (useExistingCacheFile) {
     464               0 :           mLocalCachedFileHolder = lp->mLocalCachedFileHolder;
     465               0 :           break;
     466                 :         }
     467                 :       }
     468               0 :       if (useExistingCacheFile)
     469               0 :         break;
     470                 :     }
     471                 :   }
     472                 : 
     473                 :   // Create a new cache file if one could not be found.
     474               0 :   if (!useExistingCacheFile) {
     475               0 :     nsCOMPtr<nsIFile> pluginTmp;
     476               0 :     rv = nsPluginHost::GetPluginTempDir(getter_AddRefs(pluginTmp));
     477               0 :     if (NS_FAILED(rv)) {
     478               0 :       return rv;
     479                 :     }
     480                 :     
     481                 :     // Get the filename from the channel
     482               0 :     nsCOMPtr<nsIURI> uri;
     483               0 :     rv = channel->GetURI(getter_AddRefs(uri));
     484               0 :     if (NS_FAILED(rv)) return rv;
     485                 :     
     486               0 :     nsCOMPtr<nsIURL> url(do_QueryInterface(uri));
     487               0 :     if (!url)
     488               0 :       return NS_ERROR_FAILURE;
     489                 :     
     490               0 :     nsCAutoString filename;
     491               0 :     url->GetFileName(filename);
     492               0 :     if (NS_FAILED(rv))
     493               0 :       return rv;
     494                 :     
     495                 :     // Create a file to save our stream into. Should we scramble the name?
     496               0 :     filename.Insert(NS_LITERAL_CSTRING("plugin-"), 0);
     497               0 :     rv = pluginTmp->AppendNative(filename);
     498               0 :     if (NS_FAILED(rv))
     499               0 :       return rv;
     500                 :     
     501                 :     // Yes, make it unique.
     502               0 :     rv = pluginTmp->CreateUnique(nsIFile::NORMAL_FILE_TYPE, 0600);
     503               0 :     if (NS_FAILED(rv))
     504               0 :       return rv;
     505                 :     
     506                 :     // create a file output stream to write to...
     507               0 :     nsCOMPtr<nsIOutputStream> outstream;
     508               0 :     rv = NS_NewLocalFileOutputStream(getter_AddRefs(mFileCacheOutputStream), pluginTmp, -1, 00600);
     509               0 :     if (NS_FAILED(rv))
     510               0 :       return rv;
     511                 :     
     512                 :     // save the file.
     513               0 :     mLocalCachedFileHolder = new CachedFileHolder(pluginTmp);
     514                 :   }
     515                 : 
     516                 :   // add this listenerPeer to list of stream peers for this instance
     517               0 :   mPluginInstance->FileCachedStreamListeners()->AppendElement(this);
     518                 : 
     519               0 :   return rv;
     520                 : }
     521                 : 
     522                 : NS_IMETHODIMP
     523               0 : nsPluginStreamListenerPeer::OnStartRequest(nsIRequest *request,
     524                 :                                            nsISupports* aContext)
     525                 : {
     526               0 :   nsresult rv = NS_OK;
     527               0 :   SAMPLE_LABEL("nsPluginStreamListenerPeer", "OnStartRequest");
     528                 : 
     529               0 :   if (mRequests.IndexOfObject(GetBaseRequest(request)) == -1) {
     530               0 :     NS_ASSERTION(mRequests.Count() == 0,
     531                 :                  "Only our initial stream should be unknown!");
     532               0 :     TrackRequest(request);
     533                 :   }
     534                 :   
     535               0 :   if (mHaveFiredOnStartRequest) {
     536               0 :     return NS_OK;
     537                 :   }
     538                 :   
     539               0 :   mHaveFiredOnStartRequest = true;
     540                 :   
     541               0 :   nsCOMPtr<nsIChannel> channel = do_QueryInterface(request);
     542               0 :   NS_ENSURE_TRUE(channel, NS_ERROR_FAILURE);
     543                 :   
     544                 :   // deal with 404 (Not Found) HTTP response,
     545                 :   // just return, this causes the request to be ignored.
     546               0 :   nsCOMPtr<nsIHttpChannel> httpChannel(do_QueryInterface(channel));
     547               0 :   if (httpChannel) {
     548               0 :     PRUint32 responseCode = 0;
     549               0 :     rv = httpChannel->GetResponseStatus(&responseCode);
     550               0 :     if (NS_FAILED(rv)) {
     551                 :       // NPP_Notify() will be called from OnStopRequest
     552                 :       // in nsNPAPIPluginStreamListener::CleanUpStream
     553                 :       // return error will cancel this request
     554                 :       // ...and we also need to tell the plugin that
     555               0 :       mRequestFailed = true;
     556               0 :       return NS_ERROR_FAILURE;
     557                 :     }
     558                 :     
     559               0 :     if (responseCode > 206) { // not normal
     560               0 :       bool bWantsAllNetworkStreams = false;
     561                 : 
     562                 :       // We don't always have an instance here already, but if we do, check
     563                 :       // to see if it wants all streams.
     564               0 :       if (mPluginInstance) {
     565                 :         rv = mPluginInstance->GetValueFromPlugin(NPPVpluginWantsAllNetworkStreams,
     566               0 :                                                  &bWantsAllNetworkStreams);
     567                 :         // If the call returned an error code make sure we still use our default value.
     568               0 :         if (NS_FAILED(rv)) {
     569               0 :           bWantsAllNetworkStreams = false;
     570                 :         }
     571                 :       }
     572                 : 
     573               0 :       if (!bWantsAllNetworkStreams) {
     574               0 :         mRequestFailed = true;
     575               0 :         return NS_ERROR_FAILURE;
     576                 :       }
     577                 :     }
     578                 :   }
     579                 :   
     580                 :   // Get the notification callbacks from the channel and save it as
     581                 :   // week ref we'll use it in nsPluginStreamInfo::RequestRead() when
     582                 :   // we'll create channel for byte range request.
     583               0 :   nsCOMPtr<nsIInterfaceRequestor> callbacks;
     584               0 :   channel->GetNotificationCallbacks(getter_AddRefs(callbacks));
     585               0 :   if (callbacks)
     586               0 :     mWeakPtrChannelCallbacks = do_GetWeakReference(callbacks);
     587                 :   
     588               0 :   nsCOMPtr<nsILoadGroup> loadGroup;
     589               0 :   channel->GetLoadGroup(getter_AddRefs(loadGroup));
     590               0 :   if (loadGroup)
     591               0 :     mWeakPtrChannelLoadGroup = do_GetWeakReference(loadGroup);
     592                 :   
     593                 :   PRInt32 length;
     594               0 :   rv = channel->GetContentLength(&length);
     595                 :   
     596                 :   // it's possible for the server to not send a Content-Length.
     597                 :   // we should still work in this case.
     598               0 :   if (NS_FAILED(rv) || length == -1) {
     599                 :     // check out if this is file channel
     600               0 :     nsCOMPtr<nsIFileChannel> fileChannel = do_QueryInterface(channel);
     601               0 :     if (fileChannel) {
     602                 :       // file does not exist
     603               0 :       mRequestFailed = true;
     604               0 :       return NS_ERROR_FAILURE;
     605                 :     }
     606               0 :     mLength = 0;
     607                 :   }
     608                 :   else {
     609               0 :     mLength = length;
     610                 :   }
     611                 :   
     612               0 :   nsCAutoString aContentType; // XXX but we already got the type above!
     613               0 :   rv = channel->GetContentType(aContentType);
     614               0 :   if (NS_FAILED(rv))
     615               0 :     return rv;
     616                 :   
     617               0 :   nsCOMPtr<nsIURI> aURL;
     618               0 :   rv = channel->GetURI(getter_AddRefs(aURL));
     619               0 :   if (NS_FAILED(rv))
     620               0 :     return rv;
     621                 :   
     622               0 :   aURL->GetSpec(mURLSpec);
     623                 :   
     624               0 :   if (!aContentType.IsEmpty())
     625               0 :     mContentType = aContentType;
     626                 :   
     627                 : #ifdef PLUGIN_LOGGING
     628               0 :   PR_LOG(nsPluginLogging::gPluginLog, PLUGIN_LOG_NOISY,
     629                 :          ("nsPluginStreamListenerPeer::OnStartRequest this=%p request=%p mime=%s, url=%s\n",
     630                 :           this, request, aContentType.get(), mURLSpec.get()));
     631                 :   
     632               0 :   PR_LogFlush();
     633                 : #endif
     634                 : 
     635                 :   // If we don't have an instance yet it means we weren't able to load
     636                 :   // a plugin previously because we didn't have the mimetype. Try again
     637                 :   // if we have a mime type now.
     638               0 :   if (!mPluginInstance && mContent && !aContentType.IsEmpty()) {
     639               0 :     nsObjectLoadingContent *olc = static_cast<nsObjectLoadingContent*>(mContent.get());
     640               0 :     rv = olc->InstantiatePluginInstance(aContentType.get(), aURL.get());
     641               0 :     if (NS_SUCCEEDED(rv)) {
     642               0 :       rv = olc->GetPluginInstance(getter_AddRefs(mPluginInstance));
     643               0 :       if (NS_FAILED(rv)) {
     644               0 :         return rv;
     645                 :       }
     646                 :     }
     647                 :   }
     648                 : 
     649                 :   // Set up the stream listener...
     650               0 :   rv = SetUpStreamListener(request, aURL);
     651               0 :   if (NS_FAILED(rv)) return rv;
     652                 :   
     653               0 :   return rv;
     654                 : }
     655                 : 
     656               0 : NS_IMETHODIMP nsPluginStreamListenerPeer::OnProgress(nsIRequest *request,
     657                 :                                                      nsISupports* aContext,
     658                 :                                                      PRUint64 aProgress,
     659                 :                                                      PRUint64 aProgressMax)
     660                 : {
     661               0 :   nsresult rv = NS_OK;
     662               0 :   return rv;
     663                 : }
     664                 : 
     665               0 : NS_IMETHODIMP nsPluginStreamListenerPeer::OnStatus(nsIRequest *request,
     666                 :                                                    nsISupports* aContext,
     667                 :                                                    nsresult aStatus,
     668                 :                                                    const PRUnichar* aStatusArg)
     669                 : {
     670               0 :   return NS_OK;
     671                 : }
     672                 : 
     673                 : NS_IMETHODIMP
     674               0 : nsPluginStreamListenerPeer::GetContentType(char** result)
     675                 : {
     676               0 :   *result = const_cast<char*>(mContentType.get());
     677               0 :   return NS_OK;
     678                 : }
     679                 : 
     680                 : 
     681                 : NS_IMETHODIMP
     682               0 : nsPluginStreamListenerPeer::IsSeekable(bool* result)
     683                 : {
     684               0 :   *result = mSeekable;
     685               0 :   return NS_OK;
     686                 : }
     687                 : 
     688                 : NS_IMETHODIMP
     689               0 : nsPluginStreamListenerPeer::GetLength(PRUint32* result)
     690                 : {
     691               0 :   *result = mLength;
     692               0 :   return NS_OK;
     693                 : }
     694                 : 
     695                 : NS_IMETHODIMP
     696               0 : nsPluginStreamListenerPeer::GetLastModified(PRUint32* result)
     697                 : {
     698               0 :   *result = mModified;
     699               0 :   return NS_OK;
     700                 : }
     701                 : 
     702                 : NS_IMETHODIMP
     703               0 : nsPluginStreamListenerPeer::GetURL(const char** result)
     704                 : {
     705               0 :   *result = mURLSpec.get();
     706               0 :   return NS_OK;
     707                 : }
     708                 : 
     709                 : void
     710               0 : nsPluginStreamListenerPeer::MakeByteRangeString(NPByteRange* aRangeList, nsACString &rangeRequest,
     711                 :                                                 PRInt32 *numRequests)
     712                 : {
     713               0 :   rangeRequest.Truncate();
     714               0 :   *numRequests  = 0;
     715                 :   //the string should look like this: bytes=500-700,601-999
     716               0 :   if (!aRangeList)
     717               0 :     return;
     718                 :   
     719               0 :   PRInt32 requestCnt = 0;
     720               0 :   nsCAutoString string("bytes=");
     721                 :   
     722               0 :   for (NPByteRange * range = aRangeList; range != nsnull; range = range->next) {
     723                 :     // XXX zero length?
     724               0 :     if (!range->length)
     725               0 :       continue;
     726                 :     
     727                 :     // XXX needs to be fixed for negative offsets
     728               0 :     string.AppendInt(range->offset);
     729               0 :     string.Append("-");
     730               0 :     string.AppendInt(range->offset + range->length - 1);
     731               0 :     if (range->next)
     732               0 :       string += ",";
     733                 :     
     734               0 :     requestCnt++;
     735                 :   }
     736                 :   
     737                 :   // get rid of possible trailing comma
     738               0 :   string.Trim(",", false);
     739                 :   
     740               0 :   rangeRequest = string;
     741               0 :   *numRequests  = requestCnt;
     742                 :   return;
     743                 : }
     744                 : 
     745                 : NS_IMETHODIMP
     746               0 : nsPluginStreamListenerPeer::RequestRead(NPByteRange* rangeList)
     747                 : {
     748               0 :   nsCAutoString rangeString;
     749                 :   PRInt32 numRequests;
     750                 :   
     751               0 :   MakeByteRangeString(rangeList, rangeString, &numRequests);
     752                 :   
     753               0 :   if (numRequests == 0)
     754               0 :     return NS_ERROR_FAILURE;
     755                 :   
     756               0 :   nsresult rv = NS_OK;
     757                 :   
     758               0 :   nsCOMPtr<nsIInterfaceRequestor> callbacks = do_QueryReferent(mWeakPtrChannelCallbacks);
     759               0 :   nsCOMPtr<nsILoadGroup> loadGroup = do_QueryReferent(mWeakPtrChannelLoadGroup);
     760               0 :   nsCOMPtr<nsIChannel> channel;
     761               0 :   rv = NS_NewChannel(getter_AddRefs(channel), mURL, nsnull, loadGroup, callbacks);
     762               0 :   if (NS_FAILED(rv))
     763               0 :     return rv;
     764                 :   
     765               0 :   nsCOMPtr<nsIHttpChannel> httpChannel(do_QueryInterface(channel));
     766               0 :   if (!httpChannel)
     767               0 :     return NS_ERROR_FAILURE;
     768                 :   
     769               0 :   httpChannel->SetRequestHeader(NS_LITERAL_CSTRING("Range"), rangeString, false);
     770                 :   
     771               0 :   mAbort = true; // instruct old stream listener to cancel
     772                 :   // the request on the next ODA.
     773                 :   
     774               0 :   nsCOMPtr<nsIStreamListener> converter;
     775                 :   
     776               0 :   if (numRequests == 1) {
     777               0 :     converter = this;
     778                 :     // set current stream offset equal to the first offset in the range list
     779                 :     // it will work for single byte range request
     780                 :     // for multy range we'll reset it in ODA
     781               0 :     SetStreamOffset(rangeList->offset);
     782                 :   } else {
     783                 :     nsWeakPtr weakpeer =
     784               0 :     do_GetWeakReference(static_cast<nsISupportsWeakReference*>(this));
     785                 :     nsPluginByteRangeStreamListener *brrListener =
     786               0 :     new nsPluginByteRangeStreamListener(weakpeer);
     787               0 :     if (brrListener)
     788               0 :       converter = brrListener;
     789                 :     else
     790               0 :       return NS_ERROR_OUT_OF_MEMORY;
     791                 :   }
     792                 :   
     793               0 :   mPendingRequests += numRequests;
     794                 :   
     795               0 :   nsCOMPtr<nsISupportsPRUint32> container = do_CreateInstance(NS_SUPPORTS_PRUINT32_CONTRACTID, &rv);
     796               0 :   if (NS_FAILED(rv))
     797               0 :     return rv;
     798               0 :   rv = container->SetData(MAGIC_REQUEST_CONTEXT);
     799               0 :   if (NS_FAILED(rv))
     800               0 :     return rv;
     801                 :   
     802               0 :   rv = channel->AsyncOpen(converter, container);
     803               0 :   if (NS_SUCCEEDED(rv))
     804               0 :     TrackRequest(channel);
     805               0 :   return rv;
     806                 : }
     807                 : 
     808                 : NS_IMETHODIMP
     809               0 : nsPluginStreamListenerPeer::GetStreamOffset(PRInt32* result)
     810                 : {
     811               0 :   *result = mStreamOffset;
     812               0 :   return NS_OK;
     813                 : }
     814                 : 
     815                 : NS_IMETHODIMP
     816               0 : nsPluginStreamListenerPeer::SetStreamOffset(PRInt32 value)
     817                 : {
     818               0 :   mStreamOffset = value;
     819               0 :   return NS_OK;
     820                 : }
     821                 : 
     822               0 : nsresult nsPluginStreamListenerPeer::ServeStreamAsFile(nsIRequest *request,
     823                 :                                                        nsISupports* aContext)
     824                 : {
     825               0 :   if (!mPluginInstance)
     826               0 :     return NS_ERROR_FAILURE;
     827                 :   
     828                 :   // mPluginInstance->Stop calls mPStreamListener->CleanUpStream(), so stream will be properly clean up
     829               0 :   mPluginInstance->Stop();
     830               0 :   mPluginInstance->Start();
     831               0 :   nsCOMPtr<nsIPluginInstanceOwner> owner;
     832               0 :   mPluginInstance->GetOwner(getter_AddRefs(owner));
     833               0 :   if (owner) {
     834               0 :     NPWindow* window = nsnull;
     835               0 :     owner->GetWindow(window);
     836                 : #if defined(MOZ_WIDGET_GTK2) || defined(MOZ_WIDGET_QT)
     837                 :     // Should call GetPluginPort() here.
     838                 :     // This part is copied from nsPluginInstanceOwner::GetPluginPort(). 
     839               0 :     nsCOMPtr<nsIWidget> widget;
     840               0 :     ((nsPluginNativeWindow*)window)->GetPluginWidget(getter_AddRefs(widget));
     841               0 :     if (widget) {
     842               0 :       window->window = widget->GetNativeData(NS_NATIVE_PLUGIN_PORT);
     843                 :     }
     844                 : #endif
     845               0 :     owner->CallSetWindow();
     846                 :   }
     847                 :   
     848               0 :   mSeekable = false;
     849               0 :   mPStreamListener->OnStartBinding(this);
     850               0 :   mStreamOffset = 0;
     851                 :   
     852                 :   // force the plugin to use stream as file
     853               0 :   mStreamType = NP_ASFILE;
     854                 :   
     855                 :   // then check it out if browser cache is not available
     856               0 :   nsCOMPtr<nsICachingChannel> cacheChannel = do_QueryInterface(request);
     857               0 :   if (!(cacheChannel && (NS_SUCCEEDED(cacheChannel->SetCacheAsFile(true))))) {
     858               0 :     nsCOMPtr<nsIChannel> channel = do_QueryInterface(request);
     859               0 :     if (channel) {
     860               0 :       SetupPluginCacheFile(channel);
     861                 :     }
     862                 :   }
     863                 :   
     864                 :   // unset mPendingRequests
     865               0 :   mPendingRequests = 0;
     866                 :   
     867               0 :   return NS_OK;
     868                 : }
     869                 : 
     870                 : bool
     871               0 : nsPluginStreamListenerPeer::UseExistingPluginCacheFile(nsPluginStreamListenerPeer* psi)
     872                 : {
     873               0 :   NS_ENSURE_TRUE(psi, false);
     874                 :   
     875               0 :   if (psi->mLength == mLength &&
     876                 :       psi->mModified == mModified &&
     877                 :       mStreamComplete &&
     878               0 :       mURLSpec.Equals(psi->mURLSpec))
     879                 :   {
     880               0 :     return true;
     881                 :   }
     882               0 :   return false;
     883                 : }
     884                 : 
     885               0 : NS_IMETHODIMP nsPluginStreamListenerPeer::OnDataAvailable(nsIRequest *request,
     886                 :                                                           nsISupports* aContext,
     887                 :                                                           nsIInputStream *aIStream,
     888                 :                                                           PRUint32 sourceOffset,
     889                 :                                                           PRUint32 aLength)
     890                 : {
     891               0 :   NS_ASSERTION(mRequests.IndexOfObject(GetBaseRequest(request)) != -1,
     892                 :                "Received OnDataAvailable for untracked request.");
     893                 :   
     894               0 :   if (mRequestFailed)
     895               0 :     return NS_ERROR_FAILURE;
     896                 :   
     897               0 :   if (mAbort) {
     898               0 :     PRUint32 magicNumber = 0;  // set it to something that is not the magic number.
     899               0 :     nsCOMPtr<nsISupportsPRUint32> container = do_QueryInterface(aContext);
     900               0 :     if (container)
     901               0 :       container->GetData(&magicNumber);
     902                 :     
     903               0 :     if (magicNumber != MAGIC_REQUEST_CONTEXT) {
     904                 :       // this is not one of our range requests
     905               0 :       mAbort = false;
     906               0 :       return NS_BINDING_ABORTED;
     907                 :     }
     908                 :   }
     909                 :   
     910               0 :   nsresult rv = NS_OK;
     911                 :   
     912               0 :   if (!mPStreamListener)
     913               0 :     return NS_ERROR_FAILURE;
     914                 :   
     915               0 :   const char * url = nsnull;
     916               0 :   GetURL(&url);
     917                 :   
     918               0 :   PLUGIN_LOG(PLUGIN_LOG_NOISY,
     919                 :              ("nsPluginStreamListenerPeer::OnDataAvailable this=%p request=%p, offset=%d, length=%d, url=%s\n",
     920                 :               this, request, sourceOffset, aLength, url ? url : "no url set"));
     921                 :   
     922                 :   // if the plugin has requested an AsFileOnly stream, then don't
     923                 :   // call OnDataAvailable
     924               0 :   if (mStreamType != NP_ASFILEONLY) {
     925                 :     // get the absolute offset of the request, if one exists.
     926               0 :     nsCOMPtr<nsIByteRangeRequest> brr = do_QueryInterface(request);
     927               0 :     if (brr) {
     928               0 :       if (!mDataForwardToRequest)
     929               0 :         return NS_ERROR_FAILURE;
     930                 :       
     931               0 :       PRInt64 absoluteOffset64 = LL_ZERO;
     932               0 :       brr->GetStartRange(&absoluteOffset64);
     933                 :       
     934                 :       // XXX handle 64-bit for real
     935               0 :       PRInt32 absoluteOffset = (PRInt32)PRInt64(absoluteOffset64);
     936                 :       
     937                 :       // we need to track how much data we have forwarded to the
     938                 :       // plugin.
     939                 :       
     940                 :       // FIXME: http://bugzilla.mozilla.org/show_bug.cgi?id=240130
     941                 :       //
     942                 :       // Why couldn't this be tracked on the plugin info, and not in a
     943                 :       // *hash table*?
     944               0 :       nsPRUintKey key(absoluteOffset);
     945                 :       PRInt32 amtForwardToPlugin =
     946               0 :       NS_PTR_TO_INT32(mDataForwardToRequest->Get(&key));
     947               0 :       mDataForwardToRequest->Put(&key, NS_INT32_TO_PTR(amtForwardToPlugin + aLength));
     948                 :       
     949               0 :       SetStreamOffset(absoluteOffset + amtForwardToPlugin);
     950                 :     }
     951                 :     
     952               0 :     nsCOMPtr<nsIInputStream> stream = aIStream;
     953                 :     
     954                 :     // if we are caching the file ourselves to disk, we want to 'tee' off
     955                 :     // the data as the plugin read from the stream.  We do this by the magic
     956                 :     // of an input stream tee.
     957                 :     
     958               0 :     if (mFileCacheOutputStream) {
     959               0 :       rv = NS_NewInputStreamTee(getter_AddRefs(stream), aIStream, mFileCacheOutputStream);
     960               0 :       if (NS_FAILED(rv))
     961               0 :         return rv;
     962                 :     }
     963                 :     
     964               0 :     rv =  mPStreamListener->OnDataAvailable(this,
     965                 :                                             stream,
     966               0 :                                             aLength);
     967                 :     
     968                 :     // if a plugin returns an error, the peer must kill the stream
     969                 :     //   else the stream and PluginStreamListener leak
     970               0 :     if (NS_FAILED(rv))
     971               0 :       request->Cancel(rv);
     972                 :   }
     973                 :   else
     974                 :   {
     975                 :     // if we don't read from the stream, OnStopRequest will never be called
     976               0 :     char* buffer = new char[aLength];
     977               0 :     PRUint32 amountRead, amountWrote = 0;
     978               0 :     rv = aIStream->Read(buffer, aLength, &amountRead);
     979                 :     
     980                 :     // if we are caching this to disk ourselves, lets write the bytes out.
     981               0 :     if (mFileCacheOutputStream) {
     982               0 :       while (amountWrote < amountRead && NS_SUCCEEDED(rv)) {
     983               0 :         rv = mFileCacheOutputStream->Write(buffer, amountRead, &amountWrote);
     984                 :       }
     985                 :     }
     986               0 :     delete [] buffer;
     987                 :   }
     988               0 :   return rv;
     989                 : }
     990                 : 
     991               0 : NS_IMETHODIMP nsPluginStreamListenerPeer::OnStopRequest(nsIRequest *request,
     992                 :                                                         nsISupports* aContext,
     993                 :                                                         nsresult aStatus)
     994                 : {
     995               0 :   nsresult rv = NS_OK;
     996                 : 
     997               0 :   nsCOMPtr<nsIMultiPartChannel> mp = do_QueryInterface(request);
     998               0 :   if (!mp) {
     999               0 :     bool found = mRequests.RemoveObject(request);
    1000               0 :     if (!found) {
    1001               0 :       NS_ERROR("Received OnStopRequest for untracked request.");
    1002                 :     }
    1003                 :   }
    1004                 :   
    1005               0 :   PLUGIN_LOG(PLUGIN_LOG_NOISY,
    1006                 :              ("nsPluginStreamListenerPeer::OnStopRequest this=%p aStatus=%d request=%p\n",
    1007                 :               this, aStatus, request));
    1008                 :   
    1009                 :   // for ByteRangeRequest we're just updating the mDataForwardToRequest hash and return.
    1010               0 :   nsCOMPtr<nsIByteRangeRequest> brr = do_QueryInterface(request);
    1011               0 :   if (brr) {
    1012               0 :     PRInt64 absoluteOffset64 = LL_ZERO;
    1013               0 :     brr->GetStartRange(&absoluteOffset64);
    1014                 :     // XXX support 64-bit offsets
    1015               0 :     PRInt32 absoluteOffset = (PRInt32)PRInt64(absoluteOffset64);
    1016                 :     
    1017               0 :     nsPRUintKey key(absoluteOffset);
    1018                 :     
    1019                 :     // remove the request from our data forwarding count hash.
    1020               0 :     mDataForwardToRequest->Remove(&key);
    1021                 :     
    1022                 :     
    1023               0 :     PLUGIN_LOG(PLUGIN_LOG_NOISY,
    1024                 :                ("                          ::OnStopRequest for ByteRangeRequest Started=%d\n",
    1025                 :                 absoluteOffset));
    1026                 :   } else {
    1027                 :     // if this is not byte range request and
    1028                 :     // if we are writting the stream to disk ourselves,
    1029                 :     // close & tear it down here
    1030               0 :     mFileCacheOutputStream = nsnull;
    1031                 :   }
    1032                 :   
    1033                 :   // if we still have pending stuff to do, lets not close the plugin socket.
    1034               0 :   if (--mPendingRequests > 0)
    1035               0 :     return NS_OK;
    1036                 :   
    1037                 :   // we keep our connections around...
    1038               0 :   nsCOMPtr<nsISupportsPRUint32> container = do_QueryInterface(aContext);
    1039               0 :   if (container) {
    1040               0 :     PRUint32 magicNumber = 0;  // set it to something that is not the magic number.
    1041               0 :     container->GetData(&magicNumber);
    1042               0 :     if (magicNumber == MAGIC_REQUEST_CONTEXT) {
    1043                 :       // this is one of our range requests
    1044               0 :       return NS_OK;
    1045                 :     }
    1046                 :   }
    1047                 :   
    1048               0 :   if (!mPStreamListener)
    1049               0 :     return NS_ERROR_FAILURE;
    1050                 :   
    1051               0 :   nsCOMPtr<nsIChannel> channel = do_QueryInterface(request);
    1052               0 :   if (!channel)
    1053               0 :     return NS_ERROR_FAILURE;
    1054                 :   // Set the content type to ensure we don't pass null to the plugin
    1055               0 :   nsCAutoString aContentType;
    1056               0 :   rv = channel->GetContentType(aContentType);
    1057               0 :   if (NS_FAILED(rv) && !mRequestFailed)
    1058               0 :     return rv;
    1059                 :   
    1060               0 :   if (!aContentType.IsEmpty())
    1061               0 :     mContentType = aContentType;
    1062                 :   
    1063                 :   // set error status if stream failed so we notify the plugin
    1064               0 :   if (mRequestFailed)
    1065               0 :     aStatus = NS_ERROR_FAILURE;
    1066                 :   
    1067               0 :   if (NS_FAILED(aStatus)) {
    1068                 :     // on error status cleanup the stream
    1069                 :     // and return w/o OnFileAvailable()
    1070               0 :     mPStreamListener->OnStopBinding(this, aStatus);
    1071               0 :     return NS_OK;
    1072                 :   }
    1073                 :   
    1074                 :   // call OnFileAvailable if plugin requests stream type StreamType_AsFile or StreamType_AsFileOnly
    1075               0 :   if (mStreamType >= NP_ASFILE) {
    1076               0 :     nsCOMPtr<nsIFile> localFile;
    1077               0 :     if (mLocalCachedFileHolder)
    1078               0 :       localFile = mLocalCachedFileHolder->file();
    1079                 :     else {
    1080               0 :       nsCOMPtr<nsICachingChannel> cacheChannel = do_QueryInterface(request);
    1081               0 :       if (cacheChannel) {
    1082               0 :         cacheChannel->GetCacheFile(getter_AddRefs(localFile));
    1083                 :       } else {
    1084                 :         // see if it is a file channel.
    1085               0 :         nsCOMPtr<nsIFileChannel> fileChannel = do_QueryInterface(request);
    1086               0 :         if (fileChannel) {
    1087               0 :           fileChannel->GetFile(getter_AddRefs(localFile));
    1088                 :         }
    1089                 :       }
    1090                 :     }
    1091                 :     
    1092               0 :     if (localFile) {
    1093               0 :       OnFileAvailable(localFile);
    1094                 :     }
    1095                 :   }
    1096                 :   
    1097               0 :   if (mStartBinding) {
    1098                 :     // On start binding has been called
    1099               0 :     mPStreamListener->OnStopBinding(this, aStatus);
    1100                 :   } else {
    1101                 :     // OnStartBinding hasn't been called, so complete the action.
    1102               0 :     mPStreamListener->OnStartBinding(this);
    1103               0 :     mPStreamListener->OnStopBinding(this, aStatus);
    1104                 :   }
    1105                 :   
    1106               0 :   if (NS_SUCCEEDED(aStatus)) {
    1107               0 :     mStreamComplete = true;
    1108                 :   }
    1109                 :   
    1110               0 :   return NS_OK;
    1111                 : }
    1112                 : 
    1113               0 : nsresult nsPluginStreamListenerPeer::SetUpStreamListener(nsIRequest *request,
    1114                 :                                                          nsIURI* aURL)
    1115                 : {
    1116               0 :   nsresult rv = NS_OK;
    1117                 :   
    1118                 :   // If we don't yet have a stream listener, we need to get
    1119                 :   // one from the plugin.
    1120                 :   // NOTE: this should only happen when a stream was NOT created
    1121                 :   // with GetURL or PostURL (i.e. it's the initial stream we
    1122                 :   // send to the plugin as determined by the SRC or DATA attribute)
    1123               0 :   if (!mPStreamListener) {
    1124               0 :     if (!mPluginInstance) {
    1125               0 :       return NS_ERROR_FAILURE;
    1126                 :     }
    1127                 : 
    1128               0 :     nsCOMPtr<nsIPluginStreamListener> streamListener;
    1129                 :     rv = mPluginInstance->NewStreamListener(nsnull, nsnull,
    1130               0 :                                             getter_AddRefs(streamListener));
    1131               0 :     if (NS_FAILED(rv) || !streamListener) {
    1132               0 :       return NS_ERROR_FAILURE;
    1133                 :     }
    1134                 : 
    1135               0 :     mPStreamListener = static_cast<nsNPAPIPluginStreamListener*>(streamListener.get());
    1136                 :   }
    1137                 : 
    1138               0 :   mPStreamListener->SetStreamListenerPeer(this);
    1139                 : 
    1140               0 :   bool useLocalCache = false;
    1141                 :   
    1142                 :   // get httpChannel to retrieve some info we need for nsIPluginStreamInfo setup
    1143               0 :   nsCOMPtr<nsIChannel> channel = do_QueryInterface(request);
    1144               0 :   nsCOMPtr<nsIHttpChannel> httpChannel = do_QueryInterface(channel);
    1145                 :   
    1146                 :   /*
    1147                 :    * Assumption
    1148                 :    * By the time nsPluginStreamListenerPeer::OnDataAvailable() gets
    1149                 :    * called, all the headers have been read.
    1150                 :    */
    1151               0 :   if (httpChannel) {
    1152                 :     // Reassemble the HTTP response status line and provide it to our
    1153                 :     // listener.  Would be nice if we could get the raw status line,
    1154                 :     // but nsIHttpChannel doesn't currently provide that.
    1155                 :     // Status code: required; the status line isn't useful without it.
    1156                 :     PRUint32 statusNum;
    1157               0 :     if (NS_SUCCEEDED(httpChannel->GetResponseStatus(&statusNum)) &&
    1158                 :         statusNum < 1000) {
    1159                 :       // HTTP version: provide if available.  Defaults to empty string.
    1160               0 :       nsCString ver;
    1161                 :       nsCOMPtr<nsIHttpChannelInternal> httpChannelInternal =
    1162               0 :       do_QueryInterface(channel);
    1163               0 :       if (httpChannelInternal) {
    1164                 :         PRUint32 major, minor;
    1165               0 :         if (NS_SUCCEEDED(httpChannelInternal->GetResponseVersion(&major,
    1166                 :                                                                  &minor))) {
    1167               0 :           ver = nsPrintfCString("/%lu.%lu", major, minor);
    1168                 :         }
    1169                 :       }
    1170                 : 
    1171                 :       // Status text: provide if available.  Defaults to "OK".
    1172               0 :       nsCString statusText;
    1173               0 :       if (NS_FAILED(httpChannel->GetResponseStatusText(statusText))) {
    1174               0 :         statusText = "OK";
    1175                 :       }
    1176                 : 
    1177                 :       // Assemble everything and pass to listener.
    1178                 :       nsPrintfCString status(100, "HTTP%s %lu %s", ver.get(), statusNum,
    1179               0 :                              statusText.get());
    1180               0 :       static_cast<nsIHTTPHeaderListener*>(mPStreamListener)->StatusLine(status.get());
    1181                 :     }
    1182                 : 
    1183                 :     // Also provide all HTTP response headers to our listener.
    1184               0 :     httpChannel->VisitResponseHeaders(this);
    1185                 :     
    1186               0 :     mSeekable = false;
    1187                 :     // first we look for a content-encoding header. If we find one, we tell the
    1188                 :     // plugin that stream is not seekable, because the plugin always sees
    1189                 :     // uncompressed data, so it can't make meaningful range requests on a
    1190                 :     // compressed entity.  Also, we force the plugin to use
    1191                 :     // nsPluginStreamType_AsFile stream type and we have to save decompressed
    1192                 :     // file into local plugin cache, because necko cache contains original
    1193                 :     // compressed file.
    1194               0 :     nsCAutoString contentEncoding;
    1195               0 :     if (NS_SUCCEEDED(httpChannel->GetResponseHeader(NS_LITERAL_CSTRING("Content-Encoding"),
    1196                 :                                                     contentEncoding))) {
    1197               0 :       useLocalCache = true;
    1198                 :     } else {
    1199                 :       // set seekability (seekable if the stream has a known length and if the
    1200                 :       // http server accepts byte ranges).
    1201                 :       PRUint32 length;
    1202               0 :       GetLength(&length);
    1203               0 :       if (length) {
    1204               0 :         nsCAutoString range;
    1205               0 :         if (NS_SUCCEEDED(httpChannel->GetResponseHeader(NS_LITERAL_CSTRING("accept-ranges"), range)) &&
    1206               0 :             range.Equals(NS_LITERAL_CSTRING("bytes"), nsCaseInsensitiveCStringComparator())) {
    1207               0 :           mSeekable = true;
    1208                 :         }
    1209                 :       }
    1210                 :     }
    1211                 :     
    1212                 :     // we require a content len
    1213                 :     // get Last-Modified header for plugin info
    1214               0 :     nsCAutoString lastModified;
    1215               0 :     if (NS_SUCCEEDED(httpChannel->GetResponseHeader(NS_LITERAL_CSTRING("last-modified"), lastModified)) &&
    1216               0 :         !lastModified.IsEmpty()) {
    1217                 :       PRTime time64;
    1218               0 :       PR_ParseTimeString(lastModified.get(), true, &time64);  //convert string time to integer time
    1219                 :       
    1220                 :       // Convert PRTime to unix-style time_t, i.e. seconds since the epoch
    1221                 :       double fpTime;
    1222               0 :       LL_L2D(fpTime, time64);
    1223               0 :       mModified = (PRUint32)(fpTime * 1e-6 + 0.5);
    1224                 :     }
    1225                 :   }
    1226                 :   
    1227               0 :   rv = mPStreamListener->OnStartBinding(this);
    1228                 :   
    1229               0 :   mStartBinding = true;
    1230                 :   
    1231               0 :   if (NS_FAILED(rv))
    1232               0 :     return rv;
    1233                 :   
    1234               0 :   mPStreamListener->GetStreamType(&mStreamType);
    1235                 :   
    1236               0 :   if (!useLocalCache && mStreamType >= NP_ASFILE) {
    1237                 :     // check it out if this is not a file channel.
    1238               0 :     nsCOMPtr<nsIFileChannel> fileChannel = do_QueryInterface(request);
    1239               0 :     if (!fileChannel) {
    1240                 :       // and browser cache is not available
    1241               0 :       nsCOMPtr<nsICachingChannel> cacheChannel = do_QueryInterface(request);
    1242               0 :       if (!(cacheChannel && (NS_SUCCEEDED(cacheChannel->SetCacheAsFile(true))))) {
    1243               0 :         useLocalCache = true;
    1244                 :       }
    1245                 :     }
    1246                 :   }
    1247                 :   
    1248               0 :   if (useLocalCache) {
    1249               0 :     SetupPluginCacheFile(channel);
    1250                 :   }
    1251                 :   
    1252               0 :   return NS_OK;
    1253                 : }
    1254                 : 
    1255                 : nsresult
    1256               0 : nsPluginStreamListenerPeer::OnFileAvailable(nsIFile* aFile)
    1257                 : {
    1258                 :   nsresult rv;
    1259               0 :   if (!mPStreamListener)
    1260               0 :     return NS_ERROR_FAILURE;
    1261                 :   
    1262               0 :   nsCAutoString path;
    1263               0 :   rv = aFile->GetNativePath(path);
    1264               0 :   if (NS_FAILED(rv)) return rv;
    1265                 :   
    1266               0 :   if (path.IsEmpty()) {
    1267               0 :     NS_WARNING("empty path");
    1268               0 :     return NS_OK;
    1269                 :   }
    1270                 :   
    1271               0 :   rv = mPStreamListener->OnFileAvailable(this, path.get());
    1272               0 :   return rv;
    1273                 : }
    1274                 : 
    1275                 : NS_IMETHODIMP
    1276               0 : nsPluginStreamListenerPeer::VisitHeader(const nsACString &header, const nsACString &value)
    1277                 : {
    1278               0 :   return mPStreamListener->NewResponseHeader(PromiseFlatCString(header).get(),
    1279               0 :                                              PromiseFlatCString(value).get());
    1280                 : }
    1281                 : 
    1282                 : nsresult
    1283               0 : nsPluginStreamListenerPeer::GetInterfaceGlobal(const nsIID& aIID, void** result)
    1284                 : {
    1285               0 :   if (!mPluginInstance) {
    1286               0 :     return NS_ERROR_FAILURE;
    1287                 :   }
    1288                 : 
    1289               0 :   nsCOMPtr<nsIPluginInstanceOwner> owner;
    1290               0 :   mPluginInstance->GetOwner(getter_AddRefs(owner));
    1291               0 :   if (owner) {
    1292               0 :     nsCOMPtr<nsIDocument> doc;
    1293               0 :     nsresult rv = owner->GetDocument(getter_AddRefs(doc));
    1294               0 :     if (NS_SUCCEEDED(rv) && doc) {
    1295               0 :       nsPIDOMWindow *window = doc->GetWindow();
    1296               0 :       if (window) {
    1297               0 :         nsCOMPtr<nsIWebNavigation> webNav = do_GetInterface(window);
    1298               0 :         nsCOMPtr<nsIInterfaceRequestor> ir = do_QueryInterface(webNav);
    1299               0 :         return ir->GetInterface(aIID, result);
    1300                 :       }
    1301                 :     }
    1302                 :   }
    1303                 : 
    1304               0 :   return NS_ERROR_FAILURE;
    1305                 : }
    1306                 : 
    1307                 : NS_IMETHODIMP
    1308               0 : nsPluginStreamListenerPeer::GetInterface(const nsIID& aIID, void** result)
    1309                 : {
    1310                 :   // Provide nsIChannelEventSink ourselves, otherwise let our document's
    1311                 :   // script global object owner provide the interface.
    1312               0 :   if (aIID.Equals(NS_GET_IID(nsIChannelEventSink))) {
    1313               0 :     return QueryInterface(aIID, result);
    1314                 :   }
    1315                 : 
    1316               0 :   return GetInterfaceGlobal(aIID, result);
    1317                 : }
    1318                 : 
    1319                 : /**
    1320                 :  * Proxy class which forwards async redirect notifications back to the necko
    1321                 :  * callback, keeping nsPluginStreamListenerPeer::mRequests in sync with
    1322                 :  * which channel is active.
    1323                 :  */
    1324                 : class ChannelRedirectProxyCallback : public nsIAsyncVerifyRedirectCallback
    1325                 : {
    1326                 : public:
    1327               0 :   ChannelRedirectProxyCallback(nsINPAPIPluginStreamInfo* listener,
    1328                 :                                nsIAsyncVerifyRedirectCallback* parent,
    1329                 :                                nsIChannel* oldChannel,
    1330                 :                                nsIChannel* newChannel)
    1331               0 :     : mWeakListener(do_GetWeakReference(listener))
    1332                 :     , mParent(parent)
    1333                 :     , mOldChannel(oldChannel)
    1334               0 :     , mNewChannel(newChannel)
    1335                 :   {
    1336               0 :   }
    1337                 : 
    1338                 :   ChannelRedirectProxyCallback() {}
    1339               0 :   virtual ~ChannelRedirectProxyCallback() {}
    1340                 : 
    1341                 :   NS_DECL_ISUPPORTS
    1342                 : 
    1343               0 :   NS_IMETHODIMP OnRedirectVerifyCallback(nsresult result)
    1344                 :   {
    1345               0 :     if (NS_SUCCEEDED(result)) {
    1346               0 :       nsCOMPtr<nsINPAPIPluginStreamInfo> listener = do_QueryReferent(mWeakListener);
    1347               0 :       if (listener)
    1348               0 :         listener->ReplaceRequest(mOldChannel, mNewChannel);
    1349                 :     }
    1350               0 :     return mParent->OnRedirectVerifyCallback(result);
    1351                 :   }
    1352                 : 
    1353                 : private:
    1354                 :   nsWeakPtr mWeakListener;
    1355                 :   nsCOMPtr<nsIAsyncVerifyRedirectCallback> mParent;
    1356                 :   nsCOMPtr<nsIChannel> mOldChannel;
    1357                 :   nsCOMPtr<nsIChannel> mNewChannel;
    1358                 : };
    1359                 : 
    1360               0 : NS_IMPL_ISUPPORTS1(ChannelRedirectProxyCallback, nsIAsyncVerifyRedirectCallback)
    1361                 :     
    1362                 : 
    1363                 : NS_IMETHODIMP
    1364               0 : nsPluginStreamListenerPeer::AsyncOnChannelRedirect(nsIChannel *oldChannel, nsIChannel *newChannel,
    1365                 :                                                    PRUint32 flags, nsIAsyncVerifyRedirectCallback* callback)
    1366                 : {
    1367                 :   // Disallow redirects if we don't have a stream listener.
    1368               0 :   if (!mPStreamListener) {
    1369               0 :     return NS_ERROR_FAILURE;
    1370                 :   }
    1371                 : 
    1372                 :   nsCOMPtr<nsIAsyncVerifyRedirectCallback> proxyCallback =
    1373               0 :     new ChannelRedirectProxyCallback(this, callback, oldChannel, newChannel);
    1374                 : 
    1375                 :   // Give NPAPI a chance to control redirects.
    1376               0 :   bool notificationHandled = mPStreamListener->HandleRedirectNotification(oldChannel, newChannel, proxyCallback);
    1377               0 :   if (notificationHandled) {
    1378               0 :     return NS_OK;
    1379                 :   }
    1380                 : 
    1381                 :   // Don't allow cross-origin 307 POST redirects.
    1382               0 :   nsCOMPtr<nsIHttpChannel> oldHttpChannel(do_QueryInterface(oldChannel));
    1383               0 :   if (oldHttpChannel) {
    1384                 :     PRUint32 responseStatus;
    1385               0 :     nsresult rv = oldHttpChannel->GetResponseStatus(&responseStatus);
    1386               0 :     if (NS_FAILED(rv)) {
    1387               0 :       return rv;
    1388                 :     }
    1389               0 :     if (responseStatus == 307) {
    1390               0 :       nsCAutoString method;
    1391               0 :       rv = oldHttpChannel->GetRequestMethod(method);
    1392               0 :       if (NS_FAILED(rv)) {
    1393               0 :         return rv;
    1394                 :       }
    1395               0 :       if (method.EqualsLiteral("POST")) {
    1396               0 :         rv = nsContentUtils::CheckSameOrigin(oldChannel, newChannel);
    1397               0 :         if (NS_FAILED(rv)) {
    1398               0 :           return rv;
    1399                 :         }
    1400                 :       }
    1401                 :     }
    1402                 :   }
    1403                 : 
    1404                 :   // Fall back to channel event sink for window.
    1405               0 :   nsCOMPtr<nsIChannelEventSink> channelEventSink;
    1406               0 :   nsresult rv = GetInterfaceGlobal(NS_GET_IID(nsIChannelEventSink), getter_AddRefs(channelEventSink));
    1407               0 :   if (NS_FAILED(rv)) {
    1408               0 :     return rv;
    1409                 :   }
    1410                 : 
    1411               0 :   return channelEventSink->AsyncOnChannelRedirect(oldChannel, newChannel, flags, proxyCallback);
    1412                 : }

Generated by: LCOV version 1.7