Bug 43567 - ftp keeping connections alive forever

r=dougt, sr=darin
This commit is contained in:
bbaetz%cs.mcgill.ca 2001-12-06 00:02:24 +00:00
Родитель 15de579974
Коммит 50e7519779
7 изменённых файлов: 167 добавлений и 36 удалений

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

@ -388,6 +388,9 @@ pref("network.http.pipelining.maxrequests" , 4);
pref("network.http.proxy.ssl.connect",true);
// </ruslan>
// Idle timeout for ftp control connections - 5 minute default
pref("network.ftp.idleConnectionTimeout", 300);
// until the directory view has an owner
// necko will produce html -- dougt
pref("network.dir.generate_html", true);

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

@ -35,6 +35,7 @@ REQUIRES = xpcom \
string \
necko \
nkcache \
timer \
$(NULL)
CPPSRCS = nsNetModule2.cpp

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

@ -28,6 +28,7 @@ REQUIRES = xpcom \
string \
nkcache \
necko \
timer \
$(NULL)
LCFLAGS = -DWIN32_LEAN_AND_MEAN -D_IMPL_NS_NET

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

@ -37,6 +37,7 @@ REQUIRES = xpcom \
intl \
necko \
nkcache \
timer \
$(NULL)
CPPSRCS = \

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

@ -27,6 +27,7 @@ REQUIRES = xpcom \
intl \
nkcache \
necko \
timer \
$(NULL)
DEPTH = ..\..\..\..

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

@ -17,7 +17,7 @@
* Copyright (C) 1998 Netscape Communications Corporation. All
* Rights Reserved.
*
* Contributor(s):
* Contributor(s): Bradley Baetz <bbaetz@cs.mcgill.ca>
*
*
* This Original Code has been modified by IBM Corporation.
@ -45,10 +45,9 @@
#include "prlog.h"
#include "nsIPref.h"
#include "nsNetUtil.h"
// For proxification of FTP URLs
#include "nsIHttpProtocolHandler.h"
#include "nsIErrorService.h"
#include "nsIPrefService.h"
#include "nsIPrefBranchInternal.h"
#if defined(PR_LOGGING)
//
@ -66,31 +65,39 @@ PRLogModuleInfo* gFTPLog = nsnull;
#endif /* PR_LOGGING */
#define IDLE_TIMEOUT_PREF "network.ftp.idleConnectionTimeout"
static NS_DEFINE_IID(kIOServiceCID, NS_IOSERVICE_CID);
static NS_DEFINE_CID(kStandardURLCID, NS_STANDARDURL_CID);
static NS_DEFINE_CID(kHttpHandlerCID, NS_HTTPPROTOCOLHANDLER_CID);
static NS_DEFINE_CID(kErrorServiceCID, NS_ERRORSERVICE_CID);
static NS_DEFINE_CID(kPrefServiceCID, NS_PREF_CID);
static NS_DEFINE_CID(kCacheServiceCID, NS_CACHESERVICE_CID);
nsSupportsHashtable* nsFtpProtocolHandler::mRootConnectionList = nsnull;
nsVoidArray* nsFtpProtocolHandler::mRootConnectionList = nsnull;
PRInt32 nsFtpProtocolHandler::mIdleTimeout = -1;
////////////////////////////////////////////////////////////////////////////////
nsFtpProtocolHandler::nsFtpProtocolHandler() {
NS_INIT_REFCNT();
NS_INIT_ISUPPORTS();
}
nsFtpProtocolHandler::~nsFtpProtocolHandler() {
PR_LOG(gFTPLog, PR_LOG_ALWAYS, ("~nsFtpProtocolHandler() called"));
if (mRootConnectionList) {
if (mRootConnectionList) {
PRInt32 i;
for (i=0;i<mRootConnectionList->Count();++i)
delete (timerStruct*)mRootConnectionList->ElementAt(i);
NS_DELETEXPCOM(mRootConnectionList);
mRootConnectionList = nsnull;
}
mIdleTimeout = -1;
mIOSvc = 0;
}
NS_IMPL_THREADSAFE_ISUPPORTS2(nsFtpProtocolHandler,
NS_IMPL_THREADSAFE_ISUPPORTS4(nsFtpProtocolHandler,
nsIProtocolHandler,
nsIProxiedProtocolHandler);
nsIProxiedProtocolHandler,
nsIObserver,
nsISupportsWeakReference);
nsresult
nsFtpProtocolHandler::Init() {
@ -103,9 +110,9 @@ nsFtpProtocolHandler::Init() {
mIOSvc = do_GetService(kIOServiceCID, &rv);
if (NS_FAILED(rv)) return rv;
mRootConnectionList = new nsSupportsHashtable(16, PR_TRUE); /* xxx what should be the size of this hashtable?? */
mRootConnectionList = new nsVoidArray(8);
if (!mRootConnectionList) return NS_ERROR_OUT_OF_MEMORY;
NS_LOG_NEW_XPCOM(mRootConnectionList, "nsSupportsHashtable", sizeof(nsSupportsHashtable), __FILE__, __LINE__);
NS_LOG_NEW_XPCOM(mRootConnectionList, "nsVoidArray", sizeof(nsVoidArray), __FILE__, __LINE__);
// XXX hack until xpidl supports error info directly (http://bugzilla.mozilla.org/show_bug.cgi?id=13423)
nsCOMPtr<nsIErrorService> errorService = do_GetService(kErrorServiceCID, &rv);
@ -115,7 +122,24 @@ nsFtpProtocolHandler::Init() {
rv = errorService->RegisterErrorStringBundleKey(NS_NET_STATUS_END_FTP_TRANSACTION, "EndFTPTransaction");
if (NS_FAILED(rv)) return rv;
}
return rv;
if (mIdleTimeout == -1) {
nsCOMPtr<nsIPrefService> prefSrv = do_GetService(NS_PREFSERVICE_CONTRACTID, &rv);
if (NS_FAILED(rv)) return rv;
nsCOMPtr<nsIPrefBranch> branch;
// I have to get the root pref branch because of bug 107617
rv = prefSrv->GetBranch(nsnull, getter_AddRefs(branch));
if (NS_FAILED(rv)) return rv;
rv = branch->GetIntPref(IDLE_TIMEOUT_PREF, &mIdleTimeout);
if (NS_FAILED(rv))
mIdleTimeout = 5*60; // 5 minute default
prefSrv->GetBranch(nsnull, getter_AddRefs(branch));
nsCOMPtr<nsIPrefBranchInternal> pbi = do_QueryInterface(branch);
rv = pbi->AddObserver(IDLE_TIMEOUT_PREF, this, PR_TRUE);
if (NS_FAILED(rv)) return rv;
}
return NS_OK;
}
@ -208,6 +232,23 @@ nsFtpProtocolHandler::AllowPort(PRInt32 port, const char *scheme, PRBool *_retva
}
// connection cache methods
void
nsFtpProtocolHandler::Timeout(nsITimer *aTimer, void *aClosure)
{
PR_LOG(gFTPLog, PR_LOG_DEBUG, ("Timeout reached for %0x\n", aClosure));
NS_ASSERTION(mRootConnectionList, "Timeout called without a connection list!");
PRBool found = mRootConnectionList->RemoveElement(aClosure);
NS_ASSERTION(found, "Timeout without entry!");
if (!found)
return;
timerStruct* s = (timerStruct*)aClosure;
delete s;
}
nsresult
nsFtpProtocolHandler::RemoveConnection(nsIURI *aKey, nsISupports* *_retval) {
NS_ASSERTION(_retval, "null pointer");
@ -221,23 +262,33 @@ nsFtpProtocolHandler::RemoveConnection(nsIURI *aKey, nsISupports* *_retval) {
nsXPIDLCString spec;
aKey->GetPrePath(getter_Copies(spec));
nsCStringKey stringKey(spec);
PR_LOG(gFTPLog, PR_LOG_DEBUG, ("Removing connection for %s\b", spec.get()));
timerStruct* ts = nsnull;
PRInt32 i;
PRBool found = PR_FALSE;
// Do not have to addRef since there is only one connection (with this key)
// in this hash table at any time and that one has been addRef'ed
// by the Put(). If we change connection caching, we will have
// to re-address this.
if (mRootConnectionList)
mRootConnectionList->Remove(&stringKey, (nsISupports**)_retval);
for (i=0;i<mRootConnectionList->Count();++i) {
ts = (timerStruct*)mRootConnectionList->ElementAt(i);
if (!nsCRT::strcmp(spec.get(), ts->key)) {
found = PR_TRUE;
mRootConnectionList->RemoveElementAt(i);
break;
}
}
if (*_retval)
return NS_OK;
if (!found)
return NS_ERROR_FAILURE;
return NS_ERROR_FAILURE;
NS_ADDREF(*_retval = ts->conn);
delete ts;
return NS_OK;
}
nsresult
nsFtpProtocolHandler::InsertConnection(nsIURI *aKey, nsISupports *aConn) {
nsFtpProtocolHandler::InsertConnection(nsIURI *aKey, nsISupports *aConn)
{
NS_ASSERTION(aConn, "null pointer");
NS_ASSERTION(aKey, "null pointer");
@ -246,14 +297,63 @@ nsFtpProtocolHandler::InsertConnection(nsIURI *aKey, nsISupports *aConn) {
nsXPIDLCString spec;
aKey->GetPrePath(getter_Copies(spec));
nsCStringKey stringKey(spec);
PR_LOG(gFTPLog, PR_LOG_DEBUG, ("Inserting connection for %s\b", spec.get()));
if (!mRootConnectionList)
return NS_ERROR_FAILURE;
if (mRootConnectionList)
{
mRootConnectionList->Put(&stringKey, aConn);
return NS_OK;
}
return NS_ERROR_FAILURE;
nsresult rv;
nsCOMPtr<nsITimer> timer = do_CreateInstance("@mozilla.org/timer;1", &rv);
if (NS_FAILED(rv)) return rv;
timerStruct* ts = new timerStruct();
if (!ts)
return NS_ERROR_OUT_OF_MEMORY;
rv = timer->Init(nsFtpProtocolHandler::Timeout,
ts,
mIdleTimeout*1000,
NS_PRIORITY_LOW);
if (NS_FAILED(rv)) {
delete ts;
return rv;
}
ts->key = nsCRT::strdup(spec.get());
if (!ts->key) {
delete ts;
return NS_ERROR_OUT_OF_MEMORY;
}
ts->conn = aConn;
ts->timer = timer;
mRootConnectionList->AppendElement(ts);
return NS_OK;
}
////////////////////////////////////////////////////////////////////////////////
// nsIObserver
NS_IMETHODIMP
nsFtpProtocolHandler::Observe(nsISupports* aSubject,
const char* aTopic,
const PRUnichar* aData)
{
PR_LOG(gFTPLog, PR_LOG_DEBUG, ("nsFtpProtocolHandler::Observe\n"));
nsCOMPtr<nsIPrefBranch> branch = do_QueryInterface(aSubject);
NS_ASSERTION(branch, "Didn't get a prefBranch in Observe");
if (!branch)
return NS_ERROR_UNEXPECTED;
NS_ASSERTION(!strcmp(aTopic, NS_PREFBRANCH_PREFCHANGE_TOPIC_ID),
"Wrong aTopic passed to Observer");
PRInt32 timeout;
nsresult rv = branch->GetIntPref(IDLE_TIMEOUT_PREF, &timeout);
if (NS_SUCCEEDED(rv))
mIdleTimeout = timeout;
return NS_OK;
}

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

@ -40,22 +40,29 @@
#include "nsIServiceManager.h"
#include "nsIProxiedProtocolHandler.h"
#include "nsHashtable.h"
#include "nsVoidArray.h"
#include "nsIIOService.h"
#include "nsIThreadPool.h"
#include "nsITimer.h"
#include "nsIObserverService.h"
#include "nsAutoLock.h"
#include "nsICacheSession.h"
#include "nsIObserver.h"
#include "nsWeakReference.h"
#include "nsCRT.h"
class nsITimer;
// {25029490-F132-11d2-9588-00805F369F95}
#define NS_FTPPROTOCOLHANDLER_CID \
{ 0x25029490, 0xf132, 0x11d2, { 0x95, 0x88, 0x0, 0x80, 0x5f, 0x36, 0x9f, 0x95 } }
class nsFtpProtocolHandler : public nsIProxiedProtocolHandler {
class nsFtpProtocolHandler : public nsIProxiedProtocolHandler,
public nsIObserver,
public nsSupportsWeakReference {
public:
NS_DECL_ISUPPORTS
NS_DECL_NSIPROTOCOLHANDLER
NS_DECL_NSIPROXIEDPROTOCOLHANDLER
NS_DECL_NSIOBSERVER
// nsFtpProtocolHandler methods:
nsFtpProtocolHandler();
@ -69,10 +76,27 @@ public:
static nsresult BuildStreamConverter(nsIStreamListener* in, nsIStreamListener** out);
protected:
static nsSupportsHashtable* mRootConnectionList;
// Stuff for the timer callback function
struct timerStruct {
nsCOMPtr<nsITimer> timer;
nsCOMPtr<nsISupports> conn;
char* key;
timerStruct() : key(nsnull) {};
~timerStruct() {
if (timer)
timer->Cancel();
CRTFREEIF(key);
}
};
static void Timeout(nsITimer *aTimer, void *aClosure);
static nsVoidArray* mRootConnectionList;
nsCOMPtr<nsIIOService> mIOSvc;
nsCOMPtr<nsICacheSession> mCacheSession;
static PRInt32 mIdleTimeout;
};
#endif /* nsFtpProtocolHandler_h___ */