зеркало из https://github.com/mozilla/gecko-dev.git
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.
This commit is contained in:
Родитель
25a47745c1
Коммит
3a4a5695b4
|
@ -28,6 +28,7 @@ XPIDL_MODULE = necko_ftp
|
|||
XPIDLSRCS = \
|
||||
nsIFTPChannel.idl \
|
||||
nsIFTPContext.idl \
|
||||
nsIConnectionCache.idl \
|
||||
$(NULL)
|
||||
|
||||
EXPORTS = ftpCore.h
|
||||
|
|
|
@ -25,6 +25,7 @@ XPIDL_MODULE = necko_ftp
|
|||
XPIDLSRCS = \
|
||||
.\nsIFTPChannel.idl \
|
||||
.\nsIFTPContext.idl \
|
||||
.\nsIConnectionCache.idl \
|
||||
$(NULL)
|
||||
|
||||
EXPORTS = \
|
||||
|
|
|
@ -29,7 +29,6 @@ IS_COMPONENT = 1
|
|||
CPPSRCS = \
|
||||
nsFtpProtocolHandler.cpp \
|
||||
nsFTPChannel.cpp \
|
||||
nsFtpStreamListenerEvent.cpp \
|
||||
nsFtpConnectionThread.cpp \
|
||||
nsFtpModule.cpp \
|
||||
$(NULL)
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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<nsISupports> 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)
|
||||
|
|
|
@ -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;
|
||||
|
||||
|
||||
|
@ -1348,27 +1343,22 @@ nsFtpConnectionThread::R_list() {
|
|||
|
||||
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<nsIInputStream> 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,57 +1701,44 @@ 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;
|
||||
mConn = new nsConnectionCacheObj(mCPipe, mCInStream, mCOutStream);
|
||||
if (!mConn) return NS_ERROR_OUT_OF_MEMORY;
|
||||
}
|
||||
|
||||
mConnectionList->Put(mCacheKey, conn);
|
||||
}
|
||||
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
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
|
|
@ -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___ */
|
||||
|
|
Загрузка…
Ссылка в новой задаче