dom/plugins/ipc/BrowserStreamChild.cpp

Thu, 22 Jan 2015 13:21:57 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Thu, 22 Jan 2015 13:21:57 +0100
branch
TOR_BUG_9701
changeset 15
b8a032363ba2
permissions
-rw-r--r--

Incorporate requested changes from Mozilla in review:
https://bugzilla.mozilla.org/show_bug.cgi?id=1123480#c6

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

mercurial