LCOV - app.info - dom/plugins/base/nsPluginStreamListenerPeer.cpp

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-04-21 | 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