From d35036b4b4d5e629b29880bad8989c553042341c Mon Sep 17 00:00:00 2001 From: "warren%netscape.com" Date: Sat, 12 Jun 1999 07:14:19 +0000 Subject: [PATCH] Merged in file transport stuff (now file transport is obsolete). --- netwerk/protocol/file/public/Makefile.in | 5 +- netwerk/protocol/file/public/makefile.win | 5 +- .../protocol/file/public/nsIFileChannel.idl | 18 +- .../file/public/nsIFileProtocolHandler.idl | 26 ++ netwerk/protocol/file/src/makefile.win | 17 +- netwerk/protocol/file/src/nsFileChannel.cpp | 356 +++++++++++++++++- netwerk/protocol/file/src/nsFileChannel.h | 60 ++- .../file/src/nsFileProtocolHandler.cpp | 94 ++++- .../protocol/file/src/nsFileProtocolHandler.h | 16 + 9 files changed, 561 insertions(+), 36 deletions(-) create mode 100644 netwerk/protocol/file/public/nsIFileProtocolHandler.idl diff --git a/netwerk/protocol/file/public/Makefile.in b/netwerk/protocol/file/public/Makefile.in index fe53c7de3f7e..129479a5f2a0 100644 --- a/netwerk/protocol/file/public/Makefile.in +++ b/netwerk/protocol/file/public/Makefile.in @@ -25,8 +25,9 @@ VPATH = @srcdir@ XPIDL_MODULE = netwerk_file -XPIDLSRCS = \ - nsIFileChannel.idl \ +XPIDLSRCS = \ + .\nsIFileChannel.idl \ + .\nsIFileProtocolHandler.idl \ $(NULL) include $(DEPTH)/config/autoconf.mk diff --git a/netwerk/protocol/file/public/makefile.win b/netwerk/protocol/file/public/makefile.win index 15d41efe615f..d246bcf9ac11 100644 --- a/netwerk/protocol/file/public/makefile.win +++ b/netwerk/protocol/file/public/makefile.win @@ -27,8 +27,9 @@ PUBLIC = $(DEPTH)\netwerk\dist\include XPIDL_MODULE = netwerk_file -XPIDLSRCS = \ - .\nsIFileChannel.idl \ +XPIDLSRCS = \ + .\nsIFileChannel.idl \ + .\nsIFileProtocolHandler.idl \ $(NULL) include <$(DEPTH)/config/rules.mak> diff --git a/netwerk/protocol/file/public/nsIFileChannel.idl b/netwerk/protocol/file/public/nsIFileChannel.idl index 1075db2824e9..c68882c18f54 100644 --- a/netwerk/protocol/file/public/nsIFileChannel.idl +++ b/netwerk/protocol/file/public/nsIFileChannel.idl @@ -18,6 +18,8 @@ #include "nsIChannel.idl" +interface nsISimpleEnumerator; + [scriptable, uuid(73025830-0ce2-11d3-9331-00104ba0fd40)] interface nsIFileChannel : nsIChannel { @@ -42,6 +44,14 @@ interface nsIFileChannel : nsIChannel */ readonly attribute nsIFileChannel Parent; + /** + * Returns an enumeration of the elements in a directory. Each + * element in the enumeration is an nsIFileChannel. + * @return NS_ERROR_FAILURE if the current nsIFileChannel does + * not specify a directory. + */ + readonly attribute nsISimpleEnumerator Children; + /** * Returns a native path string suitable to be passes to native platform * routines. @@ -64,7 +74,7 @@ interface nsIFileChannel : nsIChannel void Delete(); /** - * Move or renames a file. + * Move or rename a file. */ void MoveFrom(in nsIURI src); @@ -102,5 +112,11 @@ interface nsIFileChannel : nsIChannel */ string MakeUniqueFileName(in string baseName); + /** + * Executes a program specified by the file channel. + * @param args - The program arguments to run with. If not specified, + * the Query portion of the URI is used as the argument string. + */ + void Execute(in string args); }; diff --git a/netwerk/protocol/file/public/nsIFileProtocolHandler.idl b/netwerk/protocol/file/public/nsIFileProtocolHandler.idl new file mode 100644 index 000000000000..18e7d022a238 --- /dev/null +++ b/netwerk/protocol/file/public/nsIFileProtocolHandler.idl @@ -0,0 +1,26 @@ +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 4 -*- + * + * The contents of this file are subject to the Netscape Public License + * Version 1.0 (the "NPL"); you may not use this file except in + * compliance with the NPL. You may obtain a copy of the NPL at + * http://www.mozilla.org/NPL/ + * + * Software distributed under the NPL is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the NPL + * for the specific language governing rights and limitations under the + * NPL. + * + * The Initial Developer of this code under the NPL is Netscape + * Communications Corporation. Portions created by Netscape are + * Copyright (C) 1998 Netscape Communications Corporation. All Rights + * Reserved. + */ + +#include "nsIProtocolHandler.idl" + +interface nsIFileChannel; + +interface nsIFileProtocolHandler : nsIProtocolHandler +{ + nsIFileChannel NewChannelFromNativePath(in string nativePath); +}; diff --git a/netwerk/protocol/file/src/makefile.win b/netwerk/protocol/file/src/makefile.win index 9e565664d227..b30a7d97f390 100644 --- a/netwerk/protocol/file/src/makefile.win +++ b/netwerk/protocol/file/src/makefile.win @@ -29,18 +29,19 @@ MAKE_OBJ_TYPE=DLL DLLNAME=fileprotocol DLL=.\$(OBJDIR)\$(DLLNAME).dll -LLIBS= $(LLIBS) \ - $(LIBNSPR) \ - $(DIST)\lib\plc3.lib \ - $(DIST)\lib\xpcom.lib \ +LLIBS= $(LLIBS) \ + $(LIBNSPR) \ + $(DIST)\lib\plc3.lib \ + $(DIST)\lib\xpcom.lib \ + $(DIST)\lib\netwerk.lib \ $(NULL) MISCDEP=$(LLIBS) -CPP_OBJS= \ - .\$(OBJDIR)\nsFileChannel.obj \ - .\$(OBJDIR)\nsFileProtocolHandler.obj \ - .\$(OBJDIR)\nsFileProtocolFactory.obj \ +CPP_OBJS= \ + .\$(OBJDIR)\nsFileChannel.obj \ + .\$(OBJDIR)\nsFileProtocolHandler.obj \ + .\$(OBJDIR)\nsFileProtocolFactory.obj \ $(NULL) LOCAL_INCLUDES=-I. diff --git a/netwerk/protocol/file/src/nsFileChannel.cpp b/netwerk/protocol/file/src/nsFileChannel.cpp index 4f909fa95068..4cb6932d9f91 100644 --- a/netwerk/protocol/file/src/nsFileChannel.cpp +++ b/netwerk/protocol/file/src/nsFileChannel.cpp @@ -24,13 +24,27 @@ #include "nsIStreamListener.h" #include "nsIIOService.h" #include "nsIServiceManager.h" +#include "nsFileProtocolHandler.h" +#include "nsIBuffer.h" +#include "nsIBufferInputStream.h" +#include "nsIBufferOutputStream.h" +#include "nsAutoLock.h" +#include "netCore.h" +#include "nsIFileStream.h" +#include "nsISimpleEnumerator.h" +#include "nsIURL.h" +#include "prio.h" +NS_DEFINE_IID(kISupportsIID, NS_ISUPPORTS_IID); NS_DEFINE_CID(kIOServiceCID, NS_IOSERVICE_CID); //////////////////////////////////////////////////////////////////////////////// nsFileChannel::nsFileChannel() - : mURI(nsnull), mGetter(nsnull), mListener(nsnull), mEventQueue(nsnull) + : mURI(nsnull), mGetter(nsnull), mListener(nsnull), mEventQueue(nsnull), + mContext(nsnull), mState(ENDED), + mSuspended(PR_FALSE), mFileStream(nsnull), mBuffer(nsnull), + mBufferStream(nsnull), mStatus(NS_OK), mHandler(nsnull), mSourceOffset(0) { NS_INIT_REFCNT(); } @@ -44,6 +58,10 @@ nsFileChannel::Init(const char* verb, nsIURI* uri, nsIEventSinkGetter* getter, mGetter = getter; NS_ADDREF(mGetter); + mLock = PR_NewLock(); + if (mLock == nsnull) + return NS_ERROR_OUT_OF_MEMORY; + rv = getter->GetEventSink(verb, nsIStreamListener::GetIID(), (nsISupports**)&mListener); if (NS_FAILED(rv)) return rv; @@ -70,6 +88,13 @@ nsFileChannel::~nsFileChannel() NS_IF_RELEASE(mGetter); NS_IF_RELEASE(mListener); NS_IF_RELEASE(mEventQueue); + NS_IF_RELEASE(mContext); + NS_IF_RELEASE(mHandler); + NS_IF_RELEASE(mFileStream); + NS_IF_RELEASE(mBuffer); + NS_IF_RELEASE(mBufferStream); + if (mLock) + PR_DestroyLock(mLock); } NS_IMETHODIMP @@ -78,7 +103,7 @@ nsFileChannel::QueryInterface(const nsIID& aIID, void** aInstancePtr) NS_ASSERTION(aInstancePtr, "no instance pointer"); if (aIID.Equals(nsIFileChannel::GetIID()) || aIID.Equals(nsIChannel::GetIID()) || - aIID.Equals(nsISupports::GetIID()) ) { + aIID.Equals(kISupportsIID)) { *aInstancePtr = NS_STATIC_CAST(nsIFileChannel*, this); NS_ADDREF_THIS(); return NS_OK; @@ -108,19 +133,43 @@ nsFileChannel::Create(nsISupports* aOuter, const nsIID& aIID, void* *aResult) NS_IMETHODIMP nsFileChannel::Cancel() { - return NS_ERROR_NOT_IMPLEMENTED; + nsAutoLock lock(mLock); + + nsresult rv = NS_OK; + mStatus = NS_BINDING_ABORTED; + if (mSuspended) { + Resume(); + } + mState = ENDING; + return rv; } NS_IMETHODIMP nsFileChannel::Suspend() { - return NS_ERROR_NOT_IMPLEMENTED; + nsAutoLock lock(mLock); + + nsresult rv = NS_OK; + if (!mSuspended) { + // XXX close the stream here? + mStatus = mHandler->Suspend(this); + mSuspended = PR_TRUE; + } + return rv; } NS_IMETHODIMP nsFileChannel::Resume() { - return NS_ERROR_NOT_IMPLEMENTED; + nsAutoLock lock(mLock); + + nsresult rv = NS_OK; + if (!mSuspended) { + // XXX re-open the stream and seek here? + mStatus = mHandler->Resume(this); + mSuspended = PR_FALSE; + } + return rv; } //////////////////////////////////////////////////////////////////////////////// @@ -136,17 +185,41 @@ nsFileChannel::GetURI(nsIURI * *aURI) } NS_IMETHODIMP -nsFileChannel::OpenInputStream(PRUint32 startPosition, PRInt32 count, - nsIInputStream **_retval) +nsFileChannel::OpenInputStream(PRUint32 startPosition, PRInt32 readCount, + nsIInputStream **result) { - NS_ASSERTION(startPosition == 0 && count == -1, "fix me"); - return NS_ERROR_NOT_IMPLEMENTED; + nsAutoLock lock(mLock); + + nsresult rv; + + if (mState != ENDED) + return NS_ERROR_IN_PROGRESS; + + nsIStreamListener* syncListener; + nsIBufferInputStream* inStr; + rv = NS_NewSyncStreamListener(&syncListener, &inStr); + if (NS_FAILED(rv)) return rv; + + mListener = syncListener; + mState = START_READ; + mSourceOffset = startPosition; + mAmount = readCount; + + rv = mHandler->DispatchRequest(this); + if (NS_FAILED(rv)) { + NS_RELEASE(inStr); + return rv; + } + + *result = inStr; + return NS_OK; } NS_IMETHODIMP nsFileChannel::OpenOutputStream(PRUint32 startPosition, nsIOutputStream **_retval) { - NS_ASSERTION(startPosition == 0, "fix me"); + nsAutoLock lock(mLock); + return NS_ERROR_NOT_IMPLEMENTED; } @@ -156,8 +229,27 @@ nsFileChannel::AsyncRead(PRUint32 startPosition, PRInt32 readCount, nsIEventQueue *eventQueue, nsIStreamListener *listener) { - NS_ASSERTION(startPosition == 0 && readCount == -1, "fix me"); - return NS_ERROR_NOT_IMPLEMENTED; + nsAutoLock lock(mLock); + + nsresult rv; + + nsIStreamListener* asyncListener; + rv = NS_NewAsyncStreamListener(&asyncListener, eventQueue, listener); + if (NS_FAILED(rv)) return rv; + + mListener = asyncListener; + + mContext = ctxt; + NS_IF_ADDREF(mContext); + + mState = START_READ; + mSourceOffset = startPosition; + mAmount = readCount; + + rv = mHandler->DispatchRequest(this); + if (NS_FAILED(rv)) return rv; + + return NS_OK; } NS_IMETHODIMP @@ -167,7 +259,8 @@ nsFileChannel::AsyncWrite(nsIInputStream *fromStream, nsIEventQueue *eventQueue, nsIStreamObserver *observer) { - NS_ASSERTION(startPosition == 0, "fix me"); + nsAutoLock lock(mLock); + return NS_ERROR_NOT_IMPLEMENTED; } @@ -224,6 +317,104 @@ nsFileChannel::GetParent(nsIFileChannel * *aParent) return NS_OK; } +class nsDirEnumerator : public nsISimpleEnumerator +{ +public: + NS_DECL_ISUPPORTS + + nsDirEnumerator() : mHandler(nsnull), mDir(nsnull), mNext(nsnull) { + NS_INIT_REFCNT(); + } + + nsresult Init(nsFileProtocolHandler* handler, nsFileSpec& spec) { + const char* path = spec.GetNativePathCString(); + mDir = PR_OpenDir(path); + if (mDir == nsnull) // not a directory? + return NS_ERROR_FAILURE; + + mHandler = handler; + NS_ADDREF(mHandler); + return NS_OK; + } + + NS_IMETHOD HasMoreElements(PRBool *result) { + nsresult rv; + if (mNext == nsnull && mDir) { + PRDirEntry* entry = PR_ReadDir(mDir, PR_SKIP_BOTH); + if (entry == nsnull) { + // end of dir entries + + PRStatus status = PR_CloseDir(mDir); + if (status != PR_SUCCESS) + return NS_ERROR_FAILURE; + mDir = nsnull; + + *result = PR_FALSE; + return NS_OK; + } + + const char* path = entry->name; + rv = mHandler->NewChannelFromNativePath(path, &mNext); + if (NS_FAILED(rv)) return rv; + + NS_ASSERTION(mNext, "NewChannel failed"); + } + *result = mNext != nsnull; + return NS_OK; + } + + NS_IMETHOD GetNext(nsISupports **result) { + nsresult rv; + PRBool hasMore; + rv = HasMoreElements(&hasMore); + if (NS_FAILED(rv)) return rv; + + *result = mNext; // might return nsnull + mNext = nsnull; + return NS_OK; + } + + virtual ~nsDirEnumerator() { + if (mDir) { + PRStatus status = PR_CloseDir(mDir); + NS_ASSERTION(status == PR_SUCCESS, "close failed"); + } + NS_IF_RELEASE(mHandler); + NS_IF_RELEASE(mNext); + } + +protected: + nsFileProtocolHandler* mHandler; + PRDir* mDir; + nsIFileChannel* mNext; +}; + +NS_IMPL_ISUPPORTS(nsDirEnumerator, nsISimpleEnumerator::GetIID()); + +NS_IMETHODIMP +nsFileChannel::GetChildren(nsISimpleEnumerator * *aChildren) +{ + nsresult rv; + + PRBool isDir; + rv = IsDirectory(&isDir); + if (NS_FAILED(rv)) return rv; + if (!isDir) + return NS_ERROR_FAILURE; + + nsDirEnumerator* dirEnum = new nsDirEnumerator(); + if (dirEnum == nsnull) + return NS_ERROR_OUT_OF_MEMORY; + NS_ADDREF(dirEnum); + rv = dirEnum->Init(mHandler, mSpec); + if (NS_FAILED(rv)) { + NS_RELEASE(dirEnum); + return rv; + } + *aChildren = dirEnum; + return NS_OK; +} + NS_IMETHODIMP nsFileChannel::GetNativePath(char * *aNativePath) { @@ -334,4 +525,143 @@ nsFileChannel::MakeUniqueFileName(const char* baseName, char **_retval) return NS_ERROR_NOT_IMPLEMENTED; } +NS_IMETHODIMP +nsFileChannel::Execute(const char *args) +{ + nsresult rv; + char* queryArgs = nsnull; + + if (args == nsnull) { + nsIURL* url; + rv = mURI->QueryInterface(nsIURL::GetIID(), (void**)&url); + if (NS_SUCCEEDED(rv)) { + rv = url->GetQuery(&queryArgs); + NS_RELEASE(url); + if (NS_FAILED(rv)) return rv; + args = queryArgs; + } + } + + rv = mSpec.Execute(args); + if (queryArgs) + nsCRT::free(queryArgs); + return rv; +} + +//////////////////////////////////////////////////////////////////////////////// +// nsIRunnable methods: + +NS_IMETHODIMP +nsFileChannel::Run(void) +{ + while (mState != ENDED && !mSuspended) { + Process(); + } + return NS_OK; +} + +void +nsFileChannel::Process(void) +{ + nsAutoLock lock(mLock); + + switch (mState) { + case START_READ: { + nsISupports* fs; + + mStatus = mListener->OnStartBinding(mContext); // always send the start notification + if (NS_FAILED(mStatus)) goto error; + + mStatus = NS_NewTypicalInputFileStream(&fs, mSpec); + if (NS_FAILED(mStatus)) goto error; + + mStatus = fs->QueryInterface(nsIInputStream::GetIID(), (void**)&mFileStream); + NS_RELEASE(fs); + if (NS_FAILED(mStatus)) goto error; + + mStatus = NS_NewBuffer(&mBuffer, NS_FILE_TRANSPORT_BUFFER_SIZE, + NS_FILE_TRANSPORT_BUFFER_SIZE); + if (NS_FAILED(mStatus)) goto error; + + mStatus = NS_NewBufferInputStream(&mBufferStream, mBuffer, PR_FALSE); + if (NS_FAILED(mStatus)) goto error; + + mState = READING; + break; + } + case READING: { + if (NS_FAILED(mStatus)) goto error; + + PRUint32 amt; + nsIInputStream* inStr = NS_STATIC_CAST(nsIInputStream*, mFileStream); + PRUint32 inLen; + mStatus = inStr->GetLength(&inLen); + if (NS_FAILED(mStatus)) goto error; + + mStatus = mBuffer->WriteFrom(inStr, inLen, &amt); + if (mStatus == NS_BASE_STREAM_EOF) goto error; + if (NS_FAILED(mStatus)) goto error; + + // and feed the buffer to the application via the byte buffer stream: + // XXX maybe amt should be mBufferStream->GetLength(): + mStatus = mListener->OnDataAvailable(mContext, mBufferStream, mSourceOffset, amt); + if (NS_FAILED(mStatus)) goto error; + + mSourceOffset += amt; + + // stay in the READING state + break; + } + case START_WRITE: { + nsISupports* fs; + + mStatus = mListener->OnStartBinding(mContext); // always send the start notification + if (NS_FAILED(mStatus)) goto error; + + mStatus = NS_NewTypicalOutputFileStream(&fs, mSpec); + if (NS_FAILED(mStatus)) goto error; + + mStatus = fs->QueryInterface(nsIOutputStream::GetIID(), (void**)&mFileStream); + NS_RELEASE(fs); + if (NS_FAILED(mStatus)) goto error; + + mStatus = NS_NewBuffer(&mBuffer, NS_FILE_TRANSPORT_BUFFER_SIZE, + NS_FILE_TRANSPORT_BUFFER_SIZE); + if (NS_FAILED(mStatus)) goto error; + + mStatus = NS_NewBufferInputStream(&mBufferStream, mBuffer, PR_FALSE); + if (NS_FAILED(mStatus)) goto error; + + mState = WRITING; + break; + } + case WRITING: { + break; + } + case ENDING: { + NS_IF_RELEASE(mBufferStream); + mBufferStream = nsnull; + NS_IF_RELEASE(mFileStream); + mFileStream = nsnull; + NS_IF_RELEASE(mContext); + mContext = nsnull; + + // XXX where do we get the error message? + (void)mListener->OnStopBinding(mContext, mStatus, nsnull); + + mState = ENDED; + break; + } + case ENDED: { + NS_NOTREACHED("trying to continue an ended file transfer"); + break; + } + } + return; + + error: + mState = ENDING; + return; +} + //////////////////////////////////////////////////////////////////////////////// diff --git a/netwerk/protocol/file/src/nsFileChannel.h b/netwerk/protocol/file/src/nsFileChannel.h index dbfb6dc26f66..09d8a18ce6d4 100644 --- a/netwerk/protocol/file/src/nsFileChannel.h +++ b/netwerk/protocol/file/src/nsFileChannel.h @@ -20,12 +20,18 @@ #define nsFileChannel_h__ #include "nsIFileChannel.h" +#include "nsIThread.h" #include "nsFileSpec.h" +#include "prlock.h" class nsIEventSinkGetter; class nsIStreamListener; +class nsFileProtocolHandler; +class nsIBaseStream; +class nsIBuffer; +class nsIBufferInputStream; -class nsFileChannel : public nsIFileChannel { +class nsFileChannel : public nsIFileChannel, public nsIRunnable { public: NS_DECL_ISUPPORTS @@ -75,6 +81,9 @@ public: /* readonly attribute nsIFileChannel Parent; */ NS_IMETHOD GetParent(nsIFileChannel * *aParent); + /* readonly attribute nsISimpleEnumerator Children; */ + NS_IMETHOD GetChildren(nsISimpleEnumerator * *aChildren); + /* readonly attribute string NativePath; */ NS_IMETHOD GetNativePath(char * *aNativePath); @@ -108,6 +117,14 @@ public: /* string MakeUniqueFileName (in string baseName); */ NS_IMETHOD MakeUniqueFileName(const char *baseName, char **_retval); + /* void Execute (in string args); */ + NS_IMETHOD Execute(const char *args); + + //////////////////////////////////////////////////////////////////////////// + // nsIRunnable methods: + + NS_IMETHOD Run(void); + //////////////////////////////////////////////////////////////////////////// // nsFileChannel: @@ -122,13 +139,42 @@ public: nsresult Init(const char* verb, nsIURI* uri, nsIEventSinkGetter* getter, nsIEventQueue* queue); -protected: - nsIURI* mURI; - nsIEventSinkGetter* mGetter; // XXX it seems wrong keeping this -- used by GetParent - nsIStreamListener* mListener; - nsIEventQueue* mEventQueue; + void Process(void); - nsFileSpec mSpec; + enum State { + START_READ, + READING, + START_WRITE, + WRITING, + ENDING, + ENDED + }; + +protected: + nsIURI* mURI; + nsIEventSinkGetter* mGetter; // XXX it seems wrong keeping this -- used by GetParent + nsIStreamListener* mListener; + nsIEventQueue* mEventQueue; + + nsFileSpec mSpec; + + nsISupports* mContext; + nsFileProtocolHandler* mHandler; + State mState; + PRBool mSuspended; + + // state variables: + nsIBaseStream* mFileStream; // cast to nsIInputStream/nsIOutputStream for reading/writing + nsIBuffer* mBuffer; + nsIBufferInputStream* mBufferStream; + nsresult mStatus; + PRUint32 mSourceOffset; + PRInt32 mAmount; + +private: + PRLock* mLock; }; +#define NS_FILE_TRANSPORT_BUFFER_SIZE (4*1024) + #endif // nsFileChannel_h__ diff --git a/netwerk/protocol/file/src/nsFileProtocolHandler.cpp b/netwerk/protocol/file/src/nsFileProtocolHandler.cpp index 690092c3a3d5..fdc743521842 100644 --- a/netwerk/protocol/file/src/nsFileProtocolHandler.cpp +++ b/netwerk/protocol/file/src/nsFileProtocolHandler.cpp @@ -24,16 +24,34 @@ #include "nsIServiceManager.h" #include "nsIEventSinkGetter.h" #include "nsIProgressEventSink.h" +#include "nsIThread.h" +#include "nsISupportsArray.h" +#include "nsFileSpec.h" static NS_DEFINE_CID(kStandardURLCID, NS_STANDARDURL_CID); //////////////////////////////////////////////////////////////////////////////// -nsFileProtocolHandler::nsFileProtocolHandler() { +nsFileProtocolHandler::nsFileProtocolHandler() + : mPool(nsnull) +{ NS_INIT_REFCNT(); } -nsFileProtocolHandler::~nsFileProtocolHandler() { +nsresult +nsFileProtocolHandler::Init() +{ + nsresult rv; + rv = NS_NewThreadPool(&mPool, NS_FILE_TRANSPORT_WORKER_COUNT, + NS_FILE_TRANSPORT_WORKER_COUNT, 8*1024); + return rv; +} + +nsFileProtocolHandler::~nsFileProtocolHandler() +{ + // this will wait for all outstanding requests to be processed, then + // join with the worker threads, and finally free the pool: + NS_IF_RELEASE(mPool); } NS_IMPL_ISUPPORTS(nsFileProtocolHandler, nsIProtocolHandler::GetIID()); @@ -48,7 +66,10 @@ nsFileProtocolHandler::Create(nsISupports *aOuter, REFNSIID aIID, void **aResult if (ph == nsnull) return NS_ERROR_OUT_OF_MEMORY; NS_ADDREF(ph); - nsresult rv = ph->QueryInterface(aIID, aResult); + nsresult rv = ph->Init(); + if (NS_SUCCEEDED(rv)) { + rv = ph->QueryInterface(aIID, aResult); + } NS_RELEASE(ph); return rv; } @@ -150,3 +171,70 @@ nsFileProtocolHandler::NewChannel(const char* verb, nsIURI* url, } //////////////////////////////////////////////////////////////////////////////// + +NS_IMETHODIMP +nsFileProtocolHandler::NewChannelFromNativePath(const char* nativePath, + nsIFileChannel* *result) +{ + nsresult rv; + nsFileSpec spec(nativePath); + nsFileURL fileURL(spec); + const char* urlStr = fileURL.GetURLString(); + nsIURI* uri; + + rv = NewURI(urlStr, nsnull, &uri); + if (NS_FAILED(rv)) return rv; + + rv = NewChannel("load", // XXX what should this be? + uri, + nsnull, // XXX bogus getter + nsnull, // XXX bogus + (nsIChannel**)result); + NS_RELEASE(uri); + return rv; +} + +//////////////////////////////////////////////////////////////////////////////// + +nsresult +nsFileProtocolHandler::ProcessPendingRequests(void) +{ + return mPool->ProcessPendingRequests(); +} + +nsresult +nsFileProtocolHandler::DispatchRequest(nsIRunnable* runnable) +{ + return mPool->DispatchRequest(runnable); +} + +//////////////////////////////////////////////////////////////////////////////// + +nsresult +nsFileProtocolHandler::Suspend(nsFileChannel* request) +{ + nsresult rv; + if (mSuspended == nsnull) { + rv = NS_NewISupportsArray(&mSuspended); + if (NS_FAILED(rv)) return rv; + } + return mSuspended->AppendElement(NS_STATIC_CAST(nsIChannel*, request)); +} + +nsresult +nsFileProtocolHandler::Resume(nsFileChannel* request) +{ + nsresult rv; + if (mSuspended == nsnull) + return NS_ERROR_FAILURE; + // XXX RemoveElement returns a bool instead of nsresult! + PRBool removed = mSuspended->RemoveElement(NS_STATIC_CAST(nsIChannel*, request)); + rv = removed ? NS_OK : NS_ERROR_FAILURE; + if (NS_FAILED(rv)) return rv; + + // restart the request + rv = mPool->DispatchRequest(NS_STATIC_CAST(nsIRunnable*, request)); + return rv; +} + +//////////////////////////////////////////////////////////////////////////////// diff --git a/netwerk/protocol/file/src/nsFileProtocolHandler.h b/netwerk/protocol/file/src/nsFileProtocolHandler.h index 50b38de8014a..c0427de9e7e2 100644 --- a/netwerk/protocol/file/src/nsFileProtocolHandler.h +++ b/netwerk/protocol/file/src/nsFileProtocolHandler.h @@ -21,6 +21,10 @@ #include "nsIProtocolHandler.h" +class nsISupportsArray; + +#define NS_FILE_TRANSPORT_WORKER_COUNT 4 + // {25029490-F132-11d2-9588-00805F369F95} #define NS_FILEPROTOCOLHANDLER_CID \ { /* fbc81170-1f69-11d3-9344-00104ba0fd40 */ \ @@ -47,6 +51,10 @@ public: nsIEventQueue *eventQueue, nsIChannel **_retval); + // nsIFileProtocolHandler methods: + NS_IMETHOD NewChannelFromNativePath(const char* nativePath, + nsIFileChannel* *result); + // nsFileProtocolHandler methods: nsFileProtocolHandler(); virtual ~nsFileProtocolHandler(); @@ -54,8 +62,16 @@ public: static NS_METHOD Create(nsISupports *aOuter, REFNSIID aIID, void **aResult); + nsresult Init(); + nsresult DispatchRequest(nsIRunnable* runnable); + nsresult Suspend(nsFileChannel* request); + nsresult Resume(nsFileChannel* request); + nsresult ProcessPendingRequests(void); + protected: nsISupports* mEventSinkGetter; + nsIThreadPool* mPool; + nsISupportsArray* mSuspended; }; #endif /* nsFileProtocolHandler_h___ */