LCOV - code coverage report
Current view: directory - dom/plugins/base - nsNPAPIPluginStreamListener.cpp (source / functions) Found Hit Coverage
Test: app.info Lines: 346 0 0.0 %
Date: 2012-06-02 Functions: 35 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                 :  *
      24                 :  * Alternatively, the contents of this file may be used under the terms of
      25                 :  * either the GNU General Public License Version 2 or later (the "GPL"), or
      26                 :  * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
      27                 :  * in which case the provisions of the GPL or the LGPL are applicable instead
      28                 :  * of those above. If you wish to allow use of your version of this file only
      29                 :  * under the terms of either the GPL or the LGPL, and not to allow others to
      30                 :  * use your version of this file under the terms of the MPL, indicate your
      31                 :  * decision by deleting the provisions above and replace them with the notice
      32                 :  * and other provisions required by the GPL or the LGPL. If you do not delete
      33                 :  * the provisions above, a recipient may use your version of this file under
      34                 :  * the terms of any one of the MPL, the GPL or the LGPL.
      35                 :  *
      36                 :  * ***** END LICENSE BLOCK ***** */
      37                 : 
      38                 : #include "nsNPAPIPluginStreamListener.h"
      39                 : #include "plstr.h"
      40                 : #include "prmem.h"
      41                 : #include "nsDirectoryServiceDefs.h"
      42                 : #include "nsDirectoryServiceUtils.h"
      43                 : #include "nsILocalFile.h"
      44                 : #include "nsNetUtil.h"
      45                 : #include "nsPluginHost.h"
      46                 : #include "nsNPAPIPlugin.h"
      47                 : #include "nsPluginSafety.h"
      48                 : #include "nsPluginLogging.h"
      49                 : #include "nsPluginStreamListenerPeer.h"
      50                 : 
      51               0 : NS_IMPL_ISUPPORTS1(nsPluginStreamToFile, nsIOutputStream)
      52                 : 
      53               0 : nsPluginStreamToFile::nsPluginStreamToFile(const char* target,
      54                 :                                            nsIPluginInstanceOwner* owner)
      55               0 : : mTarget(PL_strdup(target)),
      56               0 : mOwner(owner)
      57                 : {
      58                 :   nsresult rv;
      59               0 :   nsCOMPtr<nsIFile> pluginTmp;
      60               0 :   rv = NS_GetSpecialDirectory(NS_OS_TEMP_DIR, getter_AddRefs(pluginTmp));
      61               0 :   if (NS_FAILED(rv)) return;
      62                 :   
      63               0 :   mTempFile = do_QueryInterface(pluginTmp, &rv);
      64               0 :   if (NS_FAILED(rv)) return;
      65                 :   
      66                 :   // need to create a file with a unique name - use target as the basis
      67               0 :   rv = mTempFile->AppendNative(nsDependentCString(target));
      68               0 :   if (NS_FAILED(rv)) return;
      69                 :   
      70                 :   // Yes, make it unique.
      71               0 :   rv = mTempFile->CreateUnique(nsIFile::NORMAL_FILE_TYPE, 0700); 
      72               0 :   if (NS_FAILED(rv)) return;
      73                 :   
      74                 :   // create the file
      75               0 :   rv = NS_NewLocalFileOutputStream(getter_AddRefs(mOutputStream), mTempFile, -1, 00600);
      76               0 :   if (NS_FAILED(rv))
      77                 :     return;
      78                 :         
      79                 :   // construct the URL we'll use later in calls to GetURL()
      80               0 :   NS_GetURLSpecFromFile(mTempFile, mFileURL);
      81                 :   
      82                 : #ifdef NS_DEBUG
      83               0 :   printf("File URL = %s\n", mFileURL.get());
      84                 : #endif
      85                 : }
      86                 : 
      87               0 : nsPluginStreamToFile::~nsPluginStreamToFile()
      88                 : {
      89                 :   // should we be deleting mTempFile here?
      90               0 :   if (nsnull != mTarget)
      91               0 :     PL_strfree(mTarget);
      92               0 : }
      93                 : 
      94                 : NS_IMETHODIMP
      95               0 : nsPluginStreamToFile::Flush()
      96                 : {
      97               0 :   return NS_OK;
      98                 : }
      99                 : 
     100                 : NS_IMETHODIMP
     101               0 : nsPluginStreamToFile::Write(const char* aBuf, PRUint32 aCount,
     102                 :                             PRUint32 *aWriteCount)
     103                 : {
     104               0 :   mOutputStream->Write(aBuf, aCount, aWriteCount);
     105               0 :   mOutputStream->Flush();
     106               0 :   mOwner->GetURL(mFileURL.get(), mTarget, nsnull, nsnull, 0);
     107                 :   
     108               0 :   return NS_OK;
     109                 : }
     110                 : 
     111                 : NS_IMETHODIMP
     112               0 : nsPluginStreamToFile::WriteFrom(nsIInputStream *inStr, PRUint32 count,
     113                 :                                 PRUint32 *_retval)
     114                 : {
     115               0 :   NS_NOTREACHED("WriteFrom");
     116               0 :   return NS_ERROR_NOT_IMPLEMENTED;
     117                 : }
     118                 : 
     119                 : NS_IMETHODIMP
     120               0 : nsPluginStreamToFile::WriteSegments(nsReadSegmentFun reader, void * closure,
     121                 :                                     PRUint32 count, PRUint32 *_retval)
     122                 : {
     123               0 :   NS_NOTREACHED("WriteSegments");
     124               0 :   return NS_ERROR_NOT_IMPLEMENTED;
     125                 : }
     126                 : 
     127                 : NS_IMETHODIMP
     128               0 : nsPluginStreamToFile::IsNonBlocking(bool *aNonBlocking)
     129                 : {
     130               0 :   *aNonBlocking = false;
     131               0 :   return NS_OK;
     132                 : }
     133                 : 
     134                 : NS_IMETHODIMP
     135               0 : nsPluginStreamToFile::Close(void)
     136                 : {
     137               0 :   mOutputStream->Close();
     138               0 :   mOwner->GetURL(mFileURL.get(), mTarget, nsnull, nsnull, 0);
     139               0 :   return NS_OK;
     140                 : }
     141                 : 
     142                 : // nsNPAPIPluginStreamListener Methods
     143                 : 
     144               0 : NS_IMPL_ISUPPORTS3(nsNPAPIPluginStreamListener, nsIPluginStreamListener,
     145                 :                    nsITimerCallback, nsIHTTPHeaderListener)
     146                 : 
     147               0 : nsNPAPIPluginStreamListener::nsNPAPIPluginStreamListener(nsNPAPIPluginInstance* inst, 
     148                 :                                                          void* notifyData,
     149                 :                                                          const char* aURL)
     150                 : : mStreamBuffer(nsnull),
     151                 : mNotifyURL(aURL ? PL_strdup(aURL) : nsnull),
     152                 : mInst(inst),
     153                 : mStreamListenerPeer(nsnull),
     154                 : mStreamBufferSize(0),
     155                 : mStreamBufferByteCount(0),
     156                 : mStreamType(NP_NORMAL),
     157                 : mStreamStarted(false),
     158                 : mStreamCleanedUp(false),
     159                 : mCallNotify(notifyData ? true : false),
     160                 : mIsSuspended(false),
     161               0 : mIsPluginInitJSStream(mInst->mInPluginInitCall &&
     162                 :                       aURL && strncmp(aURL, "javascript:",
     163               0 :                                       sizeof("javascript:") - 1) == 0),
     164                 : mRedirectDenied(false),
     165               0 : mResponseHeaderBuf(nsnull)
     166                 : {
     167               0 :   memset(&mNPStream, 0, sizeof(mNPStream));
     168               0 :   mNPStream.notifyData = notifyData;
     169               0 : }
     170                 : 
     171               0 : nsNPAPIPluginStreamListener::~nsNPAPIPluginStreamListener()
     172                 : {
     173                 :   // remove this from the plugin instance's stream list
     174               0 :   nsTArray<nsNPAPIPluginStreamListener*> *streamListeners = mInst->StreamListeners();
     175               0 :   streamListeners->RemoveElement(this);
     176                 : 
     177                 :   // For those cases when NewStream is never called, we still may need
     178                 :   // to fire a notification callback. Return network error as fallback
     179                 :   // reason because for other cases, notify should have already been
     180                 :   // called for other reasons elsewhere.
     181               0 :   CallURLNotify(NPRES_NETWORK_ERR);
     182                 :   
     183                 :   // lets get rid of the buffer
     184               0 :   if (mStreamBuffer) {
     185               0 :     PR_Free(mStreamBuffer);
     186               0 :     mStreamBuffer=nsnull;
     187                 :   }
     188                 :   
     189               0 :   if (mNotifyURL)
     190               0 :     PL_strfree(mNotifyURL);
     191                 :   
     192               0 :   if (mResponseHeaderBuf)
     193               0 :     PL_strfree(mResponseHeaderBuf);
     194               0 : }
     195                 : 
     196                 : nsresult
     197               0 : nsNPAPIPluginStreamListener::CleanUpStream(NPReason reason)
     198                 : {
     199               0 :   nsresult rv = NS_ERROR_FAILURE;
     200                 :   
     201               0 :   if (mStreamCleanedUp)
     202               0 :     return NS_OK;
     203                 :   
     204               0 :   mStreamCleanedUp = true;
     205                 :   
     206               0 :   StopDataPump();
     207                 : 
     208                 :   // Release any outstanding redirect callback.
     209               0 :   if (mHTTPRedirectCallback) {
     210               0 :     mHTTPRedirectCallback->OnRedirectVerifyCallback(NS_ERROR_FAILURE);
     211               0 :     mHTTPRedirectCallback = nsnull;
     212                 :   }
     213                 : 
     214                 :   // Seekable streams have an extra addref when they are created which must
     215                 :   // be matched here.
     216               0 :   if (NP_SEEK == mStreamType)
     217               0 :     NS_RELEASE_THIS();
     218                 :   
     219               0 :   if (!mInst || !mInst->CanFireNotifications())
     220               0 :     return rv;
     221                 :   
     222               0 :   mStreamInfo = NULL;
     223                 :   
     224               0 :   PluginDestructionGuard guard(mInst);
     225                 : 
     226               0 :   nsNPAPIPlugin* plugin = mInst->GetPlugin();
     227               0 :   if (!plugin || !plugin->GetLibrary())
     228               0 :     return rv;
     229                 : 
     230               0 :   NPPluginFuncs* pluginFunctions = plugin->PluginFuncs();
     231                 : 
     232                 :   NPP npp;
     233               0 :   mInst->GetNPP(&npp);
     234                 : 
     235               0 :   if (mStreamStarted && pluginFunctions->destroystream) {
     236               0 :     NPPAutoPusher nppPusher(npp);
     237                 : 
     238                 :     NPError error;
     239               0 :     NS_TRY_SAFE_CALL_RETURN(error, (*pluginFunctions->destroystream)(npp, &mNPStream, reason), mInst);
     240                 :     
     241               0 :     NPP_PLUGIN_LOG(PLUGIN_LOG_NORMAL,
     242                 :                    ("NPP DestroyStream called: this=%p, npp=%p, reason=%d, return=%d, url=%s\n",
     243                 :                     this, npp, reason, error, mNPStream.url));
     244                 :     
     245               0 :     if (error == NPERR_NO_ERROR)
     246               0 :       rv = NS_OK;
     247                 :   }
     248                 :   
     249               0 :   mStreamStarted = false;
     250                 :   
     251                 :   // fire notification back to plugin, just like before
     252               0 :   CallURLNotify(reason);
     253                 :   
     254               0 :   return rv;
     255                 : }
     256                 : 
     257                 : void
     258               0 : nsNPAPIPluginStreamListener::CallURLNotify(NPReason reason)
     259                 : {
     260               0 :   if (!mCallNotify || !mInst || !mInst->CanFireNotifications())
     261               0 :     return;
     262                 :   
     263               0 :   PluginDestructionGuard guard(mInst);
     264                 :   
     265               0 :   mCallNotify = false; // only do this ONCE and prevent recursion
     266                 : 
     267               0 :   nsNPAPIPlugin* plugin = mInst->GetPlugin();
     268               0 :   if (!plugin || !plugin->GetLibrary())
     269                 :     return;
     270                 : 
     271               0 :   NPPluginFuncs* pluginFunctions = plugin->PluginFuncs();
     272                 : 
     273               0 :   if (pluginFunctions->urlnotify) {
     274                 :     NPP npp;
     275               0 :     mInst->GetNPP(&npp);
     276                 :     
     277               0 :     NS_TRY_SAFE_CALL_VOID((*pluginFunctions->urlnotify)(npp, mNotifyURL, reason, mNPStream.notifyData), mInst);
     278                 :     
     279               0 :     NPP_PLUGIN_LOG(PLUGIN_LOG_NORMAL,
     280                 :                    ("NPP URLNotify called: this=%p, npp=%p, notify=%p, reason=%d, url=%s\n",
     281                 :                     this, npp, mNPStream.notifyData, reason, mNotifyURL));
     282                 :   }
     283                 : }
     284                 : 
     285                 : NS_IMETHODIMP
     286               0 : nsNPAPIPluginStreamListener::OnStartBinding(nsIPluginStreamInfo* pluginInfo)
     287                 : {
     288               0 :   if (!mInst || !mInst->CanFireNotifications())
     289               0 :     return NS_ERROR_FAILURE;
     290                 : 
     291               0 :   PluginDestructionGuard guard(mInst);
     292                 : 
     293               0 :   nsNPAPIPlugin* plugin = mInst->GetPlugin();
     294               0 :   if (!plugin || !plugin->GetLibrary())
     295               0 :     return NS_ERROR_FAILURE;
     296                 : 
     297               0 :   NPPluginFuncs* pluginFunctions = plugin->PluginFuncs();
     298                 : 
     299               0 :   if (!pluginFunctions->newstream)
     300               0 :     return NS_ERROR_FAILURE;
     301                 : 
     302                 :   NPP npp;
     303               0 :   mInst->GetNPP(&npp);
     304                 : 
     305                 :   bool seekable;
     306                 :   char* contentType;
     307               0 :   PRUint16 streamType = NP_NORMAL;
     308                 :   NPError error;
     309                 :   
     310               0 :   mNPStream.ndata = (void*) this;
     311               0 :   pluginInfo->GetURL(&mNPStream.url);
     312                 :   
     313               0 :   pluginInfo->GetLength((PRUint32*)&(mNPStream.end));
     314               0 :   pluginInfo->GetLastModified((PRUint32*)&(mNPStream.lastmodified));
     315               0 :   pluginInfo->IsSeekable(&seekable);
     316               0 :   pluginInfo->GetContentType(&contentType);
     317                 :   
     318               0 :   if (!mResponseHeaders.IsEmpty()) {
     319               0 :     mResponseHeaderBuf = PL_strdup(mResponseHeaders.get());
     320               0 :     mNPStream.headers = mResponseHeaderBuf;
     321                 :   }
     322                 :   
     323               0 :   mStreamInfo = pluginInfo;
     324                 :   
     325               0 :   NPPAutoPusher nppPusher(npp);
     326                 :   
     327               0 :   NS_TRY_SAFE_CALL_RETURN(error, (*pluginFunctions->newstream)(npp, (char*)contentType, &mNPStream, seekable, &streamType), mInst);
     328                 :   
     329               0 :   NPP_PLUGIN_LOG(PLUGIN_LOG_NORMAL,
     330                 :                  ("NPP NewStream called: this=%p, npp=%p, mime=%s, seek=%d, type=%d, return=%d, url=%s\n",
     331                 :                   this, npp, (char *)contentType, seekable, streamType, error, mNPStream.url));
     332                 :   
     333               0 :   if (error != NPERR_NO_ERROR)
     334               0 :     return NS_ERROR_FAILURE;
     335                 :   
     336               0 :   switch(streamType)
     337                 :   {
     338                 :     case NP_NORMAL:
     339               0 :       mStreamType = NP_NORMAL; 
     340               0 :       break;
     341                 :     case NP_ASFILEONLY:
     342               0 :       mStreamType = NP_ASFILEONLY; 
     343               0 :       break;
     344                 :     case NP_ASFILE:
     345               0 :       mStreamType = NP_ASFILE; 
     346               0 :       break;
     347                 :     case NP_SEEK:
     348               0 :       mStreamType = NP_SEEK; 
     349                 :       // Seekable streams should continue to exist even after OnStopRequest
     350                 :       // is fired, so we AddRef ourself an extra time and Release when the
     351                 :       // plugin calls NPN_DestroyStream (CleanUpStream). If the plugin never
     352                 :       // calls NPN_DestroyStream the stream will be destroyed before the plugin
     353                 :       // instance is destroyed.
     354               0 :       NS_ADDREF_THIS();
     355               0 :       break;
     356                 :     default:
     357               0 :       return NS_ERROR_FAILURE;
     358                 :   }
     359                 :   
     360               0 :   mStreamStarted = true;
     361               0 :   return NS_OK;
     362                 : }
     363                 : 
     364                 : void
     365               0 : nsNPAPIPluginStreamListener::SuspendRequest()
     366                 : {
     367               0 :   NS_ASSERTION(!mIsSuspended,
     368                 :                "Suspending a request that's already suspended!");
     369                 :   
     370                 :   nsCOMPtr<nsINPAPIPluginStreamInfo> pluginInfoNPAPI =
     371               0 :   do_QueryInterface(mStreamInfo);
     372                 :   
     373               0 :   if (!pluginInfoNPAPI) {
     374                 :     return;
     375                 :   }
     376                 :   
     377               0 :   nsresult rv = StartDataPump();
     378               0 :   if (NS_FAILED(rv))
     379                 :     return;
     380                 :   
     381               0 :   mIsSuspended = true;
     382                 :   
     383               0 :   pluginInfoNPAPI->SuspendRequests();
     384                 : }
     385                 : 
     386                 : void
     387               0 : nsNPAPIPluginStreamListener::ResumeRequest()
     388                 : {
     389                 :   nsCOMPtr<nsINPAPIPluginStreamInfo> pluginInfoNPAPI =
     390               0 :   do_QueryInterface(mStreamInfo);
     391                 :   
     392               0 :   pluginInfoNPAPI->ResumeRequests();
     393                 :   
     394               0 :   mIsSuspended = false;
     395               0 : }
     396                 : 
     397                 : nsresult
     398               0 : nsNPAPIPluginStreamListener::StartDataPump()
     399                 : {
     400                 :   nsresult rv;
     401               0 :   mDataPumpTimer = do_CreateInstance("@mozilla.org/timer;1", &rv);
     402               0 :   NS_ENSURE_SUCCESS(rv, rv);
     403                 :   
     404                 :   // Start pumping data to the plugin every 100ms until it obeys and
     405                 :   // eats the data.
     406               0 :   return mDataPumpTimer->InitWithCallback(this, 100,
     407               0 :                                           nsITimer::TYPE_REPEATING_SLACK);
     408                 : }
     409                 : 
     410                 : void
     411               0 : nsNPAPIPluginStreamListener::StopDataPump()
     412                 : {
     413               0 :   if (mDataPumpTimer) {
     414               0 :     mDataPumpTimer->Cancel();
     415               0 :     mDataPumpTimer = nsnull;
     416                 :   }
     417               0 : }
     418                 : 
     419                 : // Return true if a javascript: load that was started while the plugin
     420                 : // was being initialized is still in progress.
     421                 : bool
     422               0 : nsNPAPIPluginStreamListener::PluginInitJSLoadInProgress()
     423                 : {
     424               0 :   if (!mInst)
     425               0 :     return false;
     426                 : 
     427               0 :   nsTArray<nsNPAPIPluginStreamListener*> *streamListeners = mInst->StreamListeners();
     428               0 :   for (unsigned int i = 0; i < streamListeners->Length(); i++) {
     429               0 :     if (streamListeners->ElementAt(i)->mIsPluginInitJSStream) {
     430               0 :       return true;
     431                 :     }
     432                 :   }
     433                 :   
     434               0 :   return false;
     435                 : }
     436                 : 
     437                 : // This method is called when there's more data available off the
     438                 : // network, but it's also called from our data pump when we're feeding
     439                 : // the plugin data that we already got off the network, but the plugin
     440                 : // was unable to consume it at the point it arrived. In the case when
     441                 : // the plugin pump calls this method, the input argument will be null,
     442                 : // and the length will be the number of bytes available in our
     443                 : // internal buffer.
     444                 : NS_IMETHODIMP
     445               0 : nsNPAPIPluginStreamListener::OnDataAvailable(nsIPluginStreamInfo* pluginInfo,
     446                 :                                              nsIInputStream* input,
     447                 :                                              PRUint32 length)
     448                 : {
     449               0 :   if (!length || !mInst || !mInst->CanFireNotifications())
     450               0 :     return NS_ERROR_FAILURE;
     451                 :   
     452               0 :   PluginDestructionGuard guard(mInst);
     453                 :   
     454                 :   // Just in case the caller switches plugin info on us.
     455               0 :   mStreamInfo = pluginInfo;
     456                 : 
     457               0 :   nsNPAPIPlugin* plugin = mInst->GetPlugin();
     458               0 :   if (!plugin || !plugin->GetLibrary())
     459               0 :     return NS_ERROR_FAILURE;
     460                 : 
     461               0 :   NPPluginFuncs* pluginFunctions = plugin->PluginFuncs();
     462                 : 
     463                 :   // check out if plugin implements NPP_Write call
     464               0 :   if (!pluginFunctions->write)
     465               0 :     return NS_ERROR_FAILURE; // it'll cancel necko transaction 
     466                 :   
     467               0 :   if (!mStreamBuffer) {
     468                 :     // To optimize the mem usage & performance we have to allocate
     469                 :     // mStreamBuffer here in first ODA when length of data available
     470                 :     // in input stream is known.  mStreamBuffer will be freed in DTOR.
     471                 :     // we also have to remember the size of that buff to make safe
     472                 :     // consecutive Read() calls form input stream into our buff.
     473                 :     
     474                 :     PRUint32 contentLength;
     475               0 :     pluginInfo->GetLength(&contentLength);
     476                 :     
     477               0 :     mStreamBufferSize = NS_MAX(length, contentLength);
     478                 :     
     479                 :     // Limit the size of the initial buffer to MAX_PLUGIN_NECKO_BUFFER
     480                 :     // (16k). This buffer will grow if needed, as in the case where
     481                 :     // we're getting data faster than the plugin can process it.
     482                 :     mStreamBufferSize = NS_MIN(mStreamBufferSize,
     483               0 :                                PRUint32(MAX_PLUGIN_NECKO_BUFFER));
     484                 :     
     485               0 :     mStreamBuffer = (char*) PR_Malloc(mStreamBufferSize);
     486               0 :     if (!mStreamBuffer)
     487               0 :       return NS_ERROR_OUT_OF_MEMORY;
     488                 :   }
     489                 :   
     490                 :   // prepare NPP_ calls params
     491                 :   NPP npp;
     492               0 :   mInst->GetNPP(&npp);
     493                 :   
     494                 :   PRInt32 streamPosition;
     495               0 :   pluginInfo->GetStreamOffset(&streamPosition);
     496               0 :   PRInt32 streamOffset = streamPosition;
     497                 :   
     498               0 :   if (input) {
     499               0 :     streamOffset += length;
     500                 :     
     501                 :     // Set new stream offset for the next ODA call regardless of how
     502                 :     // following NPP_Write call will behave we pretend to consume all
     503                 :     // data from the input stream.  It's possible that current steam
     504                 :     // position will be overwritten from NPP_RangeRequest call made
     505                 :     // from NPP_Write, so we cannot call SetStreamOffset after
     506                 :     // NPP_Write.
     507                 :     //
     508                 :     // Note: there is a special case when data flow should be
     509                 :     // temporarily stopped if NPP_WriteReady returns 0 (bug #89270)
     510               0 :     pluginInfo->SetStreamOffset(streamOffset);
     511                 :     
     512                 :     // set new end in case the content is compressed
     513                 :     // initial end is less than end of decompressed stream
     514                 :     // and some plugins (e.g. acrobat) can fail. 
     515               0 :     if ((PRInt32)mNPStream.end < streamOffset)
     516               0 :       mNPStream.end = streamOffset;
     517                 :   }
     518                 :   
     519               0 :   nsresult rv = NS_OK;
     520               0 :   while (NS_SUCCEEDED(rv) && length > 0) {
     521               0 :     if (input && length) {
     522               0 :       if (mStreamBufferSize < mStreamBufferByteCount + length && mIsSuspended) {
     523                 :         // We're in the ::OnDataAvailable() call that we might get
     524                 :         // after suspending a request, or we suspended the request
     525                 :         // from within this ::OnDataAvailable() call while there's
     526                 :         // still data in the input, and we don't have enough space to
     527                 :         // store what we got off the network. Reallocate our internal
     528                 :         // buffer.
     529               0 :         mStreamBufferSize = mStreamBufferByteCount + length;
     530               0 :         char *buf = (char*)PR_Realloc(mStreamBuffer, mStreamBufferSize);
     531               0 :         if (!buf)
     532               0 :           return NS_ERROR_OUT_OF_MEMORY;
     533                 :         
     534               0 :         mStreamBuffer = buf;
     535                 :       }
     536                 :       
     537                 :       PRUint32 bytesToRead =
     538               0 :       NS_MIN(length, mStreamBufferSize - mStreamBufferByteCount);
     539                 :       
     540               0 :       PRUint32 amountRead = 0;
     541                 :       rv = input->Read(mStreamBuffer + mStreamBufferByteCount, bytesToRead,
     542               0 :                        &amountRead);
     543               0 :       NS_ENSURE_SUCCESS(rv, rv);
     544                 :       
     545               0 :       if (amountRead == 0) {
     546                 :         NS_NOTREACHED("input->Read() returns no data, it's almost impossible "
     547               0 :                       "to get here");
     548                 :         
     549               0 :         break;
     550                 :       }
     551                 :       
     552               0 :       mStreamBufferByteCount += amountRead;
     553               0 :       length -= amountRead;
     554                 :     } else {
     555                 :       // No input, nothing to read. Set length to 0 so that we don't
     556                 :       // keep iterating through this outer loop any more.
     557                 :       
     558               0 :       length = 0;
     559                 :     }
     560                 :     
     561                 :     // Temporary pointer to the beginning of the data we're writing as
     562                 :     // we loop and feed the plugin data.
     563               0 :     char *ptrStreamBuffer = mStreamBuffer;
     564                 :     
     565                 :     // it is possible plugin's NPP_Write() returns 0 byte consumed. We
     566                 :     // use zeroBytesWriteCount to count situation like this and break
     567                 :     // the loop
     568               0 :     PRInt32 zeroBytesWriteCount = 0;
     569                 :     
     570                 :     // mStreamBufferByteCount tells us how many bytes there are in the
     571                 :     // buffer. WriteReady returns to us how many bytes the plugin is
     572                 :     // ready to handle.
     573               0 :     while (mStreamBufferByteCount > 0) {
     574                 :       PRInt32 numtowrite;
     575               0 :       if (pluginFunctions->writeready) {
     576               0 :         NPPAutoPusher nppPusher(npp);
     577                 :         
     578               0 :         NS_TRY_SAFE_CALL_RETURN(numtowrite, (*pluginFunctions->writeready)(npp, &mNPStream), mInst);
     579               0 :         NPP_PLUGIN_LOG(PLUGIN_LOG_NOISY,
     580                 :                        ("NPP WriteReady called: this=%p, npp=%p, "
     581                 :                         "return(towrite)=%d, url=%s\n",
     582                 :                         this, npp, numtowrite, mNPStream.url));
     583                 :         
     584               0 :         if (!mStreamStarted) {
     585                 :           // The plugin called NPN_DestroyStream() from within
     586                 :           // NPP_WriteReady(), kill the stream.
     587                 :           
     588               0 :           return NS_BINDING_ABORTED;
     589                 :         }
     590                 :         
     591                 :         // if WriteReady returned 0, the plugin is not ready to handle
     592                 :         // the data, suspend the stream (if it isn't already
     593                 :         // suspended).
     594                 :         //
     595                 :         // Also suspend the stream if the stream we're loading is not
     596                 :         // a javascript: URL load that was initiated during plugin
     597                 :         // initialization and there currently is such a stream
     598                 :         // loading. This is done to work around a Windows Media Player
     599                 :         // plugin bug where it can't deal with being fed data for
     600                 :         // other streams while it's waiting for data from the
     601                 :         // javascript: URL loads it requests during
     602                 :         // initialization. See bug 386493 for more details.
     603                 :         
     604               0 :         if (numtowrite <= 0 ||
     605               0 :             (!mIsPluginInitJSStream && PluginInitJSLoadInProgress())) {
     606               0 :           if (!mIsSuspended) {
     607               0 :             SuspendRequest();
     608                 :           }
     609                 :           
     610                 :           // Break out of the inner loop, but keep going through the
     611                 :           // outer loop in case there's more data to read from the
     612                 :           // input stream.
     613                 :           
     614                 :           break;
     615                 :         }
     616                 :         
     617               0 :         numtowrite = NS_MIN(numtowrite, mStreamBufferByteCount);
     618                 :       } else {
     619                 :         // if WriteReady is not supported by the plugin, just write
     620                 :         // the whole buffer
     621               0 :         numtowrite = mStreamBufferByteCount;
     622                 :       }
     623                 :       
     624               0 :       NPPAutoPusher nppPusher(npp);
     625                 :       
     626               0 :       PRInt32 writeCount = 0; // bytes consumed by plugin instance
     627               0 :       NS_TRY_SAFE_CALL_RETURN(writeCount, (*pluginFunctions->write)(npp, &mNPStream, streamPosition, numtowrite, ptrStreamBuffer), mInst);
     628                 :       
     629               0 :       NPP_PLUGIN_LOG(PLUGIN_LOG_NOISY,
     630                 :                      ("NPP Write called: this=%p, npp=%p, pos=%d, len=%d, "
     631                 :                       "buf=%s, return(written)=%d,  url=%s\n",
     632                 :                       this, npp, streamPosition, numtowrite,
     633                 :                       ptrStreamBuffer, writeCount, mNPStream.url));
     634                 :       
     635               0 :       if (!mStreamStarted) {
     636                 :         // The plugin called NPN_DestroyStream() from within
     637                 :         // NPP_Write(), kill the stream.
     638               0 :         return NS_BINDING_ABORTED;
     639                 :       }
     640                 :       
     641               0 :       if (writeCount > 0) {
     642               0 :         NS_ASSERTION(writeCount <= mStreamBufferByteCount,
     643                 :                      "Plugin read past the end of the available data!");
     644                 :         
     645               0 :         writeCount = NS_MIN(writeCount, mStreamBufferByteCount);
     646               0 :         mStreamBufferByteCount -= writeCount;
     647                 :         
     648               0 :         streamPosition += writeCount;
     649                 :         
     650               0 :         zeroBytesWriteCount = 0;
     651                 :         
     652               0 :         if (mStreamBufferByteCount > 0) {
     653                 :           // This alignment code is most likely bogus, but we'll leave
     654                 :           // it in for now in case it matters for some plugins on some
     655                 :           // architectures. Who knows...
     656               0 :           if (writeCount % sizeof(PRWord)) {
     657                 :             // memmove will take care  about alignment 
     658                 :             memmove(mStreamBuffer, ptrStreamBuffer + writeCount,
     659               0 :                     mStreamBufferByteCount);
     660               0 :             ptrStreamBuffer = mStreamBuffer;
     661                 :           } else {
     662                 :             // if aligned we can use ptrStreamBuffer += to eliminate
     663                 :             // memmove()
     664               0 :             ptrStreamBuffer += writeCount;
     665                 :           }
     666                 :         }
     667               0 :       } else if (writeCount == 0) {
     668                 :         // if NPP_Write() returns writeCount == 0 lets say 3 times in
     669                 :         // a row, suspend the request and continue feeding the plugin
     670                 :         // the data we got so far. Once that data is consumed, we'll
     671                 :         // resume the request.
     672               0 :         if (mIsSuspended || ++zeroBytesWriteCount == 3) {
     673               0 :           if (!mIsSuspended) {
     674               0 :             SuspendRequest();
     675                 :           }
     676                 :           
     677                 :           // Break out of the for loop, but keep going through the
     678                 :           // while loop in case there's more data to read from the
     679                 :           // input stream.
     680                 :           
     681                 :           break;
     682                 :         }
     683                 :       } else {
     684                 :         // Something's really wrong, kill the stream.
     685               0 :         rv = NS_ERROR_FAILURE;
     686                 :         
     687                 :         break;
     688                 :       }  
     689                 :     } // end of inner while loop
     690                 :     
     691               0 :     if (mStreamBufferByteCount && mStreamBuffer != ptrStreamBuffer) {
     692               0 :       memmove(mStreamBuffer, ptrStreamBuffer, mStreamBufferByteCount);
     693                 :     }
     694                 :   }
     695                 :   
     696               0 :   if (streamPosition != streamOffset) {
     697                 :     // The plugin didn't consume all available data, or consumed some
     698                 :     // of our cached data while we're pumping cached data. Adjust the
     699                 :     // plugin info's stream offset to match reality, except if the
     700                 :     // plugin info's stream offset was set by a re-entering
     701                 :     // NPN_RequestRead() call.
     702                 :     
     703                 :     PRInt32 postWriteStreamPosition;
     704               0 :     pluginInfo->GetStreamOffset(&postWriteStreamPosition);
     705                 :     
     706               0 :     if (postWriteStreamPosition == streamOffset) {
     707               0 :       pluginInfo->SetStreamOffset(streamPosition);
     708                 :     }
     709                 :   }
     710                 :   
     711               0 :   return rv;
     712                 : }
     713                 : 
     714                 : NS_IMETHODIMP
     715               0 : nsNPAPIPluginStreamListener::OnFileAvailable(nsIPluginStreamInfo* pluginInfo, 
     716                 :                                              const char* fileName)
     717                 : {
     718               0 :   if (!mInst || !mInst->CanFireNotifications())
     719               0 :     return NS_ERROR_FAILURE;
     720                 :   
     721               0 :   PluginDestructionGuard guard(mInst);
     722                 : 
     723               0 :   nsNPAPIPlugin* plugin = mInst->GetPlugin();
     724               0 :   if (!plugin || !plugin->GetLibrary())
     725               0 :     return NS_ERROR_FAILURE;
     726                 : 
     727               0 :   NPPluginFuncs* pluginFunctions = plugin->PluginFuncs();
     728                 : 
     729               0 :   if (!pluginFunctions->asfile)
     730               0 :     return NS_ERROR_FAILURE;
     731                 : 
     732                 :   NPP npp;
     733               0 :   mInst->GetNPP(&npp);
     734                 :   
     735               0 :   NS_TRY_SAFE_CALL_VOID((*pluginFunctions->asfile)(npp, &mNPStream, fileName), mInst);
     736                 :   
     737               0 :   NPP_PLUGIN_LOG(PLUGIN_LOG_NORMAL,
     738                 :                  ("NPP StreamAsFile called: this=%p, npp=%p, url=%s, file=%s\n",
     739                 :                   this, npp, mNPStream.url, fileName));
     740                 :   
     741               0 :   return NS_OK;
     742                 : }
     743                 : 
     744                 : NS_IMETHODIMP
     745               0 : nsNPAPIPluginStreamListener::OnStopBinding(nsIPluginStreamInfo* pluginInfo, 
     746                 :                                            nsresult status)
     747                 : {
     748               0 :   StopDataPump();
     749                 :   
     750               0 :   if (NS_FAILED(status)) {
     751                 :     // The stream was destroyed, or died for some reason. Make sure we
     752                 :     // cancel the underlying request.
     753                 :     nsCOMPtr<nsINPAPIPluginStreamInfo> pluginInfoNPAPI =
     754               0 :     do_QueryInterface(mStreamInfo);
     755                 :     
     756               0 :     if (pluginInfoNPAPI) {
     757               0 :       pluginInfoNPAPI->CancelRequests(status);
     758                 :     }
     759                 :   }
     760                 :   
     761               0 :   if (!mInst || !mInst->CanFireNotifications())
     762               0 :     return NS_ERROR_FAILURE;
     763                 : 
     764                 :   // check if the stream is of seekable type and later its destruction
     765                 :   // see bug 91140
     766               0 :   nsresult rv = NS_OK;
     767               0 :   NPReason reason = NS_FAILED(status) ? NPRES_NETWORK_ERR : NPRES_DONE;
     768               0 :   if (mRedirectDenied) {
     769               0 :     reason = NPRES_USER_BREAK;
     770                 :   }
     771               0 :   if (mStreamType != NP_SEEK ||
     772                 :       (NP_SEEK == mStreamType && NS_BINDING_ABORTED == status)) {
     773               0 :     rv = CleanUpStream(reason);
     774                 :   }
     775                 : 
     776               0 :   return rv;
     777                 : }
     778                 : 
     779                 : NS_IMETHODIMP
     780               0 : nsNPAPIPluginStreamListener::GetStreamType(PRInt32 *result)
     781                 : {
     782               0 :   *result = mStreamType;
     783               0 :   return NS_OK;
     784                 : }
     785                 : 
     786                 : NS_IMETHODIMP
     787               0 : nsNPAPIPluginStreamListener::Notify(nsITimer *aTimer)
     788                 : {
     789               0 :   NS_ASSERTION(aTimer == mDataPumpTimer, "Uh, wrong timer?");
     790                 :   
     791               0 :   PRInt32 oldStreamBufferByteCount = mStreamBufferByteCount;
     792                 :   
     793               0 :   nsresult rv = OnDataAvailable(mStreamInfo, nsnull, mStreamBufferByteCount);
     794                 :   
     795               0 :   if (NS_FAILED(rv)) {
     796                 :     // We ran into an error, no need to keep firing this timer then.
     797               0 :     aTimer->Cancel();
     798               0 :     return NS_OK;
     799                 :   }
     800                 :   
     801               0 :   if (mStreamBufferByteCount != oldStreamBufferByteCount &&
     802                 :       ((mStreamStarted && mStreamBufferByteCount < 1024) ||
     803                 :        mStreamBufferByteCount == 0)) {
     804                 :         // The plugin read some data and we've got less than 1024 bytes in
     805                 :         // our buffer (or its empty and the stream is already
     806                 :         // done). Resume the request so that we get more data off the
     807                 :         // network.
     808               0 :         ResumeRequest();
     809                 :         // Necko will pump data now that we've resumed the request.
     810               0 :         StopDataPump();
     811                 :       }
     812                 :   
     813               0 :   return NS_OK;
     814                 : }
     815                 : 
     816                 : NS_IMETHODIMP
     817               0 : nsNPAPIPluginStreamListener::StatusLine(const char* line)
     818                 : {
     819               0 :   mResponseHeaders.Append(line);
     820               0 :   mResponseHeaders.Append('\n');
     821               0 :   return NS_OK;
     822                 : }
     823                 : 
     824                 : NS_IMETHODIMP
     825               0 : nsNPAPIPluginStreamListener::NewResponseHeader(const char* headerName,
     826                 :                                                const char* headerValue)
     827                 : {
     828               0 :   mResponseHeaders.Append(headerName);
     829               0 :   mResponseHeaders.Append(": ");
     830               0 :   mResponseHeaders.Append(headerValue);
     831               0 :   mResponseHeaders.Append('\n');
     832               0 :   return NS_OK;
     833                 : }
     834                 : 
     835                 : bool
     836               0 : nsNPAPIPluginStreamListener::HandleRedirectNotification(nsIChannel *oldChannel, nsIChannel *newChannel,
     837                 :                                                         nsIAsyncVerifyRedirectCallback* callback)
     838                 : {
     839               0 :   nsCOMPtr<nsIHttpChannel> oldHttpChannel = do_QueryInterface(oldChannel);
     840               0 :   nsCOMPtr<nsIHttpChannel> newHttpChannel = do_QueryInterface(newChannel);
     841               0 :   if (!oldHttpChannel || !newHttpChannel) {
     842               0 :     return false;
     843                 :   }
     844                 : 
     845               0 :   if (!mInst || !mInst->CanFireNotifications()) {
     846               0 :     return false;
     847                 :   }
     848                 : 
     849               0 :   nsNPAPIPlugin* plugin = mInst->GetPlugin();
     850               0 :   if (!plugin || !plugin->GetLibrary()) {
     851               0 :     return false;
     852                 :   }
     853                 : 
     854               0 :   NPPluginFuncs* pluginFunctions = plugin->PluginFuncs();
     855               0 :   if (!pluginFunctions->urlredirectnotify) {
     856               0 :     return false;
     857                 :   }
     858                 : 
     859                 :   // A non-null closure is required for redirect handling support.
     860               0 :   if (mNPStream.notifyData) {
     861                 :     PRUint32 status;
     862               0 :     if (NS_SUCCEEDED(oldHttpChannel->GetResponseStatus(&status))) {
     863               0 :       nsCOMPtr<nsIURI> uri;
     864               0 :       if (NS_SUCCEEDED(newHttpChannel->GetURI(getter_AddRefs(uri))) && uri) {
     865               0 :         nsCAutoString spec;
     866               0 :         if (NS_SUCCEEDED(uri->GetAsciiSpec(spec))) {
     867                 :           // At this point the plugin will be responsible for making the callback
     868                 :           // so save the callback object.
     869               0 :           mHTTPRedirectCallback = callback;
     870                 : 
     871                 :           NPP npp;
     872               0 :           mInst->GetNPP(&npp);
     873                 : #if defined(XP_WIN) || defined(XP_OS2)
     874                 :           NS_TRY_SAFE_CALL_VOID((*pluginFunctions->urlredirectnotify)(npp, spec.get(), static_cast<int32_t>(status), mNPStream.notifyData), mInst);
     875                 : #else
     876               0 :           (*pluginFunctions->urlredirectnotify)(npp, spec.get(), static_cast<int32_t>(status), mNPStream.notifyData);
     877                 : #endif
     878               0 :           return true;
     879                 :         }
     880                 :       }
     881                 :     }
     882                 :   }
     883                 : 
     884               0 :   callback->OnRedirectVerifyCallback(NS_ERROR_FAILURE);
     885               0 :   return true;
     886                 : }
     887                 : 
     888                 : void
     889               0 : nsNPAPIPluginStreamListener::URLRedirectResponse(NPBool allow)
     890                 : {
     891               0 :   if (mHTTPRedirectCallback) {
     892               0 :     mHTTPRedirectCallback->OnRedirectVerifyCallback(allow ? NS_OK : NS_ERROR_FAILURE);
     893               0 :     mRedirectDenied = allow ? false : true;
     894               0 :     mHTTPRedirectCallback = nsnull;
     895                 :   }
     896               0 : }

Generated by: LCOV version 1.7