зеркало из https://github.com/mozilla/gecko-dev.git
604796 - close our idle HTTP connection when server closes its end r=honzab
--HG-- extra : rebase_source : b4c89df4d3eab7b7c8c60d625467847557bc7291
This commit is contained in:
Родитель
5be8433fbb
Коммит
f5a58bd8b8
|
@ -82,6 +82,7 @@ nsHttpConnection::nsHttpConnection()
|
|||
, mIsActivated(PR_FALSE)
|
||||
, mCompletedProxyConnect(PR_FALSE)
|
||||
, mLastTransactionExpectedNoContent(PR_FALSE)
|
||||
, mIdleMonitoring(PR_FALSE)
|
||||
{
|
||||
LOG(("Creating nsHttpConnection @%x\n", this));
|
||||
|
||||
|
@ -170,6 +171,10 @@ nsHttpConnection::Activate(nsAHttpTransaction *trans, PRUint8 caps)
|
|||
mTransaction = trans;
|
||||
mIsActivated = PR_TRUE;
|
||||
|
||||
NS_ABORT_IF_FALSE(!mIdleMonitoring,
|
||||
"Activating a connection with an Idle Monitor");
|
||||
mIdleMonitoring = PR_FALSE;
|
||||
|
||||
// set mKeepAlive according to what will be requested
|
||||
mKeepAliveMask = mKeepAlive = (caps & NS_HTTP_ALLOW_KEEPALIVE);
|
||||
|
||||
|
@ -203,6 +208,9 @@ nsHttpConnection::Close(nsresult reason)
|
|||
NS_ABORT_IF_FALSE(PR_GetCurrentThread() == gSocketThread, "wrong thread");
|
||||
|
||||
if (NS_FAILED(reason)) {
|
||||
if (mIdleMonitoring)
|
||||
EndIdleMonitoring();
|
||||
|
||||
if (mSocketTransport) {
|
||||
mSocketTransport->SetSecurityCallbacks(nsnull);
|
||||
mSocketTransport->SetEventSink(nsnull, nsnull);
|
||||
|
@ -580,6 +588,34 @@ nsHttpConnection::ResumeRecv()
|
|||
return NS_ERROR_UNEXPECTED;
|
||||
}
|
||||
|
||||
void
|
||||
nsHttpConnection::BeginIdleMonitoring()
|
||||
{
|
||||
LOG(("nsHttpConnection::BeginIdleMonitoring [this=%p]\n", this));
|
||||
NS_ABORT_IF_FALSE(PR_GetCurrentThread() == gSocketThread, "wrong thread");
|
||||
NS_ABORT_IF_FALSE(!mTransaction, "BeginIdleMonitoring() while active");
|
||||
|
||||
LOG(("Entering Idle Monitoring Mode [this=%p]", this));
|
||||
mIdleMonitoring = PR_TRUE;
|
||||
if (mSocketIn)
|
||||
mSocketIn->AsyncWait(this, 0, 0, nsnull);
|
||||
}
|
||||
|
||||
void
|
||||
nsHttpConnection::EndIdleMonitoring()
|
||||
{
|
||||
LOG(("nsHttpConnection::EndIdleMonitoring [this=%p]\n", this));
|
||||
NS_ABORT_IF_FALSE(PR_GetCurrentThread() == gSocketThread, "wrong thread");
|
||||
NS_ABORT_IF_FALSE(!mTransaction, "EndIdleMonitoring() while active");
|
||||
|
||||
if (mIdleMonitoring) {
|
||||
LOG(("Leaving Idle Monitoring Mode [this=%p]", this));
|
||||
mIdleMonitoring = PR_FALSE;
|
||||
if (mSocketIn)
|
||||
mSocketIn->AsyncWait(nsnull, 0, 0, nsnull);
|
||||
}
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// nsHttpConnection <private>
|
||||
//-----------------------------------------------------------------------------
|
||||
|
@ -856,6 +892,25 @@ nsHttpConnection::OnInputStreamReady(nsIAsyncInputStream *in)
|
|||
NS_ASSERTION(in == mSocketIn, "unexpected stream");
|
||||
NS_ASSERTION(PR_GetCurrentThread() == gSocketThread, "wrong thread");
|
||||
|
||||
if (mIdleMonitoring) {
|
||||
NS_ABORT_IF_FALSE(!mTransaction, "Idle Input Event While Active");
|
||||
|
||||
// The only read event that is protocol compliant for an idle connection
|
||||
// is an EOF, which we check for with CanReuse(). If the data is
|
||||
// something else then just ignore it and suspend checking for EOF -
|
||||
// our normal timers or protocol stack are the place to deal with
|
||||
// any exception logic.
|
||||
|
||||
if (!CanReuse()) {
|
||||
LOG(("Server initiated close of idle conn %p\n", this));
|
||||
gHttpHandler->ConnMgr()->CloseIdleConnection(this);
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
LOG(("Input data on idle conn %p, but not closing yet\n", this));
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
// if the transaction was dropped...
|
||||
if (!mTransaction) {
|
||||
LOG((" no transaction; ignoring event\n"));
|
||||
|
|
|
@ -146,6 +146,13 @@ public:
|
|||
static NS_METHOD ReadFromStream(nsIInputStream *, void *, const char *,
|
||||
PRUint32, PRUint32, PRUint32 *);
|
||||
|
||||
// When a persistent connection is in the connection manager idle
|
||||
// connection pool, the nsHttpConnection still reads errors and hangups
|
||||
// on the socket so that it can be proactively released if the server
|
||||
// initiates a termination. Only call on socket thread.
|
||||
void BeginIdleMonitoring();
|
||||
void EndIdleMonitoring();
|
||||
|
||||
private:
|
||||
// called to cause the underlying socket to start speaking SSL
|
||||
nsresult ProxyStartSSL();
|
||||
|
@ -196,6 +203,7 @@ private:
|
|||
PRPackedBool mIsActivated;
|
||||
PRPackedBool mCompletedProxyConnect;
|
||||
PRPackedBool mLastTransactionExpectedNoContent;
|
||||
PRPackedBool mIdleMonitoring;
|
||||
};
|
||||
|
||||
#endif // nsHttpConnection_h__
|
||||
|
|
|
@ -383,6 +383,31 @@ nsHttpConnectionMgr::ProcessPendingQ(nsHttpConnectionInfo *ci)
|
|||
return rv;
|
||||
}
|
||||
|
||||
nsresult
|
||||
nsHttpConnectionMgr::CloseIdleConnection(nsHttpConnection *conn)
|
||||
{
|
||||
NS_ABORT_IF_FALSE(PR_GetCurrentThread() == gSocketThread, "wrong thread");
|
||||
LOG(("nsHttpConnectionMgr::CloseIdleConnection %p conn=%p",
|
||||
this, conn));
|
||||
|
||||
nsHttpConnectionInfo *ci = conn->ConnectionInfo();
|
||||
if (!ci)
|
||||
return NS_ERROR_UNEXPECTED;
|
||||
|
||||
nsCStringKey key(ci->HashKey());
|
||||
nsConnectionEntry *ent = (nsConnectionEntry *) mCT.Get(&key);
|
||||
|
||||
if (!ent || !ent->mIdleConns.RemoveElement(conn))
|
||||
return NS_ERROR_UNEXPECTED;
|
||||
|
||||
conn->Close(NS_ERROR_ABORT);
|
||||
NS_RELEASE(conn);
|
||||
mNumIdleConns--;
|
||||
if (0 == mNumIdleConns)
|
||||
StopPruneDeadConnectionsTimer();
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// enumeration callbacks
|
||||
|
||||
|
@ -689,8 +714,11 @@ nsHttpConnectionMgr::GetConnection(nsConnectionEntry *ent,
|
|||
conn->Close(NS_ERROR_ABORT);
|
||||
NS_RELEASE(conn);
|
||||
}
|
||||
else
|
||||
else {
|
||||
LOG((" reusing connection [conn=%x]\n", conn));
|
||||
conn->EndIdleMonitoring();
|
||||
}
|
||||
|
||||
ent->mIdleConns.RemoveElementAt(0);
|
||||
mNumIdleConns--;
|
||||
|
||||
|
@ -1091,6 +1119,7 @@ nsHttpConnectionMgr::OnMsgReclaimConnection(PRInt32, void *param)
|
|||
NS_ADDREF(conn);
|
||||
ent->mIdleConns.InsertElementAt(idx, conn);
|
||||
mNumIdleConns++;
|
||||
conn->BeginIdleMonitoring();
|
||||
|
||||
// If the added connection was first idle connection or has shortest
|
||||
// time to live among the idle connections, pruning dead
|
||||
|
|
|
@ -138,6 +138,11 @@ public:
|
|||
// preference to the specified connection.
|
||||
nsresult ProcessPendingQ(nsHttpConnectionInfo *);
|
||||
|
||||
// This is used to force an idle connection to be closed and removed from
|
||||
// the idle connection list. It is called when the idle connection detects
|
||||
// that the network peer has closed the transport.
|
||||
nsresult CloseIdleConnection(nsHttpConnection *);
|
||||
|
||||
private:
|
||||
virtual ~nsHttpConnectionMgr();
|
||||
class nsHalfOpenSocket;
|
||||
|
|
Загрузка…
Ссылка в новой задаче