Fixing bug 237076 (and bug 89270 too). Make our plugin stream code deal with cases where we're getting data off of the network faster than the plugin can handle it. Suspend the incoming request when the plugin says it can't handle more data, then keep feeding the plugin that we got so far until it's done with it, and then resume the network request. r=brendan@mozilla.org, sr=darin@meer.net, a=asa@mozilla.org
git-svn-id: svn://10.0.0.236/trunk@154683 18797224-902f-48f8-a5cc-f745e15eee43
This commit is contained in:
@@ -1,4 +1,4 @@
|
||||
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
|
||||
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/* ***** BEGIN LICENSE BLOCK *****
|
||||
* Version: NPL 1.1/GPL 2.0/LGPL 2.1
|
||||
*
|
||||
@@ -89,10 +89,7 @@ enum eNPPStreamTypeInternal {
|
||||
static NS_DEFINE_CID(kPrefServiceCID, NS_PREF_CID);
|
||||
static NS_DEFINE_IID(kCPluginManagerCID, NS_PLUGINMANAGER_CID);
|
||||
static NS_DEFINE_IID(kPluginManagerCID, NS_PLUGINMANAGER_CID);
|
||||
static NS_DEFINE_IID(kIPluginManagerIID, NS_IPLUGINMANAGER_IID);
|
||||
static NS_DEFINE_IID(kMemoryCID, NS_MEMORY_CID);
|
||||
static NS_DEFINE_IID(kIMemoryIID, NS_IMEMORY_IID);
|
||||
static NS_DEFINE_IID(kIPluginStreamListenerIID, NS_IPLUGINSTREAMLISTENER_IID);
|
||||
|
||||
PR_BEGIN_EXTERN_C
|
||||
|
||||
@@ -461,9 +458,9 @@ ns4xPlugin::CreatePlugin(nsIServiceManagerObsolete* aServiceMgr,
|
||||
CheckClassInitialized();
|
||||
|
||||
// set up the MemAllocator service now because it might be used by the plugin
|
||||
if (aServiceMgr != nsnull) {
|
||||
if (nsnull == gMalloc)
|
||||
aServiceMgr->GetService(kMemoryCID, kIMemoryIID, (nsISupports**)&gMalloc);
|
||||
if (aServiceMgr && !gMalloc) {
|
||||
aServiceMgr->GetService(kMemoryCID, NS_GET_IID(nsIMemory),
|
||||
(nsISupports**)&gMalloc);
|
||||
}
|
||||
|
||||
#if defined(XP_UNIX) && !defined(XP_MACOSX)
|
||||
@@ -703,9 +700,9 @@ ns4xPlugin::CreatePlugin(nsIServiceManagerObsolete* aServiceMgr,
|
||||
//----------------
|
||||
//Creates a ns4xPluginInstance object.
|
||||
|
||||
nsresult ns4xPlugin :: CreateInstance(nsISupports *aOuter,
|
||||
const nsIID &aIID,
|
||||
void **aResult)
|
||||
nsresult ns4xPlugin::CreateInstance(nsISupports *aOuter,
|
||||
const nsIID &aIID,
|
||||
void **aResult)
|
||||
{
|
||||
if (aResult == NULL)
|
||||
return NS_ERROR_NULL_POINTER;
|
||||
@@ -713,23 +710,18 @@ nsresult ns4xPlugin :: CreateInstance(nsISupports *aOuter,
|
||||
*aResult = NULL;
|
||||
|
||||
// XXX This is suspicuous!
|
||||
ns4xPluginInstance *inst = new ns4xPluginInstance(&fCallbacks, fLibrary);
|
||||
nsRefPtr<ns4xPluginInstance> inst =
|
||||
new ns4xPluginInstance(&fCallbacks, fLibrary);
|
||||
|
||||
if (inst == NULL)
|
||||
return NS_ERROR_OUT_OF_MEMORY;
|
||||
|
||||
NS_ADDREF(inst); // Stabilize
|
||||
|
||||
nsresult res = inst->QueryInterface(aIID, aResult);
|
||||
|
||||
NS_RELEASE(inst); // Destabilize and avoid leaks. Avoid calling delete <interface pointer>
|
||||
|
||||
return res;
|
||||
return inst->QueryInterface(aIID, aResult);
|
||||
}
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////////////////
|
||||
nsresult ns4xPlugin :: LockFactory(PRBool aLock)
|
||||
nsresult ns4xPlugin::LockFactory(PRBool aLock)
|
||||
{
|
||||
// Not implemented in simplest case.
|
||||
return NS_OK;
|
||||
@@ -737,10 +729,10 @@ nsresult ns4xPlugin :: LockFactory(PRBool aLock)
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////////////////
|
||||
NS_METHOD ns4xPlugin :: CreatePluginInstance(nsISupports *aOuter,
|
||||
REFNSIID aIID,
|
||||
const char *aPluginMIMEType,
|
||||
void **aResult)
|
||||
NS_METHOD ns4xPlugin::CreatePluginInstance(nsISupports *aOuter,
|
||||
REFNSIID aIID,
|
||||
const char *aPluginMIMEType,
|
||||
void **aResult)
|
||||
{
|
||||
return CreateInstance(aOuter, aIID, aResult);
|
||||
}
|
||||
@@ -1031,31 +1023,38 @@ NPError NP_EXPORT
|
||||
_destroystream(NPP npp, NPStream *pstream, NPError reason)
|
||||
{
|
||||
NPN_PLUGIN_LOG(PLUGIN_LOG_NORMAL,
|
||||
("NPN_DestroyStream: npp=%p, url=%s, reason=%d\n", (void*)npp, pstream->url, (int)reason));
|
||||
("NPN_DestroyStream: npp=%p, url=%s, reason=%d\n", (void*)npp,
|
||||
pstream->url, (int)reason));
|
||||
|
||||
if(!npp)
|
||||
if (!npp)
|
||||
return NPERR_INVALID_INSTANCE_ERROR;
|
||||
|
||||
nsISupports* stream = (nsISupports*) pstream->ndata;
|
||||
nsIPluginStreamListener* listener;
|
||||
nsCOMPtr<nsIPluginStreamListener> listener =
|
||||
do_QueryInterface((nsISupports *)pstream->ndata);
|
||||
|
||||
// DestroyStream can kill two kinds of streams: NPP derived and NPN derived.
|
||||
// check to see if they're trying to kill a NPP stream
|
||||
if(stream->QueryInterface(kIPluginStreamListenerIID, (void**)&listener) == NS_OK) {
|
||||
// XXX we should try to kill this listener here somehow
|
||||
NS_RELEASE(listener);
|
||||
return NPERR_NO_ERROR;
|
||||
if (listener) {
|
||||
// Tell the stream listner that the stream is now gone.
|
||||
listener->OnStopBinding(nsnull, NS_BINDING_ABORTED);
|
||||
|
||||
// FIXME: http://bugzilla.mozilla.org/show_bug.cgi?id=240131
|
||||
//
|
||||
// Is it ok to leave pstream->ndata set here, and who releases it
|
||||
// (or is it even properly ref counted)? And who closes the stream
|
||||
// etc?
|
||||
} else {
|
||||
ns4xStreamWrapper* wrapper = (ns4xStreamWrapper *)pstream->ndata;
|
||||
NS_ASSERTION(wrapper != NULL, "null wrapper");
|
||||
|
||||
if (wrapper == NULL)
|
||||
return NPERR_INVALID_PARAM;
|
||||
|
||||
// This will release the wrapped nsIOutputStream.
|
||||
delete wrapper;
|
||||
pstream->ndata = nsnull;
|
||||
}
|
||||
|
||||
ns4xStreamWrapper* wrapper = (ns4xStreamWrapper*) pstream->ndata;
|
||||
NS_ASSERTION(wrapper != NULL, "null wrapper");
|
||||
|
||||
if (wrapper == NULL)
|
||||
return NPERR_INVALID_PARAM;
|
||||
|
||||
// This will release the wrapped nsIOutputStream.
|
||||
delete wrapper;
|
||||
pstream->ndata = nsnull;
|
||||
return NPERR_NO_ERROR;
|
||||
}
|
||||
|
||||
@@ -1112,12 +1111,9 @@ _reloadplugins(NPBool reloadPages)
|
||||
if(gServiceMgr == nsnull)
|
||||
return;
|
||||
|
||||
nsIPluginManager * pm;
|
||||
gServiceMgr->GetService(kPluginManagerCID, kIPluginManagerIID, (nsISupports**)&pm);
|
||||
nsCOMPtr<nsIPluginManager> pm(do_GetService(kPluginManagerCID));
|
||||
|
||||
pm->ReloadPlugins(reloadPages);
|
||||
|
||||
NS_RELEASE(pm);
|
||||
}
|
||||
|
||||
|
||||
@@ -1491,14 +1487,11 @@ _useragent(NPP npp)
|
||||
return NULL;
|
||||
|
||||
char *retstr;
|
||||
|
||||
nsIPluginManager * pm;
|
||||
gServiceMgr->GetService(kPluginManagerCID, kIPluginManagerIID, (nsISupports**)&pm);
|
||||
|
||||
|
||||
nsCOMPtr<nsIPluginManager> pm(do_GetService(kPluginManagerCID));
|
||||
|
||||
pm->UserAgent((const char **)&retstr);
|
||||
|
||||
NS_RELEASE(pm);
|
||||
|
||||
|
||||
return retstr;
|
||||
}
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/* ***** BEGIN LICENSE BLOCK *****
|
||||
* Version: NPL 1.1/GPL 2.0/LGPL 2.1
|
||||
*
|
||||
@@ -78,31 +78,30 @@ static NS_DEFINE_IID(kIPluginStreamListenerIID, NS_IPLUGINSTREAMLISTENER_IID);
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
// ns4xPluginStreamListener Methods
|
||||
|
||||
NS_IMPL_ISUPPORTS1(ns4xPluginStreamListener, nsIPluginStreamListener)
|
||||
NS_IMPL_ISUPPORTS2(ns4xPluginStreamListener, nsIPluginStreamListener,
|
||||
nsITimerCallback)
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
ns4xPluginStreamListener::ns4xPluginStreamListener(nsIPluginInstance* inst,
|
||||
void* notifyData,
|
||||
const char* aURL)
|
||||
: mNotifyData(notifyData),
|
||||
mStreamBuffer(nsnull),
|
||||
mNotifyURL(nsnull),
|
||||
mStreamStarted(PR_FALSE),
|
||||
mStreamCleanedUp(PR_FALSE),
|
||||
mCallNotify(PR_FALSE),
|
||||
mStreamInfo(nsnull)
|
||||
: mNotifyData(notifyData),
|
||||
mStreamBuffer(nsnull),
|
||||
mNotifyURL(aURL ? PL_strdup(aURL) : nsnull),
|
||||
mInst((ns4xPluginInstance *)inst),
|
||||
mStreamBufferSize(0),
|
||||
mStreamBufferByteCount(0),
|
||||
mStreamType(nsPluginStreamType_Normal),
|
||||
mStreamStarted(PR_FALSE),
|
||||
mStreamCleanedUp(PR_FALSE),
|
||||
mCallNotify(PR_FALSE),
|
||||
mIsSuspended(PR_FALSE)
|
||||
{
|
||||
mInst = (ns4xPluginInstance*) inst;
|
||||
mPosition = 0;
|
||||
mStreamBufferSize = 0;
|
||||
// Initialize the 4.x interface structure
|
||||
memset(&mNPStream, 0, sizeof(mNPStream));
|
||||
|
||||
NS_IF_ADDREF(mInst);
|
||||
|
||||
if (aURL)
|
||||
mNotifyURL = PL_strdup(aURL);
|
||||
}
|
||||
|
||||
|
||||
@@ -127,9 +126,10 @@ ns4xPluginStreamListener::~ns4xPluginStreamListener(void)
|
||||
}
|
||||
}
|
||||
|
||||
// For those cases when NewStream is never called, we still may need to fire a
|
||||
// notification callback. Return network error as fallback reason because for other
|
||||
// cases, notify should have already been called for other reasons elsewhere.
|
||||
// For those cases when NewStream is never called, we still may need
|
||||
// to fire a notification callback. Return network error as fallback
|
||||
// reason because for other cases, notify should have already been
|
||||
// called for other reasons elsewhere.
|
||||
CallURLNotify(NPRES_NETWORK_ERR);
|
||||
|
||||
// lets get rid of the buffer
|
||||
@@ -139,7 +139,6 @@ ns4xPluginStreamListener::~ns4xPluginStreamListener(void)
|
||||
mStreamBuffer=nsnull;
|
||||
}
|
||||
|
||||
|
||||
NS_IF_RELEASE(inst);
|
||||
|
||||
if (mNotifyURL)
|
||||
@@ -186,6 +185,8 @@ nsresult ns4xPluginStreamListener::CleanUpStream(NPReason reason)
|
||||
mStreamCleanedUp = PR_TRUE;
|
||||
mStreamStarted = PR_FALSE;
|
||||
|
||||
StopDataPump();
|
||||
|
||||
// fire notification back to plugin, just like before
|
||||
CallURLNotify(reason);
|
||||
|
||||
@@ -261,7 +262,6 @@ ns4xPluginStreamListener::OnStartBinding(nsIPluginStreamInfo* pluginInfo)
|
||||
|
||||
mStreamInfo = pluginInfo;
|
||||
|
||||
|
||||
NS_TRY_SAFE_CALL_RETURN(error, CallNPP_NewStreamProc(callbacks->newstream,
|
||||
npp,
|
||||
(char *)contentType,
|
||||
@@ -299,172 +299,322 @@ ns4xPluginStreamListener::OnStartBinding(nsIPluginStreamInfo* pluginInfo)
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
nsresult
|
||||
ns4xPluginStreamListener::SuspendRequest()
|
||||
{
|
||||
NS_ASSERTION(!mIsSuspended,
|
||||
"Suspending a request that's already suspended!");
|
||||
|
||||
nsCOMPtr<nsI4xPluginStreamInfo> pluginInfo4x =
|
||||
do_QueryInterface(mStreamInfo);
|
||||
nsIRequest *request;
|
||||
|
||||
if (!pluginInfo4x || !(request = pluginInfo4x->GetRequest())) {
|
||||
NS_ERROR("Trying to suspend a non-suspendable stream!");
|
||||
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
|
||||
nsresult rv = StartDataPump();
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
mIsSuspended = PR_TRUE;
|
||||
|
||||
return request->Suspend();
|
||||
}
|
||||
|
||||
void
|
||||
ns4xPluginStreamListener::ResumeRequest()
|
||||
{
|
||||
nsCOMPtr<nsI4xPluginStreamInfo> pluginInfo4x =
|
||||
do_QueryInterface(mStreamInfo);
|
||||
|
||||
nsIRequest *request = pluginInfo4x->GetRequest();
|
||||
|
||||
// request can be null if the network stream is done.
|
||||
if (request) {
|
||||
request->Resume();
|
||||
}
|
||||
|
||||
mIsSuspended = PR_FALSE;
|
||||
}
|
||||
|
||||
nsresult
|
||||
ns4xPluginStreamListener::StartDataPump()
|
||||
{
|
||||
nsresult rv;
|
||||
mDataPumpTimer = do_CreateInstance("@mozilla.org/timer;1", &rv);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
// Start pumping data to the plugin every 100ms until it obeys and
|
||||
// eats the data.
|
||||
return mDataPumpTimer->InitWithCallback(this, 100,
|
||||
nsITimer::TYPE_REPEATING_SLACK);
|
||||
}
|
||||
|
||||
void
|
||||
ns4xPluginStreamListener::StopDataPump()
|
||||
{
|
||||
if (mDataPumpTimer) {
|
||||
mDataPumpTimer->Cancel();
|
||||
|
||||
mDataPumpTimer = nsnull;
|
||||
}
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
// 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.
|
||||
NS_IMETHODIMP
|
||||
ns4xPluginStreamListener::OnDataAvailable(nsIPluginStreamInfo* pluginInfo,
|
||||
nsIInputStream* input,
|
||||
PRUint32 length)
|
||||
{
|
||||
nsresult rv = NS_ERROR_FAILURE;
|
||||
if (!mInst || !mInst->IsStarted())
|
||||
return rv;
|
||||
return NS_ERROR_FAILURE;
|
||||
|
||||
// Just in case the caller switches plugin info on us.
|
||||
mStreamInfo = pluginInfo;
|
||||
|
||||
const NPPluginFuncs *callbacks = nsnull;
|
||||
mInst->GetCallbacks(&callbacks);
|
||||
// check out if plugin implements NPP_Write call
|
||||
if(!callbacks || !callbacks->write || !length)
|
||||
return rv; // it'll cancel necko transaction
|
||||
return NS_ERROR_FAILURE; // it'll cancel necko transaction
|
||||
|
||||
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.
|
||||
if (length >= MAX_PLUGIN_NECKO_BUFFER) {
|
||||
// ">" is rare case for decoded stream, but lets eat it all
|
||||
mStreamBufferSize = length;
|
||||
} else {
|
||||
PRUint32 contentLength;
|
||||
pluginInfo->GetLength(&contentLength);
|
||||
if (contentLength < MAX_PLUGIN_NECKO_BUFFER) {
|
||||
// this is most common case for contentLength < 16k
|
||||
mStreamBufferSize = length < contentLength ? contentLength:length;
|
||||
} else {
|
||||
mStreamBufferSize = MAX_PLUGIN_NECKO_BUFFER;
|
||||
}
|
||||
}
|
||||
// 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);
|
||||
|
||||
mStreamBufferSize = PR_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 = PR_MIN(mStreamBufferSize, MAX_PLUGIN_NECKO_BUFFER);
|
||||
|
||||
mStreamBuffer = (char*) PR_Malloc(mStreamBufferSize);
|
||||
if (!mStreamBuffer)
|
||||
return NS_ERROR_OUT_OF_MEMORY;
|
||||
}
|
||||
|
||||
// prepare NPP_ calls params
|
||||
NPP npp;
|
||||
NPP npp;
|
||||
mInst->GetNPP(&npp);
|
||||
PRInt32 streamOffset;
|
||||
pluginInfo->GetStreamOffset(&streamOffset);
|
||||
mPosition = streamOffset;
|
||||
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);
|
||||
PRInt32 streamPosition;
|
||||
pluginInfo->GetStreamOffset(&streamPosition);
|
||||
PRInt32 streamOffset = streamPosition;
|
||||
|
||||
// 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)mNPStream.end < streamOffset)
|
||||
mNPStream.end = streamOffset;
|
||||
if (input) {
|
||||
streamOffset += length;
|
||||
|
||||
do
|
||||
{
|
||||
PRUint32 bytesToRead = PR_MIN(length, mStreamBufferSize);
|
||||
PRInt32 amountRead = 0;
|
||||
rv = input->Read(mStreamBuffer, bytesToRead, (PRUint32*)&amountRead);
|
||||
if (amountRead == 0 || NS_FAILED(rv)) {
|
||||
NS_WARNING("input->Read() returns no data, it's almost impossible to get here");
|
||||
break;
|
||||
// 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);
|
||||
|
||||
// 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)mNPStream.end < streamOffset)
|
||||
mNPStream.end = streamOffset;
|
||||
}
|
||||
|
||||
nsresult rv = NS_OK;
|
||||
while (NS_SUCCEEDED(rv) && length > 0) {
|
||||
if (input && length) {
|
||||
if (mStreamBufferSize < mStreamBufferByteCount + length &&
|
||||
mIsSuspended) {
|
||||
// We're in the ::OnDataAvailable() call that we might get
|
||||
// after suspending a request, or we suspended the request
|
||||
// from within this ::OnDataAvailable() call while there's
|
||||
// still data in the input, and we don't have enough space to
|
||||
// store what we got off the network. Reallocate our internal
|
||||
// buffer.
|
||||
mStreamBufferSize = mStreamBufferByteCount + length;
|
||||
char *buf = (char *)PR_Realloc(mStreamBuffer, mStreamBufferSize);
|
||||
if (!buf)
|
||||
return NS_ERROR_OUT_OF_MEMORY;
|
||||
|
||||
mStreamBuffer = buf;
|
||||
}
|
||||
|
||||
PRUint32 bytesToRead =
|
||||
PR_MIN(length, mStreamBufferSize - mStreamBufferByteCount);
|
||||
|
||||
PRUint32 amountRead = 0;
|
||||
rv = input->Read(mStreamBuffer + mStreamBufferByteCount, bytesToRead,
|
||||
&amountRead);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
if (amountRead == 0) {
|
||||
NS_NOTREACHED("input->Read() returns no data, it's almost impossible "
|
||||
"to get here");
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
mStreamBufferByteCount += amountRead;
|
||||
length -= amountRead;
|
||||
} else {
|
||||
// No input, nothing to read. Set length to 0 so that we don't
|
||||
// keep iterating through this outer loop any more.
|
||||
|
||||
length = 0;
|
||||
}
|
||||
|
||||
// this loop in general case will end on length <= 0, without extra input->Read() call
|
||||
length -= amountRead;
|
||||
|
||||
char *ptrStreamBuffer = mStreamBuffer; // tmp ptr
|
||||
// Temporary pointer to the beginning of the data we're writing as
|
||||
// we loop and feed the plugin data.
|
||||
char *ptrStreamBuffer = mStreamBuffer;
|
||||
|
||||
// it is possible plugin's NPP_Write() returns 0 byte consumed
|
||||
// we use zeroBytesWriteCount to count situation like this
|
||||
// and break the loop
|
||||
// it is possible plugin's NPP_Write() returns 0 byte consumed. We
|
||||
// use zeroBytesWriteCount to count situation like this and break
|
||||
// the loop
|
||||
PRInt32 zeroBytesWriteCount = 0;
|
||||
|
||||
// amountRead tells us how many bytes were put in the buffer
|
||||
// WriteReady returns to us how many bytes the plugin is
|
||||
// ready to handle - we have to keep calling WriteReady and
|
||||
// Write until amountRead > 0
|
||||
for(;;)
|
||||
{ // it breaks on (amountRead <= 0) or on error
|
||||
PRInt32 numtowrite;
|
||||
if (callbacks->writeready)
|
||||
{
|
||||
|
||||
// mStreamBufferByteCount tells us how many bytes there are in the
|
||||
// buffer. WriteReady returns to us how many bytes the plugin is
|
||||
// ready to handle.
|
||||
while (mStreamBufferByteCount > 0) {
|
||||
PRInt32 numtowrite;
|
||||
if (callbacks->writeready) {
|
||||
NS_TRY_SAFE_CALL_RETURN(numtowrite,
|
||||
CallNPP_WriteReadyProc(callbacks->writeready, npp, &mNPStream),
|
||||
mInst->fLibrary, mInst);
|
||||
|
||||
CallNPP_WriteReadyProc(callbacks->writeready,
|
||||
npp, &mNPStream),
|
||||
mInst->fLibrary, mInst);
|
||||
|
||||
NPP_PLUGIN_LOG(PLUGIN_LOG_NOISY,
|
||||
("NPP WriteReady called: this=%p, npp=%p, return(towrite)=%d, url=%s\n",
|
||||
this, npp, numtowrite, mNPStream.url));
|
||||
|
||||
// if WriteReady returned 0, the plugin is not ready to handle
|
||||
// the data, return FAILURE for now
|
||||
("NPP WriteReady called: this=%p, npp=%p, "
|
||||
"return(towrite)=%d, url=%s\n",
|
||||
this, npp, numtowrite, mNPStream.url));
|
||||
|
||||
// if WriteReady returned 0, the plugin is not ready to handle
|
||||
// the data, suspend the stream (if it isn't already
|
||||
// suspended).
|
||||
if (numtowrite <= 0) {
|
||||
NS_ASSERTION(numtowrite,"WriteReady returned Zero");
|
||||
rv = NS_ERROR_FAILURE;
|
||||
if (!mIsSuspended) {
|
||||
rv = SuspendRequest();
|
||||
}
|
||||
|
||||
// Break out of the inner loop, but keep going through the
|
||||
// outer loop in case there's more data to read from the
|
||||
// input stream.
|
||||
|
||||
break;
|
||||
}
|
||||
if (numtowrite > amountRead)
|
||||
numtowrite = amountRead;
|
||||
|
||||
numtowrite = PR_MIN(numtowrite, mStreamBufferByteCount);
|
||||
} else {
|
||||
// if WriteReady is not supported by the plugin, just write
|
||||
// the whole buffer
|
||||
numtowrite = mStreamBufferByteCount;
|
||||
}
|
||||
else
|
||||
{
|
||||
// if WriteReady is not supported by the plugin,
|
||||
// just write the whole buffer
|
||||
numtowrite = amountRead;
|
||||
}
|
||||
|
||||
PRInt32 writeCount = 0; // bytes consumed by plugin instance
|
||||
|
||||
|
||||
PRInt32 writeCount = 0; // bytes consumed by plugin instance
|
||||
NS_TRY_SAFE_CALL_RETURN(writeCount,
|
||||
CallNPP_WriteProc(callbacks->write, npp, &mNPStream, mPosition, numtowrite, (void *)ptrStreamBuffer),
|
||||
mInst->fLibrary, mInst);
|
||||
|
||||
CallNPP_WriteProc(callbacks->write, npp,
|
||||
&mNPStream, streamPosition,
|
||||
numtowrite,
|
||||
ptrStreamBuffer),
|
||||
mInst->fLibrary, mInst);
|
||||
|
||||
NPP_PLUGIN_LOG(PLUGIN_LOG_NOISY,
|
||||
("NPP Write called: this=%p, npp=%p, pos=%d, len=%d, buf=%s, return(written)=%d, url=%s\n",
|
||||
this, npp, mPosition, numtowrite, (char *)ptrStreamBuffer, writeCount, mNPStream.url));
|
||||
|
||||
if (writeCount > 0)
|
||||
{
|
||||
mPosition += writeCount;
|
||||
amountRead -= writeCount;
|
||||
if (amountRead <= 0)
|
||||
break; // in common case we'll break for(;;) loop here
|
||||
|
||||
("NPP Write called: this=%p, npp=%p, pos=%d, len=%d, "
|
||||
"buf=%s, return(written)=%d, url=%s\n",
|
||||
this, npp, streamPosition, numtowrite,
|
||||
ptrStreamBuffer, writeCount, mNPStream.url));
|
||||
|
||||
if (writeCount > 0) {
|
||||
NS_ASSERTION(writeCount <= mStreamBufferByteCount,
|
||||
"Plugin read past the end of the available data!");
|
||||
|
||||
writeCount = PR_MIN(writeCount, mStreamBufferByteCount);
|
||||
mStreamBufferByteCount -= writeCount;
|
||||
|
||||
streamPosition += writeCount;
|
||||
|
||||
zeroBytesWriteCount = 0;
|
||||
if (writeCount % sizeof(long)) {
|
||||
// memmove will take care about alignment
|
||||
memmove(ptrStreamBuffer,ptrStreamBuffer+writeCount,amountRead);
|
||||
} else {
|
||||
// if aligned we can use ptrStreamBuffer += to eliminate memmove()
|
||||
ptrStreamBuffer += writeCount;
|
||||
|
||||
if (mStreamBufferByteCount > 0) {
|
||||
// This alignment code is most likely bogus, but we'll leave
|
||||
// it in for now in case it matters for some plugins on some
|
||||
// architectures. Who knows...
|
||||
if (writeCount % sizeof(PRWord)) {
|
||||
// memmove will take care about alignment
|
||||
memmove(mStreamBuffer, ptrStreamBuffer + writeCount,
|
||||
mStreamBufferByteCount);
|
||||
ptrStreamBuffer = mStreamBuffer;
|
||||
} else {
|
||||
// if aligned we can use ptrStreamBuffer += to eliminate
|
||||
// memmove()
|
||||
ptrStreamBuffer += writeCount;
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (writeCount == 0)
|
||||
{
|
||||
// if NPP_Write() returns writeCount == 0 lets say 3 times in a raw
|
||||
// lets consider this as end of ODA call (plugin isn't hungry, or broken) without an error.
|
||||
if (++zeroBytesWriteCount == 3)
|
||||
{
|
||||
length = 0; // break do{}while
|
||||
rv = NS_OK;
|
||||
} else if (writeCount == 0) {
|
||||
// if NPP_Write() returns writeCount == 0 lets say 3 times in
|
||||
// a row, suspend the request and continue feeding the plugin
|
||||
// the data we got so far. Once that data is consumed, we'll
|
||||
// resume the request.
|
||||
if (mIsSuspended || ++zeroBytesWriteCount == 3) {
|
||||
if (!mIsSuspended) {
|
||||
rv = SuspendRequest();
|
||||
}
|
||||
|
||||
// Break out of the for loop, but keep going through the
|
||||
// while loop in case there's more data to read from the
|
||||
// input stream.
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
length = 0; // break do{}while
|
||||
} else {
|
||||
// Something's really wrong, kill the stream.
|
||||
rv = NS_ERROR_FAILURE;
|
||||
|
||||
break;
|
||||
}
|
||||
} // end of for(;;)
|
||||
} while ((PRInt32)(length) > 0);
|
||||
} // end of inner while loop
|
||||
|
||||
return rv == NS_BASE_STREAM_WOULD_BLOCK ? NS_OK:rv;
|
||||
if (mStreamBufferByteCount && mStreamBuffer != ptrStreamBuffer) {
|
||||
memmove(mStreamBuffer, ptrStreamBuffer, mStreamBufferByteCount);
|
||||
}
|
||||
}
|
||||
|
||||
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);
|
||||
|
||||
if (postWriteStreamPosition == streamOffset) {
|
||||
pluginInfo->SetStreamOffset(streamPosition);
|
||||
}
|
||||
}
|
||||
|
||||
return rv;
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
@@ -504,6 +654,20 @@ NS_IMETHODIMP
|
||||
ns4xPluginStreamListener::OnStopBinding(nsIPluginStreamInfo* pluginInfo,
|
||||
nsresult status)
|
||||
{
|
||||
StopDataPump();
|
||||
|
||||
if (mIsSuspended && NS_FAILED(status)) {
|
||||
// We're suspended, and the stream was destroyed, or died for some
|
||||
// reason. Make sure we cancel the suspended request.
|
||||
nsCOMPtr<nsI4xPluginStreamInfo> pluginInfo4x =
|
||||
do_QueryInterface(mStreamInfo);
|
||||
|
||||
nsIRequest *request;
|
||||
if (pluginInfo4x && (request = pluginInfo4x->GetRequest())) {
|
||||
request->Cancel(status);
|
||||
}
|
||||
}
|
||||
|
||||
if(!mInst || !mInst->IsStarted())
|
||||
return NS_ERROR_FAILURE;
|
||||
|
||||
@@ -518,7 +682,7 @@ ns4xPluginStreamListener::OnStopBinding(nsIPluginStreamInfo* pluginInfo,
|
||||
|
||||
rv = CleanUpStream(reason);
|
||||
}
|
||||
|
||||
|
||||
if(rv != NPERR_NO_ERROR)
|
||||
return NS_ERROR_FAILURE;
|
||||
|
||||
@@ -532,6 +696,39 @@ ns4xPluginStreamListener::GetStreamType(nsPluginStreamType *result)
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
ns4xPluginStreamListener::Notify(nsITimer *aTimer)
|
||||
{
|
||||
NS_ASSERTION(aTimer == mDataPumpTimer, "Uh, wrong timer?");
|
||||
|
||||
PRInt32 oldStreamBufferByteCount = mStreamBufferByteCount;
|
||||
|
||||
nsresult rv = OnDataAvailable(mStreamInfo, 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 &&
|
||||
((mStreamStarted && mStreamBufferByteCount < 1024) ||
|
||||
mStreamBufferByteCount == 0)) {
|
||||
// The plugin read some data and we've got less than 1024 bytes in
|
||||
// our buffer (or its empty and the stream is already
|
||||
// done). Resume the request so that we get more data off the
|
||||
// network.
|
||||
|
||||
ResumeRequest();
|
||||
|
||||
// Necko will pump data now that we've resumed the request.
|
||||
StopDataPump();
|
||||
}
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
nsInstanceStream::nsInstanceStream()
|
||||
@@ -553,7 +750,8 @@ NS_IMPL_ISUPPORTS2(ns4xPluginInstance, nsIPluginInstance, nsIScriptablePlugin)
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
ns4xPluginInstance :: ns4xPluginInstance(NPPluginFuncs* callbacks, PRLibrary* aLibrary)
|
||||
ns4xPluginInstance::ns4xPluginInstance(NPPluginFuncs* callbacks,
|
||||
PRLibrary* aLibrary)
|
||||
: fCallbacks(callbacks)
|
||||
{
|
||||
NS_ASSERTION(fCallbacks != NULL, "null callbacks");
|
||||
@@ -575,7 +773,7 @@ ns4xPluginInstance :: ns4xPluginInstance(NPPluginFuncs* callbacks, PRLibrary* aL
|
||||
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
ns4xPluginInstance :: ~ns4xPluginInstance(void)
|
||||
ns4xPluginInstance::~ns4xPluginInstance(void)
|
||||
{
|
||||
PLUGIN_LOG(PLUGIN_LOG_BASIC, ("ns4xPluginInstance dtor: this=%p\n",this));
|
||||
|
||||
@@ -599,7 +797,7 @@ ns4xPluginInstance :: ~ns4xPluginInstance(void)
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
PRBool
|
||||
ns4xPluginInstance :: IsStarted(void)
|
||||
ns4xPluginInstance::IsStarted(void)
|
||||
{
|
||||
return mStarted;
|
||||
}
|
||||
@@ -1220,8 +1418,8 @@ nsresult ns4xPluginInstance::GetValueInternal(NPPVariable variable, void* value)
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////////////////
|
||||
NS_IMETHODIMP ns4xPluginInstance :: GetValue(nsPluginInstanceVariable variable,
|
||||
void *value)
|
||||
NS_IMETHODIMP ns4xPluginInstance::GetValue(nsPluginInstanceVariable variable,
|
||||
void *value)
|
||||
{
|
||||
nsresult res = NS_OK;
|
||||
|
||||
@@ -1275,7 +1473,7 @@ nsresult ns4xPluginInstance::GetCallbacks(const NPPluginFuncs ** aCallbacks)
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////////////////
|
||||
nsresult ns4xPluginInstance :: SetWindowless(PRBool aWindowless)
|
||||
nsresult ns4xPluginInstance::SetWindowless(PRBool aWindowless)
|
||||
{
|
||||
mWindowless = aWindowless;
|
||||
return NS_OK;
|
||||
@@ -1283,7 +1481,7 @@ nsresult ns4xPluginInstance :: SetWindowless(PRBool aWindowless)
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////////////////
|
||||
nsresult ns4xPluginInstance :: SetTransparent(PRBool aTransparent)
|
||||
nsresult ns4xPluginInstance::SetTransparent(PRBool aTransparent)
|
||||
{
|
||||
mTransparent = aTransparent;
|
||||
return NS_OK;
|
||||
@@ -1291,7 +1489,7 @@ nsresult ns4xPluginInstance :: SetTransparent(PRBool aTransparent)
|
||||
|
||||
////////////////////////////////////////////////////////////////////////
|
||||
/* readonly attribute nsQIResult scriptablePeer; */
|
||||
NS_IMETHODIMP ns4xPluginInstance :: GetScriptablePeer(void * *aScriptablePeer)
|
||||
NS_IMETHODIMP ns4xPluginInstance::GetScriptablePeer(void * *aScriptablePeer)
|
||||
{
|
||||
if (!aScriptablePeer)
|
||||
return NS_ERROR_NULL_POINTER;
|
||||
@@ -1303,7 +1501,7 @@ NS_IMETHODIMP ns4xPluginInstance :: GetScriptablePeer(void * *aScriptablePeer)
|
||||
|
||||
////////////////////////////////////////////////////////////////////////
|
||||
/* readonly attribute nsIIDPtr scriptableInterface; */
|
||||
NS_IMETHODIMP ns4xPluginInstance :: GetScriptableInterface(nsIID * *aScriptableInterface)
|
||||
NS_IMETHODIMP ns4xPluginInstance::GetScriptableInterface(nsIID * *aScriptableInterface)
|
||||
{
|
||||
if (!aScriptableInterface)
|
||||
return NS_ERROR_NULL_POINTER;
|
||||
|
||||
@@ -40,28 +40,47 @@
|
||||
|
||||
#include "nsIPluginStreamListener.h"
|
||||
#include "nsIPluginStreamInfo.h"
|
||||
#include "nsIRequest.h"
|
||||
#include "nsITimer.h"
|
||||
#include "nsCOMPtr.h"
|
||||
|
||||
#define MAX_PLUGIN_NECKO_BUFFER 16384
|
||||
|
||||
class ns4xPluginStreamListener : public nsIPluginStreamListener
|
||||
class ns4xPluginInstance;
|
||||
class nsI4xPluginStreamInfo;
|
||||
|
||||
class ns4xPluginStreamListener : public nsIPluginStreamListener,
|
||||
public nsITimerCallback
|
||||
{
|
||||
public:
|
||||
NS_DECL_ISUPPORTS
|
||||
|
||||
// from nsIPluginStreamListener:
|
||||
NS_IMETHOD OnStartBinding(nsIPluginStreamInfo* pluginInfo);
|
||||
NS_IMETHOD OnDataAvailable(nsIPluginStreamInfo* pluginInfo, nsIInputStream* input, PRUint32 length);
|
||||
NS_IMETHOD OnFileAvailable( nsIPluginStreamInfo* pluginInfo, const char* fileName);
|
||||
NS_IMETHOD OnDataAvailable(nsIPluginStreamInfo* pluginInfo,
|
||||
nsIInputStream* input, PRUint32 length);
|
||||
NS_IMETHOD OnFileAvailable( nsIPluginStreamInfo* pluginInfo,
|
||||
const char* fileName);
|
||||
NS_IMETHOD OnStopBinding(nsIPluginStreamInfo* pluginInfo, nsresult status);
|
||||
NS_IMETHOD GetStreamType(nsPluginStreamType *result);
|
||||
|
||||
NS_DECL_NSITIMERCALLBACK
|
||||
|
||||
// ns4xPluginStreamListener specific methods:
|
||||
ns4xPluginStreamListener(nsIPluginInstance* inst, void* notifyData, const char* aURL);
|
||||
ns4xPluginStreamListener(nsIPluginInstance* inst, void* notifyData,
|
||||
const char* aURL);
|
||||
virtual ~ns4xPluginStreamListener();
|
||||
PRBool IsStarted();
|
||||
nsresult CleanUpStream(NPReason reason);
|
||||
void CallURLNotify(NPReason reason);
|
||||
void SetCallNotify(PRBool aCallNotify) { mCallNotify = aCallNotify; }
|
||||
void SetCallNotify(PRBool aCallNotify)
|
||||
{
|
||||
mCallNotify = aCallNotify;
|
||||
}
|
||||
nsresult SuspendRequest();
|
||||
void ResumeRequest();
|
||||
nsresult StartDataPump();
|
||||
void StopDataPump();
|
||||
|
||||
protected:
|
||||
void* mNotifyData;
|
||||
@@ -69,16 +88,38 @@ protected:
|
||||
char* mNotifyURL;
|
||||
ns4xPluginInstance* mInst;
|
||||
NPStream mNPStream;
|
||||
PRUint32 mPosition;
|
||||
PRUint32 mStreamBufferSize;
|
||||
PRInt32 mStreamBufferByteCount;
|
||||
nsPluginStreamType mStreamType;
|
||||
PRPackedBool mStreamStarted;
|
||||
PRPackedBool mStreamCleanedUp;
|
||||
PRPackedBool mCallNotify;
|
||||
PRPackedBool mIsSuspended;
|
||||
|
||||
nsCOMPtr<nsITimer> mDataPumpTimer;
|
||||
|
||||
public:
|
||||
nsIPluginStreamInfo * mStreamInfo;
|
||||
nsCOMPtr<nsIPluginStreamInfo> mStreamInfo;
|
||||
};
|
||||
|
||||
// nsI4xPluginStreamInfo is an internal helper interface that exposes
|
||||
// the underlying necko request to consumers of nsIPluginStreamInfo's.
|
||||
#define NS_I4XPLUGINSTREAMINFO_IID \
|
||||
{ 0x097fdaaa, 0xa2a3, 0x49c2, \
|
||||
{0x91, 0xee, 0xeb, 0xc5, 0x7d, 0x6c, 0x9c, 0x97} }
|
||||
|
||||
class nsI4xPluginStreamInfo : public nsIPluginStreamInfo
|
||||
{
|
||||
public:
|
||||
NS_DEFINE_STATIC_IID_ACCESSOR(NS_I4XPLUGINSTREAMINFO_IID)
|
||||
|
||||
nsIRequest *GetRequest()
|
||||
{
|
||||
return mRequest;
|
||||
}
|
||||
|
||||
protected:
|
||||
nsCOMPtr<nsIRequest> mRequest;
|
||||
};
|
||||
|
||||
#endif
|
||||
|
||||
@@ -45,6 +45,7 @@
|
||||
#include "prio.h"
|
||||
#include "prmem.h"
|
||||
#include "ns4xPlugin.h"
|
||||
#include "ns4xPluginStreamListener.h"
|
||||
#include "nsPluginInstancePeer.h"
|
||||
#include "nsIPlugin.h"
|
||||
#ifdef OJI
|
||||
@@ -1093,7 +1094,7 @@ PRBool nsPluginTag::Equals(nsPluginTag *aPluginTag)
|
||||
////////////////////////////////////////////////////////////////////////
|
||||
class nsPluginStreamListenerPeer;
|
||||
|
||||
class nsPluginStreamInfo : public nsIPluginStreamInfo
|
||||
class nsPluginStreamInfo : public nsI4xPluginStreamInfo
|
||||
{
|
||||
public:
|
||||
nsPluginStreamInfo();
|
||||
@@ -1159,6 +1160,12 @@ public:
|
||||
void
|
||||
SetStreamComplete(const PRBool complete);
|
||||
|
||||
void
|
||||
SetRequest(nsIRequest *request)
|
||||
{
|
||||
mRequest = request;
|
||||
}
|
||||
|
||||
private:
|
||||
|
||||
char* mContentType;
|
||||
@@ -1216,7 +1223,7 @@ private:
|
||||
nsIPluginInstanceOwner *mOwner;
|
||||
nsIPluginInstance *mInstance;
|
||||
nsIPluginStreamListener *mPStreamListener;
|
||||
nsPluginStreamInfo *mPluginStreamInfo;
|
||||
nsRefPtr<nsPluginStreamInfo> mPluginStreamInfo;
|
||||
|
||||
// Set to PR_TRUE if we request failed (like with a HTTP response of 404)
|
||||
PRPackedBool mRequestFailed;
|
||||
@@ -1297,37 +1304,10 @@ nsPluginStreamInfo::~nsPluginStreamInfo()
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////
|
||||
NS_IMPL_ADDREF(nsPluginStreamInfo)
|
||||
NS_IMPL_RELEASE(nsPluginStreamInfo)
|
||||
NS_IMPL_ISUPPORTS2(nsPluginStreamInfo, nsIPluginStreamInfo,
|
||||
nsI4xPluginStreamInfo)
|
||||
////////////////////////////////////////////////////////////////////////
|
||||
|
||||
nsresult nsPluginStreamInfo::QueryInterface(const nsIID& aIID,
|
||||
void** aInstancePtrResult)
|
||||
{
|
||||
NS_PRECONDITION(nsnull != aInstancePtrResult, "null pointer");
|
||||
|
||||
if (nsnull == aInstancePtrResult)
|
||||
return NS_ERROR_NULL_POINTER;
|
||||
|
||||
if (aIID.Equals(kIPluginStreamInfoIID))
|
||||
{
|
||||
*aInstancePtrResult = (void *)((nsIPluginStreamInfo *)this);
|
||||
AddRef();
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
if (aIID.Equals(kISupportsIID))
|
||||
{
|
||||
*aInstancePtrResult = (void *)((nsISupports *)((nsIStreamListener *)this));
|
||||
AddRef();
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
return NS_NOINTERFACE;
|
||||
}
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////////////////
|
||||
NS_IMETHODIMP
|
||||
nsPluginStreamInfo::GetContentType(nsMIMEType* result)
|
||||
{
|
||||
@@ -1335,8 +1315,6 @@ nsPluginStreamInfo::GetContentType(nsMIMEType* result)
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////////////////
|
||||
NS_IMETHODIMP
|
||||
nsPluginStreamInfo::IsSeekable(PRBool* result)
|
||||
{
|
||||
@@ -1344,8 +1322,6 @@ nsPluginStreamInfo::IsSeekable(PRBool* result)
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////////////////
|
||||
NS_IMETHODIMP
|
||||
nsPluginStreamInfo::GetLength(PRUint32* result)
|
||||
{
|
||||
@@ -1353,8 +1329,6 @@ nsPluginStreamInfo::GetLength(PRUint32* result)
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////////////////
|
||||
NS_IMETHODIMP
|
||||
nsPluginStreamInfo::GetLastModified(PRUint32* result)
|
||||
{
|
||||
@@ -1362,8 +1336,6 @@ nsPluginStreamInfo::GetLastModified(PRUint32* result)
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////////////////
|
||||
NS_IMETHODIMP
|
||||
nsPluginStreamInfo::GetURL(const char** result)
|
||||
{
|
||||
@@ -1371,9 +1343,6 @@ nsPluginStreamInfo::GetURL(const char** result)
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////////////////
|
||||
void
|
||||
nsPluginStreamInfo::MakeByteRangeString(nsByteRange* aRangeList, nsACString &rangeRequest, PRInt32 *numRequests)
|
||||
{
|
||||
@@ -1647,7 +1616,6 @@ nsPluginStreamListenerPeer::nsPluginStreamListenerPeer()
|
||||
mOwner = nsnull;
|
||||
mInstance = nsnull;
|
||||
mPStreamListener = nsnull;
|
||||
mPluginStreamInfo = nsnull;
|
||||
mHost = nsnull;
|
||||
mStreamType = nsPluginStreamType_Normal;
|
||||
mStartBinding = PR_FALSE;
|
||||
@@ -1677,7 +1645,6 @@ nsPluginStreamListenerPeer::~nsPluginStreamListenerPeer()
|
||||
NS_IF_RELEASE(mInstance);
|
||||
NS_IF_RELEASE(mPStreamListener);
|
||||
NS_IF_RELEASE(mHost);
|
||||
NS_IF_RELEASE(mPluginStreamInfo);
|
||||
|
||||
// close FD of mFileCacheOutputStream if it's still open
|
||||
// or we won't be able to remove the cache file
|
||||
@@ -1747,7 +1714,6 @@ nsresult nsPluginStreamListenerPeer::Initialize(nsIURI *aURL,
|
||||
if (!mPluginStreamInfo)
|
||||
return NS_ERROR_OUT_OF_MEMORY;
|
||||
|
||||
NS_ADDREF(mPluginStreamInfo);
|
||||
mPluginStreamInfo->SetPluginInstance(aInstance);
|
||||
mPluginStreamInfo->SetPluginStreamListenerPeer(this);
|
||||
|
||||
@@ -1802,7 +1768,6 @@ nsresult nsPluginStreamListenerPeer::InitializeEmbeded(nsIURI *aURL,
|
||||
if (!mPluginStreamInfo)
|
||||
return NS_ERROR_OUT_OF_MEMORY;
|
||||
|
||||
NS_ADDREF(mPluginStreamInfo);
|
||||
mPluginStreamInfo->SetPluginInstance(aInstance);
|
||||
mPluginStreamInfo->SetPluginStreamListenerPeer(this);
|
||||
|
||||
@@ -1829,7 +1794,6 @@ nsresult nsPluginStreamListenerPeer::InitializeFullPage(nsIPluginInstance *aInst
|
||||
if (!mPluginStreamInfo)
|
||||
return NS_ERROR_OUT_OF_MEMORY;
|
||||
|
||||
NS_ADDREF(mPluginStreamInfo);
|
||||
mPluginStreamInfo->SetPluginInstance(aInstance);
|
||||
mPluginStreamInfo->SetPluginStreamListenerPeer(this);
|
||||
|
||||
@@ -2023,6 +1987,8 @@ nsPluginStreamListenerPeer::OnStartRequest(nsIRequest *request, nsISupports* aCo
|
||||
mPluginStreamInfo->SetLength(length);
|
||||
}
|
||||
|
||||
mPluginStreamInfo->SetRequest(request);
|
||||
|
||||
nsCAutoString aContentType;
|
||||
rv = channel->GetContentType(aContentType);
|
||||
if (NS_FAILED(rv))
|
||||
@@ -2176,6 +2142,8 @@ NS_IMETHODIMP nsPluginStreamListenerPeer::OnDataAvailable(nsIRequest *request,
|
||||
if(!mPStreamListener || !mPluginStreamInfo)
|
||||
return NS_ERROR_FAILURE;
|
||||
|
||||
mPluginStreamInfo->SetRequest(request);
|
||||
|
||||
const char * url = nsnull;
|
||||
mPluginStreamInfo->GetURL(&url);
|
||||
|
||||
@@ -2190,21 +2158,25 @@ NS_IMETHODIMP nsPluginStreamListenerPeer::OnDataAvailable(nsIRequest *request,
|
||||
// get the absolute offset of the request, if one exists.
|
||||
nsCOMPtr<nsIByteRangeRequest> brr = do_QueryInterface(request);
|
||||
PRInt32 absoluteOffset = 0;
|
||||
PRInt32 amtForwardToPlugin = 0;
|
||||
if (brr) {
|
||||
brr->GetStartRange(&absoluteOffset);
|
||||
|
||||
// we need to track how much data we have forward on to the plugin.
|
||||
nsPRUintKey key(absoluteOffset);
|
||||
if (!mDataForwardToRequest)
|
||||
return NS_ERROR_FAILURE;
|
||||
|
||||
if (!mDataForwardToRequest)
|
||||
return NS_ERROR_FAILURE;
|
||||
brr->GetStartRange(&absoluteOffset);
|
||||
|
||||
if (mDataForwardToRequest->Exists(&key))
|
||||
amtForwardToPlugin = NS_PTR_TO_INT32(mDataForwardToRequest->Remove(&key));
|
||||
|
||||
mDataForwardToRequest->Put(&key, (void*) (amtForwardToPlugin+aLength));
|
||||
mPluginStreamInfo->SetStreamOffset(absoluteOffset + amtForwardToPlugin);
|
||||
// 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*?
|
||||
nsPRUintKey key(absoluteOffset);
|
||||
PRInt32 amtForwardToPlugin =
|
||||
NS_PTR_TO_INT32(mDataForwardToRequest->Get(&key));
|
||||
mDataForwardToRequest->Put(&key, NS_INT32_TO_PTR(amtForwardToPlugin + aLength));
|
||||
|
||||
mPluginStreamInfo->SetStreamOffset(absoluteOffset + amtForwardToPlugin);
|
||||
}
|
||||
|
||||
nsCOMPtr<nsIInputStream> stream = aIStream;
|
||||
@@ -2219,9 +2191,9 @@ NS_IMETHODIMP nsPluginStreamListenerPeer::OnDataAvailable(nsIRequest *request,
|
||||
return rv;
|
||||
}
|
||||
|
||||
rv = mPStreamListener->OnDataAvailable((nsIPluginStreamInfo*)mPluginStreamInfo,
|
||||
stream,
|
||||
aLength);
|
||||
rv = mPStreamListener->OnDataAvailable(mPluginStreamInfo,
|
||||
stream,
|
||||
aLength);
|
||||
|
||||
// if a plugin returns an error, the peer must kill the stream
|
||||
// else the stream and PluginStreamListener leak
|
||||
@@ -2317,7 +2289,7 @@ NS_IMETHODIMP nsPluginStreamListenerPeer::OnStopRequest(nsIRequest *request,
|
||||
if (NS_FAILED(aStatus)) {
|
||||
// on error status cleanup the stream
|
||||
// and return w/o OnFileAvailable()
|
||||
mPStreamListener->OnStopBinding((nsIPluginStreamInfo*)mPluginStreamInfo, aStatus);
|
||||
mPStreamListener->OnStopBinding(mPluginStreamInfo, aStatus);
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
@@ -2345,13 +2317,13 @@ NS_IMETHODIMP nsPluginStreamListenerPeer::OnStopRequest(nsIRequest *request,
|
||||
if (mStartBinding)
|
||||
{
|
||||
// On start binding has been called
|
||||
mPStreamListener->OnStopBinding((nsIPluginStreamInfo*)mPluginStreamInfo, aStatus);
|
||||
mPStreamListener->OnStopBinding(mPluginStreamInfo, aStatus);
|
||||
}
|
||||
else
|
||||
{
|
||||
// OnStartBinding hasn't been called, so complete the action.
|
||||
mPStreamListener->OnStartBinding((nsIPluginStreamInfo*)mPluginStreamInfo);
|
||||
mPStreamListener->OnStopBinding((nsIPluginStreamInfo*)mPluginStreamInfo, aStatus);
|
||||
mPStreamListener->OnStartBinding(mPluginStreamInfo);
|
||||
mPStreamListener->OnStopBinding(mPluginStreamInfo, aStatus);
|
||||
}
|
||||
|
||||
if (NS_SUCCEEDED(aStatus))
|
||||
@@ -2449,7 +2421,7 @@ nsresult nsPluginStreamListenerPeer::SetUpStreamListener(nsIRequest *request,
|
||||
}
|
||||
}
|
||||
|
||||
rv = mPStreamListener->OnStartBinding((nsIPluginStreamInfo*)mPluginStreamInfo);
|
||||
rv = mPStreamListener->OnStartBinding(mPluginStreamInfo);
|
||||
|
||||
mStartBinding = PR_TRUE;
|
||||
|
||||
@@ -2495,7 +2467,7 @@ nsPluginStreamListenerPeer::OnFileAvailable(nsIFile* aFile)
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
rv = mPStreamListener->OnFileAvailable((nsIPluginStreamInfo*)mPluginStreamInfo, path.get());
|
||||
rv = mPStreamListener->OnFileAvailable(mPluginStreamInfo, path.get());
|
||||
return rv;
|
||||
}
|
||||
|
||||
@@ -6594,7 +6566,7 @@ nsresult nsPluginStreamListenerPeer::ServeStreamAsFile(nsIRequest *request,
|
||||
}
|
||||
|
||||
mPluginStreamInfo->SetSeekable(0);
|
||||
mPStreamListener->OnStartBinding((nsIPluginStreamInfo*)mPluginStreamInfo);
|
||||
mPStreamListener->OnStartBinding(mPluginStreamInfo);
|
||||
mPluginStreamInfo->SetStreamOffset(0);
|
||||
|
||||
// force the plugin use stream as file
|
||||
@@ -6740,4 +6712,10 @@ void
|
||||
nsPluginStreamInfo::SetStreamComplete(const PRBool complete)
|
||||
{
|
||||
mStreamComplete = complete;
|
||||
|
||||
if (complete) {
|
||||
// We're done, release the request.
|
||||
|
||||
SetRequest(nsnull);
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user