From 59eb2b1392b6c5ba720863e3bff245015de6017d Mon Sep 17 00:00:00 2001 From: "dougt%netscape.com" Date: Tue, 22 May 2001 22:32:45 +0000 Subject: [PATCH] Implements NPN_RequestRead(). Bug number 53363. r=peterl@netscape.com, sr=attinasi@netscape.com. --- .../base/public/nsIPluginStreamListener.h | 2 +- modules/plugin/base/src/ns4xPlugin.cpp | 48 +- .../plugin/base/src/ns4xPluginInstance.cpp | 80 +-- modules/plugin/base/src/ns4xPluginInstance.h | 2 +- .../base/src/ns4xPluginStreamListener.h | 60 ++ modules/plugin/base/src/nsPluginHostImpl.cpp | 592 +++++++++++++----- modules/plugin/nglsrc/ns4xPlugin.cpp | 48 +- modules/plugin/nglsrc/ns4xPluginInstance.cpp | 80 +-- modules/plugin/nglsrc/ns4xPluginInstance.h | 2 +- .../plugin/nglsrc/ns4xPluginStreamListener.h | 60 ++ modules/plugin/nglsrc/nsPluginHostImpl.cpp | 592 +++++++++++++----- .../plugin/public/nsIPluginStreamListener.h | 2 +- 12 files changed, 1150 insertions(+), 418 deletions(-) create mode 100644 modules/plugin/base/src/ns4xPluginStreamListener.h create mode 100644 modules/plugin/nglsrc/ns4xPluginStreamListener.h diff --git a/modules/plugin/base/public/nsIPluginStreamListener.h b/modules/plugin/base/public/nsIPluginStreamListener.h index dafc287a33ed..52a48c7644ed 100644 --- a/modules/plugin/base/public/nsIPluginStreamListener.h +++ b/modules/plugin/base/public/nsIPluginStreamListener.h @@ -82,7 +82,7 @@ public: * @return The return value is currently ignored. */ NS_IMETHOD - OnDataAvailable(nsIPluginStreamInfo* pluginInfo, nsIInputStream* input, PRUint32 length) = 0; + OnDataAvailable(nsIPluginStreamInfo* pluginInfo, nsIInputStream* input, PRUint32 sourceOffset, PRUint32 length) = 0; NS_IMETHOD OnFileAvailable(nsIPluginStreamInfo* pluginInfo, const char* fileName) = 0; diff --git a/modules/plugin/base/src/ns4xPlugin.cpp b/modules/plugin/base/src/ns4xPlugin.cpp index d38211c3ab49..3f5977a578f3 100644 --- a/modules/plugin/base/src/ns4xPlugin.cpp +++ b/modules/plugin/base/src/ns4xPlugin.cpp @@ -26,6 +26,7 @@ #include "nsplugin.h" #include "ns4xPlugin.h" #include "ns4xPluginInstance.h" +#include "ns4xPluginStreamListener.h" #include "nsIServiceManager.h" #include "nsIMemory.h" #include "nsIPluginStreamListener.h" @@ -676,6 +677,11 @@ ns4xStreamWrapper::GetStream(nsIOutputStream* &result) NPError NP_EXPORT _newstream(NPP npp, NPMIMEType type, const char* window, NPStream* *result) { + +#ifdef NS_DEBUG + printf("\nNewStream called \n\n"); +#endif + if(!npp) return NPERR_INVALID_INSTANCE_ERROR; @@ -719,6 +725,10 @@ _newstream(NPP npp, NPMIMEType type, const char* window, NPStream* *result) int32 NP_EXPORT _write(NPP npp, NPStream *pstream, int32 len, void *buffer) { +#ifdef NS_DEBUG + printf("\nWrite called by plugin: \n%s\n", buffer); +#endif + // negative return indicates failure to the plugin if(!npp) return -1; @@ -745,6 +755,11 @@ _write(NPP npp, NPStream *pstream, int32 len, void *buffer) NPError NP_EXPORT _destroystream(NPP npp, NPStream *pstream, NPError reason) { + + +#ifdef NS_DEBUG + printf("\nDestroy Stream called \n\n"); +#endif if(!npp) return NPERR_INVALID_INSTANCE_ERROR; @@ -770,7 +785,7 @@ _destroystream(NPP npp, NPStream *pstream, NPError reason) // This will release the wrapped nsIOutputStream. delete wrapper; - + pstream->ndata = nsnull; return NPERR_NO_ERROR; } @@ -1035,7 +1050,38 @@ _setvalue(NPP npp, NPPVariable variable, void *result) NPError NP_EXPORT _requestread(NPStream *pstream, NPByteRange *rangeList) { +#ifdef NS_DEBUG + printf("\nRequestRead called by plugin: "); + for(NPByteRange * range = rangeList; range != nsnull; range = range->next) + { + printf("%i-%i", range->offset, range->offset + range->length - 1); + if(range->next) + printf(","); + } + printf("\n\n"); +#endif + + if(!pstream || !rangeList || !pstream->ndata) + return NPERR_INVALID_PARAM; + + nsresult res = NS_OK; + + ns4xPluginStreamListener * streamlistener = (ns4xPluginStreamListener *)pstream->ndata; + + if(NS_FAILED(res)) + return NPERR_GENERIC_ERROR; + + nsPluginStreamType streamtype = nsPluginStreamType_Normal; + + streamlistener->GetStreamType(&streamtype); + + if(streamtype != nsPluginStreamType_Seek) return NPERR_STREAM_NOT_SEEKABLE; + + if(streamlistener->mStreamInfo) + streamlistener->mStreamInfo->RequestRead((nsByteRange *)rangeList); + + return NS_OK; } diff --git a/modules/plugin/base/src/ns4xPluginInstance.cpp b/modules/plugin/base/src/ns4xPluginInstance.cpp index a07163bb5e1a..7d373fbcb060 100644 --- a/modules/plugin/base/src/ns4xPluginInstance.cpp +++ b/modules/plugin/base/src/ns4xPluginInstance.cpp @@ -21,7 +21,7 @@ */ #include "ns4xPluginInstance.h" -#include "nsIPluginStreamListener.h" +#include "ns4xPluginStreamListener.h" #include "nsPluginHostImpl.h" #include "prlog.h" @@ -40,46 +40,6 @@ static NS_DEFINE_CID(kPrefServiceCID, NS_PREF_CID); // needed for NS_TRY_SAFE_CALL_* static NS_DEFINE_IID(kCPluginManagerCID, NS_PLUGINMANAGER_CID); -#define MAX_PLUGIN_NECKO_BUFFER 16384 - -class ns4xPluginStreamListener : public nsIPluginStreamListener { - -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 OnStopBinding(nsIPluginStreamInfo* pluginInfo, nsresult status); - - NS_IMETHOD GetStreamType(nsPluginStreamType *result); - - /////////////////////////////////////////////////////////////////////////// - // ns4xPluginStreamListener specific methods: - - ns4xPluginStreamListener(nsIPluginInstance* inst, void* notifyData); - virtual ~ns4xPluginStreamListener(void); - PRBool IsStarted(void); - -protected: - - void* mNotifyData; - char* mStreamBuffer; - ns4xPluginInstance* mInst; - NPStream mNPStream; - PRUint32 mPosition; - nsPluginStreamType mStreamType; -}; - - /////////////////////////////////////////////////////////////////////////////// // ns4xPluginStreamListener Methods /////////////////////////////////////////////////////////////////////////////// @@ -88,13 +48,13 @@ static NS_DEFINE_IID(kIPluginStreamListenerIID, NS_IPLUGINSTREAMLISTENER_IID); ns4xPluginStreamListener::ns4xPluginStreamListener(nsIPluginInstance* inst, void* notifyData) - : mNotifyData(notifyData) + : mNotifyData(notifyData), + mStreamInfo(nsnull) { NS_INIT_REFCNT(); mInst = (ns4xPluginInstance*) inst; - mPosition = 0; - mStreamBuffer=nsnull; - + mStreamBuffer=nsnull; + mPosition = 0; // Initialize the 4.x interface structure memset(&mNPStream, 0, sizeof(mNPStream)); @@ -137,6 +97,8 @@ ns4xPluginStreamListener::OnStartBinding(nsIPluginStreamInfo* pluginInfo) pluginInfo->IsSeekable(&seekable); pluginInfo->GetContentType(&contentType); + mStreamInfo = pluginInfo; + PRLibrary* lib = mInst->fLibrary; // if we don't know the end of the stream, use 0 instead of -1. bug 59571 @@ -185,6 +147,7 @@ ns4xPluginStreamListener::OnStartBinding(nsIPluginStreamInfo* pluginInfo) NS_IMETHODIMP ns4xPluginStreamListener::OnDataAvailable(nsIPluginStreamInfo* pluginInfo, nsIInputStream* input, + PRUint32 sourceOffset, PRUint32 length) { if (!mInst || !mInst->IsStarted()) @@ -205,6 +168,11 @@ ns4xPluginStreamListener::OnDataAvailable(nsIPluginStreamInfo* pluginInfo, PRUint32 leftToRead = 0; // just in case OnDataaAvail tries to overflow our buffer PRBool createdHere = PR_FALSE; // we did malloc in locally, so we must free locally + // we are getting a range request, reset mPosition since postion passed to plugin will + // be relative to the absolute position of the file. + if (sourceOffset != 0) + mPosition = 0; + pluginInfo->GetURL(&mNPStream.url); pluginInfo->GetLastModified((PRUint32*)&(mNPStream.lastmodified)); @@ -267,10 +235,24 @@ ns4xPluginStreamListener::OnDataAvailable(nsIPluginStreamInfo* pluginInfo, { PRLibrary* lib = mInst->fLibrary; +#ifdef DEBUG_dougt + printf("> %d - %d \n", sourceOffset + writeCount + mPosition, numtowrite); +#if 0 + nsCString x; + x.Append("d:\\parts\\"); + x.AppendInt(sourceOffset); + + PRFileDesc* fd; + fd = PR_Open(x, PR_CREATE_FILE |PR_SYNC| PR_APPEND | PR_RDWR, 777); + PR_Write(fd, mStreamBuffer, numtowrite); + PR_Close(fd); +#endif +#endif + NS_TRY_SAFE_CALL_RETURN(writeCount, CallNPP_WriteProc(callbacks->write, npp, &mNPStream, - mPosition, + sourceOffset + writeCount + mPosition, numtowrite, (void *)mStreamBuffer), lib); if (writeCount < 0) { @@ -278,8 +260,10 @@ ns4xPluginStreamListener::OnDataAvailable(nsIPluginStreamInfo* pluginInfo, goto error; } + if (sourceOffset == 0) + mPosition += numtowrite; + amountRead -= numtowrite; - mPosition += numtowrite; } } @@ -294,7 +278,7 @@ error: if (leftToRead > 0) // if we have more to read in this pass, do it recursivly { - OnDataAvailable(pluginInfo, input, leftToRead); + OnDataAvailable(pluginInfo, input, sourceOffset, leftToRead); } return rv; diff --git a/modules/plugin/base/src/ns4xPluginInstance.h b/modules/plugin/base/src/ns4xPluginInstance.h index 88c64f5e416f..c54c545c3cd1 100644 --- a/modules/plugin/base/src/ns4xPluginInstance.h +++ b/modules/plugin/base/src/ns4xPluginInstance.h @@ -116,7 +116,7 @@ public: // returns the state of mStarted PRBool IsStarted(void); - + protected: nsresult InitializePlugin(nsIPluginInstancePeer* peer); diff --git a/modules/plugin/base/src/ns4xPluginStreamListener.h b/modules/plugin/base/src/ns4xPluginStreamListener.h new file mode 100644 index 000000000000..1eea37fe3dc6 --- /dev/null +++ b/modules/plugin/base/src/ns4xPluginStreamListener.h @@ -0,0 +1,60 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- + * + * The contents of this file are subject to the Netscape Public + * License Version 1.1 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.mozilla.org/NPL/ + * + * Software distributed under the License is distributed on an "AS + * IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or + * implied. See the License for the specific language governing + * rights and limitations under the License. + * + * The Original Code is mozilla.org code. + * + * The Initial Developer of the Original Code is Netscape + * Communications Corporation. Portions created by Netscape are + * Copyright (C) 1998 Netscape Communications Corporation. All + * Rights Reserved. + * + * Contributor(s): + */ + +#ifndef ns4xPluginStreamListener_h__ +#define ns4xPluginStreamListener_h__ + +#include "nsIPluginStreamListener.h" +#include "nsIPluginStreamInfo.h" + +#define MAX_PLUGIN_NECKO_BUFFER 16384 + +class ns4xPluginStreamListener : public nsIPluginStreamListener +{ +public: + NS_DECL_ISUPPORTS + + // from nsIPluginStreamListener: + NS_IMETHOD OnStartBinding(nsIPluginStreamInfo* pluginInfo); + NS_IMETHOD OnDataAvailable(nsIPluginStreamInfo* pluginInfo, nsIInputStream* input, PRUint32 length, PRUint32 offset); + NS_IMETHOD OnFileAvailable( nsIPluginStreamInfo* pluginInfo, const char* fileName); + NS_IMETHOD OnStopBinding(nsIPluginStreamInfo* pluginInfo, nsresult status); + NS_IMETHOD GetStreamType(nsPluginStreamType *result); + + // ns4xPluginStreamListener specific methods: + ns4xPluginStreamListener(nsIPluginInstance* inst, void* notifyData); + virtual ~ns4xPluginStreamListener(); + PRBool IsStarted(); + +protected: + void* mNotifyData; + char* mStreamBuffer; + ns4xPluginInstance* mInst; + NPStream mNPStream; + PRUint32 mPosition; + nsPluginStreamType mStreamType; + +public: + nsIPluginStreamInfo * mStreamInfo; +}; + +#endif diff --git a/modules/plugin/base/src/nsPluginHostImpl.cpp b/modules/plugin/base/src/nsPluginHostImpl.cpp index df92a94a8378..f32600fed836 100644 --- a/modules/plugin/base/src/nsPluginHostImpl.cpp +++ b/modules/plugin/base/src/nsPluginHostImpl.cpp @@ -37,6 +37,7 @@ #include "nsIObserverService.h" #include "nsIHttpProtocolHandler.h" #include "nsIHttpChannel.h" +#include "nsIByteRangeRequest.h" #include "nsIStreamListener.h" #include "nsIInputStream.h" #include "nsIOutputStream.h" @@ -44,6 +45,7 @@ #include "nsXPIDLString.h" #include "nsIPref.h" #include "nsIProtocolProxyService.h" +#include "nsIStreamConverterService.h" #include "nsIFile.h" #include "nsIInputStream.h" #include "nsIIOService.h" @@ -55,6 +57,8 @@ #include "nsIDocument.h" #include "nsIScriptablePlugin.h" #include "nsICachingChannel.h" +#include "nsHashtable.h" + // Friggin' X11 has to "#define None". Lame! #ifdef None @@ -63,12 +67,11 @@ #include "nsIRegistry.h" #include "nsEnumeratorUtils.h" - +#include "nsISupportsPrimitives.h" // for the dialog #include "nsIStringBundle.h" #include "nsIPrompt.h" #include "nsIWindowWatcher.h" -#include "nsHashtable.h" #include "nsIScriptGlobalObject.h" #include "nsIScriptGlobalObjectOwner.h" @@ -144,6 +147,7 @@ static NS_DEFINE_IID(kIRequestObserverIID, NS_IREQUESTOBSERVER_IID); static NS_DEFINE_CID(kIOServiceCID, NS_IOSERVICE_CID); static NS_DEFINE_CID(kHttpHandlerCID, NS_HTTPPROTOCOLHANDLER_CID); static NS_DEFINE_CID(kIHttpHeaderVisitorIID, NS_IHTTPHEADERVISITOR_IID); +static NS_DEFINE_CID(kStreamConverterServiceCID, NS_STREAMCONVERTERSERVICE_CID); static NS_DEFINE_IID(kIFileUtilitiesIID, NS_IFILEUTILITIES_IID); static NS_DEFINE_IID(kIOutputStreamIID, NS_IOUTPUTSTREAM_IID); @@ -167,6 +171,8 @@ static NS_DEFINE_CID(kComponentManagerCID, NS_COMPONENTMANAGER_CID); #define NS_PREF_MAX_NUM_CACHED_PLUGINS "browser.plugins.max_num_cached_plugins" #define DEFAULT_NUMBER_OF_STOPPED_PLUGINS 10 +#define MAGIC_REQUEST_CONTEXT 0x01020304 + void DisplayNoDefaultPluginDialog(const char *mimeType); /** @@ -828,10 +834,11 @@ void nsPluginTag::TryUnloadPlugin(PRBool aForceShutdown) mLibrary = nsnull; } +class nsPluginStreamListenerPeer; + class nsPluginStreamInfo : public nsIPluginStreamInfo { public: - nsPluginStreamInfo(); virtual ~nsPluginStreamInfo(); @@ -874,22 +881,116 @@ public: void SetURL(const char* url); + void + SetPluginInstance(nsIPluginInstance * aPluginInstance); + + void + SetPluginStreamListenerPeer(nsPluginStreamListenerPeer * aPluginStreamListenerPeer); + + void + MakeByteRangeString(nsByteRange* aRangeList, char** string, PRInt32 *numRequests); + + void + SetLocalCachedFile(const char* path); + + void + GetLocalCachedFile(char** path); + private: char* mContentType; char* mURL; - PRBool mSeekable; + char* mFilePath; + PRBool mSeekable; PRUint32 mLength; PRUint32 mModified; + nsIPluginInstance * mPluginInstance; + nsPluginStreamListenerPeer * mPluginStreamListenerPeer; +}; + +/////////////////////////////////////////////////////////////////////////////////////////////////// + +class nsPluginStreamListenerPeer : public nsIStreamListener, + public nsIProgressEventSink, + public nsIHttpHeaderVisitor +{ +public: + nsPluginStreamListenerPeer(); + virtual ~nsPluginStreamListenerPeer(); + + NS_DECL_ISUPPORTS + NS_DECL_NSIPROGRESSEVENTSINK + NS_DECL_NSIREQUESTOBSERVER + NS_DECL_NSISTREAMLISTENER + NS_DECL_NSIHTTPHEADERVISITOR + + // Called by GetURL and PostURL (via NewStream) + nsresult Initialize(nsIURI *aURL, + nsIPluginInstance *aInstance, + nsIPluginStreamListener *aListener, + PRInt32 requestCount = 1); + + nsresult InitializeEmbeded(nsIURI *aURL, + nsIPluginInstance* aInstance, + nsIPluginInstanceOwner *aOwner = nsnull, + nsIPluginHost *aHost = nsnull); + + nsresult InitializeFullPage(nsIPluginInstance *aInstance); + + nsresult OnFileAvailable(const char* aFilename); + + nsILoadGroup* GetLoadGroup(); + + nsresult SetLocalFile(const char* aFilename); + +private: + nsresult SetUpCache(nsIURI* aURL); + nsresult SetUpStreamListener(nsIRequest* request, nsIURI* aURL); + + nsIURI *mURL; + + + nsIPluginInstanceOwner *mOwner; + nsIPluginInstance *mInstance; + nsIPluginStreamListener *mPStreamListener; + nsPluginStreamInfo *mPluginStreamInfo; + PRBool mSetUpListener; + + /* + * Set to PR_TRUE after nsIPluginInstancePeer::OnStartBinding() has + * been called. Checked in ::OnStopRequest so we can call the + * plugin's OnStartBinding if, for some reason, it has not already + * been called. + */ + PRPackedBool mStartBinding; + PRPackedBool mHaveFiredOnStartRequest; + // these get passed to the plugin stream listener + char *mMIMEType; + PRUint32 mLength; + nsPluginStreamType mStreamType; + nsIPluginHost *mHost; + + // local file which was used to post data and which should be deleted after that + char *mLocalFile; + nsHashtable *mDataForwardToRequest; + +public: + PRBool mAbort; + PRInt32 mPendingRequests; + }; nsPluginStreamInfo::nsPluginStreamInfo() { NS_INIT_REFCNT(); + mPluginInstance = nsnull; + mPluginStreamListenerPeer = nsnull; + mContentType = nsnull; mURL = nsnull; - mSeekable = PR_FALSE; + mFilePath = nsnull; + mSeekable = PR_FALSE; mLength = 0; mModified = 0; } @@ -900,6 +1001,11 @@ nsPluginStreamInfo::~nsPluginStreamInfo() PL_strfree(mContentType); if(mURL != nsnull) PL_strfree(mURL); + if(mFilePath != nsnull) + PL_strfree(mFilePath); + + NS_IF_RELEASE(mPluginInstance); + NS_IF_RELEASE(mPluginStreamListenerPeer); } NS_IMPL_ADDREF(nsPluginStreamInfo) @@ -965,10 +1071,111 @@ nsPluginStreamInfo::GetURL(const char** result) return NS_OK; } + +void +nsPluginStreamInfo::MakeByteRangeString(nsByteRange* aRangeList, char** rangeRequest, PRInt32 *numRequests) +{ + *rangeRequest = nsnull; + *numRequests = 0; + //the string should look like this: bytes=500-700,601-999 + if(!aRangeList) + return; + + PRInt32 requestCnt = 0; + // XXX needs to be smarter than that + char * string = new char[1024]; + + string[0] = '\0'; + PL_strcat(string, "bytes="); + + for(nsByteRange * range = aRangeList; range != nsnull; range = range->next) + { + // XXX zero length? + if(!range->length) + continue; + + // XXX needs to be fixed for negative offsets + nsCString firstbyte; firstbyte.AppendInt(range->offset); + nsCString lastbyte; firstbyte.AppendInt(range->offset + range->length - 1); + + PL_strcat(string, firstbyte.get()); + PL_strcat(string, "-"); + PL_strcat(string, lastbyte.get()); + if(range->next) + PL_strcat(string, ","); + + requestCnt++; + } + + // get rid of possible tailing comma + PRInt32 len = PL_strlen(string); + if(string[len - 1] == ',') + string[len - 1] = '\0'; + + *rangeRequest = string; + *numRequests = requestCnt; + + return; +} + NS_IMETHODIMP nsPluginStreamInfo::RequestRead(nsByteRange* rangeList) { - return NS_ERROR_NOT_IMPLEMENTED; + mPluginStreamListenerPeer->mAbort = PR_TRUE; + + nsresult rv = NS_OK; + nsCOMPtr url; + + rv = NS_NewURI(getter_AddRefs(url), mURL); + + nsCOMPtr channel; + rv = NS_OpenURI(getter_AddRefs(channel), url, nsnull, nsnull, nsnull); + if (NS_FAILED(rv)) + return rv; + + nsCOMPtr httpChannel(do_QueryInterface(channel)); + if(!httpChannel) + return NS_ERROR_FAILURE; + + char *rangeString; + PRInt32 numRequests; + + MakeByteRangeString(rangeList, &rangeString, &numRequests); + + if(!rangeString) + return NS_ERROR_FAILURE; + + httpChannel->SetRequestHeader("Range", rangeString); + + delete [] rangeString; + + // instruct old stream listener to cancel the request on the next + // attempt to write. + + nsCOMPtr converter = mPluginStreamListenerPeer; + + if (numRequests > 1) { + nsCOMPtr serv = do_GetService(kStreamConverterServiceCID, &rv); + if (NS_FAILED(rv)) + return rv; + + rv = serv->AsyncConvertData(NS_LITERAL_STRING("multipart/byteranges").get(), + NS_LITERAL_STRING("*/*").get(), + mPluginStreamListenerPeer, + nsnull, + getter_AddRefs(converter)); + if (NS_FAILED(rv)) + return rv; + } + + mPluginStreamListenerPeer->mPendingRequests += numRequests; + + nsCOMPtr container = do_CreateInstance(NS_SUPPORTS_PRUINT32_CONTRACTID, &rv); + if (NS_FAILED(rv)) return rv; + rv = container->SetData(MAGIC_REQUEST_CONTEXT); + if (NS_FAILED(rv)) return rv; + + return channel->AsyncOpen(converter, container); } // local methods @@ -1009,68 +1216,33 @@ nsPluginStreamInfo::SetURL(const char* url) mURL = PL_strdup(url); } -/////////////////////////////////////////////////////////////////////////////////////////////////// -class nsPluginStreamListenerPeer : public nsIStreamListener, - public nsIProgressEventSink, - public nsIHttpHeaderVisitor +void +nsPluginStreamInfo::SetLocalCachedFile(const char* path) +{ + if(mFilePath != nsnull) + PL_strfree(mFilePath); + + mFilePath = PL_strdup(path); +} + +void +nsPluginStreamInfo::GetLocalCachedFile(char** path) +{ + *path = PL_strdup(mFilePath); +} + +void +nsPluginStreamInfo::SetPluginInstance(nsIPluginInstance * aPluginInstance) { -public: - nsPluginStreamListenerPeer(); - virtual ~nsPluginStreamListenerPeer(); + NS_IF_ADDREF(mPluginInstance = aPluginInstance); +} - NS_DECL_ISUPPORTS - NS_DECL_NSIPROGRESSEVENTSINK - NS_DECL_NSIREQUESTOBSERVER - NS_DECL_NSISTREAMLISTENER - NS_DECL_NSIHTTPHEADERVISITOR - - // Called by GetURL and PostURL (via NewStream) - nsresult Initialize(nsIURI *aURL, - nsIPluginInstance *aInstance, - nsIPluginStreamListener *aListener); - - nsresult InitializeEmbeded(nsIURI *aURL, - nsIPluginInstance* aInstance, - nsIPluginInstanceOwner *aOwner = nsnull, - nsIPluginHost *aHost = nsnull); - - nsresult InitializeFullPage(nsIPluginInstance *aInstance); - - nsresult OnFileAvailable(const char* aFilename); - - nsILoadGroup* GetLoadGroup(); - - nsresult SetLocalFile(const char* aFilename); - -private: - nsresult SetUpCache(nsIURI* aURL); - nsresult SetUpStreamListener(nsIRequest* request, nsIURI* aURL); - - nsIURI *mURL; - nsIPluginInstanceOwner *mOwner; - nsIPluginInstance *mInstance; - nsIPluginStreamListener *mPStreamListener; - nsPluginStreamInfo *mPluginStreamInfo; - PRBool mSetUpListener; - - /* - * Set to PR_TRUE after nsIPluginInstancePeer::OnStartBinding() has - * been called. Checked in ::OnStopRequest so we can call the - * plugin's OnStartBinding if, for some reason, it has not already - * been called. - */ - PRBool mStartBinding; - - // these get passed to the plugin stream listener - char *mMIMEType; - PRUint32 mLength; - nsPluginStreamType mStreamType; - nsIPluginHost *mHost; - - // local file which was used to post data and which should be deleted after that - char *mLocalFile; -}; +void +nsPluginStreamInfo::SetPluginStreamListenerPeer(nsPluginStreamListenerPeer * aPluginStreamListenerPeer) +{ + NS_IF_ADDREF(mPluginStreamListenerPeer = aPluginStreamListenerPeer); +} /////////////////////////////////////////////////////////////////////////////////////////////////// @@ -1157,6 +1329,11 @@ nsPluginStreamListenerPeer::nsPluginStreamListenerPeer() mStreamType = nsPluginStreamType_Normal; mStartBinding = PR_FALSE; mLocalFile = nsnull; + mAbort = PR_FALSE; + + mPendingRequests = 0; + mHaveFiredOnStartRequest = PR_FALSE; + mDataForwardToRequest = nsnull; } nsPluginStreamListenerPeer::~nsPluginStreamListenerPeer() @@ -1187,55 +1364,21 @@ nsPluginStreamListenerPeer::~nsPluginStreamListenerPeer() localFile->Delete(PR_FALSE); delete [] mLocalFile; } + delete mDataForwardToRequest; } -NS_IMPL_ADDREF(nsPluginStreamListenerPeer); -NS_IMPL_RELEASE(nsPluginStreamListenerPeer); +NS_IMPL_ISUPPORTS3(nsPluginStreamListenerPeer, + nsIStreamListener, + nsIRequestObserver, + nsIHttpHeaderVisitor) -nsresult nsPluginStreamListenerPeer::QueryInterface(const nsIID& aIID, - void** aInstancePtrResult) -{ - NS_PRECONDITION(nsnull != aInstancePtrResult, "null pointer"); - - if (nsnull == aInstancePtrResult) - return NS_ERROR_NULL_POINTER; - - if (aIID.Equals(kIStreamListenerIID)) - { - *aInstancePtrResult = (void *)((nsIStreamListener *)this); - AddRef(); - return NS_OK; - } - - if (aIID.Equals(kIRequestObserverIID)) - { - *aInstancePtrResult = (void *)((nsIRequestObserver *)this); - AddRef(); - return NS_OK; - } - - if (aIID.Equals(kIHttpHeaderVisitorIID)) - { - *aInstancePtrResult = (void *)((nsIHttpHeaderVisitor *)this); - AddRef(); - return NS_OK; - } - - if (aIID.Equals(kISupportsIID)) - { - *aInstancePtrResult = (void *)((nsISupports *)((nsIStreamListener *)this)); - AddRef(); - return NS_OK; - } - - return NS_NOINTERFACE; -} /* Called as a result of GetURL and PostURL */ nsresult nsPluginStreamListenerPeer::Initialize(nsIURI *aURL, nsIPluginInstance *aInstance, - nsIPluginStreamListener* aListener) + nsIPluginStreamListener* aListener, + PRInt32 requestCount) { #ifdef NS_DEBUG char* spec; @@ -1255,6 +1398,15 @@ nsresult nsPluginStreamListenerPeer::Initialize(nsIURI *aURL, mPluginStreamInfo = new nsPluginStreamInfo(); + mPluginStreamInfo->SetPluginInstance(aInstance); + mPluginStreamInfo->SetPluginStreamListenerPeer(this); + + mPendingRequests = requestCount; + + mDataForwardToRequest = new nsHashtable(16, PR_FALSE); + if (!mDataForwardToRequest) + return NS_ERROR_FAILURE; + return NS_OK; } @@ -1297,6 +1449,13 @@ nsresult nsPluginStreamListenerPeer::InitializeEmbeded(nsIURI *aURL, mPluginStreamInfo = new nsPluginStreamInfo(); + mPluginStreamInfo->SetPluginInstance(aInstance); + mPluginStreamInfo->SetPluginStreamListenerPeer(this); + + mDataForwardToRequest = new nsHashtable(16, PR_FALSE); + if (!mDataForwardToRequest) + return NS_ERROR_FAILURE; + return NS_OK; } @@ -1315,6 +1474,13 @@ nsresult nsPluginStreamListenerPeer::InitializeFullPage(nsIPluginInstance *aInst mPluginStreamInfo = new nsPluginStreamInfo(); + mPluginStreamInfo->SetPluginInstance(aInstance); + mPluginStreamInfo->SetPluginStreamListenerPeer(this); + + mDataForwardToRequest = new nsHashtable(16, PR_FALSE); + if (!mDataForwardToRequest) + return NS_ERROR_FAILURE; + return NS_OK; } @@ -1324,6 +1490,12 @@ nsPluginStreamListenerPeer::OnStartRequest(nsIRequest *request, nsISupports* aCo { nsresult rv = NS_OK; + if (mHaveFiredOnStartRequest) { + return NS_OK; + } + + mHaveFiredOnStartRequest = PR_TRUE; + nsCOMPtr channel = do_QueryInterface(request); if (!channel) @@ -1435,12 +1607,52 @@ NS_IMETHODIMP nsPluginStreamListenerPeer::OnStatus(nsIRequest *request, return NS_OK; } + + +class nsPRUintKey : public nsHashKey { +protected: + PRUint32 mKey; +public: + nsPRUintKey(PRUint32 key) : mKey(key) {} + + PRUint32 HashCode(void) const { + return mKey; + } + + PRBool Equals(const nsHashKey *aKey) const { + return mKey == ((const nsPRUintKey *) aKey)->mKey; + } + nsHashKey *Clone() const { + return new nsPRUintKey(mKey); + } + PRUint32 GetValue() { return mKey; } +}; + + NS_IMETHODIMP nsPluginStreamListenerPeer::OnDataAvailable(nsIRequest *request, nsISupports* aContext, nsIInputStream *aIStream, PRUint32 sourceOffset, PRUint32 aLength) { + + + if(mAbort) + { + PRUint32 magicNumber = 0; // set it to something that is not the magic number. + nsCOMPtr container = do_QueryInterface(aContext); + if (container) + container->GetData(&magicNumber); + + if (magicNumber != MAGIC_REQUEST_CONTEXT) + { + // this is not one of our range requests + mAbort = PR_FALSE; + return NS_BINDING_ABORTED; + } + } + + nsresult rv = NS_OK; nsCOMPtr aURL; nsCOMPtr channel = do_QueryInterface(request); @@ -1463,9 +1675,30 @@ NS_IMETHODIMP nsPluginStreamListenerPeer::OnDataAvailable(nsIRequest *request, // call OnDataAvailable if(mStreamType != nsPluginStreamType_AsFileOnly) { - // It's up to the plugin to read from the stream - // If it doesn't, OnStopRequest will never be called - rv = mPStreamListener->OnDataAvailable((nsIPluginStreamInfo*)mPluginStreamInfo, aIStream, aLength); + // get the absolute offset of the request, if one exists. + nsCOMPtr 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->Exists(&key)) + amtForwardToPlugin = (PRInt32) mDataForwardToRequest->Remove(&key); + + mDataForwardToRequest->Put(&key, (void*) (amtForwardToPlugin+aLength)); + } + + rv = mPStreamListener->OnDataAvailable((nsIPluginStreamInfo*)mPluginStreamInfo, + aIStream, + absoluteOffset+amtForwardToPlugin, + aLength); + // if a plugin returns an error, the peer must kill the stream // else the stream and PluginStreamListener leak if (NS_FAILED(rv)) @@ -1486,7 +1719,74 @@ NS_IMETHODIMP nsPluginStreamListenerPeer::OnStopRequest(nsIRequest *request, nsISupports* aContext, nsresult aStatus) { + nsresult rv = NS_OK; + nsCOMPtr cacheChannel = do_QueryInterface(request); + nsCOMPtr localFile; + nsXPIDLCString pathAndFilename; + + // doing multiple requests, the main url load (the cacheable entry) could come + // out of order. Here we will check to see if the request is main url load. + + if (cacheChannel) { + rv = cacheChannel->GetCacheFile(getter_AddRefs(localFile)); + if (NS_SUCCEEDED(rv)) { + localFile->GetPath(getter_Copies(pathAndFilename)); + mPluginStreamInfo->SetLocalCachedFile(pathAndFilename); + } + } + + // remove the request from our data forwarding count hash. + nsCOMPtr brr = do_QueryInterface(request); + if (brr) { + PRInt32 absoluteOffset = 0; + brr->GetStartRange(&absoluteOffset); + + nsPRUintKey key(absoluteOffset); + + if (!mDataForwardToRequest) + return NS_ERROR_FAILURE; + + (void) mDataForwardToRequest->Remove(&key); + } + + + // if we still have pending stuff to do, lets not close the plugin socket. + if (--mPendingRequests > 0) + return NS_OK; + + // we keep our connections around... + PRUint32 magicNumber = 0; // set it to something that is not the magic number. + nsCOMPtr container = do_QueryInterface(aContext); + if (container) + container->GetData(&magicNumber); + + if (magicNumber == MAGIC_REQUEST_CONTEXT) + { + // this is one of our range requests + return NS_OK; + } + + if(!mPStreamListener) + return NS_ERROR_FAILURE; + + if (!pathAndFilename) + mPluginStreamInfo->GetLocalCachedFile(getter_Copies(pathAndFilename)); + + if (!pathAndFilename) { + // see if it is a file channel. + nsCOMPtr fileChannel = do_QueryInterface(request); + if (fileChannel) + fileChannel->GetFile(getter_AddRefs(localFile)); + if (localFile) + localFile->GetPath(getter_Copies(pathAndFilename)); + + mPluginStreamInfo->SetLocalCachedFile(pathAndFilename); + } + + if (pathAndFilename) + OnFileAvailable(pathAndFilename); + nsCOMPtr aURL; nsCOMPtr channel = do_QueryInterface(request); if (!channel) @@ -1495,59 +1795,34 @@ NS_IMETHODIMP nsPluginStreamListenerPeer::OnStopRequest(nsIRequest *request, rv = channel->GetURI(getter_AddRefs(aURL)); if (NS_FAILED(rv)) return rv; + + nsXPIDLCString urlString; + rv = aURL->GetSpec(getter_Copies(urlString)); + if (NS_SUCCEEDED(rv)) + mPluginStreamInfo->SetURL(urlString); + + // Set the content type to ensure we don't pass null to the plugin + nsXPIDLCString aContentType; + rv = channel->GetContentType(getter_Copies(aContentType)); + if (NS_FAILED(rv)) + return rv; - if(nsnull != mPStreamListener) + if (aContentType) + mPluginStreamInfo->SetContentType(aContentType); + + if (mStartBinding) { - char* urlString; - nsCOMPtr localFile; - - nsCOMPtr cacheChannel = do_QueryInterface(channel); - if (cacheChannel) - rv = cacheChannel->GetCacheFile(getter_AddRefs(localFile)); - if (NS_SUCCEEDED(rv) && localFile) - { - char* pathAndFilename; - rv = localFile->GetPath(&pathAndFilename); - if (NS_SUCCEEDED(rv)) - { - OnFileAvailable(pathAndFilename); - nsMemory::Free(pathAndFilename); - } - } - - rv = aURL->GetSpec(&urlString); - if (NS_SUCCEEDED(rv)) - { - mPluginStreamInfo->SetURL(urlString); - nsCRT::free(urlString); - } - - // Set the content type to ensure we don't pass null to the plugin - char* aContentType = nsnull; - rv = channel->GetContentType(&aContentType); - if (NS_FAILED(rv)) - return rv; - - if (nsnull != aContentType) - mPluginStreamInfo->SetContentType(aContentType); - - if (mStartBinding) - { - // On start binding has been called - mPStreamListener->OnStopBinding((nsIPluginStreamInfo*)mPluginStreamInfo, aStatus); - } - else - { - // OnStartBinding hasn't been called, so complete the action. - mPStreamListener->OnStartBinding((nsIPluginStreamInfo*)mPluginStreamInfo); - mPStreamListener->OnStopBinding((nsIPluginStreamInfo*)mPluginStreamInfo, aStatus); - } - - if (aContentType) - nsCRT::free(aContentType); + // On start binding has been called + mPStreamListener->OnStopBinding((nsIPluginStreamInfo*)mPluginStreamInfo, aStatus); + } + else + { + // OnStartBinding hasn't been called, so complete the action. + mPStreamListener->OnStartBinding((nsIPluginStreamInfo*)mPluginStreamInfo); + mPStreamListener->OnStopBinding((nsIPluginStreamInfo*)mPluginStreamInfo, aStatus); } - return rv; + return NS_OK; } // private methods for nsPluginStreamListenerPeer @@ -1604,6 +1879,7 @@ nsresult nsPluginStreamListenerPeer::SetUpStreamListener(nsIRequest *request, bSeekable = PR_TRUE; } } + mPluginStreamInfo->SetSeekable(bSeekable); // get Last-Modified header for plugin info diff --git a/modules/plugin/nglsrc/ns4xPlugin.cpp b/modules/plugin/nglsrc/ns4xPlugin.cpp index d38211c3ab49..3f5977a578f3 100644 --- a/modules/plugin/nglsrc/ns4xPlugin.cpp +++ b/modules/plugin/nglsrc/ns4xPlugin.cpp @@ -26,6 +26,7 @@ #include "nsplugin.h" #include "ns4xPlugin.h" #include "ns4xPluginInstance.h" +#include "ns4xPluginStreamListener.h" #include "nsIServiceManager.h" #include "nsIMemory.h" #include "nsIPluginStreamListener.h" @@ -676,6 +677,11 @@ ns4xStreamWrapper::GetStream(nsIOutputStream* &result) NPError NP_EXPORT _newstream(NPP npp, NPMIMEType type, const char* window, NPStream* *result) { + +#ifdef NS_DEBUG + printf("\nNewStream called \n\n"); +#endif + if(!npp) return NPERR_INVALID_INSTANCE_ERROR; @@ -719,6 +725,10 @@ _newstream(NPP npp, NPMIMEType type, const char* window, NPStream* *result) int32 NP_EXPORT _write(NPP npp, NPStream *pstream, int32 len, void *buffer) { +#ifdef NS_DEBUG + printf("\nWrite called by plugin: \n%s\n", buffer); +#endif + // negative return indicates failure to the plugin if(!npp) return -1; @@ -745,6 +755,11 @@ _write(NPP npp, NPStream *pstream, int32 len, void *buffer) NPError NP_EXPORT _destroystream(NPP npp, NPStream *pstream, NPError reason) { + + +#ifdef NS_DEBUG + printf("\nDestroy Stream called \n\n"); +#endif if(!npp) return NPERR_INVALID_INSTANCE_ERROR; @@ -770,7 +785,7 @@ _destroystream(NPP npp, NPStream *pstream, NPError reason) // This will release the wrapped nsIOutputStream. delete wrapper; - + pstream->ndata = nsnull; return NPERR_NO_ERROR; } @@ -1035,7 +1050,38 @@ _setvalue(NPP npp, NPPVariable variable, void *result) NPError NP_EXPORT _requestread(NPStream *pstream, NPByteRange *rangeList) { +#ifdef NS_DEBUG + printf("\nRequestRead called by plugin: "); + for(NPByteRange * range = rangeList; range != nsnull; range = range->next) + { + printf("%i-%i", range->offset, range->offset + range->length - 1); + if(range->next) + printf(","); + } + printf("\n\n"); +#endif + + if(!pstream || !rangeList || !pstream->ndata) + return NPERR_INVALID_PARAM; + + nsresult res = NS_OK; + + ns4xPluginStreamListener * streamlistener = (ns4xPluginStreamListener *)pstream->ndata; + + if(NS_FAILED(res)) + return NPERR_GENERIC_ERROR; + + nsPluginStreamType streamtype = nsPluginStreamType_Normal; + + streamlistener->GetStreamType(&streamtype); + + if(streamtype != nsPluginStreamType_Seek) return NPERR_STREAM_NOT_SEEKABLE; + + if(streamlistener->mStreamInfo) + streamlistener->mStreamInfo->RequestRead((nsByteRange *)rangeList); + + return NS_OK; } diff --git a/modules/plugin/nglsrc/ns4xPluginInstance.cpp b/modules/plugin/nglsrc/ns4xPluginInstance.cpp index a07163bb5e1a..7d373fbcb060 100644 --- a/modules/plugin/nglsrc/ns4xPluginInstance.cpp +++ b/modules/plugin/nglsrc/ns4xPluginInstance.cpp @@ -21,7 +21,7 @@ */ #include "ns4xPluginInstance.h" -#include "nsIPluginStreamListener.h" +#include "ns4xPluginStreamListener.h" #include "nsPluginHostImpl.h" #include "prlog.h" @@ -40,46 +40,6 @@ static NS_DEFINE_CID(kPrefServiceCID, NS_PREF_CID); // needed for NS_TRY_SAFE_CALL_* static NS_DEFINE_IID(kCPluginManagerCID, NS_PLUGINMANAGER_CID); -#define MAX_PLUGIN_NECKO_BUFFER 16384 - -class ns4xPluginStreamListener : public nsIPluginStreamListener { - -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 OnStopBinding(nsIPluginStreamInfo* pluginInfo, nsresult status); - - NS_IMETHOD GetStreamType(nsPluginStreamType *result); - - /////////////////////////////////////////////////////////////////////////// - // ns4xPluginStreamListener specific methods: - - ns4xPluginStreamListener(nsIPluginInstance* inst, void* notifyData); - virtual ~ns4xPluginStreamListener(void); - PRBool IsStarted(void); - -protected: - - void* mNotifyData; - char* mStreamBuffer; - ns4xPluginInstance* mInst; - NPStream mNPStream; - PRUint32 mPosition; - nsPluginStreamType mStreamType; -}; - - /////////////////////////////////////////////////////////////////////////////// // ns4xPluginStreamListener Methods /////////////////////////////////////////////////////////////////////////////// @@ -88,13 +48,13 @@ static NS_DEFINE_IID(kIPluginStreamListenerIID, NS_IPLUGINSTREAMLISTENER_IID); ns4xPluginStreamListener::ns4xPluginStreamListener(nsIPluginInstance* inst, void* notifyData) - : mNotifyData(notifyData) + : mNotifyData(notifyData), + mStreamInfo(nsnull) { NS_INIT_REFCNT(); mInst = (ns4xPluginInstance*) inst; - mPosition = 0; - mStreamBuffer=nsnull; - + mStreamBuffer=nsnull; + mPosition = 0; // Initialize the 4.x interface structure memset(&mNPStream, 0, sizeof(mNPStream)); @@ -137,6 +97,8 @@ ns4xPluginStreamListener::OnStartBinding(nsIPluginStreamInfo* pluginInfo) pluginInfo->IsSeekable(&seekable); pluginInfo->GetContentType(&contentType); + mStreamInfo = pluginInfo; + PRLibrary* lib = mInst->fLibrary; // if we don't know the end of the stream, use 0 instead of -1. bug 59571 @@ -185,6 +147,7 @@ ns4xPluginStreamListener::OnStartBinding(nsIPluginStreamInfo* pluginInfo) NS_IMETHODIMP ns4xPluginStreamListener::OnDataAvailable(nsIPluginStreamInfo* pluginInfo, nsIInputStream* input, + PRUint32 sourceOffset, PRUint32 length) { if (!mInst || !mInst->IsStarted()) @@ -205,6 +168,11 @@ ns4xPluginStreamListener::OnDataAvailable(nsIPluginStreamInfo* pluginInfo, PRUint32 leftToRead = 0; // just in case OnDataaAvail tries to overflow our buffer PRBool createdHere = PR_FALSE; // we did malloc in locally, so we must free locally + // we are getting a range request, reset mPosition since postion passed to plugin will + // be relative to the absolute position of the file. + if (sourceOffset != 0) + mPosition = 0; + pluginInfo->GetURL(&mNPStream.url); pluginInfo->GetLastModified((PRUint32*)&(mNPStream.lastmodified)); @@ -267,10 +235,24 @@ ns4xPluginStreamListener::OnDataAvailable(nsIPluginStreamInfo* pluginInfo, { PRLibrary* lib = mInst->fLibrary; +#ifdef DEBUG_dougt + printf("> %d - %d \n", sourceOffset + writeCount + mPosition, numtowrite); +#if 0 + nsCString x; + x.Append("d:\\parts\\"); + x.AppendInt(sourceOffset); + + PRFileDesc* fd; + fd = PR_Open(x, PR_CREATE_FILE |PR_SYNC| PR_APPEND | PR_RDWR, 777); + PR_Write(fd, mStreamBuffer, numtowrite); + PR_Close(fd); +#endif +#endif + NS_TRY_SAFE_CALL_RETURN(writeCount, CallNPP_WriteProc(callbacks->write, npp, &mNPStream, - mPosition, + sourceOffset + writeCount + mPosition, numtowrite, (void *)mStreamBuffer), lib); if (writeCount < 0) { @@ -278,8 +260,10 @@ ns4xPluginStreamListener::OnDataAvailable(nsIPluginStreamInfo* pluginInfo, goto error; } + if (sourceOffset == 0) + mPosition += numtowrite; + amountRead -= numtowrite; - mPosition += numtowrite; } } @@ -294,7 +278,7 @@ error: if (leftToRead > 0) // if we have more to read in this pass, do it recursivly { - OnDataAvailable(pluginInfo, input, leftToRead); + OnDataAvailable(pluginInfo, input, sourceOffset, leftToRead); } return rv; diff --git a/modules/plugin/nglsrc/ns4xPluginInstance.h b/modules/plugin/nglsrc/ns4xPluginInstance.h index 88c64f5e416f..c54c545c3cd1 100644 --- a/modules/plugin/nglsrc/ns4xPluginInstance.h +++ b/modules/plugin/nglsrc/ns4xPluginInstance.h @@ -116,7 +116,7 @@ public: // returns the state of mStarted PRBool IsStarted(void); - + protected: nsresult InitializePlugin(nsIPluginInstancePeer* peer); diff --git a/modules/plugin/nglsrc/ns4xPluginStreamListener.h b/modules/plugin/nglsrc/ns4xPluginStreamListener.h new file mode 100644 index 000000000000..1eea37fe3dc6 --- /dev/null +++ b/modules/plugin/nglsrc/ns4xPluginStreamListener.h @@ -0,0 +1,60 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- + * + * The contents of this file are subject to the Netscape Public + * License Version 1.1 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.mozilla.org/NPL/ + * + * Software distributed under the License is distributed on an "AS + * IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or + * implied. See the License for the specific language governing + * rights and limitations under the License. + * + * The Original Code is mozilla.org code. + * + * The Initial Developer of the Original Code is Netscape + * Communications Corporation. Portions created by Netscape are + * Copyright (C) 1998 Netscape Communications Corporation. All + * Rights Reserved. + * + * Contributor(s): + */ + +#ifndef ns4xPluginStreamListener_h__ +#define ns4xPluginStreamListener_h__ + +#include "nsIPluginStreamListener.h" +#include "nsIPluginStreamInfo.h" + +#define MAX_PLUGIN_NECKO_BUFFER 16384 + +class ns4xPluginStreamListener : public nsIPluginStreamListener +{ +public: + NS_DECL_ISUPPORTS + + // from nsIPluginStreamListener: + NS_IMETHOD OnStartBinding(nsIPluginStreamInfo* pluginInfo); + NS_IMETHOD OnDataAvailable(nsIPluginStreamInfo* pluginInfo, nsIInputStream* input, PRUint32 length, PRUint32 offset); + NS_IMETHOD OnFileAvailable( nsIPluginStreamInfo* pluginInfo, const char* fileName); + NS_IMETHOD OnStopBinding(nsIPluginStreamInfo* pluginInfo, nsresult status); + NS_IMETHOD GetStreamType(nsPluginStreamType *result); + + // ns4xPluginStreamListener specific methods: + ns4xPluginStreamListener(nsIPluginInstance* inst, void* notifyData); + virtual ~ns4xPluginStreamListener(); + PRBool IsStarted(); + +protected: + void* mNotifyData; + char* mStreamBuffer; + ns4xPluginInstance* mInst; + NPStream mNPStream; + PRUint32 mPosition; + nsPluginStreamType mStreamType; + +public: + nsIPluginStreamInfo * mStreamInfo; +}; + +#endif diff --git a/modules/plugin/nglsrc/nsPluginHostImpl.cpp b/modules/plugin/nglsrc/nsPluginHostImpl.cpp index df92a94a8378..f32600fed836 100644 --- a/modules/plugin/nglsrc/nsPluginHostImpl.cpp +++ b/modules/plugin/nglsrc/nsPluginHostImpl.cpp @@ -37,6 +37,7 @@ #include "nsIObserverService.h" #include "nsIHttpProtocolHandler.h" #include "nsIHttpChannel.h" +#include "nsIByteRangeRequest.h" #include "nsIStreamListener.h" #include "nsIInputStream.h" #include "nsIOutputStream.h" @@ -44,6 +45,7 @@ #include "nsXPIDLString.h" #include "nsIPref.h" #include "nsIProtocolProxyService.h" +#include "nsIStreamConverterService.h" #include "nsIFile.h" #include "nsIInputStream.h" #include "nsIIOService.h" @@ -55,6 +57,8 @@ #include "nsIDocument.h" #include "nsIScriptablePlugin.h" #include "nsICachingChannel.h" +#include "nsHashtable.h" + // Friggin' X11 has to "#define None". Lame! #ifdef None @@ -63,12 +67,11 @@ #include "nsIRegistry.h" #include "nsEnumeratorUtils.h" - +#include "nsISupportsPrimitives.h" // for the dialog #include "nsIStringBundle.h" #include "nsIPrompt.h" #include "nsIWindowWatcher.h" -#include "nsHashtable.h" #include "nsIScriptGlobalObject.h" #include "nsIScriptGlobalObjectOwner.h" @@ -144,6 +147,7 @@ static NS_DEFINE_IID(kIRequestObserverIID, NS_IREQUESTOBSERVER_IID); static NS_DEFINE_CID(kIOServiceCID, NS_IOSERVICE_CID); static NS_DEFINE_CID(kHttpHandlerCID, NS_HTTPPROTOCOLHANDLER_CID); static NS_DEFINE_CID(kIHttpHeaderVisitorIID, NS_IHTTPHEADERVISITOR_IID); +static NS_DEFINE_CID(kStreamConverterServiceCID, NS_STREAMCONVERTERSERVICE_CID); static NS_DEFINE_IID(kIFileUtilitiesIID, NS_IFILEUTILITIES_IID); static NS_DEFINE_IID(kIOutputStreamIID, NS_IOUTPUTSTREAM_IID); @@ -167,6 +171,8 @@ static NS_DEFINE_CID(kComponentManagerCID, NS_COMPONENTMANAGER_CID); #define NS_PREF_MAX_NUM_CACHED_PLUGINS "browser.plugins.max_num_cached_plugins" #define DEFAULT_NUMBER_OF_STOPPED_PLUGINS 10 +#define MAGIC_REQUEST_CONTEXT 0x01020304 + void DisplayNoDefaultPluginDialog(const char *mimeType); /** @@ -828,10 +834,11 @@ void nsPluginTag::TryUnloadPlugin(PRBool aForceShutdown) mLibrary = nsnull; } +class nsPluginStreamListenerPeer; + class nsPluginStreamInfo : public nsIPluginStreamInfo { public: - nsPluginStreamInfo(); virtual ~nsPluginStreamInfo(); @@ -874,22 +881,116 @@ public: void SetURL(const char* url); + void + SetPluginInstance(nsIPluginInstance * aPluginInstance); + + void + SetPluginStreamListenerPeer(nsPluginStreamListenerPeer * aPluginStreamListenerPeer); + + void + MakeByteRangeString(nsByteRange* aRangeList, char** string, PRInt32 *numRequests); + + void + SetLocalCachedFile(const char* path); + + void + GetLocalCachedFile(char** path); + private: char* mContentType; char* mURL; - PRBool mSeekable; + char* mFilePath; + PRBool mSeekable; PRUint32 mLength; PRUint32 mModified; + nsIPluginInstance * mPluginInstance; + nsPluginStreamListenerPeer * mPluginStreamListenerPeer; +}; + +/////////////////////////////////////////////////////////////////////////////////////////////////// + +class nsPluginStreamListenerPeer : public nsIStreamListener, + public nsIProgressEventSink, + public nsIHttpHeaderVisitor +{ +public: + nsPluginStreamListenerPeer(); + virtual ~nsPluginStreamListenerPeer(); + + NS_DECL_ISUPPORTS + NS_DECL_NSIPROGRESSEVENTSINK + NS_DECL_NSIREQUESTOBSERVER + NS_DECL_NSISTREAMLISTENER + NS_DECL_NSIHTTPHEADERVISITOR + + // Called by GetURL and PostURL (via NewStream) + nsresult Initialize(nsIURI *aURL, + nsIPluginInstance *aInstance, + nsIPluginStreamListener *aListener, + PRInt32 requestCount = 1); + + nsresult InitializeEmbeded(nsIURI *aURL, + nsIPluginInstance* aInstance, + nsIPluginInstanceOwner *aOwner = nsnull, + nsIPluginHost *aHost = nsnull); + + nsresult InitializeFullPage(nsIPluginInstance *aInstance); + + nsresult OnFileAvailable(const char* aFilename); + + nsILoadGroup* GetLoadGroup(); + + nsresult SetLocalFile(const char* aFilename); + +private: + nsresult SetUpCache(nsIURI* aURL); + nsresult SetUpStreamListener(nsIRequest* request, nsIURI* aURL); + + nsIURI *mURL; + + + nsIPluginInstanceOwner *mOwner; + nsIPluginInstance *mInstance; + nsIPluginStreamListener *mPStreamListener; + nsPluginStreamInfo *mPluginStreamInfo; + PRBool mSetUpListener; + + /* + * Set to PR_TRUE after nsIPluginInstancePeer::OnStartBinding() has + * been called. Checked in ::OnStopRequest so we can call the + * plugin's OnStartBinding if, for some reason, it has not already + * been called. + */ + PRPackedBool mStartBinding; + PRPackedBool mHaveFiredOnStartRequest; + // these get passed to the plugin stream listener + char *mMIMEType; + PRUint32 mLength; + nsPluginStreamType mStreamType; + nsIPluginHost *mHost; + + // local file which was used to post data and which should be deleted after that + char *mLocalFile; + nsHashtable *mDataForwardToRequest; + +public: + PRBool mAbort; + PRInt32 mPendingRequests; + }; nsPluginStreamInfo::nsPluginStreamInfo() { NS_INIT_REFCNT(); + mPluginInstance = nsnull; + mPluginStreamListenerPeer = nsnull; + mContentType = nsnull; mURL = nsnull; - mSeekable = PR_FALSE; + mFilePath = nsnull; + mSeekable = PR_FALSE; mLength = 0; mModified = 0; } @@ -900,6 +1001,11 @@ nsPluginStreamInfo::~nsPluginStreamInfo() PL_strfree(mContentType); if(mURL != nsnull) PL_strfree(mURL); + if(mFilePath != nsnull) + PL_strfree(mFilePath); + + NS_IF_RELEASE(mPluginInstance); + NS_IF_RELEASE(mPluginStreamListenerPeer); } NS_IMPL_ADDREF(nsPluginStreamInfo) @@ -965,10 +1071,111 @@ nsPluginStreamInfo::GetURL(const char** result) return NS_OK; } + +void +nsPluginStreamInfo::MakeByteRangeString(nsByteRange* aRangeList, char** rangeRequest, PRInt32 *numRequests) +{ + *rangeRequest = nsnull; + *numRequests = 0; + //the string should look like this: bytes=500-700,601-999 + if(!aRangeList) + return; + + PRInt32 requestCnt = 0; + // XXX needs to be smarter than that + char * string = new char[1024]; + + string[0] = '\0'; + PL_strcat(string, "bytes="); + + for(nsByteRange * range = aRangeList; range != nsnull; range = range->next) + { + // XXX zero length? + if(!range->length) + continue; + + // XXX needs to be fixed for negative offsets + nsCString firstbyte; firstbyte.AppendInt(range->offset); + nsCString lastbyte; firstbyte.AppendInt(range->offset + range->length - 1); + + PL_strcat(string, firstbyte.get()); + PL_strcat(string, "-"); + PL_strcat(string, lastbyte.get()); + if(range->next) + PL_strcat(string, ","); + + requestCnt++; + } + + // get rid of possible tailing comma + PRInt32 len = PL_strlen(string); + if(string[len - 1] == ',') + string[len - 1] = '\0'; + + *rangeRequest = string; + *numRequests = requestCnt; + + return; +} + NS_IMETHODIMP nsPluginStreamInfo::RequestRead(nsByteRange* rangeList) { - return NS_ERROR_NOT_IMPLEMENTED; + mPluginStreamListenerPeer->mAbort = PR_TRUE; + + nsresult rv = NS_OK; + nsCOMPtr url; + + rv = NS_NewURI(getter_AddRefs(url), mURL); + + nsCOMPtr channel; + rv = NS_OpenURI(getter_AddRefs(channel), url, nsnull, nsnull, nsnull); + if (NS_FAILED(rv)) + return rv; + + nsCOMPtr httpChannel(do_QueryInterface(channel)); + if(!httpChannel) + return NS_ERROR_FAILURE; + + char *rangeString; + PRInt32 numRequests; + + MakeByteRangeString(rangeList, &rangeString, &numRequests); + + if(!rangeString) + return NS_ERROR_FAILURE; + + httpChannel->SetRequestHeader("Range", rangeString); + + delete [] rangeString; + + // instruct old stream listener to cancel the request on the next + // attempt to write. + + nsCOMPtr converter = mPluginStreamListenerPeer; + + if (numRequests > 1) { + nsCOMPtr serv = do_GetService(kStreamConverterServiceCID, &rv); + if (NS_FAILED(rv)) + return rv; + + rv = serv->AsyncConvertData(NS_LITERAL_STRING("multipart/byteranges").get(), + NS_LITERAL_STRING("*/*").get(), + mPluginStreamListenerPeer, + nsnull, + getter_AddRefs(converter)); + if (NS_FAILED(rv)) + return rv; + } + + mPluginStreamListenerPeer->mPendingRequests += numRequests; + + nsCOMPtr container = do_CreateInstance(NS_SUPPORTS_PRUINT32_CONTRACTID, &rv); + if (NS_FAILED(rv)) return rv; + rv = container->SetData(MAGIC_REQUEST_CONTEXT); + if (NS_FAILED(rv)) return rv; + + return channel->AsyncOpen(converter, container); } // local methods @@ -1009,68 +1216,33 @@ nsPluginStreamInfo::SetURL(const char* url) mURL = PL_strdup(url); } -/////////////////////////////////////////////////////////////////////////////////////////////////// -class nsPluginStreamListenerPeer : public nsIStreamListener, - public nsIProgressEventSink, - public nsIHttpHeaderVisitor +void +nsPluginStreamInfo::SetLocalCachedFile(const char* path) +{ + if(mFilePath != nsnull) + PL_strfree(mFilePath); + + mFilePath = PL_strdup(path); +} + +void +nsPluginStreamInfo::GetLocalCachedFile(char** path) +{ + *path = PL_strdup(mFilePath); +} + +void +nsPluginStreamInfo::SetPluginInstance(nsIPluginInstance * aPluginInstance) { -public: - nsPluginStreamListenerPeer(); - virtual ~nsPluginStreamListenerPeer(); + NS_IF_ADDREF(mPluginInstance = aPluginInstance); +} - NS_DECL_ISUPPORTS - NS_DECL_NSIPROGRESSEVENTSINK - NS_DECL_NSIREQUESTOBSERVER - NS_DECL_NSISTREAMLISTENER - NS_DECL_NSIHTTPHEADERVISITOR - - // Called by GetURL and PostURL (via NewStream) - nsresult Initialize(nsIURI *aURL, - nsIPluginInstance *aInstance, - nsIPluginStreamListener *aListener); - - nsresult InitializeEmbeded(nsIURI *aURL, - nsIPluginInstance* aInstance, - nsIPluginInstanceOwner *aOwner = nsnull, - nsIPluginHost *aHost = nsnull); - - nsresult InitializeFullPage(nsIPluginInstance *aInstance); - - nsresult OnFileAvailable(const char* aFilename); - - nsILoadGroup* GetLoadGroup(); - - nsresult SetLocalFile(const char* aFilename); - -private: - nsresult SetUpCache(nsIURI* aURL); - nsresult SetUpStreamListener(nsIRequest* request, nsIURI* aURL); - - nsIURI *mURL; - nsIPluginInstanceOwner *mOwner; - nsIPluginInstance *mInstance; - nsIPluginStreamListener *mPStreamListener; - nsPluginStreamInfo *mPluginStreamInfo; - PRBool mSetUpListener; - - /* - * Set to PR_TRUE after nsIPluginInstancePeer::OnStartBinding() has - * been called. Checked in ::OnStopRequest so we can call the - * plugin's OnStartBinding if, for some reason, it has not already - * been called. - */ - PRBool mStartBinding; - - // these get passed to the plugin stream listener - char *mMIMEType; - PRUint32 mLength; - nsPluginStreamType mStreamType; - nsIPluginHost *mHost; - - // local file which was used to post data and which should be deleted after that - char *mLocalFile; -}; +void +nsPluginStreamInfo::SetPluginStreamListenerPeer(nsPluginStreamListenerPeer * aPluginStreamListenerPeer) +{ + NS_IF_ADDREF(mPluginStreamListenerPeer = aPluginStreamListenerPeer); +} /////////////////////////////////////////////////////////////////////////////////////////////////// @@ -1157,6 +1329,11 @@ nsPluginStreamListenerPeer::nsPluginStreamListenerPeer() mStreamType = nsPluginStreamType_Normal; mStartBinding = PR_FALSE; mLocalFile = nsnull; + mAbort = PR_FALSE; + + mPendingRequests = 0; + mHaveFiredOnStartRequest = PR_FALSE; + mDataForwardToRequest = nsnull; } nsPluginStreamListenerPeer::~nsPluginStreamListenerPeer() @@ -1187,55 +1364,21 @@ nsPluginStreamListenerPeer::~nsPluginStreamListenerPeer() localFile->Delete(PR_FALSE); delete [] mLocalFile; } + delete mDataForwardToRequest; } -NS_IMPL_ADDREF(nsPluginStreamListenerPeer); -NS_IMPL_RELEASE(nsPluginStreamListenerPeer); +NS_IMPL_ISUPPORTS3(nsPluginStreamListenerPeer, + nsIStreamListener, + nsIRequestObserver, + nsIHttpHeaderVisitor) -nsresult nsPluginStreamListenerPeer::QueryInterface(const nsIID& aIID, - void** aInstancePtrResult) -{ - NS_PRECONDITION(nsnull != aInstancePtrResult, "null pointer"); - - if (nsnull == aInstancePtrResult) - return NS_ERROR_NULL_POINTER; - - if (aIID.Equals(kIStreamListenerIID)) - { - *aInstancePtrResult = (void *)((nsIStreamListener *)this); - AddRef(); - return NS_OK; - } - - if (aIID.Equals(kIRequestObserverIID)) - { - *aInstancePtrResult = (void *)((nsIRequestObserver *)this); - AddRef(); - return NS_OK; - } - - if (aIID.Equals(kIHttpHeaderVisitorIID)) - { - *aInstancePtrResult = (void *)((nsIHttpHeaderVisitor *)this); - AddRef(); - return NS_OK; - } - - if (aIID.Equals(kISupportsIID)) - { - *aInstancePtrResult = (void *)((nsISupports *)((nsIStreamListener *)this)); - AddRef(); - return NS_OK; - } - - return NS_NOINTERFACE; -} /* Called as a result of GetURL and PostURL */ nsresult nsPluginStreamListenerPeer::Initialize(nsIURI *aURL, nsIPluginInstance *aInstance, - nsIPluginStreamListener* aListener) + nsIPluginStreamListener* aListener, + PRInt32 requestCount) { #ifdef NS_DEBUG char* spec; @@ -1255,6 +1398,15 @@ nsresult nsPluginStreamListenerPeer::Initialize(nsIURI *aURL, mPluginStreamInfo = new nsPluginStreamInfo(); + mPluginStreamInfo->SetPluginInstance(aInstance); + mPluginStreamInfo->SetPluginStreamListenerPeer(this); + + mPendingRequests = requestCount; + + mDataForwardToRequest = new nsHashtable(16, PR_FALSE); + if (!mDataForwardToRequest) + return NS_ERROR_FAILURE; + return NS_OK; } @@ -1297,6 +1449,13 @@ nsresult nsPluginStreamListenerPeer::InitializeEmbeded(nsIURI *aURL, mPluginStreamInfo = new nsPluginStreamInfo(); + mPluginStreamInfo->SetPluginInstance(aInstance); + mPluginStreamInfo->SetPluginStreamListenerPeer(this); + + mDataForwardToRequest = new nsHashtable(16, PR_FALSE); + if (!mDataForwardToRequest) + return NS_ERROR_FAILURE; + return NS_OK; } @@ -1315,6 +1474,13 @@ nsresult nsPluginStreamListenerPeer::InitializeFullPage(nsIPluginInstance *aInst mPluginStreamInfo = new nsPluginStreamInfo(); + mPluginStreamInfo->SetPluginInstance(aInstance); + mPluginStreamInfo->SetPluginStreamListenerPeer(this); + + mDataForwardToRequest = new nsHashtable(16, PR_FALSE); + if (!mDataForwardToRequest) + return NS_ERROR_FAILURE; + return NS_OK; } @@ -1324,6 +1490,12 @@ nsPluginStreamListenerPeer::OnStartRequest(nsIRequest *request, nsISupports* aCo { nsresult rv = NS_OK; + if (mHaveFiredOnStartRequest) { + return NS_OK; + } + + mHaveFiredOnStartRequest = PR_TRUE; + nsCOMPtr channel = do_QueryInterface(request); if (!channel) @@ -1435,12 +1607,52 @@ NS_IMETHODIMP nsPluginStreamListenerPeer::OnStatus(nsIRequest *request, return NS_OK; } + + +class nsPRUintKey : public nsHashKey { +protected: + PRUint32 mKey; +public: + nsPRUintKey(PRUint32 key) : mKey(key) {} + + PRUint32 HashCode(void) const { + return mKey; + } + + PRBool Equals(const nsHashKey *aKey) const { + return mKey == ((const nsPRUintKey *) aKey)->mKey; + } + nsHashKey *Clone() const { + return new nsPRUintKey(mKey); + } + PRUint32 GetValue() { return mKey; } +}; + + NS_IMETHODIMP nsPluginStreamListenerPeer::OnDataAvailable(nsIRequest *request, nsISupports* aContext, nsIInputStream *aIStream, PRUint32 sourceOffset, PRUint32 aLength) { + + + if(mAbort) + { + PRUint32 magicNumber = 0; // set it to something that is not the magic number. + nsCOMPtr container = do_QueryInterface(aContext); + if (container) + container->GetData(&magicNumber); + + if (magicNumber != MAGIC_REQUEST_CONTEXT) + { + // this is not one of our range requests + mAbort = PR_FALSE; + return NS_BINDING_ABORTED; + } + } + + nsresult rv = NS_OK; nsCOMPtr aURL; nsCOMPtr channel = do_QueryInterface(request); @@ -1463,9 +1675,30 @@ NS_IMETHODIMP nsPluginStreamListenerPeer::OnDataAvailable(nsIRequest *request, // call OnDataAvailable if(mStreamType != nsPluginStreamType_AsFileOnly) { - // It's up to the plugin to read from the stream - // If it doesn't, OnStopRequest will never be called - rv = mPStreamListener->OnDataAvailable((nsIPluginStreamInfo*)mPluginStreamInfo, aIStream, aLength); + // get the absolute offset of the request, if one exists. + nsCOMPtr 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->Exists(&key)) + amtForwardToPlugin = (PRInt32) mDataForwardToRequest->Remove(&key); + + mDataForwardToRequest->Put(&key, (void*) (amtForwardToPlugin+aLength)); + } + + rv = mPStreamListener->OnDataAvailable((nsIPluginStreamInfo*)mPluginStreamInfo, + aIStream, + absoluteOffset+amtForwardToPlugin, + aLength); + // if a plugin returns an error, the peer must kill the stream // else the stream and PluginStreamListener leak if (NS_FAILED(rv)) @@ -1486,7 +1719,74 @@ NS_IMETHODIMP nsPluginStreamListenerPeer::OnStopRequest(nsIRequest *request, nsISupports* aContext, nsresult aStatus) { + nsresult rv = NS_OK; + nsCOMPtr cacheChannel = do_QueryInterface(request); + nsCOMPtr localFile; + nsXPIDLCString pathAndFilename; + + // doing multiple requests, the main url load (the cacheable entry) could come + // out of order. Here we will check to see if the request is main url load. + + if (cacheChannel) { + rv = cacheChannel->GetCacheFile(getter_AddRefs(localFile)); + if (NS_SUCCEEDED(rv)) { + localFile->GetPath(getter_Copies(pathAndFilename)); + mPluginStreamInfo->SetLocalCachedFile(pathAndFilename); + } + } + + // remove the request from our data forwarding count hash. + nsCOMPtr brr = do_QueryInterface(request); + if (brr) { + PRInt32 absoluteOffset = 0; + brr->GetStartRange(&absoluteOffset); + + nsPRUintKey key(absoluteOffset); + + if (!mDataForwardToRequest) + return NS_ERROR_FAILURE; + + (void) mDataForwardToRequest->Remove(&key); + } + + + // if we still have pending stuff to do, lets not close the plugin socket. + if (--mPendingRequests > 0) + return NS_OK; + + // we keep our connections around... + PRUint32 magicNumber = 0; // set it to something that is not the magic number. + nsCOMPtr container = do_QueryInterface(aContext); + if (container) + container->GetData(&magicNumber); + + if (magicNumber == MAGIC_REQUEST_CONTEXT) + { + // this is one of our range requests + return NS_OK; + } + + if(!mPStreamListener) + return NS_ERROR_FAILURE; + + if (!pathAndFilename) + mPluginStreamInfo->GetLocalCachedFile(getter_Copies(pathAndFilename)); + + if (!pathAndFilename) { + // see if it is a file channel. + nsCOMPtr fileChannel = do_QueryInterface(request); + if (fileChannel) + fileChannel->GetFile(getter_AddRefs(localFile)); + if (localFile) + localFile->GetPath(getter_Copies(pathAndFilename)); + + mPluginStreamInfo->SetLocalCachedFile(pathAndFilename); + } + + if (pathAndFilename) + OnFileAvailable(pathAndFilename); + nsCOMPtr aURL; nsCOMPtr channel = do_QueryInterface(request); if (!channel) @@ -1495,59 +1795,34 @@ NS_IMETHODIMP nsPluginStreamListenerPeer::OnStopRequest(nsIRequest *request, rv = channel->GetURI(getter_AddRefs(aURL)); if (NS_FAILED(rv)) return rv; + + nsXPIDLCString urlString; + rv = aURL->GetSpec(getter_Copies(urlString)); + if (NS_SUCCEEDED(rv)) + mPluginStreamInfo->SetURL(urlString); + + // Set the content type to ensure we don't pass null to the plugin + nsXPIDLCString aContentType; + rv = channel->GetContentType(getter_Copies(aContentType)); + if (NS_FAILED(rv)) + return rv; - if(nsnull != mPStreamListener) + if (aContentType) + mPluginStreamInfo->SetContentType(aContentType); + + if (mStartBinding) { - char* urlString; - nsCOMPtr localFile; - - nsCOMPtr cacheChannel = do_QueryInterface(channel); - if (cacheChannel) - rv = cacheChannel->GetCacheFile(getter_AddRefs(localFile)); - if (NS_SUCCEEDED(rv) && localFile) - { - char* pathAndFilename; - rv = localFile->GetPath(&pathAndFilename); - if (NS_SUCCEEDED(rv)) - { - OnFileAvailable(pathAndFilename); - nsMemory::Free(pathAndFilename); - } - } - - rv = aURL->GetSpec(&urlString); - if (NS_SUCCEEDED(rv)) - { - mPluginStreamInfo->SetURL(urlString); - nsCRT::free(urlString); - } - - // Set the content type to ensure we don't pass null to the plugin - char* aContentType = nsnull; - rv = channel->GetContentType(&aContentType); - if (NS_FAILED(rv)) - return rv; - - if (nsnull != aContentType) - mPluginStreamInfo->SetContentType(aContentType); - - if (mStartBinding) - { - // On start binding has been called - mPStreamListener->OnStopBinding((nsIPluginStreamInfo*)mPluginStreamInfo, aStatus); - } - else - { - // OnStartBinding hasn't been called, so complete the action. - mPStreamListener->OnStartBinding((nsIPluginStreamInfo*)mPluginStreamInfo); - mPStreamListener->OnStopBinding((nsIPluginStreamInfo*)mPluginStreamInfo, aStatus); - } - - if (aContentType) - nsCRT::free(aContentType); + // On start binding has been called + mPStreamListener->OnStopBinding((nsIPluginStreamInfo*)mPluginStreamInfo, aStatus); + } + else + { + // OnStartBinding hasn't been called, so complete the action. + mPStreamListener->OnStartBinding((nsIPluginStreamInfo*)mPluginStreamInfo); + mPStreamListener->OnStopBinding((nsIPluginStreamInfo*)mPluginStreamInfo, aStatus); } - return rv; + return NS_OK; } // private methods for nsPluginStreamListenerPeer @@ -1604,6 +1879,7 @@ nsresult nsPluginStreamListenerPeer::SetUpStreamListener(nsIRequest *request, bSeekable = PR_TRUE; } } + mPluginStreamInfo->SetSeekable(bSeekable); // get Last-Modified header for plugin info diff --git a/modules/plugin/public/nsIPluginStreamListener.h b/modules/plugin/public/nsIPluginStreamListener.h index dafc287a33ed..52a48c7644ed 100644 --- a/modules/plugin/public/nsIPluginStreamListener.h +++ b/modules/plugin/public/nsIPluginStreamListener.h @@ -82,7 +82,7 @@ public: * @return The return value is currently ignored. */ NS_IMETHOD - OnDataAvailable(nsIPluginStreamInfo* pluginInfo, nsIInputStream* input, PRUint32 length) = 0; + OnDataAvailable(nsIPluginStreamInfo* pluginInfo, nsIInputStream* input, PRUint32 sourceOffset, PRUint32 length) = 0; NS_IMETHOD OnFileAvailable(nsIPluginStreamInfo* pluginInfo, const char* fileName) = 0;