LCOV - code coverage report
Current view: top level - dom/plugins/ipc - BrowserStreamChild.cpp (source / functions) Hit Total Coverage
Test: output.info Lines: 0 158 0.0 %
Date: 2017-07-14 16:53:18 Functions: 0 15 0.0 %
Legend: Lines: hit not hit

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

Generated by: LCOV version 1.13