diff --git a/netwerk/protocol/http/nsHttpConnection.cpp b/netwerk/protocol/http/nsHttpConnection.cpp index bf6d2bbb288..e9ae768890c 100644 --- a/netwerk/protocol/http/nsHttpConnection.cpp +++ b/netwerk/protocol/http/nsHttpConnection.cpp @@ -86,6 +86,7 @@ nsHttpConnection::nsHttpConnection() , mIdleMonitoring(false) , mProxyConnectInProgress(false) , mHttp1xTransactionCount(0) + , mRemainingConnectionUses(0xffffffff) , mClassification(nsAHttpTransaction::CLASS_GENERAL) , mNPNComplete(false) , mSetupNPNCalled(false) @@ -534,9 +535,28 @@ nsHttpConnection::DontReuse() mSpdySession->DontReuse(); } +// Checked by the Connection Manager before scheduling a pipelined transaction +bool +nsHttpConnection::SupportsPipelining() +{ + if (mTransaction && + mTransaction->PipelineDepth() >= mRemainingConnectionUses) { + LOG(("nsHttpConnection::SupportsPipelining this=%p deny pipeline " + "because current depth %d exceeds max remaining uses %d\n", + this, mTransaction->PipelineDepth(), mRemainingConnectionUses)); + return false; + } + return mSupportsPipelining && IsKeepAlive(); +} + bool nsHttpConnection::CanReuse() { + if ((mTransaction ? mTransaction->PipelineDepth() : 0) >= + mRemainingConnectionUses) { + return false; + } + bool canReuse; if (mUsingSpdy) @@ -733,9 +753,13 @@ nsHttpConnection::OnHeadersAvailable(nsAHttpTransaction *trans, // HTTP/1.1 connections are by default persistent if (val && !PL_strcasecmp(val, "close")) { mKeepAlive = false; - // persistent connections are required for pipelining to work - gHttpHandler->ConnMgr()->PipelineFeedbackInfo( - mConnInfo, nsHttpConnectionMgr::BadExplicitClose, this, 0); + + // persistent connections are required for pipelining to work - if + // this close was not pre-announced then generate the negative + // BadExplicitClose feedback + if (mRemainingConnectionUses > 1) + gHttpHandler->ConnMgr()->PipelineFeedbackInfo( + mConnInfo, nsHttpConnectionMgr::BadExplicitClose, this, 0); } else { mKeepAlive = true; @@ -783,6 +807,7 @@ nsHttpConnection::OnHeadersAvailable(nsAHttpTransaction *trans, // a "keep-alive" connection is by definition capable of being reused, and // we only care about being able to reuse it once. if a timeout is not // specified then we use our advertized timeout value. + bool foundKeepAliveMax = false; if (mKeepAlive) { val = responseHead->PeekHeader(nsHttp::Keep_Alive); @@ -792,6 +817,15 @@ nsHttpConnection::OnHeadersAvailable(nsAHttpTransaction *trans, mIdleTimeout = PR_SecondsToInterval((PRUint32) atoi(cp + 8)); else mIdleTimeout = gHttpHandler->SpdyTimeout(); + + cp = PL_strcasestr(val, "max="); + if (cp) { + int val = atoi(cp + 4); + if (val > 0) { + foundKeepAliveMax = true; + mRemainingConnectionUses = static_cast(val); + } + } } else { mIdleTimeout = gHttpHandler->SpdyTimeout(); @@ -801,6 +835,9 @@ nsHttpConnection::OnHeadersAvailable(nsAHttpTransaction *trans, this, PR_IntervalToSeconds(mIdleTimeout))); } + if (!foundKeepAliveMax && mRemainingConnectionUses && !mUsingSpdy) + --mRemainingConnectionUses; + if (!mProxyConnectStream) HandleAlternateProtocol(responseHead); diff --git a/netwerk/protocol/http/nsHttpConnection.h b/netwerk/protocol/http/nsHttpConnection.h index 6239ef0f717..ba59f907654 100644 --- a/netwerk/protocol/http/nsHttpConnection.h +++ b/netwerk/protocol/http/nsHttpConnection.h @@ -106,7 +106,7 @@ public: //------------------------------------------------------------------------- // XXX document when these are ok to call - bool SupportsPipelining() { return mSupportsPipelining && IsKeepAlive(); } + bool SupportsPipelining(); bool IsKeepAlive() { return mUsingSpdy || (mKeepAliveMask && mKeepAlive); } bool CanReuse(); // can this connection be reused? @@ -250,6 +250,11 @@ private: // excludes spdy transactions. PRUint32 mHttp1xTransactionCount; + // Keep-Alive: max="mRemainingConnectionUses" provides the number of future + // transactions (including the current one) that the server expects to allow + // on this persistent connection. + PRUint32 mRemainingConnectionUses; + nsAHttpTransaction::Classifier mClassification; // SPDY related