Bug 1136930: Fix nsNPAPIPluginStreamListener so that destroystream calls are made during async plugin init; r=jimm
authorAaron Klotz <aklotz@mozilla.com>
Thu, 12 Mar 2015 11:45:31 -0600
changeset 233451 00a32fed278ea562e44b247a696b0cc1add8211b
parent 233418 42afc7ef5ccbe8eb97c027c0eccf9528019e5ad3
child 233452 c4c7be13c0675086c6bebe22dc7ee5ef056ad247
push id28413
push usercbook@mozilla.com
push dateFri, 13 Mar 2015 13:03:26 +0000
treeherdermozilla-central@9dbb2d41bb2c [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersjimm
bugs1136930
milestone39.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Bug 1136930: Fix nsNPAPIPluginStreamListener so that destroystream calls are made during async plugin init; r=jimm
dom/plugins/base/nsNPAPIPluginStreamListener.cpp
dom/plugins/base/nsNPAPIPluginStreamListener.h
--- a/dom/plugins/base/nsNPAPIPluginStreamListener.cpp
+++ b/dom/plugins/base/nsNPAPIPluginStreamListener.cpp
@@ -129,31 +129,31 @@ nsPluginStreamToFile::Close(void)
 // nsNPAPIPluginStreamListener Methods
 
 NS_IMPL_ISUPPORTS(nsNPAPIPluginStreamListener,
                   nsITimerCallback, nsIHTTPHeaderListener)
 
 nsNPAPIPluginStreamListener::nsNPAPIPluginStreamListener(nsNPAPIPluginInstance* inst, 
                                                          void* notifyData,
                                                          const char* aURL)
-: mStreamBuffer(nullptr),
-mNotifyURL(aURL ? PL_strdup(aURL) : nullptr),
-mInst(inst),
-mStreamBufferSize(0),
-mStreamBufferByteCount(0),
-mStreamType(NP_NORMAL),
-mStreamStarted(false),
-mStreamCleanedUp(false),
-mCallNotify(notifyData ? true : false),
-mIsSuspended(false),
-mIsPluginInitJSStream(mInst->mInPluginInitCall &&
-                      aURL && strncmp(aURL, "javascript:",
-                                      sizeof("javascript:") - 1) == 0),
-mRedirectDenied(false),
-mResponseHeaderBuf(nullptr)
+  : mStreamBuffer(nullptr)
+  , mNotifyURL(aURL ? PL_strdup(aURL) : nullptr)
+  , mInst(inst)
+  , mStreamBufferSize(0)
+  , mStreamBufferByteCount(0)
+  , mStreamType(NP_NORMAL)
+  , mStreamState(eStreamStopped)
+  , mStreamCleanedUp(false)
+  , mCallNotify(notifyData ? true : false)
+  , mIsSuspended(false)
+  , mIsPluginInitJSStream(mInst->mInPluginInitCall &&
+                          aURL && strncmp(aURL, "javascript:",
+                                          sizeof("javascript:") - 1) == 0)
+  , mRedirectDenied(false)
+  , mResponseHeaderBuf(nullptr)
 {
   mNPStreamWrapper = new nsNPAPIStreamWrapper(nullptr, this);
   mNPStreamWrapper->mNPStream.notifyData = notifyData;
 }
 
 nsNPAPIPluginStreamListener::~nsNPAPIPluginStreamListener()
 {
   // remove this from the plugin instance's stream list
@@ -203,17 +203,17 @@ nsNPAPIPluginStreamListener::CleanUpStre
   // Release any outstanding redirect callback.
   if (mHTTPRedirectCallback) {
     mHTTPRedirectCallback->OnRedirectVerifyCallback(NS_ERROR_FAILURE);
     mHTTPRedirectCallback = nullptr;
   }
 
   // Seekable streams have an extra addref when they are created which must
   // be matched here.
-  if (NP_SEEK == mStreamType && mStreamStarted)
+  if (NP_SEEK == mStreamType && mStreamState == eStreamTypeSet)
     NS_RELEASE_THIS();
 
   if (mStreamListenerPeer) {
     mStreamListenerPeer->CancelRequests(NS_BINDING_ABORTED);
     mStreamListenerPeer = nullptr;
   }
 
   if (!mInst || !mInst->CanFireNotifications())
@@ -225,32 +225,32 @@ nsNPAPIPluginStreamListener::CleanUpStre
   if (!plugin || !plugin->GetLibrary())
     return rv;
 
   NPPluginFuncs* pluginFunctions = plugin->PluginFuncs();
 
   NPP npp;
   mInst->GetNPP(&npp);
 
-  if (mStreamStarted && pluginFunctions->destroystream) {
+  if (mStreamState >= eNewStreamCalled && pluginFunctions->destroystream) {
     NPPAutoPusher nppPusher(npp);
 
     NPError error;
     NS_TRY_SAFE_CALL_RETURN(error, (*pluginFunctions->destroystream)(npp, &mNPStreamWrapper->mNPStream, reason), mInst,
                             NS_PLUGIN_CALL_UNSAFE_TO_REENTER_GECKO);
     
     NPP_PLUGIN_LOG(PLUGIN_LOG_NORMAL,
                    ("NPP DestroyStream called: this=%p, npp=%p, reason=%d, return=%d, url=%s\n",
                     this, npp, reason, error, mNPStreamWrapper->mNPStream.url));
     
     if (error == NPERR_NO_ERROR)
       rv = NS_OK;
   }
   
-  mStreamStarted = false;
+  mStreamState = eStreamStopped;
   
   // fire notification back to plugin, just like before
   CallURLNotify(reason);
   
   return rv;
 }
 
 void
@@ -362,17 +362,17 @@ nsNPAPIPluginStreamListener::SetStreamTy
       // plugin calls NPN_DestroyStream (CleanUpStream). If the plugin never
       // calls NPN_DestroyStream the stream will be destroyed before the plugin
       // instance is destroyed.
       NS_ADDREF_THIS();
       break;
     default:
       return false;
   }
-  mStreamStarted = true;
+  mStreamState = eStreamTypeSet;
   if (aNeedsResume) {
     if (mStreamListenerPeer) {
       mStreamListenerPeer->OnStreamTypeSet(mStreamType);
     }
     ResumeRequest();
   }
   return true;
 }
@@ -586,17 +586,17 @@ nsNPAPIPluginStreamListener::OnDataAvail
         
         NS_TRY_SAFE_CALL_RETURN(numtowrite, (*pluginFunctions->writeready)(npp, &mNPStreamWrapper->mNPStream), mInst,
                                 NS_PLUGIN_CALL_UNSAFE_TO_REENTER_GECKO);
         NPP_PLUGIN_LOG(PLUGIN_LOG_NOISY,
                        ("NPP WriteReady called: this=%p, npp=%p, "
                         "return(towrite)=%d, url=%s\n",
                         this, npp, numtowrite, mNPStreamWrapper->mNPStream.url));
         
-        if (!mStreamStarted) {
+        if (mStreamState == eStreamStopped) {
           // The plugin called NPN_DestroyStream() from within
           // NPP_WriteReady(), kill the stream.
           
           return NS_BINDING_ABORTED;
         }
         
         // if WriteReady returned 0, the plugin is not ready to handle
         // the data, suspend the stream (if it isn't already
@@ -638,17 +638,17 @@ nsNPAPIPluginStreamListener::OnDataAvail
                               NS_PLUGIN_CALL_UNSAFE_TO_REENTER_GECKO);
       
       NPP_PLUGIN_LOG(PLUGIN_LOG_NOISY,
                      ("NPP Write called: this=%p, npp=%p, pos=%d, len=%d, "
                       "buf=%s, return(written)=%d,  url=%s\n",
                       this, npp, streamPosition, numtowrite,
                       ptrStreamBuffer, writeCount, mNPStreamWrapper->mNPStream.url));
       
-      if (!mStreamStarted) {
+      if (mStreamState == eStreamStopped) {
         // The plugin called NPN_DestroyStream() from within
         // NPP_Write(), kill the stream.
         return NS_BINDING_ABORTED;
       }
       
       if (writeCount > 0) {
         NS_ASSERTION(writeCount <= mStreamBufferByteCount,
                      "Plugin read past the end of the available data!");
@@ -809,17 +809,17 @@ nsNPAPIPluginStreamListener::Notify(nsIT
   
   if (NS_FAILED(rv)) {
     // We ran into an error, no need to keep firing this timer then.
     aTimer->Cancel();
     return NS_OK;
   }
   
   if (mStreamBufferByteCount != oldStreamBufferByteCount &&
-      ((mStreamStarted && mStreamBufferByteCount < 1024) ||
+      ((mStreamState == eStreamTypeSet && mStreamBufferByteCount < 1024) ||
        mStreamBufferByteCount == 0)) {
         // The plugin read some data and we've got less than 1024 bytes in
         // our buffer (or its empty and the stream is already
         // done). Resume the request so that we get more data off the
         // network.
         ResumeRequest();
         // Necko will pump data now that we've resumed the request.
         StopDataPump();
--- a/dom/plugins/base/nsNPAPIPluginStreamListener.h
+++ b/dom/plugins/base/nsNPAPIPluginStreamListener.h
@@ -100,25 +100,33 @@ public:
   void SetStreamListenerPeer(nsPluginStreamListenerPeer* aPeer) { mStreamListenerPeer = aPeer; }
 
   // Returns true if the redirect will be handled by NPAPI, false otherwise.
   bool HandleRedirectNotification(nsIChannel *oldChannel, nsIChannel *newChannel,
                                   nsIAsyncVerifyRedirectCallback* callback);
   void URLRedirectResponse(NPBool allow);
 
 protected:
+
+  enum StreamState
+  {
+    eStreamStopped = 0, // The stream is stopped
+    eNewStreamCalled,   // NPP_NewStream was called but has not completed yet
+    eStreamTypeSet      // The stream is fully initialized
+  };
+
   virtual ~nsNPAPIPluginStreamListener();
   char* mStreamBuffer;
   char* mNotifyURL;
   nsRefPtr<nsNPAPIPluginInstance> mInst;
   nsNPAPIStreamWrapper *mNPStreamWrapper;
   uint32_t mStreamBufferSize;
   int32_t mStreamBufferByteCount;
   int32_t mStreamType;
-  bool mStreamStarted;
+  StreamState mStreamState;
   bool mStreamCleanedUp;
   bool mCallNotify;
   bool mIsSuspended;
   bool mIsPluginInitJSStream;
   bool mRedirectDenied;
   nsCString mResponseHeaders;
   char* mResponseHeaderBuf;
   nsCOMPtr<nsITimer> mDataPumpTimer;