From d53a4e079f613dfb734ea338f37bc8492e930153 Mon Sep 17 00:00:00 2001 From: "valeski%netscape.com" Date: Wed, 15 Dec 1999 03:35:15 +0000 Subject: [PATCH] 21723, a=chofmann, r=rpotts. landing new FTP implementation. It's now much leaner on event processing, and no longer buffers data between the socket transport and consumer. This change went in in order to unblock the xpinstall guys on a UI thread starvation problem git-svn-id: svn://10.0.0.236/trunk@56020 18797224-902f-48f8-a5cc-f745e15eee43 --- .../protocol/ftp/public/nsPIFTPChannel.idl | 1 - mozilla/netwerk/protocol/ftp/src/Makefile.in | 1 + mozilla/netwerk/protocol/ftp/src/makefile.win | 1 + .../netwerk/protocol/ftp/src/nsFTPChannel.cpp | 128 +--- .../netwerk/protocol/ftp/src/nsFTPChannel.h | 10 +- .../ftp/src/nsFtpConnectionThread.cpp | 720 +++++++----------- .../protocol/ftp/src/nsFtpConnectionThread.h | 270 +++---- .../netwerk/protocol/ftp/src/nsFtpModule.cpp | 226 +----- .../protocol/ftp/src/nsFtpProtocolHandler.cpp | 16 +- .../protocol/ftp/src/nsFtpProtocolHandler.h | 22 +- 10 files changed, 450 insertions(+), 945 deletions(-) diff --git a/mozilla/netwerk/protocol/ftp/public/nsPIFTPChannel.idl b/mozilla/netwerk/protocol/ftp/public/nsPIFTPChannel.idl index 105b8bfb940..e097c8c77d7 100644 --- a/mozilla/netwerk/protocol/ftp/public/nsPIFTPChannel.idl +++ b/mozilla/netwerk/protocol/ftp/public/nsPIFTPChannel.idl @@ -30,7 +30,6 @@ interface nsIEventQueue; [scriptable, uuid(64718e40-18c2-11d3-9337-00104ba0fd40)] interface nsPIFTPChannel : nsIChannel { - void SetConnectionQueue(in nsIEventQueue aEventQ); void SetContentLength(in long aLength); void SetContentType(in string aContentType); void Stopped(in nsresult aStatus, in wstring aMsg); diff --git a/mozilla/netwerk/protocol/ftp/src/Makefile.in b/mozilla/netwerk/protocol/ftp/src/Makefile.in index 1e7c1aaabc8..cd0787f92f0 100644 --- a/mozilla/netwerk/protocol/ftp/src/Makefile.in +++ b/mozilla/netwerk/protocol/ftp/src/Makefile.in @@ -35,6 +35,7 @@ CPPSRCS = \ nsFTPChannel.cpp \ nsFtpConnectionThread.cpp \ nsFtpModule.cpp \ + nsFTPListener.cpp \ $(NULL) EXTRA_DSO_LDOPTS += $(MOZ_COMPONENT_LIBS) diff --git a/mozilla/netwerk/protocol/ftp/src/makefile.win b/mozilla/netwerk/protocol/ftp/src/makefile.win index 007f13dde7e..96a51ee9ce5 100644 --- a/mozilla/netwerk/protocol/ftp/src/makefile.win +++ b/mozilla/netwerk/protocol/ftp/src/makefile.win @@ -36,6 +36,7 @@ CPP_OBJS = \ .\$(OBJDIR)\nsFTPChannel.obj \ .\$(OBJDIR)\nsFtpConnectionThread.obj \ .\$(OBJDIR)\nsFtpModule.obj \ + .\$(OBJDIR)\nsFTPListener.obj \ $(NULL) LLIBS= \ diff --git a/mozilla/netwerk/protocol/ftp/src/nsFTPChannel.cpp b/mozilla/netwerk/protocol/ftp/src/nsFTPChannel.cpp index 25dc4b115ef..7321242b6ac 100644 --- a/mozilla/netwerk/protocol/ftp/src/nsFTPChannel.cpp +++ b/mozilla/netwerk/protocol/ftp/src/nsFTPChannel.cpp @@ -23,28 +23,21 @@ // ftp implementation #include "nsFTPChannel.h" +#include "nsIStreamListener.h" #include "nscore.h" #include "prlog.h" -#include "nsCOMPtr.h" #include "nsIServiceManager.h" -#include "nsFtpConnectionThread.h" -#include "nsIEventQueueService.h" -#include "nsIProgressEventSink.h" -#include "nsIInterfaceRequestor.h" #include "nsIMIMEService.h" -#include "nsProxyObjectManager.h" #include "nsIPipe.h" -#include "nsAutoLock.h" +#include "nsNetUtil.h" -static NS_DEFINE_IID(kProxyObjectManagerCID, NS_PROXYEVENT_MANAGER_CID); static NS_DEFINE_CID(kMIMEServiceCID, NS_MIMESERVICE_CID); -static NS_DEFINE_CID(kEventQueueService, NS_EVENTQUEUESERVICE_CID); #if defined(PR_LOGGING) extern PRLogModuleInfo* gFTPLog; #endif /* PR_LOGGING */ -// There are actually two transport connections established for an +// There are two transport connections established for an // ftp connection. One is used for the command channel , and // the other for the data channel. The command channel is the first // connection made and is used to negotiate the second, data, channel. @@ -135,39 +128,26 @@ nsFTPChannel::Create(nsISupports* aOuter, const nsIID& aIID, void* *aResult) // cross thread call. NS_IMETHODIMP -nsFTPChannel::IsPending(PRBool *result) -{ +nsFTPChannel::IsPending(PRBool *result) { return NS_ERROR_NOT_IMPLEMENTED; } NS_IMETHODIMP -nsFTPChannel::Cancel(void) -{ - nsresult rv = NS_OK; - if (mProxiedThreadRequest) - rv = mProxiedThreadRequest->Cancel(); - return rv; +nsFTPChannel::Cancel(void) { + NS_ASSERTION(mConnThread, "lost the connection thread."); + return mConnThread->Cancel(); } NS_IMETHODIMP -nsFTPChannel::Suspend(void) -{ - nsresult rv = NS_OK; - if (mProxiedThreadRequest) - rv = mProxiedThreadRequest->Suspend(); - return rv; +nsFTPChannel::Suspend(void) { + NS_ASSERTION(mConnThread, "lost the connection thread."); + return mConnThread->Suspend(); } NS_IMETHODIMP -nsFTPChannel::Resume(void) -{ - // we can't use the mProxiedThreadRequest to resume the thread - // because it needs the event pump to be running on the thread - // (which is blocking right now). Instead wake it up directly - // with a monitor notification. - NS_ASSERTION(mConnThread, "FTP: connection thread was dropped"); - nsAutoCMonitor mon(mConnThread); - return mon.Notify(); +nsFTPChannel::Resume(void) { + NS_ASSERTION(mConnThread, "lost the connection thread."); + return mConnThread->Resume(); } //////////////////////////////////////////////////////////////////////////////// @@ -189,9 +169,6 @@ nsFTPChannel::GetURI(nsIURI * *aURL) return NS_OK; } -#define NS_FTP_SEGMENT_SIZE (2*1024) -#define NS_FTP_BUFFER_SIZE (8*1024) - NS_IMETHODIMP nsFTPChannel::OpenInputStream(PRUint32 startPosition, PRInt32 readCount, nsIInputStream **_retval) @@ -206,15 +183,12 @@ nsFTPChannel::OpenInputStream(PRUint32 startPosition, PRInt32 readCount, // and the FTP thread get's the output stream end. // The FTP thread will write to the output stream end // when data become available to it. - nsCOMPtr bufOutStream; - nsCOMPtr bufInStream; - rv = NS_NewPipe(getter_AddRefs(bufInStream), getter_AddRefs(bufOutStream), - nsnull, NS_FTP_SEGMENT_SIZE, NS_FTP_BUFFER_SIZE); + nsCOMPtr bufOutStream; // we don't use this piece + nsCOMPtr listener; + rv = NS_NewSyncStreamListener(_retval, getter_AddRefs(bufOutStream), + getter_AddRefs(listener)); if (NS_FAILED(rv)) return rv; - *_retval = NS_STATIC_CAST(nsIInputStream*, bufInStream.get()); - NS_ADDREF(*_retval); - /////////////////////////// //// setup channel state mSourceOffset = startPosition; @@ -224,28 +198,23 @@ nsFTPChannel::OpenInputStream(PRUint32 startPosition, PRInt32 readCount, //// setup the channel thread NS_NEWXPCOM(mConnThread, nsFtpConnectionThread); if (!mConnThread) return NS_ERROR_OUT_OF_MEMORY; - NS_ADDREF(mConnThread); // keep our own ref to the thread obj (we'll - // release it later in this same call. + NS_ADDREF(mConnThread); - rv = mConnThread->Init(mHandler, this, nsnull, - mBufferSegmentSize, mBufferMaxSize); + rv = mConnThread->Init(mHandler, this, mBufferSegmentSize, mBufferMaxSize); mHandler = 0; if (NS_FAILED(rv)) { NS_RELEASE(mConnThread); return rv; } - rv = mConnThread->SetOutputStream(bufOutStream); + rv = mConnThread->SetStreamListener(listener); if (NS_FAILED(rv)) { NS_RELEASE(mConnThread); return rv; } - mThreadRequest = do_QueryInterface((nsISupports*)(nsIRequest*)mConnThread); - rv = mPool->DispatchRequest((nsIRunnable*)mConnThread); - NS_RELEASE(mConnThread); // we're done w/ the raw thread obj if (NS_FAILED(rv)) return rv; mConnected = PR_TRUE; @@ -272,16 +241,10 @@ nsFTPChannel::AsyncOpen(nsIStreamObserver *observer, nsISupports* ctxt) //// setup the channel thread NS_NEWXPCOM(mConnThread, nsFtpConnectionThread); if (!mConnThread) return NS_ERROR_OUT_OF_MEMORY; + NS_ADDREF(mConnThread); - // becuase we want to use the actual thread object as a monitor variable - // we need to hang on to it until the thread itself tells us it's invalid. - // See nsFTPChannel::Stopped(). - NS_ADDREF(mConnThread); // keep our own ref to the thread obj - mThreadRequest = do_QueryInterface((nsISupports*)(nsIRequest*)mConnThread); - - rv = mConnThread->Init(mHandler, this, ctxt, - mBufferSegmentSize, mBufferMaxSize); + rv = mConnThread->Init(mHandler, this, mBufferSegmentSize, mBufferMaxSize); mHandler = 0; if (NS_FAILED(rv)) { NS_RELEASE(mConnThread); @@ -294,7 +257,6 @@ nsFTPChannel::AsyncOpen(nsIStreamObserver *observer, nsISupports* ctxt) mConnected = PR_TRUE; mAsyncOpen = PR_TRUE; - // start the run return mPool->DispatchRequest((nsIRunnable*)mConnThread); } @@ -332,8 +294,7 @@ nsFTPChannel::AsyncRead(PRUint32 startPosition, PRInt32 readCount, rv = mConnThread->SetStreamListener(listener); if (NS_FAILED(rv)) return rv; - nsAutoCMonitor mon(mConnThread); - mon.Notify(); + mConnThread->Resume(); } else { if (mConnected) return NS_ERROR_ALREADY_CONNECTED; @@ -344,24 +305,21 @@ nsFTPChannel::AsyncRead(PRUint32 startPosition, PRInt32 readCount, if (!mConnThread) return NS_ERROR_OUT_OF_MEMORY; NS_ADDREF(mConnThread); - mThreadRequest = do_QueryInterface((nsISupports*)(nsIRequest*)mConnThread); - - rv = mConnThread->Init(mHandler, this, ctxt, - mBufferSegmentSize, mBufferMaxSize); + rv = mConnThread->Init(mHandler, this, mBufferSegmentSize, mBufferMaxSize); mHandler = 0; if (NS_FAILED(rv)) { NS_RELEASE(mConnThread); return rv; } - rv = mConnThread->SetStreamListener(listener); - if (NS_FAILED(rv)) return rv; + rv = mConnThread->SetStreamListener(listener, ctxt); + if (NS_FAILED(rv)) { + NS_RELEASE(mConnThread); + return rv; + } rv = mPool->DispatchRequest((nsIRunnable*)mConnThread); - NS_RELEASE(mConnThread); - if (NS_FAILED(rv)) return rv; - mConnected = PR_TRUE; } @@ -507,29 +465,6 @@ nsFTPChannel::SetNotificationCallbacks(nsIInterfaceRequestor* aNotificationCallb return NS_OK; } -//////////////////////////////////////////////////////////////////////////////// -// nsPIFTPChannel methods: -NS_IMETHODIMP -nsFTPChannel::SetConnectionQueue(nsIEventQueue *aEventQ) { - nsresult rv = NS_OK; - - if (aEventQ) { - // create the proxy object so we can call into the FTP thread. - NS_WITH_SERVICE(nsIProxyObjectManager, proxyManager, kProxyObjectManagerCID, &rv); - if (NS_FAILED(rv)) return rv; - - // change the thread request over to a proxy thread request. - rv = proxyManager->GetProxyObject(aEventQ, - NS_GET_IID(nsIRequest), - mThreadRequest, - PROXY_ASYNC | PROXY_ALWAYS, - getter_AddRefs(mProxiedThreadRequest)); - } - mThreadRequest = 0; - - return rv; -} - NS_IMETHODIMP nsFTPChannel::SetContentLength(PRInt32 aLength) { mContentLength = aLength; @@ -547,9 +482,8 @@ nsFTPChannel::Stopped(nsresult aStatus, const PRUnichar *aMsg) { nsresult rv = NS_OK; // the underlying connection thread has gone away. mConnected = PR_FALSE; - mThreadRequest = 0; - mProxiedThreadRequest = 0; - NS_IF_RELEASE(mConnThread); + NS_ASSERTION(mConnThread, "lost the connection thread"); + NS_RELEASE(mConnThread); if (mLoadGroup) rv = mLoadGroup->RemoveChannel(this, nsnull, aStatus, aMsg); diff --git a/mozilla/netwerk/protocol/ftp/src/nsFTPChannel.h b/mozilla/netwerk/protocol/ftp/src/nsFTPChannel.h index 4de453ca4e8..95d700bc9a8 100644 --- a/mozilla/netwerk/protocol/ftp/src/nsFTPChannel.h +++ b/mozilla/netwerk/protocol/ftp/src/nsFTPChannel.h @@ -26,22 +26,16 @@ #define nsFTPChannel_h___ #include "nsPIFTPChannel.h" -#include "nsIStreamListener.h" #include "nsIURI.h" #include "nsString2.h" -#include "nsIEventQueue.h" #include "nsILoadGroup.h" #include "nsCOMPtr.h" -#include "nsHashtable.h" #include "nsIProtocolHandler.h" #include "nsIProgressEventSink.h" #include "nsIInterfaceRequestor.h" #include "nsIThreadPool.h" -#include "nsIRequest.h" -#include "nsAutoLock.h" #include "nsFtpConnectionThread.h" #include "netCore.h" -#include "nsIProgressEventSink.h" class nsFTPChannel : public nsPIFTPChannel, public nsIInterfaceRequestor, @@ -89,12 +83,10 @@ protected: PRUint32 mSourceOffset; PRInt32 mAmount; nsCOMPtr mLoadGroup; - nsAutoString mContentType; + nsCAutoString mContentType; PRInt32 mContentLength; nsCOMPtr mOwner; - nsCOMPtr mThreadRequest; - nsCOMPtr mProxiedThreadRequest; nsCOMPtr mHandler; nsCOMPtr mPool; // the thread pool we want to use to fire off connections. nsFtpConnectionThread *mConnThread; // the raw pointer to the thread object. diff --git a/mozilla/netwerk/protocol/ftp/src/nsFtpConnectionThread.cpp b/mozilla/netwerk/protocol/ftp/src/nsFtpConnectionThread.cpp index 67332478f8c..b7b16064e88 100644 --- a/mozilla/netwerk/protocol/ftp/src/nsFtpConnectionThread.cpp +++ b/mozilla/netwerk/protocol/ftp/src/nsFtpConnectionThread.cpp @@ -26,25 +26,21 @@ #include "nsIPipe.h" #include "nsIMIMEService.h" #include "nsIStreamConverterService.h" -#include "nsIIOService.h" #include "prprf.h" #include "prlog.h" +#include "prmon.h" #include "netCore.h" #include "ftpCore.h" #include "nsProxiedService.h" -#include "nsAutoLock.h" #include "nsCRT.h" #include "nsIInterfaceRequestor.h" +#include "nsFTPListener.h" #include "nsAppShellCIDs.h" // TODO remove later #include "nsIAppShellService.h" // TODO remove later #include "nsIWebShellWindow.h" // TODO remove later #include "nsINetPrompt.h" -#include "nsFtpProtocolHandler.h" -#include "nsPIFTPChannel.h" - -static NS_DEFINE_CID(kIOServiceCID, NS_IOSERVICE_CID); static NS_DEFINE_CID(kStreamConverterServiceCID, NS_STREAMCONVERTERSERVICE_CID); static NS_DEFINE_CID(kMIMEServiceCID, NS_MIMESERVICE_CID); static NS_DEFINE_CID(kEventQueueServiceCID, NS_EVENTQUEUESERVICE_CID); @@ -53,60 +49,126 @@ static NS_DEFINE_CID(kAppShellServiceCID, NS_APPSHELL_SERVICE_CID); static NS_DEFINE_CID(kProxyObjectManagerCID, NS_PROXYEVENT_MANAGER_CID); static NS_DEFINE_CID(kSocketTransportServiceCID, NS_SOCKETTRANSPORTSERVICE_CID); -static NS_DEFINE_CID(kFTPHandlerCID, NS_FTPPROTOCOLHANDLER_CID); #if defined(PR_LOGGING) extern PRLogModuleInfo* gFTPLog; #endif /* PR_LOGGING */ -NS_IMPL_ISUPPORTS2(nsFtpConnectionThread, nsIRunnable, nsIRequest); + +class nsFTPAsyncReadEvent { +public: + nsFTPAsyncReadEvent(nsIChannel *aChannel, + nsIStreamListener *aListener, + nsISupports *aContext); + virtual ~nsFTPAsyncReadEvent(); + + nsresult Fire(nsIEventQueue* aEventQ); + nsresult HandleEvent(); + +protected: + static void PR_CALLBACK HandlePLEvent(PLEvent* aEvent); + static void PR_CALLBACK DestroyPLEvent(PLEvent* aEvent); + + nsCOMPtr mChannel; + nsCOMPtr mListener; + nsCOMPtr mContext; + PLEvent *mEvent; +}; + +//////////////////////////////////////////////////////////////////////////////// + +nsFTPAsyncReadEvent::nsFTPAsyncReadEvent(nsIChannel *aChannel, + nsIStreamListener *aListener, + nsISupports *aContext) + : mChannel(aChannel), mListener(aListener), mContext(aContext), mEvent(nsnull) +{} + +nsFTPAsyncReadEvent::~nsFTPAsyncReadEvent() { + if (mEvent) { + delete mEvent; + mEvent = nsnull; + } +} + +nsresult +nsFTPAsyncReadEvent::HandleEvent() { + return mChannel->AsyncRead(0, -1, mContext, mListener); +} + +void PR_CALLBACK +nsFTPAsyncReadEvent::HandlePLEvent(PLEvent* aEvent) { + nsFTPAsyncReadEvent *ev = (nsFTPAsyncReadEvent*) PL_GetEventOwner(aEvent); + NS_ASSERTION(nsnull != ev,"null event."); + ev->HandleEvent(); +} + +void PR_CALLBACK +nsFTPAsyncReadEvent::DestroyPLEvent(PLEvent* aEvent) { + nsFTPAsyncReadEvent *ev = (nsFTPAsyncReadEvent*) PL_GetEventOwner(aEvent); + NS_ASSERTION(nsnull != ev,"null event."); + delete ev; +} + +nsresult +nsFTPAsyncReadEvent::Fire(nsIEventQueue* aEventQueue) { + NS_PRECONDITION(nsnull != aEventQueue, "nsIEventQueue for thread is null"); + NS_PRECONDITION(nsnull == mEvent, "Init plevent only once."); + mEvent = new PLEvent; + if (!mEvent) return NS_ERROR_OUT_OF_MEMORY; + + PL_InitEvent(mEvent, + this, + (PLHandleEventProc) nsFTPAsyncReadEvent::HandlePLEvent, + (PLDestroyEventProc) nsFTPAsyncReadEvent::DestroyPLEvent); + + PRStatus status = aEventQueue->PostEvent(mEvent); + return status == PR_SUCCESS ? NS_OK : NS_ERROR_FAILURE; +} + +NS_IMPL_ISUPPORTS3(nsFtpConnectionThread, nsIRunnable, nsIRequest, nsIStreamObserver); nsFtpConnectionThread::nsFtpConnectionThread() { NS_INIT_REFCNT(); - mSTS = nsnull; + // bool init + mConnected = mResetMode = mList = mRetryPass = mCachedConn = mSentStart = PR_FALSE; + mUsePasv = mBin = mKeepRunning = mAnonymous = PR_TRUE; + mAction = GET; - mUsePasv = PR_TRUE; mState = FTP_S_USER; mNextState = FTP_S_USER; - mBin = PR_TRUE; mLength = -1; - mConnected = PR_FALSE; - mResetMode = PR_FALSE; - mList = PR_FALSE; - mKeepRunning = PR_TRUE; - mContinueRead = PR_FALSE; - mAnonymous = PR_TRUE; - mRetryPass = PR_FALSE; - mCachedConn = PR_FALSE; - mInternalError = NS_OK; // start out on the up 'n up. - mSentStart = PR_FALSE; + + mInternalError = NS_OK; mConn = nsnull; mSuspendCount = 0; - mPort = 21; // default FTP port + mPort = 21; + + mLock = nsnull; + mMonitor = nsnull; } nsFtpConnectionThread::~nsFtpConnectionThread() { - // lose the socket transport - NS_IF_RELEASE(mSTS); PR_LOG(gFTPLog, PR_LOG_ALWAYS, ("~nsFtpConnectionThread() called")); + if (mLock) { + PR_DestroyLock(mLock); + mLock = nsnull; + } + + if (mMonitor) { + PR_DestroyMonitor(mMonitor); + mMonitor = nsnull; + } } nsresult nsFtpConnectionThread::Process() { - nsresult rv; + nsresult rv = NS_OK; + PRBool continueRead = PR_FALSE; PR_LOG(gFTPLog, PR_LOG_DEBUG, ("nsFtpConnectionThread::Process() started for %x (spec =%s)\n", mURL.get(), (const char *) mURLSpec)); while (mKeepRunning) { - - // churn the event pump - PLEvent *event; - rv = mFTPEventQueue->GetEvent(&event); - if (NS_FAILED(rv)) return rv; - rv = mFTPEventQueue->HandleEvent(event); - if (NS_FAILED(rv)) return rv; - switch(mState) { ////////////////////////////// @@ -135,26 +197,24 @@ nsFtpConnectionThread::Process() { PR_LOG(gFTPLog, PR_LOG_DEBUG, ("%x Process() - READ_BUF - read \"%s\" (%d bytes)", mURL.get(), buffer, read)); // get the response code out. - if (!mContinueRead) { + if (!continueRead) { PR_sscanf(buffer, "%d", &mResponseCode); mResponseCode = mResponseCode / 100; // truncate it } // see if we're handling a multi-line response. - if (mContinueRead || (buffer[3] == '-')) { + if (continueRead || (buffer[3] == '-')) { // yup, multi-line response, start appending char *tmpBuffer = buffer, *crlf = nsnull; PRBool lastLine = PR_FALSE; while ( (crlf = PL_strstr(tmpBuffer, CRLF)) ) { - if (crlf) { - char tmpChar = crlf[2]; - crlf[2] = '\0'; - // see if this is the last line - lastLine = tmpBuffer[3] != '-'; - mResponseMsg += tmpBuffer+4; // skip over the code and '-' - crlf[2] = tmpChar; - tmpBuffer = crlf+2; - } + char tmpChar = crlf[2]; + crlf[2] = '\0'; + // see if this is the last line + lastLine = tmpBuffer[3] != '-'; + mResponseMsg += tmpBuffer+4; // skip over the code and '-' + crlf[2] = tmpChar; + tmpBuffer = crlf+2; } if (*tmpBuffer) mResponseMsg += tmpBuffer+4; @@ -169,10 +229,10 @@ nsFtpConnectionThread::Process() { } else { mState = mNextState; } - mContinueRead = PR_FALSE; + continueRead = PR_FALSE; } else { // don't increment state, we need to read more. - mContinueRead = PR_TRUE; + continueRead = PR_TRUE; } break; } @@ -190,83 +250,6 @@ nsFtpConnectionThread::Process() { } // END: FTP_READ_BUF - case FTP_READ_DATA_BUF: - { - PRUint32 read = 0, readSoFar = 0; - - if (mCallerOutputStream) { - // we have an output stream, write data to it - // rather than sending OnDataAvailable() calls. - - while (readSoFar < NS_FTP_BUFFER_READ_SIZE) { - rv = mCallerOutputStream->WriteFrom(mDInStream, - NS_FTP_BUFFER_READ_SIZE-readSoFar, - &read); - if (NS_FAILED(rv)) { - mInternalError = NS_ERROR_FAILURE; - mState = FTP_ERROR; - break; - } - readSoFar += read; - - if (!read) { - // EOF - mCallerOutputStream->Close(); - - mState = FTP_READ_BUF; - mNextState = FTP_COMPLETE; - break; - } - } - } else { - NS_ASSERTION(mListener, "FTP: conn thread listener DNE"); - // no output stream. shuttle data over using the listener - while (readSoFar < NS_FTP_BUFFER_READ_SIZE) { - PRUint32 avail = 0; - rv = mBufInStream->Available(&avail); - if (NS_FAILED(rv)) return rv; - - // suck in the data from the server - rv = mBufOutStream->WriteFrom(mDInStream, NS_FTP_BUFFER_READ_SIZE-readSoFar, &read); - if (NS_FAILED(rv)) { - mInternalError = NS_ERROR_FAILURE; - mState = FTP_ERROR; - break; - } - readSoFar += read; - if (read == 0) { - // we've exhausted the stream, send any data we have left and get out of dodge. - rv = mListener->OnDataAvailable(mChannel, mContext, mBufInStream, avail, readSoFar); - if (NS_FAILED(rv)) { - mInternalError = NS_ERROR_FAILURE; - mState = FTP_ERROR; - break; - } - - // we're done filling this end of the pipe. close it. - mBufOutStream->Close(); - - mState = FTP_READ_BUF; - mNextState = FTP_COMPLETE; - break; // this terminates the loop - } - - if (readSoFar == NS_FTP_BUFFER_READ_SIZE) { - // we've filled our buffer, send the data off - rv = mListener->OnDataAvailable(mChannel, mContext, mBufInStream, avail, NS_FTP_BUFFER_READ_SIZE); - if (NS_FAILED(rv)) { - mInternalError = NS_ERROR_FAILURE; - mState = FTP_ERROR; - break; - } - mState = FTP_READ_DATA_BUF; - } - } - } // end mCallerOutputStream - break; - } - // END: FTP_READ_DATA_BUF - case FTP_ERROR: { PR_LOG(gFTPLog, PR_LOG_DEBUG, ("%x Process() - ERROR\n", mURL.get())); @@ -297,7 +280,6 @@ nsFtpConnectionThread::Process() { } // END: FTP_COMPLETE - ////////////////////////////// //// CONNECTION SETUP STATES ////////////////////////////// @@ -572,15 +554,6 @@ nsFtpConnectionThread::Process() { PR_LOG(gFTPLog, PR_LOG_DEBUG, ("FAILED\n")); } else { PR_LOG(gFTPLog, PR_LOG_DEBUG, ("SUCCEEDED\n")); - // get the data channel ready - PR_LOG(gFTPLog, PR_LOG_DEBUG, ("%x Process() - S_LIST - Opening data stream ", mURL.get())); - rv = mDPipe->OpenInputStream(0, -1, getter_AddRefs(mDInStream)); - if (NS_FAILED(rv)) { - PR_LOG(gFTPLog, PR_LOG_DEBUG, ("FAILED\n")); - return rv; - } - PR_LOG(gFTPLog, PR_LOG_DEBUG, ("SUCCEEDED\n")); - mState = FTP_READ_BUF; mNextState = FTP_R_LIST; } @@ -591,9 +564,12 @@ nsFtpConnectionThread::Process() { case FTP_R_LIST: { mState = R_list(); - if (FTP_ERROR == mState) - mInternalError = NS_ERROR_FAILURE; - mNextState = FTP_COMPLETE; + if (FTP_ERROR == mState) { + mInternalError = rv; + mNextState = FTP_ERROR; + } else { + mNextState = FTP_COMPLETE; + } break; } // END: FTP_R_LIST @@ -608,15 +584,6 @@ nsFtpConnectionThread::Process() { PR_LOG(gFTPLog, PR_LOG_DEBUG, ("FAILED\n")); } else { PR_LOG(gFTPLog, PR_LOG_DEBUG, ("SUCCEEDED\n")); - // get the data channel ready - PR_LOG(gFTPLog, PR_LOG_DEBUG, ("%x Process() - S_RETR - Opening data stream ", mURL.get())); - rv = mDPipe->OpenInputStream(0, -1, getter_AddRefs(mDInStream)); - if (NS_FAILED(rv)) { - PR_LOG(gFTPLog, PR_LOG_DEBUG, ("FAILED\n")); - return rv; - } - PR_LOG(gFTPLog, PR_LOG_DEBUG, ("SUCCEEDED\n")); - mState = FTP_READ_BUF; mNextState = FTP_R_RETR; } @@ -658,8 +625,13 @@ nsFtpConnectionThread::Process() { case FTP_R_PASV: { mState = R_pasv(); + PLEvent *event = nsnull; + if ( NS_FAILED(mFTPEventQueue->WaitForEvent(&event)) + || NS_FAILED(mFTPEventQueue->HandleEvent(event))) return rv; + if (FTP_ERROR == mState) mInternalError = NS_ERROR_FTP_PASV; + mNextState = FTP_READ_BUF; break; } // END: FTP_R_PASV @@ -757,55 +729,26 @@ nsFtpConnectionThread::Process() { return NS_OK; } -nsresult -nsFtpConnectionThread::SetOutputStream(nsIBufferOutputStream* aOutputStream) { - if (mCallerOutputStream) return NS_ERROR_FAILURE; - mCallerOutputStream = aOutputStream; - return NS_OK; -} - nsresult nsFtpConnectionThread::SetStreamObserver(nsIStreamObserver* aObserver, nsISupports *aContext) { - nsresult rv; - static PRBool streamObserverSet = PR_FALSE; - if (streamObserverSet) return NS_ERROR_FAILURE; + nsresult rv = NS_OK; + if (mConnected) return NS_ERROR_ALREADY_CONNECTED; + mObserverContext = aContext; NS_WITH_SERVICE(nsIProxyObjectManager, pIProxyObjectManager, kProxyObjectManagerCID, &rv); if(NS_FAILED(rv)) return rv; - rv = pIProxyObjectManager->GetProxyObject(nsnull, /* use the main thread's eventQ */ + return pIProxyObjectManager->GetProxyObject(NS_UI_THREAD_EVENTQ, NS_GET_IID(nsIStreamObserver), aObserver, PROXY_ASYNC | PROXY_ALWAYS, getter_AddRefs(mObserver)); - mObserverContext = aContext; - streamObserverSet = PR_TRUE; - return rv; } nsresult -nsFtpConnectionThread::SetStreamListener(nsIStreamListener* aListener) { - nsresult rv; - // stream listeners can be reset at any time. - mListener = 0; - mSyncListener = 0; - - NS_WITH_SERVICE(nsIProxyObjectManager, pIProxyObjectManager, kProxyObjectManagerCID, &rv); - if(NS_FAILED(rv)) return rv; - - rv = pIProxyObjectManager->GetProxyObject(nsnull, - NS_GET_IID(nsIStreamListener), - aListener, - PROXY_ASYNC | PROXY_ALWAYS, - getter_AddRefs(mListener)); - if (NS_FAILED(rv)) return rv; - - rv = pIProxyObjectManager->GetProxyObject(nsnull, - NS_GET_IID(nsIStreamListener), - aListener, - PROXY_SYNC | PROXY_ALWAYS, - getter_AddRefs(mSyncListener)); - if (NS_FAILED(rv)) return rv; - +nsFtpConnectionThread::SetStreamListener(nsIStreamListener* aListener, nsISupports *aContext) { + nsresult rv = NS_OK; + mListener = aListener; + mListenerContext = aContext; return NS_OK; } @@ -823,20 +766,20 @@ nsFtpConnectionThread::S_user() { } else { if (!mUsername.Length()) { - NS_WITH_SERVICE(nsIAppShellService, appshellservice, kAppShellServiceCID, &rv); - if (NS_FAILED(rv)) return rv; + NS_WITH_SERVICE(nsIAppShellService, appshellservice, kAppShellServiceCID, &rv); + if (NS_FAILED(rv)) return rv; - nsCOMPtr webshellwindow; - appshellservice->GetHiddenWindow(getter_AddRefs( webshellwindow ) ); - nsCOMPtr prompter( do_QueryInterface( webshellwindow ) ); + nsCOMPtr webshellwindow; + appshellservice->GetHiddenWindow(getter_AddRefs( webshellwindow ) ); + nsCOMPtr prompter( do_QueryInterface( webshellwindow ) ); - NS_WITH_SERVICE(nsIProxyObjectManager, pIProxyObjectManager, kProxyObjectManagerCID, &rv); - if(NS_FAILED(rv)) { - return rv; - } - nsINetPrompt* proxyprompter = NULL; - rv = pIProxyObjectManager->GetProxyObject - (NS_UI_THREAD_EVENTQ, nsINetPrompt::GetIID(), prompter, PROXY_SYNC, (void**)&proxyprompter); + NS_WITH_SERVICE(nsIProxyObjectManager, pIProxyObjectManager, kProxyObjectManagerCID, &rv); + if (NS_FAILED(rv)) return rv; + + nsCOMPtr proxyprompter; + rv = pIProxyObjectManager->GetProxyObject(NS_UI_THREAD_EVENTQ, + NS_GET_IID(nsINetPrompt), prompter, + PROXY_SYNC, getter_AddRefs(proxyprompter)); PRUnichar *user = nsnull, *passwd = nsnull; PRBool retval; static nsAutoString message; @@ -849,7 +792,6 @@ nsFtpConnectionThread::S_user() { } rv = proxyprompter->PromptUsernameAndPassword(host, NULL, message.GetUnicode(), &user, &passwd, &retval); - proxyprompter->Release(); // Must be done as not managed for you. // if the user canceled or didn't supply a username we want to fail if (!retval || (user && !*user) ) return NS_ERROR_FAILURE; @@ -900,20 +842,20 @@ nsFtpConnectionThread::S_pass() { } else { if (!mPassword.Length() || mRetryPass) { // ignore any password we have, it's not working - NS_WITH_SERVICE(nsIAppShellService, appshellservice, kAppShellServiceCID, &rv); - if (NS_FAILED(rv)) return rv; + NS_WITH_SERVICE(nsIAppShellService, appshellservice, kAppShellServiceCID, &rv); + if (NS_FAILED(rv)) return rv; - nsCOMPtr webshellwindow; - appshellservice->GetHiddenWindow(getter_AddRefs( webshellwindow ) ); - nsCOMPtr prompter( do_QueryInterface( webshellwindow ) ); + nsCOMPtr webshellwindow; + appshellservice->GetHiddenWindow(getter_AddRefs( webshellwindow ) ); + nsCOMPtr prompter( do_QueryInterface( webshellwindow ) ); - NS_WITH_SERVICE(nsIProxyObjectManager, pIProxyObjectManager, kProxyObjectManagerCID, &rv); - if(NS_FAILED(rv)) { - return rv; - } - nsINetPrompt* proxyprompter = NULL; - rv = pIProxyObjectManager->GetProxyObject - (NS_UI_THREAD_EVENTQ, nsINetPrompt::GetIID(), prompter, PROXY_SYNC, (void**)&proxyprompter); + NS_WITH_SERVICE(nsIProxyObjectManager, pIProxyObjectManager, kProxyObjectManagerCID, &rv); + if (NS_FAILED(rv)) return rv; + + nsCOMPtr proxyprompter; + rv = pIProxyObjectManager->GetProxyObject(NS_UI_THREAD_EVENTQ, + NS_GET_IID(nsINetPrompt), prompter, + PROXY_SYNC, getter_AddRefs(proxyprompter)); PRUnichar *passwd = nsnull; PRBool retval; static nsAutoString message; @@ -938,7 +880,6 @@ nsFtpConnectionThread::S_pass() { } rv = proxyprompter->PromptPassword(userAtHostC, NULL, message.GetUnicode(), &passwd, &retval); nsCRT::free(userAtHostC); - proxyprompter->Release(); // Must be done as not managed for you. // we want to fail if the user canceled or didn't enter a password. if (!retval || (passwd && !*passwd) ) @@ -1321,6 +1262,7 @@ nsFtpConnectionThread::R_mdtm() { nsresult nsFtpConnectionThread::S_list() { + nsresult rv; char *buffer; PRUint32 bytes; if (mList) @@ -1330,19 +1272,9 @@ nsFtpConnectionThread::S_list() { PR_LOG(gFTPLog, PR_LOG_DEBUG, ("%x Writing \"%s\"\n", mURL.get(), buffer)); - return mCOutStream->Write(buffer, PL_strlen(buffer), &bytes); -} + rv = mCOutStream->Write(buffer, PL_strlen(buffer), &bytes); + if (NS_FAILED(rv)) return rv; -FTP_STATE -nsFtpConnectionThread::R_list() { - nsresult rv; - - if ((mResponseCode == 4) - || - (mResponseCode == 5)) { - // unable to open the data connection. - return FTP_ERROR; - } // setup a listener to push the data into. This listener sits inbetween the // unconverted data of fromType, and the final listener in the chain (in this case @@ -1350,89 +1282,43 @@ nsFtpConnectionThread::R_list() { nsCOMPtr converterListener; NS_WITH_SERVICE(nsIStreamConverterService, StreamConvService, kStreamConverterServiceCID, &rv); - if (NS_FAILED(rv)) { - return FTP_ERROR; - } + if (NS_FAILED(rv)) return rv; nsAutoString fromStr("text/ftp-dir-"); SetDirMIMEType(fromStr); - - // all FTP directory listings are converted to http-index nsAutoString toStr("application/http-index-format"); - if (mCallerOutputStream) { - nsCOMPtr convertedStream; - rv = StreamConvService->Convert(mDInStream, - fromStr.GetUnicode(), - toStr.GetUnicode(), - mURL, - getter_AddRefs(convertedStream)); - if (NS_FAILED(rv)) return FTP_ERROR; + rv = StreamConvService->AsyncConvertData(fromStr.GetUnicode(), toStr.GetUnicode(), + mListener, mURL, getter_AddRefs(converterListener)); + if (NS_FAILED(rv)) return rv; + + nsFTPListener *FTPListener = new nsFTPListener(converterListener, mChannel); + if (!FTPListener) return rv; - mDInStream->Close(); - mDInStream = 0; + nsFTPAsyncReadEvent *event = new nsFTPAsyncReadEvent(mDPipe, + FTPListener, + mListenerContext); + if (!event) return NS_ERROR_OUT_OF_MEMORY; - mDInStream = convertedStream; - return FTP_READ_DATA_BUF; - } else { - rv = StreamConvService->AsyncConvertData(fromStr.GetUnicode(), - toStr.GetUnicode(), - mSyncListener, - mURL, getter_AddRefs(converterListener)); - if (NS_FAILED(rv)) { - return FTP_ERROR; - } + return event->Fire(mUIEventQ); +} - rv = converterListener->OnStartRequest(mChannel, mContext); - if (NS_FAILED(rv)) return FTP_ERROR; - - mSentStart = PR_TRUE; - - // The only way out of this loop is if the stream read - // fails or we read the end of the stream. - while (1) { - PRUint32 read; - char *listBuf = (char*)nsAllocator::Alloc(NS_FTP_BUFFER_READ_SIZE + 1); - if (!listBuf) return FTP_ERROR; - - rv = mDInStream->Read(listBuf, NS_FTP_BUFFER_READ_SIZE, &read); - - if (NS_FAILED(rv)) { - PR_LOG(gFTPLog, PR_LOG_DEBUG, ("%x R_list() data pipe read failed w/ rv = %d\n", mURL.get(), rv)); - nsAllocator::Free(listBuf); - return FTP_ERROR; - } else if (read < 1) { - // EOF - PR_LOG(gFTPLog, PR_LOG_DEBUG, ("%x R_list() data pipe read hit EOF\n", mURL.get())); - nsAllocator::Free(listBuf); - return FTP_READ_BUF; - } - listBuf[read] = '\0'; - - PR_LOG(gFTPLog, PR_LOG_DEBUG, ("%x R_list() data pipe read %d bytes:\n%s\n", mURL.get(), read, listBuf)); - - nsCOMPtr stringStreamSup; - rv = NS_NewCharInputStream(getter_AddRefs(stringStreamSup), listBuf); - if (NS_FAILED(rv)) return FTP_ERROR; - - nsCOMPtr listStream = do_QueryInterface(stringStreamSup, &rv); - - rv = converterListener->OnDataAvailable(mChannel, mContext, listStream, 0, read); - if (NS_FAILED(rv)) return FTP_ERROR; - } +FTP_STATE +nsFtpConnectionThread::R_list() { + nsresult rv = NS_OK; + if ((mResponseCode == 4) + || + (mResponseCode == 5)) { + // unable to open the data connection. + return FTP_ERROR; } - - // NOTE: that we're not firing an OnStopRequest() to the converterListener (the - // stream converter). It (at least this implementation of it) doesn't care - // about stops. FTP_COMPLETE will send the stop. - return FTP_READ_BUF; } nsresult nsFtpConnectionThread::S_retr() { - nsresult rv; + nsresult rv = NS_OK; nsXPIDLCString path; PRUint32 bytes; rv = mURL->GetPath(getter_Copies(path)); @@ -1451,34 +1337,24 @@ nsFtpConnectionThread::S_retr() { PR_LOG(gFTPLog, PR_LOG_DEBUG, ("%x Writing \"%s\"\n", mURL.get(), retrStr.GetBuffer())); rv = mCOutStream->Write(retrStr.GetBuffer(), retrStr.Length(), &bytes); - return rv; -} -#define NS_FTP_SEGMENT_SIZE (2*1024) -#define NS_FTP_BUFFER_SIZE (8*1024) + nsFTPListener *FTPListener = new nsFTPListener(mListener, mChannel); + if (!FTPListener) return NS_ERROR_OUT_OF_MEMORY; + + nsFTPAsyncReadEvent *event = new nsFTPAsyncReadEvent(mDPipe, + FTPListener, + mListenerContext); + if (!event) return NS_ERROR_OUT_OF_MEMORY; + + return event->Fire(mUIEventQ); +} FTP_STATE nsFtpConnectionThread::R_retr() { - nsresult rv; - // The only way we can get here is if we knew we were dealing with - // a file and not a dir listing. This state assumes we're retrieving - // a file! + nsresult rv = NS_OK; if (mResponseCode == 1) { // success. - - // we may not have a listener if we were OpenInputStream()ed. - if (mListener) { - rv = mListener->OnStartRequest(mChannel, mContext); - if (NS_FAILED(rv)) return FTP_ERROR; - mSentStart = PR_TRUE; - } - - rv = NS_NewPipe(getter_AddRefs(mBufInStream), getter_AddRefs(mBufOutStream), - nsnull, NS_FTP_SEGMENT_SIZE, NS_FTP_BUFFER_SIZE); - if (NS_FAILED(rv)) return FTP_ERROR; - - return FTP_READ_DATA_BUF; - + return FTP_READ_BUF; } else { if (mServerType == FTP_VMS_TYPE) { return FTP_ERROR; @@ -1488,7 +1364,6 @@ nsFtpConnectionThread::R_retr() { } } - nsresult nsFtpConnectionThread::S_pasv() { char *buffer = "PASV" CRLF; @@ -1572,20 +1447,16 @@ nsFtpConnectionThread::R_pasv() { getter_AddRefs(mDPipe)); // the data channel if (NS_FAILED(rv)) return FTP_ERROR; + // The FTP connection thread will receive transport leve + // AsyncOpen notifications. + rv = mDPipe->AsyncOpen(this, nsnull); + if (NS_FAILED(rv)) return FTP_ERROR; + // hook ourself up as a proxy for progress notifications nsCOMPtr progressProxy(do_QueryInterface(mChannel)); rv = mDPipe->SetNotificationCallbacks(progressProxy); if (NS_FAILED(rv)) return FTP_ERROR; - - if (mAction == GET) { - // Setup the data channel for file reception - } else { - // get the output stream so we can write to the server - rv = mDPipe->OpenOutputStream(0, getter_AddRefs(mDOutStream)); - if (NS_FAILED(rv)) return FTP_ERROR; - } - // we're connected figure out what type of transfer we're doing (ascii or binary) nsXPIDLCString type; rv = mFTPChannel->GetContentType(getter_Copies(type)); @@ -1595,8 +1466,6 @@ nsFtpConnectionThread::R_pasv() { else typeStr = type; - mContentType = typeStr; - PRInt32 textType = typeStr.Find("text"); if (textType == 0) // only send ascii for text type files @@ -1613,7 +1482,7 @@ nsFtpConnectionThread::S_del_file() { nsXPIDLCString filename; PRUint32 bytes; rv = mURL->GetPath(getter_Copies(filename)); // XXX we should probably check to - // XXX make sure we have an actual filename. + // XXX make sure we have an actual filename. if (NS_FAILED(rv)) return rv; nsCAutoString delStr("DELE "); @@ -1691,7 +1560,8 @@ nsFtpConnectionThread::R_mkdir() { // END: STATE METHODS /////////////////////////////////// - +#define FTP_COMMAND_CHANNEL_SEG_SIZE 64 +#define FTP_COMMAND_CHANNEL_MAX_SIZE 512 //////////////////////////////////////////////////////////////////////////////// // nsIRunnable method: @@ -1709,26 +1579,12 @@ nsFtpConnectionThread::Run() { rv = eventQService->GetThreadEventQueue(NS_CURRENT_THREAD, getter_AddRefs(mFTPEventQueue)); if (NS_FAILED(rv)) return rv; - // we've got to send the event queue for this sucker over to the - // channel's thread so he can post event back to us. - NS_WITH_SERVICE(nsIProxyObjectManager, pIProxyObjectManager, kProxyObjectManagerCID, &rv); - if(NS_FAILED(rv)) return rv; - - nsCOMPtr ftpChannel; - rv = pIProxyObjectManager->GetProxyObject(nsnull, - NS_GET_IID(nsPIFTPChannel), - mChannel, - PROXY_SYNC | PROXY_ALWAYS, - getter_AddRefs(ftpChannel)); + rv = eventQService->GetThreadEventQueue(NS_UI_THREAD, getter_AddRefs(mUIEventQ)); if (NS_FAILED(rv)) return rv; - rv = ftpChannel->SetConnectionQueue(mFTPEventQueue); - if (NS_FAILED(rv)) return rv; - - rv = nsServiceManager::GetService(kSocketTransportServiceCID, NS_GET_IID(nsISocketTransportService), - (nsISupports **)&mSTS); + getter_AddRefs(mSTS)); if(NS_FAILED(rv)) return rv; ///////////////////////// @@ -1757,7 +1613,8 @@ nsFtpConnectionThread::Run() { // build our own rv = mSTS->CreateTransport(host, mPort, host, - mBufferSegmentSize, mBufferMaxSize, + FTP_COMMAND_CHANNEL_SEG_SIZE, + FTP_COMMAND_CHANNEL_MAX_SIZE, getter_AddRefs(mCPipe)); // the command channel if (NS_FAILED(rv)) return rv; @@ -1778,64 +1635,10 @@ nsFtpConnectionThread::Run() { /////////////////////////////// if (!mCachedConn) { - // digest any server greeting. - char greetBuf[NS_FTP_BUFFER_READ_SIZE]; - for (PRInt32 i=0; i < NS_FTP_BUFFER_READ_SIZE; i++) - greetBuf[i] = '\0'; - PRUint32 read; - rv = mCInStream->Read(greetBuf, NS_FTP_BUFFER_READ_SIZE, &read); - if (NS_FAILED(rv)) { - PR_LOG(gFTPLog, PR_LOG_DEBUG, ("%x nsFTPConnTrd::Run() greeting read failed with rv = %d\n", mURL.get(), rv)); - return rv; - } - - if (read > 0) { - // we got something. - // look for a response code - switch (greetBuf[0]) { - case '2': - PR_sscanf(greetBuf, "%d", &mResponseCode); - mResponseCode = mResponseCode / 100; // truncate it - - // we're receiving some data - // see if it's multiline - if (greetBuf[3] == '-') { - // yup, multi-line. be sure to digest the rest of it later. - char *tmpBuffer = greetBuf, *crlf = nsnull; - PRBool lastLine = PR_FALSE; - while ( (crlf = PL_strstr(tmpBuffer, CRLF)) ) { - if (crlf) { - char tmpChar = crlf[2]; - crlf[2] = '\0'; - // see if this is the last line - lastLine = tmpBuffer[3] != '-'; - mResponseMsg += tmpBuffer+4; // skip over the code and '-' - crlf[2] = tmpChar; - tmpBuffer = crlf+2; - } - } - if (*tmpBuffer) - mResponseMsg += tmpBuffer+4; - - // see if this was the last line - if (lastLine || (*tmpBuffer && (tmpBuffer[3] != '-')) ) { - // yup. last line, let's move on. - mContinueRead = PR_FALSE; - mState = mNextState; - } else { - //we need to read more. - mContinueRead = PR_TRUE; - mState = FTP_READ_BUF; - } - } - break; - default: - break; - } - } + rv = DigestServerGreeting(); + if (NS_FAILED(rv)) return rv; } else { - // we're already connected to this server. - // skip login. + // we're already connected to this server, skip login. mState = FTP_S_PASV; } @@ -1843,7 +1646,6 @@ nsFtpConnectionThread::Run() { rv = Process(); mListener = 0; - mSyncListener = 0; mChannel = 0; mConnCache = 0; @@ -1858,6 +1660,8 @@ nsFtpConnectionThread::IsPending(PRBool *result) { nsresult rv = NS_OK; *result = PR_FALSE; + nsAutoLock aLock(mLock); + if (mCPipe) { rv = mCPipe->IsPending(result); if (NS_FAILED(rv)) return rv; @@ -1873,6 +1677,8 @@ NS_IMETHODIMP nsFtpConnectionThread::Cancel(void) { nsresult rv = NS_OK; + nsAutoLock aLock(mLock); + if (mCPipe) { rv = mCPipe->Cancel(); if (NS_FAILED(rv)) return rv; @@ -1881,7 +1687,7 @@ nsFtpConnectionThread::Cancel(void) rv = mDPipe->Cancel(); if (NS_FAILED(rv)) return rv; } - mInternalError = NS_ERROR_FAILURE; // XXX should be an FTP code. + mInternalError = NS_ERROR_FAILURE; mState = FTP_COMPLETE; return rv; } @@ -1890,6 +1696,12 @@ NS_IMETHODIMP nsFtpConnectionThread::Suspend(void) { nsresult rv = NS_OK; + nsAutoLock aLock(mLock); + + // suspending the underlying socket transport will + // cause the FTP state machine to "suspend" when it + // tries to use the transport. May not be granular + // enough. if (mSuspendCount < 1) { mSuspendCount++; if (mCPipe) { @@ -1900,10 +1712,6 @@ nsFtpConnectionThread::Suspend(void) rv = mDPipe->Suspend(); if (NS_FAILED(rv)) return rv; } - nsAutoCMonitor mon(this); - mon.Wait(); - // If we're notifiec, let everythign resume. - rv = Resume(); } return rv; @@ -1913,6 +1721,11 @@ NS_IMETHODIMP nsFtpConnectionThread::Resume(void) { nsresult rv = NS_ERROR_FAILURE; + nsAutoLock aLock(mLock); + + // resuming the underlying socket transports will + // cause the FTP state machine to unblock and + // go on about it's business. if (mSuspendCount) { // only a suspended thread can be resumed if (mCPipe) { @@ -1926,27 +1739,44 @@ nsFtpConnectionThread::Resume(void) rv = NS_OK; } mSuspendCount--; - return rv; } +// nsIStreamObserver methods +NS_IMETHODIMP +nsFtpConnectionThread::OnStartRequest(nsIChannel *aChannel, nsISupports *aContext) { + mState = FTP_S_MODE; // bump to the next state. + return NS_OK; +} + +NS_IMETHODIMP +nsFtpConnectionThread::OnStopRequest(nsIChannel *aChannel, nsISupports *aContext, + nsresult aStatus, const PRUnichar *aMsg) { + return NS_OK; +} nsresult nsFtpConnectionThread::Init(nsIProtocolHandler* aHandler, nsIChannel* aChannel, - nsISupports* aContext, PRUint32 bufferSegmentSize, PRUint32 bufferMaxSize) { - nsresult rv; + nsresult rv = NS_OK; + + if (mConnected) return NS_ERROR_ALREADY_CONNECTED; mBufferSegmentSize = bufferSegmentSize; mBufferMaxSize = bufferMaxSize; + mLock = PR_NewLock(); + if (!mLock) return NS_ERROR_OUT_OF_MEMORY; + + mMonitor = PR_NewMonitor(); + if (!mMonitor) return NS_ERROR_OUT_OF_MEMORY; + // parameter validation NS_ASSERTION(aChannel, "FTP: thread needs a channel"); // setup internal member variables mChannel = aChannel; // a straight com ptr to the channel - mContext = aContext; // this is the original caller's context rv = aChannel->GetURI(getter_AddRefs(mURL)); if (NS_FAILED(rv)) return rv; @@ -1990,7 +1820,7 @@ nsFtpConnectionThread::Init(nsIProtocolHandler* aHandler, // This proxied channel is used to set channel related // state on the *real* channel back in the main thread. - rv = pIProxyObjectManager->GetProxyObject(nsnull, + rv = pIProxyObjectManager->GetProxyObject(NS_UI_THREAD_EVENTQ, NS_GET_IID(nsPIFTPChannel), aChannel, PROXY_SYNC | PROXY_ALWAYS, @@ -1999,7 +1829,7 @@ nsFtpConnectionThread::Init(nsIProtocolHandler* aHandler, // get a proxied ptr to the FTP protocol handler service so we can control // the connection cache from here. - rv = pIProxyObjectManager->GetProxyObject(nsnull, + rv = pIProxyObjectManager->GetProxyObject(NS_UI_THREAD_EVENTQ, NS_GET_IID(nsIConnectionCache), aHandler, PROXY_SYNC | PROXY_ALWAYS, @@ -2009,12 +1839,59 @@ nsFtpConnectionThread::Init(nsIProtocolHandler* aHandler, nsresult nsFtpConnectionThread::SetAction(FTP_ACTION aAction) { - if (mConnected) - return NS_ERROR_ALREADY_CONNECTED; + if (mConnected) return NS_ERROR_ALREADY_CONNECTED; mAction = aAction; return NS_OK; } +nsresult +nsFtpConnectionThread::DigestServerGreeting() { + nsresult rv = NS_OK; + char greetBuf[NS_FTP_BUFFER_READ_SIZE+1]; + PRUint32 read = -1; + mResponseCode = 0; + PRBool multiline = PR_FALSE, lastline = PR_FALSE; + + while (1) { + rv = mCInStream->Read(greetBuf, NS_FTP_BUFFER_READ_SIZE, &read); + if (NS_FAILED(rv)) { + PR_LOG(gFTPLog, PR_LOG_DEBUG, ("%x FTP:Digest() greeting read failed with rv = %d\n", mURL.get(), rv)); + return rv; + } + + if (read < 1) break; + greetBuf[read] = '\0'; + + // we got something. look for a response code + if (!mResponseCode) { + PR_sscanf(greetBuf, "%d", &mResponseCode); + mResponseCode = mResponseCode / 100; // truncate it + } + + // first determine whether or not we're dealing with a + // multiline response. + //multiline = greetBuf[3] == '-'; + + // handle all the lines we Read() + char *buf = greetBuf, *lineEnd = nsnull; + while ( (lineEnd = PL_strstr(buf, CRLF)) ) { + char tmpChar = lineEnd[2]; + lineEnd[2] = '\0'; + mResponseMsg += buf+4; + lastline = buf[3] != '-'; // look for last line indicator + lineEnd[2] = tmpChar; + buf = lineEnd+2; // move to the next line + } + + if (lineEnd && lineEnd[4]) + mResponseMsg += lineEnd+4; + + if (lastline) break; + } + + return rv; +} + nsresult nsFtpConnectionThread::StopProcessing() { @@ -2035,24 +1912,10 @@ nsFtpConnectionThread::StopProcessing() { if (NS_FAILED(rv)) return rv; } - rv = mFTPChannel->Stopped(mInternalError, errorMsg); if (NS_FAILED(rv)) return rv; - // if we have a listener, end the transaction. - if (mListener) { - // if we haven't sent an OnStartRequest() yet, fire one now. We don't want - // to blidly send an OnStop if we haven't "started" anything. - if (!mSentStart) { - rv = mListener->OnStartRequest(mChannel, mContext); - if (NS_FAILED(rv)) return rv; - } - - rv = mListener->OnStopRequest(mChannel, mContext, mInternalError, errorMsg); - if (NS_FAILED(rv)) return rv; - } - - // if we have an observer, end hte transaction + // if we have an observer, end the transaction if (mObserver) { rv = mObserver->OnStopRequest(mChannel, mObserverContext, mInternalError, errorMsg); } @@ -2143,7 +2006,6 @@ nsFtpConnectionThread::FindGetState(void) { if (mServerType == FTP_VMS_TYPE) { // check for directory if (!path[0] || (path[0] == '/' && !path[1]) ) { - mDirectory = PR_TRUE; result = FTP_S_LIST; } else if (!PL_strchr(path, '/')) { @@ -2153,7 +2015,6 @@ nsFtpConnectionThread::FindGetState(void) { result = FTP_S_CWD; } } else { - // XXX I've removed the check for "aleady tried RETR" if (path[PL_strlen(path) -1] == '/') { result = FTP_S_CWD; } else { @@ -2250,4 +2111,3 @@ nsFtpConnectionThread::SetDirMIMEType(nsString& aString) { aString.Append("generic"); } } - diff --git a/mozilla/netwerk/protocol/ftp/src/nsFtpConnectionThread.h b/mozilla/netwerk/protocol/ftp/src/nsFtpConnectionThread.h index 2ed42442742..55427c3dc70 100644 --- a/mozilla/netwerk/protocol/ftp/src/nsFtpConnectionThread.h +++ b/mozilla/netwerk/protocol/ftp/src/nsFtpConnectionThread.h @@ -25,15 +25,14 @@ #include "nsIThread.h" #include "nsIRunnable.h" -#include "nsIRequest.h" #include "nsISocketTransportService.h" #include "nsIServiceManager.h" #include "nsIStreamListener.h" #include "nsIURI.h" #include "prtime.h" +#include "prmon.h" #include "nsString2.h" #include "nsIEventQueue.h" -#include "nsHashtable.h" #include "nsPIFTPChannel.h" #include "nsIConnectionCache.h" #include "nsConnectionCacheObj.h" @@ -42,6 +41,7 @@ #include "nsXPIDLString.h" #include "nsIBufferInputStream.h" #include "nsIBufferOutputStream.h" +#include "nsAutoLock.h" // ftp server types #define FTP_GENERIC_TYPE 0 @@ -60,217 +60,167 @@ typedef enum _FTP_STATE { /////////////////////// //// Internal states -/////////////////////// FTP_READ_BUF, - FTP_READ_DATA_BUF, FTP_ERROR, FTP_COMPLETE, /////////////////////// //// Command channel connection setup states -/////////////////////// - FTP_S_USER, // send username - FTP_R_USER, - FTP_S_PASS, // send password - FTP_R_PASS, - FTP_S_SYST, // send system (interrogates server) - FTP_R_SYST, - FTP_S_ACCT, // send account - FTP_R_ACCT, - FTP_S_MACB, - FTP_R_MACB, - FTP_S_PWD , // send parent working directory (pwd) - FTP_R_PWD , - FTP_S_DEL_FILE, // send delete file - FTP_R_DEL_FILE, - FTP_S_DEL_DIR , // send delete directory - FTP_R_DEL_DIR , - FTP_S_MKDIR, // send mkdir - FTP_R_MKDIR, - FTP_S_MODE, // send ASCII or BINARY - FTP_R_MODE, - FTP_S_CWD, // send change working directory - FTP_R_CWD, - FTP_S_SIZE, // send size - FTP_R_SIZE, - FTP_S_PUT, // send STOR to upload the file - FTP_R_PUT, - FTP_S_RETR, // send retrieve to download the file - FTP_R_RETR, - FTP_S_MDTM, // send MDTM to get time information - FTP_R_MDTM, - FTP_S_LIST, // send LIST or NLST (server dependent) to get a dir listing - FTP_R_LIST, - FTP_S_TYPE, // send TYPE to indicate what type of file will be transfered - FTP_R_TYPE, + FTP_S_USER, FTP_R_USER, + FTP_S_PASS, FTP_R_PASS, + FTP_S_SYST, FTP_R_SYST, + FTP_S_ACCT, FTP_R_ACCT, + FTP_S_MACB, FTP_R_MACB, + FTP_S_PWD , FTP_R_PWD , + FTP_S_DEL_FILE, FTP_R_DEL_FILE, + FTP_S_DEL_DIR , FTP_R_DEL_DIR , + FTP_S_MKDIR, FTP_R_MKDIR, + FTP_S_MODE, FTP_R_MODE, + FTP_S_CWD, FTP_R_CWD, + FTP_S_SIZE, FTP_R_SIZE, + FTP_S_PUT, FTP_R_PUT, + FTP_S_RETR, FTP_R_RETR, + FTP_S_MDTM, FTP_R_MDTM, + FTP_S_LIST, FTP_R_LIST, + FTP_S_TYPE, FTP_R_TYPE, /////////////////////// //// Data channel connection setup states -/////////////////////// - FTP_S_PASV, // send passsive - FTP_R_PASV + FTP_S_PASV, FTP_R_PASV } FTP_STATE; // higher level ftp actions -typedef enum _FTP_ACTION { - GET, - PUT, - MKDIR, - DEL -} FTP_ACTION; +typedef enum _FTP_ACTION { GET, PUT, MKDIR, DEL} FTP_ACTION; class nsFtpConnectionThread : public nsIRunnable, - public nsIRequest { + public nsIRequest, + public nsIStreamObserver { public: NS_DECL_ISUPPORTS NS_DECL_NSIRUNNABLE NS_DECL_NSIREQUEST + NS_DECL_NSISTREAMOBSERVER nsFtpConnectionThread(); virtual ~nsFtpConnectionThread(); nsresult Init(nsIProtocolHandler *aHandler, nsIChannel *aChannel, - nsISupports *aContext, PRUint32 bufferSegmentSize, PRUint32 bufferMaxSize); - nsresult Process(); - - // use this to have data written to an output stream (OpenInputStream) - nsresult SetOutputStream(nsIBufferOutputStream *aOutputStream); - // use this to set an observer. (as in the asyncopen case) nsresult SetStreamObserver(nsIStreamObserver *aObserver, nsISupports *aContext); // use this to set a listener to receive data related On*() notifications - nsresult SetStreamListener(nsIStreamListener *aListener); + nsresult SetStreamListener(nsIStreamListener *aListener, nsISupports *aContext=nsnull); // user level setup nsresult SetAction(FTP_ACTION aAction); + private: + /////////////////////////////////// + // BEGIN: STATE METHODS + nsresult S_user(); FTP_STATE R_user(); + nsresult S_pass(); FTP_STATE R_pass(); + nsresult S_syst(); FTP_STATE R_syst(); + nsresult S_acct(); FTP_STATE R_acct(); - /////////////////////////////////// - // STATE METHODS - /////////////////////////////////// - nsresult S_user(); - FTP_STATE R_user(); - nsresult S_pass(); - FTP_STATE R_pass(); - nsresult S_syst(); - FTP_STATE R_syst(); - nsresult S_acct(); - FTP_STATE R_acct(); - nsresult S_macb(); - FTP_STATE R_macb(); - nsresult S_pwd(); - FTP_STATE R_pwd(); - nsresult S_mode(); - FTP_STATE R_mode(); - nsresult S_cwd(); - FTP_STATE R_cwd(); - nsresult S_size(); - FTP_STATE R_size(); - nsresult S_mdtm(); - FTP_STATE R_mdtm(); - nsresult S_list(); - FTP_STATE R_list(); - nsresult S_retr(); - FTP_STATE R_retr(); + nsresult S_macb(); FTP_STATE R_macb(); + nsresult S_pwd(); FTP_STATE R_pwd(); + nsresult S_mode(); FTP_STATE R_mode(); + nsresult S_cwd(); FTP_STATE R_cwd(); - nsresult S_pasv(); - FTP_STATE R_pasv(); - nsresult S_del_file(); - FTP_STATE R_del_file(); - nsresult S_del_dir(); - FTP_STATE R_del_dir(); - nsresult S_mkdir(); - FTP_STATE R_mkdir(); - /////////////////////////////////// + nsresult S_size(); FTP_STATE R_size(); + nsresult S_mdtm(); FTP_STATE R_mdtm(); + nsresult S_list(); FTP_STATE R_list(); + + nsresult S_retr(); FTP_STATE R_retr(); + nsresult S_pasv(); FTP_STATE R_pasv(); + nsresult S_del_file(); FTP_STATE R_del_file(); + nsresult S_del_dir(); FTP_STATE R_del_dir(); + + nsresult S_mkdir(); FTP_STATE R_mkdir(); // END: STATE METHODS /////////////////////////////////// - nsresult StopProcessing(); - void SetSystInternals(void); - FTP_STATE FindActionState(void); - FTP_STATE FindGetState(void); - nsresult MapResultCodeToString(nsresult aResultCode, PRUnichar* *aOutMsg); - void SetDirMIMEType(nsString& aString); + // internal methods + nsresult StopProcessing(); + void SetSystInternals(void); + FTP_STATE FindActionState(void); + FTP_STATE FindGetState(void); + nsresult MapResultCodeToString(nsresult aResultCode, PRUnichar* *aOutMsg); + void SetDirMIMEType(nsString& aString); + nsresult DigestServerGreeting(); + nsresult Process(); + /////////////////////////////////// // Private members - nsCOMPtr mFTPEventQueue; // the eventq for this thread. - nsCOMPtr mURL; - PRInt32 mPort; // the port to connect to - + // ****** state machine vars FTP_STATE mState; // the current state FTP_STATE mNextState; // the next state - FTP_ACTION mAction; // the higher level action (GET/PUT) - - nsISocketTransportService *mSTS; // the socket transport service; - - nsCOMPtr mCPipe; // the command channel transport - nsCOMPtr mDPipe; // the data channel transport - - nsCOMPtr mCOutStream; // command channel output - nsCOMPtr mCInStream; // command channel input - - nsCOMPtr mDOutStream; // data channel output - nsCOMPtr mDInStream; // data channel input - - PRInt32 mResponseCode; // the last command response code. + PRBool mKeepRunning; // thread event loop boolean + PRInt32 mResponseCode; // the last command response code nsCAutoString mResponseMsg; // the last command response text - nsString2 mUsername; - nsString2 mPassword; - nsString2 mFilename; // url filename (if any) - PRInt32 mLength; // length of the file - PRTime mLastModified; // last modified time for file + nsCOMPtr mFTPEventQueue; // the eventq for this thread -// these members should be hung off of a specific transport connection - PRInt32 mServerType; - PRBool mPasv; - PRBool mList; // use LIST instead of NLST - nsCAutoString mCwd; // Our current working dir. - nsCAutoString mCwdAttempt; // the dir we're trying to get into. -// end "these ...." + // ****** channel/transport/stream vars + nsCOMPtr mSTS; // the socket transport service + nsCOMPtr mCPipe; // the command channel transport + nsCOMPtr mDPipe; // the data channel transport + nsCOMPtr mCOutStream; // command channel output + nsCOMPtr mCInStream; // command channel input - nsCAutoString mCacheKey; // the key into the cache hash. + // ****** consumer vars + nsCOMPtr mListener; // the consumer of our read events + nsCOMPtr mListenerContext; // the context we pass through our read events + nsCOMPtr mObserver; // the consumer of our open events + nsCOMPtr mObserverContext; // the context we pass through our open events + nsCOMPtr mChannel; // our owning FTP channel we pass through our events - PRBool mConnected; - PRBool mUsePasv; // use a passive data connection. - PRBool mDirectory; // this url is a directory - PRBool mBin; // transfer mode (ascii or binary) - PRBool mContinueRead; // continue digesting a multi-line reponse - PRBool mResetMode; // have we reset the mode to ascii - PRBool mAnonymous; // try connecting anonymous (default) - PRBool mRetryPass; // retrying the password - PRBool mCachedConn; // is this connection from the cache - PRBool mSentStart; // have we sent an OnStartRequest() notification - PRUint8 mSuspendCount; - nsresult mInternalError; // represents internal state errors + // ****** connection cache vars + PRInt32 mServerType; // What kind of server are we talking to + PRBool mPasv; // Should we use PASV for data channel + PRBool mList; // Use LIST instead of NLST + nsCAutoString mCwd; // Our current working dir. + nsCAutoString mCwdAttempt; // The dir we're trying to get into. + nsCAutoString mCacheKey; // the key into the cache hash. + PRBool mCachedConn; // is this connection from the cache + nsCOMPtr mConnCache;// the nsISupports proxy ptr to our connection cache + nsConnectionCacheObj *mConn; // The cached connection. - nsCOMPtr mListener; // the listener we want to call - // during our event firing. - nsCOMPtr mSyncListener; // a syncronous version of our listener - nsCOMPtr mChannel; - nsCOMPtr mContext; - nsCOMPtr mConnCache; // the nsISupports proxy ptr to the FTP proto handler - nsConnectionCacheObj* mConn; // The cached connection. - PRBool mKeepRunning; // thread event loop boolean + // ****** protocol interpretation related state vars + nsAutoString mUsername; // username + nsAutoString mPassword; // password + FTP_ACTION mAction; // the higher level action (GET/PUT) + PRBool mUsePasv; // use a passive data connection. + PRBool mBin; // transfer mode (ascii or binary) + PRBool mResetMode; // have we reset the mode to ascii + PRBool mAnonymous; // try connecting anonymous (default) + PRBool mRetryPass; // retrying the password + nsresult mInternalError; // represents internal state errors - nsString2 mContentType; // the content type of the data we're dealing w/. - nsXPIDLCString mURLSpec; - nsCOMPtr mFTPChannel; + // ****** URI vars + nsCOMPtr mURL; // the uri we're connecting to + nsXPIDLCString mURLSpec; // raw spec of the url + PRInt32 mPort; // the port to connect to + nsAutoString mFilename; // url filename (if any) + PRInt32 mLength; // length of the file + PRTime mLastModified;// last modified time for file - nsCOMPtr mBufInStream; - nsCOMPtr mBufOutStream; - nsCOMPtr mCallerOutputStream; - - nsCOMPtr mObserver; - nsCOMPtr mObserverContext; - PRUint32 mBufferSegmentSize; - PRUint32 mBufferMaxSize; + // ****** other vars + PRBool mConnected; // are we connected. + PRBool mSentStart; // have we sent an OnStartRequest() notification + PRUint8 mSuspendCount;// number of times we've been suspended. + nsCOMPtr mFTPChannel;// used to synchronize w/ our owning channel. + PRUint32 mBufferSegmentSize; + PRUint32 mBufferMaxSize; + PRLock *mLock; + PRMonitor *mMonitor; + nsCOMPtrmUIEventQ; + PLEvent *mAsyncReadEvent; }; #define NS_FTP_BUFFER_READ_SIZE (8*1024) diff --git a/mozilla/netwerk/protocol/ftp/src/nsFtpModule.cpp b/mozilla/netwerk/protocol/ftp/src/nsFtpModule.cpp index 6c40aed43aa..ccd02efb755 100644 --- a/mozilla/netwerk/protocol/ftp/src/nsFtpModule.cpp +++ b/mozilla/netwerk/protocol/ftp/src/nsFtpModule.cpp @@ -19,226 +19,16 @@ * * Contributor(s): */ -#include "nsCOMPtr.h" -#include "nsIModule.h" + #include "nsIGenericFactory.h" -#include "nsIComponentManager.h" -#include "nsIServiceManager.h" #include "nsFtpProtocolHandler.h" -#include "nscore.h" -static NS_DEFINE_CID(kFtpProtocolHandlerCID, NS_FTPPROTOCOLHANDLER_CID); - -/////////////////////////////////////////////////////////////////////////////// - -class nsFTPModule : public nsIModule -{ -public: - nsFTPModule(); - virtual ~nsFTPModule(); - - NS_DECL_ISUPPORTS - - NS_DECL_NSIMODULE - -protected: - nsresult Initialize(); - - void Shutdown(); - - PRBool mInitialized; - nsCOMPtr mFactory; +static nsModuleComponentInfo gResComponents[] = { + { "The FTP Protocol Handler", + NS_FTPPROTOCOLHANDLER_CID, + NS_NETWORK_PROTOCOL_PROGID_PREFIX "ftp", + nsFtpProtocolHandler::Create + } }; -static NS_DEFINE_IID(kIModuleIID, NS_IMODULE_IID); - -nsFTPModule::nsFTPModule() - : mInitialized(PR_FALSE) -{ - NS_INIT_ISUPPORTS(); -} - -nsFTPModule::~nsFTPModule() -{ - Shutdown(); -} - -NS_IMPL_ISUPPORTS(nsFTPModule, kIModuleIID) - -// Perform our one-time intialization for this module -nsresult -nsFTPModule::Initialize() -{ - if (mInitialized) { - return NS_OK; - } - mInitialized = PR_TRUE; - return NS_OK; -} - -// Shutdown this module, releasing all of the module resources -void -nsFTPModule::Shutdown() -{ - // Release the factory object - mFactory = nsnull; -} - -// Create a factory object for creating instances of aClass. -NS_IMETHODIMP -nsFTPModule::GetClassObject(nsIComponentManager *aCompMgr, - const nsCID& aClass, - const nsIID& aIID, - void** r_classObj) -{ - nsresult rv; - - // Defensive programming: Initialize *r_classObj in case of error below - if (!r_classObj) { - return NS_ERROR_INVALID_POINTER; - } - *r_classObj = NULL; - - // Do one-time-only initialization if necessary - if (!mInitialized) { - rv = Initialize(); - if (NS_FAILED(rv)) { - // Initialization failed! yikes! - return rv; - } - } - - // Choose the appropriate factory, based on the desired instance - // class type (aClass). - nsCOMPtr fact; - if (aClass.Equals(kFtpProtocolHandlerCID)) { - if (!mFactory) { - rv = NS_NewGenericFactory(getter_AddRefs(mFactory), - nsFtpProtocolHandler::Create); - } - fact = mFactory; - } - else { - rv = NS_ERROR_FACTORY_NOT_REGISTERED; -#ifdef DEBUG - char* cs = aClass.ToString(); - printf("+++ nsFTPModule: unable to create factory for %s\n", cs); - nsCRT::free(cs); -#endif - } - - if (fact) { - rv = fact->QueryInterface(aIID, r_classObj); - } - - return rv; -} - -//---------------------------------------- - -struct Components { - const char* mDescription; - const nsID* mCID; - const char* mProgID; -}; - -// The list of components we register -static Components gComponents[] = { - { "FTP Protocol Handler", &kFtpProtocolHandlerCID, - NS_NETWORK_PROTOCOL_PROGID_PREFIX "ftp", }, -}; -#define NUM_COMPONENTS (sizeof(gComponents) / sizeof(gComponents[0])) - -NS_IMETHODIMP -nsFTPModule::RegisterSelf(nsIComponentManager *aCompMgr, - nsIFileSpec* aPath, - const char* registryLocation, - const char* componentType) -{ - nsresult rv = NS_OK; - -#ifdef DEBUG - printf("*** Registering ftp: components\n"); -#endif - - Components* cp = gComponents; - Components* end = cp + NUM_COMPONENTS; - while (cp < end) { - rv = aCompMgr->RegisterComponentSpec(*cp->mCID, cp->mDescription, - cp->mProgID, aPath, PR_TRUE, - PR_TRUE); - if (NS_FAILED(rv)) { -#ifdef DEBUG - printf("nsFTPModule: unable to register %s component => %x\n", - cp->mDescription, rv); -#endif - break; - } - cp++; - } - - return rv; -} - -NS_IMETHODIMP -nsFTPModule::UnregisterSelf(nsIComponentManager* aCompMgr, - nsIFileSpec* aPath, - const char* registryLocation) -{ -#ifdef DEBUG - printf("*** Unregistering ftp: components\n"); -#endif - Components* cp = gComponents; - Components* end = cp + NUM_COMPONENTS; - while (cp < end) { - nsresult rv = aCompMgr->UnregisterComponentSpec(*cp->mCID, aPath); - if (NS_FAILED(rv)) { -#ifdef DEBUG - printf("nsFTPModule: unable to unregister %s component => %x\n", - cp->mDescription, rv); -#endif - } - cp++; - } - - return NS_OK; -} - -NS_IMETHODIMP -nsFTPModule::CanUnload(nsIComponentManager *aCompMgr, PRBool *okToUnload) -{ - if (!okToUnload) { - return NS_ERROR_INVALID_POINTER; - } - *okToUnload = PR_FALSE; - return NS_ERROR_FAILURE; -} - -//---------------------------------------------------------------------- - -static nsFTPModule *gModule = NULL; - -extern "C" NS_EXPORT nsresult NSGetModule(nsIComponentManager *servMgr, - nsIFileSpec* location, - nsIModule** return_cobj) -{ - nsresult rv = NS_OK; - - NS_ASSERTION(return_cobj, "Null argument"); - NS_ASSERTION(gModule == NULL, "nsFTPModule: Module already created."); - - // Create and initialize the module instance - nsFTPModule *m = new nsFTPModule(); - if (!m) { - return NS_ERROR_OUT_OF_MEMORY; - } - - // Increase refcnt and store away nsIModule interface to m in return_cobj - rv = m->QueryInterface(NS_GET_IID(nsIModule), (void**)return_cobj); - if (NS_FAILED(rv)) { - delete m; - m = nsnull; - } - gModule = m; // WARNING: Weak Reference - return rv; -} +NS_IMPL_NSGETMODULE("ftp", gResComponents) \ No newline at end of file diff --git a/mozilla/netwerk/protocol/ftp/src/nsFtpProtocolHandler.cpp b/mozilla/netwerk/protocol/ftp/src/nsFtpProtocolHandler.cpp index accae426160..873e733f373 100644 --- a/mozilla/netwerk/protocol/ftp/src/nsFtpProtocolHandler.cpp +++ b/mozilla/netwerk/protocol/ftp/src/nsFtpProtocolHandler.cpp @@ -20,15 +20,15 @@ * Contributor(s): */ -#include "nspr.h" -#include "nsFTPChannel.h" #include "nsFtpProtocolHandler.h" +#include "nsFTPChannel.h" #include "nsIURL.h" #include "nsCRT.h" #include "nsIComponentManager.h" #include "nsIInterfaceRequestor.h" #include "nsIProgressEventSink.h" #include "nsConnectionCacheObj.h" +#include "prlog.h" #if defined(PR_LOGGING) // @@ -58,16 +58,7 @@ nsFtpProtocolHandler::~nsFtpProtocolHandler() { PR_LOG(gFTPLog, PR_LOG_ALWAYS, ("~nsFtpProtocolHandler() called")); } -NS_IMPL_ADDREF(nsFtpProtocolHandler) -NS_IMPL_RELEASE(nsFtpProtocolHandler) - -NS_INTERFACE_MAP_BEGIN(nsFtpProtocolHandler) - NS_INTERFACE_MAP_ENTRY(nsIProtocolHandler) - NS_INTERFACE_MAP_ENTRY(nsIConnectionCache) - NS_INTERFACE_MAP_ENTRY(nsIObserver) - NS_INTERFACE_MAP_ENTRY(nsISupportsWeakReference) - NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsISupports, nsIProtocolHandler) -NS_INTERFACE_MAP_END +NS_IMPL_ISUPPORTS3(nsFtpProtocolHandler, nsIProtocolHandler, nsIConnectionCache, nsIObserver) NS_METHOD nsFtpProtocolHandler::Create(nsISupports* aOuter, const nsIID& aIID, void* *aResult) @@ -209,7 +200,6 @@ nsFtpProtocolHandler::InsertConn(const char *aKey, nsConnectionCacheObj *aConn) // cleans up a connection list entry PRBool CleanupConnEntry(nsHashKey *aKey, void *aData, void *closure) { - // XXX do we need to explicitly close the streams? delete (nsConnectionCacheObj*)aData; return PR_TRUE; } diff --git a/mozilla/netwerk/protocol/ftp/src/nsFtpProtocolHandler.h b/mozilla/netwerk/protocol/ftp/src/nsFtpProtocolHandler.h index d3eccd16f09..cb91c28d0c7 100644 --- a/mozilla/netwerk/protocol/ftp/src/nsFtpProtocolHandler.h +++ b/mozilla/netwerk/protocol/ftp/src/nsFtpProtocolHandler.h @@ -26,13 +26,10 @@ #include "nsIServiceManager.h" #include "nsIProtocolHandler.h" #include "nsHashtable.h" -#include "nsVoidArray.h" #include "nsIConnectionCache.h" #include "nsConnectionCacheObj.h" #include "nsIThreadPool.h" #include "nsIObserverService.h" -#include "nsIObserver.h" -#include "nsWeakReference.h" // {25029490-F132-11d2-9588-00805F369F95} #define NS_FTPPROTOCOLHANDLER_CID \ @@ -40,19 +37,12 @@ class nsFtpProtocolHandler : public nsIProtocolHandler, public nsIConnectionCache, - public nsIObserver, - public nsSupportsWeakReference + public nsIObserver { public: NS_DECL_ISUPPORTS - - // nsIProtocolHandler methods: NS_DECL_NSIPROTOCOLHANDLER - - // nsIConnectionCache methods NS_DECL_NSICONNECTIONCACHE - - // nsIObserver methods NS_DECL_NSIOBSERVER // nsFtpProtocolHandler methods: @@ -60,17 +50,15 @@ public: virtual ~nsFtpProtocolHandler(); // Define a Create method to be used with a factory: - static NS_METHOD - Create(nsISupports* aOuter, const nsIID& aIID, void* *aResult); + static NS_METHOD Create(nsISupports* aOuter, const nsIID& aIID, void* *aResult); nsresult Init(); protected: - nsISupports* mEventSinkGetter; - nsHashtable* mRootConnectionList; // hash of FTP connections - nsCOMPtr mPool; // thread pool for FTP connections + nsHashtable* mRootConnectionList; // hash of FTP connections + nsCOMPtr mPool; // thread pool for FTP connections }; -#define NS_FTP_CONNECTION_COUNT 6 +#define NS_FTP_CONNECTION_COUNT 4 #define NS_FTP_CONNECTION_STACK_SIZE (64 * 1024) #endif /* nsFtpProtocolHandler_h___ */