1;2cBug 548217 - Make NP_SEEK streams work properly: they shouldn't crash if NPN_RequestRead is called after all the stream data is delivered, and they should call NPP_DestroyStream when NPN_DestroyStream is called, but not before. To this end, the classes nsPluginStreamInfo and nsPluginStreamListenerPeer have been unified: the nsNPAPIPluginStreamListener holds the stream listener peer alive so that additional range requests can be made on it. In addition the nsNPAPIPluginStreamListener holds *itself* alive for NP_SEEK streams, and only calls releases itself/calls CleanUpStream when the plugin explicitly calls NPN_DestroyStream or when the associated plugin instance is being destroyed. r=josh

--HG--
extra : rebase_source : 372df117d2b0c955605f44ee0e2fa512f0ad972b
This commit is contained in:
Benjamin Smedberg 2010-02-23 21:58:27 -05:00
Родитель 8520b6f00d
Коммит fbe4f3516c
5 изменённых файлов: 136 добавлений и 328 удалений

Просмотреть файл

@ -63,6 +63,13 @@ interface nsIPluginInstanceOwner : nsISupports
*/ */
void getInstance(in nsIPluginInstanceRef aInstance); void getInstance(in nsIPluginInstanceRef aInstance);
%{C++
// make getter_AddRefs work
inline nsresult GetInstance(nsIPluginInstance** aInstance) {
return GetInstance(*aInstance);
}
%}
/** /**
* Get a handle to the window structure of the owner. * Get a handle to the window structure of the owner.
* This pointer cannot be made persistent by the caller. * This pointer cannot be made persistent by the caller.

Просмотреть файл

@ -2380,8 +2380,13 @@ _requestread(NPStream *pstream, NPByteRange *rangeList)
if (streamtype != NP_SEEK) if (streamtype != NP_SEEK)
return NPERR_STREAM_NOT_SEEKABLE; return NPERR_STREAM_NOT_SEEKABLE;
if (streamlistener->mStreamInfo) if (!streamlistener->mStreamInfo)
streamlistener->mStreamInfo->RequestRead((NPByteRange *)rangeList); return NPERR_GENERIC_ERROR;
nsresult rv = streamlistener->mStreamInfo
->RequestRead((NPByteRange *)rangeList);
if (NS_FAILED(rv))
return NPERR_GENERIC_ERROR;
return NS_OK; return NS_OK;
} }

Просмотреть файл

@ -256,9 +256,20 @@ nsresult nsNPAPIPluginStreamListener::CleanUpStream(NPReason reason)
if (mStreamCleanedUp) if (mStreamCleanedUp)
return NS_OK; return NS_OK;
mStreamCleanedUp = PR_TRUE;
StopDataPump();
// 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->IsRunning()) if (!mInst || !mInst->IsRunning())
return rv; return rv;
mStreamInfo = NULL;
PluginDestructionGuard guard(mInst); PluginDestructionGuard guard(mInst);
const NPPluginFuncs *callbacks = nsnull; const NPPluginFuncs *callbacks = nsnull;
@ -285,11 +296,8 @@ nsresult nsNPAPIPluginStreamListener::CleanUpStream(NPReason reason)
rv = NS_OK; rv = NS_OK;
} }
mStreamCleanedUp = PR_TRUE;
mStreamStarted = PR_FALSE; mStreamStarted = PR_FALSE;
StopDataPump();
// fire notification back to plugin, just like before // fire notification back to plugin, just like before
CallURLNotify(reason); CallURLNotify(reason);
@ -385,6 +393,12 @@ nsNPAPIPluginStreamListener::OnStartBinding(nsIPluginStreamInfo* pluginInfo)
break; break;
case NP_SEEK: case NP_SEEK:
mStreamType = 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; break;
default: default:
return NS_ERROR_FAILURE; return NS_ERROR_FAILURE;
@ -794,19 +808,13 @@ nsNPAPIPluginStreamListener::OnStopBinding(nsIPluginStreamInfo* pluginInfo,
// check if the stream is of seekable type and later its destruction // check if the stream is of seekable type and later its destruction
// see bug 91140 // see bug 91140
nsresult rv = NS_OK; nsresult rv = NS_OK;
if (mStreamType != NP_SEEK) { NPReason reason = NS_FAILED(status) ? NPRES_NETWORK_ERR : NPRES_DONE;
NPReason reason = NPRES_DONE; if (mStreamType != NP_SEEK ||
(NP_SEEK == mStreamType && NS_BINDING_ABORTED == status)) {
if (NS_FAILED(status))
reason = NPRES_NETWORK_ERR; // since the stream failed, we need to tell the plugin that
rv = CleanUpStream(reason); rv = CleanUpStream(reason);
} }
if (rv != NPERR_NO_ERROR) return rv;
return NS_ERROR_FAILURE;
return NS_OK;
} }
NS_IMETHODIMP NS_IMETHODIMP
@ -1011,7 +1019,7 @@ NS_IMETHODIMP nsNPAPIPluginInstance::Stop()
// clean up open streams // clean up open streams
for (nsInstanceStream *is = mStreams; is != nsnull;) { for (nsInstanceStream *is = mStreams; is != nsnull;) {
nsNPAPIPluginStreamListener * listener = is->mPluginStreamListener; nsRefPtr<nsNPAPIPluginStreamListener> listener = is->mPluginStreamListener;
nsInstanceStream *next = is->mNext; nsInstanceStream *next = is->mNext;
delete is; delete is;

Просмотреть файл

@ -138,7 +138,7 @@
#include "nsPluginManifestLineReader.h" #include "nsPluginManifestLineReader.h"
#include "nsDefaultPlugin.h" #include "nsDefaultPlugin.h"
#include "nsWeakReference.h" #include "nsIWeakReferenceUtils.h"
#include "nsIDOMElement.h" #include "nsIDOMElement.h"
#include "nsIDOMHTMLObjectElement.h" #include "nsIDOMHTMLObjectElement.h"
#include "nsIDOMHTMLEmbedElement.h" #include "nsIDOMHTMLEmbedElement.h"
@ -345,97 +345,11 @@ nsresult nsPluginHost::PostPluginUnloadEvent(PRLibrary* aLibrary)
return NS_ERROR_FAILURE; return NS_ERROR_FAILURE;
} }
class nsPluginStreamListenerPeer;
class nsPluginStreamInfo : public nsINPAPIPluginStreamInfo
{
public:
nsPluginStreamInfo();
virtual ~nsPluginStreamInfo();
NS_DECL_ISUPPORTS
// nsINPAPIPluginStreamInfo interface
NS_IMETHOD
GetContentType(char **result);
NS_IMETHOD
IsSeekable(PRBool* result);
NS_IMETHOD
GetLength(PRUint32* result);
NS_IMETHOD
GetLastModified(PRUint32* result);
NS_IMETHOD
GetURL(const char** result);
NS_IMETHOD
RequestRead(NPByteRange* rangeList);
NS_IMETHOD
GetStreamOffset(PRInt32 *result);
NS_IMETHOD
SetStreamOffset(PRInt32 result);
// local methods
void
SetContentType(const char* contentType);
void
SetSeekable(const PRBool seekable);
void
SetLength(const PRUint32 length);
void
SetLastModified(const PRUint32 modified);
void
SetURL(const char* url);
void
SetPluginInstance(nsIPluginInstance * aPluginInstance);
void
SetPluginStreamListenerPeer(nsPluginStreamListenerPeer * aPluginStreamListenerPeer);
void
MakeByteRangeString(NPByteRange* aRangeList, nsACString &string, PRInt32 *numRequests);
PRBool
UseExistingPluginCacheFile(nsPluginStreamInfo* psi);
void
SetStreamComplete(const PRBool complete);
void
SetRequest(nsIRequest *request)
{
mRequest = request;
}
private:
char* mContentType;
char* mURL;
PRBool mSeekable;
PRUint32 mLength;
PRUint32 mModified;
nsIPluginInstance * mPluginInstance;
nsPluginStreamListenerPeer * mPluginStreamListenerPeer;
PRInt32 mStreamOffset;
PRBool mStreamComplete;
};
class nsPluginStreamListenerPeer : public nsIStreamListener, class nsPluginStreamListenerPeer : public nsIStreamListener,
public nsIProgressEventSink, public nsIProgressEventSink,
public nsIHttpHeaderVisitor, public nsIHttpHeaderVisitor,
public nsSupportsWeakReference public nsSupportsWeakReference,
public nsINPAPIPluginStreamInfo
{ {
public: public:
nsPluginStreamListenerPeer(); nsPluginStreamListenerPeer();
@ -447,6 +361,15 @@ public:
NS_DECL_NSISTREAMLISTENER NS_DECL_NSISTREAMLISTENER
NS_DECL_NSIHTTPHEADERVISITOR NS_DECL_NSIHTTPHEADERVISITOR
// nsINPAPIPluginStreamInfo interface
NS_DECL_NSIPLUGINSTREAMINFO
// Called by RequestRead
void
MakeByteRangeString(NPByteRange* aRangeList, nsACString &string, PRInt32 *numRequests);
PRBool UseExistingPluginCacheFile(nsPluginStreamListenerPeer* psi);
// Called by GetURL and PostURL (via NewStream) // Called by GetURL and PostURL (via NewStream)
nsresult Initialize(nsIURI *aURL, nsresult Initialize(nsIURI *aURL,
nsIPluginInstance *aInstance, nsIPluginInstance *aInstance,
@ -469,11 +392,11 @@ private:
nsresult SetUpStreamListener(nsIRequest* request, nsIURI* aURL); nsresult SetUpStreamListener(nsIRequest* request, nsIURI* aURL);
nsresult SetupPluginCacheFile(nsIChannel* channel); nsresult SetupPluginCacheFile(nsIChannel* channel);
nsIURI *mURL; nsCOMPtr<nsIURI> mURL;
nsIPluginInstanceOwner *mOwner; nsCString mURLSpec; // Have to keep this member because GetURL hands out char*
nsIPluginInstance *mInstance; nsCOMPtr<nsIPluginInstanceOwner> mOwner;
nsIPluginStreamListener *mPStreamListener; nsCOMPtr<nsIPluginInstance> mInstance;
nsRefPtr<nsPluginStreamInfo> mPluginStreamInfo; nsCOMPtr<nsIPluginStreamListener> mPStreamListener;
// Set to PR_TRUE if we request failed (like with a HTTP response of 404) // Set to PR_TRUE if we request failed (like with a HTTP response of 404)
PRPackedBool mRequestFailed; PRPackedBool mRequestFailed;
@ -487,16 +410,22 @@ private:
PRPackedBool mStartBinding; PRPackedBool mStartBinding;
PRPackedBool mHaveFiredOnStartRequest; PRPackedBool mHaveFiredOnStartRequest;
// these get passed to the plugin stream listener // these get passed to the plugin stream listener
char *mMIMEType;
PRUint32 mLength; PRUint32 mLength;
PRInt32 mStreamType; PRInt32 mStreamType;
// local cached file, we save the content into local cache if browser cache is not available, // 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 // or plugin asks stream as file and it expects file extension until bug 90558 got fixed
nsIFile *mLocalCachedFile; nsCOMPtr<nsIFile> mLocalCachedFile;
nsCOMPtr<nsIOutputStream> mFileCacheOutputStream; nsCOMPtr<nsIOutputStream> mFileCacheOutputStream;
nsHashtable *mDataForwardToRequest; nsHashtable *mDataForwardToRequest;
nsCString mContentType;
PRBool mSeekable;
PRUint32 mModified;
nsCOMPtr<nsIPluginInstance> mPluginInstance;
PRInt32 mStreamOffset;
PRBool mStreamComplete;
public: public:
PRBool mAbort; PRBool mAbort;
PRInt32 mPendingRequests; PRInt32 mPendingRequests;
@ -519,70 +448,44 @@ private:
PRBool mRemoveMagicNumber; PRBool mRemoveMagicNumber;
}; };
nsPluginStreamInfo::nsPluginStreamInfo()
{
mPluginInstance = nsnull;
mPluginStreamListenerPeer = nsnull;
mContentType = nsnull;
mURL = nsnull;
mSeekable = PR_FALSE;
mLength = 0;
mModified = 0;
mStreamOffset = 0;
mStreamComplete = PR_FALSE;
}
nsPluginStreamInfo::~nsPluginStreamInfo()
{
if (mContentType)
PL_strfree(mContentType);
if (mURL)
PL_strfree(mURL);
NS_IF_RELEASE(mPluginInstance);
}
NS_IMPL_ISUPPORTS2(nsPluginStreamInfo, nsIPluginStreamInfo,
nsINPAPIPluginStreamInfo)
NS_IMETHODIMP NS_IMETHODIMP
nsPluginStreamInfo::GetContentType(char **result) nsPluginStreamListenerPeer::GetContentType(char** result)
{ {
*result = mContentType; *result = const_cast<char*>(mContentType.get());
return NS_OK; return NS_OK;
} }
NS_IMETHODIMP NS_IMETHODIMP
nsPluginStreamInfo::IsSeekable(PRBool* result) nsPluginStreamListenerPeer::IsSeekable(PRBool* result)
{ {
*result = mSeekable; *result = mSeekable;
return NS_OK; return NS_OK;
} }
NS_IMETHODIMP NS_IMETHODIMP
nsPluginStreamInfo::GetLength(PRUint32* result) nsPluginStreamListenerPeer::GetLength(PRUint32* result)
{ {
*result = mLength; *result = mLength;
return NS_OK; return NS_OK;
} }
NS_IMETHODIMP NS_IMETHODIMP
nsPluginStreamInfo::GetLastModified(PRUint32* result) nsPluginStreamListenerPeer::GetLastModified(PRUint32* result)
{ {
*result = mModified; *result = mModified;
return NS_OK; return NS_OK;
} }
NS_IMETHODIMP NS_IMETHODIMP
nsPluginStreamInfo::GetURL(const char** result) nsPluginStreamListenerPeer::GetURL(const char** result)
{ {
*result = mURL; *result = mURLSpec.get();
return NS_OK; return NS_OK;
} }
void void
nsPluginStreamInfo::MakeByteRangeString(NPByteRange* aRangeList, nsACString &rangeRequest, PRInt32 *numRequests) nsPluginStreamListenerPeer::MakeByteRangeString(NPByteRange* aRangeList, nsACString &rangeRequest,
PRInt32 *numRequests)
{ {
rangeRequest.Truncate(); rangeRequest.Truncate();
*numRequests = 0; *numRequests = 0;
@ -617,36 +520,22 @@ nsPluginStreamInfo::MakeByteRangeString(NPByteRange* aRangeList, nsACString &ran
} }
NS_IMETHODIMP NS_IMETHODIMP
nsPluginStreamInfo::RequestRead(NPByteRange* rangeList) nsPluginStreamListenerPeer::RequestRead(NPByteRange* rangeList)
{ {
nsCAutoString rangeString; nsCAutoString rangeString;
PRInt32 numRequests; PRInt32 numRequests;
//first of all lets see if mPluginStreamListenerPeer is still alive
nsCOMPtr<nsISupportsWeakReference> suppWeakRef(
do_QueryInterface((nsISupportsWeakReference *)(mPluginStreamListenerPeer)));
if (!suppWeakRef)
return NS_ERROR_FAILURE;
nsCOMPtr<nsIWeakReference> pWeakRefPluginStreamListenerPeer =
do_GetWeakReference(suppWeakRef);
if (!pWeakRefPluginStreamListenerPeer)
return NS_ERROR_FAILURE;
MakeByteRangeString(rangeList, rangeString, &numRequests); MakeByteRangeString(rangeList, rangeString, &numRequests);
if (numRequests == 0) if (numRequests == 0)
return NS_ERROR_FAILURE; return NS_ERROR_FAILURE;
nsresult rv = NS_OK; nsresult rv = NS_OK;
nsCOMPtr<nsIURI> url;
rv = NS_NewURI(getter_AddRefs(url), nsDependentCString(mURL)); nsCOMPtr<nsIInterfaceRequestor> callbacks = do_QueryReferent(mWeakPtrChannelCallbacks);
nsCOMPtr<nsILoadGroup> loadGroup = do_QueryReferent(mWeakPtrChannelLoadGroup);
nsCOMPtr<nsIInterfaceRequestor> callbacks = do_QueryReferent(mPluginStreamListenerPeer->mWeakPtrChannelCallbacks);
nsCOMPtr<nsILoadGroup> loadGroup = do_QueryReferent(mPluginStreamListenerPeer->mWeakPtrChannelLoadGroup);
nsCOMPtr<nsIChannel> channel; nsCOMPtr<nsIChannel> channel;
rv = NS_NewChannel(getter_AddRefs(channel), url, nsnull, loadGroup, callbacks); rv = NS_NewChannel(getter_AddRefs(channel), mURL, nsnull, loadGroup, callbacks);
if (NS_FAILED(rv)) if (NS_FAILED(rv))
return rv; return rv;
@ -656,28 +545,29 @@ nsPluginStreamInfo::RequestRead(NPByteRange* rangeList)
httpChannel->SetRequestHeader(NS_LITERAL_CSTRING("Range"), rangeString, PR_FALSE); httpChannel->SetRequestHeader(NS_LITERAL_CSTRING("Range"), rangeString, PR_FALSE);
mPluginStreamListenerPeer->mAbort = PR_TRUE; // instruct old stream listener to cancel mAbort = PR_TRUE; // instruct old stream listener to cancel
// the request on the next ODA. // the request on the next ODA.
nsCOMPtr<nsIStreamListener> converter; nsCOMPtr<nsIStreamListener> converter;
if (numRequests == 1) { if (numRequests == 1) {
converter = mPluginStreamListenerPeer; converter = this;
// set current stream offset equal to the first offset in the range list // set current stream offset equal to the first offset in the range list
// it will work for single byte range request // it will work for single byte range request
// for multy range we'll reset it in ODA // for multy range we'll reset it in ODA
SetStreamOffset(rangeList->offset); SetStreamOffset(rangeList->offset);
} else { } else {
nsWeakPtr weakpeer =
do_GetWeakReference(static_cast<nsISupportsWeakReference*>(this));
nsPluginByteRangeStreamListener *brrListener = nsPluginByteRangeStreamListener *brrListener =
new nsPluginByteRangeStreamListener(pWeakRefPluginStreamListenerPeer); new nsPluginByteRangeStreamListener(weakpeer);
if (brrListener) if (brrListener)
converter = brrListener; converter = brrListener;
else else
return NS_ERROR_OUT_OF_MEMORY; return NS_ERROR_OUT_OF_MEMORY;
} }
mPluginStreamListenerPeer->mPendingRequests += numRequests; mPendingRequests += numRequests;
nsCOMPtr<nsISupportsPRUint32> container = do_CreateInstance(NS_SUPPORTS_PRUINT32_CONTRACTID, &rv); nsCOMPtr<nsISupportsPRUint32> container = do_CreateInstance(NS_SUPPORTS_PRUINT32_CONTRACTID, &rv);
if (NS_FAILED(rv)) if (NS_FAILED(rv))
@ -690,68 +580,19 @@ nsPluginStreamInfo::RequestRead(NPByteRange* rangeList)
} }
NS_IMETHODIMP NS_IMETHODIMP
nsPluginStreamInfo::GetStreamOffset(PRInt32 *result) nsPluginStreamListenerPeer::GetStreamOffset(PRInt32* result)
{ {
*result = mStreamOffset; *result = mStreamOffset;
return NS_OK; return NS_OK;
} }
NS_IMETHODIMP NS_IMETHODIMP
nsPluginStreamInfo::SetStreamOffset(PRInt32 offset) nsPluginStreamListenerPeer::SetStreamOffset(PRInt32 value)
{ {
mStreamOffset = offset; mStreamOffset = value;
return NS_OK; return NS_OK;
} }
void
nsPluginStreamInfo::SetContentType(const char* contentType)
{
if (mContentType != nsnull)
PL_strfree(mContentType);
mContentType = PL_strdup(contentType);
}
void
nsPluginStreamInfo::SetSeekable(const PRBool seekable)
{
mSeekable = seekable;
}
void
nsPluginStreamInfo::SetLength(const PRUint32 length)
{
mLength = length;
}
void
nsPluginStreamInfo::SetLastModified(const PRUint32 modified)
{
mModified = modified;
}
void
nsPluginStreamInfo::SetURL(const char* url)
{
if (mURL)
PL_strfree(mURL);
mURL = PL_strdup(url);
}
void
nsPluginStreamInfo::SetPluginInstance(nsIPluginInstance * aPluginInstance)
{
NS_IF_ADDREF(mPluginInstance = aPluginInstance);
}
void
nsPluginStreamInfo::SetPluginStreamListenerPeer(nsPluginStreamListenerPeer * aPluginStreamListenerPeer)
{
// not addref'd - nsPluginStreamInfo is owned by mPluginStreamListenerPeer
mPluginStreamListenerPeer = aPluginStreamListenerPeer;
}
class nsPluginCacheListener : public nsIStreamListener class nsPluginCacheListener : public nsIStreamListener
{ {
public: public:
@ -818,10 +659,6 @@ nsPluginCacheListener::OnStopRequest(nsIRequest *request,
nsPluginStreamListenerPeer::nsPluginStreamListenerPeer() nsPluginStreamListenerPeer::nsPluginStreamListenerPeer()
{ {
mURL = nsnull;
mOwner = nsnull;
mInstance = nsnull;
mPStreamListener = nsnull;
mStreamType = NP_NORMAL; mStreamType = NP_NORMAL;
mStartBinding = PR_FALSE; mStartBinding = PR_FALSE;
mAbort = PR_FALSE; mAbort = PR_FALSE;
@ -830,24 +667,20 @@ nsPluginStreamListenerPeer::nsPluginStreamListenerPeer()
mPendingRequests = 0; mPendingRequests = 0;
mHaveFiredOnStartRequest = PR_FALSE; mHaveFiredOnStartRequest = PR_FALSE;
mDataForwardToRequest = nsnull; mDataForwardToRequest = nsnull;
mLocalCachedFile = nsnull;
mSeekable = PR_FALSE;
mModified = 0;
mStreamOffset = 0;
mStreamComplete = 0;
} }
nsPluginStreamListenerPeer::~nsPluginStreamListenerPeer() nsPluginStreamListenerPeer::~nsPluginStreamListenerPeer()
{ {
#ifdef PLUGIN_LOGGING #ifdef PLUGIN_LOGGING
nsCAutoString urlSpec;
if (mURL != nsnull) mURL->GetSpec(urlSpec);
PR_LOG(nsPluginLogging::gPluginLog, PLUGIN_LOG_NORMAL, PR_LOG(nsPluginLogging::gPluginLog, PLUGIN_LOG_NORMAL,
("nsPluginStreamListenerPeer::dtor this=%p, url=%s%c",this, urlSpec.get(), mLocalCachedFile?',':'\n')); ("nsPluginStreamListenerPeer::dtor this=%p, url=%s%c",this, mURLSpec.get(), mLocalCachedFile?',':'\n'));
#endif #endif
NS_IF_RELEASE(mURL);
NS_IF_RELEASE(mOwner);
NS_IF_RELEASE(mInstance);
NS_IF_RELEASE(mPStreamListener);
// close FD of mFileCacheOutputStream if it's still open // close FD of mFileCacheOutputStream if it's still open
// or we won't be able to remove the cache file // or we won't be able to remove the cache file
if (mFileCacheOutputStream) if (mFileCacheOutputStream)
@ -869,18 +702,19 @@ nsPluginStreamListenerPeer::~nsPluginStreamListenerPeer()
if (refcnt == 1) { if (refcnt == 1) {
mLocalCachedFile->Remove(PR_FALSE); mLocalCachedFile->Remove(PR_FALSE);
NS_RELEASE(mLocalCachedFile);
} }
} }
delete mDataForwardToRequest; delete mDataForwardToRequest;
} }
NS_IMPL_ISUPPORTS4(nsPluginStreamListenerPeer, NS_IMPL_ISUPPORTS6(nsPluginStreamListenerPeer,
nsIStreamListener, nsIStreamListener,
nsIRequestObserver, nsIRequestObserver,
nsIHttpHeaderVisitor, nsIHttpHeaderVisitor,
nsISupportsWeakReference) nsISupportsWeakReference,
nsIPluginStreamInfo,
nsINPAPIPluginStreamInfo)
// Called as a result of GetURL and PostURL // Called as a result of GetURL and PostURL
nsresult nsPluginStreamListenerPeer::Initialize(nsIURI *aURL, nsresult nsPluginStreamListenerPeer::Initialize(nsIURI *aURL,
@ -899,20 +733,9 @@ nsresult nsPluginStreamListenerPeer::Initialize(nsIURI *aURL,
#endif #endif
mURL = aURL; mURL = aURL;
NS_ADDREF(mURL);
mInstance = aInstance; mInstance = aInstance;
NS_ADDREF(mInstance);
mPStreamListener = aListener; mPStreamListener = aListener;
NS_ADDREF(mPStreamListener);
mPluginStreamInfo = new nsPluginStreamInfo();
if (!mPluginStreamInfo)
return NS_ERROR_OUT_OF_MEMORY;
mPluginStreamInfo->SetPluginInstance(aInstance);
mPluginStreamInfo->SetPluginStreamListenerPeer(this);
mPendingRequests = requestCount; mPendingRequests = requestCount;
@ -944,24 +767,14 @@ nsresult nsPluginStreamListenerPeer::InitializeEmbedded(nsIURI *aURL,
#endif #endif
mURL = aURL; mURL = aURL;
NS_ADDREF(mURL);
if (aInstance) { if (aInstance) {
NS_ASSERTION(mInstance == nsnull, "nsPluginStreamListenerPeer::InitializeEmbedded mInstance != nsnull"); NS_ASSERTION(mInstance == nsnull, "nsPluginStreamListenerPeer::InitializeEmbedded mInstance != nsnull");
mInstance = aInstance; mInstance = aInstance;
NS_ADDREF(mInstance);
} else { } else {
mOwner = aOwner; mOwner = aOwner;
NS_IF_ADDREF(mOwner);
} }
mPluginStreamInfo = new nsPluginStreamInfo();
if (!mPluginStreamInfo)
return NS_ERROR_OUT_OF_MEMORY;
mPluginStreamInfo->SetPluginInstance(aInstance);
mPluginStreamInfo->SetPluginStreamListenerPeer(this);
mDataForwardToRequest = new nsHashtable(16, PR_FALSE); mDataForwardToRequest = new nsHashtable(16, PR_FALSE);
if (!mDataForwardToRequest) if (!mDataForwardToRequest)
return NS_ERROR_FAILURE; return NS_ERROR_FAILURE;
@ -978,14 +791,6 @@ nsresult nsPluginStreamListenerPeer::InitializeFullPage(nsIPluginInstance *aInst
NS_ASSERTION(mInstance == nsnull, "nsPluginStreamListenerPeer::InitializeFullPage mInstance != nsnull"); NS_ASSERTION(mInstance == nsnull, "nsPluginStreamListenerPeer::InitializeFullPage mInstance != nsnull");
mInstance = aInstance; mInstance = aInstance;
NS_ADDREF(mInstance);
mPluginStreamInfo = new nsPluginStreamInfo();
if (!mPluginStreamInfo)
return NS_ERROR_OUT_OF_MEMORY;
mPluginStreamInfo->SetPluginInstance(aInstance);
mPluginStreamInfo->SetPluginStreamListenerPeer(this);
mDataForwardToRequest = new nsHashtable(16, PR_FALSE); mDataForwardToRequest = new nsHashtable(16, PR_FALSE);
if (!mDataForwardToRequest) if (!mDataForwardToRequest)
@ -1019,11 +824,10 @@ nsPluginStreamListenerPeer::SetupPluginCacheFile(nsIChannel* channel)
while (--cnt >= 0) { while (--cnt >= 0) {
nsPluginStreamListenerPeer *lp = nsPluginStreamListenerPeer *lp =
reinterpret_cast<nsPluginStreamListenerPeer*>(instanceTag->mStreams->ElementAt(cnt)); reinterpret_cast<nsPluginStreamListenerPeer*>(instanceTag->mStreams->ElementAt(cnt));
if (lp && lp->mLocalCachedFile && lp->mPluginStreamInfo) { if (lp && lp->mLocalCachedFile) {
useExistingCacheFile = lp->mPluginStreamInfo->UseExistingPluginCacheFile(mPluginStreamInfo); useExistingCacheFile = lp->UseExistingPluginCacheFile(this);
if (useExistingCacheFile) { if (useExistingCacheFile) {
mLocalCachedFile = lp->mLocalCachedFile; mLocalCachedFile = lp->mLocalCachedFile;
NS_ADDREF(mLocalCachedFile);
break; break;
} }
NS_RELEASE(lp); NS_RELEASE(lp);
@ -1073,8 +877,9 @@ nsPluginStreamListenerPeer::SetupPluginCacheFile(nsIChannel* channel)
return rv; return rv;
// save the file. // save the file.
CallQueryInterface(pluginTmp, &mLocalCachedFile); // no need to check return value, just addref
// add one extra refcnt, we can use NS_RELEASE2(mLocalCachedFile...) in dtor mLocalCachedFile = pluginTmp;
// Addref to add one extra refcnt, we can use NS_RELEASE2(mLocalCachedFile...) in dtor
// to remove this file when refcnt == 1 // to remove this file when refcnt == 1
NS_ADDREF(mLocalCachedFile); NS_ADDREF(mLocalCachedFile);
} }
@ -1174,13 +979,13 @@ nsPluginStreamListenerPeer::OnStartRequest(nsIRequest *request,
mRequestFailed = PR_TRUE; mRequestFailed = PR_TRUE;
return NS_ERROR_FAILURE; return NS_ERROR_FAILURE;
} }
mPluginStreamInfo->SetLength(PRUint32(0)); mLength = 0;
} }
else { else {
mPluginStreamInfo->SetLength(length); mLength = length;
} }
mPluginStreamInfo->SetRequest(request); mRequest = request;
nsCAutoString aContentType; // XXX but we already got the type above! nsCAutoString aContentType; // XXX but we already got the type above!
rv = channel->GetContentType(aContentType); rv = channel->GetContentType(aContentType);
@ -1192,17 +997,15 @@ nsPluginStreamListenerPeer::OnStartRequest(nsIRequest *request,
if (NS_FAILED(rv)) if (NS_FAILED(rv))
return rv; return rv;
nsCAutoString urlSpec; aURL->GetSpec(mURLSpec);
aURL->GetSpec(urlSpec);
mPluginStreamInfo->SetURL(urlSpec.get());
if (!aContentType.IsEmpty()) if (!aContentType.IsEmpty())
mPluginStreamInfo->SetContentType(aContentType.get()); mContentType = aContentType;
#ifdef PLUGIN_LOGGING #ifdef PLUGIN_LOGGING
PR_LOG(nsPluginLogging::gPluginLog, PLUGIN_LOG_NOISY, PR_LOG(nsPluginLogging::gPluginLog, PLUGIN_LOG_NOISY,
("nsPluginStreamListenerPeer::OnStartRequest this=%p request=%p mime=%s, url=%s\n", ("nsPluginStreamListenerPeer::OnStartRequest this=%p request=%p mime=%s, url=%s\n",
this, request, aContentType.get(), urlSpec.get())); this, request, aContentType.get(), mURLSpec.get()));
PR_LogFlush(); PR_LogFlush();
#endif #endif
@ -1217,7 +1020,8 @@ nsPluginStreamListenerPeer::OnStartRequest(nsIRequest *request,
// NOTE: we don't want to try again if we didn't get the MIME type this time // NOTE: we don't want to try again if we didn't get the MIME type this time
if (!mInstance && mOwner && !aContentType.IsEmpty()) { if (!mInstance && mOwner && !aContentType.IsEmpty()) {
mOwner->GetInstance(mInstance); mOwner->GetInstance(getter_AddRefs(mInstance));
mOwner->GetWindow(window); mOwner->GetWindow(window);
if (!mInstance && window) { if (!mInstance && window) {
nsRefPtr<nsPluginHost> pluginHost = dont_AddRef(nsPluginHost::GetInst()); nsRefPtr<nsPluginHost> pluginHost = dont_AddRef(nsPluginHost::GetInst());
@ -1231,8 +1035,7 @@ nsPluginStreamListenerPeer::OnStartRequest(nsIRequest *request,
rv = pluginHost->SetUpPluginInstance(aContentType.get(), aURL, mOwner); rv = pluginHost->SetUpPluginInstance(aContentType.get(), aURL, mOwner);
if (NS_OK == rv) { if (NS_OK == rv) {
// GetInstance() adds a ref mOwner->GetInstance(getter_AddRefs(mInstance));
mOwner->GetInstance(mInstance);
if (mInstance) { if (mInstance) {
mInstance->Start(); mInstance->Start();
mOwner->CreateWidget(); mOwner->CreateWidget();
@ -1313,13 +1116,13 @@ NS_IMETHODIMP nsPluginStreamListenerPeer::OnDataAvailable(nsIRequest *request,
nsresult rv = NS_OK; nsresult rv = NS_OK;
if (!mPStreamListener || !mPluginStreamInfo) if (!mPStreamListener)
return NS_ERROR_FAILURE; return NS_ERROR_FAILURE;
mPluginStreamInfo->SetRequest(request); mRequest = request;
const char * url = nsnull; const char * url = nsnull;
mPluginStreamInfo->GetURL(&url); GetURL(&url);
PLUGIN_LOG(PLUGIN_LOG_NOISY, PLUGIN_LOG(PLUGIN_LOG_NOISY,
("nsPluginStreamListenerPeer::OnDataAvailable this=%p request=%p, offset=%d, length=%d, url=%s\n", ("nsPluginStreamListenerPeer::OnDataAvailable this=%p request=%p, offset=%d, length=%d, url=%s\n",
@ -1352,7 +1155,7 @@ NS_IMETHODIMP nsPluginStreamListenerPeer::OnDataAvailable(nsIRequest *request,
NS_PTR_TO_INT32(mDataForwardToRequest->Get(&key)); NS_PTR_TO_INT32(mDataForwardToRequest->Get(&key));
mDataForwardToRequest->Put(&key, NS_INT32_TO_PTR(amtForwardToPlugin + aLength)); mDataForwardToRequest->Put(&key, NS_INT32_TO_PTR(amtForwardToPlugin + aLength));
mPluginStreamInfo->SetStreamOffset(absoluteOffset + amtForwardToPlugin); SetStreamOffset(absoluteOffset + amtForwardToPlugin);
} }
nsCOMPtr<nsIInputStream> stream = aIStream; nsCOMPtr<nsIInputStream> stream = aIStream;
@ -1367,7 +1170,7 @@ NS_IMETHODIMP nsPluginStreamListenerPeer::OnDataAvailable(nsIRequest *request,
return rv; return rv;
} }
rv = mPStreamListener->OnDataAvailable(mPluginStreamInfo, rv = mPStreamListener->OnDataAvailable(this,
stream, stream,
aLength); aLength);
@ -1456,7 +1259,7 @@ NS_IMETHODIMP nsPluginStreamListenerPeer::OnStopRequest(nsIRequest *request,
return rv; return rv;
if (!aContentType.IsEmpty()) if (!aContentType.IsEmpty())
mPluginStreamInfo->SetContentType(aContentType.get()); mContentType = aContentType;
// set error status if stream failed so we notify the plugin // set error status if stream failed so we notify the plugin
if (mRequestFailed) if (mRequestFailed)
@ -1465,13 +1268,13 @@ NS_IMETHODIMP nsPluginStreamListenerPeer::OnStopRequest(nsIRequest *request,
if (NS_FAILED(aStatus)) { if (NS_FAILED(aStatus)) {
// on error status cleanup the stream // on error status cleanup the stream
// and return w/o OnFileAvailable() // and return w/o OnFileAvailable()
mPStreamListener->OnStopBinding(mPluginStreamInfo, aStatus); mPStreamListener->OnStopBinding(this, aStatus);
return NS_OK; return NS_OK;
} }
// call OnFileAvailable if plugin requests stream type StreamType_AsFile or StreamType_AsFileOnly // call OnFileAvailable if plugin requests stream type StreamType_AsFile or StreamType_AsFileOnly
if (mStreamType >= NP_ASFILE) { if (mStreamType >= NP_ASFILE) {
nsCOMPtr<nsIFile> localFile = do_QueryInterface(mLocalCachedFile); nsCOMPtr<nsIFile> localFile = mLocalCachedFile;
if (!localFile) { if (!localFile) {
nsCOMPtr<nsICachingChannel> cacheChannel = do_QueryInterface(request); nsCOMPtr<nsICachingChannel> cacheChannel = do_QueryInterface(request);
if (cacheChannel) { if (cacheChannel) {
@ -1492,15 +1295,17 @@ NS_IMETHODIMP nsPluginStreamListenerPeer::OnStopRequest(nsIRequest *request,
if (mStartBinding) { if (mStartBinding) {
// On start binding has been called // On start binding has been called
mPStreamListener->OnStopBinding(mPluginStreamInfo, aStatus); mPStreamListener->OnStopBinding(this, aStatus);
} else { } else {
// OnStartBinding hasn't been called, so complete the action. // OnStartBinding hasn't been called, so complete the action.
mPStreamListener->OnStartBinding(mPluginStreamInfo); mPStreamListener->OnStartBinding(this);
mPStreamListener->OnStopBinding(mPluginStreamInfo, aStatus); mPStreamListener->OnStopBinding(this, aStatus);
} }
if (NS_SUCCEEDED(aStatus)) if (NS_SUCCEEDED(aStatus)) {
mPluginStreamInfo->SetStreamComplete(PR_TRUE); mStreamComplete = PR_TRUE;
}
mRequest = NULL;
return NS_OK; return NS_OK;
} }
@ -1516,7 +1321,7 @@ nsresult nsPluginStreamListenerPeer::SetUpStreamListener(nsIRequest *request,
// with GetURL or PostURL (i.e. it's the initial stream we // with GetURL or PostURL (i.e. it's the initial stream we
// send to the plugin as determined by the SRC or DATA attribute) // send to the plugin as determined by the SRC or DATA attribute)
if (!mPStreamListener && mInstance) if (!mPStreamListener && mInstance)
rv = mInstance->NewStreamToPlugin(&mPStreamListener); rv = mInstance->NewStreamToPlugin(getter_AddRefs(mPStreamListener));
if (NS_FAILED(rv)) if (NS_FAILED(rv))
return rv; return rv;
@ -1574,7 +1379,7 @@ nsresult nsPluginStreamListenerPeer::SetUpStreamListener(nsIRequest *request,
// Also provide all HTTP response headers to our listener. // Also provide all HTTP response headers to our listener.
httpChannel->VisitResponseHeaders(this); httpChannel->VisitResponseHeaders(this);
PRBool bSeekable = PR_FALSE; mSeekable = PR_FALSE;
// first we look for a content-encoding header. If we find one, we tell the // 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 // plugin that stream is not seekable, because the plugin always sees
// uncompressed data, so it can't make meaningful range requests on a // uncompressed data, so it can't make meaningful range requests on a
@ -1590,15 +1395,12 @@ nsresult nsPluginStreamListenerPeer::SetUpStreamListener(nsIRequest *request,
// set seekability (seekable if the stream has a known length and if the // set seekability (seekable if the stream has a known length and if the
// http server accepts byte ranges). // http server accepts byte ranges).
PRUint32 length; PRUint32 length;
mPluginStreamInfo->GetLength(&length); GetLength(&length);
if (length) { if (length) {
nsCAutoString range; nsCAutoString range;
if (NS_SUCCEEDED(httpChannel->GetResponseHeader(NS_LITERAL_CSTRING("accept-ranges"), range)) && if (NS_SUCCEEDED(httpChannel->GetResponseHeader(NS_LITERAL_CSTRING("accept-ranges"), range)) &&
range.Equals(NS_LITERAL_CSTRING("bytes"), nsCaseInsensitiveCStringComparator())) { range.Equals(NS_LITERAL_CSTRING("bytes"), nsCaseInsensitiveCStringComparator())) {
bSeekable = PR_TRUE; mSeekable = PR_TRUE;
// nsPluginStreamInfo.mSeekable intitialized by PR_FALSE in ctor of nsPluginStreamInfo
// so we reset it only here.
mPluginStreamInfo->SetSeekable(bSeekable);
} }
} }
} }
@ -1614,11 +1416,11 @@ nsresult nsPluginStreamListenerPeer::SetUpStreamListener(nsIRequest *request,
// Convert PRTime to unix-style time_t, i.e. seconds since the epoch // Convert PRTime to unix-style time_t, i.e. seconds since the epoch
double fpTime; double fpTime;
LL_L2D(fpTime, time64); LL_L2D(fpTime, time64);
mPluginStreamInfo->SetLastModified((PRUint32)(fpTime * 1e-6 + 0.5)); mModified = (PRUint32)(fpTime * 1e-6 + 0.5);
} }
} }
rv = mPStreamListener->OnStartBinding(mPluginStreamInfo); rv = mPStreamListener->OnStartBinding(this);
mStartBinding = PR_TRUE; mStartBinding = PR_TRUE;
@ -1662,7 +1464,7 @@ nsPluginStreamListenerPeer::OnFileAvailable(nsIFile* aFile)
return NS_OK; return NS_OK;
} }
rv = mPStreamListener->OnFileAvailable(mPluginStreamInfo, path.get()); rv = mPStreamListener->OnFileAvailable(this, path.get());
return rv; return rv;
} }
@ -5371,9 +5173,9 @@ nsresult nsPluginStreamListenerPeer::ServeStreamAsFile(nsIRequest *request,
} }
} }
mPluginStreamInfo->SetSeekable(0); mSeekable = PR_FALSE;
mPStreamListener->OnStartBinding(mPluginStreamInfo); mPStreamListener->OnStartBinding(this);
mPluginStreamInfo->SetStreamOffset(0); mStreamOffset = 0;
// force the plugin to use stream as file // force the plugin to use stream as file
mStreamType = NP_ASFILE; mStreamType = NP_ASFILE;
@ -5509,7 +5311,7 @@ nsPluginByteRangeStreamListener::OnDataAvailable(nsIRequest *request, nsISupport
} }
PRBool PRBool
nsPluginStreamInfo::UseExistingPluginCacheFile(nsPluginStreamInfo* psi) nsPluginStreamListenerPeer::UseExistingPluginCacheFile(nsPluginStreamListenerPeer* psi)
{ {
NS_ENSURE_ARG_POINTER(psi); NS_ENSURE_ARG_POINTER(psi);
@ -5517,24 +5319,13 @@ nsPluginStreamInfo::UseExistingPluginCacheFile(nsPluginStreamInfo* psi)
if ( psi->mLength == mLength && if ( psi->mLength == mLength &&
psi->mModified == mModified && psi->mModified == mModified &&
mStreamComplete && mStreamComplete &&
!PL_strcmp(psi->mURL, mURL)) mURLSpec.Equals(psi->mURLSpec))
{ {
return PR_TRUE; return PR_TRUE;
} }
return PR_FALSE; return PR_FALSE;
} }
void
nsPluginStreamInfo::SetStreamComplete(const PRBool complete)
{
mStreamComplete = complete;
if (complete) {
// We're done, release the request.
SetRequest(nsnull);
}
}
// Runnable that does an async destroy of a plugin. // Runnable that does an async destroy of a plugin.
class nsPluginDestroyRunnable : public nsRunnable, class nsPluginDestroyRunnable : public nsRunnable,

Просмотреть файл

@ -1025,9 +1025,6 @@ NPP_Write(NPP instance, NPStream* stream, int32_t offset, int32_t len, void* buf
if (err != NPERR_NO_ERROR) { if (err != NPERR_NO_ERROR) {
instanceData->err << "Error: NPN_DestroyStream returned " << err; instanceData->err << "Error: NPN_DestroyStream returned " << err;
} }
if (instanceData->frame.length() > 0) {
sendBufferToFrame(instance);
}
} }
} }
else { else {