fix 145054, Plugins may starve when cached data they read from is removed too soon; r=av,sr=darin

This commit is contained in:
serge%netscape.com 2002-08-29 22:00:20 +00:00
Родитель be187d5e77
Коммит 1b4cdd623a
2 изменённых файлов: 204 добавлений и 242 удалений

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

@ -276,6 +276,7 @@ static const char *hashValue = "value";
*/ */
#define NS_MIME_TYPES_HASH_NUM (20) #define NS_MIME_TYPES_HASH_NUM (20)
static nsActivePluginList *gActivePluginList;
//////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////
void DisplayNoDefaultPluginDialog(const char *mimeType, nsIPrompt *prompt) void DisplayNoDefaultPluginDialog(const char *mimeType, nsIPrompt *prompt)
@ -485,7 +486,6 @@ nsActivePlugin::nsActivePlugin(nsPluginTag* aPluginTag,
mDefaultPlugin = aDefaultPlugin; mDefaultPlugin = aDefaultPlugin;
mStopped = PR_FALSE; mStopped = PR_FALSE;
mllStopTime = LL_ZERO; mllStopTime = LL_ZERO;
mStreams = new nsVoidArray(); // create a new stream array
} }
@ -493,14 +493,6 @@ nsActivePlugin::nsActivePlugin(nsPluginTag* aPluginTag,
nsActivePlugin::~nsActivePlugin() nsActivePlugin::~nsActivePlugin()
{ {
mPluginTag = nsnull; mPluginTag = nsnull;
// free our streams array
if (mStreams)
{
delete mStreams;
mStreams = nsnull;
}
if(mInstance != nsnull) if(mInstance != nsnull)
{ {
if(mPeer) if(mPeer)
@ -533,24 +525,9 @@ void nsActivePlugin::setStopped(PRBool stopped)
{ {
mStopped = stopped; mStopped = stopped;
if(mStopped) // plugin instance is told to stop if(mStopped) // plugin instance is told to stop
{
mllStopTime = PR_Now(); mllStopTime = PR_Now();
// Since we are "stopped", we should clear our our streams array
if (mStreams)
while (mStreams->Count() > 0 ) // simple loop, always removing the first element
{
nsIStreamListener * s = (nsIStreamListener *) mStreams->ElementAt(0); // XXX nasty cast!
if (s)
{
NS_RELEASE(s); // should cause stream destructions (and prevent leaks!)
mStreams->RemoveElementAt(0);
}
}
}
else else
mllStopTime = LL_ZERO; mllStopTime = LL_ZERO;
} }
@ -1287,30 +1264,18 @@ public:
void void
MakeByteRangeString(nsByteRange* aRangeList, nsACString &string, PRInt32 *numRequests); MakeByteRangeString(nsByteRange* aRangeList, nsACString &string, PRInt32 *numRequests);
void PRBool
SetLocalCachedFile(nsIFile *file); nsPluginStreamInfo::UseExistingPluginCacheFile(nsPluginStreamInfo* psi, nsIFile* file);
void
GetLocalCachedFile(nsIFile** file);
void
SetLocalCachedFileStream(nsIOutputStream *stream);
void
GetLocalCachedFileStream(nsIOutputStream **stream);
private: private:
char* mContentType; char* mContentType;
char* mURL; char* mURL;
nsCOMPtr<nsIFile> mCachedFile;
PRBool mSeekable; PRBool mSeekable;
PRUint32 mLength; PRUint32 mLength;
PRUint32 mModified; PRUint32 mModified;
nsIPluginInstance * mPluginInstance; nsIPluginInstance * mPluginInstance;
nsPluginStreamListenerPeer * mPluginStreamListenerPeer; nsPluginStreamListenerPeer * mPluginStreamListenerPeer;
nsCOMPtr<nsIOutputStream> mFileCacheOutputStream;
PRBool mLocallyCached;
PRInt32 mStreamOffset; PRInt32 mStreamOffset;
}; };
@ -1349,8 +1314,6 @@ public:
nsILoadGroup* GetLoadGroup(); nsILoadGroup* GetLoadGroup();
nsresult SetLocalFile(nsIFile* aFile);
nsresult ServeStreamAsFile(nsIRequest *request, nsISupports *ctxt); nsresult ServeStreamAsFile(nsIRequest *request, nsISupports *ctxt);
private: private:
@ -1359,8 +1322,6 @@ private:
nsresult SetupPluginCacheFile(nsIChannel* channel); nsresult SetupPluginCacheFile(nsIChannel* channel);
nsIURI *mURL; nsIURI *mURL;
nsIPluginInstanceOwner *mOwner; nsIPluginInstanceOwner *mOwner;
nsIPluginInstance *mInstance; nsIPluginInstance *mInstance;
nsIPluginStreamListener *mPStreamListener; nsIPluginStreamListener *mPStreamListener;
@ -1384,8 +1345,10 @@ private:
nsPluginStreamType mStreamType; nsPluginStreamType mStreamType;
nsIPluginHost *mHost; nsIPluginHost *mHost;
// local file which was used to post data and which should be deleted after that // local cached file, we save the content into local cache if browser cache is not available,
nsCOMPtr<nsIFile> mLocalFile; // or plugin asks stream as file and it expects file extension until bug 90558 got fixed
nsIFile *mLocalCachedFile;
nsCOMPtr<nsIOutputStream> mFileCacheOutputStream;
nsHashtable *mDataForwardToRequest; nsHashtable *mDataForwardToRequest;
public: public:
@ -1429,7 +1392,6 @@ nsPluginStreamInfo::nsPluginStreamInfo()
mSeekable = PR_FALSE; mSeekable = PR_FALSE;
mLength = 0; mLength = 0;
mModified = 0; mModified = 0;
mLocallyCached = PR_FALSE;
mStreamOffset = 0; mStreamOffset = 0;
} }
@ -1442,17 +1404,6 @@ nsPluginStreamInfo::~nsPluginStreamInfo()
if(mURL != nsnull) if(mURL != nsnull)
PL_strfree(mURL); PL_strfree(mURL);
// close FD of mFileCacheOutputStream if it's still open
// or we won't be able to remove the cache file
if (mFileCacheOutputStream)
mFileCacheOutputStream->Close();
// ONLY delete our cached file if we created it
if(mLocallyCached && mCachedFile)
{
mCachedFile->Remove(PR_FALSE);
}
NS_IF_RELEASE(mPluginInstance); NS_IF_RELEASE(mPluginInstance);
} }
@ -1705,42 +1656,6 @@ nsPluginStreamInfo::SetURL(const char* url)
mURL = PL_strdup(url); mURL = PL_strdup(url);
} }
////////////////////////////////////////////////////////////////////////
void
nsPluginStreamInfo::SetLocalCachedFile(nsIFile* file)
{
file->Clone(getter_AddRefs(mCachedFile));
}
////////////////////////////////////////////////////////////////////////
void
nsPluginStreamInfo::GetLocalCachedFile(nsIFile** file)
{
*file = mCachedFile;
NS_IF_ADDREF(*file);
}
////////////////////////////////////////////////////////////////////////
void
nsPluginStreamInfo::SetLocalCachedFileStream(nsIOutputStream *stream)
{
mFileCacheOutputStream = stream;
mLocallyCached = PR_TRUE;
}
////////////////////////////////////////////////////////////////////////
void
nsPluginStreamInfo::GetLocalCachedFileStream(nsIOutputStream **stream)
{
if (!stream) return;
NS_IF_ADDREF(*stream = mFileCacheOutputStream);
}
//////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////
void void
nsPluginStreamInfo::SetPluginInstance(nsIPluginInstance * aPluginInstance) nsPluginStreamInfo::SetPluginInstance(nsIPluginInstance * aPluginInstance)
@ -1858,6 +1773,7 @@ nsPluginStreamListenerPeer::nsPluginStreamListenerPeer()
mPendingRequests = 0; mPendingRequests = 0;
mHaveFiredOnStartRequest = PR_FALSE; mHaveFiredOnStartRequest = PR_FALSE;
mDataForwardToRequest = nsnull; mDataForwardToRequest = nsnull;
mLocalCachedFile = nsnull;
} }
@ -1868,13 +1784,8 @@ nsPluginStreamListenerPeer::~nsPluginStreamListenerPeer()
nsCAutoString urlSpec; nsCAutoString urlSpec;
if(mURL != nsnull) (void)mURL->GetSpec(urlSpec); if(mURL != nsnull) (void)mURL->GetSpec(urlSpec);
nsCAutoString filePath;
if(mLocalFile != nsnull) (void)mLocalFile->GetNativePath(filePath);
PR_LOG(nsPluginLogging::gPluginLog, PLUGIN_LOG_NORMAL, PR_LOG(nsPluginLogging::gPluginLog, PLUGIN_LOG_NORMAL,
("nsPluginStreamListenerPeer::dtor this=%p, url=%s, POST_file=%s\n",this, urlSpec.get(), filePath.get())); ("nsPluginStreamListenerPeer::dtor this=%p, url=%s%c",this, urlSpec.get(), mLocalCachedFile?',':'\n'));
PR_LogFlush();
#endif #endif
NS_IF_RELEASE(mURL); NS_IF_RELEASE(mURL);
@ -1884,10 +1795,30 @@ nsPluginStreamListenerPeer::~nsPluginStreamListenerPeer()
NS_IF_RELEASE(mHost); NS_IF_RELEASE(mHost);
NS_IF_RELEASE(mPluginStreamInfo); NS_IF_RELEASE(mPluginStreamInfo);
// if we have mLocalFile (temp file used to post data) it should be // close FD of mFileCacheOutputStream if it's still open
// safe to delete it now, and hopefully the owner doesn't hold it. // or we won't be able to remove the cache file
if(mLocalFile) if (mFileCacheOutputStream)
mLocalFile->Remove(PR_FALSE); mFileCacheOutputStream = nsnull;
// if we have mLocalCachedFile lets release it
// and it'll be fiscally remove if refcnt == 1
if (mLocalCachedFile) {
nsrefcnt refcnt;
NS_RELEASE2(mLocalCachedFile, refcnt);
#ifdef PLUGIN_LOGGING
nsCAutoString filePath;
mLocalCachedFile->GetNativePath(filePath);
PR_LOG(nsPluginLogging::gPluginLog, PLUGIN_LOG_NORMAL,
("LocalyCachedFile=%s has %d refcnt and will %s be deleted now\n",filePath.get(),refcnt,refcnt==1?"":"NOT"));
#endif
if (refcnt == 1) {
mLocalCachedFile->Remove(PR_FALSE);
NS_RELEASE(mLocalCachedFile);
}
}
delete mDataForwardToRequest; delete mDataForwardToRequest;
} }
@ -2037,10 +1968,40 @@ nsresult nsPluginStreamListenerPeer::InitializeFullPage(nsIPluginInstance *aInst
nsresult nsresult
nsPluginStreamListenerPeer::SetupPluginCacheFile(nsIChannel* channel) nsPluginStreamListenerPeer::SetupPluginCacheFile(nsIChannel* channel)
{ {
nsresult rv; nsresult rv = NS_OK;
// lets try to reused a file if we already have in the local plugin cache
// we loop through all of active plugins
// and call |nsPluginStreamInfo::UseExistingPluginCacheFile()| on opened stream
// will return RP_TRUE if file exisrs
// and some conditions are matched, in this case that file will be use
// in |::OnFileAvailable()| calls w/o rewriting the file again.
// The file will be deleted in |nsPluginStreamListenerPeer::~nsPluginStreamListenerPeer|
PRBool useExistingCacheFile = PR_FALSE;
nsActivePlugin *pActivePlugins = gActivePluginList->mFirst;
while (pActivePlugins && pActivePlugins->mStreams && !useExistingCacheFile) {
// most recent streams are at the end of list
PRInt32 cnt;
pActivePlugins->mStreams->Count((PRUint32*)&cnt);
while (--cnt >= 0 && !useExistingCacheFile) {
nsPluginStreamListenerPeer *lp =
NS_REINTERPRET_CAST(nsPluginStreamListenerPeer *, pActivePlugins->mStreams->ElementAt(cnt));
if (lp) {
if (lp->mLocalCachedFile &&
lp->mPluginStreamInfo &&
(useExistingCacheFile =
lp->mPluginStreamInfo->UseExistingPluginCacheFile(mPluginStreamInfo,lp->mLocalCachedFile)))
{
NS_ADDREF(mLocalCachedFile = lp->mLocalCachedFile);
}
NS_RELEASE(lp);
}
}
pActivePlugins = pActivePlugins->mNext;
}
// Is this the best place to put this temp file? if (!useExistingCacheFile) {
nsCOMPtr<nsIFile> pluginTmp; nsCOMPtr<nsIFile> pluginTmp;
// Is this the best place to put this temp file?
rv = NS_GetSpecialDirectory(NS_OS_TEMP_DIR, getter_AddRefs(pluginTmp)); rv = NS_GetSpecialDirectory(NS_OS_TEMP_DIR, getter_AddRefs(pluginTmp));
if (NS_FAILED(rv)) return rv; if (NS_FAILED(rv)) return rv;
@ -2060,26 +2021,47 @@ nsPluginStreamListenerPeer::SetupPluginCacheFile(nsIChannel* channel)
nsCAutoString filename; nsCAutoString filename;
url->GetFileName(filename); url->GetFileName(filename);
if (NS_FAILED(rv)) return rv; if (NS_FAILED(rv))
return rv;
// Create a file to save our stream into. Should we scramble the name? // Create a file to save our stream into. Should we scramble the name?
rv = pluginTmp->AppendNative(filename); rv = pluginTmp->AppendNative(filename);
if (NS_FAILED(rv)) return rv; if (NS_FAILED(rv))
return rv;
// Yes, make it unique. // Yes, make it unique.
rv = pluginTmp->CreateUnique(nsIFile::NORMAL_FILE_TYPE, 0777); rv = pluginTmp->CreateUnique(nsIFile::NORMAL_FILE_TYPE, 0600);
if (NS_FAILED(rv)) return rv; if (NS_FAILED(rv))
return rv;
// save the file.
mPluginStreamInfo->SetLocalCachedFile(pluginTmp);
// create a file output stream to write to... // create a file output stream to write to...
nsCOMPtr<nsIOutputStream> outstream; nsCOMPtr<nsIOutputStream> outstream;
rv = NS_NewLocalFileOutputStream(getter_AddRefs(outstream), pluginTmp, -1, 00600); rv = NS_NewLocalFileOutputStream(getter_AddRefs(mFileCacheOutputStream), pluginTmp, -1, 00600);
if (NS_FAILED(rv)) return rv; if (NS_FAILED(rv))
return rv;
mPluginStreamInfo->SetLocalCachedFileStream(outstream); // save the file.
return NS_OK; CallQueryInterface(pluginTmp, &mLocalCachedFile); // no need to check return value, just addref
// add one extra refcnt, we can use NS_RELEASE2(mLocalCachedFile...) in dtor
// to remove this file when refcnt == 1
NS_ADDREF(mLocalCachedFile);
}
// add this listenerPeer to list of stream peers for this instance
// it'll delay release of listenerPeer until nsActivePlugin::~nsActivePlugin
// and the temp file is going to stay alive until then
pActivePlugins = gActivePluginList->find(mInstance);
if (pActivePlugins) {
if (!pActivePlugins->mStreams &&
(NS_FAILED(rv = NS_NewISupportsArray(getter_AddRefs(pActivePlugins->mStreams))))) {
return rv;
}
nsISupports* supports = NS_STATIC_CAST(nsISupports*, (NS_STATIC_CAST(nsIStreamListener*, this)));
pActivePlugins->mStreams->AppendElement(supports);
}
return rv;
} }
@ -2111,10 +2093,7 @@ nsPluginStreamListenerPeer::OnStartRequest(nsIRequest *request, nsISupports* aCo
// deal with 404 (Not Found) HTTP response, // deal with 404 (Not Found) HTTP response,
// just return, this causes the request to be ignored. // just return, this causes the request to be ignored.
// Also deal with content-encoding
nsCOMPtr<nsIHttpChannel> httpChannel(do_QueryInterface(channel)); nsCOMPtr<nsIHttpChannel> httpChannel(do_QueryInterface(channel));
PRBool useCacheAsFile = PR_TRUE;
if (httpChannel) { if (httpChannel) {
PRUint32 responseCode = 0; PRUint32 responseCode = 0;
rv = httpChannel->GetResponseStatus(&responseCode); rv = httpChannel->GetResponseStatus(&responseCode);
@ -2127,17 +2106,6 @@ nsPluginStreamListenerPeer::OnStartRequest(nsIRequest *request, nsISupports* aCo
return NS_ERROR_FAILURE; return NS_ERROR_FAILURE;
} }
// Now we look for a content-encoding header. If we find one,
// we can't use the cache as a file
nsCAutoString contentEncoding;
rv = httpChannel->GetResponseHeader(NS_LITERAL_CSTRING("Content-Encoding"),
contentEncoding);
if (NS_SUCCEEDED(rv) &&
!contentEncoding.Equals("identity",
nsCaseInsensitiveCStringComparator())) {
useCacheAsFile = PR_FALSE;
}
// Get the notification callbacks from the channel and save it as week ref // Get the notification callbacks from the channel and save it as week ref
// we'll use it in nsPluginStreamInfo::RequestRead() // we'll use it in nsPluginStreamInfo::RequestRead()
// when we'll create channel for byte range request. // when we'll create channel for byte range request.
@ -2152,24 +2120,6 @@ nsPluginStreamListenerPeer::OnStartRequest(nsIRequest *request, nsISupports* aCo
mWeakPtrChannelLoadGroup = getter_AddRefs(NS_GetWeakReference(loadGroup)); mWeakPtrChannelLoadGroup = getter_AddRefs(NS_GetWeakReference(loadGroup));
} }
if (useCacheAsFile) {
nsCOMPtr<nsICachingChannel> cacheChannel = do_QueryInterface(channel, &rv);
if (cacheChannel)
rv = cacheChannel->SetCacheAsFile(PR_TRUE);
else {
// do not cache if this is a file channel,
// just overwrite rv here
nsCOMPtr<nsIFileChannel> fileChannel = do_QueryInterface(channel, &rv);
}
}
if (!useCacheAsFile || NS_FAILED(rv)) {
// The channel doesn't want to do our bidding, lets cache it to disk ourselves
rv = SetupPluginCacheFile(channel);
if (NS_FAILED(rv))
NS_WARNING("No Cache Aval. Some plugins wont work OR we don't have a URL");
}
nsCAutoString aContentType; nsCAutoString aContentType;
rv = channel->GetContentType(aContentType); rv = channel->GetContentType(aContentType);
if (NS_FAILED(rv)) if (NS_FAILED(rv))
@ -2311,6 +2261,9 @@ NS_IMETHODIMP nsPluginStreamListenerPeer::OnDataAvailable(nsIRequest *request,
PRUint32 sourceOffset, PRUint32 sourceOffset,
PRUint32 aLength) PRUint32 aLength)
{ {
if (mRequestFailed)
return NS_ERROR_FAILURE;
if(mAbort) if(mAbort)
{ {
PRUint32 magicNumber = 0; // set it to something that is not the magic number. PRUint32 magicNumber = 0; // set it to something that is not the magic number.
@ -2368,10 +2321,8 @@ NS_IMETHODIMP nsPluginStreamListenerPeer::OnDataAvailable(nsIRequest *request,
// the data as the plugin read from the stream. We do this by the magic // the data as the plugin read from the stream. We do this by the magic
// of an input stream tee. // of an input stream tee.
nsCOMPtr<nsIOutputStream> outStream; if (mFileCacheOutputStream) {
mPluginStreamInfo->GetLocalCachedFileStream(getter_AddRefs(outStream)); rv = NS_NewInputStreamTee(getter_AddRefs(stream), aIStream, mFileCacheOutputStream);
if (outStream) {
rv = NS_NewInputStreamTee(getter_AddRefs(stream), aIStream, outStream);
if (NS_FAILED(rv)) if (NS_FAILED(rv))
return rv; return rv;
} }
@ -2393,10 +2344,11 @@ NS_IMETHODIMP nsPluginStreamListenerPeer::OnDataAvailable(nsIRequest *request,
rv = aIStream->Read(buffer, aLength, &amountRead); rv = aIStream->Read(buffer, aLength, &amountRead);
// if we are caching this to disk ourselves, lets write the bytes out. // if we are caching this to disk ourselves, lets write the bytes out.
nsCOMPtr<nsIOutputStream> outStream; if (mFileCacheOutputStream) {
mPluginStreamInfo->GetLocalCachedFileStream(getter_AddRefs(outStream)); while (amountWrote < amountRead && NS_SUCCEEDED(rv)) {
while (outStream && amountWrote < amountRead && NS_SUCCEEDED(rv)) rv = mFileCacheOutputStream->Write(buffer, amountRead, &amountWrote);
rv = outStream->Write(buffer, amountRead, &amountWrote); }
}
delete [] buffer; delete [] buffer;
} }
return rv; return rv;
@ -2431,13 +2383,9 @@ NS_IMETHODIMP nsPluginStreamListenerPeer::OnStopRequest(nsIRequest *request,
absoluteOffset)); absoluteOffset));
} else { } else {
// if this is not byte range request and // if this is not byte range request and
// if we are writting the stream to disk ourselves, lets close it // if we are writting the stream to disk ourselves,
nsCOMPtr<nsIOutputStream> outStream; // close & tear it down here
mPluginStreamInfo->GetLocalCachedFileStream(getter_AddRefs(outStream)); mFileCacheOutputStream = nsnull;
if (outStream) {
outStream->Close();
mPluginStreamInfo->SetLocalCachedFileStream(nsnull);
}
} }
// if we still have pending stuff to do, lets not close the plugin socket. // if we still have pending stuff to do, lets not close the plugin socket.
@ -2481,9 +2429,9 @@ NS_IMETHODIMP nsPluginStreamListenerPeer::OnStopRequest(nsIRequest *request,
return NS_OK; return NS_OK;
} }
nsCOMPtr<nsIFile> localFile; // call OnFileAvailable if plugin requests stream type StreamType_AsFile or StreamType_AsFileOnly
mPluginStreamInfo->GetLocalCachedFile(getter_AddRefs(localFile)); if (mStreamType >= nsPluginStreamType_AsFile) {
nsCOMPtr<nsIFile> localFile = do_QueryInterface(mLocalCachedFile);
if (!localFile) { if (!localFile) {
nsCOMPtr<nsICachingChannel> cacheChannel = do_QueryInterface(request); nsCOMPtr<nsICachingChannel> cacheChannel = do_QueryInterface(request);
if (cacheChannel) { if (cacheChannel) {
@ -2500,6 +2448,7 @@ NS_IMETHODIMP nsPluginStreamListenerPeer::OnStopRequest(nsIRequest *request,
if (localFile) { if (localFile) {
OnFileAvailable(localFile); OnFileAvailable(localFile);
} }
}
if (mStartBinding) if (mStartBinding)
{ {
@ -2600,26 +2549,44 @@ nsresult nsPluginStreamListenerPeer::SetUpStreamListener(nsIRequest *request,
mStartBinding = PR_TRUE; mStartBinding = PR_TRUE;
if (NS_SUCCEEDED(rv)) { if (NS_FAILED(rv))
return rv;
mPStreamListener->GetStreamType(&mStreamType); mPStreamListener->GetStreamType(&mStreamType);
// now lets figure out if we have to save the file into plugin local cache
PRBool useLocalCache = PR_FALSE;
if (httpChannel) {
// Now we look for a content-encoding header. If we find one,
// we have to use the local cache, it'll have decoded copy of file
nsCAutoString contentEncoding;
rv = httpChannel->GetResponseHeader(NS_LITERAL_CSTRING("Content-Encoding"),
contentEncoding);
if (NS_SUCCEEDED(rv) &&
!contentEncoding.Equals("identity",nsCaseInsensitiveCStringComparator())) {
useLocalCache = PR_TRUE;
} else if (mStreamType >= nsPluginStreamType_AsFile) {
// if plugin requests stream type StreamType_AsFile or StreamType_AsFileOnly // if plugin requests stream type StreamType_AsFile or StreamType_AsFileOnly
// most likely it'll try to check file extension, // check out if browser's cache is avalable
// but our cache does nor support it yet. nsCOMPtr<nsICachingChannel> cacheChannel = do_QueryInterface(httpChannel);
// temp fix is to copy the file+ext into temp location if (cacheChannel && NS_FAILED(cacheChannel->SetCacheAsFile(PR_TRUE))) {
// all this code should be deleted when bug 90558 got fixed useLocalCache = PR_TRUE; // we'll use local cache
}
#if !defined(CACHE_SUPPOPTS_FILE_EXTENSION) #if !defined(CACHE_SUPPOPTS_FILE_EXTENSION)
if (mStreamType >= nsPluginStreamType_AsFile && httpChannel) { // until bug 90558 got fixed
// check out if we already set output stream for this channel // and necko cache starts to support file extension
nsCOMPtr<nsIOutputStream> outStream; // we'll force to copy the file+ext into local plugin cache
mPluginStreamInfo->GetLocalCachedFileStream(getter_AddRefs(outStream)); // becase several plugins (e.g. acrobat, quick time) do not work w/o file extension
if (!outStream) { useLocalCache = PR_TRUE;
SetupPluginCacheFile(httpChannel);
}
}
#endif #endif
} }
return rv; if (useLocalCache) {
SetupPluginCacheFile(httpChannel);
}
}
return NS_OK;
} }
@ -2672,22 +2639,6 @@ nsPluginStreamListenerPeer::VisitHeader(const nsACString &header, const nsACStri
PromiseFlatCString(value).get()); PromiseFlatCString(value).get());
} }
////////////////////////////////////////////////////////////////////////
nsresult nsPluginStreamListenerPeer::SetLocalFile(nsIFile* aFile)
{
NS_ENSURE_ARG_POINTER(aFile);
if(mLocalFile)
{
NS_ASSERTION(!mLocalFile, "nsPluginStreamListenerPeer::SetLocalFile -- path already set, cleaning...");
mLocalFile = nsnull;
}
// clone file to prevent it from being changed out from under us
return aFile->Clone(getter_AddRefs(mLocalFile));
}
///////////////////////////////////////////////////////////////////////// /////////////////////////////////////////////////////////////////////////
nsPluginHostImpl::nsPluginHostImpl() nsPluginHostImpl::nsPluginHostImpl()
@ -2700,6 +2651,8 @@ nsPluginHostImpl::nsPluginHostImpl()
mAllowAlienStarHandler = PR_FALSE; mAllowAlienStarHandler = PR_FALSE;
mUnusedLibraries.Clear(); mUnusedLibraries.Clear();
gActivePluginList = &mActivePluginList;
// check to see if pref is set at startup to let plugins take over in // check to see if pref is set at startup to let plugins take over in
// full page mode for certain image mime types that we handle internally // full page mode for certain image mime types that we handle internally
nsCOMPtr<nsIPref> prefs(do_GetService(kPrefServiceCID)); nsCOMPtr<nsIPref> prefs(do_GetService(kPrefServiceCID));
@ -5644,20 +5597,6 @@ NS_IMETHODIMP nsPluginHostImpl::NewPluginURLStream(const nsString& aURL,
if (NS_SUCCEEDED(rv)) if (NS_SUCCEEDED(rv))
{ {
// it is possible one plugin instance can request several different
// streams, if we are serving those streams as files from
// temp location (e.g. browser cache is not available)
// we do not have to delete the files until instance is active,
// usually temp files are getting deleted when listener peer is released by OnStopRequest(),
// lets add this listener peer to the to list of stream peers for this instance,
// it'll delay the release until nsActivePlugin::setStopped() call.
nsActivePlugin * p = mActivePluginList.find(aInstance);
if (p && p->mStreams)
{
p->mStreams->AppendElement((void *)listenerPeer);
NS_ADDREF(listenerPeer);
}
nsCOMPtr<nsIInterfaceRequestor> callbacks; nsCOMPtr<nsIInterfaceRequestor> callbacks;
if (doc) if (doc)
@ -5917,10 +5856,10 @@ nsresult nsPluginHostImpl::NewFullPagePluginStream(nsIStreamListener *&aStreamLi
// add peer to list of stream peers for this instance // add peer to list of stream peers for this instance
nsActivePlugin * p = mActivePluginList.find(aInstance); nsActivePlugin * p = mActivePluginList.find(aInstance);
if (p && p->mStreams) if (p) {
{ if (!p->mStreams && (NS_FAILED(rv = NS_NewISupportsArray(getter_AddRefs(p->mStreams)))))
p->mStreams->AppendElement((void *)aStreamListener); return rv;
NS_ADDREF(listener); p->mStreams->AppendElement(aStreamListener);
} }
return rv; return rv;
@ -6381,7 +6320,7 @@ nsPluginHostImpl::CreateTmpFileToPost(const char *postDataURL, char **pTmpFileNa
PRBool dirExists; PRBool dirExists;
tempFile->Exists(&dirExists); tempFile->Exists(&dirExists);
if (!dirExists) if (!dirExists)
(void) tempFile->Create(nsIFile::DIRECTORY_TYPE, 0600); (void) tempFile->Create(nsIFile::DIRECTORY_TYPE, 0777);
nsCAutoString inFileName; nsCAutoString inFileName;
inFile->GetNativeLeafName(inFileName); inFile->GetNativeLeafName(inFileName);
@ -6554,15 +6493,11 @@ nsresult nsPluginStreamListenerPeer::ServeStreamAsFile(nsIRequest *request,
mPluginStreamInfo->SetSeekable(0); mPluginStreamInfo->SetSeekable(0);
mPStreamListener->OnStartBinding((nsIPluginStreamInfo*)mPluginStreamInfo); mPStreamListener->OnStartBinding((nsIPluginStreamInfo*)mPluginStreamInfo);
mPluginStreamInfo->SetStreamOffset(0); mPluginStreamInfo->SetStreamOffset(0);
mStreamType = nsPluginStreamType_AsFile;
#if !defined(CACHE_SUPPOPTS_FILE_EXTENSION) #if !defined(CACHE_SUPPOPTS_FILE_EXTENSION)
// check out if we already saving the stream into plugins cache // close & tear down existing cached stream
nsCOMPtr<nsIOutputStream> outStream; mFileCacheOutputStream = nsnull;
mPluginStreamInfo->GetLocalCachedFileStream(getter_AddRefs(outStream));
if (outStream) {
outStream->Close();
mPluginStreamInfo->SetLocalCachedFileStream(nsnull);
}
nsCOMPtr<nsIChannel> channel = do_QueryInterface(request); nsCOMPtr<nsIChannel> channel = do_QueryInterface(request);
nsCOMPtr<nsIHttpChannel> httpChannel = do_QueryInterface(channel); nsCOMPtr<nsIHttpChannel> httpChannel = do_QueryInterface(channel);
@ -6682,3 +6617,29 @@ nsPluginByteRangeStreamListener::OnDataAvailable(nsIRequest *request, nsISupport
return mStreamConverter->OnDataAvailable(request, ctxt, inStr, sourceOffset, count); return mStreamConverter->OnDataAvailable(request, ctxt, inStr, sourceOffset, count);
} }
PRBool
nsPluginStreamInfo::UseExistingPluginCacheFile(nsPluginStreamInfo* psi, nsIFile* file)
{
NS_ENSURE_ARG_POINTER(psi);
if ( psi->mLength == mLength &&
psi->mModified == mModified &&
!PL_strcmp(psi->mURL, mURL))
{
if (psi->mLength != (PRUint32) mStreamOffset) { //lets check a file size
PRInt64 size;
if (NS_FAILED(file->GetFileSize(&size)))
return PR_FALSE;
PRUint32 fs = nsInt64(size);
if (psi->mLength != fs) {
return PR_FALSE;
}
}
return PR_TRUE;
}
return PR_FALSE;
}

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

@ -54,6 +54,7 @@
#include "nsWeakPtr.h" #include "nsWeakPtr.h"
#include "nsIPrompt.h" #include "nsIPrompt.h"
#include "nsIGenericFactory.h" #include "nsIGenericFactory.h"
#include "nsISupportsArray.h"
class ns4xPlugin; class ns4xPlugin;
class nsFileSpec; class nsFileSpec;
@ -62,7 +63,6 @@ class nsIFile;
class nsIChannel; class nsIChannel;
class nsIRegistry; class nsIRegistry;
class nsPluginHostImpl; class nsPluginHostImpl;
class nsISupportsArray;
/** /**
* A linked-list of plugin information that is used for * A linked-list of plugin information that is used for
@ -123,7 +123,8 @@ struct nsActivePlugin
PRTime mllStopTime; PRTime mllStopTime;
PRBool mDefaultPlugin; PRBool mDefaultPlugin;
PRBool mXPConnected; PRBool mXPConnected;
nsVoidArray* mStreams; //Array holding all opened stream listeners for this entry
nsCOMPtr <nsISupportsArray> mStreams;
nsActivePlugin(nsPluginTag* aPluginTag, nsActivePlugin(nsPluginTag* aPluginTag,
nsIPluginInstance* aInstance, nsIPluginInstance* aInstance,