зеркало из https://github.com/mozilla/gecko-dev.git
Bug 1341572
- Fix multiple HalfOpen socket for a single transaction. r=mcmanus
This commit is contained in:
Родитель
925aa86f06
Коммит
1c99ae8f32
|
@ -204,5 +204,15 @@ nsHttpTransaction::PrintDiagnostics(nsCString &log)
|
|||
log.AppendPrintf(" restart count = %u\n", mRestartCount);
|
||||
}
|
||||
|
||||
void
|
||||
nsHttpConnectionMgr::PendingTransactionInfo::PrintDiagnostics(nsCString &log)
|
||||
{
|
||||
log.AppendPrintf(" ::: Pending transaction\n");
|
||||
mTransaction->PrintDiagnostics(log);
|
||||
RefPtr<nsHalfOpenSocket> halfOpen = do_QueryReferent(mHalfOpen);
|
||||
log.AppendPrintf(" Waiting for half open sock: %p or connection: %p\n",
|
||||
halfOpen.get(), mActiveConn.get());
|
||||
}
|
||||
|
||||
} // namespace net
|
||||
} // namespace mozilla
|
||||
|
|
|
@ -141,6 +141,12 @@ NullHttpTransaction::Claim()
|
|||
return true;
|
||||
}
|
||||
|
||||
void
|
||||
NullHttpTransaction::Unclaim()
|
||||
{
|
||||
mClaimed = false;
|
||||
}
|
||||
|
||||
void
|
||||
NullHttpTransaction::SetConnection(nsAHttpConnection *conn)
|
||||
{
|
||||
|
|
|
@ -39,6 +39,7 @@ public:
|
|||
uint32_t caps);
|
||||
|
||||
MOZ_MUST_USE bool Claim();
|
||||
void Unclaim();
|
||||
|
||||
// Overload of nsAHttpTransaction methods
|
||||
bool IsNullTransaction() override final { return true; }
|
||||
|
|
|
@ -2074,11 +2074,22 @@ nsHttpConnection::DisableTCPKeepalives()
|
|||
// nsHttpConnection::nsISupports
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
NS_IMPL_ISUPPORTS(nsHttpConnection,
|
||||
nsIInputStreamCallback,
|
||||
nsIOutputStreamCallback,
|
||||
nsITransportEventSink,
|
||||
nsIInterfaceRequestor)
|
||||
NS_IMPL_ADDREF(nsHttpConnection)
|
||||
NS_IMPL_RELEASE(nsHttpConnection)
|
||||
|
||||
NS_INTERFACE_MAP_BEGIN(nsHttpConnection)
|
||||
NS_INTERFACE_MAP_ENTRY(nsISupportsWeakReference)
|
||||
NS_INTERFACE_MAP_ENTRY(nsIInputStreamCallback)
|
||||
NS_INTERFACE_MAP_ENTRY(nsIOutputStreamCallback)
|
||||
NS_INTERFACE_MAP_ENTRY(nsITransportEventSink)
|
||||
NS_INTERFACE_MAP_ENTRY(nsIInterfaceRequestor)
|
||||
// we have no macro that covers this case.
|
||||
if (aIID.Equals(NS_GET_IID(nsHttpConnection)) ) {
|
||||
AddRef();
|
||||
*aInstancePtr = this;
|
||||
return NS_OK;
|
||||
} else
|
||||
NS_INTERFACE_MAP_END
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// nsHttpConnection::nsIInputStreamCallback
|
||||
|
|
|
@ -31,6 +31,10 @@ namespace net {
|
|||
class nsHttpHandler;
|
||||
class ASpdySession;
|
||||
|
||||
// 1dcc863e-db90-4652-a1fe-13fea0b54e46
|
||||
#define NS_HTTPCONNECTION_IID \
|
||||
{ 0x1dcc863e, 0xdb90, 0x4652, {0xa1, 0xfe, 0x13, 0xfe, 0xa0, 0xb5, 0x4e, 0x46 }}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// nsHttpConnection - represents a connection to a HTTP server (or proxy)
|
||||
//
|
||||
|
@ -46,10 +50,12 @@ class nsHttpConnection final : public nsAHttpSegmentReader
|
|||
, public nsIInterfaceRequestor
|
||||
, public NudgeTunnelCallback
|
||||
, public ARefBase
|
||||
, public nsSupportsWeakReference
|
||||
{
|
||||
virtual ~nsHttpConnection();
|
||||
|
||||
public:
|
||||
NS_DECLARE_STATIC_IID_ACCESSOR(NS_HTTPCONNECTION_IID)
|
||||
NS_DECL_THREADSAFE_ISUPPORTS
|
||||
NS_DECL_NSAHTTPSEGMENTREADER
|
||||
NS_DECL_NSAHTTPSEGMENTWRITER
|
||||
|
@ -376,6 +382,8 @@ private:
|
|||
bool mDid0RTTSpdy;
|
||||
};
|
||||
|
||||
NS_DEFINE_STATIC_IID_ACCESSOR(nsHttpConnection, NS_HTTPCONNECTION_IID)
|
||||
|
||||
} // namespace net
|
||||
} // namespace mozilla
|
||||
|
||||
|
|
|
@ -44,31 +44,34 @@ namespace net {
|
|||
|
||||
NS_IMPL_ISUPPORTS(nsHttpConnectionMgr, nsIObserver)
|
||||
|
||||
static void
|
||||
InsertTransactionSorted(nsTArray<RefPtr<nsHttpTransaction>> &pendingQ, nsHttpTransaction *trans)
|
||||
void
|
||||
nsHttpConnectionMgr::InsertTransactionSorted(nsTArray<RefPtr<nsHttpConnectionMgr::PendingTransactionInfo> > &pendingQ,
|
||||
nsHttpConnectionMgr::PendingTransactionInfo *pendingTransInfo)
|
||||
{
|
||||
// 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).
|
||||
|
||||
nsHttpTransaction *trans = pendingTransInfo->mTransaction;
|
||||
|
||||
for (int32_t i = pendingQ.Length() - 1; i >= 0; --i) {
|
||||
nsHttpTransaction *t = pendingQ[i];
|
||||
nsHttpTransaction *t = pendingQ[i]->mTransaction;
|
||||
if (trans->Priority() >= t->Priority()) {
|
||||
if (ChaosMode::isActive(ChaosFeature::NetworkScheduling)) {
|
||||
int32_t samePriorityCount;
|
||||
for (samePriorityCount = 0; i - samePriorityCount >= 0; ++samePriorityCount) {
|
||||
if (pendingQ[i - samePriorityCount]->Priority() != trans->Priority()) {
|
||||
if (pendingQ[i - samePriorityCount]->mTransaction->Priority() != trans->Priority()) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
// skip over 0...all of the elements with the same priority.
|
||||
i -= ChaosMode::randomUint32LessThan(samePriorityCount + 1);
|
||||
}
|
||||
pendingQ.InsertElementAt(i+1, trans);
|
||||
pendingQ.InsertElementAt(i+1, pendingTransInfo);
|
||||
return;
|
||||
}
|
||||
}
|
||||
pendingQ.InsertElementAt(0, trans);
|
||||
pendingQ.InsertElementAt(0, pendingTransInfo);
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
|
@ -633,8 +636,8 @@ nsHttpConnectionMgr::LookupConnectionEntry(nsHttpConnectionInfo *ci,
|
|||
}
|
||||
|
||||
if (trans &&
|
||||
(preferred->mPendingQ.Contains(trans) ||
|
||||
preferred->mUrgentStartQ.Contains(trans))) {
|
||||
(preferred->mPendingQ.Contains(trans, PendingComparator()) ||
|
||||
preferred->mUrgentStartQ.Contains(trans, PendingComparator()))) {
|
||||
return preferred;
|
||||
}
|
||||
|
||||
|
@ -877,36 +880,73 @@ nsHttpConnectionMgr::GetSpdyPreferredEnt(nsConnectionEntry *aOriginalEntry)
|
|||
|
||||
//-----------------------------------------------------------------------------
|
||||
void
|
||||
nsHttpConnectionMgr::DispatchPendingQ(nsTArray<RefPtr<nsHttpTransaction>> &pendingQ,
|
||||
nsHttpConnectionMgr::DispatchPendingQ(nsTArray<RefPtr<nsHttpConnectionMgr::PendingTransactionInfo> > &pendingQ,
|
||||
nsConnectionEntry *ent,
|
||||
bool &dispatchedSuccessfully,
|
||||
bool considerAll)
|
||||
{
|
||||
MOZ_ASSERT(PR_GetCurrentThread() == gSocketThread);
|
||||
nsHttpTransaction *trans = nullptr;
|
||||
PendingTransactionInfo *pendingTransInfo = nullptr;
|
||||
nsresult rv;
|
||||
// if !considerAll iterate the pending list until one is dispatched successfully.
|
||||
// Keep iterating afterwards only until a transaction fails to dispatch.
|
||||
// if considerAll == true then try and dispatch all items.
|
||||
for (uint32_t i = 0; i < pendingQ.Length(); ) {
|
||||
trans = pendingQ[i];
|
||||
pendingTransInfo = pendingQ[i];
|
||||
LOG(("nsHttpConnectionMgr::ProcessPendingQForEntry "
|
||||
"[trans=%p, halfOpen=%p, activeConn=%p]\n",
|
||||
pendingTransInfo->mTransaction.get(),
|
||||
pendingTransInfo->mHalfOpen.get(),
|
||||
pendingTransInfo->mActiveConn.get()));
|
||||
|
||||
// When this transaction has already established a half-open
|
||||
// connection, we want to prevent any duplicate half-open
|
||||
// connections from being established and bound to this
|
||||
// transaction. Allow only use of an idle persistent connection
|
||||
// (if found) for transactions referred by a half-open connection.
|
||||
bool alreadyHalfOpen = false;
|
||||
for (int32_t j = 0; j < ((int32_t) ent->mHalfOpens.Length()); ++j) {
|
||||
if (ent->mHalfOpens[j]->Transaction() == trans) {
|
||||
alreadyHalfOpen = true;
|
||||
break;
|
||||
bool alreadyHalfOpenOrWaitingForTLS = false;
|
||||
if (pendingTransInfo->mHalfOpen) {
|
||||
MOZ_ASSERT(!pendingTransInfo->mActiveConn);
|
||||
RefPtr<nsHalfOpenSocket> halfOpen =
|
||||
do_QueryReferent(pendingTransInfo->mHalfOpen);
|
||||
if (halfOpen) {
|
||||
// The half open socket was made for this transaction, in
|
||||
// that case ent->mHalfOpens[j]->Transaction() == trans or
|
||||
// the half open socket was opened speculatively and this
|
||||
// transaction took it (in this case it must be:
|
||||
// ent->mHalfOpens[j]->Transaction().IsNullTransaction())
|
||||
MOZ_ASSERT(halfOpen->Transaction()->IsNullTransaction() ||
|
||||
halfOpen->Transaction() == pendingTransInfo->mTransaction);
|
||||
alreadyHalfOpenOrWaitingForTLS = true;
|
||||
} else {
|
||||
// If we have not found the halfOpen socket, remove the pointer.
|
||||
pendingTransInfo->mHalfOpen = nullptr;
|
||||
}
|
||||
} else if (pendingTransInfo->mActiveConn) {
|
||||
MOZ_ASSERT(!pendingTransInfo->mHalfOpen);
|
||||
RefPtr<nsHttpConnection> activeConn =
|
||||
do_QueryReferent(pendingTransInfo->mActiveConn);
|
||||
// Check if this transaction claimed a connection that is still
|
||||
// performing tls handshake with a NullHttpTransaction or it is between
|
||||
// finishing tls and reclaiming (When nullTrans finishes tls handshake,
|
||||
// httpConnection does not have a transaction any more and a
|
||||
// ReclaimConnection is dispatched). But if an error occurred the
|
||||
// connection will be closed, it will exist but CanReused will be
|
||||
// false.
|
||||
if (activeConn &&
|
||||
((activeConn->Transaction() &&
|
||||
activeConn->Transaction()->IsNullTransaction()) ||
|
||||
(!activeConn->Transaction() && activeConn->CanReuse()))) {
|
||||
alreadyHalfOpenOrWaitingForTLS = true;
|
||||
} else {
|
||||
// If we have not found the connection, remove the pointer.
|
||||
pendingTransInfo->mActiveConn = nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
rv = TryDispatchTransaction(ent,
|
||||
alreadyHalfOpen || !!trans->TunnelProvider(),
|
||||
trans);
|
||||
alreadyHalfOpenOrWaitingForTLS || !!pendingTransInfo->mTransaction->TunnelProvider(),
|
||||
pendingTransInfo);
|
||||
if (NS_SUCCEEDED(rv) || (rv != NS_ERROR_NOT_AVAILABLE)) {
|
||||
if (NS_SUCCEEDED(rv)) {
|
||||
LOG((" dispatching pending transaction...\n"));
|
||||
|
@ -915,8 +955,9 @@ nsHttpConnectionMgr::DispatchPendingQ(nsTArray<RefPtr<nsHttpTransaction>> &pendi
|
|||
"TryDispatchTransaction returning hard error %" PRIx32 "\n",
|
||||
static_cast<uint32_t>(rv)));
|
||||
}
|
||||
if (pendingQ.RemoveElement(trans)) {
|
||||
// trans is now potentially destroyed
|
||||
ReleaseClaimedSockets(ent, pendingTransInfo);
|
||||
if (pendingQ.RemoveElement(pendingTransInfo)) {
|
||||
// pendingTransInfo is now potentially destroyed
|
||||
dispatchedSuccessfully = true;
|
||||
continue; // dont ++i as we just made the array shorter
|
||||
}
|
||||
|
@ -1093,8 +1134,10 @@ nsHttpConnectionMgr::RestrictConnections(nsConnectionEntry *ent)
|
|||
// returns other NS_ERROR on hard failure conditions
|
||||
nsresult
|
||||
nsHttpConnectionMgr::MakeNewConnection(nsConnectionEntry *ent,
|
||||
nsHttpTransaction *trans)
|
||||
PendingTransactionInfo *pendingTransInfo)
|
||||
{
|
||||
nsHttpTransaction *trans = pendingTransInfo->mTransaction;
|
||||
|
||||
LOG(("nsHttpConnectionMgr::MakeNewConnection %p ent=%p trans=%p",
|
||||
this, ent, trans));
|
||||
MOZ_ASSERT(PR_GetCurrentThread() == gSocketThread);
|
||||
|
@ -1113,6 +1156,8 @@ nsHttpConnectionMgr::MakeNewConnection(nsConnectionEntry *ent,
|
|||
|
||||
uint32_t flags;
|
||||
ent->mHalfOpens[i]->SetSpeculative(false);
|
||||
pendingTransInfo->mHalfOpen =
|
||||
do_GetWeakReference(static_cast<nsISupportsWeakReference*>(ent->mHalfOpens[i]));
|
||||
nsISocketTransport *transport = ent->mHalfOpens[i]->SocketTransport();
|
||||
if (transport && NS_SUCCEEDED(transport->GetConnectionFlags(&flags))) {
|
||||
flags &= ~nsISocketTransport::DISABLE_RFC1918;
|
||||
|
@ -1144,6 +1189,8 @@ nsHttpConnectionMgr::MakeNewConnection(nsConnectionEntry *ent,
|
|||
LOG(("nsHttpConnectionMgr::MakeNewConnection [ci = %s] "
|
||||
"Claiming a null transaction for later use\n",
|
||||
ent->mConnInfo->HashKey().get()));
|
||||
pendingTransInfo->mActiveConn =
|
||||
do_GetWeakReference(static_cast<nsISupportsWeakReference*>(ent->mActiveConns[i]));
|
||||
return NS_OK;
|
||||
}
|
||||
}
|
||||
|
@ -1220,7 +1267,8 @@ nsHttpConnectionMgr::MakeNewConnection(nsConnectionEntry *ent,
|
|||
if (AtActiveConnectionLimit(ent, trans->Caps()))
|
||||
return NS_ERROR_NOT_AVAILABLE;
|
||||
|
||||
nsresult rv = CreateTransport(ent, trans, trans->Caps(), false, false, true);
|
||||
nsresult rv = CreateTransport(ent, trans, trans->Caps(), false, false,
|
||||
true, pendingTransInfo);
|
||||
if (NS_FAILED(rv)) {
|
||||
/* hard failure */
|
||||
LOG(("nsHttpConnectionMgr::MakeNewConnection [ci = %s trans = %p] "
|
||||
|
@ -1244,13 +1292,18 @@ nsHttpConnectionMgr::MakeNewConnection(nsConnectionEntry *ent,
|
|||
nsresult
|
||||
nsHttpConnectionMgr::TryDispatchTransaction(nsConnectionEntry *ent,
|
||||
bool onlyReusedConnection,
|
||||
nsHttpTransaction *trans)
|
||||
PendingTransactionInfo *pendingTransInfo)
|
||||
{
|
||||
MOZ_ASSERT(PR_GetCurrentThread() == gSocketThread);
|
||||
|
||||
nsHttpTransaction *trans = pendingTransInfo->mTransaction;
|
||||
|
||||
LOG(("nsHttpConnectionMgr::TryDispatchTransaction without conn "
|
||||
"[trans=%p ci=%p ci=%s caps=%x tunnelprovider=%p onlyreused=%d "
|
||||
"active=%" PRIuSIZE " idle=%" PRIuSIZE "]\n", trans,
|
||||
ent->mConnInfo.get(), ent->mConnInfo->HashKey().get(),
|
||||
"[trans=%p halfOpen=%p conn=%p ci=%p ci=%s caps=%x tunnelprovider=%p "
|
||||
"onlyreused=%d active=%" PRIuSIZE " idle=%" PRIuSIZE "]\n", trans,
|
||||
pendingTransInfo->mHalfOpen.get(),
|
||||
pendingTransInfo->mActiveConn.get(), ent->mConnInfo.get(),
|
||||
ent->mConnInfo->HashKey().get(),
|
||||
uint32_t(trans->Caps()), trans->TunnelProvider(),
|
||||
onlyReusedConnection, ent->mActiveConns.Length(),
|
||||
ent->mIdleConns.Length()));
|
||||
|
@ -1386,7 +1439,7 @@ nsHttpConnectionMgr::TryDispatchTransaction(nsConnectionEntry *ent,
|
|||
|
||||
// step 4
|
||||
if (!onlyReusedConnection) {
|
||||
nsresult rv = MakeNewConnection(ent, trans);
|
||||
nsresult rv = MakeNewConnection(ent, pendingTransInfo);
|
||||
if (NS_SUCCEEDED(rv)) {
|
||||
// this function returns NOT_AVAILABLE for asynchronous connects
|
||||
LOG((" dispatched step 4 (async new conn) trans=%p\n", trans));
|
||||
|
@ -1615,6 +1668,7 @@ nsHttpConnectionMgr::ProcessNewTransaction(nsHttpTransaction *trans)
|
|||
|
||||
nsAHttpConnection *wrappedConnection = trans->Connection();
|
||||
RefPtr<nsHttpConnection> conn;
|
||||
RefPtr<PendingTransactionInfo> pendingTransInfo;
|
||||
if (wrappedConnection)
|
||||
conn = wrappedConnection->TakeHttpConnection();
|
||||
|
||||
|
@ -1638,7 +1692,8 @@ nsHttpConnectionMgr::ProcessNewTransaction(nsHttpTransaction *trans)
|
|||
trans->SetConnection(nullptr);
|
||||
rv = DispatchTransaction(ent, trans, conn);
|
||||
} else {
|
||||
rv = TryDispatchTransaction(ent, !!trans->TunnelProvider(), trans);
|
||||
pendingTransInfo = new PendingTransactionInfo(trans);
|
||||
rv = TryDispatchTransaction(ent, !!trans->TunnelProvider(), pendingTransInfo);
|
||||
}
|
||||
|
||||
if (NS_SUCCEEDED(rv)) {
|
||||
|
@ -1647,18 +1702,21 @@ nsHttpConnectionMgr::ProcessNewTransaction(nsHttpTransaction *trans)
|
|||
}
|
||||
|
||||
if (rv == NS_ERROR_NOT_AVAILABLE) {
|
||||
if (!pendingTransInfo) {
|
||||
pendingTransInfo = new PendingTransactionInfo(trans);
|
||||
}
|
||||
if (trans->Caps() & NS_HTTP_URGENT_START) {
|
||||
LOG((" adding transaction to pending queue "
|
||||
"[trans=%p urgent-start-count=%" PRIuSIZE "]\n",
|
||||
trans, ent->mUrgentStartQ.Length()+1));
|
||||
// put this transaction on the urgent-start queue...
|
||||
InsertTransactionSorted(ent->mUrgentStartQ, trans);
|
||||
InsertTransactionSorted(ent->mUrgentStartQ, pendingTransInfo);
|
||||
} else {
|
||||
LOG((" adding transaction to pending queue "
|
||||
"[trans=%p pending-count=%" PRIuSIZE "]\n",
|
||||
trans, ent->mPendingQ.Length()+1));
|
||||
// put this transaction on the pending queue...
|
||||
InsertTransactionSorted(ent->mPendingQ, trans);
|
||||
InsertTransactionSorted(ent->mPendingQ, pendingTransInfo);
|
||||
}
|
||||
return NS_OK;
|
||||
}
|
||||
|
@ -1700,13 +1758,43 @@ nsHttpConnectionMgr::RecvdConnect()
|
|||
ConditionallyStopTimeoutTick();
|
||||
}
|
||||
|
||||
void
|
||||
nsHttpConnectionMgr::ReleaseClaimedSockets(nsConnectionEntry *ent,
|
||||
PendingTransactionInfo * pendingTransInfo)
|
||||
{
|
||||
if (pendingTransInfo->mHalfOpen) {
|
||||
RefPtr<nsHalfOpenSocket> halfOpen =
|
||||
do_QueryReferent(pendingTransInfo->mHalfOpen);
|
||||
if (halfOpen) {
|
||||
if (halfOpen->Transaction() &&
|
||||
halfOpen->Transaction()->IsNullTransaction()) {
|
||||
LOG(("nsHttpConnectionMgr::ReleaseClaimedSockets - mark halfOpne %p "
|
||||
"speculative again.", halfOpen.get()));
|
||||
halfOpen->SetSpeculative(true);
|
||||
}
|
||||
}
|
||||
pendingTransInfo->mHalfOpen = nullptr;
|
||||
} else if (pendingTransInfo->mActiveConn) {
|
||||
RefPtr<nsHttpConnection> activeConn =
|
||||
do_QueryReferent(pendingTransInfo->mActiveConn);
|
||||
if (activeConn && activeConn->Transaction() &&
|
||||
activeConn->Transaction()->IsNullTransaction()) {
|
||||
NullHttpTransaction *nullTrans = activeConn->Transaction()->QueryNullTransaction();
|
||||
nullTrans->Unclaim();
|
||||
LOG(("nsHttpConnectionMgr::ReleaseClaimedSockets - mark %p unclaimed.",
|
||||
activeConn.get()));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
nsresult
|
||||
nsHttpConnectionMgr::CreateTransport(nsConnectionEntry *ent,
|
||||
nsAHttpTransaction *trans,
|
||||
uint32_t caps,
|
||||
bool speculative,
|
||||
bool isFromPredictor,
|
||||
bool allow1918)
|
||||
bool allow1918,
|
||||
PendingTransactionInfo *pendingTransInfo)
|
||||
{
|
||||
MOZ_ASSERT(PR_GetCurrentThread() == gSocketThread);
|
||||
|
||||
|
@ -1730,13 +1818,18 @@ nsHttpConnectionMgr::CreateTransport(nsConnectionEntry *ent,
|
|||
nsresult rv = sock->SetupPrimaryStreams();
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
if (pendingTransInfo) {
|
||||
pendingTransInfo->mHalfOpen =
|
||||
do_GetWeakReference(static_cast<nsISupportsWeakReference*>(sock));
|
||||
}
|
||||
|
||||
ent->mHalfOpens.AppendElement(sock);
|
||||
mNumHalfOpenConns++;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
void
|
||||
nsHttpConnectionMgr::DispatchSpdyPendingQ(nsTArray<RefPtr<nsHttpTransaction>> &pendingQ,
|
||||
nsHttpConnectionMgr::DispatchSpdyPendingQ(nsTArray<RefPtr<PendingTransactionInfo>> &pendingQ,
|
||||
nsConnectionEntry *ent,
|
||||
nsHttpConnection *conn)
|
||||
{
|
||||
|
@ -1744,36 +1837,38 @@ nsHttpConnectionMgr::DispatchSpdyPendingQ(nsTArray<RefPtr<nsHttpTransaction>> &p
|
|||
return;
|
||||
}
|
||||
|
||||
nsTArray<RefPtr<nsHttpTransaction>> leftovers;
|
||||
nsTArray<RefPtr<PendingTransactionInfo>> leftovers;
|
||||
uint32_t index;
|
||||
// Dispatch all the transactions we can
|
||||
for (index = 0;
|
||||
index < pendingQ.Length() && conn->CanDirectlyActivate();
|
||||
++index) {
|
||||
nsHttpTransaction *trans = pendingQ[index];
|
||||
PendingTransactionInfo *pendingTransInfo = pendingQ[index];
|
||||
|
||||
if (!(trans->Caps() & NS_HTTP_ALLOW_KEEPALIVE) ||
|
||||
trans->Caps() & NS_HTTP_DISALLOW_SPDY) {
|
||||
leftovers.AppendElement(trans);
|
||||
if (!(pendingTransInfo->mTransaction->Caps() & NS_HTTP_ALLOW_KEEPALIVE) ||
|
||||
pendingTransInfo->mTransaction->Caps() & NS_HTTP_DISALLOW_SPDY) {
|
||||
leftovers.AppendElement(pendingTransInfo);
|
||||
continue;
|
||||
}
|
||||
|
||||
nsresult rv = DispatchTransaction(ent, trans, conn);
|
||||
nsresult rv = DispatchTransaction(ent, pendingTransInfo->mTransaction,
|
||||
conn);
|
||||
if (NS_FAILED(rv)) {
|
||||
// this cannot happen, but if due to some bug it does then
|
||||
// close the transaction
|
||||
MOZ_ASSERT(false, "Dispatch SPDY Transaction");
|
||||
LOG(("ProcessSpdyPendingQ Dispatch Transaction failed trans=%p\n",
|
||||
trans));
|
||||
trans->Close(rv);
|
||||
pendingTransInfo->mTransaction.get()));
|
||||
pendingTransInfo->mTransaction->Close(rv);
|
||||
}
|
||||
ReleaseClaimedSockets(ent, pendingTransInfo);
|
||||
}
|
||||
|
||||
// Slurp up the rest of the pending queue into our leftovers bucket (we
|
||||
// might have some left if conn->CanDirectlyActivate returned false)
|
||||
for (; index < pendingQ.Length(); ++index) {
|
||||
nsHttpTransaction *trans = pendingQ[index];
|
||||
leftovers.AppendElement(trans);
|
||||
PendingTransactionInfo *pendingTransInfo = pendingQ[index];
|
||||
leftovers.AppendElement(pendingTransInfo);
|
||||
}
|
||||
|
||||
// Put the leftovers back in the pending queue and get rid of the
|
||||
|
@ -1908,15 +2003,15 @@ nsHttpConnectionMgr::OnMsgShutdown(int32_t, ARefBase *param)
|
|||
|
||||
// Close all urgentStart transactions.
|
||||
while (ent->mUrgentStartQ.Length()) {
|
||||
nsHttpTransaction *trans = ent->mUrgentStartQ[0];
|
||||
trans->Close(NS_ERROR_ABORT);
|
||||
PendingTransactionInfo *pendingTransInfo = ent->mUrgentStartQ[0];
|
||||
pendingTransInfo->mTransaction->Close(NS_ERROR_ABORT);
|
||||
ent->mUrgentStartQ.RemoveElementAt(0);
|
||||
}
|
||||
|
||||
// Close all pending transactions.
|
||||
while (ent->mPendingQ.Length()) {
|
||||
nsHttpTransaction *trans = ent->mPendingQ[0];
|
||||
trans->Close(NS_ERROR_ABORT);
|
||||
PendingTransactionInfo *pendingTransInfo = ent->mPendingQ[0];
|
||||
pendingTransInfo->mTransaction->Close(NS_ERROR_ABORT);
|
||||
ent->mPendingQ.RemoveElementAt(0);
|
||||
}
|
||||
|
||||
|
@ -1985,17 +2080,18 @@ nsHttpConnectionMgr::OnMsgReschedTransaction(int32_t priority, ARefBase *param)
|
|||
|
||||
if (ent) {
|
||||
int32_t caps = trans->Caps();
|
||||
nsTArray<RefPtr<nsHttpTransaction>> *pendingQ;
|
||||
nsTArray<RefPtr<PendingTransactionInfo>> *pendingQ;
|
||||
if (caps & NS_HTTP_URGENT_START) {
|
||||
pendingQ = &(ent->mUrgentStartQ);
|
||||
} else {
|
||||
pendingQ = &(ent->mPendingQ);
|
||||
}
|
||||
|
||||
int32_t index = pendingQ->IndexOf(trans);
|
||||
int32_t index = pendingQ->IndexOf(trans, 0, PendingComparator());
|
||||
if (index >= 0) {
|
||||
RefPtr<PendingTransactionInfo> pendingTransInfo = (*pendingQ)[index];
|
||||
pendingQ->RemoveElementAt(index);
|
||||
InsertTransactionSorted(*pendingQ, trans);
|
||||
InsertTransactionSorted(*pendingQ, pendingTransInfo);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -2026,32 +2122,43 @@ nsHttpConnectionMgr::OnMsgCancelTransaction(int32_t reason, ARefBase *param)
|
|||
if (ent) {
|
||||
uint32_t caps = trans->Caps();
|
||||
int32_t transIndex;
|
||||
// We will abandon all half-open sockets belonging to the given
|
||||
// transaction.
|
||||
RefPtr<PendingTransactionInfo> pendingTransInfo;
|
||||
if (caps & NS_HTTP_URGENT_START) {
|
||||
transIndex = ent->mUrgentStartQ.IndexOf(trans);
|
||||
transIndex = ent->mUrgentStartQ.IndexOf(trans, 0,
|
||||
PendingComparator());
|
||||
if (transIndex >=0) {
|
||||
LOG(("nsHttpConnectionMgr::OnMsgCancelTransaction [trans=%p]"
|
||||
" found in urgentStart queue\n", trans));
|
||||
pendingTransInfo = ent->mUrgentStartQ[transIndex];
|
||||
// We do not need to ReleaseClaimedSockets while we are
|
||||
// going to close them all any way!
|
||||
ent->mUrgentStartQ.RemoveElementAt(transIndex);
|
||||
}
|
||||
} else {
|
||||
transIndex = ent->mPendingQ.IndexOf(trans);
|
||||
transIndex = ent->mPendingQ.IndexOf(trans, 0,
|
||||
PendingComparator());
|
||||
if (transIndex >=0) {
|
||||
LOG(("nsHttpConnectionMgr::OnMsgCancelTransaction [trans=%p]"
|
||||
" found in pending queue\n", trans));
|
||||
pendingTransInfo = ent->mPendingQ[transIndex];
|
||||
// We do not need to ReleaseClaimedSockets while we are
|
||||
// going to close them all any way!
|
||||
ent->mPendingQ.RemoveElementAt(transIndex);
|
||||
}
|
||||
}
|
||||
|
||||
// Abandon all half-open sockets belonging to the given transaction.
|
||||
for (uint32_t index = 0;
|
||||
index < ent->mHalfOpens.Length();
|
||||
++index) {
|
||||
nsHalfOpenSocket *half = ent->mHalfOpens[index];
|
||||
if (trans == half->Transaction()) {
|
||||
if (pendingTransInfo) {
|
||||
RefPtr<nsHalfOpenSocket> half =
|
||||
do_QueryReferent(pendingTransInfo->mHalfOpen);
|
||||
if (half) {
|
||||
MOZ_ASSERT(trans == half->Transaction() ||
|
||||
half->Transaction()->IsNullTransaction());
|
||||
half->Abandon();
|
||||
// there is only one, and now mHalfOpens[] has been changed.
|
||||
break;
|
||||
}
|
||||
pendingTransInfo->mHalfOpen = nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -2132,19 +2239,19 @@ nsHttpConnectionMgr::OnMsgCancelTransactions(int32_t code, ARefBase *param)
|
|||
|
||||
for (uint32_t i = ent->mUrgentStartQ.Length(); i > 0;) {
|
||||
--i;
|
||||
nsHttpTransaction *trans = ent->mUrgentStartQ[i];
|
||||
PendingTransactionInfo *pendingTransInfo = ent->mUrgentStartQ[i];
|
||||
LOG(("nsHttpConnectionMgr::OnMsgCancelTransactions %s %p %p\n",
|
||||
ci->HashKey().get(), ent, trans));
|
||||
trans->Close(reason);
|
||||
ci->HashKey().get(), ent, pendingTransInfo->mTransaction.get()));
|
||||
pendingTransInfo->mTransaction->Close(reason);
|
||||
ent->mUrgentStartQ.RemoveElementAt(i);
|
||||
}
|
||||
|
||||
for (uint32_t i = ent->mPendingQ.Length(); i > 0;) {
|
||||
--i;
|
||||
nsHttpTransaction *trans = ent->mPendingQ[i];
|
||||
PendingTransactionInfo *pendingTransInfo = ent->mPendingQ[i];
|
||||
LOG(("nsHttpConnectionMgr::OnMsgCancelTransactions %s %p %p\n",
|
||||
ci->HashKey().get(), ent, trans));
|
||||
trans->Close(reason);
|
||||
ci->HashKey().get(), ent, pendingTransInfo->mTransaction.get()));
|
||||
pendingTransInfo->mTransaction->Close(reason);
|
||||
ent->mPendingQ.RemoveElementAt(i);
|
||||
}
|
||||
}
|
||||
|
@ -2739,7 +2846,8 @@ nsHttpConnectionMgr::OnMsgSpeculativeConnect(int32_t, ARefBase *param)
|
|||
!AtActiveConnectionLimit(ent, args->mTrans->Caps())) {
|
||||
DebugOnly<nsresult> rv = CreateTransport(ent, args->mTrans,
|
||||
args->mTrans->Caps(), true,
|
||||
isFromPredictor, allow1918);
|
||||
isFromPredictor, allow1918,
|
||||
nullptr);
|
||||
MOZ_ASSERT(NS_SUCCEEDED(rv));
|
||||
} else {
|
||||
LOG(("OnMsgSpeculativeConnect Transport "
|
||||
|
@ -2773,12 +2881,22 @@ ConnectionHandle::PushBack(const char *buf, uint32_t bufLen)
|
|||
|
||||
|
||||
//////////////////////// nsHalfOpenSocket
|
||||
NS_IMPL_ADDREF(nsHttpConnectionMgr::nsHalfOpenSocket)
|
||||
NS_IMPL_RELEASE(nsHttpConnectionMgr::nsHalfOpenSocket)
|
||||
|
||||
NS_IMPL_ISUPPORTS(nsHttpConnectionMgr::nsHalfOpenSocket,
|
||||
nsIOutputStreamCallback,
|
||||
nsITransportEventSink,
|
||||
nsIInterfaceRequestor,
|
||||
nsITimerCallback)
|
||||
NS_INTERFACE_MAP_BEGIN(nsHttpConnectionMgr::nsHalfOpenSocket)
|
||||
NS_INTERFACE_MAP_ENTRY(nsISupportsWeakReference)
|
||||
NS_INTERFACE_MAP_ENTRY(nsIOutputStreamCallback)
|
||||
NS_INTERFACE_MAP_ENTRY(nsITransportEventSink)
|
||||
NS_INTERFACE_MAP_ENTRY(nsIInterfaceRequestor)
|
||||
NS_INTERFACE_MAP_ENTRY(nsITimerCallback)
|
||||
// we have no macro that covers this case.
|
||||
if (aIID.Equals(NS_GET_IID(nsHttpConnectionMgr::nsHalfOpenSocket)) ) {
|
||||
AddRef();
|
||||
*aInstancePtr = this;
|
||||
return NS_OK;
|
||||
} else
|
||||
NS_INTERFACE_MAP_END
|
||||
|
||||
nsHttpConnectionMgr::
|
||||
nsHalfOpenSocket::nsHalfOpenSocket(nsConnectionEntry *ent,
|
||||
|
@ -3187,14 +3305,15 @@ nsHalfOpenSocket::OnOutputStreamReady(nsIAsyncOutputStream *out)
|
|||
uint32_t caps = mTransaction->Caps();
|
||||
int32_t index;
|
||||
if (caps & NS_HTTP_URGENT_START) {
|
||||
index = mEnt->mUrgentStartQ.IndexOf(mTransaction);
|
||||
index = mEnt->mUrgentStartQ.IndexOf(mTransaction, 0,
|
||||
PendingComparator());
|
||||
} else {
|
||||
index = mEnt->mPendingQ.IndexOf(mTransaction);
|
||||
index = mEnt->mPendingQ.IndexOf(mTransaction, 0, PendingComparator());
|
||||
}
|
||||
if (index > -1) {
|
||||
MOZ_ASSERT(!mSpeculative,
|
||||
"Speculative Half Open found mTransaction");
|
||||
RefPtr<nsHttpTransaction> temp;
|
||||
RefPtr<PendingTransactionInfo> temp;
|
||||
if (caps & NS_HTTP_URGENT_START) {
|
||||
temp = mEnt->mUrgentStartQ[index];
|
||||
mEnt->mUrgentStartQ.RemoveElementAt(index);
|
||||
|
@ -3203,7 +3322,9 @@ nsHalfOpenSocket::OnOutputStreamReady(nsIAsyncOutputStream *out)
|
|||
mEnt->mPendingQ.RemoveElementAt(index);
|
||||
}
|
||||
gHttpHandler->ConnMgr()->AddActiveConn(conn, mEnt);
|
||||
rv = gHttpHandler->ConnMgr()->DispatchTransaction(mEnt, temp, conn);
|
||||
rv = gHttpHandler->ConnMgr()->DispatchTransaction(mEnt,
|
||||
temp->mTransaction,
|
||||
conn);
|
||||
} else {
|
||||
// this transaction was dispatched off the pending q before all the
|
||||
// sockets established themselves.
|
||||
|
@ -3258,8 +3379,21 @@ nsHttpConnectionMgr::nsHalfOpenSocket::OnTransportStatus(nsITransport *trans,
|
|||
{
|
||||
MOZ_ASSERT(PR_GetCurrentThread() == gSocketThread);
|
||||
|
||||
if (mTransaction)
|
||||
if (mTransaction) {
|
||||
if ((trans == mSocketTransport) ||
|
||||
((trans == mBackupTransport) && (status == NS_NET_STATUS_CONNECTED_TO) &&
|
||||
mEnt->mPendingQ.Contains(mTransaction, PendingComparator()))) {
|
||||
// Send this status event only if the transaction is still panding,
|
||||
// i.e. it has not found a free already connected socket.
|
||||
// Sockets in halfOpen state can only get following events:
|
||||
// NS_NET_STATUS_RESOLVING_HOST, NS_NET_STATUS_RESOLVED_HOST,
|
||||
// NS_NET_STATUS_CONNECTING_TO and NS_NET_STATUS_CONNECTED_TO.
|
||||
// mBackupTransport is only started after
|
||||
// NS_NET_STATUS_CONNECTING_TO of mSocketTransport, so ignore all
|
||||
// mBackupTransport events until NS_NET_STATUS_CONNECTED_TO.
|
||||
mTransaction->OnTransportStatus(trans, status, progress);
|
||||
}
|
||||
}
|
||||
|
||||
MOZ_ASSERT(trans == mSocketTransport || trans == mBackupTransport);
|
||||
if (status == NS_NET_STATUS_CONNECTED_TO) {
|
||||
|
|
|
@ -18,6 +18,7 @@
|
|||
#include "mozilla/Attributes.h"
|
||||
#include "AlternateServices.h"
|
||||
#include "ARefBase.h"
|
||||
#include "nsWeakReference.h"
|
||||
|
||||
#include "nsIObserver.h"
|
||||
#include "nsITimer.h"
|
||||
|
@ -30,6 +31,10 @@ class EventTokenBucket;
|
|||
class NullHttpTransaction;
|
||||
struct HttpRetParams;
|
||||
|
||||
// 8d411b53-54bc-4a99-8b78-ff125eab1564
|
||||
#define NS_HALFOPENSOCKET_IID \
|
||||
{ 0x8d411b53, 0x54bc, 0x4a99, {0x8b, 0x78, 0xff, 0x12, 0x5e, 0xab, 0x15, 0x64 }}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
// message handlers have this signature
|
||||
|
@ -200,6 +205,7 @@ private:
|
|||
virtual ~nsHttpConnectionMgr();
|
||||
|
||||
class nsHalfOpenSocket;
|
||||
class PendingTransactionInfo;
|
||||
|
||||
// nsConnectionEntry
|
||||
//
|
||||
|
@ -214,8 +220,8 @@ private:
|
|||
~nsConnectionEntry();
|
||||
|
||||
RefPtr<nsHttpConnectionInfo> mConnInfo;
|
||||
nsTArray<RefPtr<nsHttpTransaction> > mUrgentStartQ;// the urgent start transaction queue
|
||||
nsTArray<RefPtr<nsHttpTransaction> > mPendingQ; // pending transaction queue
|
||||
nsTArray<RefPtr<PendingTransactionInfo> > mUrgentStartQ;// the urgent start transaction queue
|
||||
nsTArray<RefPtr<PendingTransactionInfo> > mPendingQ; // pending transaction queue
|
||||
nsTArray<RefPtr<nsHttpConnection> > mActiveConns; // active connections
|
||||
nsTArray<RefPtr<nsHttpConnection> > mIdleConns; // idle persistent connections
|
||||
nsTArray<nsHalfOpenSocket*> mHalfOpens; // half open connections
|
||||
|
@ -276,11 +282,13 @@ private:
|
|||
class nsHalfOpenSocket final : public nsIOutputStreamCallback,
|
||||
public nsITransportEventSink,
|
||||
public nsIInterfaceRequestor,
|
||||
public nsITimerCallback
|
||||
public nsITimerCallback,
|
||||
public nsSupportsWeakReference
|
||||
{
|
||||
~nsHalfOpenSocket();
|
||||
|
||||
public:
|
||||
NS_DECLARE_STATIC_IID_ACCESSOR(NS_HALFOPENSOCKET_IID)
|
||||
NS_DECL_THREADSAFE_ISUPPORTS
|
||||
NS_DECL_NSIOUTPUTSTREAMCALLBACK
|
||||
NS_DECL_NSITRANSPORTEVENTSINK
|
||||
|
@ -361,6 +369,35 @@ private:
|
|||
};
|
||||
friend class nsHalfOpenSocket;
|
||||
|
||||
class PendingTransactionInfo : public ARefBase
|
||||
{
|
||||
public:
|
||||
explicit PendingTransactionInfo(nsHttpTransaction * trans)
|
||||
: mTransaction(trans)
|
||||
{}
|
||||
|
||||
NS_INLINE_DECL_THREADSAFE_REFCOUNTING(PendingTransactionInfo)
|
||||
|
||||
void PrintDiagnostics(nsCString &log);
|
||||
public: // meant to be public.
|
||||
RefPtr<nsHttpTransaction> mTransaction;
|
||||
nsWeakPtr mHalfOpen;
|
||||
nsWeakPtr mActiveConn;
|
||||
|
||||
private:
|
||||
virtual ~PendingTransactionInfo() {}
|
||||
};
|
||||
friend class PendingTransactionInfo;
|
||||
|
||||
class PendingComparator
|
||||
{
|
||||
public:
|
||||
bool Equals(const PendingTransactionInfo *aPendingTrans,
|
||||
const nsAHttpTransaction *aTrans) const {
|
||||
return aPendingTrans->mTransaction.get() == aTrans;
|
||||
}
|
||||
};
|
||||
|
||||
//-------------------------------------------------------------------------
|
||||
// NOTE: these members may be accessed from any thread (use mReentrantMonitor)
|
||||
//-------------------------------------------------------------------------
|
||||
|
@ -382,14 +419,14 @@ private:
|
|||
|
||||
MOZ_MUST_USE bool ProcessPendingQForEntry(nsConnectionEntry *,
|
||||
bool considerAll);
|
||||
void DispatchPendingQ(nsTArray<RefPtr<nsHttpTransaction>> &pendingQ,
|
||||
void DispatchPendingQ(nsTArray<RefPtr<PendingTransactionInfo>> &pendingQ,
|
||||
nsConnectionEntry *ent,
|
||||
bool &dispatchedSuccessfully,
|
||||
bool considerAll);
|
||||
bool AtActiveConnectionLimit(nsConnectionEntry *, uint32_t caps);
|
||||
MOZ_MUST_USE nsresult TryDispatchTransaction(nsConnectionEntry *ent,
|
||||
bool onlyReusedConnection,
|
||||
nsHttpTransaction *trans);
|
||||
PendingTransactionInfo *pendingTransInfo);
|
||||
MOZ_MUST_USE nsresult DispatchTransaction(nsConnectionEntry *,
|
||||
nsHttpTransaction *,
|
||||
nsHttpConnection *);
|
||||
|
@ -405,17 +442,27 @@ private:
|
|||
void ReportProxyTelemetry(nsConnectionEntry *ent);
|
||||
MOZ_MUST_USE nsresult CreateTransport(nsConnectionEntry *,
|
||||
nsAHttpTransaction *, uint32_t, bool,
|
||||
bool, bool);
|
||||
bool, bool,
|
||||
PendingTransactionInfo *pendingTransInfo);
|
||||
void AddActiveConn(nsHttpConnection *, nsConnectionEntry *);
|
||||
void DecrementActiveConnCount(nsHttpConnection *);
|
||||
void StartedConnect();
|
||||
void RecvdConnect();
|
||||
|
||||
// This function will unclaim the claimed connection or set a halfOpen
|
||||
// socket to the speculative state if the transaction claiming them ends up
|
||||
// using another connection.
|
||||
void ReleaseClaimedSockets(nsConnectionEntry *ent,
|
||||
PendingTransactionInfo * pendingTransInfo);
|
||||
|
||||
void InsertTransactionSorted(nsTArray<RefPtr<PendingTransactionInfo> > &pendingQ,
|
||||
PendingTransactionInfo *pendingTransInfo);
|
||||
|
||||
nsConnectionEntry *GetOrCreateConnectionEntry(nsHttpConnectionInfo *,
|
||||
bool allowWildCard);
|
||||
|
||||
MOZ_MUST_USE nsresult MakeNewConnection(nsConnectionEntry *ent,
|
||||
nsHttpTransaction *trans);
|
||||
PendingTransactionInfo *pendingTransInfo);
|
||||
|
||||
// Manage the preferred spdy connection entry for this address
|
||||
nsConnectionEntry *GetSpdyPreferredEnt(nsConnectionEntry *aOriginalEntry);
|
||||
|
@ -429,7 +476,7 @@ private:
|
|||
nsHttpTransaction *trans);
|
||||
|
||||
void ProcessSpdyPendingQ(nsConnectionEntry *ent);
|
||||
void DispatchSpdyPendingQ(nsTArray<RefPtr<nsHttpTransaction>> &pendingQ,
|
||||
void DispatchSpdyPendingQ(nsTArray<RefPtr<PendingTransactionInfo>> &pendingQ,
|
||||
nsConnectionEntry *ent,
|
||||
nsHttpConnection *conn);
|
||||
// used to marshall events to the socket transport thread.
|
||||
|
@ -504,6 +551,8 @@ private:
|
|||
uint64_t mCurrentTopLevelOuterContentWindowId;
|
||||
};
|
||||
|
||||
NS_DEFINE_STATIC_IID_ACCESSOR(nsHttpConnectionMgr::nsHalfOpenSocket, NS_HALFOPENSOCKET_IID)
|
||||
|
||||
} // namespace net
|
||||
} // namespace mozilla
|
||||
|
||||
|
|
Загрузка…
Ссылка в новой задаче