Bug 758227: NPAPI plugin stream decomtamination: nsIPluginStreamInfo. r=bsmedberg
authorJosh Aas <joshmoz@gmail.com>
Tue, 05 Jun 2012 09:58:39 -0400
changeset 95865 8dd2e853993e2c6631bf963ed82447b8dd7badfb
parent 95864 3a23e11202f98ba1cc5af1b3f7c950cfa8e4a432
child 95866 1212d4edfff63a359df3eafe9af391db79c6b11c
push id22859
push useremorley@mozilla.com
push dateWed, 06 Jun 2012 08:23:59 +0000
treeherdermozilla-central@a6c39a15557b [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersbsmedberg
bugs758227
milestone16.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 758227: NPAPI plugin stream decomtamination: nsIPluginStreamInfo. r=bsmedberg
dom/plugins/base/Makefile.in
dom/plugins/base/nsIPluginStreamInfo.idl
dom/plugins/base/nsNPAPIPlugin.cpp
dom/plugins/base/nsNPAPIPluginStreamListener.cpp
dom/plugins/base/nsNPAPIPluginStreamListener.h
dom/plugins/base/nsPluginHost.cpp
dom/plugins/base/nsPluginStreamListenerPeer.cpp
dom/plugins/base/nsPluginStreamListenerPeer.h
--- a/dom/plugins/base/Makefile.in
+++ b/dom/plugins/base/Makefile.in
@@ -21,17 +21,16 @@ LIBXUL_LIBRARY = 1
 EXPORTS_NAMESPACES = mozilla
 
 XPIDLSRCS = \
   nsIHTTPHeaderListener.idl \
   nsIPluginDocument.idl \
   nsIPluginHost.idl \
   nsIPluginInputStream.idl \
   nsIPluginInstanceOwner.idl \
-  nsIPluginStreamInfo.idl \
   nsIPluginTag.idl \
   nsIPluginTagInfo.idl \
   nspluginroot.idl \
   $(NULL)
 
 EXPORTS = \
   npapi.h \
   npfunctions.h \
deleted file mode 100644
--- a/dom/plugins/base/nsIPluginStreamInfo.idl
+++ /dev/null
@@ -1,39 +0,0 @@
-/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
-/* This Source Code Form is subject to the terms of the Mozilla Public
- * License, v. 2.0. If a copy of the MPL was not distributed with this
- * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
-
-/**
- * nsIPluginStreamInfo
- *
- * @status DEPRECATED
- *
- * Originally published XPCOM Plugin API is now deprecated
- * Developers are welcome to use NPAPI, please refer to:
- * http://mozilla.org/projects/plugins/
- */
-
-#include "nsISupports.idl"
-#include "nspluginroot.idl"
-
-%{C++
-#include "npapi.h"
-%}
-
-[uuid(A700845F-0E26-44EA-84F5-3BE5381F98D5)]
-interface nsIPluginStreamInfo : nsISupports
-{
-  readonly attribute string contentType;
-
-  void isSeekable(out boolean aSeekable);
-
-    readonly attribute unsigned long length;
-
-    readonly attribute unsigned long lastModified;
-
-  void getURL(out constCharPtr aURL);
-
-  void requestRead(in NPByteRangePtr aRangeList);
-
-  attribute long streamOffset;
-};
--- a/dom/plugins/base/nsNPAPIPlugin.cpp
+++ b/dom/plugins/base/nsNPAPIPlugin.cpp
@@ -14,16 +14,17 @@
 #include "prclist.h"
 
 #include "jsfriendapi.h"
 
 #include "nsPluginHost.h"
 #include "nsNPAPIPlugin.h"
 #include "nsNPAPIPluginInstance.h"
 #include "nsNPAPIPluginStreamListener.h"
+#include "nsPluginStreamListenerPeer.h"
 #include "nsIServiceManager.h"
 #include "nsThreadUtils.h"
 #include "mozilla/Preferences.h"
 
 #include "nsPluginsDir.h"
 #include "nsPluginSafety.h"
 #include "nsPluginLogging.h"
 
@@ -528,21 +529,22 @@ nsNPAPIPlugin::RetainStream(NPStream *ps
     return NPERR_INVALID_PARAM;
 
   nsNPAPIStreamWrapper* streamWrapper = static_cast<nsNPAPIStreamWrapper*>(pstream->ndata);
   nsNPAPIPluginStreamListener* listener = streamWrapper->GetStreamListener();
   if (!listener) {
     return NPERR_GENERIC_ERROR;
   }
 
-  nsPluginStreamListenerPeer* peer = listener->GetStreamListenerPeer();
-  if (!peer)
+  nsIStreamListener* streamListener = listener->GetStreamListenerPeer();
+  if (!streamListener) {
     return NPERR_GENERIC_ERROR;
-
-  *aRetainedPeer = (nsISupports*) peer;
+  }
+
+  *aRetainedPeer = streamListener;
   NS_ADDREF(*aRetainedPeer);
   return NS_OK;
 }
 
 // Create a new NPP GET or POST (given in the type argument) url
 // stream that may have a notify callback
 NPError
 MakeNewNPAPIStreamInternal(NPP npp, const char *relativeURL, const char *target,
@@ -2505,20 +2507,20 @@ NPError NP_CALLBACK
 
   PRInt32 streamtype = NP_NORMAL;
 
   streamlistener->GetStreamType(&streamtype);
 
   if (streamtype != NP_SEEK)
     return NPERR_STREAM_NOT_SEEKABLE;
 
-  if (!streamlistener->mStreamInfo)
+  if (!streamlistener->mStreamListenerPeer)
     return NPERR_GENERIC_ERROR;
 
-  nsresult rv = streamlistener->mStreamInfo->RequestRead((NPByteRange *)rangeList);
+  nsresult rv = streamlistener->mStreamListenerPeer->RequestRead((NPByteRange *)rangeList);
   if (NS_FAILED(rv))
     return NPERR_GENERIC_ERROR;
 
   return NS_OK;
 }
 
 // Deprecated, only stubbed out
 void* NP_CALLBACK /* OJI type: JRIEnv* */
--- a/dom/plugins/base/nsNPAPIPluginStreamListener.cpp
+++ b/dom/plugins/base/nsNPAPIPluginStreamListener.cpp
@@ -132,17 +132,16 @@ NS_IMPL_ISUPPORTS2(nsNPAPIPluginStreamLi
                    nsITimerCallback, nsIHTTPHeaderListener)
 
 nsNPAPIPluginStreamListener::nsNPAPIPluginStreamListener(nsNPAPIPluginInstance* inst, 
                                                          void* notifyData,
                                                          const char* aURL)
 : mStreamBuffer(nsnull),
 mNotifyURL(aURL ? PL_strdup(aURL) : nsnull),
 mInst(inst),
-mStreamListenerPeer(nsnull),
 mStreamBufferSize(0),
 mStreamBufferByteCount(0),
 mStreamType(NP_NORMAL),
 mStreamStarted(false),
 mStreamCleanedUp(false),
 mCallNotify(notifyData ? true : false),
 mIsSuspended(false),
 mIsPluginInitJSStream(mInst->mInPluginInitCall &&
@@ -210,17 +209,17 @@ nsNPAPIPluginStreamListener::CleanUpStre
   // Seekable streams have an extra addref when they are created which must
   // be matched here.
   if (NP_SEEK == mStreamType)
     NS_RELEASE_THIS();
   
   if (!mInst || !mInst->CanFireNotifications())
     return rv;
   
-  mStreamInfo = NULL;
+  mStreamListenerPeer = nsnull;
   
   PluginDestructionGuard guard(mInst);
 
   nsNPAPIPlugin* plugin = mInst->GetPlugin();
   if (!plugin || !plugin->GetLibrary())
     return rv;
 
   NPPluginFuncs* pluginFunctions = plugin->PluginFuncs();
@@ -274,17 +273,17 @@ nsNPAPIPluginStreamListener::CallURLNoti
     
     NPP_PLUGIN_LOG(PLUGIN_LOG_NORMAL,
                    ("NPP URLNotify called: this=%p, npp=%p, notify=%p, reason=%d, url=%s\n",
                     this, npp, mNPStreamWrapper->mNPStream.notifyData, reason, mNotifyURL));
   }
 }
 
 nsresult
-nsNPAPIPluginStreamListener::OnStartBinding(nsIPluginStreamInfo* pluginInfo)
+nsNPAPIPluginStreamListener::OnStartBinding(nsPluginStreamListenerPeer* streamPeer)
 {
   if (!mInst || !mInst->CanFireNotifications())
     return NS_ERROR_FAILURE;
 
   PluginDestructionGuard guard(mInst);
 
   nsNPAPIPlugin* plugin = mInst->GetPlugin();
   if (!plugin || !plugin->GetLibrary())
@@ -298,28 +297,28 @@ nsNPAPIPluginStreamListener::OnStartBind
   NPP npp;
   mInst->GetNPP(&npp);
 
   bool seekable;
   char* contentType;
   PRUint16 streamType = NP_NORMAL;
   NPError error;
 
-  pluginInfo->GetURL(&mNPStreamWrapper->mNPStream.url);
-  pluginInfo->GetLength((PRUint32*)&(mNPStreamWrapper->mNPStream.end));
-  pluginInfo->GetLastModified((PRUint32*)&(mNPStreamWrapper->mNPStream.lastmodified));
-  pluginInfo->IsSeekable(&seekable);
-  pluginInfo->GetContentType(&contentType);
+  streamPeer->GetURL(&mNPStreamWrapper->mNPStream.url);
+  streamPeer->GetLength((PRUint32*)&(mNPStreamWrapper->mNPStream.end));
+  streamPeer->GetLastModified((PRUint32*)&(mNPStreamWrapper->mNPStream.lastmodified));
+  streamPeer->IsSeekable(&seekable);
+  streamPeer->GetContentType(&contentType);
   
   if (!mResponseHeaders.IsEmpty()) {
     mResponseHeaderBuf = PL_strdup(mResponseHeaders.get());
     mNPStreamWrapper->mNPStream.headers = mResponseHeaderBuf;
   }
   
-  mStreamInfo = pluginInfo;
+  mStreamListenerPeer = streamPeer;
   
   NPPAutoPusher nppPusher(npp);
   
   NS_TRY_SAFE_CALL_RETURN(error, (*pluginFunctions->newstream)(npp, (char*)contentType, &mNPStreamWrapper->mNPStream, seekable, &streamType), mInst);
   
   NPP_PLUGIN_LOG(PLUGIN_LOG_NORMAL,
                  ("NPP NewStream called: this=%p, npp=%p, mime=%s, seek=%d, type=%d, return=%d, url=%s\n",
                   this, npp, (char *)contentType, seekable, streamType, error, mNPStreamWrapper->mNPStream.url));
@@ -355,41 +354,32 @@ nsNPAPIPluginStreamListener::OnStartBind
   return NS_OK;
 }
 
 void
 nsNPAPIPluginStreamListener::SuspendRequest()
 {
   NS_ASSERTION(!mIsSuspended,
                "Suspending a request that's already suspended!");
-  
-  nsCOMPtr<nsINPAPIPluginStreamInfo> pluginInfoNPAPI =
-  do_QueryInterface(mStreamInfo);
-  
-  if (!pluginInfoNPAPI) {
-    return;
-  }
-  
+
   nsresult rv = StartDataPump();
   if (NS_FAILED(rv))
     return;
   
   mIsSuspended = true;
-  
-  pluginInfoNPAPI->SuspendRequests();
+
+  if (mStreamListenerPeer) {
+   mStreamListenerPeer->SuspendRequests();
+  }
 }
 
 void
 nsNPAPIPluginStreamListener::ResumeRequest()
 {
-  nsCOMPtr<nsINPAPIPluginStreamInfo> pluginInfoNPAPI =
-  do_QueryInterface(mStreamInfo);
-  
-  pluginInfoNPAPI->ResumeRequests();
-  
+  mStreamListenerPeer->ResumeRequests();
   mIsSuspended = false;
 }
 
 nsresult
 nsNPAPIPluginStreamListener::StartDataPump()
 {
   nsresult rv;
   mDataPumpTimer = do_CreateInstance("@mozilla.org/timer;1", &rv);
@@ -431,27 +421,27 @@ nsNPAPIPluginStreamListener::PluginInitJ
 // This method is called when there's more data available off the
 // network, but it's also called from our data pump when we're feeding
 // the plugin data that we already got off the network, but the plugin
 // was unable to consume it at the point it arrived. In the case when
 // the plugin pump calls this method, the input argument will be null,
 // and the length will be the number of bytes available in our
 // internal buffer.
 nsresult
-nsNPAPIPluginStreamListener::OnDataAvailable(nsIPluginStreamInfo* pluginInfo,
+nsNPAPIPluginStreamListener::OnDataAvailable(nsPluginStreamListenerPeer* streamPeer,
                                              nsIInputStream* input,
                                              PRUint32 length)
 {
   if (!length || !mInst || !mInst->CanFireNotifications())
     return NS_ERROR_FAILURE;
   
   PluginDestructionGuard guard(mInst);
   
   // Just in case the caller switches plugin info on us.
-  mStreamInfo = pluginInfo;
+  mStreamListenerPeer = streamPeer;
 
   nsNPAPIPlugin* plugin = mInst->GetPlugin();
   if (!plugin || !plugin->GetLibrary())
     return NS_ERROR_FAILURE;
 
   NPPluginFuncs* pluginFunctions = plugin->PluginFuncs();
 
   // check out if plugin implements NPP_Write call
@@ -461,17 +451,17 @@ nsNPAPIPluginStreamListener::OnDataAvail
   if (!mStreamBuffer) {
     // To optimize the mem usage & performance we have to allocate
     // mStreamBuffer here in first ODA when length of data available
     // in input stream is known.  mStreamBuffer will be freed in DTOR.
     // we also have to remember the size of that buff to make safe
     // consecutive Read() calls form input stream into our buff.
     
     PRUint32 contentLength;
-    pluginInfo->GetLength(&contentLength);
+    streamPeer->GetLength(&contentLength);
     
     mStreamBufferSize = NS_MAX(length, contentLength);
     
     // Limit the size of the initial buffer to MAX_PLUGIN_NECKO_BUFFER
     // (16k). This buffer will grow if needed, as in the case where
     // we're getting data faster than the plugin can process it.
     mStreamBufferSize = NS_MIN(mStreamBufferSize,
                                PRUint32(MAX_PLUGIN_NECKO_BUFFER));
@@ -481,32 +471,32 @@ nsNPAPIPluginStreamListener::OnDataAvail
       return NS_ERROR_OUT_OF_MEMORY;
   }
   
   // prepare NPP_ calls params
   NPP npp;
   mInst->GetNPP(&npp);
   
   PRInt32 streamPosition;
-  pluginInfo->GetStreamOffset(&streamPosition);
+  streamPeer->GetStreamOffset(&streamPosition);
   PRInt32 streamOffset = streamPosition;
   
   if (input) {
     streamOffset += length;
     
     // Set new stream offset for the next ODA call regardless of how
     // following NPP_Write call will behave we pretend to consume all
     // data from the input stream.  It's possible that current steam
     // position will be overwritten from NPP_RangeRequest call made
     // from NPP_Write, so we cannot call SetStreamOffset after
     // NPP_Write.
     //
     // Note: there is a special case when data flow should be
     // temporarily stopped if NPP_WriteReady returns 0 (bug #89270)
-    pluginInfo->SetStreamOffset(streamOffset);
+    streamPeer->SetStreamOffset(streamOffset);
     
     // set new end in case the content is compressed
     // initial end is less than end of decompressed stream
     // and some plugins (e.g. acrobat) can fail. 
     if ((PRInt32)mNPStreamWrapper->mNPStream.end < streamOffset)
       mNPStreamWrapper->mNPStream.end = streamOffset;
   }
   
@@ -690,28 +680,28 @@ nsNPAPIPluginStreamListener::OnDataAvail
   if (streamPosition != streamOffset) {
     // The plugin didn't consume all available data, or consumed some
     // of our cached data while we're pumping cached data. Adjust the
     // plugin info's stream offset to match reality, except if the
     // plugin info's stream offset was set by a re-entering
     // NPN_RequestRead() call.
     
     PRInt32 postWriteStreamPosition;
-    pluginInfo->GetStreamOffset(&postWriteStreamPosition);
+    streamPeer->GetStreamOffset(&postWriteStreamPosition);
     
     if (postWriteStreamPosition == streamOffset) {
-      pluginInfo->SetStreamOffset(streamPosition);
+      streamPeer->SetStreamOffset(streamPosition);
     }
   }
   
   return rv;
 }
 
 nsresult
-nsNPAPIPluginStreamListener::OnFileAvailable(nsIPluginStreamInfo* pluginInfo, 
+nsNPAPIPluginStreamListener::OnFileAvailable(nsPluginStreamListenerPeer* streamPeer, 
                                              const char* fileName)
 {
   if (!mInst || !mInst->CanFireNotifications())
     return NS_ERROR_FAILURE;
   
   PluginDestructionGuard guard(mInst);
 
   nsNPAPIPlugin* plugin = mInst->GetPlugin();
@@ -731,27 +721,26 @@ nsNPAPIPluginStreamListener::OnFileAvail
   NPP_PLUGIN_LOG(PLUGIN_LOG_NORMAL,
                  ("NPP StreamAsFile called: this=%p, npp=%p, url=%s, file=%s\n",
                   this, npp, mNPStreamWrapper->mNPStream.url, fileName));
   
   return NS_OK;
 }
 
 nsresult
-nsNPAPIPluginStreamListener::OnStopBinding(nsIPluginStreamInfo* pluginInfo, 
+nsNPAPIPluginStreamListener::OnStopBinding(nsPluginStreamListenerPeer* streamPeer, 
                                            nsresult status)
 {
   StopDataPump();
   
   if (NS_FAILED(status)) {
     // The stream was destroyed, or died for some reason. Make sure we
     // cancel the underlying request.
-    nsCOMPtr<nsINPAPIPluginStreamInfo> pluginInfoNPAPI = do_QueryInterface(mStreamInfo);
-    if (pluginInfoNPAPI) {
-      pluginInfoNPAPI->CancelRequests(status);
+    if (mStreamListenerPeer) {
+      mStreamListenerPeer->CancelRequests(status);
     }
   }
   
   if (!mInst || !mInst->CanFireNotifications())
     return NS_ERROR_FAILURE;
 
   NPReason reason = NS_FAILED(status) ? NPRES_NETWORK_ERR : NPRES_DONE;
   if (mRedirectDenied) {
@@ -783,17 +772,17 @@ nsNPAPIPluginStreamListener::GetStreamTy
 
 NS_IMETHODIMP
 nsNPAPIPluginStreamListener::Notify(nsITimer *aTimer)
 {
   NS_ASSERTION(aTimer == mDataPumpTimer, "Uh, wrong timer?");
   
   PRInt32 oldStreamBufferByteCount = mStreamBufferByteCount;
   
-  nsresult rv = OnDataAvailable(mStreamInfo, nsnull, mStreamBufferByteCount);
+  nsresult rv = OnDataAvailable(mStreamListenerPeer, nsnull, mStreamBufferByteCount);
   
   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 &&
--- a/dom/plugins/base/nsNPAPIPluginStreamListener.h
+++ b/dom/plugins/base/nsNPAPIPluginStreamListener.h
@@ -2,32 +2,30 @@
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #ifndef nsNPAPIPluginStreamListener_h_
 #define nsNPAPIPluginStreamListener_h_
 
 #include "nscore.h"
-#include "nsIPluginStreamInfo.h"
 #include "nsIHTTPHeaderListener.h"
 #include "nsIRequest.h"
 #include "nsITimer.h"
 #include "nsAutoPtr.h"
 #include "nsCOMArray.h"
 #include "nsIOutputStream.h"
 #include "nsIPluginInstanceOwner.h"
 #include "nsString.h"
 #include "nsNPAPIPluginInstance.h"
 #include "nsIAsyncVerifyRedirectCallback.h"
 #include "mozilla/PluginLibrary.h"
 
 #define MAX_PLUGIN_NECKO_BUFFER 16384
 
-class nsINPAPIPluginStreamInfo;
 class nsPluginStreamListenerPeer;
 class nsNPAPIPluginStreamListener;
 
 class nsNPAPIStreamWrapper
 {
 public:
   nsNPAPIStreamWrapper(nsIOutputStream *outputStream,
                        nsNPAPIPluginStreamListener *streamListener);
@@ -37,74 +35,16 @@ public:
   nsNPAPIPluginStreamListener* GetStreamListener() { return mStreamListener; }
 
   NPStream                              mNPStream;
 protected:
   nsCOMPtr<nsIOutputStream>             mOutputStream; // only valid if not browser initiated
   nsNPAPIPluginStreamListener*          mStreamListener; // only valid if browser initiated
 };
 
-// nsINPAPIPluginStreamInfo is an internal helper interface that exposes
-// the underlying necko request to consumers of nsIPluginStreamInfo's.
-#define NS_INPAPIPLUGINSTREAMINFO_IID       \
-{ 0x097fdaaa, 0xa2a3, 0x49c2, \
-{0x91, 0xee, 0xeb, 0xc5, 0x7d, 0x6c, 0x9c, 0x97} }
-
-class nsINPAPIPluginStreamInfo : public nsIPluginStreamInfo
-{
-public:
-  NS_DECLARE_STATIC_IID_ACCESSOR(NS_INPAPIPLUGINSTREAMINFO_IID)
-
-  void TrackRequest(nsIRequest* request)
-  {
-    mRequests.AppendObject(request);
-  }
-
-  void ReplaceRequest(nsIRequest* oldRequest, nsIRequest* newRequest)
-  {
-    PRInt32 i = mRequests.IndexOfObject(oldRequest);
-    if (i == -1) {
-      NS_ASSERTION(mRequests.Count() == 0,
-                   "Only our initial stream should be unknown!");
-      mRequests.AppendObject(oldRequest);
-    }
-    else {
-      mRequests.ReplaceObjectAt(newRequest, i);
-    }
-  }
-  
-  void CancelRequests(nsresult status)
-  {
-    // Copy the array to avoid modification during the loop.
-    nsCOMArray<nsIRequest> requestsCopy(mRequests);
-    for (PRInt32 i = 0; i < requestsCopy.Count(); ++i)
-      requestsCopy[i]->Cancel(status);
-  }
-
-  void SuspendRequests() {
-    nsCOMArray<nsIRequest> requestsCopy(mRequests);
-    for (PRInt32 i = 0; i < requestsCopy.Count(); ++i)
-      requestsCopy[i]->Suspend();
-  }
-
-  void ResumeRequests() {
-    nsCOMArray<nsIRequest> requestsCopy(mRequests);
-    for (PRInt32 i = 0; i < requestsCopy.Count(); ++i)
-      requestsCopy[i]->Resume();
-  }
-
-protected:
-  friend class nsPluginByteRangeStreamListener;
-  
-  nsCOMArray<nsIRequest> mRequests;
-};
-
-NS_DEFINE_STATIC_IID_ACCESSOR(nsINPAPIPluginStreamInfo,
-                              NS_INPAPIPLUGINSTREAMINFO_IID)
-
 // Used to handle NPN_NewStream() - writes the stream as received by the plugin
 // to a file and at completion (NPN_DestroyStream), tells the browser to load it into
 // a plugin-specified target
 class nsPluginStreamToFile : public nsIOutputStream
 {
 public:
   nsPluginStreamToFile(const char* target, nsIPluginInstanceOwner* owner);
   virtual ~nsPluginStreamToFile();
@@ -129,23 +69,23 @@ public:
   NS_DECL_ISUPPORTS
   NS_DECL_NSITIMERCALLBACK
   NS_DECL_NSIHTTPHEADERLISTENER
 
   nsNPAPIPluginStreamListener(nsNPAPIPluginInstance* inst, void* notifyData,
                               const char* aURL);
   virtual ~nsNPAPIPluginStreamListener();
 
-  nsresult OnStartBinding(nsIPluginStreamInfo* pluginInfo);
-  nsresult OnDataAvailable(nsIPluginStreamInfo* pluginInfo,
+  nsresult OnStartBinding(nsPluginStreamListenerPeer* streamPeer);
+  nsresult OnDataAvailable(nsPluginStreamListenerPeer* streamPeer,
                            nsIInputStream* input,
                            PRUint32 length);
-  nsresult OnFileAvailable(nsIPluginStreamInfo* pluginInfo, 
+  nsresult OnFileAvailable(nsPluginStreamListenerPeer* streamPeer, 
                            const char* fileName);
-  nsresult OnStopBinding(nsIPluginStreamInfo* pluginInfo, 
+  nsresult OnStopBinding(nsPluginStreamListenerPeer* streamPeer, 
                          nsresult status);
   nsresult GetStreamType(PRInt32 *result);
 
   bool IsStarted();
   nsresult CleanUpStream(NPReason reason);
   void CallURLNotify(NPReason reason);
   void SetCallNotify(bool aCallNotify) { mCallNotify = aCallNotify; }
   void SuspendRequest();
@@ -162,29 +102,28 @@ public:
   bool HandleRedirectNotification(nsIChannel *oldChannel, nsIChannel *newChannel,
                                   nsIAsyncVerifyRedirectCallback* callback);
   void URLRedirectResponse(NPBool allow);
 
 protected:
   char* mStreamBuffer;
   char* mNotifyURL;
   nsRefPtr<nsNPAPIPluginInstance> mInst;
-  nsPluginStreamListenerPeer* mStreamListenerPeer;
   nsNPAPIStreamWrapper *mNPStreamWrapper;
   PRUint32 mStreamBufferSize;
   PRInt32 mStreamBufferByteCount;
   PRInt32 mStreamType;
   bool mStreamStarted;
   bool mStreamCleanedUp;
   bool mCallNotify;
   bool mIsSuspended;
   bool mIsPluginInitJSStream;
   bool mRedirectDenied;
   nsCString mResponseHeaders;
   char* mResponseHeaderBuf;
   nsCOMPtr<nsITimer> mDataPumpTimer;
   nsCOMPtr<nsIAsyncVerifyRedirectCallback> mHTTPRedirectCallback;
 
 public:
-  nsCOMPtr<nsIPluginStreamInfo> mStreamInfo;
+  nsRefPtr<nsPluginStreamListenerPeer> mStreamListenerPeer;
 };
 
 #endif // nsNPAPIPluginStreamListener_h_
--- a/dom/plugins/base/nsPluginHost.cpp
+++ b/dom/plugins/base/nsPluginHost.cpp
@@ -10,16 +10,18 @@
 
 #include <stdio.h>
 #include "prio.h"
 #include "prmem.h"
 #include "nsIComponentManager.h"
 #include "nsNPAPIPlugin.h"
 #include "nsNPAPIPluginStreamListener.h"
 #include "nsNPAPIPluginInstance.h"
+#include "nsPluginInstanceOwner.h"
+#include "nsObjectLoadingContent.h"
 #include "nsIHTTPHeaderListener.h"
 #include "nsIHttpHeaderVisitor.h"
 #include "nsIObserverService.h"
 #include "nsIHttpProtocolHandler.h"
 #include "nsIHttpChannel.h"
 #include "nsIHttpChannelInternal.h"
 #include "nsIUploadChannel.h"
 #include "nsIByteRangeRequest.h"
--- a/dom/plugins/base/nsPluginStreamListenerPeer.cpp
+++ b/dom/plugins/base/nsPluginStreamListenerPeer.cpp
@@ -22,16 +22,17 @@
 #include "nsPrintfCString.h"
 #include "nsIScriptGlobalObject.h"
 #include "nsIDocument.h"
 #include "nsIWebNavigation.h"
 #include "nsContentUtils.h"
 #include "nsNetUtil.h"
 #include "nsPluginNativeWindow.h"
 #include "sampler.h"
+#include "nsObjectLoadingContent.h"
 
 #define MAGIC_REQUEST_CONTEXT 0x01020304
 
 // nsPluginByteRangeStreamListener
 
 class nsPluginByteRangeStreamListener
   : public nsIStreamListener
   , public nsIInterfaceRequestor
@@ -259,23 +260,21 @@ public:
   nsHashKey *Clone() const {
     return new nsPRUintKey(mKey);
   }
   PRUint32 GetValue() { return mKey; }
 };
 
 // nsPluginStreamListenerPeer
 
-NS_IMPL_ISUPPORTS8(nsPluginStreamListenerPeer,
+NS_IMPL_ISUPPORTS6(nsPluginStreamListenerPeer,
                    nsIStreamListener,
                    nsIRequestObserver,
                    nsIHttpHeaderVisitor,
                    nsISupportsWeakReference,
-                   nsIPluginStreamInfo,
-                   nsINPAPIPluginStreamInfo,
                    nsIInterfaceRequestor,
                    nsIChannelEventSink)
 
 nsPluginStreamListenerPeer::nsPluginStreamListenerPeer()
 {
   mStreamType = NP_NORMAL;
   mStartBinding = false;
   mAbort = false;
@@ -630,46 +629,46 @@ NS_IMETHODIMP nsPluginStreamListenerPeer
 NS_IMETHODIMP nsPluginStreamListenerPeer::OnStatus(nsIRequest *request,
                                                    nsISupports* aContext,
                                                    nsresult aStatus,
                                                    const PRUnichar* aStatusArg)
 {
   return NS_OK;
 }
 
-NS_IMETHODIMP
+nsresult
 nsPluginStreamListenerPeer::GetContentType(char** result)
 {
   *result = const_cast<char*>(mContentType.get());
   return NS_OK;
 }
 
 
-NS_IMETHODIMP
+nsresult
 nsPluginStreamListenerPeer::IsSeekable(bool* result)
 {
   *result = mSeekable;
   return NS_OK;
 }
 
-NS_IMETHODIMP
+nsresult
 nsPluginStreamListenerPeer::GetLength(PRUint32* result)
 {
   *result = mLength;
   return NS_OK;
 }
 
-NS_IMETHODIMP
+nsresult
 nsPluginStreamListenerPeer::GetLastModified(PRUint32* result)
 {
   *result = mModified;
   return NS_OK;
 }
 
-NS_IMETHODIMP
+nsresult
 nsPluginStreamListenerPeer::GetURL(const char** result)
 {
   *result = mURLSpec.get();
   return NS_OK;
 }
 
 void
 nsPluginStreamListenerPeer::MakeByteRangeString(NPByteRange* aRangeList, nsACString &rangeRequest,
@@ -702,17 +701,17 @@ nsPluginStreamListenerPeer::MakeByteRang
   // get rid of possible trailing comma
   string.Trim(",", false);
   
   rangeRequest = string;
   *numRequests  = requestCnt;
   return;
 }
 
-NS_IMETHODIMP
+nsresult
 nsPluginStreamListenerPeer::RequestRead(NPByteRange* rangeList)
 {
   nsCAutoString rangeString;
   PRInt32 numRequests;
   
   MakeByteRangeString(rangeList, rangeString, &numRequests);
   
   if (numRequests == 0)
@@ -765,24 +764,24 @@ nsPluginStreamListenerPeer::RequestRead(
     return rv;
   
   rv = channel->AsyncOpen(converter, container);
   if (NS_SUCCEEDED(rv))
     TrackRequest(channel);
   return rv;
 }
 
-NS_IMETHODIMP
+nsresult
 nsPluginStreamListenerPeer::GetStreamOffset(PRInt32* result)
 {
   *result = mStreamOffset;
   return NS_OK;
 }
 
-NS_IMETHODIMP
+nsresult
 nsPluginStreamListenerPeer::SetStreamOffset(PRInt32 value)
 {
   mStreamOffset = value;
   return NS_OK;
 }
 
 nsresult nsPluginStreamListenerPeer::ServeStreamAsFile(nsIRequest *request,
                                                        nsISupports* aContext)
@@ -1284,38 +1283,38 @@ nsPluginStreamListenerPeer::GetInterface
 /**
  * Proxy class which forwards async redirect notifications back to the necko
  * callback, keeping nsPluginStreamListenerPeer::mRequests in sync with
  * which channel is active.
  */
 class ChannelRedirectProxyCallback : public nsIAsyncVerifyRedirectCallback
 {
 public:
-  ChannelRedirectProxyCallback(nsINPAPIPluginStreamInfo* listener,
+  ChannelRedirectProxyCallback(nsPluginStreamListenerPeer* listener,
                                nsIAsyncVerifyRedirectCallback* parent,
                                nsIChannel* oldChannel,
                                nsIChannel* newChannel)
-    : mWeakListener(do_GetWeakReference(listener))
+    : mWeakListener(do_GetWeakReference(static_cast<nsIStreamListener*>(listener)))
     , mParent(parent)
     , mOldChannel(oldChannel)
     , mNewChannel(newChannel)
   {
   }
 
   ChannelRedirectProxyCallback() {}
   virtual ~ChannelRedirectProxyCallback() {}
 
   NS_DECL_ISUPPORTS
 
   NS_IMETHODIMP OnRedirectVerifyCallback(nsresult result)
   {
     if (NS_SUCCEEDED(result)) {
-      nsCOMPtr<nsINPAPIPluginStreamInfo> listener = do_QueryReferent(mWeakListener);
+      nsCOMPtr<nsIStreamListener> listener = do_QueryReferent(mWeakListener);
       if (listener)
-        listener->ReplaceRequest(mOldChannel, mNewChannel);
+        static_cast<nsPluginStreamListenerPeer*>(listener.get())->ReplaceRequest(mOldChannel, mNewChannel);
     }
     return mParent->OnRedirectVerifyCallback(result);
   }
 
 private:
   nsWeakPtr mWeakListener;
   nsCOMPtr<nsIAsyncVerifyRedirectCallback> mParent;
   nsCOMPtr<nsIChannel> mOldChannel;
--- a/dom/plugins/base/nsPluginStreamListenerPeer.h
+++ b/dom/plugins/base/nsPluginStreamListenerPeer.h
@@ -12,19 +12,20 @@
 #include "nsIProgressEventSink.h"
 #include "nsIHttpHeaderVisitor.h"
 #include "nsWeakReference.h"
 #include "nsNPAPIPluginStreamListener.h"
 #include "nsHashtable.h"
 #include "nsNPAPIPluginInstance.h"
 #include "nsIInterfaceRequestor.h"
 #include "nsIChannelEventSink.h"
-#include "nsObjectLoadingContent.h"
+#include "nsIObjectLoadingContent.h"
 
 class nsIChannel;
+class nsObjectLoadingContent;
 
 /**
  * When a plugin requests opens multiple requests to the same URL and
  * the request must be satified by saving a file to disk, each stream
  * listener holds a reference to the backing file: the file is only removed
  * when all the listeners are done.
  */
 class CachedFileHolder
@@ -42,35 +43,31 @@ private:
   nsAutoRefCnt mRefCnt;
   nsCOMPtr<nsIFile> mFile;
 };
 
 class nsPluginStreamListenerPeer : public nsIStreamListener,
 public nsIProgressEventSink,
 public nsIHttpHeaderVisitor,
 public nsSupportsWeakReference,
-public nsINPAPIPluginStreamInfo,
 public nsIInterfaceRequestor,
 public nsIChannelEventSink
 {
 public:
   nsPluginStreamListenerPeer();
   virtual ~nsPluginStreamListenerPeer();
   
   NS_DECL_ISUPPORTS
   NS_DECL_NSIPROGRESSEVENTSINK
   NS_DECL_NSIREQUESTOBSERVER
   NS_DECL_NSISTREAMLISTENER
   NS_DECL_NSIHTTPHEADERVISITOR
   NS_DECL_NSIINTERFACEREQUESTOR
   NS_DECL_NSICHANNELEVENTSINK
 
-  // nsINPAPIPluginStreamInfo interface
-  NS_DECL_NSIPLUGINSTREAMINFO
-  
   // Called by RequestRead
   void
   MakeByteRangeString(NPByteRange* aRangeList, nsACString &string, PRInt32 *numRequests);
   
   bool UseExistingPluginCacheFile(nsPluginStreamListenerPeer* psi);
   
   // Called by GetURL and PostURL (via NewStream)
   nsresult Initialize(nsIURI *aURL,
@@ -84,16 +81,63 @@ public:
   nsresult InitializeFullPage(nsIURI* aURL, nsNPAPIPluginInstance *aInstance);
 
   nsresult OnFileAvailable(nsIFile* aFile);
   
   nsresult ServeStreamAsFile(nsIRequest *request, nsISupports *ctxt);
   
   nsNPAPIPluginInstance *GetPluginInstance() { return mPluginInstance; }
   
+  nsresult RequestRead(NPByteRange* rangeList);
+  nsresult GetLength(PRUint32* result);
+  nsresult GetURL(const char** result);
+  nsresult GetLastModified(PRUint32* result);
+  nsresult IsSeekable(bool* result);
+  nsresult GetContentType(char** result);
+  nsresult GetStreamOffset(PRInt32* result);
+  nsresult SetStreamOffset(PRInt32 value);
+
+  void TrackRequest(nsIRequest* request)
+  {
+    mRequests.AppendObject(request);
+  }
+
+  void ReplaceRequest(nsIRequest* oldRequest, nsIRequest* newRequest)
+  {
+    PRInt32 i = mRequests.IndexOfObject(oldRequest);
+    if (i == -1) {
+      NS_ASSERTION(mRequests.Count() == 0,
+                   "Only our initial stream should be unknown!");
+      mRequests.AppendObject(oldRequest);
+    }
+    else {
+      mRequests.ReplaceObjectAt(newRequest, i);
+    }
+  }
+  
+  void CancelRequests(nsresult status)
+  {
+    // Copy the array to avoid modification during the loop.
+    nsCOMArray<nsIRequest> requestsCopy(mRequests);
+    for (PRInt32 i = 0; i < requestsCopy.Count(); ++i)
+      requestsCopy[i]->Cancel(status);
+  }
+
+  void SuspendRequests() {
+    nsCOMArray<nsIRequest> requestsCopy(mRequests);
+    for (PRInt32 i = 0; i < requestsCopy.Count(); ++i)
+      requestsCopy[i]->Suspend();
+  }
+
+  void ResumeRequests() {
+    nsCOMArray<nsIRequest> requestsCopy(mRequests);
+    for (PRInt32 i = 0; i < requestsCopy.Count(); ++i)
+      requestsCopy[i]->Resume();
+  }
+
 private:
   nsresult SetUpStreamListener(nsIRequest* request, nsIURI* aURL);
   nsresult SetupPluginCacheFile(nsIChannel* channel);
   nsresult GetInterfaceGlobal(const nsIID& aIID, void** result);
 
   nsCOMPtr<nsIURI> mURL;
   nsCString mURLSpec; // Have to keep this member because GetURL hands out char*
   nsCOMPtr<nsIObjectLoadingContent> mContent;
@@ -127,11 +171,12 @@ private:
   PRInt32 mStreamOffset;
   bool mStreamComplete;
   
 public:
   bool                    mAbort;
   PRInt32                 mPendingRequests;
   nsWeakPtr               mWeakPtrChannelCallbacks;
   nsWeakPtr               mWeakPtrChannelLoadGroup;
+  nsCOMArray<nsIRequest> mRequests;
 };
 
 #endif // nsPluginStreamListenerPeer_h_