bug 762162 - network.http.timeout-connection r=honzab

This commit is contained in:
Patrick McManus 2012-07-23 19:10:00 -04:00
parent 314a0f595f
commit 623040ca15
5 changed files with 89 additions and 14 deletions

View File

@ -868,6 +868,10 @@ pref("network.http.qos", 0);
// connection.
pref("network.http.connection-retry-timeout", 250);
// The number of seconds after sending initial SYN for an HTTP connection
// to give up if the OS does not give up first
pref("network.http.connection-timeout", 90);
// Disable IPv6 for backup connections to workaround problems about broken
// IPv6 connectivity.
pref("network.http.fast-fallback-to-IPv4", true);

View File

@ -1704,6 +1704,7 @@ void
nsHttpConnectionMgr::StartedConnect()
{
mNumActiveConns++;
ActivateTimeoutTick(); // likely disabled by RecvdConnect()
}
void
@ -2161,10 +2162,42 @@ nsHttpConnectionMgr::ReadTimeoutTickCB(const nsACString &key,
LOG(("nsHttpConnectionMgr::ReadTimeoutTickCB() this=%p host=%s\n",
self, ent->mConnInfo->Host()));
// first call the tick handler for each active connection
PRIntervalTime now = PR_IntervalNow();
for (PRUint32 index = 0; index < ent->mActiveConns.Length(); ++index)
ent->mActiveConns[index]->ReadTimeoutTick(now);
// now check for any stalled half open sockets
if (ent->mHalfOpens.Length()) {
TimeStamp now = TimeStamp::Now();
double maxConnectTime = gHttpHandler->ConnectTimeout(); /* in milliseconds */
for (PRUint32 index = ent->mHalfOpens.Length(); index > 0; ) {
index--;
nsHalfOpenSocket *half = ent->mHalfOpens[index];
double delta = half->Duration(now);
// If the socket has timed out, close it so the waiting transaction
// will get the proper signal
if (delta > maxConnectTime) {
LOG(("Force timeout of half open to %s after %.2fms.\n",
ent->mConnInfo->HashKey().get(), delta));
if (half->SocketTransport())
half->SocketTransport()->Close(NS_ERROR_NET_TIMEOUT);
if (half->BackupTransport())
half->BackupTransport()->Close(NS_ERROR_NET_TIMEOUT);
}
// If this half open hangs around for 5 seconds after we've closed() it
// then just abandon the socket.
if (delta > maxConnectTime + 5000) {
LOG(("Abandon half open to %s after %.2fms.\n",
ent->mConnInfo->HashKey().get(), delta));
half->Abandon();
}
}
}
return PL_DHASH_NEXT;
}
@ -2301,17 +2334,8 @@ nsHttpConnectionMgr::nsHalfOpenSocket::~nsHalfOpenSocket()
NS_ABORT_IF_FALSE(!mSynTimer, "syntimer not null");
LOG(("Destroying nsHalfOpenSocket [this=%p]\n", this));
if (mEnt) {
// A failure to create the transport object at all
// will result in this not being present in the halfopen table
// so ignore failures of RemoveElement()
mEnt->mHalfOpens.RemoveElement(this);
// If there are no unconnected half opens left in the array, then
// it is liekly that this dtor transitioned
if (!mEnt->UnconnectedHalfOpens())
gHttpHandler->ConnMgr()->ProcessPendingQForEntry(mEnt);
}
if (mEnt)
mEnt->RemoveHalfOpen(this);
}
nsresult
@ -2496,9 +2520,21 @@ nsHttpConnectionMgr::nsHalfOpenSocket::Abandon()
CancelBackupTimer();
if (mEnt)
mEnt->RemoveHalfOpen(this);
mEnt = nsnull;
}
double
nsHttpConnectionMgr::nsHalfOpenSocket::Duration(mozilla::TimeStamp epoch)
{
if (mPrimarySynStarted.IsNull())
return 0;
return (epoch - mPrimarySynStarted).ToMilliseconds();
}
NS_IMETHODIMP // method for nsITimerCallback
nsHttpConnectionMgr::nsHalfOpenSocket::Notify(nsITimer *timer)
{
@ -3023,3 +3059,17 @@ nsHttpConnectionMgr::nsConnectionEntry::UnconnectedHalfOpens()
}
return unconnectedHalfOpens;
}
void
nsHttpConnectionMgr::
nsConnectionEntry::RemoveHalfOpen(nsHalfOpenSocket *halfOpen)
{
// A failure to create the transport object at all
// will result in it not being present in the halfopen table
// so ignore failures of RemoveElement()
mHalfOpens.RemoveElement(halfOpen);
if (!UnconnectedHalfOpens())
// perhaps this reverted RestrictConnections()
gHttpHandler->ConnMgr()->ProcessPendingQForEntry(this);
}

View File

@ -265,6 +265,9 @@ private:
// connection complete
PRUint32 UnconnectedHalfOpens();
// Remove a particular half open socket from the mHalfOpens array
void RemoveHalfOpen(nsHalfOpenSocket *);
// Pipeline depths for various states
const static PRUint32 kPipelineUnlimited = 1024; // fully open - extended green
const static PRUint32 kPipelineOpen = 6; // 6 on each conn - normal green
@ -388,7 +391,10 @@ private:
void SetupBackupTimer();
void CancelBackupTimer();
void Abandon();
double Duration(mozilla::TimeStamp epoch);
nsISocketTransport *SocketTransport() { return mSocketTransport; }
nsISocketTransport *BackupTransport() { return mBackupTransport; }
nsAHttpTransaction *Transaction() { return mTransaction; }
bool IsSpeculative() { return mSpeculative; }
@ -580,8 +586,8 @@ private:
nsCOMPtr<nsITimer> mTimer;
// A 1s tick to call nsHttpConnection::ReadTimeoutTick on
// active http/1 connections. Disabled when there are no
// active connections.
// active http/1 connections and check for orphaned half opens.
// Disabled when there are no active or half open connections.
nsCOMPtr<nsITimer> mReadTimeoutTick;
bool mReadTimeoutTickArmed;

View File

@ -175,6 +175,7 @@ nsHttpHandler::nsHttpHandler()
, mSpdySendingChunkSize(ASpdySession::kSendingChunkSize)
, mSpdyPingThreshold(PR_SecondsToInterval(44))
, mSpdyPingTimeout(PR_SecondsToInterval(8))
, mConnectTimeout(90000)
{
#if defined(PR_LOGGING)
gHttpLog = PR_NewLogModule("nsHttp");
@ -1107,6 +1108,15 @@ nsHttpHandler::PrefsChanged(nsIPrefBranch *prefs, const char *pref)
PR_SecondsToInterval((PRUint16) clamped(val, 0, 0x7fffffff));
}
// The maximum amount of time to wait for socket transport to be
// established
if (PREF_CHANGED(HTTP_PREF("connection-timeout"))) {
rv = prefs->GetIntPref(HTTP_PREF("connection-timeout"), &val);
if (NS_SUCCEEDED(rv))
// the pref is in seconds, but the variable is in milliseconds
mConnectTimeout = clamped(val, 1, 0xffff) * PR_MSEC_PER_SEC;
}
// on transition of network.http.diagnostics to true print
// a bunch of information to the console
if (pref && PREF_CHANGED(HTTP_PREF("diagnostics"))) {

View File

@ -94,6 +94,7 @@ public:
PRUint32 SpdySendingChunkSize() { return mSpdySendingChunkSize; }
PRIntervalTime SpdyPingThreshold() { return mSpdyPingThreshold; }
PRIntervalTime SpdyPingTimeout() { return mSpdyPingTimeout; }
PRUint32 ConnectTimeout() { return mConnectTimeout; }
bool PromptTempRedirect() { return mPromptTempRedirect; }
@ -366,6 +367,10 @@ private:
PRUint32 mSpdySendingChunkSize;
PRIntervalTime mSpdyPingThreshold;
PRIntervalTime mSpdyPingTimeout;
// The maximum amount of time to wait for socket transport to be
// established. In milliseconds.
PRUint32 mConnectTimeout;
};
//-----------------------------------------------------------------------------