bug 973207 - revert 905460 for nightly crashes r=backout

This commit is contained in:
Patrick McManus 2014-02-17 13:53:25 -05:00
parent 5413422a19
commit b03da0f6e7
10 changed files with 222 additions and 176 deletions

View File

@ -80,12 +80,12 @@ nsHttpConnection::nsHttpConnection()
, mResponseTimeoutEnabled(false) , mResponseTimeoutEnabled(false)
, mTCPKeepaliveConfig(kTCPKeepaliveDisabled) , mTCPKeepaliveConfig(kTCPKeepaliveDisabled)
{ {
LOG(("Creating nsHttpConnection @%p\n", this)); LOG(("Creating nsHttpConnection @%x\n", this));
} }
nsHttpConnection::~nsHttpConnection() nsHttpConnection::~nsHttpConnection()
{ {
LOG(("Destroying nsHttpConnection @%p\n", this)); LOG(("Destroying nsHttpConnection @%x\n", this));
ReportDataUsage(false); ReportDataUsage(false);
if (!mEverUsedSpdy) { if (!mEverUsedSpdy) {
@ -313,7 +313,7 @@ nsHttpConnection::Activate(nsAHttpTransaction *trans, uint32_t caps, int32_t pri
nsresult rv; nsresult rv;
MOZ_ASSERT(PR_GetCurrentThread() == gSocketThread); MOZ_ASSERT(PR_GetCurrentThread() == gSocketThread);
LOG(("nsHttpConnection::Activate [this=%p trans=%p caps=%x]\n", LOG(("nsHttpConnection::Activate [this=%p trans=%x caps=%x]\n",
this, trans, caps)); this, trans, caps));
if (!trans->IsNullTransaction()) if (!trans->IsNullTransaction())
@ -1247,7 +1247,7 @@ nsHttpConnection::EndIdleMonitoring()
void void
nsHttpConnection::CloseTransaction(nsAHttpTransaction *trans, nsresult reason) nsHttpConnection::CloseTransaction(nsAHttpTransaction *trans, nsresult reason)
{ {
LOG(("nsHttpConnection::CloseTransaction[this=%p trans=%p reason=%x]\n", LOG(("nsHttpConnection::CloseTransaction[this=%p trans=%x reason=%x]\n",
this, trans, reason)); this, trans, reason));
MOZ_ASSERT(trans == mTransaction, "wrong transaction"); MOZ_ASSERT(trans == mTransaction, "wrong transaction");
@ -1809,7 +1809,6 @@ nsHttpConnection::OnInputStreamReady(nsIAsyncInputStream *in)
if (!CanReuse()) { if (!CanReuse()) {
LOG(("Server initiated close of idle conn %p\n", this)); LOG(("Server initiated close of idle conn %p\n", this));
// CloseIdleConnection may delete "this" - return immediately
gHttpHandler->ConnMgr()->CloseIdleConnection(this); gHttpHandler->ConnMgr()->CloseIdleConnection(this);
return NS_OK; return NS_OK;
} }

View File

@ -27,7 +27,7 @@ nsHttpConnectionInfo::nsHttpConnectionInfo(const nsACString &host, int32_t port,
, mUsingSSL(usingSSL) , mUsingSSL(usingSSL)
, mUsingConnect(false) , mUsingConnect(false)
{ {
LOG(("Creating nsHttpConnectionInfo @%p\n", this)); LOG(("Creating nsHttpConnectionInfo @%x\n", this));
mUsingHttpProxy = (proxyInfo && proxyInfo->IsHTTP()); mUsingHttpProxy = (proxyInfo && proxyInfo->IsHTTP());

View File

@ -41,6 +41,25 @@ namespace net {
NS_IMPL_ISUPPORTS1(nsHttpConnectionMgr, nsIObserver) NS_IMPL_ISUPPORTS1(nsHttpConnectionMgr, nsIObserver)
static void
InsertTransactionSorted(nsTArray<nsHttpTransaction*> &pendingQ, nsHttpTransaction *trans)
{
// insert into queue with smallest valued number first. search in reverse
// order under the assumption that many of the existing transactions will
// have the same priority (usually 0).
for (int32_t i=pendingQ.Length()-1; i>=0; --i) {
nsHttpTransaction *t = pendingQ[i];
if (trans->Priority() >= t->Priority()) {
pendingQ.InsertElementAt(i+1, trans);
return;
}
}
pendingQ.InsertElementAt(0, trans);
}
//-----------------------------------------------------------------------------
nsHttpConnectionMgr::nsHttpConnectionMgr() nsHttpConnectionMgr::nsHttpConnectionMgr()
: mReentrantMonitor("nsHttpConnectionMgr.mReentrantMonitor") : mReentrantMonitor("nsHttpConnectionMgr.mReentrantMonitor")
, mMaxConns(0) , mMaxConns(0)
@ -55,12 +74,12 @@ nsHttpConnectionMgr::nsHttpConnectionMgr()
, mTimeoutTickArmed(false) , mTimeoutTickArmed(false)
, mTimeoutTickNext(1) , mTimeoutTickNext(1)
{ {
LOG(("Creating nsHttpConnectionMgr @%p\n", this)); LOG(("Creating nsHttpConnectionMgr @%x\n", this));
} }
nsHttpConnectionMgr::~nsHttpConnectionMgr() nsHttpConnectionMgr::~nsHttpConnectionMgr()
{ {
LOG(("Destroying nsHttpConnectionMgr @%p\n", this)); LOG(("Destroying nsHttpConnectionMgr @%x\n", this));
if (mTimeoutTick) if (mTimeoutTick)
mTimeoutTick->Cancel(); mTimeoutTick->Cancel();
} }
@ -158,7 +177,8 @@ nsHttpConnectionMgr::PostEvent(nsConnEventHandler handler, int32_t iparam, void
if (!mSocketThreadTarget) { if (!mSocketThreadTarget) {
NS_WARNING("cannot post event if not initialized"); NS_WARNING("cannot post event if not initialized");
rv = NS_ERROR_NOT_INITIALIZED; rv = NS_ERROR_NOT_INITIALIZED;
} else { }
else {
nsRefPtr<nsIRunnable> event = new nsConnEvent(this, handler, iparam, vparam); nsRefPtr<nsIRunnable> event = new nsConnEvent(this, handler, iparam, vparam);
rv = mSocketThreadTarget->Dispatch(event, NS_DISPATCH_NORMAL); rv = mSocketThreadTarget->Dispatch(event, NS_DISPATCH_NORMAL);
} }
@ -234,9 +254,11 @@ nsHttpConnectionMgr::Observe(nsISupports *subject,
nsCOMPtr<nsITimer> timer = do_QueryInterface(subject); nsCOMPtr<nsITimer> timer = do_QueryInterface(subject);
if (timer == mTimer) { if (timer == mTimer) {
PruneDeadConnections(); PruneDeadConnections();
} else if (timer == mTimeoutTick) { }
else if (timer == mTimeoutTick) {
TimeoutTick(); TimeoutTick();
} else { }
else {
MOZ_ASSERT(false, "unexpected timer-callback"); MOZ_ASSERT(false, "unexpected timer-callback");
LOG(("Unexpected timer object\n")); LOG(("Unexpected timer object\n"));
return NS_ERROR_UNEXPECTED; return NS_ERROR_UNEXPECTED;
@ -250,42 +272,39 @@ nsHttpConnectionMgr::Observe(nsISupports *subject,
//----------------------------------------------------------------------------- //-----------------------------------------------------------------------------
nsresult nsresult
nsHttpConnectionMgr::AddTransaction(nsHttpTransaction *aTrans, int32_t priority) nsHttpConnectionMgr::AddTransaction(nsHttpTransaction *trans, int32_t priority)
{ {
LOG(("nsHttpConnectionMgr::AddTransaction [trans=%p %d]\n", aTrans, priority)); LOG(("nsHttpConnectionMgr::AddTransaction [trans=%x %d]\n", trans, priority));
nsRefPtr<nsHttpTransaction> trans(aTrans); NS_ADDREF(trans);
nsresult rv = PostEvent(&nsHttpConnectionMgr::OnMsgNewTransaction, priority, trans); nsresult rv = PostEvent(&nsHttpConnectionMgr::OnMsgNewTransaction, priority, trans);
if (NS_SUCCEEDED(rv)) { if (NS_FAILED(rv))
trans.forget(); NS_RELEASE(trans);
}
return rv; return rv;
} }
nsresult nsresult
nsHttpConnectionMgr::RescheduleTransaction(nsHttpTransaction *aTrans, int32_t priority) nsHttpConnectionMgr::RescheduleTransaction(nsHttpTransaction *trans, int32_t priority)
{ {
LOG(("nsHttpConnectionMgr::RescheduleTransaction [trans=%p %d]\n", aTrans, priority)); LOG(("nsHttpConnectionMgr::RescheduleTransaction [trans=%x %d]\n", trans, priority));
nsRefPtr<nsHttpTransaction> trans(aTrans); NS_ADDREF(trans);
nsresult rv = PostEvent(&nsHttpConnectionMgr::OnMsgReschedTransaction, priority, trans); nsresult rv = PostEvent(&nsHttpConnectionMgr::OnMsgReschedTransaction, priority, trans);
if (NS_SUCCEEDED(rv)) { if (NS_FAILED(rv))
trans.forget(); NS_RELEASE(trans);
}
return rv; return rv;
} }
nsresult nsresult
nsHttpConnectionMgr::CancelTransaction(nsHttpTransaction *aTrans, nsresult reason) nsHttpConnectionMgr::CancelTransaction(nsHttpTransaction *trans, nsresult reason)
{ {
LOG(("nsHttpConnectionMgr::CancelTransaction [trans=%p reason=%x]\n", aTrans, reason)); LOG(("nsHttpConnectionMgr::CancelTransaction [trans=%x reason=%x]\n", trans, reason));
nsRefPtr<nsHttpTransaction> trans(aTrans); NS_ADDREF(trans);
nsresult rv = PostEvent(&nsHttpConnectionMgr::OnMsgCancelTransaction, nsresult rv = PostEvent(&nsHttpConnectionMgr::OnMsgCancelTransaction,
static_cast<int32_t>(reason), trans); static_cast<int32_t>(reason), trans);
if (NS_SUCCEEDED(rv)) { if (NS_FAILED(rv))
trans.forget(); NS_RELEASE(trans);
}
return rv; return rv;
} }
@ -302,9 +321,8 @@ nsHttpConnectionMgr::DoShiftReloadConnectionCleanup(nsHttpConnectionInfo *aCI)
nsresult rv = PostEvent(&nsHttpConnectionMgr::OnMsgDoShiftReloadConnectionCleanup, nsresult rv = PostEvent(&nsHttpConnectionMgr::OnMsgDoShiftReloadConnectionCleanup,
0, connInfo); 0, connInfo);
if (NS_SUCCEEDED(rv)) { if (NS_SUCCEEDED(rv))
connInfo.forget(); connInfo.forget();
}
return rv; return rv;
} }
@ -378,9 +396,8 @@ nsHttpConnectionMgr::SpeculativeConnect(nsHttpConnectionInfo *ci,
nsresult rv = nsresult rv =
PostEvent(&nsHttpConnectionMgr::OnMsgSpeculativeConnect, 0, args); PostEvent(&nsHttpConnectionMgr::OnMsgSpeculativeConnect, 0, args);
if (NS_SUCCEEDED(rv)) { if (NS_SUCCEEDED(rv))
args.forget(); args.forget();
}
return rv; return rv;
} }
@ -395,15 +412,14 @@ nsHttpConnectionMgr::GetSocketThreadTarget(nsIEventTarget **target)
} }
nsresult nsresult
nsHttpConnectionMgr::ReclaimConnection(nsHttpConnection *aConn) nsHttpConnectionMgr::ReclaimConnection(nsHttpConnection *conn)
{ {
LOG(("nsHttpConnectionMgr::ReclaimConnection [conn=%p]\n", aConn)); LOG(("nsHttpConnectionMgr::ReclaimConnection [conn=%x]\n", conn));
nsRefPtr<nsHttpConnection> conn(aConn); NS_ADDREF(conn);
nsresult rv = PostEvent(&nsHttpConnectionMgr::OnMsgReclaimConnection, 0, conn); nsresult rv = PostEvent(&nsHttpConnectionMgr::OnMsgReclaimConnection, 0, conn);
if (NS_SUCCEEDED(rv)) { if (NS_FAILED(rv))
conn.forget(); NS_RELEASE(conn);
}
return rv; return rv;
} }
@ -428,9 +444,8 @@ nsHttpConnectionMgr::CompleteUpgrade(nsAHttpConnection *aConn,
new nsCompleteUpgradeData(aConn, aUpgradeListener); new nsCompleteUpgradeData(aConn, aUpgradeListener);
nsresult rv; nsresult rv;
rv = PostEvent(&nsHttpConnectionMgr::OnMsgCompleteUpgrade, 0, data); rv = PostEvent(&nsHttpConnectionMgr::OnMsgCompleteUpgrade, 0, data);
if (NS_FAILED(rv)) { if (NS_FAILED(rv))
delete data; delete data;
}
return rv; return rv;
} }
@ -443,15 +458,14 @@ nsHttpConnectionMgr::UpdateParam(nsParamName name, uint16_t value)
} }
nsresult nsresult
nsHttpConnectionMgr::ProcessPendingQ(nsHttpConnectionInfo *aCI) nsHttpConnectionMgr::ProcessPendingQ(nsHttpConnectionInfo *ci)
{ {
LOG(("nsHttpConnectionMgr::ProcessPendingQ [ci=%s]\n", aCI->HashKey().get())); LOG(("nsHttpConnectionMgr::ProcessPendingQ [ci=%s]\n", ci->HashKey().get()));
nsRefPtr<nsHttpConnectionInfo> ci(aCI); NS_ADDREF(ci);
nsresult rv = PostEvent(&nsHttpConnectionMgr::OnMsgProcessPendingQ, 0, ci); nsresult rv = PostEvent(&nsHttpConnectionMgr::OnMsgProcessPendingQ, 0, ci);
if (NS_SUCCEEDED(rv)) { if (NS_FAILED(rv))
ci.forget(); NS_RELEASE(ci);
}
return rv; return rv;
} }
@ -479,9 +493,8 @@ nsHttpConnectionMgr::UpdateRequestTokenBucket(EventTokenBucket *aBucket)
// to post the new value to the socket thread. // to post the new value to the socket thread.
nsresult rv = PostEvent(&nsHttpConnectionMgr::OnMsgUpdateRequestTokenBucket, nsresult rv = PostEvent(&nsHttpConnectionMgr::OnMsgUpdateRequestTokenBucket,
0, bucket.get()); 0, bucket.get());
if (NS_SUCCEEDED(rv)) { if (NS_SUCCEEDED(rv))
bucket.forget(); bucket.forget();
}
return rv; return rv;
} }
@ -535,7 +548,6 @@ nsHttpConnectionMgr::CloseIdleConnection(nsHttpConnection *conn)
MOZ_ASSERT(PR_GetCurrentThread() == gSocketThread); MOZ_ASSERT(PR_GetCurrentThread() == gSocketThread);
LOG(("nsHttpConnectionMgr::CloseIdleConnection %p conn=%p", LOG(("nsHttpConnectionMgr::CloseIdleConnection %p conn=%p",
this, conn)); this, conn));
nsRefPtr<nsHttpConnection> deleteProtector(conn);
if (!conn->ConnectionInfo()) if (!conn->ConnectionInfo())
return NS_ERROR_UNEXPECTED; return NS_ERROR_UNEXPECTED;
@ -547,7 +559,7 @@ nsHttpConnectionMgr::CloseIdleConnection(nsHttpConnection *conn)
return NS_ERROR_UNEXPECTED; return NS_ERROR_UNEXPECTED;
conn->Close(NS_ERROR_ABORT); conn->Close(NS_ERROR_ABORT);
conn = nullptr; NS_RELEASE(conn);
mNumIdleConns--; mNumIdleConns--;
ConditionallyStopPruneDeadConnectionsTimer(); ConditionallyStopPruneDeadConnectionsTimer();
return NS_OK; return NS_OK;
@ -841,10 +853,10 @@ nsHttpConnectionMgr::PurgeExcessIdleConnectionsCB(const nsACString &key,
// There are no idle conns left in this connection entry // There are no idle conns left in this connection entry
return PL_DHASH_NEXT; return PL_DHASH_NEXT;
} }
nsRefPtr<nsHttpConnection> conn(ent->mIdleConns[0]); nsHttpConnection *conn = ent->mIdleConns[0];
ent->mIdleConns.RemoveElementAt(0); ent->mIdleConns.RemoveElementAt(0);
conn->Close(NS_ERROR_ABORT); conn->Close(NS_ERROR_ABORT);
conn = nullptr; NS_RELEASE(conn);
self->mNumIdleConns--; self->mNumIdleConns--;
self->ConditionallyStopPruneDeadConnectionsTimer(); self->ConditionallyStopPruneDeadConnectionsTimer();
} }
@ -890,15 +902,15 @@ nsHttpConnectionMgr::PruneDeadConnectionsCB(const nsACString &key,
uint32_t timeToNextExpire = UINT32_MAX; uint32_t timeToNextExpire = UINT32_MAX;
int32_t count = ent->mIdleConns.Length(); int32_t count = ent->mIdleConns.Length();
if (count > 0) { if (count > 0) {
for (int32_t i = count - 1; i >= 0; --i) { for (int32_t i=count-1; i>=0; --i) {
if (!ent->mIdleConns[i]->CanReuse()) { nsHttpConnection *conn = ent->mIdleConns[i];
nsRefPtr<nsHttpConnection> conn(ent->mIdleConns[i]); if (!conn->CanReuse()) {
ent->mIdleConns.RemoveElementAt(i); ent->mIdleConns.RemoveElementAt(i);
conn->Close(NS_ERROR_ABORT); conn->Close(NS_ERROR_ABORT);
NS_RELEASE(conn);
self->mNumIdleConns--; self->mNumIdleConns--;
} else { } else {
timeToNextExpire = std::min(timeToNextExpire, timeToNextExpire = std::min(timeToNextExpire, conn->TimeToLive());
ent->mIdleConns[i]->TimeToLive());
} }
} }
} }
@ -911,7 +923,8 @@ nsHttpConnectionMgr::PruneDeadConnectionsCB(const nsACString &key,
// marking it dont reuse will create an active tear down if // marking it dont reuse will create an active tear down if
// the spdy session is idle. // the spdy session is idle.
conn->DontReuse(); conn->DontReuse();
} else { }
else {
timeToNextExpire = std::min(timeToNextExpire, timeToNextExpire = std::min(timeToNextExpire,
conn->TimeToLive()); conn->TimeToLive());
} }
@ -967,32 +980,42 @@ nsHttpConnectionMgr::ShutdownPassCB(const nsACString &key,
{ {
nsHttpConnectionMgr *self = (nsHttpConnectionMgr *) closure; nsHttpConnectionMgr *self = (nsHttpConnectionMgr *) closure;
// close all active connections and release list references nsHttpTransaction *trans;
nsHttpConnection *conn;
// close all active connections
while (ent->mActiveConns.Length()) { while (ent->mActiveConns.Length()) {
nsRefPtr<nsHttpConnection> conn(ent->mActiveConns[0]); conn = ent->mActiveConns[0];
ent->mActiveConns.RemoveElementAt(0); ent->mActiveConns.RemoveElementAt(0);
self->DecrementActiveConnCount(conn); self->DecrementActiveConnCount(conn);
conn->Close(NS_ERROR_ABORT); conn->Close(NS_ERROR_ABORT);
NS_RELEASE(conn);
} }
// close all idle connections and release list references // close all idle connections
while (ent->mIdleConns.Length()) { while (ent->mIdleConns.Length()) {
nsRefPtr<nsHttpConnection> conn(ent->mIdleConns[0]); conn = ent->mIdleConns[0];
ent->mIdleConns.RemoveElementAt(0); ent->mIdleConns.RemoveElementAt(0);
self->mNumIdleConns--; self->mNumIdleConns--;
conn->Close(NS_ERROR_ABORT); conn->Close(NS_ERROR_ABORT);
NS_RELEASE(conn);
} }
// If all idle connections are removed, // If all idle connections are removed,
// we can stop pruning dead connections. // we can stop pruning dead connections.
self->ConditionallyStopPruneDeadConnectionsTimer(); self->ConditionallyStopPruneDeadConnectionsTimer();
// close all pending transactions and release list references // close all pending transactions
while (ent->mPendingQ.Length()) { while (ent->mPendingQ.Length()) {
nsRefPtr<nsHttpTransaction> trans(ent->mPendingQ[0]); trans = ent->mPendingQ[0];
ent->mPendingQ.RemoveElementAt(0); ent->mPendingQ.RemoveElementAt(0);
trans->Close(NS_ERROR_ABORT); trans->Close(NS_ERROR_ABORT);
NS_RELEASE(trans);
} }
// close all half open tcp connections // close all half open tcp connections
@ -1047,6 +1070,7 @@ nsHttpConnectionMgr::ProcessPendingQForEntry(nsConnectionEntry *ent, bool consid
if (ent->mPendingQ.RemoveElement(trans)) { if (ent->mPendingQ.RemoveElement(trans)) {
dispatchedSuccessfully = true; dispatchedSuccessfully = true;
NS_RELEASE(trans);
continue; // dont ++i as we just made the array shorter continue; // dont ++i as we just made the array shorter
} }
@ -1239,10 +1263,11 @@ nsHttpConnectionMgr::ClosePersistentConnections(nsConnectionEntry *ent)
LOG(("nsHttpConnectionMgr::ClosePersistentConnections [ci=%s]\n", LOG(("nsHttpConnectionMgr::ClosePersistentConnections [ci=%s]\n",
ent->mConnInfo->HashKey().get())); ent->mConnInfo->HashKey().get()));
while (ent->mIdleConns.Length()) { while (ent->mIdleConns.Length()) {
nsRefPtr<nsHttpConnection> conn(ent->mIdleConns[0]); nsHttpConnection *conn = ent->mIdleConns[0];
ent->mIdleConns.RemoveElementAt(0); ent->mIdleConns.RemoveElementAt(0);
mNumIdleConns--; mNumIdleConns--;
conn->Close(NS_ERROR_ABORT); conn->Close(NS_ERROR_ABORT);
NS_RELEASE(conn);
} }
int32_t activeCount = ent->mActiveConns.Length(); int32_t activeCount = ent->mActiveConns.Length();
@ -1455,9 +1480,8 @@ nsHttpConnectionMgr::AddToShortestPipeline(nsConnectionEntry *ent,
activeTrans = bestConn->Transaction(); activeTrans = bestConn->Transaction();
nsresult rv = activeTrans->AddTransaction(trans); nsresult rv = activeTrans->AddTransaction(trans);
if (NS_FAILED(rv)) { if (NS_FAILED(rv))
return false; return false;
}
LOG((" scheduling trans %p on pipeline at position %d\n", LOG((" scheduling trans %p on pipeline at position %d\n",
trans, trans->PipelinePosition())); trans, trans->PipelinePosition()));
@ -1563,7 +1587,7 @@ nsHttpConnectionMgr::TryDispatchTransaction(nsConnectionEntry *ent,
nsRefPtr<nsHttpConnection> conn = GetSpdyPreferredConn(ent); nsRefPtr<nsHttpConnection> conn = GetSpdyPreferredConn(ent);
if (conn) { if (conn) {
if ((caps & NS_HTTP_ALLOW_KEEPALIVE) || !conn->IsExperienced()) { if ((caps & NS_HTTP_ALLOW_KEEPALIVE) || !conn->IsExperienced()) {
LOG((" dispatch to spdy: [conn=%p]\n", conn.get())); LOG((" dispatch to spdy: [conn=%x]\n", conn.get()));
trans->RemoveDispatchedAsBlocking(); /* just in case */ trans->RemoveDispatchedAsBlocking(); /* just in case */
DispatchTransaction(ent, trans, conn); DispatchTransaction(ent, trans, conn);
return NS_OK; return NS_OK;
@ -1589,7 +1613,8 @@ nsHttpConnectionMgr::TryDispatchTransaction(nsConnectionEntry *ent,
} }
} }
} }
} else { }
else {
// Mark the transaction and its load group as blocking right now to prevent // Mark the transaction and its load group as blocking right now to prevent
// other transactions from being reordered in the queue due to slow syns. // other transactions from being reordered in the queue due to slow syns.
trans->DispatchedAsBlocking(); trans->DispatchedAsBlocking();
@ -1631,15 +1656,18 @@ nsHttpConnectionMgr::TryDispatchTransaction(nsConnectionEntry *ent,
conn = ent->mIdleConns[0]; conn = ent->mIdleConns[0];
ent->mIdleConns.RemoveElementAt(0); ent->mIdleConns.RemoveElementAt(0);
mNumIdleConns--; mNumIdleConns--;
nsHttpConnection *temp = conn;
NS_RELEASE(temp);
// we check if the connection can be reused before even checking if // we check if the connection can be reused before even checking if
// it is a "matching" connection. // it is a "matching" connection.
if (!conn->CanReuse()) { if (!conn->CanReuse()) {
LOG((" dropping stale connection: [conn=%p]\n", conn.get())); LOG((" dropping stale connection: [conn=%x]\n", conn.get()));
conn->Close(NS_ERROR_ABORT); conn->Close(NS_ERROR_ABORT);
conn = nullptr; conn = nullptr;
} else { }
LOG((" reusing connection [conn=%p]\n", conn.get())); else {
LOG((" reusing connection [conn=%x]\n", conn.get()));
conn->EndIdleMonitoring(); conn->EndIdleMonitoring();
} }
@ -1714,7 +1742,7 @@ nsHttpConnectionMgr::DispatchTransaction(nsConnectionEntry *ent,
nsresult rv; nsresult rv;
LOG(("nsHttpConnectionMgr::DispatchTransaction " LOG(("nsHttpConnectionMgr::DispatchTransaction "
"[ci=%s trans=%p caps=%x conn=%p priority=%d]\n", "[ci=%s trans=%x caps=%x conn=%x priority=%d]\n",
ent->mConnInfo->HashKey().get(), trans, caps, conn, priority)); ent->mConnInfo->HashKey().get(), trans, caps, conn, priority));
// It is possible for a rate-paced transaction to be dispatched independent // It is possible for a rate-paced transaction to be dispatched independent
@ -1774,7 +1802,7 @@ nsHttpConnectionMgr::DispatchAbstractTransaction(nsConnectionEntry *ent,
MOZ_ASSERT(!conn->UsingSpdy(), MOZ_ASSERT(!conn->UsingSpdy(),
"Spdy Must Not Use DispatchAbstractTransaction"); "Spdy Must Not Use DispatchAbstractTransaction");
LOG(("nsHttpConnectionMgr::DispatchAbstractTransaction " LOG(("nsHttpConnectionMgr::DispatchAbstractTransaction "
"[ci=%s trans=%p caps=%x conn=%p]\n", "[ci=%s trans=%x caps=%x conn=%x]\n",
ent->mConnInfo->HashKey().get(), aTrans, caps, conn)); ent->mConnInfo->HashKey().get(), aTrans, caps, conn));
/* Use pipeline datastructure even if connection does not currently qualify /* Use pipeline datastructure even if connection does not currently qualify
@ -1792,7 +1820,8 @@ nsHttpConnectionMgr::DispatchAbstractTransaction(nsConnectionEntry *ent,
if (!NS_SUCCEEDED(rv)) if (!NS_SUCCEEDED(rv))
return rv; return rv;
transaction = pipeline; transaction = pipeline;
} else { }
else {
LOG((" not using pipeline datastructure due to class solo.\n")); LOG((" not using pipeline datastructure due to class solo.\n"));
transaction = aTrans; transaction = aTrans;
} }
@ -1805,7 +1834,6 @@ nsHttpConnectionMgr::DispatchAbstractTransaction(nsConnectionEntry *ent,
rv = conn->Activate(transaction, caps, priority); rv = conn->Activate(transaction, caps, priority);
if (NS_FAILED(rv)) { if (NS_FAILED(rv)) {
LOG((" conn->Activate failed [rv=%x]\n", rv)); LOG((" conn->Activate failed [rv=%x]\n", rv));
nsRefPtr<nsHttpConnection> deleteProtector(conn);
ent->mActiveConns.RemoveElement(conn); ent->mActiveConns.RemoveElement(conn);
if (conn == ent->mYellowConnection) if (conn == ent->mYellowConnection)
ent->OnYellowComplete(); ent->OnYellowComplete();
@ -1815,7 +1843,9 @@ nsHttpConnectionMgr::DispatchAbstractTransaction(nsConnectionEntry *ent,
// sever back references to connection, and do so without triggering // sever back references to connection, and do so without triggering
// a call to ReclaimConnection ;-) // a call to ReclaimConnection ;-)
transaction->SetConnection(nullptr); transaction->SetConnection(nullptr);
handle->Reset(); NS_RELEASE(handle->mConn);
// destroy the connection
NS_RELEASE(conn);
} }
// As transaction goes out of scope it will drop the last refernece to the // As transaction goes out of scope it will drop the last refernece to the
@ -1841,7 +1871,7 @@ nsHttpConnectionMgr::BuildPipeline(nsConnectionEntry *ent,
nsRefPtr<nsHttpPipeline> pipeline = new nsHttpPipeline(); nsRefPtr<nsHttpPipeline> pipeline = new nsHttpPipeline();
pipeline->AddTransaction(firstTrans); pipeline->AddTransaction(firstTrans);
pipeline.forget(result); NS_ADDREF(*result = pipeline);
return NS_OK; return NS_OK;
} }
@ -1922,9 +1952,10 @@ nsHttpConnectionMgr::ProcessNewTransaction(nsHttpTransaction *trans)
if (rv == NS_ERROR_NOT_AVAILABLE) { if (rv == NS_ERROR_NOT_AVAILABLE) {
LOG((" adding transaction to pending queue " LOG((" adding transaction to pending queue "
"[trans=%p pending-count=%u]\n", "[trans=%p pending-count=%u]\n",
trans, ent->mPendingQ.Length() + 1)); trans, ent->mPendingQ.Length()+1));
// put this transaction on the pending queue... // put this transaction on the pending queue...
InsertTransactionSorted(ent->mPendingQ, trans); InsertTransactionSorted(ent->mPendingQ, trans);
NS_ADDREF(trans);
return NS_OK; return NS_OK;
} }
@ -1932,10 +1963,12 @@ nsHttpConnectionMgr::ProcessNewTransaction(nsHttpTransaction *trans)
return rv; return rv;
} }
void void
nsHttpConnectionMgr::AddActiveConn(nsHttpConnection *conn, nsHttpConnectionMgr::AddActiveConn(nsHttpConnection *conn,
nsConnectionEntry *ent) nsConnectionEntry *ent)
{ {
NS_ADDREF(conn);
ent->mActiveConns.AppendElement(conn); ent->mActiveConns.AppendElement(conn);
mNumActiveConns++; mNumActiveConns++;
ActivateTimeoutTick(); ActivateTimeoutTick();
@ -1995,7 +2028,7 @@ nsHttpConnectionMgr::ProcessSpdyPendingQ(nsConnectionEntry *ent)
if (!conn || !conn->CanDirectlyActivate()) if (!conn || !conn->CanDirectlyActivate())
return; return;
nsTArray<nsRefPtr<nsHttpTransaction> > leftovers; nsTArray<nsHttpTransaction*> leftovers;
uint32_t index; uint32_t index;
// Dispatch all the transactions we can // Dispatch all the transactions we can
@ -2016,15 +2049,17 @@ nsHttpConnectionMgr::ProcessSpdyPendingQ(nsConnectionEntry *ent)
// close the transaction // close the transaction
MOZ_ASSERT(false, "Dispatch SPDY Transaction"); MOZ_ASSERT(false, "Dispatch SPDY Transaction");
LOG(("ProcessSpdyPendingQ Dispatch Transaction failed trans=%p\n", LOG(("ProcessSpdyPendingQ Dispatch Transaction failed trans=%p\n",
trans)); trans));
trans->Close(rv); trans->Close(rv);
} }
NS_RELEASE(trans);
} }
// Slurp up the rest of the pending queue into our leftovers bucket (we // Slurp up the rest of the pending queue into our leftovers bucket (we
// might have some left if conn->CanDirectlyActivate returned false) // might have some left if conn->CanDirectlyActivate returned false)
for (; index < ent->mPendingQ.Length(); ++index) { for (; index < ent->mPendingQ.Length(); ++index) {
leftovers.AppendElement(ent->mPendingQ[index]); nsHttpTransaction *trans = ent->mPendingQ[index];
leftovers.AppendElement(trans);
} }
// Put the leftovers back in the pending queue and get rid of the // Put the leftovers back in the pending queue and get rid of the
@ -2120,13 +2155,12 @@ nsHttpConnectionMgr::OnMsgNewTransaction(int32_t priority, void *param)
{ {
LOG(("nsHttpConnectionMgr::OnMsgNewTransaction [trans=%p]\n", param)); LOG(("nsHttpConnectionMgr::OnMsgNewTransaction [trans=%p]\n", param));
nsRefPtr<nsHttpTransaction> trans = nsHttpTransaction *trans = (nsHttpTransaction *) param;
dont_AddRef(static_cast<nsHttpTransaction *>(param));
trans->SetPriority(priority); trans->SetPriority(priority);
nsresult rv = ProcessNewTransaction(trans); nsresult rv = ProcessNewTransaction(trans);
if (NS_FAILED(rv)) { if (NS_FAILED(rv))
trans->Close(rv); // for whatever its worth trans->Close(rv); // for whatever its worth
} NS_RELEASE(trans);
} }
void void
@ -2135,8 +2169,7 @@ nsHttpConnectionMgr::OnMsgReschedTransaction(int32_t priority, void *param)
MOZ_ASSERT(PR_GetCurrentThread() == gSocketThread); MOZ_ASSERT(PR_GetCurrentThread() == gSocketThread);
LOG(("nsHttpConnectionMgr::OnMsgReschedTransaction [trans=%p]\n", param)); LOG(("nsHttpConnectionMgr::OnMsgReschedTransaction [trans=%p]\n", param));
nsRefPtr<nsHttpTransaction> trans = nsHttpTransaction *trans = (nsHttpTransaction *) param;
dont_AddRef(static_cast<nsHttpTransaction *>(param));
trans->SetPriority(priority); trans->SetPriority(priority);
nsConnectionEntry *ent = LookupConnectionEntry(trans->ConnectionInfo(), nsConnectionEntry *ent = LookupConnectionEntry(trans->ConnectionInfo(),
@ -2149,6 +2182,8 @@ nsHttpConnectionMgr::OnMsgReschedTransaction(int32_t priority, void *param)
InsertTransactionSorted(ent->mPendingQ, trans); InsertTransactionSorted(ent->mPendingQ, trans);
} }
} }
NS_RELEASE(trans);
} }
void void
@ -2158,8 +2193,7 @@ nsHttpConnectionMgr::OnMsgCancelTransaction(int32_t reason, void *param)
LOG(("nsHttpConnectionMgr::OnMsgCancelTransaction [trans=%p]\n", param)); LOG(("nsHttpConnectionMgr::OnMsgCancelTransaction [trans=%p]\n", param));
nsresult closeCode = static_cast<nsresult>(reason); nsresult closeCode = static_cast<nsresult>(reason);
nsRefPtr<nsHttpTransaction> trans = nsHttpTransaction *trans = (nsHttpTransaction *) param;
dont_AddRef(static_cast<nsHttpTransaction *>(param));
// //
// if the transaction owns a connection and the transaction is not done, // if the transaction owns a connection and the transaction is not done,
// then ask the connection to close the transaction. otherwise, close the // then ask the connection to close the transaction. otherwise, close the
@ -2176,8 +2210,10 @@ nsHttpConnectionMgr::OnMsgCancelTransaction(int32_t reason, void *param)
int32_t index = ent->mPendingQ.IndexOf(trans); int32_t index = ent->mPendingQ.IndexOf(trans);
if (index >= 0) { if (index >= 0) {
LOG(("nsHttpConnectionMgr::OnMsgCancelTransaction [trans=%p]" LOG(("nsHttpConnectionMgr::OnMsgCancelTransaction [trans=%p]"
" found in pending queue\n", trans.get())); " found in pending queue\n", trans));
ent->mPendingQ.RemoveElementAt(index); ent->mPendingQ.RemoveElementAt(index);
nsHttpTransaction *temp = trans;
NS_RELEASE(temp); // b/c NS_RELEASE nulls its argument!
} }
} }
trans->Close(closeCode); trans->Close(closeCode);
@ -2196,19 +2232,19 @@ nsHttpConnectionMgr::OnMsgCancelTransaction(int32_t reason, void *param)
if (liveTransaction && liveTransaction->IsNullTransaction()) { if (liveTransaction && liveTransaction->IsNullTransaction()) {
LOG(("nsHttpConnectionMgr::OnMsgCancelTransaction [trans=%p] " LOG(("nsHttpConnectionMgr::OnMsgCancelTransaction [trans=%p] "
"also canceling Null Transaction %p on conn %p\n", "also canceling Null Transaction %p on conn %p\n",
trans.get(), liveTransaction, activeConn)); trans, liveTransaction, activeConn));
activeConn->CloseTransaction(liveTransaction, closeCode); activeConn->CloseTransaction(liveTransaction, closeCode);
} }
} }
} }
NS_RELEASE(trans);
} }
void void
nsHttpConnectionMgr::OnMsgProcessPendingQ(int32_t, void *param) nsHttpConnectionMgr::OnMsgProcessPendingQ(int32_t, void *param)
{ {
MOZ_ASSERT(PR_GetCurrentThread() == gSocketThread); MOZ_ASSERT(PR_GetCurrentThread() == gSocketThread);
nsRefPtr<nsHttpConnectionInfo> ci = nsHttpConnectionInfo *ci = (nsHttpConnectionInfo *) param;
dont_AddRef(static_cast<nsHttpConnectionInfo *>(param));
if (!ci) { if (!ci) {
LOG(("nsHttpConnectionMgr::OnMsgProcessPendingQ [ci=nullptr]\n")); LOG(("nsHttpConnectionMgr::OnMsgProcessPendingQ [ci=nullptr]\n"));
@ -2227,6 +2263,8 @@ nsHttpConnectionMgr::OnMsgProcessPendingQ(int32_t, void *param)
// for the specified connection info. walk the connection table... // for the specified connection info. walk the connection table...
mCT.Enumerate(ProcessOneTransactionCB, this); mCT.Enumerate(ProcessOneTransactionCB, this);
} }
NS_RELEASE(ci);
} }
void void
@ -2264,8 +2302,7 @@ nsHttpConnectionMgr::OnMsgReclaimConnection(int32_t, void *param)
MOZ_ASSERT(PR_GetCurrentThread() == gSocketThread); MOZ_ASSERT(PR_GetCurrentThread() == gSocketThread);
LOG(("nsHttpConnectionMgr::OnMsgReclaimConnection [conn=%p]\n", param)); LOG(("nsHttpConnectionMgr::OnMsgReclaimConnection [conn=%p]\n", param));
nsRefPtr<nsHttpConnection> conn = nsHttpConnection *conn = (nsHttpConnection *) param;
dont_AddRef(static_cast<nsHttpConnection *>(param));
// //
// 1) remove the connection from the active list // 1) remove the connection from the active list
@ -2275,15 +2312,16 @@ nsHttpConnectionMgr::OnMsgReclaimConnection(int32_t, void *param)
nsConnectionEntry *ent = LookupConnectionEntry(conn->ConnectionInfo(), nsConnectionEntry *ent = LookupConnectionEntry(conn->ConnectionInfo(),
conn, nullptr); conn, nullptr);
nsRefPtr<nsHttpConnectionInfo> ci; nsHttpConnectionInfo *ci = nullptr;
if (!ent) { if (!ent) {
// this should never happen // this should never happen
LOG(("nsHttpConnectionMgr::OnMsgReclaimConnection ent == null\n")); LOG(("nsHttpConnectionMgr::OnMsgReclaimConnection ent == null\n"));
MOZ_ASSERT(false, "no connection entry"); MOZ_ASSERT(false, "no connection entry");
ci = conn->ConnectionInfo(); NS_ADDREF(ci = conn->ConnectionInfo());
} else { }
ci = ent->mConnInfo; else {
NS_ADDREF(ci = ent->mConnInfo);
// If the connection is in the active list, remove that entry // If the connection is in the active list, remove that entry
// and the reference held by the mActiveConns list. // and the reference held by the mActiveConns list.
@ -2303,7 +2341,8 @@ nsHttpConnectionMgr::OnMsgReclaimConnection(int32_t, void *param)
if (ent->mActiveConns.RemoveElement(conn)) { if (ent->mActiveConns.RemoveElement(conn)) {
if (conn == ent->mYellowConnection) if (conn == ent->mYellowConnection)
ent->OnYellowComplete(); ent->OnYellowComplete();
nsHttpConnection *temp = conn;
NS_RELEASE(temp);
DecrementActiveConnCount(conn); DecrementActiveConnCount(conn);
ConditionallyStopTimeoutTick(); ConditionallyStopTimeoutTick();
} }
@ -2324,6 +2363,7 @@ nsHttpConnectionMgr::OnMsgReclaimConnection(int32_t, void *param)
break; break;
} }
NS_ADDREF(conn);
ent->mIdleConns.InsertElementAt(idx, conn); ent->mIdleConns.InsertElementAt(idx, conn);
mNumIdleConns++; mNumIdleConns++;
conn->BeginIdleMonitoring(); conn->BeginIdleMonitoring();
@ -2334,13 +2374,15 @@ nsHttpConnectionMgr::OnMsgReclaimConnection(int32_t, void *param)
uint32_t timeToLive = conn->TimeToLive(); uint32_t timeToLive = conn->TimeToLive();
if(!mTimer || NowInSeconds() + timeToLive < mTimeOfNextWakeUp) if(!mTimer || NowInSeconds() + timeToLive < mTimeOfNextWakeUp)
PruneDeadConnectionsAfter(timeToLive); PruneDeadConnectionsAfter(timeToLive);
} else { }
else {
LOG((" connection cannot be reused; closing connection\n")); LOG((" connection cannot be reused; closing connection\n"));
conn->Close(NS_ERROR_ABORT); conn->Close(NS_ERROR_ABORT);
} }
} }
OnMsgProcessPendingQ(0, ci.forget().get()); // releases |ci ref| OnMsgProcessPendingQ(0, ci); // releases |ci|
NS_RELEASE(conn);
} }
void void
@ -2403,6 +2445,8 @@ nsHttpConnectionMgr::nsConnectionEntry::~nsConnectionEntry()
{ {
if (mSpdyPreferred) if (mSpdyPreferred)
gHttpHandler->ConnMgr()->RemoveSpdyPreferredEnt(mCoalescingKey); gHttpHandler->ConnMgr()->RemoveSpdyPreferredEnt(mCoalescingKey);
NS_RELEASE(mConnInfo);
} }
void void
@ -2525,26 +2569,6 @@ nsHttpConnectionMgr::TimeoutTickCB(const nsACString &key,
return PL_DHASH_NEXT; return PL_DHASH_NEXT;
} }
void
nsHttpConnectionMgr::
InsertTransactionSorted(nsTArray<nsRefPtr<nsHttpTransaction> > &pendingQ,
nsHttpTransaction *trans)
{
// Insert into queue with smallest valued number first. Search in reverse
// order under the assumption that many of the existing transactions will
// have the same priority (usually 0).
// List holds a reference on all members of mPendingQ
for (int32_t i = pendingQ.Length() - 1; i >= 0; --i) {
nsHttpTransaction *t = pendingQ[i];
if (trans->Priority() >= t->Priority()) {
pendingQ.InsertElementAt(i + 1, trans);
return;
}
}
pendingQ.InsertElementAt(0, trans);
}
//----------------------------------------------------------------------------- //-----------------------------------------------------------------------------
// nsHttpConnectionMgr::nsConnectionHandle // nsHttpConnectionMgr::nsConnectionHandle
@ -2552,6 +2576,7 @@ nsHttpConnectionMgr::nsConnectionHandle::~nsConnectionHandle()
{ {
if (mConn) { if (mConn) {
gHttpHandler->ReclaimConnection(mConn); gHttpHandler->ReclaimConnection(mConn);
NS_RELEASE(mConn);
} }
} }
@ -2632,7 +2657,8 @@ nsHttpConnectionMgr::OnMsgSpeculativeConnect(int32_t, void *param)
!RestrictConnections(ent, ignorePossibleSpdyConnections) && !RestrictConnections(ent, ignorePossibleSpdyConnections) &&
!AtActiveConnectionLimit(ent, args->mTrans->Caps())) { !AtActiveConnectionLimit(ent, args->mTrans->Caps())) {
CreateTransport(ent, args->mTrans, args->mTrans->Caps(), true); CreateTransport(ent, args->mTrans, args->mTrans->Caps(), true);
} else { }
else {
LOG((" Transport not created due to existing connection count\n")); LOG((" Transport not created due to existing connection count\n"));
} }
} }
@ -2982,7 +3008,8 @@ nsHalfOpenSocket::OnOutputStreamReady(nsIAsyncOutputStream *out)
mStreamOut = nullptr; mStreamOut = nullptr;
mStreamIn = nullptr; mStreamIn = nullptr;
mSocketTransport = nullptr; mSocketTransport = nullptr;
} else { }
else {
TimeDuration rtt = TimeStamp::Now() - mBackupSynStarted; TimeDuration rtt = TimeStamp::Now() - mBackupSynStarted;
rv = conn->Init(mEnt->mConnInfo, rv = conn->Init(mEnt->mConnInfo,
gHttpHandler->ConnMgr()->mMaxRequestDelay, gHttpHandler->ConnMgr()->mMaxRequestDelay,
@ -3015,11 +3042,12 @@ nsHalfOpenSocket::OnOutputStreamReady(nsIAsyncOutputStream *out)
if (index != -1) { if (index != -1) {
MOZ_ASSERT(!mSpeculative, MOZ_ASSERT(!mSpeculative,
"Speculative Half Open found mTranscation"); "Speculative Half Open found mTranscation");
nsRefPtr<nsHttpTransaction> temp(mEnt->mPendingQ[index]); nsRefPtr<nsHttpTransaction> temp = dont_AddRef(mEnt->mPendingQ[index]);
mEnt->mPendingQ.RemoveElementAt(index); mEnt->mPendingQ.RemoveElementAt(index);
gHttpHandler->ConnMgr()->AddActiveConn(conn, mEnt); gHttpHandler->ConnMgr()->AddActiveConn(conn, mEnt);
rv = gHttpHandler->ConnMgr()->DispatchTransaction(mEnt, temp, conn); rv = gHttpHandler->ConnMgr()->DispatchTransaction(mEnt, temp, conn);
} else { }
else {
// this transaction was dispatched off the pending q before all the // this transaction was dispatched off the pending q before all the
// sockets established themselves. // sockets established themselves.
@ -3054,7 +3082,8 @@ nsHalfOpenSocket::OnOutputStreamReady(nsIAsyncOutputStream *out)
conn->Classify(nsAHttpTransaction::CLASS_SOLO); conn->Classify(nsAHttpTransaction::CLASS_SOLO);
rv = gHttpHandler->ConnMgr()-> rv = gHttpHandler->ConnMgr()->
DispatchAbstractTransaction(mEnt, trans, mCaps, conn, 0); DispatchAbstractTransaction(mEnt, trans, mCaps, conn, 0);
} else { }
else {
// otherwise just put this in the persistent connection pool // otherwise just put this in the persistent connection pool
LOG(("nsHalfOpenSocket::OnOutputStreamReady no transaction match " LOG(("nsHalfOpenSocket::OnOutputStreamReady no transaction match "
"returning conn %p to pool\n", conn.get())); "returning conn %p to pool\n", conn.get()));
@ -3208,6 +3237,7 @@ nsConnectionEntry::nsConnectionEntry(nsHttpConnectionInfo *ci)
, mPreferIPv4(false) , mPreferIPv4(false)
, mPreferIPv6(false) , mPreferIPv6(false)
{ {
NS_ADDREF(mConnInfo);
if (gHttpHandler->GetPipelineAggressive()) { if (gHttpHandler->GetPipelineAggressive()) {
mGreenDepth = kPipelineUnlimited; mGreenDepth = kPipelineUnlimited;
mPipelineState = PS_GREEN; mPipelineState = PS_GREEN;
@ -3333,7 +3363,8 @@ nsConnectionEntry::OnPipelineFeedbackInfo(
"Penalty now %d, throttle[%d] = %d\n", mConnInfo->Host(), "Penalty now %d, throttle[%d] = %d\n", mConnInfo->Host(),
classification, info, mPipeliningPenalty, classification, classification, info, mPipeliningPenalty, classification,
mPipeliningClassPenalty[classification])); mPipeliningClassPenalty[classification]));
} else { }
else {
// hand out credits for neutral and good events such as // hand out credits for neutral and good events such as
// "headers look ok" events // "headers look ok" events
@ -3368,7 +3399,8 @@ nsConnectionEntry::OnYellowComplete()
LOG(("transition %s to green\n", mConnInfo->Host())); LOG(("transition %s to green\n", mConnInfo->Host()));
mPipelineState = PS_GREEN; mPipelineState = PS_GREEN;
mGreenDepth = mInitialGreenDepth; mGreenDepth = mInitialGreenDepth;
} else { }
else {
// The purpose of the yellow state is to witness at least // The purpose of the yellow state is to witness at least
// one successful pipelined transaction without seeing any // one successful pipelined transaction without seeing any
// kind of negative feedback before opening the flood gates. // kind of negative feedback before opening the flood gates.
@ -3412,7 +3444,8 @@ nsConnectionEntry::CreditPenalty()
// update last credit mark to reflect elapsed time // update last credit mark to reflect elapsed time
mLastCreditTime += TimeDuration::FromSeconds(creditsEarned << 4); mLastCreditTime += TimeDuration::FromSeconds(creditsEarned << 4);
} else { }
else {
failed = true; /* just assume this */ failed = true; /* just assume this */
} }

View File

@ -265,10 +265,10 @@ private:
nsConnectionEntry(nsHttpConnectionInfo *ci); nsConnectionEntry(nsHttpConnectionInfo *ci);
~nsConnectionEntry(); ~nsConnectionEntry();
nsRefPtr<nsHttpConnectionInfo> mConnInfo; nsHttpConnectionInfo *mConnInfo;
nsTArray<nsRefPtr<nsHttpTransaction> > mPendingQ; // pending transaction queue nsTArray<nsHttpTransaction*> mPendingQ; // pending transaction queue
nsTArray<nsRefPtr<nsHttpConnection> > mActiveConns; // active connections nsTArray<nsHttpConnection*> mActiveConns; // active connections
nsTArray<nsRefPtr<nsHttpConnection> > mIdleConns; // idle persistent connections nsTArray<nsHttpConnection*> mIdleConns; // idle persistent connections
nsTArray<nsHalfOpenSocket*> mHalfOpens; // half open connections nsTArray<nsHalfOpenSocket*> mHalfOpens; // half open connections
// calculate the number of half open sockets that have not had at least 1 // calculate the number of half open sockets that have not had at least 1
@ -379,18 +379,16 @@ private:
// need for consumer code to know when to give the connection back to the // need for consumer code to know when to give the connection back to the
// connection manager. // connection manager.
// //
class nsConnectionHandle MOZ_FINAL : public nsAHttpConnection class nsConnectionHandle : public nsAHttpConnection
{ {
public: public:
NS_DECL_THREADSAFE_ISUPPORTS NS_DECL_THREADSAFE_ISUPPORTS
NS_DECL_NSAHTTPCONNECTION(mConn) NS_DECL_NSAHTTPCONNECTION(mConn)
nsConnectionHandle(nsHttpConnection *conn) : mConn(conn) { } nsConnectionHandle(nsHttpConnection *conn) { NS_ADDREF(mConn = conn); }
virtual ~nsConnectionHandle(); virtual ~nsConnectionHandle();
void Reset() { mConn = nullptr; }
private: nsHttpConnection *mConn;
nsRefPtr<nsHttpConnection> mConn;
}; };
// nsHalfOpenSocket is used to hold the state of an opening TCP socket // nsHalfOpenSocket is used to hold the state of an opening TCP socket
@ -522,8 +520,6 @@ private:
void StartedConnect(); void StartedConnect();
void RecvdConnect(); void RecvdConnect();
static void InsertTransactionSorted(nsTArray<nsRefPtr<nsHttpTransaction> > &,
nsHttpTransaction *);
nsConnectionEntry *GetOrCreateConnectionEntry(nsHttpConnectionInfo *); nsConnectionEntry *GetOrCreateConnectionEntry(nsHttpConnectionInfo *);
nsresult MakeNewConnection(nsConnectionEntry *ent, nsresult MakeNewConnection(nsConnectionEntry *ent,

View File

@ -111,14 +111,19 @@ NewURI(const nsACString &aSpec,
int32_t aDefaultPort, int32_t aDefaultPort,
nsIURI **aURI) nsIURI **aURI)
{ {
nsRefPtr<nsStandardURL> url = new nsStandardURL(); nsStandardURL *url = new nsStandardURL();
if (!url)
return NS_ERROR_OUT_OF_MEMORY;
NS_ADDREF(url);
nsresult rv = url->Init(nsIStandardURL::URLTYPE_AUTHORITY, nsresult rv = url->Init(nsIStandardURL::URLTYPE_AUTHORITY,
aDefaultPort, aSpec, aCharset, aBaseURI); aDefaultPort, aSpec, aCharset, aBaseURI);
if (NS_FAILED(rv)) { if (NS_FAILED(rv)) {
NS_RELEASE(url);
return rv; return rv;
} }
url.forget(aURI);
*aURI = url; // no QI needed
return NS_OK; return NS_OK;
} }
@ -129,7 +134,8 @@ NewURI(const nsACString &aSpec,
nsHttpHandler *gHttpHandler = nullptr; nsHttpHandler *gHttpHandler = nullptr;
nsHttpHandler::nsHttpHandler() nsHttpHandler::nsHttpHandler()
: mHttpVersion(NS_HTTP_VERSION_1_1) : mConnMgr(nullptr)
, mHttpVersion(NS_HTTP_VERSION_1_1)
, mProxyHttpVersion(NS_HTTP_VERSION_1_1) , mProxyHttpVersion(NS_HTTP_VERSION_1_1)
, mCapabilities(NS_HTTP_ALLOW_KEEPALIVE) , mCapabilities(NS_HTTP_ALLOW_KEEPALIVE)
, mReferrerLevel(0xff) // by default we always send a referrer , mReferrerLevel(0xff) // by default we always send a referrer
@ -225,7 +231,7 @@ nsHttpHandler::~nsHttpHandler()
// make sure the connection manager is shutdown // make sure the connection manager is shutdown
if (mConnMgr) { if (mConnMgr) {
mConnMgr->Shutdown(); mConnMgr->Shutdown();
mConnMgr = nullptr; NS_RELEASE(mConnMgr);
} }
// Note: don't call NeckoChild::DestroyNeckoChild() here, as it's too late // Note: don't call NeckoChild::DestroyNeckoChild() here, as it's too late
@ -383,6 +389,9 @@ nsHttpHandler::InitConnectionMgr()
if (!mConnMgr) { if (!mConnMgr) {
mConnMgr = new nsHttpConnectionMgr(); mConnMgr = new nsHttpConnectionMgr();
if (!mConnMgr)
return NS_ERROR_OUT_OF_MEMORY;
NS_ADDREF(mConnMgr);
} }
rv = mConnMgr->Init(mMaxConnections, rv = mConnMgr->Init(mMaxConnections,

View File

@ -345,7 +345,7 @@ private:
nsHttpAuthCache mPrivateAuthCache; nsHttpAuthCache mPrivateAuthCache;
// the connection manager // the connection manager
nsRefPtr<nsHttpConnectionMgr> mConnMgr; nsHttpConnectionMgr *mConnMgr;
// //
// prefs // prefs

View File

@ -62,7 +62,8 @@ private:
//----------------------------------------------------------------------------- //-----------------------------------------------------------------------------
nsHttpPipeline::nsHttpPipeline() nsHttpPipeline::nsHttpPipeline()
: mStatus(NS_OK) : mConnection(nullptr)
, mStatus(NS_OK)
, mRequestIsPartial(false) , mRequestIsPartial(false)
, mResponseIsPartial(false) , mResponseIsPartial(false)
, mClosed(false) , mClosed(false)
@ -82,6 +83,8 @@ nsHttpPipeline::~nsHttpPipeline()
// make sure we aren't still holding onto any transactions! // make sure we aren't still holding onto any transactions!
Close(NS_ERROR_ABORT); Close(NS_ERROR_ABORT);
NS_IF_RELEASE(mConnection);
if (mPushBackBuf) if (mPushBackBuf)
free(mPushBackBuf); free(mPushBackBuf);
} }
@ -94,7 +97,7 @@ nsHttpPipeline::AddTransaction(nsAHttpTransaction *trans)
if (mRequestQ.Length() || mResponseQ.Length()) if (mRequestQ.Length() || mResponseQ.Length())
mUtilizedPipeline = true; mUtilizedPipeline = true;
trans->AddRef(); // ref held by mRequestQ NS_ADDREF(trans);
mRequestQ.AppendElement(trans); mRequestQ.AppendElement(trans);
uint32_t qlen = PipelineDepth(); uint32_t qlen = PipelineDepth();
@ -202,11 +205,10 @@ nsHttpPipeline::OnHeadersAvailable(nsAHttpTransaction *trans,
} }
void void
nsHttpPipeline::CloseTransaction(nsAHttpTransaction *aTrans, nsresult reason) nsHttpPipeline::CloseTransaction(nsAHttpTransaction *trans, nsresult reason)
{ {
nsRefPtr<nsAHttpTransaction> trans(dont_AddRef(aTrans));
LOG(("nsHttpPipeline::CloseTransaction [this=%p trans=%x reason=%x]\n", LOG(("nsHttpPipeline::CloseTransaction [this=%p trans=%x reason=%x]\n",
this, trans.get(), reason)); this, trans, reason));
MOZ_ASSERT(PR_GetCurrentThread() == gSocketThread); MOZ_ASSERT(PR_GetCurrentThread() == gSocketThread);
MOZ_ASSERT(NS_FAILED(reason), "expecting failure code"); MOZ_ASSERT(NS_FAILED(reason), "expecting failure code");
@ -241,7 +243,7 @@ nsHttpPipeline::CloseTransaction(nsAHttpTransaction *aTrans, nsresult reason)
DontReuse(); DontReuse();
trans->Close(reason); trans->Close(reason);
trans = nullptr; NS_RELEASE(trans);
if (killPipeline) { if (killPipeline) {
// reschedule anything from this pipeline onto a different connection // reschedule anything from this pipeline onto a different connection
@ -383,11 +385,12 @@ nsHttpPipeline::TakeSubTransactions(
int32_t i, count = mRequestQ.Length(); int32_t i, count = mRequestQ.Length();
for (i = 0; i < count; ++i) { for (i = 0; i < count; ++i) {
nsRefPtr<nsAHttpTransaction> trans(dont_AddRef(Request(i))); nsAHttpTransaction *trans = Request(i);
// set the transaction conneciton object back to the underlying // set the transaction conneciton object back to the underlying
// nsHttpConnectionHandle // nsHttpConnectionHandle
trans->SetConnection(mConnection); trans->SetConnection(mConnection);
outTransactions.AppendElement(trans); outTransactions.AppendElement(trans);
NS_RELEASE(trans);
} }
mRequestQ.Clear(); mRequestQ.Clear();
@ -406,13 +409,14 @@ nsHttpPipeline::SetConnection(nsAHttpConnection *conn)
MOZ_ASSERT(PR_GetCurrentThread() == gSocketThread); MOZ_ASSERT(PR_GetCurrentThread() == gSocketThread);
MOZ_ASSERT(!mConnection, "already have a connection"); MOZ_ASSERT(!mConnection, "already have a connection");
mConnection = conn;
NS_IF_ADDREF(mConnection = conn);
} }
nsAHttpConnection * nsAHttpConnection *
nsHttpPipeline::Connection() nsHttpPipeline::Connection()
{ {
LOG(("nsHttpPipeline::Connection [this=%p conn=%x]\n", this, mConnection.get())); LOG(("nsHttpPipeline::Connection [this=%p conn=%x]\n", this, mConnection));
MOZ_ASSERT(PR_GetCurrentThread() == gSocketThread); MOZ_ASSERT(PR_GetCurrentThread() == gSocketThread);
return mConnection; return mConnection;
@ -684,7 +688,7 @@ nsHttpPipeline::WriteSegments(nsAHttpSegmentWriter *writer,
// Release the transaction if it is not IsProxyConnectInProgress() // Release the transaction if it is not IsProxyConnectInProgress()
if (trans == Response(0)) { if (trans == Response(0)) {
nsRefPtr<nsAHttpTransaction> listReference(dont_AddRef(trans)); NS_RELEASE(trans);
mResponseQ.RemoveElementAt(0); mResponseQ.RemoveElementAt(0);
mResponseIsPartial = false; mResponseIsPartial = false;
++mHttp1xTransactionCount; ++mHttp1xTransactionCount;
@ -727,6 +731,7 @@ uint32_t
nsHttpPipeline::CancelPipeline(nsresult originalReason) nsHttpPipeline::CancelPipeline(nsresult originalReason)
{ {
uint32_t i, reqLen, respLen, total; uint32_t i, reqLen, respLen, total;
nsAHttpTransaction *trans;
reqLen = mRequestQ.Length(); reqLen = mRequestQ.Length();
respLen = mResponseQ.Length(); respLen = mResponseQ.Length();
@ -742,12 +747,12 @@ nsHttpPipeline::CancelPipeline(nsresult originalReason)
// any pending requests can ignore this error and be restarted // any pending requests can ignore this error and be restarted
// unless it is during a CONNECT tunnel request // unless it is during a CONNECT tunnel request
for (i = 0; i < reqLen; ++i) { for (i = 0; i < reqLen; ++i) {
// Each element on the list has a reference held by the list trans = Request(i);
nsRefPtr<nsAHttpTransaction> trans(dont_AddRef(Request(i)));
if (mConnection && mConnection->IsProxyConnectInProgress()) if (mConnection && mConnection->IsProxyConnectInProgress())
trans->Close(originalReason); trans->Close(originalReason);
else else
trans->Close(NS_ERROR_NET_RESET); trans->Close(NS_ERROR_NET_RESET);
NS_RELEASE(trans);
} }
mRequestQ.Clear(); mRequestQ.Clear();
@ -756,8 +761,9 @@ nsHttpPipeline::CancelPipeline(nsresult originalReason)
// Higher levels of callers ensure that we don't process non-idempotent // Higher levels of callers ensure that we don't process non-idempotent
// tranasction with the NS_HTTP_ALLOW_PIPELINING bit set // tranasction with the NS_HTTP_ALLOW_PIPELINING bit set
for (i = 1; i < respLen; ++i) { for (i = 1; i < respLen; ++i) {
nsRefPtr<nsAHttpTransaction> trans(dont_AddRef(Response(i))); trans = Response(i);
trans->Close(NS_ERROR_NET_RESET); trans->Close(NS_ERROR_NET_RESET);
NS_RELEASE(trans);
} }
if (respLen > 1) if (respLen > 1)
@ -795,10 +801,9 @@ nsHttpPipeline::Close(nsresult reason)
gHttpHandler->ConnMgr()->PipelineFeedbackInfo( gHttpHandler->ConnMgr()->PipelineFeedbackInfo(
ci, nsHttpConnectionMgr::RedCanceledPipeline, nullptr, 0); ci, nsHttpConnectionMgr::RedCanceledPipeline, nullptr, 0);
if (!Response(0)) { nsAHttpTransaction *trans = Response(0);
if (!trans)
return; return;
}
nsRefPtr<nsAHttpTransaction> trans(dont_AddRef(Response(0)));
// The current transaction can be restarted via reset // The current transaction can be restarted via reset
// if the response has not started to arrive and the reason // if the response has not started to arrive and the reason
@ -814,7 +819,7 @@ nsHttpPipeline::Close(nsresult reason)
trans->Close(reason); trans->Close(reason);
} }
trans = nullptr; NS_RELEASE(trans);
mResponseQ.Clear(); mResponseQ.Clear();
} }

View File

@ -58,7 +58,7 @@ private:
// overload of nsAHttpTransaction::QueryPipeline() // overload of nsAHttpTransaction::QueryPipeline()
nsHttpPipeline *QueryPipeline(); nsHttpPipeline *QueryPipeline();
nsRefPtr<nsAHttpConnection> mConnection; nsAHttpConnection *mConnection;
nsTArray<nsAHttpTransaction*> mRequestQ; // array of transactions nsTArray<nsAHttpTransaction*> mRequestQ; // array of transactions
nsTArray<nsAHttpTransaction*> mResponseQ; // array of transactions nsTArray<nsAHttpTransaction*> mResponseQ; // array of transactions
nsresult mStatus; nsresult mStatus;

View File

@ -89,6 +89,8 @@ LogHeaders(const char *lineStart)
nsHttpTransaction::nsHttpTransaction() nsHttpTransaction::nsHttpTransaction()
: mCallbacksLock("transaction mCallbacks lock") : mCallbacksLock("transaction mCallbacks lock")
, mRequestSize(0) , mRequestSize(0)
, mConnection(nullptr)
, mConnInfo(nullptr)
, mRequestHead(nullptr) , mRequestHead(nullptr)
, mResponseHead(nullptr) , mResponseHead(nullptr)
, mContentLength(-1) , mContentLength(-1)
@ -147,6 +149,9 @@ nsHttpTransaction::~nsHttpTransaction()
// Force the callbacks to be released right now // Force the callbacks to be released right now
mCallbacks = nullptr; mCallbacks = nullptr;
NS_IF_RELEASE(mConnection);
NS_IF_RELEASE(mConnInfo);
delete mResponseHead; delete mResponseHead;
delete mForTakeResponseHead; delete mForTakeResponseHead;
delete mChunkedDecoder; delete mChunkedDecoder;
@ -264,7 +269,7 @@ nsHttpTransaction::Init(uint32_t caps,
!activityDistributorActive); !activityDistributorActive);
if (NS_FAILED(rv)) return rv; if (NS_FAILED(rv)) return rv;
mConnInfo = cinfo; NS_ADDREF(mConnInfo = cinfo);
mCallbacks = callbacks; mCallbacks = callbacks;
mConsumerTarget = target; mConsumerTarget = target;
mCaps = caps; mCaps = caps;
@ -440,7 +445,8 @@ nsHttpTransaction::TakeSubTransactions(
void void
nsHttpTransaction::SetConnection(nsAHttpConnection *conn) nsHttpTransaction::SetConnection(nsAHttpConnection *conn)
{ {
mConnection = conn; NS_IF_RELEASE(mConnection);
NS_IF_ADDREF(mConnection = conn);
if (conn) { if (conn) {
MOZ_EVENT_TRACER_EXEC(static_cast<nsAHttpTransaction*>(this), MOZ_EVENT_TRACER_EXEC(static_cast<nsAHttpTransaction*>(this),
@ -955,9 +961,8 @@ nsHttpTransaction::Close(nsresult reason)
mTimings.responseEnd.IsNull() && !mTimings.responseStart.IsNull()) mTimings.responseEnd.IsNull() && !mTimings.responseStart.IsNull())
mTimings.responseEnd = TimeStamp::Now(); mTimings.responseEnd = TimeStamp::Now();
if (relConn) { if (relConn && mConnection)
mConnection = nullptr; NS_RELEASE(mConnection);
}
// save network statistics in the end of transaction // save network statistics in the end of transaction
SaveNetworkStats(true); SaveNetworkStats(true);
@ -1111,7 +1116,7 @@ nsHttpTransaction::Restart()
// clear old connection state... // clear old connection state...
mSecurityInfo = 0; mSecurityInfo = 0;
mConnection = nullptr; NS_IF_RELEASE(mConnection);
// disable pipelining for the next attempt in case pipelining caused the // disable pipelining for the next attempt in case pipelining caused the
// reset. this is being overly cautious since we don't know if pipelining // reset. this is being overly cautious since we don't know if pipelining

View File

@ -185,11 +185,10 @@ private:
nsCOMPtr<nsIInputStream> mRequestStream; nsCOMPtr<nsIInputStream> mRequestStream;
uint64_t mRequestSize; uint64_t mRequestSize;
nsRefPtr<nsHttpConnectionInfo> mConnInfo; nsAHttpConnection *mConnection; // hard ref
nsRefPtr<nsAHttpConnection> mConnection; nsHttpConnectionInfo *mConnInfo; // hard ref
nsHttpRequestHead *mRequestHead; // weak ref nsHttpRequestHead *mRequestHead; // weak ref
nsHttpResponseHead *mResponseHead; // owning ref nsHttpResponseHead *mResponseHead; // hard ref
nsAHttpSegmentReader *mReader; nsAHttpSegmentReader *mReader;
nsAHttpSegmentWriter *mWriter; nsAHttpSegmentWriter *mWriter;