|
@@ -0,0 +1,1369 @@
|
|
|
+# HG changeset patch
|
|
|
+# User Benjamin Smedberg <benjamin@smedbergs.us>
|
|
|
+# Date 1506973895 25200
|
|
|
+# Node ID 3eca597f346fda5899c7da9237b1b35327b312d0
|
|
|
+# Parent 0b77cf4789d4d197b0040056696dcfaefb103b51
|
|
|
+Bug 1352567 - Remove NPAPI seekable and file streams from the dom/plugins/base code, r=jimm
|
|
|
+
|
|
|
+MozReview-Commit-ID: 4qxEFjTKMVZ
|
|
|
+
|
|
|
+diff --git a/dom/plugins/base/nsNPAPIPlugin.cpp b/dom/plugins/base/nsNPAPIPlugin.cpp
|
|
|
+--- a/dom/plugins/base/nsNPAPIPlugin.cpp
|
|
|
++++ b/dom/plugins/base/nsNPAPIPlugin.cpp
|
|
|
+@@ -1705,56 +1705,17 @@ NPError
|
|
|
+ default:
|
|
|
+ return NPERR_GENERIC_ERROR;
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ NPError
|
|
|
+ _requestread(NPStream *pstream, NPByteRange *rangeList)
|
|
|
+ {
|
|
|
+- if (!NS_IsMainThread()) {
|
|
|
+- NPN_PLUGIN_LOG(PLUGIN_LOG_ALWAYS,("NPN_requestread called from the wrong thread\n"));
|
|
|
+- return NPERR_INVALID_PARAM;
|
|
|
+- }
|
|
|
+- NPN_PLUGIN_LOG(PLUGIN_LOG_NORMAL, ("NPN_RequestRead: stream=%p\n",
|
|
|
+- (void*)pstream));
|
|
|
+-
|
|
|
+-#ifdef PLUGIN_LOGGING
|
|
|
+- for(NPByteRange * range = rangeList; range != nullptr; range = range->next)
|
|
|
+- MOZ_LOG(nsPluginLogging::gNPNLog,PLUGIN_LOG_NOISY,
|
|
|
+- ("%i-%i", range->offset, range->offset + range->length - 1));
|
|
|
+-
|
|
|
+- MOZ_LOG(nsPluginLogging::gNPNLog,PLUGIN_LOG_NOISY, ("\n\n"));
|
|
|
+- PR_LogFlush();
|
|
|
+-#endif
|
|
|
+-
|
|
|
+- if (!pstream || !rangeList || !pstream->ndata)
|
|
|
+- return NPERR_INVALID_PARAM;
|
|
|
+-
|
|
|
+- nsNPAPIStreamWrapper* streamWrapper = static_cast<nsNPAPIStreamWrapper*>(pstream->ndata);
|
|
|
+- nsNPAPIPluginStreamListener* streamlistener = streamWrapper->GetStreamListener();
|
|
|
+- if (!streamlistener) {
|
|
|
+- return NPERR_GENERIC_ERROR;
|
|
|
+- }
|
|
|
+-
|
|
|
+- int32_t streamtype = NP_NORMAL;
|
|
|
+-
|
|
|
+- streamlistener->GetStreamType(&streamtype);
|
|
|
+-
|
|
|
+- if (streamtype != NP_SEEK)
|
|
|
+- return NPERR_STREAM_NOT_SEEKABLE;
|
|
|
+-
|
|
|
+- if (!streamlistener->mStreamListenerPeer)
|
|
|
+- return NPERR_GENERIC_ERROR;
|
|
|
+-
|
|
|
+- nsresult rv = streamlistener->mStreamListenerPeer->RequestRead((NPByteRange *)rangeList);
|
|
|
+- if (NS_FAILED(rv))
|
|
|
+- return NPERR_GENERIC_ERROR;
|
|
|
+-
|
|
|
+- return NPERR_NO_ERROR;
|
|
|
++ return NPERR_STREAM_NOT_SEEKABLE;
|
|
|
+ }
|
|
|
+
|
|
|
+ // Deprecated, only stubbed out
|
|
|
+ void* /* OJI type: JRIEnv* */
|
|
|
+ _getJavaEnv()
|
|
|
+ {
|
|
|
+ NPN_PLUGIN_LOG(PLUGIN_LOG_NORMAL, ("NPN_GetJavaEnv\n"));
|
|
|
+ return nullptr;
|
|
|
+diff --git a/dom/plugins/base/nsNPAPIPluginStreamListener.cpp b/dom/plugins/base/nsNPAPIPluginStreamListener.cpp
|
|
|
+--- a/dom/plugins/base/nsNPAPIPluginStreamListener.cpp
|
|
|
++++ b/dom/plugins/base/nsNPAPIPluginStreamListener.cpp
|
|
|
+@@ -41,17 +41,16 @@ NS_IMPL_ISUPPORTS(nsNPAPIPluginStreamLis
|
|
|
+ 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)
|
|
|
+ , mStreamState(eStreamStopped)
|
|
|
+ , mStreamCleanedUp(false)
|
|
|
+ , mCallNotify(notifyData ? true : false)
|
|
|
+ , mIsSuspended(false)
|
|
|
+ , mIsPluginInitJSStream(mInst->mInPluginInitCall &&
|
|
|
+ aURL && strncmp(aURL, "javascript:",
|
|
|
+ sizeof("javascript:") - 1) == 0)
|
|
|
+ , mRedirectDenied(false)
|
|
|
+@@ -110,21 +109,16 @@ nsNPAPIPluginStreamListener::CleanUpStre
|
|
|
+ StopDataPump();
|
|
|
+
|
|
|
+ // 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 && mStreamState == eStreamTypeSet)
|
|
|
+- NS_RELEASE_THIS();
|
|
|
+-
|
|
|
+ if (mStreamListenerPeer) {
|
|
|
+ mStreamListenerPeer->CancelRequests(NS_BINDING_ABORTED);
|
|
|
+ mStreamListenerPeer = nullptr;
|
|
|
+ }
|
|
|
+
|
|
|
+ if (!mInst || !mInst->CanFireNotifications())
|
|
|
+ return rv;
|
|
|
+
|
|
|
+@@ -207,98 +201,53 @@ nsNPAPIPluginStreamListener::OnStartBind
|
|
|
+ NPPluginFuncs* pluginFunctions = plugin->PluginFuncs();
|
|
|
+
|
|
|
+ if (!pluginFunctions->newstream)
|
|
|
+ return NS_ERROR_FAILURE;
|
|
|
+
|
|
|
+ NPP npp;
|
|
|
+ mInst->GetNPP(&npp);
|
|
|
+
|
|
|
+- bool seekable;
|
|
|
+ char* contentType;
|
|
|
+ uint16_t streamType = NP_NORMAL;
|
|
|
+ NPError error;
|
|
|
+
|
|
|
+ streamPeer->GetURL(&mNPStreamWrapper->mNPStream.url);
|
|
|
+ streamPeer->GetLength((uint32_t*)&(mNPStreamWrapper->mNPStream.end));
|
|
|
+ streamPeer->GetLastModified((uint32_t*)&(mNPStreamWrapper->mNPStream.lastmodified));
|
|
|
+- streamPeer->IsSeekable(&seekable);
|
|
|
+ streamPeer->GetContentType(&contentType);
|
|
|
+
|
|
|
+ if (!mResponseHeaders.IsEmpty()) {
|
|
|
+ mResponseHeaderBuf = PL_strdup(mResponseHeaders.get());
|
|
|
+ mNPStreamWrapper->mNPStream.headers = mResponseHeaderBuf;
|
|
|
+ }
|
|
|
+
|
|
|
+ mStreamListenerPeer = streamPeer;
|
|
|
+
|
|
|
+ NPPAutoPusher nppPusher(npp);
|
|
|
+
|
|
|
+- NS_TRY_SAFE_CALL_RETURN(error, (*pluginFunctions->newstream)(npp, (char*)contentType, &mNPStreamWrapper->mNPStream, seekable, &streamType), mInst,
|
|
|
++ NS_TRY_SAFE_CALL_RETURN(error, (*pluginFunctions->newstream)(npp, (char*)contentType, &mNPStreamWrapper->mNPStream, false, &streamType), mInst,
|
|
|
+ NS_PLUGIN_CALL_UNSAFE_TO_REENTER_GECKO);
|
|
|
+
|
|
|
+ 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));
|
|
|
++ this, npp, (char *)contentType, false, streamType, error, mNPStreamWrapper->mNPStream.url));
|
|
|
+
|
|
|
+ if (error != NPERR_NO_ERROR)
|
|
|
+ return NS_ERROR_FAILURE;
|
|
|
+
|
|
|
+ mStreamState = eNewStreamCalled;
|
|
|
+
|
|
|
+- if (!SetStreamType(streamType, false)) {
|
|
|
++ if (streamType != NP_NORMAL) {
|
|
|
+ return NS_ERROR_FAILURE;
|
|
|
+ }
|
|
|
+
|
|
|
+ return NS_OK;
|
|
|
+ }
|
|
|
+
|
|
|
+-bool
|
|
|
+-nsNPAPIPluginStreamListener::SetStreamType(uint16_t aType, bool aNeedsResume)
|
|
|
+-{
|
|
|
+- switch(aType)
|
|
|
+- {
|
|
|
+- case NP_NORMAL:
|
|
|
+- mStreamType = NP_NORMAL;
|
|
|
+- break;
|
|
|
+- case NP_ASFILEONLY:
|
|
|
+- mStreamType = NP_ASFILEONLY;
|
|
|
+- break;
|
|
|
+- case NP_ASFILE:
|
|
|
+- mStreamType = NP_ASFILE;
|
|
|
+- break;
|
|
|
+- case NP_SEEK:
|
|
|
+- mStreamType = NP_SEEK;
|
|
|
+- // Seekable streams should continue to exist even after OnStopRequest
|
|
|
+- // is fired, so we AddRef ourself an extra time and Release when the
|
|
|
+- // 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;
|
|
|
+- case nsPluginStreamListenerPeer::STREAM_TYPE_UNKNOWN:
|
|
|
+- MOZ_ASSERT(!aNeedsResume);
|
|
|
+- mStreamType = nsPluginStreamListenerPeer::STREAM_TYPE_UNKNOWN;
|
|
|
+- SuspendRequest();
|
|
|
+- mStreamStopMode = eDoDeferredStop;
|
|
|
+- // In this case we do not want to execute anything else in this function.
|
|
|
+- return true;
|
|
|
+- default:
|
|
|
+- return false;
|
|
|
+- }
|
|
|
+- mStreamState = eStreamTypeSet;
|
|
|
+- if (aNeedsResume) {
|
|
|
+- if (mStreamListenerPeer) {
|
|
|
+- mStreamListenerPeer->OnStreamTypeSet(mStreamType);
|
|
|
+- }
|
|
|
+- ResumeRequest();
|
|
|
+- }
|
|
|
+- return true;
|
|
|
+-}
|
|
|
+-
|
|
|
+ void
|
|
|
+ nsNPAPIPluginStreamListener::SuspendRequest()
|
|
|
+ {
|
|
|
+ NS_ASSERTION(!mIsSuspended,
|
|
|
+ "Suspending a request that's already suspended!");
|
|
|
+
|
|
|
+ nsresult rv = StartDataPump();
|
|
|
+ if (NS_FAILED(rv))
|
|
|
+@@ -704,35 +653,17 @@ nsNPAPIPluginStreamListener::OnStopBindi
|
|
|
+
|
|
|
+ NPReason reason = NS_FAILED(status) ? NPRES_NETWORK_ERR : NPRES_DONE;
|
|
|
+ if (mRedirectDenied || status == NS_BINDING_ABORTED) {
|
|
|
+ reason = NPRES_USER_BREAK;
|
|
|
+ }
|
|
|
+
|
|
|
+ // The following code can result in the deletion of 'this'. Don't
|
|
|
+ // assume we are alive after this!
|
|
|
+- //
|
|
|
+- // Delay cleanup if the stream is of type NP_SEEK and status isn't
|
|
|
+- // NS_BINDING_ABORTED (meaning the plugin hasn't called NPN_DestroyStream).
|
|
|
+- // This is because even though we're done delivering data the plugin may
|
|
|
+- // want to seek. Eventually either the plugin will call NPN_DestroyStream
|
|
|
+- // or we'll perform cleanup when the instance goes away. See bug 91140.
|
|
|
+- if (mStreamType != NP_SEEK ||
|
|
|
+- (NP_SEEK == mStreamType && NS_BINDING_ABORTED == status)) {
|
|
|
+- return CleanUpStream(reason);
|
|
|
+- }
|
|
|
+-
|
|
|
+- return NS_OK;
|
|
|
+-}
|
|
|
+-
|
|
|
+-nsresult
|
|
|
+-nsNPAPIPluginStreamListener::GetStreamType(int32_t *result)
|
|
|
+-{
|
|
|
+- *result = mStreamType;
|
|
|
+- return NS_OK;
|
|
|
++ return CleanUpStream(reason);
|
|
|
+ }
|
|
|
+
|
|
|
+ bool
|
|
|
+ nsNPAPIPluginStreamListener::MaybeRunStopBinding()
|
|
|
+ {
|
|
|
+ if (mIsSuspended || mStreamStopMode != eStopPending) {
|
|
|
+ return false;
|
|
|
+ }
|
|
|
+diff --git a/dom/plugins/base/nsNPAPIPluginStreamListener.h b/dom/plugins/base/nsNPAPIPluginStreamListener.h
|
|
|
+--- a/dom/plugins/base/nsNPAPIPluginStreamListener.h
|
|
|
++++ b/dom/plugins/base/nsNPAPIPluginStreamListener.h
|
|
|
+@@ -60,18 +60,16 @@ public:
|
|
|
+ nsresult OnStartBinding(nsPluginStreamListenerPeer* streamPeer);
|
|
|
+ nsresult OnDataAvailable(nsPluginStreamListenerPeer* streamPeer,
|
|
|
+ nsIInputStream* input,
|
|
|
+ uint32_t length);
|
|
|
+ nsresult OnFileAvailable(nsPluginStreamListenerPeer* streamPeer,
|
|
|
+ const char* fileName);
|
|
|
+ nsresult OnStopBinding(nsPluginStreamListenerPeer* streamPeer,
|
|
|
+ nsresult status);
|
|
|
+- nsresult GetStreamType(int32_t *result);
|
|
|
+- bool SetStreamType(uint16_t aType, bool aNeedsResume = true);
|
|
|
+
|
|
|
+ bool IsStarted();
|
|
|
+ nsresult CleanUpStream(NPReason reason);
|
|
|
+ void CallURLNotify(NPReason reason);
|
|
|
+ void SetCallNotify(bool aCallNotify) { mCallNotify = aCallNotify; }
|
|
|
+ void SuspendRequest();
|
|
|
+ void ResumeRequest();
|
|
|
+ nsresult StartDataPump();
|
|
|
+@@ -107,17 +105,16 @@ protected:
|
|
|
+ bool MaybeRunStopBinding();
|
|
|
+
|
|
|
+ char* mStreamBuffer;
|
|
|
+ char* mNotifyURL;
|
|
|
+ RefPtr<nsNPAPIPluginInstance> mInst;
|
|
|
+ nsNPAPIStreamWrapper *mNPStreamWrapper;
|
|
|
+ uint32_t mStreamBufferSize;
|
|
|
+ int32_t mStreamBufferByteCount;
|
|
|
+- int32_t mStreamType;
|
|
|
+ StreamState mStreamState;
|
|
|
+ bool mStreamCleanedUp;
|
|
|
+ bool mCallNotify;
|
|
|
+ bool mIsSuspended;
|
|
|
+ bool mIsPluginInitJSStream;
|
|
|
+ bool mRedirectDenied;
|
|
|
+ nsCString mResponseHeaders;
|
|
|
+ char* mResponseHeaderBuf;
|
|
|
+diff --git a/dom/plugins/base/nsPluginStreamListenerPeer.cpp b/dom/plugins/base/nsPluginStreamListenerPeer.cpp
|
|
|
+--- a/dom/plugins/base/nsPluginStreamListenerPeer.cpp
|
|
|
++++ b/dom/plugins/base/nsPluginStreamListenerPeer.cpp
|
|
|
+@@ -15,297 +15,65 @@
|
|
|
+ #include "nsMimeTypes.h"
|
|
|
+ #include "nsISupportsPrimitives.h"
|
|
|
+ #include "nsNetCID.h"
|
|
|
+ #include "nsPluginInstanceOwner.h"
|
|
|
+ #include "nsPluginLogging.h"
|
|
|
+ #include "nsIURI.h"
|
|
|
+ #include "nsIURL.h"
|
|
|
+ #include "nsPluginHost.h"
|
|
|
+-#include "nsIByteRangeRequest.h"
|
|
|
+ #include "nsIMultiPartChannel.h"
|
|
|
+ #include "nsIInputStreamTee.h"
|
|
|
+ #include "nsPrintfCString.h"
|
|
|
+ #include "nsIScriptGlobalObject.h"
|
|
|
+ #include "nsIDocument.h"
|
|
|
+ #include "nsIWebNavigation.h"
|
|
|
+ #include "nsContentUtils.h"
|
|
|
+ #include "nsNetUtil.h"
|
|
|
+ #include "nsPluginNativeWindow.h"
|
|
|
+ #include "GeckoProfiler.h"
|
|
|
+ #include "nsPluginInstanceOwner.h"
|
|
|
+ #include "nsDataHashtable.h"
|
|
|
+ #include "NullPrincipal.h"
|
|
|
+
|
|
|
+-#define BYTERANGE_REQUEST_CONTEXT 0x01020304
|
|
|
+-
|
|
|
+-// nsPluginByteRangeStreamListener
|
|
|
+-
|
|
|
+-class nsPluginByteRangeStreamListener
|
|
|
+- : public nsIStreamListener
|
|
|
+- , public nsIInterfaceRequestor
|
|
|
+-{
|
|
|
+-public:
|
|
|
+- explicit nsPluginByteRangeStreamListener(nsIWeakReference* aWeakPtr);
|
|
|
+-
|
|
|
+- NS_DECL_ISUPPORTS
|
|
|
+- NS_DECL_NSIREQUESTOBSERVER
|
|
|
+- NS_DECL_NSISTREAMLISTENER
|
|
|
+- NS_DECL_NSIINTERFACEREQUESTOR
|
|
|
+-
|
|
|
+-private:
|
|
|
+- virtual ~nsPluginByteRangeStreamListener();
|
|
|
+-
|
|
|
+- nsCOMPtr<nsIStreamListener> mStreamConverter;
|
|
|
+- nsWeakPtr mWeakPtrPluginStreamListenerPeer;
|
|
|
+- bool mRemoveByteRangeRequest;
|
|
|
+-};
|
|
|
+-
|
|
|
+-NS_IMPL_ISUPPORTS(nsPluginByteRangeStreamListener,
|
|
|
+- nsIRequestObserver,
|
|
|
+- nsIStreamListener,
|
|
|
+- nsIInterfaceRequestor)
|
|
|
+-
|
|
|
+-nsPluginByteRangeStreamListener::nsPluginByteRangeStreamListener(nsIWeakReference* aWeakPtr)
|
|
|
+-{
|
|
|
+- mWeakPtrPluginStreamListenerPeer = aWeakPtr;
|
|
|
+- mRemoveByteRangeRequest = false;
|
|
|
+-}
|
|
|
+-
|
|
|
+-nsPluginByteRangeStreamListener::~nsPluginByteRangeStreamListener()
|
|
|
+-{
|
|
|
+- mStreamConverter = nullptr;
|
|
|
+- mWeakPtrPluginStreamListenerPeer = nullptr;
|
|
|
+-}
|
|
|
+-
|
|
|
+-/**
|
|
|
+- * Unwrap any byte-range requests so that we can check whether the base channel
|
|
|
+- * is being tracked properly.
|
|
|
+- */
|
|
|
+-static nsCOMPtr<nsIRequest>
|
|
|
+-GetBaseRequest(nsIRequest* r)
|
|
|
+-{
|
|
|
+- nsCOMPtr<nsIMultiPartChannel> mp = do_QueryInterface(r);
|
|
|
+- if (!mp)
|
|
|
+- return r;
|
|
|
+-
|
|
|
+- nsCOMPtr<nsIChannel> base;
|
|
|
+- mp->GetBaseChannel(getter_AddRefs(base));
|
|
|
+- return already_AddRefed<nsIRequest>(base.forget());
|
|
|
+-}
|
|
|
+-
|
|
|
+-NS_IMETHODIMP
|
|
|
+-nsPluginByteRangeStreamListener::OnStartRequest(nsIRequest *request, nsISupports *ctxt)
|
|
|
+-{
|
|
|
+- nsresult rv;
|
|
|
+-
|
|
|
+- nsCOMPtr<nsIStreamListener> finalStreamListener = do_QueryReferent(mWeakPtrPluginStreamListenerPeer);
|
|
|
+- if (!finalStreamListener)
|
|
|
+- return NS_ERROR_FAILURE;
|
|
|
+-
|
|
|
+- nsPluginStreamListenerPeer *pslp =
|
|
|
+- static_cast<nsPluginStreamListenerPeer*>(finalStreamListener.get());
|
|
|
+-
|
|
|
+-#ifdef DEBUG
|
|
|
+- nsCOMPtr<nsIRequest> baseRequest = GetBaseRequest(request);
|
|
|
+-#endif
|
|
|
+- NS_ASSERTION(pslp->mRequests.IndexOfObject(baseRequest) != -1,
|
|
|
+- "Untracked byte-range request?");
|
|
|
+-
|
|
|
+- nsCOMPtr<nsIStreamConverterService> serv = do_GetService(NS_STREAMCONVERTERSERVICE_CONTRACTID, &rv);
|
|
|
+- if (NS_SUCCEEDED(rv)) {
|
|
|
+- rv = serv->AsyncConvertData(MULTIPART_BYTERANGES,
|
|
|
+- "*/*",
|
|
|
+- finalStreamListener,
|
|
|
+- nullptr,
|
|
|
+- getter_AddRefs(mStreamConverter));
|
|
|
+- if (NS_SUCCEEDED(rv)) {
|
|
|
+- rv = mStreamConverter->OnStartRequest(request, ctxt);
|
|
|
+- if (NS_SUCCEEDED(rv))
|
|
|
+- return rv;
|
|
|
+- }
|
|
|
+- }
|
|
|
+- mStreamConverter = nullptr;
|
|
|
+-
|
|
|
+- nsCOMPtr<nsIHttpChannel> httpChannel(do_QueryInterface(request));
|
|
|
+- if (!httpChannel) {
|
|
|
+- return NS_ERROR_FAILURE;
|
|
|
+- }
|
|
|
+-
|
|
|
+- uint32_t responseCode = 0;
|
|
|
+- rv = httpChannel->GetResponseStatus(&responseCode);
|
|
|
+- if (NS_FAILED(rv)) {
|
|
|
+- return NS_ERROR_FAILURE;
|
|
|
+- }
|
|
|
+-
|
|
|
+- if (responseCode != 200) {
|
|
|
+- uint32_t wantsAllNetworkStreams = 0;
|
|
|
+- rv = pslp->GetPluginInstance()->GetValueFromPlugin(NPPVpluginWantsAllNetworkStreams,
|
|
|
+- &wantsAllNetworkStreams);
|
|
|
+- // If the call returned an error code make sure we still use our default value.
|
|
|
+- if (NS_FAILED(rv)) {
|
|
|
+- wantsAllNetworkStreams = 0;
|
|
|
+- }
|
|
|
+-
|
|
|
+- if (!wantsAllNetworkStreams){
|
|
|
+- return NS_ERROR_FAILURE;
|
|
|
+- }
|
|
|
+- }
|
|
|
+-
|
|
|
+- // if server cannot continue with byte range (206 status) and sending us whole object (200 status)
|
|
|
+- // reset this seekable stream & try serve it to plugin instance as a file
|
|
|
+- mStreamConverter = finalStreamListener;
|
|
|
+- mRemoveByteRangeRequest = true;
|
|
|
+-
|
|
|
+- rv = pslp->ServeStreamAsFile(request, ctxt);
|
|
|
+- return rv;
|
|
|
+-}
|
|
|
+-
|
|
|
+-NS_IMETHODIMP
|
|
|
+-nsPluginByteRangeStreamListener::OnStopRequest(nsIRequest *request, nsISupports *ctxt,
|
|
|
+- nsresult status)
|
|
|
+-{
|
|
|
+- if (!mStreamConverter)
|
|
|
+- return NS_ERROR_FAILURE;
|
|
|
+-
|
|
|
+- nsCOMPtr<nsIStreamListener> finalStreamListener = do_QueryReferent(mWeakPtrPluginStreamListenerPeer);
|
|
|
+- if (!finalStreamListener)
|
|
|
+- return NS_ERROR_FAILURE;
|
|
|
+-
|
|
|
+- nsPluginStreamListenerPeer *pslp =
|
|
|
+- static_cast<nsPluginStreamListenerPeer*>(finalStreamListener.get());
|
|
|
+- bool found = pslp->mRequests.RemoveObject(request);
|
|
|
+- if (!found) {
|
|
|
+- NS_ERROR("OnStopRequest received for untracked byte-range request!");
|
|
|
+- }
|
|
|
+-
|
|
|
+- if (mRemoveByteRangeRequest) {
|
|
|
+- // remove byte range request from container
|
|
|
+- nsCOMPtr<nsISupportsPRUint32> container = do_QueryInterface(ctxt);
|
|
|
+- if (container) {
|
|
|
+- uint32_t byteRangeRequest = 0;
|
|
|
+- container->GetData(&byteRangeRequest);
|
|
|
+- if (byteRangeRequest == BYTERANGE_REQUEST_CONTEXT) {
|
|
|
+- // to allow properly finish nsPluginStreamListenerPeer->OnStopRequest()
|
|
|
+- // set it to something that is not the byte range request.
|
|
|
+- container->SetData(0);
|
|
|
+- }
|
|
|
+- } else {
|
|
|
+- NS_WARNING("Bad state of nsPluginByteRangeStreamListener");
|
|
|
+- }
|
|
|
+- }
|
|
|
+-
|
|
|
+- return mStreamConverter->OnStopRequest(request, ctxt, status);
|
|
|
+-}
|
|
|
+-
|
|
|
+-// CachedFileHolder
|
|
|
+-
|
|
|
+-CachedFileHolder::CachedFileHolder(nsIFile* cacheFile)
|
|
|
+-: mFile(cacheFile)
|
|
|
+-{
|
|
|
+- NS_ASSERTION(mFile, "Empty CachedFileHolder");
|
|
|
+-}
|
|
|
+-
|
|
|
+-CachedFileHolder::~CachedFileHolder()
|
|
|
+-{
|
|
|
+- mFile->Remove(false);
|
|
|
+-}
|
|
|
+-
|
|
|
+-void
|
|
|
+-CachedFileHolder::AddRef()
|
|
|
+-{
|
|
|
+- ++mRefCnt;
|
|
|
+- NS_LOG_ADDREF(this, mRefCnt, "CachedFileHolder", sizeof(*this));
|
|
|
+-}
|
|
|
+-
|
|
|
+-void
|
|
|
+-CachedFileHolder::Release()
|
|
|
+-{
|
|
|
+- --mRefCnt;
|
|
|
+- NS_LOG_RELEASE(this, mRefCnt, "CachedFileHolder");
|
|
|
+- if (0 == mRefCnt)
|
|
|
+- delete this;
|
|
|
+-}
|
|
|
+-
|
|
|
+-
|
|
|
+-NS_IMETHODIMP
|
|
|
+-nsPluginByteRangeStreamListener::OnDataAvailable(nsIRequest *request, nsISupports *ctxt,
|
|
|
+- nsIInputStream *inStr,
|
|
|
+- uint64_t sourceOffset,
|
|
|
+- uint32_t count)
|
|
|
+-{
|
|
|
+- if (!mStreamConverter)
|
|
|
+- return NS_ERROR_FAILURE;
|
|
|
+-
|
|
|
+- nsCOMPtr<nsIStreamListener> finalStreamListener = do_QueryReferent(mWeakPtrPluginStreamListenerPeer);
|
|
|
+- if (!finalStreamListener)
|
|
|
+- return NS_ERROR_FAILURE;
|
|
|
+-
|
|
|
+- return mStreamConverter->OnDataAvailable(request, ctxt, inStr, sourceOffset, count);
|
|
|
+-}
|
|
|
+-
|
|
|
+-NS_IMETHODIMP
|
|
|
+-nsPluginByteRangeStreamListener::GetInterface(const nsIID& aIID, void** result)
|
|
|
+-{
|
|
|
+- // Forward interface requests to our parent
|
|
|
+- nsCOMPtr<nsIInterfaceRequestor> finalStreamListener = do_QueryReferent(mWeakPtrPluginStreamListenerPeer);
|
|
|
+- if (!finalStreamListener)
|
|
|
+- return NS_ERROR_FAILURE;
|
|
|
+-
|
|
|
+- return finalStreamListener->GetInterface(aIID, result);
|
|
|
+-}
|
|
|
+-
|
|
|
+ // nsPluginStreamListenerPeer
|
|
|
+
|
|
|
+ NS_IMPL_ISUPPORTS(nsPluginStreamListenerPeer,
|
|
|
+ nsIStreamListener,
|
|
|
+ nsIRequestObserver,
|
|
|
+ nsIHttpHeaderVisitor,
|
|
|
+ nsISupportsWeakReference,
|
|
|
+ nsIInterfaceRequestor,
|
|
|
+ nsIChannelEventSink)
|
|
|
+
|
|
|
+ nsPluginStreamListenerPeer::nsPluginStreamListenerPeer()
|
|
|
+ {
|
|
|
+ mStreamType = NP_NORMAL;
|
|
|
+ mStartBinding = false;
|
|
|
+- mAbort = false;
|
|
|
+ mRequestFailed = false;
|
|
|
+
|
|
|
+ mPendingRequests = 0;
|
|
|
+ mHaveFiredOnStartRequest = false;
|
|
|
+- mDataForwardToRequest = nullptr;
|
|
|
+
|
|
|
+ mUseLocalCache = false;
|
|
|
+- mSeekable = false;
|
|
|
+ mModified = 0;
|
|
|
+ mStreamOffset = 0;
|
|
|
+ mStreamComplete = 0;
|
|
|
+ }
|
|
|
+
|
|
|
+ nsPluginStreamListenerPeer::~nsPluginStreamListenerPeer()
|
|
|
+ {
|
|
|
+ #ifdef PLUGIN_LOGGING
|
|
|
+ MOZ_LOG(nsPluginLogging::gPluginLog, PLUGIN_LOG_NORMAL,
|
|
|
+ ("nsPluginStreamListenerPeer::dtor this=%p, url=%s\n",this, mURLSpec.get()));
|
|
|
+ #endif
|
|
|
+
|
|
|
+ if (mPStreamListener) {
|
|
|
+ mPStreamListener->SetStreamListenerPeer(nullptr);
|
|
|
+ }
|
|
|
+-
|
|
|
+- // close FD of mFileCacheOutputStream if it's still open
|
|
|
+- // or we won't be able to remove the cache file
|
|
|
+- if (mFileCacheOutputStream)
|
|
|
+- mFileCacheOutputStream = nullptr;
|
|
|
+-
|
|
|
+- delete mDataForwardToRequest;
|
|
|
+-
|
|
|
+- if (mPluginInstance)
|
|
|
+- mPluginInstance->FileCachedStreamListeners()->RemoveElement(this);
|
|
|
+ }
|
|
|
+
|
|
|
+ // Called as a result of GetURL and PostURL, or by the host in the case of the
|
|
|
+ // initial plugin stream.
|
|
|
+ nsresult nsPluginStreamListenerPeer::Initialize(nsIURI *aURL,
|
|
|
+ nsNPAPIPluginInstance *aInstance,
|
|
|
+ nsNPAPIPluginStreamListener* aListener)
|
|
|
+ {
|
|
|
+@@ -333,110 +101,27 @@ nsresult nsPluginStreamListenerPeer::Ini
|
|
|
+ // SetUpStreamListener
|
|
|
+ if (aListener) {
|
|
|
+ mPStreamListener = aListener;
|
|
|
+ mPStreamListener->SetStreamListenerPeer(this);
|
|
|
+ }
|
|
|
+
|
|
|
+ mPendingRequests = 1;
|
|
|
+
|
|
|
+- mDataForwardToRequest = new nsDataHashtable<nsUint32HashKey, uint32_t>();
|
|
|
+-
|
|
|
+ return NS_OK;
|
|
|
+ }
|
|
|
+
|
|
|
+-// SetupPluginCacheFile is called if we have to save the stream to disk.
|
|
|
+-//
|
|
|
+-// These files will be deleted when the host is destroyed.
|
|
|
+-//
|
|
|
+-// TODO? What if we fill up the the dest dir?
|
|
|
+-nsresult
|
|
|
+-nsPluginStreamListenerPeer::SetupPluginCacheFile(nsIChannel* channel)
|
|
|
+-{
|
|
|
+- nsresult rv = NS_OK;
|
|
|
+-
|
|
|
+- bool useExistingCacheFile = false;
|
|
|
+- RefPtr<nsPluginHost> pluginHost = nsPluginHost::GetInst();
|
|
|
+-
|
|
|
+- // Look for an existing cache file for the URI.
|
|
|
+- nsTArray< RefPtr<nsNPAPIPluginInstance> > *instances = pluginHost->InstanceArray();
|
|
|
+- for (uint32_t i = 0; i < instances->Length(); i++) {
|
|
|
+- // most recent streams are at the end of list
|
|
|
+- nsTArray<nsPluginStreamListenerPeer*> *streamListeners = instances->ElementAt(i)->FileCachedStreamListeners();
|
|
|
+- for (int32_t i = streamListeners->Length() - 1; i >= 0; --i) {
|
|
|
+- nsPluginStreamListenerPeer *lp = streamListeners->ElementAt(i);
|
|
|
+- if (lp && lp->mLocalCachedFileHolder) {
|
|
|
+- useExistingCacheFile = lp->UseExistingPluginCacheFile(this);
|
|
|
+- if (useExistingCacheFile) {
|
|
|
+- mLocalCachedFileHolder = lp->mLocalCachedFileHolder;
|
|
|
+- break;
|
|
|
+- }
|
|
|
+- }
|
|
|
+- if (useExistingCacheFile)
|
|
|
+- break;
|
|
|
+- }
|
|
|
+- }
|
|
|
+-
|
|
|
+- // Create a new cache file if one could not be found.
|
|
|
+- if (!useExistingCacheFile) {
|
|
|
+- nsCOMPtr<nsIFile> pluginTmp;
|
|
|
+- rv = nsPluginHost::GetPluginTempDir(getter_AddRefs(pluginTmp));
|
|
|
+- if (NS_FAILED(rv)) {
|
|
|
+- return rv;
|
|
|
+- }
|
|
|
+-
|
|
|
+- // Get the filename from the channel
|
|
|
+- nsCOMPtr<nsIURI> uri;
|
|
|
+- rv = channel->GetURI(getter_AddRefs(uri));
|
|
|
+- if (NS_FAILED(rv)) return rv;
|
|
|
+-
|
|
|
+- nsCOMPtr<nsIURL> url(do_QueryInterface(uri));
|
|
|
+- if (!url)
|
|
|
+- return NS_ERROR_FAILURE;
|
|
|
+-
|
|
|
+- nsAutoCString filename;
|
|
|
+- url->GetFileName(filename);
|
|
|
+- if (NS_FAILED(rv))
|
|
|
+- return rv;
|
|
|
+-
|
|
|
+- // Create a file to save our stream into. Should we scramble the name?
|
|
|
+- filename.InsertLiteral("plugin-", 0);
|
|
|
+- rv = pluginTmp->AppendNative(filename);
|
|
|
+- if (NS_FAILED(rv))
|
|
|
+- return rv;
|
|
|
+-
|
|
|
+- // Yes, make it unique.
|
|
|
+- rv = pluginTmp->CreateUnique(nsIFile::NORMAL_FILE_TYPE, 0600);
|
|
|
+- if (NS_FAILED(rv))
|
|
|
+- return rv;
|
|
|
+-
|
|
|
+- // create a file output stream to write to...
|
|
|
+- rv = NS_NewLocalFileOutputStream(getter_AddRefs(mFileCacheOutputStream), pluginTmp, -1, 00600);
|
|
|
+- if (NS_FAILED(rv))
|
|
|
+- return rv;
|
|
|
+-
|
|
|
+- // save the file.
|
|
|
+- mLocalCachedFileHolder = new CachedFileHolder(pluginTmp);
|
|
|
+- }
|
|
|
+-
|
|
|
+- // add this listenerPeer to list of stream peers for this instance
|
|
|
+- mPluginInstance->FileCachedStreamListeners()->AppendElement(this);
|
|
|
+-
|
|
|
+- return rv;
|
|
|
+-}
|
|
|
+-
|
|
|
+ NS_IMETHODIMP
|
|
|
+ nsPluginStreamListenerPeer::OnStartRequest(nsIRequest *request,
|
|
|
+ nsISupports* aContext)
|
|
|
+ {
|
|
|
+ nsresult rv = NS_OK;
|
|
|
+ AUTO_PROFILER_LABEL("nsPluginStreamListenerPeer::OnStartRequest", OTHER);
|
|
|
+
|
|
|
+- nsCOMPtr<nsIRequest> baseRequest = GetBaseRequest(request);
|
|
|
+- if (mRequests.IndexOfObject(baseRequest) == -1) {
|
|
|
++ if (mRequests.IndexOfObject(request) == -1) {
|
|
|
+ NS_ASSERTION(mRequests.Count() == 0,
|
|
|
+ "Only our initial stream should be unknown!");
|
|
|
+ TrackRequest(request);
|
|
|
+ }
|
|
|
+
|
|
|
+ if (mHaveFiredOnStartRequest) {
|
|
|
+ return NS_OK;
|
|
|
+ }
|
|
|
+@@ -593,23 +278,16 @@ nsresult
|
|
|
+ nsPluginStreamListenerPeer::GetContentType(char** result)
|
|
|
+ {
|
|
|
+ *result = const_cast<char*>(mContentType.get());
|
|
|
+ return NS_OK;
|
|
|
+ }
|
|
|
+
|
|
|
+
|
|
|
+ nsresult
|
|
|
+-nsPluginStreamListenerPeer::IsSeekable(bool* result)
|
|
|
+-{
|
|
|
+- *result = mSeekable;
|
|
|
+- return NS_OK;
|
|
|
+-}
|
|
|
+-
|
|
|
+-nsresult
|
|
|
+ nsPluginStreamListenerPeer::GetLength(uint32_t* result)
|
|
|
+ {
|
|
|
+ *result = mLength;
|
|
|
+ return NS_OK;
|
|
|
+ }
|
|
|
+
|
|
|
+ nsresult
|
|
|
+ nsPluginStreamListenerPeer::GetLastModified(uint32_t* result)
|
|
|
+@@ -620,51 +298,16 @@ nsPluginStreamListenerPeer::GetLastModif
|
|
|
+
|
|
|
+ nsresult
|
|
|
+ nsPluginStreamListenerPeer::GetURL(const char** result)
|
|
|
+ {
|
|
|
+ *result = mURLSpec.get();
|
|
|
+ return NS_OK;
|
|
|
+ }
|
|
|
+
|
|
|
+-void
|
|
|
+-nsPluginStreamListenerPeer::MakeByteRangeString(NPByteRange* aRangeList, nsACString &rangeRequest,
|
|
|
+- int32_t *numRequests)
|
|
|
+-{
|
|
|
+- rangeRequest.Truncate();
|
|
|
+- *numRequests = 0;
|
|
|
+- //the string should look like this: bytes=500-700,601-999
|
|
|
+- if (!aRangeList)
|
|
|
+- return;
|
|
|
+-
|
|
|
+- int32_t requestCnt = 0;
|
|
|
+- nsAutoCString string("bytes=");
|
|
|
+-
|
|
|
+- for (NPByteRange * range = aRangeList; range != nullptr; range = range->next) {
|
|
|
+- // XXX zero length?
|
|
|
+- if (!range->length)
|
|
|
+- continue;
|
|
|
+-
|
|
|
+- // XXX needs to be fixed for negative offsets
|
|
|
+- string.AppendInt(range->offset);
|
|
|
+- string.Append('-');
|
|
|
+- string.AppendInt(range->offset + range->length - 1);
|
|
|
+- if (range->next)
|
|
|
+- string.Append(',');
|
|
|
+-
|
|
|
+- requestCnt++;
|
|
|
+- }
|
|
|
+-
|
|
|
+- // get rid of possible trailing comma
|
|
|
+- string.Trim(",", false);
|
|
|
+-
|
|
|
+- rangeRequest = string;
|
|
|
+- *numRequests = requestCnt;
|
|
|
+-}
|
|
|
+-
|
|
|
+ // XXX: Converting the channel within nsPluginStreamListenerPeer
|
|
|
+ // to use asyncOpen2() and do not want to touch the fragile logic
|
|
|
+ // of byte range requests. Hence we just introduce this lightweight
|
|
|
+ // wrapper to proxy the context.
|
|
|
+ class PluginContextProxy final : public nsIStreamListener
|
|
|
+ {
|
|
|
+ public:
|
|
|
+ NS_DECL_ISUPPORTS
|
|
|
+@@ -713,275 +356,66 @@ private:
|
|
|
+ ~PluginContextProxy() {}
|
|
|
+ nsCOMPtr<nsIStreamListener> mListener;
|
|
|
+ nsCOMPtr<nsISupports> mContext;
|
|
|
+ };
|
|
|
+
|
|
|
+ NS_IMPL_ISUPPORTS(PluginContextProxy, nsIStreamListener)
|
|
|
+
|
|
|
+ nsresult
|
|
|
+-nsPluginStreamListenerPeer::RequestRead(NPByteRange* rangeList)
|
|
|
+-{
|
|
|
+- nsAutoCString rangeString;
|
|
|
+- int32_t numRequests;
|
|
|
+-
|
|
|
+- MakeByteRangeString(rangeList, rangeString, &numRequests);
|
|
|
+-
|
|
|
+- if (numRequests == 0)
|
|
|
+- return NS_ERROR_FAILURE;
|
|
|
+-
|
|
|
+- nsresult rv = NS_OK;
|
|
|
+-
|
|
|
+- RefPtr<nsPluginInstanceOwner> owner = mPluginInstance->GetOwner();
|
|
|
+- nsCOMPtr<nsIDOMElement> element;
|
|
|
+- nsCOMPtr<nsIDocument> doc;
|
|
|
+- if (owner) {
|
|
|
+- rv = owner->GetDOMElement(getter_AddRefs(element));
|
|
|
+- NS_ENSURE_SUCCESS(rv, rv);
|
|
|
+- rv = owner->GetDocument(getter_AddRefs(doc));
|
|
|
+- NS_ENSURE_SUCCESS(rv, rv);
|
|
|
+- }
|
|
|
+-
|
|
|
+- nsCOMPtr<nsIInterfaceRequestor> callbacks = do_QueryReferent(mWeakPtrChannelCallbacks);
|
|
|
+- nsCOMPtr<nsILoadGroup> loadGroup = do_QueryReferent(mWeakPtrChannelLoadGroup);
|
|
|
+-
|
|
|
+- nsCOMPtr<nsIChannel> channel;
|
|
|
+- nsCOMPtr<nsINode> requestingNode(do_QueryInterface(element));
|
|
|
+- if (requestingNode) {
|
|
|
+- rv = NS_NewChannel(getter_AddRefs(channel),
|
|
|
+- mURL,
|
|
|
+- requestingNode,
|
|
|
+- nsILoadInfo::SEC_ALLOW_CROSS_ORIGIN_DATA_IS_NULL,
|
|
|
+- nsIContentPolicy::TYPE_OTHER,
|
|
|
+- loadGroup,
|
|
|
+- callbacks,
|
|
|
+- nsIChannel::LOAD_BYPASS_SERVICE_WORKER);
|
|
|
+- }
|
|
|
+- else {
|
|
|
+- // In this else branch we really don't know where the load is coming
|
|
|
+- // from. Let's fall back to using the SystemPrincipal for such Plugins.
|
|
|
+- rv = NS_NewChannel(getter_AddRefs(channel),
|
|
|
+- mURL,
|
|
|
+- nsContentUtils::GetSystemPrincipal(),
|
|
|
+- nsILoadInfo::SEC_ALLOW_CROSS_ORIGIN_DATA_IS_NULL,
|
|
|
+- nsIContentPolicy::TYPE_OTHER,
|
|
|
+- loadGroup,
|
|
|
+- callbacks,
|
|
|
+- nsIChannel::LOAD_BYPASS_SERVICE_WORKER);
|
|
|
+- }
|
|
|
+-
|
|
|
+- if (NS_FAILED(rv))
|
|
|
+- return rv;
|
|
|
+-
|
|
|
+- nsCOMPtr<nsIHttpChannel> httpChannel(do_QueryInterface(channel));
|
|
|
+- if (!httpChannel)
|
|
|
+- return NS_ERROR_FAILURE;
|
|
|
+-
|
|
|
+- rv = httpChannel->SetRequestHeader(NS_LITERAL_CSTRING("Range"), rangeString, false);
|
|
|
+- MOZ_ASSERT(NS_SUCCEEDED(rv));
|
|
|
+-
|
|
|
+- mAbort = true; // instruct old stream listener to cancel
|
|
|
+- // the request on the next ODA.
|
|
|
+-
|
|
|
+- nsCOMPtr<nsIStreamListener> converter;
|
|
|
+-
|
|
|
+- if (numRequests == 1) {
|
|
|
+- converter = this;
|
|
|
+- // set current stream offset equal to the first offset in the range list
|
|
|
+- // it will work for single byte range request
|
|
|
+- // for multy range we'll reset it in ODA
|
|
|
+- SetStreamOffset(rangeList->offset);
|
|
|
+- } else {
|
|
|
+- nsWeakPtr weakpeer =
|
|
|
+- do_GetWeakReference(static_cast<nsISupportsWeakReference*>(this));
|
|
|
+- converter = new nsPluginByteRangeStreamListener(weakpeer);
|
|
|
+- }
|
|
|
+-
|
|
|
+- mPendingRequests += numRequests;
|
|
|
+-
|
|
|
+- nsCOMPtr<nsISupportsPRUint32> container = do_CreateInstance(NS_SUPPORTS_PRUINT32_CONTRACTID, &rv);
|
|
|
+- NS_ENSURE_SUCCESS(rv, rv);
|
|
|
+- rv = container->SetData(BYTERANGE_REQUEST_CONTEXT);
|
|
|
+- NS_ENSURE_SUCCESS(rv, rv);
|
|
|
+-
|
|
|
+- RefPtr<PluginContextProxy> pluginContextProxy =
|
|
|
+- new PluginContextProxy(converter, container);
|
|
|
+- rv = channel->AsyncOpen2(pluginContextProxy);
|
|
|
+- NS_ENSURE_SUCCESS(rv, rv);
|
|
|
+- TrackRequest(channel);
|
|
|
+- return NS_OK;
|
|
|
+-}
|
|
|
+-
|
|
|
+-nsresult
|
|
|
+ nsPluginStreamListenerPeer::GetStreamOffset(int32_t* result)
|
|
|
+ {
|
|
|
+ *result = mStreamOffset;
|
|
|
+ return NS_OK;
|
|
|
+ }
|
|
|
+
|
|
|
+ nsresult
|
|
|
+ nsPluginStreamListenerPeer::SetStreamOffset(int32_t value)
|
|
|
+ {
|
|
|
+ mStreamOffset = value;
|
|
|
+ return NS_OK;
|
|
|
+ }
|
|
|
+
|
|
|
+-nsresult nsPluginStreamListenerPeer::ServeStreamAsFile(nsIRequest *request,
|
|
|
+- nsISupports* aContext)
|
|
|
+-{
|
|
|
+- if (!mPluginInstance)
|
|
|
+- return NS_ERROR_FAILURE;
|
|
|
+-
|
|
|
+- // mPluginInstance->Stop calls mPStreamListener->CleanUpStream(), so stream will be properly clean up
|
|
|
+- mPluginInstance->Stop();
|
|
|
+- mPluginInstance->Start();
|
|
|
+- RefPtr<nsPluginInstanceOwner> owner = mPluginInstance->GetOwner();
|
|
|
+- if (owner) {
|
|
|
+- NPWindow* window = nullptr;
|
|
|
+- owner->GetWindow(window);
|
|
|
+- owner->CallSetWindow();
|
|
|
+- }
|
|
|
+-
|
|
|
+- mSeekable = false;
|
|
|
+- mPStreamListener->OnStartBinding(this);
|
|
|
+- mStreamOffset = 0;
|
|
|
+-
|
|
|
+- // force the plugin to use stream as file
|
|
|
+- mStreamType = NP_ASFILE;
|
|
|
+-
|
|
|
+- nsCOMPtr<nsIChannel> channel = do_QueryInterface(request);
|
|
|
+- if (channel) {
|
|
|
+- SetupPluginCacheFile(channel);
|
|
|
+- }
|
|
|
+-
|
|
|
+- // unset mPendingRequests
|
|
|
+- mPendingRequests = 0;
|
|
|
+-
|
|
|
+- return NS_OK;
|
|
|
+-}
|
|
|
+-
|
|
|
+-bool
|
|
|
+-nsPluginStreamListenerPeer::UseExistingPluginCacheFile(nsPluginStreamListenerPeer* psi)
|
|
|
+-{
|
|
|
+- NS_ENSURE_TRUE(psi, false);
|
|
|
+-
|
|
|
+- if (psi->mLength == mLength &&
|
|
|
+- psi->mModified == mModified &&
|
|
|
+- mStreamComplete &&
|
|
|
+- mURLSpec.Equals(psi->mURLSpec))
|
|
|
+- {
|
|
|
+- return true;
|
|
|
+- }
|
|
|
+- return false;
|
|
|
+-}
|
|
|
+-
|
|
|
+ NS_IMETHODIMP nsPluginStreamListenerPeer::OnDataAvailable(nsIRequest *request,
|
|
|
+ nsISupports* aContext,
|
|
|
+ nsIInputStream *aIStream,
|
|
|
+ uint64_t sourceOffset,
|
|
|
+ uint32_t aLength)
|
|
|
+ {
|
|
|
+- nsCOMPtr<nsIRequest> baseRequest = GetBaseRequest(request);
|
|
|
+- if (mRequests.IndexOfObject(baseRequest) == -1) {
|
|
|
++ if (mRequests.IndexOfObject(request) == -1) {
|
|
|
+ MOZ_ASSERT(false, "Received OnDataAvailable for untracked request.");
|
|
|
+ return NS_ERROR_UNEXPECTED;
|
|
|
+ }
|
|
|
+
|
|
|
+ if (mRequestFailed)
|
|
|
+ return NS_ERROR_FAILURE;
|
|
|
+
|
|
|
+- if (mAbort) {
|
|
|
+- uint32_t byteRangeRequest = 0; // set it to something that is not the byte range request.
|
|
|
+- nsCOMPtr<nsISupportsPRUint32> container = do_QueryInterface(aContext);
|
|
|
+- if (container)
|
|
|
+- container->GetData(&byteRangeRequest);
|
|
|
+-
|
|
|
+- if (byteRangeRequest != BYTERANGE_REQUEST_CONTEXT) {
|
|
|
+- // this is not one of our range requests
|
|
|
+- mAbort = false;
|
|
|
+- return NS_BINDING_ABORTED;
|
|
|
+- }
|
|
|
+- }
|
|
|
+-
|
|
|
+ nsresult rv = NS_OK;
|
|
|
+
|
|
|
+ if (!mPStreamListener)
|
|
|
+ return NS_ERROR_FAILURE;
|
|
|
+
|
|
|
+ const char * url = nullptr;
|
|
|
+ GetURL(&url);
|
|
|
+
|
|
|
+ PLUGIN_LOG(PLUGIN_LOG_NOISY,
|
|
|
+ ("nsPluginStreamListenerPeer::OnDataAvailable this=%p request=%p, offset=%" PRIu64 ", length=%u, url=%s\n",
|
|
|
+ this, request, sourceOffset, aLength, url ? url : "no url set"));
|
|
|
+
|
|
|
+- // if the plugin has requested an AsFileOnly stream, then don't
|
|
|
+- // call OnDataAvailable
|
|
|
+- if (mStreamType != NP_ASFILEONLY) {
|
|
|
+- // get the absolute offset of the request, if one exists.
|
|
|
+- nsCOMPtr<nsIByteRangeRequest> brr = do_QueryInterface(request);
|
|
|
+- if (brr) {
|
|
|
+- if (!mDataForwardToRequest)
|
|
|
+- return NS_ERROR_FAILURE;
|
|
|
+-
|
|
|
+- int64_t absoluteOffset64 = 0;
|
|
|
+- brr->GetStartRange(&absoluteOffset64);
|
|
|
+-
|
|
|
+- // XXX handle 64-bit for real
|
|
|
+- int32_t absoluteOffset = (int32_t)int64_t(absoluteOffset64);
|
|
|
+-
|
|
|
+- // we need to track how much data we have forwarded to the
|
|
|
+- // plugin.
|
|
|
+-
|
|
|
+- // FIXME: http://bugzilla.mozilla.org/show_bug.cgi?id=240130
|
|
|
+- //
|
|
|
+- // Why couldn't this be tracked on the plugin info, and not in a
|
|
|
+- // *hash table*?
|
|
|
+- int32_t amtForwardToPlugin = mDataForwardToRequest->Get(absoluteOffset);
|
|
|
+- mDataForwardToRequest->Put(absoluteOffset, (amtForwardToPlugin + aLength));
|
|
|
+-
|
|
|
+- SetStreamOffset(absoluteOffset + amtForwardToPlugin);
|
|
|
+- }
|
|
|
+-
|
|
|
+- nsCOMPtr<nsIInputStream> stream = aIStream;
|
|
|
++ nsCOMPtr<nsIInputStream> stream = aIStream;
|
|
|
++ rv = mPStreamListener->OnDataAvailable(this,
|
|
|
++ stream,
|
|
|
++ aLength);
|
|
|
+
|
|
|
+- // if we are caching the file ourselves to disk, we want to 'tee' off
|
|
|
+- // the data as the plugin read from the stream. We do this by the magic
|
|
|
+- // of an input stream tee.
|
|
|
+-
|
|
|
+- if (mFileCacheOutputStream) {
|
|
|
+- rv = NS_NewInputStreamTee(getter_AddRefs(stream), aIStream, mFileCacheOutputStream);
|
|
|
+- if (NS_FAILED(rv))
|
|
|
+- return rv;
|
|
|
+- }
|
|
|
+-
|
|
|
+- rv = mPStreamListener->OnDataAvailable(this,
|
|
|
+- stream,
|
|
|
+- aLength);
|
|
|
++ // if a plugin returns an error, the peer must kill the stream
|
|
|
++ // else the stream and PluginStreamListener leak
|
|
|
++ if (NS_FAILED(rv)) {
|
|
|
++ request->Cancel(rv);
|
|
|
++ }
|
|
|
+
|
|
|
+- // if a plugin returns an error, the peer must kill the stream
|
|
|
+- // else the stream and PluginStreamListener leak
|
|
|
+- if (NS_FAILED(rv))
|
|
|
+- request->Cancel(rv);
|
|
|
+- }
|
|
|
+- else
|
|
|
+- {
|
|
|
+- // if we don't read from the stream, OnStopRequest will never be called
|
|
|
+- char* buffer = new char[aLength];
|
|
|
+- uint32_t amountRead, amountWrote = 0;
|
|
|
+- rv = aIStream->Read(buffer, aLength, &amountRead);
|
|
|
+-
|
|
|
+- // if we are caching this to disk ourselves, lets write the bytes out.
|
|
|
+- if (mFileCacheOutputStream) {
|
|
|
+- while (amountWrote < amountRead && NS_SUCCEEDED(rv)) {
|
|
|
+- rv = mFileCacheOutputStream->Write(buffer, amountRead, &amountWrote);
|
|
|
+- }
|
|
|
+- }
|
|
|
+- delete [] buffer;
|
|
|
+- }
|
|
|
+ return rv;
|
|
|
+ }
|
|
|
+
|
|
|
+ NS_IMETHODIMP nsPluginStreamListenerPeer::OnStopRequest(nsIRequest *request,
|
|
|
+ nsISupports* aContext,
|
|
|
+ nsresult aStatus)
|
|
|
+ {
|
|
|
+ nsresult rv = NS_OK;
|
|
|
+@@ -993,53 +427,20 @@ NS_IMETHODIMP nsPluginStreamListenerPeer
|
|
|
+ NS_ERROR("Received OnStopRequest for untracked request.");
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ PLUGIN_LOG(PLUGIN_LOG_NOISY,
|
|
|
+ ("nsPluginStreamListenerPeer::OnStopRequest this=%p aStatus=%" PRIu32 " request=%p\n",
|
|
|
+ this, static_cast<uint32_t>(aStatus), request));
|
|
|
+
|
|
|
+- // for ByteRangeRequest we're just updating the mDataForwardToRequest hash and return.
|
|
|
+- nsCOMPtr<nsIByteRangeRequest> brr = do_QueryInterface(request);
|
|
|
+- if (brr) {
|
|
|
+- int64_t absoluteOffset64 = 0;
|
|
|
+- brr->GetStartRange(&absoluteOffset64);
|
|
|
+- // XXX support 64-bit offsets
|
|
|
+- int32_t absoluteOffset = (int32_t)int64_t(absoluteOffset64);
|
|
|
+-
|
|
|
+- // remove the request from our data forwarding count hash.
|
|
|
+- mDataForwardToRequest->Remove(absoluteOffset);
|
|
|
+-
|
|
|
+-
|
|
|
+- PLUGIN_LOG(PLUGIN_LOG_NOISY,
|
|
|
+- (" ::OnStopRequest for ByteRangeRequest Started=%d\n",
|
|
|
+- absoluteOffset));
|
|
|
+- } else {
|
|
|
+- // if this is not byte range request and
|
|
|
+- // if we are writting the stream to disk ourselves,
|
|
|
+- // close & tear it down here
|
|
|
+- mFileCacheOutputStream = nullptr;
|
|
|
+- }
|
|
|
+-
|
|
|
+ // if we still have pending stuff to do, lets not close the plugin socket.
|
|
|
+ if (--mPendingRequests > 0)
|
|
|
+ return NS_OK;
|
|
|
+
|
|
|
+- // we keep our connections around...
|
|
|
+- nsCOMPtr<nsISupportsPRUint32> container = do_QueryInterface(aContext);
|
|
|
+- if (container) {
|
|
|
+- uint32_t byteRangeRequest = 0; // something other than the byte range request.
|
|
|
+- container->GetData(&byteRangeRequest);
|
|
|
+- if (byteRangeRequest == BYTERANGE_REQUEST_CONTEXT) {
|
|
|
+- // this is one of our range requests
|
|
|
+- return NS_OK;
|
|
|
+- }
|
|
|
+- }
|
|
|
+-
|
|
|
+ if (!mPStreamListener)
|
|
|
+ return NS_ERROR_FAILURE;
|
|
|
+
|
|
|
+ nsCOMPtr<nsIChannel> channel = do_QueryInterface(request);
|
|
|
+ if (!channel)
|
|
|
+ return NS_ERROR_FAILURE;
|
|
|
+ // Set the content type to ensure we don't pass null to the plugin
|
|
|
+ nsAutoCString aContentType;
|
|
|
+@@ -1056,34 +457,16 @@ NS_IMETHODIMP nsPluginStreamListenerPeer
|
|
|
+
|
|
|
+ if (NS_FAILED(aStatus)) {
|
|
|
+ // on error status cleanup the stream
|
|
|
+ // and return w/o OnFileAvailable()
|
|
|
+ mPStreamListener->OnStopBinding(this, aStatus);
|
|
|
+ return NS_OK;
|
|
|
+ }
|
|
|
+
|
|
|
+- // call OnFileAvailable if plugin requests stream type StreamType_AsFile or StreamType_AsFileOnly
|
|
|
+- if (mStreamType >= NP_ASFILE) {
|
|
|
+- nsCOMPtr<nsIFile> localFile;
|
|
|
+- if (mLocalCachedFileHolder)
|
|
|
+- localFile = mLocalCachedFileHolder->file();
|
|
|
+- else {
|
|
|
+- // see if it is a file channel.
|
|
|
+- nsCOMPtr<nsIFileChannel> fileChannel = do_QueryInterface(request);
|
|
|
+- if (fileChannel) {
|
|
|
+- fileChannel->GetFile(getter_AddRefs(localFile));
|
|
|
+- }
|
|
|
+- }
|
|
|
+-
|
|
|
+- if (localFile) {
|
|
|
+- OnFileAvailable(localFile);
|
|
|
+- }
|
|
|
+- }
|
|
|
+-
|
|
|
+ if (mStartBinding) {
|
|
|
+ // On start binding has been called
|
|
|
+ mPStreamListener->OnStopBinding(this, aStatus);
|
|
|
+ } else {
|
|
|
+ // OnStartBinding hasn't been called, so complete the action.
|
|
|
+ mPStreamListener->OnStartBinding(this);
|
|
|
+ mPStreamListener->OnStopBinding(this, aStatus);
|
|
|
+ }
|
|
|
+@@ -1162,42 +545,16 @@ nsresult nsPluginStreamListenerPeer::Set
|
|
|
+ statusText.get());
|
|
|
+ static_cast<nsIHTTPHeaderListener*>(mPStreamListener)->StatusLine(status.get());
|
|
|
+ }
|
|
|
+
|
|
|
+ // Also provide all HTTP response headers to our listener.
|
|
|
+ rv = httpChannel->VisitResponseHeaders(this);
|
|
|
+ MOZ_ASSERT(NS_SUCCEEDED(rv));
|
|
|
+
|
|
|
+- mSeekable = false;
|
|
|
+- // first we look for a content-encoding header. If we find one, we tell the
|
|
|
+- // plugin that stream is not seekable, because the plugin always sees
|
|
|
+- // uncompressed data, so it can't make meaningful range requests on a
|
|
|
+- // compressed entity. Also, we force the plugin to use
|
|
|
+- // nsPluginStreamType_AsFile stream type and we have to save decompressed
|
|
|
+- // file into local plugin cache, because necko cache contains original
|
|
|
+- // compressed file.
|
|
|
+- nsAutoCString contentEncoding;
|
|
|
+- if (NS_SUCCEEDED(httpChannel->GetResponseHeader(NS_LITERAL_CSTRING("Content-Encoding"),
|
|
|
+- contentEncoding))) {
|
|
|
+- mUseLocalCache = true;
|
|
|
+- } else {
|
|
|
+- // set seekability (seekable if the stream has a known length and if the
|
|
|
+- // http server accepts byte ranges).
|
|
|
+- uint32_t length;
|
|
|
+- GetLength(&length);
|
|
|
+- if (length) {
|
|
|
+- nsAutoCString range;
|
|
|
+- if (NS_SUCCEEDED(httpChannel->GetResponseHeader(NS_LITERAL_CSTRING("accept-ranges"), range)) &&
|
|
|
+- range.Equals(NS_LITERAL_CSTRING("bytes"), nsCaseInsensitiveCStringComparator())) {
|
|
|
+- mSeekable = true;
|
|
|
+- }
|
|
|
+- }
|
|
|
+- }
|
|
|
+-
|
|
|
+ // we require a content len
|
|
|
+ // get Last-Modified header for plugin info
|
|
|
+ nsAutoCString lastModified;
|
|
|
+ if (NS_SUCCEEDED(httpChannel->GetResponseHeader(NS_LITERAL_CSTRING("last-modified"), lastModified)) &&
|
|
|
+ !lastModified.IsEmpty()) {
|
|
|
+ PRTime time64;
|
|
|
+ PR_ParseTimeString(lastModified.get(), true, &time64); //convert string time to integer time
|
|
|
+
|
|
|
+@@ -1212,66 +569,19 @@ nsresult nsPluginStreamListenerPeer::Set
|
|
|
+
|
|
|
+ rv = mPStreamListener->OnStartBinding(this);
|
|
|
+
|
|
|
+ mStartBinding = true;
|
|
|
+
|
|
|
+ if (NS_FAILED(rv))
|
|
|
+ return rv;
|
|
|
+
|
|
|
+- int32_t streamType = NP_NORMAL;
|
|
|
+- mPStreamListener->GetStreamType(&streamType);
|
|
|
+-
|
|
|
+- if (streamType != STREAM_TYPE_UNKNOWN) {
|
|
|
+- OnStreamTypeSet(streamType);
|
|
|
+- }
|
|
|
+-
|
|
|
+ return NS_OK;
|
|
|
+ }
|
|
|
+
|
|
|
+-void
|
|
|
+-nsPluginStreamListenerPeer::OnStreamTypeSet(const int32_t aStreamType)
|
|
|
+-{
|
|
|
+- MOZ_ASSERT(aStreamType != STREAM_TYPE_UNKNOWN);
|
|
|
+- MOZ_ASSERT(mRequest);
|
|
|
+- mStreamType = aStreamType;
|
|
|
+- if (!mUseLocalCache && mStreamType >= NP_ASFILE) {
|
|
|
+- // check it out if this is not a file channel.
|
|
|
+- nsCOMPtr<nsIFileChannel> fileChannel = do_QueryInterface(mRequest);
|
|
|
+- if (!fileChannel) {
|
|
|
+- mUseLocalCache = true;
|
|
|
+- }
|
|
|
+- }
|
|
|
+-
|
|
|
+- if (mUseLocalCache) {
|
|
|
+- nsCOMPtr<nsIChannel> channel = do_QueryInterface(mRequest);
|
|
|
+- SetupPluginCacheFile(channel);
|
|
|
+- }
|
|
|
+-}
|
|
|
+-
|
|
|
+-nsresult
|
|
|
+-nsPluginStreamListenerPeer::OnFileAvailable(nsIFile* aFile)
|
|
|
+-{
|
|
|
+- nsresult rv;
|
|
|
+- if (!mPStreamListener)
|
|
|
+- return NS_ERROR_FAILURE;
|
|
|
+-
|
|
|
+- nsAutoCString path;
|
|
|
+- rv = aFile->GetNativePath(path);
|
|
|
+- if (NS_FAILED(rv)) return rv;
|
|
|
+-
|
|
|
+- if (path.IsEmpty()) {
|
|
|
+- NS_WARNING("empty path");
|
|
|
+- return NS_OK;
|
|
|
+- }
|
|
|
+-
|
|
|
+- rv = mPStreamListener->OnFileAvailable(this, path.get());
|
|
|
+- return rv;
|
|
|
+-}
|
|
|
+-
|
|
|
+ NS_IMETHODIMP
|
|
|
+ nsPluginStreamListenerPeer::VisitHeader(const nsACString &header, const nsACString &value)
|
|
|
+ {
|
|
|
+ return mPStreamListener->NewResponseHeader(PromiseFlatCString(header).get(),
|
|
|
+ PromiseFlatCString(value).get());
|
|
|
+ }
|
|
|
+
|
|
|
+ nsresult
|
|
|
+diff --git a/dom/plugins/base/nsPluginStreamListenerPeer.h b/dom/plugins/base/nsPluginStreamListenerPeer.h
|
|
|
+--- a/dom/plugins/base/nsPluginStreamListenerPeer.h
|
|
|
++++ b/dom/plugins/base/nsPluginStreamListenerPeer.h
|
|
|
+@@ -58,39 +58,27 @@ public:
|
|
|
+ NS_DECL_ISUPPORTS
|
|
|
+ NS_DECL_NSIPROGRESSEVENTSINK
|
|
|
+ NS_DECL_NSIREQUESTOBSERVER
|
|
|
+ NS_DECL_NSISTREAMLISTENER
|
|
|
+ NS_DECL_NSIHTTPHEADERVISITOR
|
|
|
+ NS_DECL_NSIINTERFACEREQUESTOR
|
|
|
+ NS_DECL_NSICHANNELEVENTSINK
|
|
|
+
|
|
|
+- // Called by RequestRead
|
|
|
+- void
|
|
|
+- MakeByteRangeString(NPByteRange* aRangeList, nsACString &string, int32_t *numRequests);
|
|
|
+-
|
|
|
+- bool UseExistingPluginCacheFile(nsPluginStreamListenerPeer* psi);
|
|
|
+-
|
|
|
+ // Called by GetURL and PostURL (via NewStream) or by the host in the case of
|
|
|
+ // the initial plugin stream.
|
|
|
+ nsresult Initialize(nsIURI *aURL,
|
|
|
+ nsNPAPIPluginInstance *aInstance,
|
|
|
+ nsNPAPIPluginStreamListener *aListener);
|
|
|
+
|
|
|
+- nsresult OnFileAvailable(nsIFile* aFile);
|
|
|
+-
|
|
|
+- nsresult ServeStreamAsFile(nsIRequest *request, nsISupports *ctxt);
|
|
|
+-
|
|
|
+ nsNPAPIPluginInstance *GetPluginInstance() { return mPluginInstance; }
|
|
|
+
|
|
|
+- nsresult RequestRead(NPByteRange* rangeList);
|
|
|
+ nsresult GetLength(uint32_t* result);
|
|
|
+ nsresult GetURL(const char** result);
|
|
|
+ nsresult GetLastModified(uint32_t* result);
|
|
|
+- nsresult IsSeekable(bool* result);
|
|
|
+ nsresult GetContentType(char** result);
|
|
|
+ nsresult GetStreamOffset(int32_t* result);
|
|
|
+ nsresult SetStreamOffset(int32_t value);
|
|
|
+
|
|
|
+ void TrackRequest(nsIRequest* request)
|
|
|
+ {
|
|
|
+ mRequests.AppendObject(request);
|
|
|
+ }
|
|
|
+@@ -123,26 +111,18 @@ public:
|
|
|
+ }
|
|
|
+
|
|
|
+ void ResumeRequests() {
|
|
|
+ nsCOMArray<nsIRequest> requestsCopy(mRequests);
|
|
|
+ for (int32_t i = 0; i < requestsCopy.Count(); ++i)
|
|
|
+ requestsCopy[i]->Resume();
|
|
|
+ }
|
|
|
+
|
|
|
+- // Called by nsNPAPIPluginStreamListener
|
|
|
+- void OnStreamTypeSet(const int32_t aStreamType);
|
|
|
+-
|
|
|
+- enum {
|
|
|
+- STREAM_TYPE_UNKNOWN = UINT16_MAX
|
|
|
+- };
|
|
|
+-
|
|
|
+ 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*
|
|
|
+ RefPtr<nsNPAPIPluginStreamListener> mPStreamListener;
|
|
|
+
|
|
|
+ // Set to true if we request failed (like with a HTTP response of 404)
|
|
|
+ bool mRequestFailed;
|
|
|
+@@ -154,32 +134,24 @@ private:
|
|
|
+ * been called.
|
|
|
+ */
|
|
|
+ bool mStartBinding;
|
|
|
+ bool mHaveFiredOnStartRequest;
|
|
|
+ // these get passed to the plugin stream listener
|
|
|
+ uint32_t mLength;
|
|
|
+ int32_t mStreamType;
|
|
|
+
|
|
|
+- // local cached file, we save the content into local cache if browser cache is not available,
|
|
|
+- // or plugin asks stream as file and it expects file extension until bug 90558 got fixed
|
|
|
+- RefPtr<CachedFileHolder> mLocalCachedFileHolder;
|
|
|
+- nsCOMPtr<nsIOutputStream> mFileCacheOutputStream;
|
|
|
+- nsDataHashtable<nsUint32HashKey, uint32_t>* mDataForwardToRequest;
|
|
|
+-
|
|
|
+ nsCString mContentType;
|
|
|
+ bool mUseLocalCache;
|
|
|
+ nsCOMPtr<nsIRequest> mRequest;
|
|
|
+- bool mSeekable;
|
|
|
+ uint32_t mModified;
|
|
|
+ RefPtr<nsNPAPIPluginInstance> mPluginInstance;
|
|
|
+ int32_t mStreamOffset;
|
|
|
+ bool mStreamComplete;
|
|
|
+
|
|
|
+ public:
|
|
|
+- bool mAbort;
|
|
|
+ int32_t mPendingRequests;
|
|
|
+ nsWeakPtr mWeakPtrChannelCallbacks;
|
|
|
+ nsWeakPtr mWeakPtrChannelLoadGroup;
|
|
|
+ nsCOMArray<nsIRequest> mRequests;
|
|
|
+ };
|
|
|
+
|
|
|
+ #endif // nsPluginStreamListenerPeer_h_
|