From 3a4a5695b4c2565f6b12da5489a52b8484de90f4 Mon Sep 17 00:00:00 2001 From: "valeski%netscape.com" Date: Fri, 22 Oct 1999 04:10:46 +0000 Subject: [PATCH] 14659, r=dougt. FTP now uses xpcom proxies to send stream listener notifications back to the channel thread. it also uses them to access connections from the protocol handler cache. --- netwerk/protocol/ftp/public/Makefile.in | 1 + netwerk/protocol/ftp/public/makefile.win | 1 + netwerk/protocol/ftp/src/Makefile.in | 1 - netwerk/protocol/ftp/src/makefile.win | 1 - netwerk/protocol/ftp/src/nsFTPChannel.cpp | 32 +- netwerk/protocol/ftp/src/nsFTPChannel.h | 7 +- .../ftp/src/nsFtpConnectionThread.cpp | 283 +++++++----------- .../protocol/ftp/src/nsFtpConnectionThread.h | 57 +--- .../protocol/ftp/src/nsFtpProtocolHandler.cpp | 43 ++- .../protocol/ftp/src/nsFtpProtocolHandler.h | 9 +- 10 files changed, 173 insertions(+), 262 deletions(-) diff --git a/netwerk/protocol/ftp/public/Makefile.in b/netwerk/protocol/ftp/public/Makefile.in index fe8e50dd2258..7d484b1c5733 100644 --- a/netwerk/protocol/ftp/public/Makefile.in +++ b/netwerk/protocol/ftp/public/Makefile.in @@ -28,6 +28,7 @@ XPIDL_MODULE = necko_ftp XPIDLSRCS = \ nsIFTPChannel.idl \ nsIFTPContext.idl \ + nsIConnectionCache.idl \ $(NULL) EXPORTS = ftpCore.h diff --git a/netwerk/protocol/ftp/public/makefile.win b/netwerk/protocol/ftp/public/makefile.win index b5a4357ba79a..b057d9d49a9b 100644 --- a/netwerk/protocol/ftp/public/makefile.win +++ b/netwerk/protocol/ftp/public/makefile.win @@ -25,6 +25,7 @@ XPIDL_MODULE = necko_ftp XPIDLSRCS = \ .\nsIFTPChannel.idl \ .\nsIFTPContext.idl \ + .\nsIConnectionCache.idl \ $(NULL) EXPORTS = \ diff --git a/netwerk/protocol/ftp/src/Makefile.in b/netwerk/protocol/ftp/src/Makefile.in index 9781e7aab8a0..5b0a9c5bfb6d 100644 --- a/netwerk/protocol/ftp/src/Makefile.in +++ b/netwerk/protocol/ftp/src/Makefile.in @@ -29,7 +29,6 @@ IS_COMPONENT = 1 CPPSRCS = \ nsFtpProtocolHandler.cpp \ nsFTPChannel.cpp \ - nsFtpStreamListenerEvent.cpp \ nsFtpConnectionThread.cpp \ nsFtpModule.cpp \ $(NULL) diff --git a/netwerk/protocol/ftp/src/makefile.win b/netwerk/protocol/ftp/src/makefile.win index 09c61a849fa0..854d2068e9d1 100644 --- a/netwerk/protocol/ftp/src/makefile.win +++ b/netwerk/protocol/ftp/src/makefile.win @@ -26,7 +26,6 @@ LCFLAGS = -DWIN32_LEAN_AND_MEAN -D_IMPL_NS_NET CPP_OBJS = \ .\$(OBJDIR)\nsFtpProtocolHandler.obj \ .\$(OBJDIR)\nsFTPChannel.obj \ - .\$(OBJDIR)\nsFtpStreamListenerEvent.obj \ .\$(OBJDIR)\nsFtpConnectionThread.obj \ .\$(OBJDIR)\nsFtpModule.obj \ $(NULL) diff --git a/netwerk/protocol/ftp/src/nsFTPChannel.cpp b/netwerk/protocol/ftp/src/nsFTPChannel.cpp index d06e86941b5d..f7c71d00f0db 100644 --- a/netwerk/protocol/ftp/src/nsFTPChannel.cpp +++ b/netwerk/protocol/ftp/src/nsFTPChannel.cpp @@ -20,6 +20,7 @@ #include "nsFTPChannel.h" #include "nscore.h" +#include "prlog.h" #include "nsCOMPtr.h" #include "nsIServiceManager.h" #include "nsIBufferInputStream.h" @@ -70,6 +71,7 @@ nsFTPChannel::nsFTPChannel() { mContentLength = -1; mThreadRequest = nsnull; mConnectionEventQueue = nsnull; + mHandler = nsnull; } nsFTPChannel::~nsFTPChannel() { @@ -82,19 +84,19 @@ nsFTPChannel::~nsFTPChannel() { NS_IF_RELEASE(mThreadRequest); NS_IF_RELEASE(mBufferInputStream); NS_IF_RELEASE(mBufferOutputStream); + NS_IF_RELEASE(mHandler); } NS_IMPL_ISUPPORTS4(nsFTPChannel, nsIChannel, nsIFTPChannel, nsIStreamListener, nsIStreamObserver); nsresult nsFTPChannel::Init(const char* verb, nsIURI* uri, nsILoadGroup *aGroup, - nsIEventSinkGetter* getter, nsHashtable *aConnectionList, - nsIThread **_retval) + nsIEventSinkGetter* getter, nsIProtocolHandler* aHandler) { nsresult rv; - NS_ASSERTION(aConnectionList, "FTP needs a connection list"); - mConnectionList = aConnectionList; + mHandler = aHandler; + NS_ADDREF(mHandler); if (mConnected) return NS_ERROR_FAILURE; @@ -130,16 +132,14 @@ nsFTPChannel::Init(const char* verb, nsIURI* uri, nsILoadGroup *aGroup, // go ahead and create the thread for the connection. // we'll init it and kick it off later - rv = NS_NewThread(&mConnectionThread, 0, PR_JOINABLE_THREAD); + rv = NS_NewThread(&mConnectionThread); if (NS_FAILED(rv)) return rv; - *_retval = mConnectionThread; - NS_ADDREF(*_retval); -#if 1 // we'll create the FTP connection's event queue here, on this thread. // it will be passed to the FTP connection upon FTP connection // initialization. at that point it's up to the FTP conn thread to // turn the crank on it. +#if 1 PRThread *thread; // does not need deleting rv = mConnectionThread->GetPRThread(&thread); if (NS_FAILED(rv)) return rv; @@ -148,15 +148,11 @@ nsFTPChannel::Init(const char* verb, nsIURI* uri, nsILoadGroup *aGroup, if (!PLEventQ) return rv; rv = eventQService->CreateFromPLEventQueue(PLEventQ, &mConnectionEventQueue); - if (NS_FAILED(rv)) return rv; #else rv = eventQService->CreateFromIThread(mConnectionThread, &mConnectionEventQueue); - if (NS_FAILED(rv)) return rv; #endif - - - return NS_OK; + return rv; } NS_METHOD @@ -330,8 +326,8 @@ nsFTPChannel::AsyncRead(PRUint32 startPosition, PRInt32 readCount, rv = protocolInterpreter->Init(mConnectionEventQueue, /* FTP thread queue */ mUrl, /* url to load */ mEventQueue, /* event queue for this thread */ - this, this, ctxt, - mConnectionList /* list of cached connections */); + mHandler, + this, ctxt); if (NS_FAILED(rv)) return rv; // create the proxy object so we can call into the FTP thread. @@ -494,7 +490,7 @@ nsFTPChannel::OnStartRequest(nsIChannel* channel, nsISupports* context) { nsresult rv = NS_OK; PR_LOG(gFTPLog, PR_LOG_DEBUG, ("nsFTPChannel::OnStartRequest(channel = %x, context = %x)\n", channel, context)); if (mListener) { - rv = mListener->OnStartRequest(channel, context); + rv = mListener->OnStartRequest(channel, mContext); } return rv; } @@ -506,7 +502,7 @@ nsFTPChannel::OnStopRequest(nsIChannel* channel, nsISupports* context, nsresult rv = NS_OK; PR_LOG(gFTPLog, PR_LOG_DEBUG, ("nsFTPChannel::OnStopRequest(channel = %x, context = %x, status = %d, msg = N/A)\n",channel, context, aStatus)); if (mListener) { - rv = mListener->OnStopRequest(channel, context, aStatus, aMsg); + rv = mListener->OnStopRequest(channel, mContext, aStatus, aMsg); } // release the proxy object to the thread. @@ -546,7 +542,7 @@ nsFTPChannel::OnDataAvailable(nsIChannel* channel, nsISupports* context, } if (mListener) { - rv = mListener->OnDataAvailable(channel, context, aIStream, aSourceOffset, aLength); + rv = mListener->OnDataAvailable(channel, mContext, aIStream, aSourceOffset, aLength); } return rv; } diff --git a/netwerk/protocol/ftp/src/nsFTPChannel.h b/netwerk/protocol/ftp/src/nsFTPChannel.h index da58e2c46bf1..86ff5d18cba3 100644 --- a/netwerk/protocol/ftp/src/nsFTPChannel.h +++ b/netwerk/protocol/ftp/src/nsFTPChannel.h @@ -32,6 +32,7 @@ #include "nsILoadGroup.h" #include "nsCOMPtr.h" #include "nsHashtable.h" +#include "nsIProtocolHandler.h" class nsIEventSinkGetter; class nsIProgressEventSink; @@ -58,8 +59,8 @@ public: // and returns it so the protocol handler can cache it and // join() it on shutdown. nsresult Init(const char* verb, nsIURI* uri, nsILoadGroup *aGroup, - nsIEventSinkGetter* getter, nsHashtable *aConnectionList, - nsIThread **_retval); + nsIEventSinkGetter* getter, + nsIProtocolHandler* aHandler); protected: nsIURI* mUrl; @@ -79,11 +80,11 @@ protected: nsAutoString mContentType; PRInt32 mContentLength; nsCOMPtr mOwner; - nsHashtable* mConnectionList; // thread safe list of connections. nsIThread* mConnectionThread; // the thread for this connection. nsIEventQueue* mConnectionEventQueue; nsIRequest* mThreadRequest; // the nsIRequest proxy object. + nsIProtocolHandler* mHandler; }; #define NS_FTP_SEGMENT_SIZE (4*1024) diff --git a/netwerk/protocol/ftp/src/nsFtpConnectionThread.cpp b/netwerk/protocol/ftp/src/nsFtpConnectionThread.cpp index c08664c161f4..46350d8e770a 100644 --- a/netwerk/protocol/ftp/src/nsFtpConnectionThread.cpp +++ b/netwerk/protocol/ftp/src/nsFtpConnectionThread.cpp @@ -1,4 +1,4 @@ -/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 4 -*- +/* -*- Mode: C++; tab-width: 4; 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 @@ -17,7 +17,7 @@ */ #include "nsFtpConnectionThread.h" -#include "nsFtpStreamListenerEvent.h" // the various events we fire off to the +//#include "nsFtpStreamListenerEvent.h" // the various events we fire off to the // owning thread. #include "nsCOMPtr.h" #include "nsIChannel.h" @@ -34,11 +34,13 @@ #include "nsIStreamConverterService.h" #include "nsIIOService.h" #include "prprf.h" +#include "prlog.h" #include "netCore.h" #include "ftpCore.h" #include "nsIPrompt.h" #include "nsProxiedService.h" #include "nsINetSupportDialogService.h" +#include "nsFtpProtocolHandler.h" static NS_DEFINE_CID(kIOServiceCID, NS_IOSERVICE_CID); static NS_DEFINE_CID(kStreamConverterServiceCID, NS_STREAMCONVERTERSERVICE_CID); @@ -46,6 +48,8 @@ static NS_DEFINE_CID(kMIMEServiceCID, NS_MIMESERVICE_CID); static NS_DEFINE_CID(kEventQueueServiceCID, NS_EVENTQUEUESERVICE_CID); static NS_DEFINE_IID(kNetSupportDialogCID, NS_NETSUPPORTDIALOG_CID); static NS_DEFINE_CID(kSocketTransportServiceCID, NS_SOCKETTRANSPORTSERVICE_CID); +static NS_DEFINE_CID(kFTPHandlerCID, NS_FTPPROTOCOLHANDLER_CID); +static NS_DEFINE_IID(kProxyObjectManagerCID, NS_PROXYEVENT_MANAGER_CID); static NS_DEFINE_IID(kIFTPContextIID, NS_IFTPCONTEXT_IID); #define FTP_CRLF "\r\n" @@ -107,9 +111,10 @@ NS_IMPL_ISUPPORTS2(nsFtpConnectionThread, nsIRunnable, nsIRequest); nsFtpConnectionThread::nsFtpConnectionThread() { NS_INIT_REFCNT(); - mConnectionList = nsnull; + mHandler = nsnull; mEventQueue = nsnull; mListener = nsnull; + mSyncListener = nsnull; mAction = GET; mUsePasv = PR_TRUE; mState = FTP_S_USER; @@ -128,28 +133,29 @@ nsFtpConnectionThread::nsFtpConnectionThread() { mAnonymous = PR_TRUE; mRetryPass = PR_FALSE; mCachedConn = PR_FALSE; - mCacheLock = nsnull; - mCacheKey = nsnull; mInternalError = NS_OK; // start out on the up 'n up. mSentStart = PR_FALSE; mFTPContext = nsnull; mCPipe = nsnull; mDPipe = nsnull; + mConn = nsnull; + mConnCache = nsnull; } nsFtpConnectionThread::~nsFtpConnectionThread() { NS_RELEASE(mListener); + NS_RELEASE(mSyncListener); NS_RELEASE(mChannel); NS_IF_RELEASE(mContext); NS_IF_RELEASE(mEventQueue); NS_RELEASE(mFTPContext); + NS_RELEASE(mUrl); // lose the socket transport NS_RELEASE(mSTS); + NS_IF_RELEASE(mHandler); nsAllocator::Free(mURLSpec); - PR_DestroyLock(mCacheLock); - if (mCacheKey) delete mCacheKey; } nsresult @@ -252,13 +258,12 @@ nsFtpConnectionThread::Process() { case FTP_ERROR: { PR_LOG(gFTPLog, PR_LOG_DEBUG, ("%x Process() - ERROR\n", mUrl)); - // if something went wrong, remove this connection from the cache. - PR_Lock(mCacheLock); - nsConnCacheObj *conn = (nsConnCacheObj*)mConnectionList->Remove(mCacheKey); - if (conn) { - delete conn; - } - PR_Unlock(mCacheLock); + + // if something went wrong, delete this connection entry and don't + // bother putting it in the cache. + NS_ASSERTION(mConn, "we should have created the conn obj upon Init()"); + delete mConn; + rv = StopProcessing(); break; } @@ -268,13 +273,11 @@ nsFtpConnectionThread::Process() { { PR_LOG(gFTPLog, PR_LOG_DEBUG, ("%x Process() - COMPLETE\n", mUrl)); // push through all of the pertinent state into the cache entry; - PR_Lock(mCacheLock); - nsConnCacheObj *conn = (nsConnCacheObj*)mConnectionList->Get(mCacheKey); - NS_ASSERTION(conn, "we better have an entry. if not someone removed it from another thread"); + mConn->mCwd = mCwd; + mConn->mUseDefaultPath = mUseDefaultPath; + rv = mConnCache->InsertConn(mCacheKey.GetBuffer(), mConn); + if (NS_FAILED(rv)) return rv; - conn->mCwd = mCwd; - conn->mUseDefaultPath = mUseDefaultPath; - PR_Unlock(mCacheLock); rv = StopProcessing(); break; } @@ -578,6 +581,7 @@ nsFtpConnectionThread::Process() { mInternalError = NS_ERROR_FAILURE; mNextState = FTP_COMPLETE; mDInStream->Close(); + NS_RELEASE(mDInStream); break; } // END: FTP_R_LIST @@ -615,6 +619,7 @@ nsFtpConnectionThread::Process() { mInternalError = NS_ERROR_FAILURE; mNextState = FTP_COMPLETE; mDInStream->Close(); + NS_RELEASE(mDInStream); break; } // END: FTP_R_RETR @@ -1300,24 +1305,14 @@ nsFtpConnectionThread::R_list() { rv = StreamConvService->AsyncConvertData(fromStr.GetUnicode(), toStr.GetUnicode(), - mListener, mUrl, &converterListener); + mSyncListener, mUrl, &converterListener); if (NS_FAILED(rv)) { return FTP_ERROR; } - // tell the user that we've begun the transaction. - nsFtpOnStartRequestEvent* startEvent = new nsFtpOnStartRequestEvent(converterListener, mChannel, mContext); - if (!startEvent) { - NS_RELEASE(converterListener); - return FTP_ERROR; - } + rv = converterListener->OnStartRequest(mChannel, mContext); + if (NS_FAILED(rv)) return FTP_ERROR; - rv = startEvent->Fire(mEventQueue); - if (NS_FAILED(rv)) { - NS_RELEASE(converterListener); - delete startEvent; - return FTP_ERROR; - } mSentStart = PR_TRUE; @@ -1347,28 +1342,23 @@ nsFtpConnectionThread::R_list() { listBuf[read] = '\0'; PR_LOG(gFTPLog, PR_LOG_DEBUG, ("%x R_list() data pipe read %d bytes:\n%s\n", mUrl, read, listBuf)); - - // send data off - nsFtpListOnDataAvailableEvent* availEvent = - new nsFtpListOnDataAvailableEvent(converterListener, mChannel, mContext); - if (!availEvent) { + + nsISupports *stringStrmSup = nsnull; + rv = NS_NewCharInputStream(&stringStrmSup, listBuf); // char streams keep ref to buffer + if (NS_FAILED(rv)) { NS_RELEASE(converterListener); return FTP_ERROR; } - rv = availEvent->Init(0, read, listBuf); - nsAllocator::Free(listBuf); // we've passed the data on, we can delete our mem for it. - listBuf = nsnull; - + nsCOMPtr listStream = do_QueryInterface(stringStrmSup, &rv); + NS_RELEASE(stringStrmSup); if (NS_FAILED(rv)) { - delete availEvent; NS_RELEASE(converterListener); return FTP_ERROR; } - rv = availEvent->Fire(mEventQueue); + rv = converterListener->OnDataAvailable(mChannel, mFTPContext, listStream, 0, read); if (NS_FAILED(rv)) { - delete availEvent; NS_RELEASE(converterListener); return FTP_ERROR; } @@ -1416,16 +1406,9 @@ nsFtpConnectionThread::R_retr() { if (mResponseCode == 1) { // success. - // tell the user that we've begun the transaction. - nsFtpOnStartRequestEvent* startEvent = - new nsFtpOnStartRequestEvent(mListener, mChannel, mContext); - if (!startEvent) return FTP_ERROR; + rv = mListener->OnStartRequest(mChannel, mContext); + if (NS_FAILED(rv)) return FTP_ERROR; - rv = startEvent->Fire(mEventQueue); - if (NS_FAILED(rv)) { - delete startEvent; - return FTP_ERROR; - } mSentStart = PR_TRUE; // build up context info for the nsFTPChannel @@ -1465,40 +1448,17 @@ nsFtpConnectionThread::R_retr() { readSoFar += read; if (read == 0) { // we've exhausted the stream, send any data we have left and get out of dodge. - nsFtpOnDataAvailableEvent* event = new nsFtpOnDataAvailableEvent(mListener, mChannel, ctxtSup); - if (!event) return FTP_ERROR; + rv = mListener->OnDataAvailable(mChannel, mFTPContext, inStream, avail, readSoFar); + if (NS_FAILED(rv)) return FTP_ERROR; - rv = event->Init(inStream, avail, readSoFar); - if (NS_FAILED(rv)) { - delete event; - return FTP_ERROR; - } - - rv = event->Fire(mEventQueue); - if (NS_FAILED(rv)) { - delete event; - return FTP_ERROR; - } break; // this terminates the loop } if (readSoFar == NS_FTP_BUFFER_READ_SIZE) { // we've filled our buffer, send the data off readSoFar = 0; - nsFtpOnDataAvailableEvent* event = new nsFtpOnDataAvailableEvent(mListener, mChannel, ctxtSup); - if (!event) return FTP_ERROR; - - rv = event->Init(inStream, avail, NS_FTP_BUFFER_READ_SIZE); - if (NS_FAILED(rv)) { - delete event; - return FTP_ERROR; - } - - rv = event->Fire(mEventQueue); - if (NS_FAILED(rv)) { - delete event; - return FTP_ERROR; - } + rv = mListener->OnDataAvailable(mChannel, mContext, inStream, avail, NS_FTP_BUFFER_READ_SIZE); + if (NS_FAILED(rv)) return FTP_ERROR; } } @@ -1594,6 +1554,8 @@ nsFtpConnectionThread::R_pasv() { host.Append("."); host.Append(h3); + nsAllocator::Free(response); + // now we know where to connect our data channel rv = mSTS->CreateTransport(host.GetBuffer(), port, nsnull, &mDPipe); // the data channel if (NS_FAILED(rv)) return FTP_ERROR; @@ -1724,9 +1686,6 @@ NS_IMETHODIMP nsFtpConnectionThread::Run() { nsresult rv; - mCacheLock = PR_NewLock(); - if (!mCacheLock) return NS_ERROR_OUT_OF_MEMORY; - rv = nsServiceManager::GetService(kSocketTransportServiceCID, NS_GET_IID(nsISocketTransportService), (nsISupports **)&mSTS); @@ -1742,56 +1701,43 @@ nsFtpConnectionThread::Run() { rv = mUrl->GetPort(&port); if (NS_FAILED(rv)) return rv; - PR_Lock(mCacheLock); - nsConnCacheObj *conn = (nsConnCacheObj*)mConnectionList->Get(mCacheKey); - if (conn) { + // use a cached connection if there is one. + rv = mConnCache->RemoveConn(mCacheKey.GetBuffer(), &mConn); + if (NS_FAILED(rv)) return rv; + + if (mConn) { mCachedConn = PR_TRUE; // we were passed in a connection to use - mCPipe = conn->mSocketTransport; + mCPipe = mConn->mSocketTransport; NS_ADDREF(mCPipe); - mCInStream = conn->mInputStream; + mCInStream = mConn->mInputStream; NS_ADDREF(mCInStream); - mCOutStream = conn->mOutputStream; + mCOutStream = mConn->mOutputStream; NS_ADDREF(mCOutStream); - mServerType = conn->mServerType; - mCwd = conn->mCwd; - mList = conn->mList; - mUseDefaultPath = conn->mUseDefaultPath; + mServerType = mConn->mServerType; + mCwd = mConn->mCwd; + mList = mConn->mList; + mUseDefaultPath = mConn->mUseDefaultPath; } else { // build our own rv = mSTS->CreateTransport(host, port, nsnull, &mCPipe); // the command channel nsAllocator::Free(host); - if (NS_FAILED(rv)) { - PR_Unlock(mCacheLock); - return rv; - } + if (NS_FAILED(rv)) return rv; // get the output stream so we can write to the server rv = mCPipe->OpenOutputStream(0, &mCOutStream); - if (NS_FAILED(rv)) { - PR_Unlock(mCacheLock); - return rv; - } + if (NS_FAILED(rv)) return rv; rv = mCPipe->OpenInputStream(0, -1, &mCInStream); - if (NS_FAILED(rv)) { - PR_Unlock(mCacheLock); - return rv; - } + if (NS_FAILED(rv)) return rv; // cache this stuff. - conn = new nsConnCacheObj(mCPipe, mCInStream, mCOutStream); - if (!conn) { - PR_Unlock(mCacheLock); - return NS_ERROR_OUT_OF_MEMORY; - } - - mConnectionList->Put(mCacheKey, conn); + mConn = new nsConnectionCacheObj(mCPipe, mCInStream, mCOutStream); + if (!mConn) return NS_ERROR_OUT_OF_MEMORY; } - PR_Unlock(mCacheLock); /////////////////////////////// // END - COMMAND CHANNEL SETUP @@ -1938,13 +1884,13 @@ nsresult nsFtpConnectionThread::Init(nsIEventQueue* aFTPEventQ, nsIURI* aUrl, nsIEventQueue* aEventQ, - nsIStreamListener* aListener, - nsIChannel* channel, - nsISupports* context, - nsHashtable* aConnectionList) { + nsIProtocolHandler* aHandler, + nsIChannel* aChannel, + nsISupports* aContext) { nsresult rv; - NS_ASSERTION(aConnectionList, "FTP: connection list creation never happened."); - mConnectionList = aConnectionList; + + mHandler = aHandler; + NS_ADDREF(mHandler); NS_ASSERTION(aEventQ, "FTP: thread needs an event queue to post events to"); mEventQueue = aEventQ; @@ -1954,16 +1900,34 @@ nsFtpConnectionThread::Init(nsIEventQueue* aFTPEventQ, mFTPEventQueue = aFTPEventQ; NS_ADDREF(mFTPEventQueue); - NS_ASSERTION(aListener, "FTP: thread needs a listener"); - mListener = aListener; - NS_ADDREF(mListener); + NS_ASSERTION(aChannel, "FTP: thread needs a channel"); - NS_ASSERTION(channel, "FTP: thread needs a channel"); - mChannel = channel; - NS_ADDREF(channel); + NS_WITH_SERVICE(nsIProxyObjectManager, pIProxyObjectManager, kProxyObjectManagerCID, &rv); + if(NS_FAILED(rv)) return rv; - mContext = context; - NS_IF_ADDREF(context); + rv = pIProxyObjectManager->GetProxyObject(mEventQueue, + NS_GET_IID(nsIStreamListener), + aChannel, + PROXY_ASYNC | PROXY_ALWAYS, + (void**)&mListener); + if (NS_FAILED(rv)) return rv; + + rv = pIProxyObjectManager->GetProxyObject(mEventQueue, + NS_GET_IID(nsIStreamListener), + aChannel, + PROXY_SYNC | PROXY_ALWAYS, + (void**)&mSyncListener); + if (NS_FAILED(rv)) return rv; + + rv = pIProxyObjectManager->GetProxyObject(mEventQueue, + NS_GET_IID(nsIChannel), + aChannel, + PROXY_SYNC | PROXY_ALWAYS, + (void**)&mChannel); + if (NS_FAILED(rv)) return rv; + + mContext = aContext; + NS_IF_ADDREF(mContext); mUrl = aUrl; NS_ADDREF(mUrl); @@ -1986,13 +1950,14 @@ nsFtpConnectionThread::Init(nsIEventQueue* aFTPEventQ, } char *host; - mUrl->GetHost(&host); + rv = mUrl->GetHost(&host); + if (NS_FAILED(rv)) return rv; PRInt32 port; - mUrl->GetPort(&port); + rv = mUrl->GetPort(&port); + if (NS_FAILED(rv)) return rv; - nsCAutoString stringKey(host); - stringKey.Append(port); - mCacheKey = new nsStringKey(stringKey); + mCacheKey.SetString(host); + mCacheKey.Append(port); nsAllocator::Free(host); // this context is used to get channel specific info back into the FTP channel @@ -2001,6 +1966,15 @@ nsFtpConnectionThread::Init(nsIEventQueue* aFTPEventQ, rv = dataCtxt->QueryInterface(NS_GET_IID(nsIFTPContext), (void**)&mFTPContext); if (NS_FAILED(rv)) return rv; + // get a proxied ptr to the FTP protocol handler service so we can control + // the connection cache from here. + rv = pIProxyObjectManager->GetProxyObject(nsnull, + NS_GET_IID(nsIConnectionCache), + aHandler, + PROXY_SYNC | PROXY_ALWAYS, + (void**)&mConnCache); + if (NS_FAILED(rv)) return rv; + return NS_OK; } @@ -2023,43 +1997,18 @@ nsFtpConnectionThread::StopProcessing() { // 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) { - nsFtpOnStartRequestEvent* startEvent = - new nsFtpOnStartRequestEvent(mListener, mChannel, mContext); - if (!startEvent) - return NS_ERROR_OUT_OF_MEMORY; - - rv = startEvent->Fire(mEventQueue); - if (NS_FAILED(rv)) { - delete startEvent; - return rv; - } + rv = mListener->OnStartRequest(mChannel, mContext); + if (NS_FAILED(rv)) return rv; } - nsFtpOnStopRequestEvent* event = new nsFtpOnStopRequestEvent(mListener, mChannel, mContext); - if (!event) return NS_ERROR_OUT_OF_MEMORY; - if (NS_FAILED(mInternalError)) { // generate a FTP specific error msg. rv = MapResultCodeToString(mInternalError, &errorMsg); - if (NS_FAILED(rv)) { - delete event; - return rv; - } - // if we failed, pull this connection + if (NS_FAILED(rv)) return rv; } - // propegate the error message and error code. - rv = event->Init(mInternalError, errorMsg); - if (NS_FAILED(rv)) { - delete event; - return rv; - } - - rv = event->Fire(mEventQueue); - if (NS_FAILED(rv)) { - delete event; - return rv; - } + rv = mListener->OnStopRequest(mChannel, mContext, mInternalError, errorMsg); + if (NS_FAILED(rv)) return rv; // after notifying the listener (the FTP channel) of the error, stop processing. mKeepRunning = PR_FALSE; @@ -2106,12 +2055,8 @@ nsFtpConnectionThread::SetSystInternals(void) { mList = PR_TRUE; } - PR_Lock(mCacheLock); - nsConnCacheObj *conn = (nsConnCacheObj*)mConnectionList->Get(mCacheKey); - NS_ASSERTION(conn, "we better have an entry. if not someone removed it from another thread"); - conn->mServerType = mServerType; - conn->mList = mList; - PR_Unlock(mCacheLock); + mConn->mServerType = mServerType; + mConn->mList = mList; } FTP_STATE diff --git a/netwerk/protocol/ftp/src/nsFtpConnectionThread.h b/netwerk/protocol/ftp/src/nsFtpConnectionThread.h index 758d8866646b..4ecd23d16afe 100644 --- a/netwerk/protocol/ftp/src/nsFtpConnectionThread.h +++ b/netwerk/protocol/ftp/src/nsFtpConnectionThread.h @@ -27,50 +27,15 @@ #include "nsIStreamListener.h" #include "nsIOutputStream.h" #include "nsIURI.h" -#include "nsAutoLock.h" #include "prtime.h" #include "nsString2.h" #include "nsIEventQueue.h" #include "nsHashtable.h" #include "nsIChannel.h" #include "nsIFTPContext.h" - -// The cache object string key has the following syntax -// "HostPort" NOTE: no seperators. -class nsConnCacheObj { -public: - nsConnCacheObj(nsIChannel *aChannel, - nsIInputStream *aInputStream, - nsIOutputStream *aOutputStream) - { - mSocketTransport = aChannel; - NS_ADDREF(mSocketTransport); - - mInputStream = aInputStream; - NS_ADDREF(mInputStream); - - mOutputStream = aOutputStream; - NS_ADDREF(mOutputStream); - - mServerType = 0; - mList = PR_FALSE; - mUseDefaultPath = PR_TRUE; - }; - ~nsConnCacheObj() - { - NS_RELEASE(mSocketTransport); - NS_RELEASE(mInputStream); - NS_RELEASE(mOutputStream); - }; - - nsIChannel *mSocketTransport; // the connection - nsIInputStream *mInputStream; // to read from server - nsIOutputStream *mOutputStream; // to write to server - PRUint32 mServerType; // what kind of server is it. - nsCAutoString mCwd; // what dir are we in - PRBool mList; // are we sending LIST or NLST - PRBool mUseDefaultPath; // do we need to use the default path. -}; +#include "nsIConnectionCache.h" +#include "nsConnectionCacheObj.h" +#include "nsIProtocolHandler.h" // ftp server types #define FTP_GENERIC_TYPE 0 @@ -160,10 +125,9 @@ public: nsresult Init(nsIEventQueue* aFTPEventQ, nsIURI* aUrl, nsIEventQueue* aEventQ, - nsIStreamListener *aListener, + nsIProtocolHandler* aHandler, nsIChannel* channel, - nsISupports* ctxt, - nsHashtable* aConnectionList); + nsISupports* ctxt); nsresult Process(); // user level setup @@ -255,8 +219,7 @@ private: nsCAutoString mCwdAttempt; // the dir we're trying to get into. // end "these ...." - nsStringKey *mCacheKey; // the key into the cache hash. - PRLock *mCacheLock; // the lock for accessing the cache. + nsCAutoString mCacheKey; // the key into the cache hash. PRBool mConnected; PRBool mUseDefaultPath; // use PWD to figure out path @@ -273,16 +236,18 @@ private: nsIStreamListener* mListener; // the listener we want to call // during our event firing. + nsIStreamListener* mSyncListener; // a syncronous version of our listener + nsIChannel* mChannel; nsISupports* mContext; nsIFTPContext* mFTPContext; // FTP channel specific context. - + nsIConnectionCache* mConnCache; // the nsISupports proxy ptr to the FTP proto handler + nsIProtocolHandler* mHandler; // The protocol handler that created this. + nsConnectionCacheObj* mConn; // The cached connection. PRBool mKeepRunning; // thread event loop boolean nsString2 mContentType; // the content type of the data we're dealing w/. char* mURLSpec; - nsHashtable* mConnectionList; // list of open FTP connections - }; #define NS_FTP_BUFFER_READ_SIZE (8*1024) diff --git a/netwerk/protocol/ftp/src/nsFtpProtocolHandler.cpp b/netwerk/protocol/ftp/src/nsFtpProtocolHandler.cpp index 19859798342e..f180915056e2 100644 --- a/netwerk/protocol/ftp/src/nsFtpProtocolHandler.cpp +++ b/netwerk/protocol/ftp/src/nsFtpProtocolHandler.cpp @@ -25,7 +25,7 @@ #include "nsIServiceManager.h" #include "nsIEventSinkGetter.h" #include "nsIProgressEventSink.h" -#include "nsFtpConnectionThread.h" // for nsConnCacheObj class +#include "nsConnectionCacheObj.h" #if defined(PR_LOGGING) // @@ -50,30 +50,21 @@ static NS_DEFINE_CID(kStandardURLCID, NS_STANDARDURL_CID); nsFtpProtocolHandler::nsFtpProtocolHandler() { NS_INIT_REFCNT(); NS_NEWXPCOM(mRootConnectionList, nsHashtable); - NS_NEWXPCOM(mThreadArray, nsVoidArray); } // cleans up a connection list entry PRBool CleanupConnEntry(nsHashKey *aKey, void *aData, void *closure) { // XXX do we need to explicitly close the streams? - delete (nsConnCacheObj*)aData; + delete (nsConnectionCacheObj*)aData; return PR_TRUE; } nsFtpProtocolHandler::~nsFtpProtocolHandler() { mRootConnectionList->Reset(CleanupConnEntry); NS_DELETEXPCOM(mRootConnectionList); - - nsIThread *thread; - while ( (thread = (nsIThread*)mThreadArray->ElementAt(0)) ) { - thread->Join(); - NS_RELEASE(thread); - mThreadArray->RemoveElementAt(0); - } - NS_DELETEXPCOM(mThreadArray); } -NS_IMPL_ISUPPORTS(nsFtpProtocolHandler, NS_GET_IID(nsIProtocolHandler)); +NS_IMPL_ISUPPORTS2(nsFtpProtocolHandler, nsIProtocolHandler, nsIConnectionCache); NS_METHOD nsFtpProtocolHandler::Create(nsISupports* aOuter, const nsIID& aIID, void* *aResult) @@ -189,24 +180,32 @@ nsFtpProtocolHandler::NewChannel(const char* verb, nsIURI* url, rv = nsFTPChannel::Create(nsnull, NS_GET_IID(nsIFTPChannel), (void**)&channel); if (NS_FAILED(rv)) return rv; - nsIThread* connThread = nsnull; - rv = channel->Init(verb, url, aGroup, eventSinkGetter, - mRootConnectionList, &connThread); + rv = channel->Init(verb, url, aGroup, eventSinkGetter, this); if (NS_FAILED(rv)) { NS_RELEASE(channel); PR_LOG(gFTPLog, PR_LOG_DEBUG, ("nsFtpProtocolHandler::NewChannel() FAILED\n")); return rv; } - // add this thread to the array. - if (!mThreadArray->AppendElement(connThread)) { - NS_RELEASE(connThread); - NS_RELEASE(channel); - return NS_ERROR_FAILURE; - } - *result = channel; return NS_OK; } +// nsIConnectionCache methods +NS_IMETHODIMP +nsFtpProtocolHandler::RemoveConn(const char *aKey, nsConnectionCacheObj* *_retval) { + NS_ASSERTION(_retval, "null pointer"); + nsStringKey key(aKey); + *_retval = (nsConnectionCacheObj*)mRootConnectionList->Remove(&key); + return NS_OK; +} + +NS_IMETHODIMP +nsFtpProtocolHandler::InsertConn(const char *aKey, nsConnectionCacheObj *aConn) { + NS_ASSERTION(aConn, "null pointer"); + nsStringKey key(aKey); + mRootConnectionList->Put(&key, aConn); + return NS_OK; +} + //////////////////////////////////////////////////////////////////////////////// diff --git a/netwerk/protocol/ftp/src/nsFtpProtocolHandler.h b/netwerk/protocol/ftp/src/nsFtpProtocolHandler.h index 4fa620ab0925..40038fcd1605 100644 --- a/netwerk/protocol/ftp/src/nsFtpProtocolHandler.h +++ b/netwerk/protocol/ftp/src/nsFtpProtocolHandler.h @@ -22,12 +22,15 @@ #include "nsIProtocolHandler.h" #include "nsHashtable.h" #include "nsVoidArray.h" +#include "nsIConnectionCache.h" +#include "nsConnectionCacheObj.h" // {25029490-F132-11d2-9588-00805F369F95} #define NS_FTPPROTOCOLHANDLER_CID \ { 0x25029490, 0xf132, 0x11d2, { 0x95, 0x88, 0x0, 0x80, 0x5f, 0x36, 0x9f, 0x95 } } -class nsFtpProtocolHandler : public nsIProtocolHandler +class nsFtpProtocolHandler : public nsIProtocolHandler, + public nsIConnectionCache { public: NS_DECL_ISUPPORTS @@ -35,6 +38,9 @@ public: // nsIProtocolHandler methods: NS_DECL_NSIPROTOCOLHANDLER + // nsIConnectionCache methods + NS_DECL_NSICONNECTIONCACHE + // nsFtpProtocolHandler methods: nsFtpProtocolHandler(); virtual ~nsFtpProtocolHandler(); @@ -46,7 +52,6 @@ public: protected: nsISupports* mEventSinkGetter; nsHashtable* mRootConnectionList; // hash of FTP connections - nsVoidArray* mThreadArray; // array of FTP connection threads }; #endif /* nsFtpProtocolHandler_h___ */