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

       1                 : /* -*- Mode: C++; c-basic-offset: 2; indent-tabs-mode: nil; tab-width: 8 -*- */
       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 Plugin App.
      16                 :  *
      17                 :  * The Initial Developer of the Original Code is
      18                 :  *   Benjamin Smedberg <benjamin@smedbergs.us>
      19                 :  * Portions created by the Initial Developer are Copyright (C) 2009
      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 "BrowserStreamChild.h"
      39                 : #include "PluginInstanceChild.h"
      40                 : #include "StreamNotifyChild.h"
      41                 : 
      42                 : namespace mozilla {
      43                 : namespace plugins {
      44                 : 
      45               0 : BrowserStreamChild::BrowserStreamChild(PluginInstanceChild* instance,
      46                 :                                        const nsCString& url,
      47                 :                                        const uint32_t& length,
      48                 :                                        const uint32_t& lastmodified,
      49                 :                                        StreamNotifyChild* notifyData,
      50                 :                                        const nsCString& headers,
      51                 :                                        const nsCString& mimeType,
      52                 :                                        const bool& seekable,
      53                 :                                        NPError* rv,
      54                 :                                        uint16_t* stype)
      55                 :   : mInstance(instance)
      56                 :   , mStreamStatus(kStreamOpen)
      57                 :   , mDestroyPending(NOT_DESTROYED)
      58                 :   , mNotifyPending(false)
      59                 :   , mStreamAsFilePending(false)
      60                 :   , mInstanceDying(false)
      61                 :   , mState(CONSTRUCTING)
      62                 :   , mURL(url)
      63                 :   , mHeaders(headers)
      64                 :   , mStreamNotify(notifyData)
      65               0 :   , mDeliveryTracker(this)
      66                 : {
      67               0 :   PLUGIN_LOG_DEBUG(("%s (%s, %i, %i, %p, %s, %s)", FULLFUNCTION,
      68                 :                     url.get(), length, lastmodified, (void*) notifyData,
      69                 :                     headers.get(), mimeType.get()));
      70                 : 
      71               0 :   AssertPluginThread();
      72                 : 
      73               0 :   memset(&mStream, 0, sizeof(mStream));
      74               0 :   mStream.ndata = static_cast<AStream*>(this);
      75               0 :   mStream.url = NullableStringGet(mURL);
      76               0 :   mStream.end = length;
      77               0 :   mStream.lastmodified = lastmodified;
      78               0 :   mStream.headers = NullableStringGet(mHeaders);
      79               0 :   if (notifyData)
      80               0 :     mStream.notifyData = notifyData->mClosure;
      81               0 : }
      82                 : 
      83                 : NPError
      84               0 : BrowserStreamChild::StreamConstructed(
      85                 :             const nsCString& mimeType,
      86                 :             const bool& seekable,
      87                 :             uint16_t* stype)
      88                 : {
      89               0 :   NPError rv = NPERR_NO_ERROR;
      90                 : 
      91               0 :   *stype = NP_NORMAL;
      92                 :   rv = mInstance->mPluginIface->newstream(
      93               0 :     &mInstance->mData, const_cast<char*>(NullableStringGet(mimeType)),
      94               0 :     &mStream, seekable, stype);
      95               0 :   if (rv != NPERR_NO_ERROR) {
      96               0 :     mState = DELETING;
      97               0 :     mStreamNotify = NULL;
      98                 :   }
      99                 :   else {
     100               0 :     mState = ALIVE;
     101                 : 
     102               0 :     if (mStreamNotify)
     103               0 :       mStreamNotify->SetAssociatedStream(this);
     104                 :   }
     105                 : 
     106               0 :   return rv;
     107                 : }
     108                 : 
     109               0 : BrowserStreamChild::~BrowserStreamChild()
     110                 : {
     111               0 :   NS_ASSERTION(!mStreamNotify, "Should have nulled it by now!");
     112               0 : }
     113                 : 
     114                 : bool
     115               0 : BrowserStreamChild::RecvWrite(const int32_t& offset,
     116                 :                               const Buffer& data,
     117                 :                               const uint32_t& newlength)
     118                 : {
     119               0 :   PLUGIN_LOG_DEBUG_FUNCTION;
     120                 : 
     121               0 :   AssertPluginThread();
     122                 : 
     123               0 :   if (ALIVE != mState)
     124               0 :     NS_RUNTIMEABORT("Unexpected state: received data after NPP_DestroyStream?");
     125                 : 
     126               0 :   if (kStreamOpen != mStreamStatus)
     127               0 :     return true;
     128                 : 
     129               0 :   mStream.end = newlength;
     130                 : 
     131               0 :   NS_ASSERTION(data.Length() > 0, "Empty data");
     132                 : 
     133               0 :   PendingData* newdata = mPendingData.AppendElement();
     134               0 :   newdata->offset = offset;
     135               0 :   newdata->data = data;
     136               0 :   newdata->curpos = 0;
     137                 : 
     138               0 :   EnsureDeliveryPending();
     139                 : 
     140               0 :   return true;
     141                 : }
     142                 : 
     143                 : bool
     144               0 : BrowserStreamChild::RecvNPP_StreamAsFile(const nsCString& fname)
     145                 : {
     146               0 :   PLUGIN_LOG_DEBUG(("%s (fname=%s)", FULLFUNCTION, fname.get()));
     147                 : 
     148               0 :   AssertPluginThread();
     149                 : 
     150               0 :   if (ALIVE != mState)
     151               0 :     NS_RUNTIMEABORT("Unexpected state: received file after NPP_DestroyStream?");
     152                 : 
     153               0 :   if (kStreamOpen != mStreamStatus)
     154               0 :     return true;
     155                 : 
     156               0 :   mStreamAsFilePending = true;
     157               0 :   mStreamAsFileName = fname;
     158               0 :   EnsureDeliveryPending();
     159                 : 
     160               0 :   return true;
     161                 : }
     162                 : 
     163                 : bool
     164               0 : BrowserStreamChild::RecvNPP_DestroyStream(const NPReason& reason)
     165                 : {
     166               0 :   PLUGIN_LOG_DEBUG_METHOD;
     167                 : 
     168               0 :   if (ALIVE != mState)
     169               0 :     NS_RUNTIMEABORT("Unexpected state: recevied NPP_DestroyStream twice?");
     170                 : 
     171               0 :   mState = DYING;
     172               0 :   mDestroyPending = DESTROY_PENDING;
     173               0 :   if (NPRES_DONE != reason)
     174               0 :     mStreamStatus = reason;
     175                 : 
     176               0 :   EnsureDeliveryPending();
     177               0 :   return true;
     178                 : }
     179                 : 
     180                 : bool
     181               0 : BrowserStreamChild::Recv__delete__()
     182                 : {
     183               0 :   AssertPluginThread();
     184                 : 
     185               0 :   if (DELETING != mState)
     186               0 :     NS_RUNTIMEABORT("Bad state, not DELETING");
     187                 : 
     188               0 :   return true;
     189                 : }
     190                 : 
     191                 : NPError
     192               0 : BrowserStreamChild::NPN_RequestRead(NPByteRange* aRangeList)
     193                 : {
     194               0 :   PLUGIN_LOG_DEBUG_FUNCTION;
     195                 : 
     196               0 :   AssertPluginThread();
     197                 : 
     198               0 :   if (ALIVE != mState || kStreamOpen != mStreamStatus)
     199               0 :     return NPERR_GENERIC_ERROR;
     200                 : 
     201               0 :   IPCByteRanges ranges;
     202               0 :   for (; aRangeList; aRangeList = aRangeList->next) {
     203               0 :     IPCByteRange br = {aRangeList->offset, aRangeList->length};
     204               0 :     ranges.push_back(br);
     205                 :   }
     206                 : 
     207                 :   NPError result;
     208               0 :   CallNPN_RequestRead(ranges, &result);
     209               0 :   return result;
     210                 : }
     211                 : 
     212                 : void
     213               0 : BrowserStreamChild::NPN_DestroyStream(NPReason reason)
     214                 : {
     215               0 :   mStreamStatus = reason;
     216               0 :   if (ALIVE == mState)
     217               0 :     SendNPN_DestroyStream(reason);
     218                 : 
     219               0 :   EnsureDeliveryPending();
     220               0 : }
     221                 : 
     222                 : void
     223               0 : BrowserStreamChild::EnsureDeliveryPending()
     224                 : {
     225                 :   MessageLoop::current()->PostTask(FROM_HERE,
     226               0 :     mDeliveryTracker.NewRunnableMethod(&BrowserStreamChild::Deliver));
     227               0 : }
     228                 : 
     229                 : void
     230               0 : BrowserStreamChild::Deliver()
     231                 : {
     232               0 :   while (kStreamOpen == mStreamStatus && mPendingData.Length()) {
     233               0 :     if (DeliverPendingData() && kStreamOpen == mStreamStatus) {
     234               0 :       SetSuspendedTimer();
     235               0 :       return;
     236                 :     }
     237                 :   }
     238               0 :   ClearSuspendedTimer();
     239                 : 
     240               0 :   NS_ASSERTION(kStreamOpen != mStreamStatus || 0 == mPendingData.Length(),
     241                 :                "Exit out of the data-delivery loop with pending data");
     242               0 :   mPendingData.Clear();
     243                 : 
     244                 :   // NPP_StreamAsFile() is documented (at MDN) to be called "when the stream
     245                 :   // is complete" -- i.e. after all calls to NPP_WriteReady() and NPP_Write()
     246                 :   // have finished.  We make these calls asynchronously (from
     247                 :   // DeliverPendingData()).  So we need to make sure all the "pending data"
     248                 :   // has been "delivered" before calling NPP_StreamAsFile() (also
     249                 :   // asynchronously).  Doing this resolves bug 687610, bug 670036 and possibly
     250                 :   // also other bugs.
     251               0 :   if (mStreamAsFilePending) {
     252               0 :     if (mStreamStatus == kStreamOpen)
     253                 :       mInstance->mPluginIface->asfile(&mInstance->mData, &mStream,
     254               0 :                                       mStreamAsFileName.get());
     255               0 :     mStreamAsFilePending = false;
     256                 :   }
     257                 : 
     258               0 :   if (DESTROY_PENDING == mDestroyPending) {
     259               0 :     mDestroyPending = DESTROYED;
     260               0 :     if (mState != DYING)
     261               0 :       NS_RUNTIMEABORT("mDestroyPending but state not DYING");
     262                 : 
     263               0 :     NS_ASSERTION(NPRES_DONE != mStreamStatus, "Success status set too early!");
     264               0 :     if (kStreamOpen == mStreamStatus)
     265               0 :       mStreamStatus = NPRES_DONE;
     266                 : 
     267                 :     (void) mInstance->mPluginIface
     268               0 :       ->destroystream(&mInstance->mData, &mStream, mStreamStatus);
     269                 :   }
     270               0 :   if (DESTROYED == mDestroyPending && mNotifyPending) {
     271               0 :     NS_ASSERTION(mStreamNotify, "mDestroyPending but no mStreamNotify?");
     272                 :       
     273               0 :     mNotifyPending = false;
     274               0 :     mStreamNotify->NPP_URLNotify(mStreamStatus);
     275               0 :     delete mStreamNotify;
     276               0 :     mStreamNotify = NULL;
     277                 :   }
     278               0 :   if (DYING == mState && DESTROYED == mDestroyPending
     279               0 :       && !mStreamNotify && !mInstanceDying) {
     280               0 :     SendStreamDestroyed();
     281               0 :     mState = DELETING;
     282                 :   }
     283                 : }
     284                 : 
     285                 : bool
     286               0 : BrowserStreamChild::DeliverPendingData()
     287                 : {
     288               0 :   if (mState != ALIVE && mState != DYING)
     289               0 :     NS_RUNTIMEABORT("Unexpected state");
     290                 : 
     291               0 :   NS_ASSERTION(mPendingData.Length(), "Called from Deliver with empty pending");
     292                 : 
     293               0 :   while (mPendingData[0].curpos < static_cast<int32_t>(mPendingData[0].data.Length())) {
     294               0 :     int32_t r = mInstance->mPluginIface->writeready(&mInstance->mData, &mStream);
     295               0 :     if (kStreamOpen != mStreamStatus)
     296               0 :       return false;
     297               0 :     if (0 == r) // plugin wants to suspend delivery
     298               0 :       return true;
     299                 : 
     300                 :     r = mInstance->mPluginIface->write(
     301                 :       &mInstance->mData, &mStream,
     302               0 :       mPendingData[0].offset + mPendingData[0].curpos, // offset
     303               0 :       mPendingData[0].data.Length() - mPendingData[0].curpos, // length
     304               0 :       const_cast<char*>(mPendingData[0].data.BeginReading() + mPendingData[0].curpos));
     305               0 :     if (kStreamOpen != mStreamStatus)
     306               0 :       return false;
     307               0 :     if (0 == r)
     308               0 :       return true;
     309               0 :     if (r < 0) { // error condition
     310               0 :       NPN_DestroyStream(NPRES_NETWORK_ERR);
     311               0 :       return false;
     312                 :     }
     313               0 :     mPendingData[0].curpos += r;
     314                 :   }
     315               0 :   mPendingData.RemoveElementAt(0);
     316               0 :   return false;
     317                 : }
     318                 : 
     319                 : void
     320               0 : BrowserStreamChild::SetSuspendedTimer()
     321                 : {
     322               0 :   if (mSuspendedTimer.IsRunning())
     323               0 :     return;
     324                 :   mSuspendedTimer.Start(
     325                 :     base::TimeDelta::FromMilliseconds(100), // 100ms copied from Mozilla plugin host
     326               0 :     this, &BrowserStreamChild::Deliver);
     327                 : }
     328                 : 
     329                 : void
     330               0 : BrowserStreamChild::ClearSuspendedTimer()
     331                 : {
     332               0 :   mSuspendedTimer.Stop();
     333               0 : }
     334                 : 
     335                 : } /* namespace plugins */
     336                 : } /* namespace mozilla */

Generated by: LCOV version 1.7