16910, r=mcafee. FTP now uses thread pools. it also provides some status to the webshell. and it no longer uses the server's defualt path.

This commit is contained in:
valeski%netscape.com 1999-11-02 04:04:23 +00:00
Родитель eab20fe1b3
Коммит b7021722f9
8 изменённых файлов: 205 добавлений и 218 удалений

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

@ -18,21 +18,12 @@
#include "nsIChannel.idl" #include "nsIChannel.idl"
interface nsIStreamListener; interface nsIEventQueue;
[scriptable, uuid(64718e40-18c2-11d3-9337-00104ba0fd40)] [scriptable, uuid(64718e40-18c2-11d3-9337-00104ba0fd40)]
interface nsIFTPChannel : nsIChannel interface nsIFTPChannel : nsIChannel
{ {
// PRE connect void SetConnectionQueue(in nsIEventQueue aEventQ);
// POST connect
// Initiate connect
void Get();
void Put();
void SetStreamListener(in nsIStreamListener aListener);
}; };

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

@ -46,7 +46,6 @@ public:
mServerType = 0; mServerType = 0;
mList = PR_FALSE; mList = PR_FALSE;
mUseDefaultPath = PR_TRUE;
}; };
~nsConnectionCacheObj() ~nsConnectionCacheObj()
{ {
@ -61,7 +60,6 @@ public:
PRUint32 mServerType; // what kind of server is it. PRUint32 mServerType; // what kind of server is it.
nsCAutoString mCwd; // what dir are we in nsCAutoString mCwd; // what dir are we in
PRBool mList; // are we sending LIST or NLST PRBool mList; // are we sending LIST or NLST
PRBool mUseDefaultPath; // do we need to use the default path.
}; };
#endif // __nsconnectioncacheobj__h____ #endif // __nsconnectioncacheobj__h____

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

@ -61,12 +61,34 @@ nsFTPChannel::nsFTPChannel() {
nsFTPChannel::~nsFTPChannel() { nsFTPChannel::~nsFTPChannel() {
} }
NS_IMPL_ISUPPORTS4(nsFTPChannel, nsIChannel, nsIFTPChannel, nsIStreamListener, nsIStreamObserver); NS_IMETHODIMP_(nsrefcnt) nsFTPChannel::AddRef(void)
{
NS_PRECONDITION(PRInt32(mRefCnt) >= 0, "illegal refcnt");
++mRefCnt;
NS_LOG_ADDREF(this, mRefCnt, "nsFTPChannel", sizeof(*this));
return mRefCnt;
}
NS_IMETHODIMP_(nsrefcnt) nsFTPChannel::Release(void)
{
NS_PRECONDITION(0 != mRefCnt, "dup release");
--mRefCnt;
NS_LOG_RELEASE(this, mRefCnt, "nsFTPChannel");
if (mRefCnt == 0) {
mRefCnt = 1; /* stabilize */
NS_DELETEXPCOM(this);
return 0;
}
return mRefCnt;
}
NS_IMPL_QUERY_INTERFACE4(nsFTPChannel, nsIChannel, nsIFTPChannel, nsIStreamListener, nsIStreamObserver);
//NS_IMPL_ISUPPORTS4(nsFTPChannel, nsIChannel, nsIFTPChannel, nsIStreamListener, nsIStreamObserver);
nsresult nsresult
nsFTPChannel::Init(const char* verb, nsIURI* uri, nsILoadGroup *aGroup, nsFTPChannel::Init(const char* verb, nsIURI* uri, nsILoadGroup *aGroup,
nsIEventSinkGetter* getter, nsIURI* originalURI, nsIEventSinkGetter* getter, nsIURI* originalURI,
nsIProtocolHandler* aHandler) nsIProtocolHandler* aHandler, nsIThreadPool* aPool)
{ {
nsresult rv; nsresult rv;
@ -75,13 +97,19 @@ nsFTPChannel::Init(const char* verb, nsIURI* uri, nsILoadGroup *aGroup,
mHandler = aHandler; mHandler = aHandler;
NS_ASSERTION(aPool, "FTP channel needs a thread pool to play in");
if (!aPool) return NS_ERROR_NULL_POINTER;
mPool = aPool;
mOriginalURI = originalURI ? originalURI : uri; mOriginalURI = originalURI ? originalURI : uri;
mURL = uri; mURL = uri;
mLoadGroup = aGroup; mLoadGroup = aGroup;
if (getter) { mEventSinkGetter = getter;
rv = getter->GetEventSink(verb, NS_GET_IID(nsIProgressEventSink),
if (mEventSinkGetter) {
rv = mEventSinkGetter->GetEventSink(verb, NS_GET_IID(nsIProgressEventSink),
(nsISupports**)(nsIProgressEventSink**)getter_AddRefs(mEventSink)); (nsISupports**)(nsIProgressEventSink**)getter_AddRefs(mEventSink));
if (NS_FAILED(rv)) { if (NS_FAILED(rv)) {
PR_LOG(gFTPLog, PR_LOG_DEBUG, ("nsFTPChannel::Init() (couldn't find event sink)\n")); PR_LOG(gFTPLog, PR_LOG_DEBUG, ("nsFTPChannel::Init() (couldn't find event sink)\n"));
@ -96,28 +124,6 @@ nsFTPChannel::Init(const char* verb, nsIURI* uri, nsILoadGroup *aGroup,
rv = eventQService->GetThreadEventQueue(PR_CurrentThread(), getter_AddRefs(mEventQueue)); rv = eventQService->GetThreadEventQueue(PR_CurrentThread(), getter_AddRefs(mEventQueue));
if (NS_FAILED(rv)) return rv; if (NS_FAILED(rv)) return rv;
// go ahead and create the thread for the connection.
// we'll init it and kick it off later
rv = NS_NewThread(getter_AddRefs(mConnectionThread));
if (NS_FAILED(rv)) return rv;
// 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;
PLEventQueue* PLEventQ = PL_CreateEventQueue("FTP thread", thread);
if (!PLEventQ) return rv;
rv = eventQService->CreateFromPLEventQueue(PLEventQ, getter_AddRefs(mConnectionEventQueue));
#else
rv = eventQService->CreateFromIThread(mConnectionThread, getter_AddRefs(mConnectionEventQueue));
#endif
return rv; return rv;
} }
@ -152,8 +158,8 @@ NS_IMETHODIMP
nsFTPChannel::Cancel(void) nsFTPChannel::Cancel(void)
{ {
nsresult rv = NS_OK; nsresult rv = NS_OK;
if (mThreadRequest) if (mProxiedThreadRequest)
rv = mThreadRequest->Cancel(); rv = mProxiedThreadRequest->Cancel();
return rv; return rv;
} }
@ -161,8 +167,8 @@ NS_IMETHODIMP
nsFTPChannel::Suspend(void) nsFTPChannel::Suspend(void)
{ {
nsresult rv = NS_OK; nsresult rv = NS_OK;
if (mThreadRequest) if (mProxiedThreadRequest)
rv = mThreadRequest->Suspend(); rv = mProxiedThreadRequest->Suspend();
return rv; return rv;
} }
@ -170,8 +176,8 @@ NS_IMETHODIMP
nsFTPChannel::Resume(void) nsFTPChannel::Resume(void)
{ {
nsresult rv = NS_OK; nsresult rv = NS_OK;
if (mThreadRequest) if (mProxiedThreadRequest)
rv = mThreadRequest->Resume(); rv = mProxiedThreadRequest->Resume();
return rv; return rv;
} }
@ -200,40 +206,6 @@ NS_IMETHODIMP
nsFTPChannel::OpenInputStream(PRUint32 startPosition, PRInt32 readCount, nsFTPChannel::OpenInputStream(PRUint32 startPosition, PRInt32 readCount,
nsIInputStream **_retval) nsIInputStream **_retval)
{ {
#if 0
// The ftp channel will act as the listener which will receive
// events from the ftp connection thread. It then uses a syncstreamlistener
// as it's mListener which receives the listener notifications and writes
// data down the output stream end of a pipe.
nsresult rv;
PR_LOG(gFTPLog, PR_LOG_DEBUG, ("nsFTPChannel::OpenInputStream() called\n"));
rv = serv->NewSyncStreamListener(_retval /* nsIInputStream **inStream */,
&mBufferOutputStream /* nsIBufferOutputStream **outStream */,
&mListener/* nsIStreamListener **listener */);
if (NS_FAILED(rv)) return rv;
mSourceOffset = startPosition;
mAmount = readCount;
////////////////////////////////
//// setup the channel thread
nsIThread* workerThread = nsnull;
nsFtpConnectionThread* protocolInterpreter =
new nsFtpConnectionThread(mEventQueue, this, this, nsnull);
if (!protocolInterpreter)
return NS_ERROR_OUT_OF_MEMORY;
protocolInterpreter->Init(mURL);
protocolInterpreter->SetUsePasv(PR_TRUE);
rv = NS_NewThread(&workerThread, protocolInterpreter);
if (NS_FAILED(rv)) return rv;
return NS_OK;
#endif // 0
return NS_ERROR_NOT_IMPLEMENTED; return NS_ERROR_NOT_IMPLEMENTED;
} }
@ -258,17 +230,24 @@ nsFTPChannel::AsyncRead(PRUint32 startPosition, PRInt32 readCount,
PR_LOG(gFTPLog, PR_LOG_DEBUG, ("nsFTPChannel::AsyncRead() called\n")); PR_LOG(gFTPLog, PR_LOG_DEBUG, ("nsFTPChannel::AsyncRead() called\n"));
if (mEventSink) {
nsAutoString statusMsg("Beginning FTP transaction.");
#ifndef BUG_16273_FIXED //TODO
rv = mEventSink->OnStatus(this, ctxt, statusMsg.ToNewUnicode());
#else
rv = mEventSink->OnStatus(this, ctxt, statusMsg.GetUnicode());
#endif
if (NS_FAILED(rv)) return rv;
}
/////////////////////////// ///////////////////////////
//// setup channel state //// setup channel state
// XXX we should be using these. esp. for FTP restart. // XXX we should be using these. esp. for FTP restart.
mSourceOffset = startPosition; mSourceOffset = startPosition;
mAmount = readCount; mAmount = readCount;
mContext = ctxt; mContext = ctxt;
mListener = listener; mListener = listener;
mSourceOffset = startPosition; mSourceOffset = startPosition;
mAmount = readCount; mAmount = readCount;
@ -279,39 +258,19 @@ nsFTPChannel::AsyncRead(PRUint32 startPosition, PRInt32 readCount,
if (!protocolInterpreter) return NS_ERROR_OUT_OF_MEMORY; if (!protocolInterpreter) return NS_ERROR_OUT_OF_MEMORY;
NS_ADDREF(protocolInterpreter); NS_ADDREF(protocolInterpreter);
rv = protocolInterpreter->Init(mConnectionEventQueue, /* FTP thread queue */ mThreadRequest = do_QueryInterface((nsISupports*)(nsIRequest*)protocolInterpreter, &rv);
mURL, /* url to load */ if (NS_FAILED(rv)) return rv;
rv = protocolInterpreter->Init(mURL, /* url to load */
mEventQueue, /* event queue for this thread */ mEventQueue, /* event queue for this thread */
mHandler, mHandler,
this, ctxt); this, ctxt, mEventSinkGetter);
mHandler = 0; // XXX this can go away when the channel is no longer being leaked.
if (NS_FAILED(rv)) return rv; if (NS_FAILED(rv)) return rv;
// create the proxy object so we can call into the FTP thread. rv = mPool->DispatchRequest((nsIRunnable*)protocolInterpreter);
NS_WITH_SERVICE(nsIProxyObjectManager, proxyManager, kProxyObjectManagerCID, &rv);
if (NS_FAILED(rv)) return rv;
rv = proxyManager->GetProxyObject(mConnectionEventQueue,
NS_GET_IID(nsIRequest),
(nsISupports*)(nsIRequest*)protocolInterpreter,
PROXY_SYNC | PROXY_ALWAYS,
getter_AddRefs(mThreadRequest));
if (NS_FAILED(rv)) return rv;
rv = mConnectionThread->Init((nsIRunnable*)protocolInterpreter,
0, /* stack size */
PR_PRIORITY_NORMAL,
PR_GLOBAL_THREAD,
PR_UNJOINABLE_THREAD);
// this extra release is a result of a discussion with
// dougt. GetProxyObject is doing an extra addref. dougt
// can best explain why. If this is suddenly an *extra*
// release, yank it.
NS_RELEASE2(protocolInterpreter, rv);
NS_RELEASE(protocolInterpreter); NS_RELEASE(protocolInterpreter);
mConnectionThread = 0; // this is necessary because there is a circular dependency
// between the FTPChannel and the connection thread.
// we need to ditch our ref to the connection thread asap.
if (NS_FAILED(rv)) return rv; if (NS_FAILED(rv)) return rv;
mConnected = PR_TRUE; mConnected = PR_TRUE;
@ -424,20 +383,22 @@ nsFTPChannel::SetOwner(nsISupports * aOwner)
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
// nsIFTPChannel methods: // nsIFTPChannel methods:
NS_IMETHODIMP NS_IMETHODIMP
nsFTPChannel::Get(void) { nsFTPChannel::SetConnectionQueue(nsIEventQueue *aEventQ) {
return NS_ERROR_NOT_IMPLEMENTED; nsresult rv;
} // 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;
NS_IMETHODIMP // change the thread request over to a proxy thread request.
nsFTPChannel::Put(void) { rv = proxyManager->GetProxyObject(aEventQ,
return NS_ERROR_NOT_IMPLEMENTED; NS_GET_IID(nsIRequest),
} mThreadRequest,
PROXY_SYNC | PROXY_ALWAYS,
getter_AddRefs(mProxiedThreadRequest));
mThreadRequest = 0;
if (NS_FAILED(rv)) return rv;
NS_IMETHODIMP
nsFTPChannel::SetStreamListener(nsIStreamListener *aListener) {
mListener = aListener;
return NS_OK; return NS_OK;
} }
@ -446,6 +407,7 @@ nsFTPChannel::SetStreamListener(nsIStreamListener *aListener) {
NS_IMETHODIMP NS_IMETHODIMP
nsFTPChannel::OnStartRequest(nsIChannel* channel, nsISupports* context) { nsFTPChannel::OnStartRequest(nsIChannel* channel, nsISupports* context) {
//MOZ_TIMER_START(channelTime, "nsFTPChannel::OnStart(): hit.");
nsresult rv = NS_OK; nsresult rv = NS_OK;
PR_LOG(gFTPLog, PR_LOG_DEBUG, ("nsFTPChannel::OnStartRequest(channel = %x, context = %x)\n", channel, context)); PR_LOG(gFTPLog, PR_LOG_DEBUG, ("nsFTPChannel::OnStartRequest(channel = %x, context = %x)\n", channel, context));
if (mListener) { if (mListener) {
@ -459,6 +421,15 @@ nsFTPChannel::OnStopRequest(nsIChannel* channel, nsISupports* context,
nsresult aStatus, nsresult aStatus,
const PRUnichar* aMsg) { const PRUnichar* aMsg) {
nsresult rv = NS_OK; nsresult rv = NS_OK;
if (mEventSink) {
nsAutoString statusMsg("FTP transaction complete.");
#ifndef BUG_16273_FIXED //TODO
rv = mEventSink->OnStatus(this, context, statusMsg.ToNewUnicode());
#else
rv = mEventSink->OnStatus(this, context, statusMsg.GetUnicode());
#endif
if (NS_FAILED(rv)) return rv;
}
PR_LOG(gFTPLog, PR_LOG_DEBUG, ("nsFTPChannel::OnStopRequest(channel = %x, context = %x, status = %d, msg = N/A)\n",channel, context, aStatus)); PR_LOG(gFTPLog, PR_LOG_DEBUG, ("nsFTPChannel::OnStopRequest(channel = %x, context = %x, status = %d, msg = N/A)\n",channel, context, aStatus));
if (mListener) { if (mListener) {
rv = mListener->OnStopRequest(channel, mContext, aStatus, aMsg); rv = mListener->OnStopRequest(channel, mContext, aStatus, aMsg);

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

@ -23,7 +23,6 @@
#include "nsIFTPChannel.h" #include "nsIFTPChannel.h"
#include "nsIStreamListener.h" #include "nsIStreamListener.h"
#include "nsIThread.h"
#include "nsIURI.h" #include "nsIURI.h"
#include "nsString2.h" #include "nsString2.h"
#include "nsIEventQueue.h" #include "nsIEventQueue.h"
@ -32,6 +31,8 @@
#include "nsHashtable.h" #include "nsHashtable.h"
#include "nsIProtocolHandler.h" #include "nsIProtocolHandler.h"
#include "nsIProgressEventSink.h" #include "nsIProgressEventSink.h"
#include "nsIEventSinkGetter.h"
#include "nsIThreadPool.h"
class nsIEventSinkGetter; class nsIEventSinkGetter;
class nsIProgressEventSink; class nsIProgressEventSink;
@ -59,13 +60,14 @@ public:
// join() it on shutdown. // join() it on shutdown.
nsresult Init(const char* verb, nsIURI* uri, nsILoadGroup *aGroup, nsresult Init(const char* verb, nsIURI* uri, nsILoadGroup *aGroup,
nsIEventSinkGetter* getter, nsIURI* originalURI, nsIEventSinkGetter* getter, nsIURI* originalURI,
nsIProtocolHandler* aHandler); nsIProtocolHandler* aHandler, nsIThreadPool* aPool);
protected: protected:
nsCOMPtr<nsIURI> mOriginalURI; nsCOMPtr<nsIURI> mOriginalURI;
nsCOMPtr<nsIURI> mURL; nsCOMPtr<nsIURI> mURL;
nsCOMPtr<nsIEventQueue> mEventQueue; nsCOMPtr<nsIEventQueue> mEventQueue;
nsCOMPtr<nsIProgressEventSink> mEventSink; nsCOMPtr<nsIProgressEventSink> mEventSink;
nsCOMPtr<nsIEventSinkGetter> mEventSinkGetter;
PRBool mConnected; PRBool mConnected;
nsCOMPtr<nsIStreamListener> mListener; nsCOMPtr<nsIStreamListener> mListener;
@ -78,11 +80,11 @@ protected:
nsAutoString mContentType; nsAutoString mContentType;
PRInt32 mContentLength; PRInt32 mContentLength;
nsCOMPtr<nsISupports> mOwner; nsCOMPtr<nsISupports> mOwner;
nsCOMPtr<nsIThread> mConnectionThread; // the thread for this connection.
nsCOMPtr<nsIEventQueue> mConnectionEventQueue; nsCOMPtr<nsIRequest> mThreadRequest;
nsCOMPtr<nsIRequest> mThreadRequest; // the nsIRequest proxy object. nsCOMPtr<nsIRequest> mProxiedThreadRequest;
nsCOMPtr<nsIProtocolHandler> mHandler; nsCOMPtr<nsIProtocolHandler> mHandler;
nsCOMPtr<nsIThreadPool> mPool; // the thread pool we want to use to fire off connections.
}; };
#define NS_FTP_SEGMENT_SIZE (4*1024) #define NS_FTP_SEGMENT_SIZE (4*1024)

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

@ -39,6 +39,7 @@
#include "nsProxiedService.h" #include "nsProxiedService.h"
#include "nsINetSupportDialogService.h" #include "nsINetSupportDialogService.h"
#include "nsFtpProtocolHandler.h" #include "nsFtpProtocolHandler.h"
#include "nsIFTPChannel.h"
static NS_DEFINE_CID(kIOServiceCID, NS_IOSERVICE_CID); static NS_DEFINE_CID(kIOServiceCID, NS_IOSERVICE_CID);
static NS_DEFINE_CID(kStreamConverterServiceCID, NS_STREAMCONVERTERSERVICE_CID); static NS_DEFINE_CID(kStreamConverterServiceCID, NS_STREAMCONVERTERSERVICE_CID);
@ -104,8 +105,28 @@ NS_IMPL_ISUPPORTS(nsFTPContext, kIFTPContextIID);
// BEGIN: nsFtpConnectionThread implementation // BEGIN: nsFtpConnectionThread implementation
NS_IMETHODIMP_(nsrefcnt) nsFtpConnectionThread::AddRef(void)
NS_IMPL_ISUPPORTS2(nsFtpConnectionThread, nsIRunnable, nsIRequest); {
NS_PRECONDITION(PRInt32(mRefCnt) >= 0, "illegal refcnt");
++mRefCnt;
NS_LOG_ADDREF(this, mRefCnt, "nsFtpConnectionThread", sizeof(*this));
return mRefCnt;
}
NS_IMETHODIMP_(nsrefcnt) nsFtpConnectionThread::Release(void)
{
NS_PRECONDITION(0 != mRefCnt, "dup release");
--mRefCnt;
NS_LOG_RELEASE(this, mRefCnt, "nsFtpConnectionThread");
if (mRefCnt == 0) {
mRefCnt = 1; /* stabilize */
NS_DELETEXPCOM(this);
return 0;
}
return mRefCnt;
}
NS_IMPL_QUERY_INTERFACE2(nsFtpConnectionThread, nsIRunnable, nsIRequest);
//NS_IMPL_ISUPPORTS2(nsFtpConnectionThread, nsIRunnable, nsIRequest);
nsFtpConnectionThread::nsFtpConnectionThread() { nsFtpConnectionThread::nsFtpConnectionThread() {
NS_INIT_REFCNT(); NS_INIT_REFCNT();
@ -119,7 +140,6 @@ nsFtpConnectionThread::nsFtpConnectionThread() {
mResetMode = PR_FALSE; mResetMode = PR_FALSE;
mList = PR_FALSE; mList = PR_FALSE;
mKeepRunning = PR_TRUE; mKeepRunning = PR_TRUE;
mUseDefaultPath = PR_FALSE;
mContinueRead = PR_FALSE; mContinueRead = PR_FALSE;
mAnonymous = PR_TRUE; mAnonymous = PR_TRUE;
mRetryPass = PR_FALSE; mRetryPass = PR_FALSE;
@ -253,7 +273,6 @@ nsFtpConnectionThread::Process() {
PR_LOG(gFTPLog, PR_LOG_DEBUG, ("%x Process() - COMPLETE\n", mURL.get())); PR_LOG(gFTPLog, PR_LOG_DEBUG, ("%x Process() - COMPLETE\n", mURL.get()));
// push through all of the pertinent state into the cache entry; // push through all of the pertinent state into the cache entry;
mConn->mCwd = mCwd; mConn->mCwd = mCwd;
mConn->mUseDefaultPath = mUseDefaultPath;
rv = mConnCache->InsertConn(mCacheKey.GetBuffer(), mConn); rv = mConnCache->InsertConn(mCacheKey.GetBuffer(), mConn);
if (NS_FAILED(rv)) return rv; if (NS_FAILED(rv)) return rv;
@ -866,12 +885,11 @@ nsFtpConnectionThread::R_syst() {
SetSystInternals(); // must be called first to setup member vars. SetSystInternals(); // must be called first to setup member vars.
if (!mUseDefaultPath)
state = FindActionState();
// setup next state based on server type. // setup next state based on server type.
if (mServerType == FTP_PETER_LEWIS_TYPE || mServerType == FTP_WEBSTAR_TYPE) if (mServerType == FTP_PETER_LEWIS_TYPE || mServerType == FTP_WEBSTAR_TYPE)
state = FTP_S_MACB; state = FTP_S_MACB;
else
state = FindActionState();
} }
return state; return state;
@ -932,7 +950,6 @@ nsFtpConnectionThread::S_pwd() {
FTP_STATE FTP_STATE
nsFtpConnectionThread::R_pwd() { nsFtpConnectionThread::R_pwd() {
nsresult rv;
FTP_STATE state = FTP_ERROR; FTP_STATE state = FTP_ERROR;
nsCAutoString lNewMsg(mResponseMsg); nsCAutoString lNewMsg(mResponseMsg);
// fun response interpretation begins :) // fun response interpretation begins :)
@ -971,53 +988,6 @@ nsFtpConnectionThread::R_pwd() {
} }
} }
// we only want to use the parent working directory (pwd) when
// the url supplied provides ambiguous path info (such as /./, or
// no slash at all.
if (mUseDefaultPath && mServerType != FTP_VMS_TYPE) {
mUseDefaultPath = PR_FALSE;
// we want to use the default path specified by the PWD command.
nsCAutoString ptr;
if (lNewMsg.First() != '/') {
PRInt32 start = lNewMsg.FindChar('/');
if (start > -1) {
lNewMsg.Right(ptr, start); // use everything after the first slash (inclusive)
} else {
// if we couldn't find a slash, check for back slashes and switch them out.
start = lNewMsg.FindChar('\\');
if (start > -1) {
lNewMsg.ReplaceChar("\\", '/');
}
ptr = lNewMsg;
}
} else {
ptr = lNewMsg;
}
// construct the new url by appending
// the initial path to the new path.
if (ptr.Length()) {
nsXPIDLCString initialPath;
rv = mURL->GetPath(getter_Copies(initialPath));
if (NS_FAILED(rv)) return FTP_ERROR;
if (ptr.Last() == '/') {
PRUint32 insertionOffset = ptr.Length() - 1;
ptr.Cut(insertionOffset, 1);
ptr.Insert(initialPath, insertionOffset);
} else {
ptr.Append(initialPath);
}
const char *p = ptr.GetBuffer();
rv = mURL->SetPath(p);
if (NS_FAILED(rv)) return FTP_ERROR;
}
}
// change state for these servers. // change state for these servers.
if (mServerType == FTP_GENERIC_TYPE if (mServerType == FTP_GENERIC_TYPE
|| mServerType == FTP_NCSA_TYPE || mServerType == FTP_NCSA_TYPE
@ -1280,7 +1250,8 @@ nsFtpConnectionThread::R_list() {
rv = StreamConvService->AsyncConvertData(fromStr.GetUnicode(), rv = StreamConvService->AsyncConvertData(fromStr.GetUnicode(),
toStr.GetUnicode(), toStr.GetUnicode(),
mSyncListener, mURL, getter_AddRefs(converterListener)); mSyncListener,
mURL, getter_AddRefs(converterListener));
if (NS_FAILED(rv)) { if (NS_FAILED(rv)) {
return FTP_ERROR; return FTP_ERROR;
} }
@ -1511,7 +1482,9 @@ nsFtpConnectionThread::R_pasv() {
nsAllocator::Free(response); nsAllocator::Free(response);
// now we know where to connect our data channel // now we know where to connect our data channel
rv = mSTS->CreateTransport(host.GetBuffer(), port, nsnull, getter_AddRefs(mDPipe)); // the data channel rv = mSTS->CreateTransport(host.GetBuffer(), port,
nsnull, /* don't push the event sink getter through for the data channel */
getter_AddRefs(mDPipe)); // the data channel
if (NS_FAILED(rv)) return FTP_ERROR; if (NS_FAILED(rv)) return FTP_ERROR;
if (mAction == GET) { if (mAction == GET) {
@ -1635,7 +1608,33 @@ nsFtpConnectionThread::R_mkdir() {
NS_IMETHODIMP NS_IMETHODIMP
nsFtpConnectionThread::Run() { nsFtpConnectionThread::Run() {
nsresult rv; nsresult rv;
NS_WITH_SERVICE(nsIEventQueueService, eventQService, kEventQueueServiceCID, &rv);
if (NS_FAILED(rv)) return rv;
rv = eventQService->CreateThreadEventQueue();
if (NS_FAILED(rv)) return rv;
rv = eventQService->GetThreadEventQueue(PR_GetCurrentThread(), 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<nsIFTPChannel> ftpChannel;
rv = pIProxyObjectManager->GetProxyObject(mOutsideEventQueue,
NS_GET_IID(nsIFTPChannel),
mChannel,
PROXY_SYNC | PROXY_ALWAYS,
getter_AddRefs(ftpChannel));
if (NS_FAILED(rv)) return rv;
rv = ftpChannel->SetConnectionQueue(mFTPEventQueue);
if (NS_FAILED(rv)) return rv;
rv = nsServiceManager::GetService(kSocketTransportServiceCID, rv = nsServiceManager::GetService(kSocketTransportServiceCID,
NS_GET_IID(nsISocketTransportService), NS_GET_IID(nsISocketTransportService),
(nsISupports **)&mSTS); (nsISupports **)&mSTS);
@ -1666,10 +1665,9 @@ nsFtpConnectionThread::Run() {
mServerType = mConn->mServerType; mServerType = mConn->mServerType;
mCwd = mConn->mCwd; mCwd = mConn->mCwd;
mList = mConn->mList; mList = mConn->mList;
mUseDefaultPath = mConn->mUseDefaultPath;
} else { } else {
// build our own // build our own
rv = mSTS->CreateTransport(host, port, nsnull, getter_AddRefs(mCPipe)); // the command channel rv = mSTS->CreateTransport(host, port, mEventSinkGetter, getter_AddRefs(mCPipe)); // the command channel
if (NS_FAILED(rv)) return rv; if (NS_FAILED(rv)) return rv;
// get the output stream so we can write to the server // get the output stream so we can write to the server
@ -1753,6 +1751,10 @@ nsFtpConnectionThread::Run() {
mConnected = PR_TRUE; mConnected = PR_TRUE;
rv = Process(); rv = Process();
mListener = 0;
mSyncListener = 0;
mChannel = 0;
mConnCache = 0;
return rv; return rv;
} }
@ -1822,43 +1824,52 @@ nsFtpConnectionThread::Resume(void)
} }
nsresult nsresult
nsFtpConnectionThread::Init(nsIEventQueue* aFTPEventQ, nsFtpConnectionThread::Init(nsIURI* aUrl,
nsIURI* aUrl,
nsIEventQueue* aEventQ, nsIEventQueue* aEventQ,
nsIProtocolHandler* aHandler, nsIProtocolHandler* aHandler,
nsIChannel* aChannel, nsIChannel* aChannel,
nsISupports* aContext) { nsISupports* aContext,
nsIEventSinkGetter* aEventSinkGetter) {
nsresult rv; nsresult rv;
NS_ASSERTION(aFTPEventQ, "FTP: thread needs an event queue to process");
mFTPEventQueue = aFTPEventQ;
NS_ASSERTION(aChannel, "FTP: thread needs a channel"); NS_ASSERTION(aChannel, "FTP: thread needs a channel");
mOutsideEventQueue = aEventQ;
mEventSinkGetter = aEventSinkGetter;
NS_WITH_SERVICE(nsIProxyObjectManager, pIProxyObjectManager, kProxyObjectManagerCID, &rv); NS_WITH_SERVICE(nsIProxyObjectManager, pIProxyObjectManager, kProxyObjectManagerCID, &rv);
if(NS_FAILED(rv)) return rv; if(NS_FAILED(rv)) return rv;
rv = pIProxyObjectManager->GetProxyObject(aEventQ, rv = pIProxyObjectManager->GetProxyObject(mOutsideEventQueue,
NS_GET_IID(nsIStreamListener), NS_GET_IID(nsIStreamListener),
aChannel, aChannel,
PROXY_ASYNC | PROXY_ALWAYS, PROXY_ASYNC | PROXY_ALWAYS,
getter_AddRefs(mListener)); getter_AddRefs(mListener));
if (NS_FAILED(rv)) return rv; if (NS_FAILED(rv)) return rv;
rv = pIProxyObjectManager->GetProxyObject(aEventQ, rv = pIProxyObjectManager->GetProxyObject(mOutsideEventQueue,
NS_GET_IID(nsIStreamListener), NS_GET_IID(nsIStreamListener),
aChannel, aChannel,
PROXY_SYNC | PROXY_ALWAYS, PROXY_SYNC | PROXY_ALWAYS,
getter_AddRefs(mSyncListener)); getter_AddRefs(mSyncListener));
if (NS_FAILED(rv)) return rv; if (NS_FAILED(rv)) return rv;
rv = pIProxyObjectManager->GetProxyObject(aEventQ, rv = pIProxyObjectManager->GetProxyObject(mOutsideEventQueue,
NS_GET_IID(nsIChannel), NS_GET_IID(nsIChannel),
aChannel, aChannel,
PROXY_SYNC | PROXY_ALWAYS, PROXY_SYNC | PROXY_ALWAYS,
getter_AddRefs(mChannel)); getter_AddRefs(mChannel));
if (NS_FAILED(rv)) return rv; 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,
getter_AddRefs(mConnCache));
if (NS_FAILED(rv)) return rv;
mContext = aContext; mContext = aContext;
mURL = aUrl; mURL = aUrl;
@ -1904,24 +1915,6 @@ nsFtpConnectionThread::Init(nsIEventQueue* aFTPEventQ,
getter_AddRefs(mConnCache)); getter_AddRefs(mConnCache));
if (NS_FAILED(rv)) return rv; if (NS_FAILED(rv)) return rv;
// XXX this entire check can probably go away.
// figure out whether or not we want to use the default path supplied by the server.
// we want to do this when there's some ambiguity in our path.
nsXPIDLCString path;
rv = mURL->GetPath(getter_Copies(path));
if (NS_FAILED(rv)) return rv;
if (!path || !*path || !PL_strncmp(path, "/.", 2) ) {
// scoot past the '/.'
char *newPath = nsCRT::strdup((const char*)path+2);
if (!newPath) return NS_ERROR_OUT_OF_MEMORY;
rv = mURL->SetPath(newPath);
if (NS_FAILED(rv)) return rv;
mUseDefaultPath = PR_TRUE;
}
return NS_OK; return NS_OK;
} }

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

@ -23,6 +23,7 @@
#include "nsIRunnable.h" #include "nsIRunnable.h"
#include "nsIRequest.h" #include "nsIRequest.h"
#include "nsISocketTransportService.h" #include "nsISocketTransportService.h"
#include "nsIEventSinkGetter.h"
#include "nsIServiceManager.h" #include "nsIServiceManager.h"
#include "nsIStreamListener.h" #include "nsIStreamListener.h"
#include "nsIOutputStream.h" #include "nsIOutputStream.h"
@ -124,17 +125,16 @@ public:
nsFtpConnectionThread(); nsFtpConnectionThread();
virtual ~nsFtpConnectionThread(); virtual ~nsFtpConnectionThread();
nsresult Init(nsIEventQueue* aFTPEventQ, nsresult Init(nsIURI* aUrl,
nsIURI* aUrl,
nsIEventQueue* aEventQ, nsIEventQueue* aEventQ,
nsIProtocolHandler* aHandler, nsIProtocolHandler* aHandler,
nsIChannel* channel, nsIChannel* channel,
nsISupports* ctxt); nsISupports* ctxt,
nsIEventSinkGetter* aEventSink);
nsresult Process(); nsresult Process();
// user level setup // user level setup
nsresult SetAction(FTP_ACTION aAction); nsresult SetAction(FTP_ACTION aAction);
private: private:
/////////////////////////////////// ///////////////////////////////////
@ -187,6 +187,7 @@ private:
// Private members // Private members
nsCOMPtr<nsIEventQueue> mFTPEventQueue; // the eventq for this thread. nsCOMPtr<nsIEventQueue> mFTPEventQueue; // the eventq for this thread.
nsCOMPtr<nsIEventQueue> mOutsideEventQueue; // the eventq for the using thread.
nsCOMPtr<nsIURI> mURL; nsCOMPtr<nsIURI> mURL;
FTP_STATE mState; // the current state FTP_STATE mState; // the current state
@ -223,7 +224,6 @@ private:
nsCAutoString mCacheKey; // the key into the cache hash. nsCAutoString mCacheKey; // the key into the cache hash.
PRBool mConnected; PRBool mConnected;
PRBool mUseDefaultPath; // use PWD to figure out path
PRBool mUsePasv; // use a passive data connection. PRBool mUsePasv; // use a passive data connection.
PRBool mDirectory; // this url is a directory PRBool mDirectory; // this url is a directory
PRBool mBin; // transfer mode (ascii or binary) PRBool mBin; // transfer mode (ascii or binary)
@ -248,6 +248,7 @@ private:
nsString2 mContentType; // the content type of the data we're dealing w/. nsString2 mContentType; // the content type of the data we're dealing w/.
nsXPIDLCString mURLSpec; nsXPIDLCString mURLSpec;
nsCOMPtr<nsIEventSinkGetter> mEventSinkGetter;
}; };
#define NS_FTP_BUFFER_READ_SIZE (8*1024) #define NS_FTP_BUFFER_READ_SIZE (8*1024)

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

@ -50,6 +50,9 @@ static NS_DEFINE_CID(kStandardURLCID, NS_STANDARDURL_CID);
nsFtpProtocolHandler::nsFtpProtocolHandler() { nsFtpProtocolHandler::nsFtpProtocolHandler() {
NS_INIT_REFCNT(); NS_INIT_REFCNT();
NS_NEWXPCOM(mRootConnectionList, nsHashtable); NS_NEWXPCOM(mRootConnectionList, nsHashtable);
NS_NewThreadPool(getter_AddRefs(mPool), NS_FTP_CONNECTION_COUNT,
NS_FTP_CONNECTION_COUNT,
NS_FTP_CONNECTION_STACK_SIZE);
} }
// cleans up a connection list entry // cleans up a connection list entry
@ -64,7 +67,30 @@ nsFtpProtocolHandler::~nsFtpProtocolHandler() {
NS_DELETEXPCOM(mRootConnectionList); NS_DELETEXPCOM(mRootConnectionList);
} }
NS_IMPL_ISUPPORTS2(nsFtpProtocolHandler, nsIProtocolHandler, nsIConnectionCache);
NS_IMETHODIMP_(nsrefcnt) nsFtpProtocolHandler::AddRef(void)
{
NS_PRECONDITION(PRInt32(mRefCnt) >= 0, "illegal refcnt");
++mRefCnt;
NS_LOG_ADDREF(this, mRefCnt, "nsFtpProtocolHandler", sizeof(*this));
return mRefCnt;
}
NS_IMETHODIMP_(nsrefcnt) nsFtpProtocolHandler::Release(void)
{
NS_PRECONDITION(0 != mRefCnt, "dup release");
--mRefCnt;
NS_LOG_RELEASE(this, mRefCnt, "nsFtpProtocolHandler");
if (mRefCnt == 0) {
mRefCnt = 1; /* stabilize */
NS_DELETEXPCOM(this);
return 0;
}
return mRefCnt;
}
NS_IMPL_QUERY_INTERFACE2(nsFtpProtocolHandler, nsIProtocolHandler, nsIConnectionCache);
//NS_IMPL_ISUPPORTS2(nsFtpProtocolHandler, nsIProtocolHandler, nsIConnectionCache);
NS_METHOD NS_METHOD
nsFtpProtocolHandler::Create(nsISupports* aOuter, const nsIID& aIID, void* *aResult) nsFtpProtocolHandler::Create(nsISupports* aOuter, const nsIID& aIID, void* *aResult)
@ -181,7 +207,7 @@ nsFtpProtocolHandler::NewChannel(const char* verb, nsIURI* url,
rv = nsFTPChannel::Create(nsnull, NS_GET_IID(nsIFTPChannel), (void**)&channel); rv = nsFTPChannel::Create(nsnull, NS_GET_IID(nsIFTPChannel), (void**)&channel);
if (NS_FAILED(rv)) return rv; if (NS_FAILED(rv)) return rv;
rv = channel->Init(verb, url, aGroup, eventSinkGetter, originalURI, this); rv = channel->Init(verb, url, aGroup, eventSinkGetter, originalURI, this, mPool);
if (NS_FAILED(rv)) { if (NS_FAILED(rv)) {
NS_RELEASE(channel); NS_RELEASE(channel);
PR_LOG(gFTPLog, PR_LOG_DEBUG, ("nsFtpProtocolHandler::NewChannel() FAILED\n")); PR_LOG(gFTPLog, PR_LOG_DEBUG, ("nsFtpProtocolHandler::NewChannel() FAILED\n"));

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

@ -24,6 +24,7 @@
#include "nsVoidArray.h" #include "nsVoidArray.h"
#include "nsIConnectionCache.h" #include "nsIConnectionCache.h"
#include "nsConnectionCacheObj.h" #include "nsConnectionCacheObj.h"
#include "nsIThreadPool.h"
// {25029490-F132-11d2-9588-00805F369F95} // {25029490-F132-11d2-9588-00805F369F95}
#define NS_FTPPROTOCOLHANDLER_CID \ #define NS_FTPPROTOCOLHANDLER_CID \
@ -52,6 +53,10 @@ public:
protected: protected:
nsISupports* mEventSinkGetter; nsISupports* mEventSinkGetter;
nsHashtable* mRootConnectionList; // hash of FTP connections nsHashtable* mRootConnectionList; // hash of FTP connections
nsCOMPtr<nsIThreadPool> mPool; // thread pool for FTP connections
}; };
#define NS_FTP_CONNECTION_COUNT 6
#define NS_FTP_CONNECTION_STACK_SIZE (64 * 1024)
#endif /* nsFtpProtocolHandler_h___ */ #endif /* nsFtpProtocolHandler_h___ */