Bug 43567 - ftp keeping connections alive forever
r=dougt, sr=darin
This commit is contained in:
Родитель
15de579974
Коммит
50e7519779
|
@ -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___ */
|
||||
|
|
Загрузка…
Ссылка в новой задаче