|
@@ -0,0 +1,657 @@
|
|
|
+# HG changeset patch
|
|
|
+# User Honza Bambas <honzab.moz@firemni.cz>
|
|
|
+# Date 1515502680 18000
|
|
|
+# Node ID f6bd79484f2311acb4ebd7c1ee2071d9d2e29710
|
|
|
+# Parent ac072dbb697e9bbc91f0ba70f128dee4582da0b9
|
|
|
+Bug 1405446 - Connections created for urgent-start requests are of limits for non-urgent-start ones, r=dragana
|
|
|
+
|
|
|
+diff --git a/netwerk/protocol/http/nsHttpConnection.cpp b/netwerk/protocol/http/nsHttpConnection.cpp
|
|
|
+--- a/netwerk/protocol/http/nsHttpConnection.cpp
|
|
|
++++ b/netwerk/protocol/http/nsHttpConnection.cpp
|
|
|
+@@ -14,16 +14,17 @@
|
|
|
+ #define LOG_ENABLED() LOG5_ENABLED()
|
|
|
+
|
|
|
+ #include "ASpdySession.h"
|
|
|
+ #include "mozilla/ChaosMode.h"
|
|
|
+ #include "nsHttpConnection.h"
|
|
|
+ #include "nsHttpHandler.h"
|
|
|
+ #include "nsHttpRequestHead.h"
|
|
|
+ #include "nsHttpResponseHead.h"
|
|
|
++#include "nsIClassOfService.h"
|
|
|
+ #include "nsIOService.h"
|
|
|
+ #include "nsISocketTransport.h"
|
|
|
+ #include "nsSocketTransportService2.h"
|
|
|
+ #include "nsISSLSocketControl.h"
|
|
|
+ #include "nsISupportsPriority.h"
|
|
|
+ #include "nsPreloadedStream.h"
|
|
|
+ #include "nsProxyRelease.h"
|
|
|
+ #include "nsSocketTransport2.h"
|
|
|
+@@ -46,16 +47,18 @@ nsHttpConnection::nsHttpConnection()
|
|
|
+ , mCallbacksLock("nsHttpConnection::mCallbacksLock")
|
|
|
+ , mConsiderReusedAfterInterval(0)
|
|
|
+ , mConsiderReusedAfterEpoch(0)
|
|
|
+ , mCurrentBytesRead(0)
|
|
|
+ , mMaxBytesRead(0)
|
|
|
+ , mTotalBytesRead(0)
|
|
|
+ , mTotalBytesWritten(0)
|
|
|
+ , mContentBytesWritten(0)
|
|
|
++ , mUrgentStartPreferred(false)
|
|
|
++ , mUrgentStartPreferredKnown(false)
|
|
|
+ , mConnectedTransport(false)
|
|
|
+ , mKeepAlive(true) // assume to keep-alive by default
|
|
|
+ , mKeepAliveMask(true)
|
|
|
+ , mDontReuse(false)
|
|
|
+ , mIsReused(false)
|
|
|
+ , mCompletedProxyConnect(false)
|
|
|
+ , mLastTransactionExpectedNoContent(false)
|
|
|
+ , mIdleMonitoring(false)
|
|
|
+@@ -591,16 +594,17 @@ nsHttpConnection::Activate(nsAHttpTransa
|
|
|
+
|
|
|
+ if (!mExperienced && !trans->IsNullTransaction()) {
|
|
|
+ if (!mFastOpen) {
|
|
|
+ mExperienced = true;
|
|
|
+ }
|
|
|
+ nsHttpTransaction *hTrans = trans->QueryHttpTransaction();
|
|
|
+ if (hTrans) {
|
|
|
+ hTrans->BootstrapTimings(mBootstrappedTimings);
|
|
|
++ SetUrgentStartPreferred(hTrans->ClassOfService() & nsIClassOfService::UrgentStart);
|
|
|
+ }
|
|
|
+ mBootstrappedTimings = TimingStruct();
|
|
|
+ }
|
|
|
+
|
|
|
+ mTransactionCaps = caps;
|
|
|
+ mPriority = pri;
|
|
|
+ if (mTransaction && mUsingSpdyVersion) {
|
|
|
+ return AddTransaction(trans, pri);
|
|
|
+@@ -1032,16 +1036,27 @@ nsHttpConnection::IsAlive()
|
|
|
+ LOG(("pretending socket is still alive to test restart logic\n"));
|
|
|
+ alive = true;
|
|
|
+ }
|
|
|
+ #endif
|
|
|
+
|
|
|
+ return alive;
|
|
|
+ }
|
|
|
+
|
|
|
++void
|
|
|
++nsHttpConnection::SetUrgentStartPreferred(bool urgent)
|
|
|
++{
|
|
|
++ if (mExperienced && !mUrgentStartPreferredKnown) {
|
|
|
++ // Set only according the first ever dispatched non-null transaction
|
|
|
++ mUrgentStartPreferredKnown = true;
|
|
|
++ mUrgentStartPreferred = urgent;
|
|
|
++ LOG(("nsHttpConnection::SetUrgentStartPreferred [this=%p urgent=%d]", this, urgent));
|
|
|
++ }
|
|
|
++}
|
|
|
++
|
|
|
+ //----------------------------------------------------------------------------
|
|
|
+ // nsHttpConnection::nsAHttpConnection compatible methods
|
|
|
+ //----------------------------------------------------------------------------
|
|
|
+
|
|
|
+ nsresult
|
|
|
+ nsHttpConnection::OnHeadersAvailable(nsAHttpTransaction *trans,
|
|
|
+ nsHttpRequestHead *requestHead,
|
|
|
+ nsHttpResponseHead *responseHead,
|
|
|
+@@ -2431,17 +2446,23 @@ nsHttpConnection::CloseConnectionFastOpe
|
|
|
+
|
|
|
+ void
|
|
|
+ nsHttpConnection::SetFastOpen(bool aFastOpen)
|
|
|
+ {
|
|
|
+ mFastOpen = aFastOpen;
|
|
|
+ if (!mFastOpen &&
|
|
|
+ mTransaction &&
|
|
|
+ !mTransaction->IsNullTransaction()) {
|
|
|
++
|
|
|
+ mExperienced = true;
|
|
|
++
|
|
|
++ nsHttpTransaction *hTrans = mTransaction->QueryHttpTransaction();
|
|
|
++ if (hTrans) {
|
|
|
++ SetUrgentStartPreferred(hTrans->ClassOfService() & nsIClassOfService::UrgentStart);
|
|
|
++ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ void
|
|
|
+ nsHttpConnection::SetFastOpenStatus(uint8_t tfoStatus) {
|
|
|
+ mFastOpenStatus = tfoStatus;
|
|
|
+ if ((mFastOpenStatus >= TFO_FAILED_CONNECTION_REFUSED) &&
|
|
|
+ (mFastOpenStatus <= TFO_FAILED_BACKUP_CONNECTION_TFO_DATA_COOKIE_NOT_ACCEPTED) &&
|
|
|
+diff --git a/netwerk/protocol/http/nsHttpConnection.h b/netwerk/protocol/http/nsHttpConnection.h
|
|
|
+--- a/netwerk/protocol/http/nsHttpConnection.h
|
|
|
++++ b/netwerk/protocol/http/nsHttpConnection.h
|
|
|
+@@ -130,16 +130,19 @@ public:
|
|
|
+
|
|
|
+ // A connection is forced into plaintext when it is intended to be used as a CONNECT
|
|
|
+ // tunnel but the setup fails. The plaintext only carries the CONNECT error.
|
|
|
+ void ForcePlainText()
|
|
|
+ {
|
|
|
+ mForcePlainText = true;
|
|
|
+ }
|
|
|
+
|
|
|
++ bool IsUrgentStartPreferred() const { return mUrgentStartPreferredKnown && mUrgentStartPreferred; }
|
|
|
++ void SetUrgentStartPreferred(bool urgent);
|
|
|
++
|
|
|
+ nsISocketTransport *Transport() { return mSocketTransport; }
|
|
|
+ nsAHttpTransaction *Transaction() { return mTransaction; }
|
|
|
+ nsHttpConnectionInfo *ConnectionInfo() { return mConnInfo; }
|
|
|
+
|
|
|
+ // nsAHttpConnection compatible methods (non-virtual):
|
|
|
+ MOZ_MUST_USE nsresult OnHeadersAvailable(nsAHttpTransaction *,
|
|
|
+ nsHttpRequestHead *,
|
|
|
+ nsHttpResponseHead *, bool *reset);
|
|
|
+@@ -321,16 +324,21 @@ private:
|
|
|
+ int64_t mTotalBytesRead; // total data read
|
|
|
+ int64_t mTotalBytesWritten; // does not include CONNECT tunnel
|
|
|
+ int64_t mContentBytesWritten; // does not include CONNECT tunnel or TLS
|
|
|
+
|
|
|
+ RefPtr<nsIAsyncInputStream> mInputOverflow;
|
|
|
+
|
|
|
+ PRIntervalTime mRtt;
|
|
|
+
|
|
|
++ // Whether the first non-null transaction dispatched on this connection was
|
|
|
++ // urgent-start or not
|
|
|
++ bool mUrgentStartPreferred;
|
|
|
++ // A flag to prevent reset of mUrgentStartPreferred by subsequent transactions
|
|
|
++ bool mUrgentStartPreferredKnown;
|
|
|
+ bool mConnectedTransport;
|
|
|
+ bool mKeepAlive;
|
|
|
+ bool mKeepAliveMask;
|
|
|
+ bool mDontReuse;
|
|
|
+ bool mIsReused;
|
|
|
+ bool mCompletedProxyConnect;
|
|
|
+ bool mLastTransactionExpectedNoContent;
|
|
|
+ bool mIdleMonitoring;
|
|
|
+diff --git a/netwerk/protocol/http/nsHttpConnectionMgr.cpp b/netwerk/protocol/http/nsHttpConnectionMgr.cpp
|
|
|
+--- a/netwerk/protocol/http/nsHttpConnectionMgr.cpp
|
|
|
++++ b/netwerk/protocol/http/nsHttpConnectionMgr.cpp
|
|
|
+@@ -1147,16 +1147,40 @@ nsHttpConnectionMgr::ProcessPendingQForE
|
|
|
+ LOG((" %p", info->mTransaction.get()));
|
|
|
+ }
|
|
|
+ for (auto it = ent->mPendingTransactionTable.Iter(); !it.Done(); it.Next()) {
|
|
|
+ LOG(("] window id = %" PRIx64 " queue [", it.Key()));
|
|
|
+ for (auto info : *it.UserData()) {
|
|
|
+ LOG((" %p", info->mTransaction.get()));
|
|
|
+ }
|
|
|
+ }
|
|
|
++ LOG(("] active urgent conns ["));
|
|
|
++ for (nsHttpConnection* conn : ent->mActiveConns) {
|
|
|
++ if (conn->IsUrgentStartPreferred()) {
|
|
|
++ LOG((" %p", conn));
|
|
|
++ }
|
|
|
++ }
|
|
|
++ LOG(("] active regular conns ["));
|
|
|
++ for (nsHttpConnection* conn : ent->mActiveConns) {
|
|
|
++ if (!conn->IsUrgentStartPreferred()) {
|
|
|
++ LOG((" %p", conn));
|
|
|
++ }
|
|
|
++ }
|
|
|
++ LOG(("] idle urgent conns ["));
|
|
|
++ for (nsHttpConnection* conn : ent->mIdleConns) {
|
|
|
++ if (conn->IsUrgentStartPreferred()) {
|
|
|
++ LOG((" %p", conn));
|
|
|
++ }
|
|
|
++ }
|
|
|
++ LOG(("] idle regular conns ["));
|
|
|
++ for (nsHttpConnection* conn : ent->mIdleConns) {
|
|
|
++ if (!conn->IsUrgentStartPreferred()) {
|
|
|
++ LOG((" %p", conn));
|
|
|
++ }
|
|
|
++ }
|
|
|
+ LOG(("]"));
|
|
|
+ }
|
|
|
+
|
|
|
+ if (!ent->mUrgentStartQ.Length() && !ent->PendingQLength()) {
|
|
|
+ return false;
|
|
|
+ }
|
|
|
+ ProcessSpdyPendingQ(ent);
|
|
|
+
|
|
|
+@@ -1340,17 +1364,18 @@ nsHttpConnectionMgr::MakeNewConnection(n
|
|
|
+ nsHttpTransaction *trans = pendingTransInfo->mTransaction;
|
|
|
+
|
|
|
+ LOG(("nsHttpConnectionMgr::MakeNewConnection %p ent=%p trans=%p",
|
|
|
+ this, ent, trans));
|
|
|
+ MOZ_ASSERT(OnSocketThread(), "not on socket thread");
|
|
|
+
|
|
|
+ uint32_t halfOpenLength = ent->mHalfOpens.Length();
|
|
|
+ for (uint32_t i = 0; i < halfOpenLength; i++) {
|
|
|
+- if (ent->mHalfOpens[i]->Claim()) {
|
|
|
++ auto halfOpen = ent->mHalfOpens[i];
|
|
|
++ if (halfOpen->AcceptsTransaction(trans) && halfOpen->Claim()) {
|
|
|
+ // We've found a speculative connection or a connection that
|
|
|
+ // is free to be used in the half open list.
|
|
|
+ // A free to be used connection is a connection that was
|
|
|
+ // open for a concrete transaction, but that trunsaction
|
|
|
+ // ended up using another connection.
|
|
|
+ LOG(("nsHttpConnectionMgr::MakeNewConnection [ci = %s]\n"
|
|
|
+ "Found a speculative or a free-to-use half open connection\n",
|
|
|
+ ent->mConnInfo->HashKey().get()));
|
|
|
+@@ -1447,16 +1472,17 @@ nsHttpConnectionMgr::MakeNewConnection(n
|
|
|
+ outerLoopEnd:
|
|
|
+ ;
|
|
|
+ }
|
|
|
+
|
|
|
+ if (AtActiveConnectionLimit(ent, trans->Caps()))
|
|
|
+ return NS_ERROR_NOT_AVAILABLE;
|
|
|
+
|
|
|
+ nsresult rv = CreateTransport(ent, trans, trans->Caps(), false, false,
|
|
|
++ trans->ClassOfService() & nsIClassOfService::UrgentStart,
|
|
|
+ true, pendingTransInfo);
|
|
|
+ if (NS_FAILED(rv)) {
|
|
|
+ /* hard failure */
|
|
|
+ LOG(("nsHttpConnectionMgr::MakeNewConnection [ci = %s trans = %p] "
|
|
|
+ "CreateTransport() hard failure.\n",
|
|
|
+ ent->mConnInfo->HashKey().get(), trans));
|
|
|
+ trans->Close(rv);
|
|
|
+ if (rv == NS_ERROR_NOT_AVAILABLE)
|
|
|
+@@ -1578,45 +1604,21 @@ nsHttpConnectionMgr::TryDispatchTransact
|
|
|
+ if (!runNow) {
|
|
|
+ LOG((" blocked due to rate pacing trans=%p\n", trans));
|
|
|
+ return NS_ERROR_NOT_AVAILABLE;
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ // step 2
|
|
|
+ // consider an idle persistent connection
|
|
|
++ bool idleConnsAllUrgent = false;
|
|
|
+ if (caps & NS_HTTP_ALLOW_KEEPALIVE) {
|
|
|
+- RefPtr<nsHttpConnection> conn;
|
|
|
+- while (!conn && (ent->mIdleConns.Length() > 0)) {
|
|
|
+- conn = ent->mIdleConns[0];
|
|
|
+- ent->mIdleConns.RemoveElementAt(0);
|
|
|
+- mNumIdleConns--;
|
|
|
+-
|
|
|
+- // we check if the connection can be reused before even checking if
|
|
|
+- // it is a "matching" connection.
|
|
|
+- if (!conn->CanReuse()) {
|
|
|
+- LOG((" dropping stale connection: [conn=%p]\n", conn.get()));
|
|
|
+- conn->Close(NS_ERROR_ABORT);
|
|
|
+- conn = nullptr;
|
|
|
+- }
|
|
|
+- else {
|
|
|
+- LOG((" reusing connection [conn=%p]\n", conn.get()));
|
|
|
+- conn->EndIdleMonitoring();
|
|
|
+- }
|
|
|
+-
|
|
|
+- // If there are no idle connections left at all, we need to make
|
|
|
+- // sure that we are not pruning dead connections anymore.
|
|
|
+- ConditionallyStopPruneDeadConnectionsTimer();
|
|
|
+- }
|
|
|
+- if (conn) {
|
|
|
+- // This will update the class of the connection to be the class of
|
|
|
+- // the transaction dispatched on it.
|
|
|
+- AddActiveConn(conn, ent);
|
|
|
+- nsresult rv = DispatchTransaction(ent, trans, conn);
|
|
|
+- NS_ENSURE_SUCCESS(rv, rv);
|
|
|
++ nsresult rv = TryDispatchTransactionOnIdleConn(ent, pendingTransInfo,
|
|
|
++ true, &idleConnsAllUrgent);
|
|
|
++ if (NS_SUCCEEDED(rv)) {
|
|
|
+ LOG((" dispatched step 2 (idle) trans=%p\n", trans));
|
|
|
+ return NS_OK;
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ // step 3
|
|
|
+ // consider pipelining scripts and revalidations
|
|
|
+ // h1 pipelining has been removed
|
|
|
+@@ -1632,16 +1634,31 @@ nsHttpConnectionMgr::TryDispatchTransact
|
|
|
+
|
|
|
+ if (rv != NS_ERROR_NOT_AVAILABLE) {
|
|
|
+ // not available return codes should try next step as they are
|
|
|
+ // not hard errors. Other codes should stop now
|
|
|
+ LOG((" failed step 4 (%" PRIx32 ") trans=%p\n",
|
|
|
+ static_cast<uint32_t>(rv), trans));
|
|
|
+ return rv;
|
|
|
+ }
|
|
|
++
|
|
|
++ // repeat step 2 when there are only idle connections and all are urgent,
|
|
|
++ // don't respect urgency so that non-urgent transaction will be allowed
|
|
|
++ // to dispatch on an urgent-start-only marked connection to avoid
|
|
|
++ // dispatch deadlocks
|
|
|
++ if (!(trans->ClassOfService() & nsIClassOfService::UrgentStart) &&
|
|
|
++ idleConnsAllUrgent &&
|
|
|
++ ent->mActiveConns.Length() < MaxPersistConnections(ent))
|
|
|
++ {
|
|
|
++ rv = TryDispatchTransactionOnIdleConn(ent, pendingTransInfo, false);
|
|
|
++ if (NS_SUCCEEDED(rv)) {
|
|
|
++ LOG((" dispatched step 2a (idle, reuse urgent) trans=%p\n", trans));
|
|
|
++ return NS_OK;
|
|
|
++ }
|
|
|
++ }
|
|
|
+ } else if (trans->TunnelProvider() && trans->TunnelProvider()->MaybeReTunnel(trans)) {
|
|
|
+ LOG((" sort of dispatched step 4a tunnel requeue trans=%p\n", trans));
|
|
|
+ // the tunnel provider took responsibility for making a new tunnel
|
|
|
+ return NS_OK;
|
|
|
+ }
|
|
|
+
|
|
|
+ // step 5
|
|
|
+ // previously pipelined anything here if allowed but h1 pipelining has been removed
|
|
|
+@@ -1654,16 +1671,82 @@ nsHttpConnectionMgr::TryDispatchTransact
|
|
|
+ unusedSpdyPersistentConnection->DontReuse();
|
|
|
+ }
|
|
|
+
|
|
|
+ LOG((" not dispatched (queued) trans=%p\n", trans));
|
|
|
+ return NS_ERROR_NOT_AVAILABLE; /* queue it */
|
|
|
+ }
|
|
|
+
|
|
|
+ nsresult
|
|
|
++nsHttpConnectionMgr::TryDispatchTransactionOnIdleConn(
|
|
|
++ nsConnectionEntry * ent, PendingTransactionInfo * pendingTransInfo,
|
|
|
++ bool respectUrgency, bool *allUrgent)
|
|
|
++{
|
|
|
++ bool onlyUrgent = !!ent->mIdleConns.Length();
|
|
|
++
|
|
|
++ nsHttpTransaction *trans = pendingTransInfo->mTransaction;
|
|
|
++ bool urgentTrans = trans->ClassOfService() & nsIClassOfService::UrgentStart;
|
|
|
++
|
|
|
++ LOG(("nsHttpConnectionMgr::TryDispatchTransactionOnIdleConn, ent=%p, trans=%p, urgent=%d",
|
|
|
++ ent, trans, urgentTrans));
|
|
|
++
|
|
|
++ RefPtr<nsHttpConnection> conn;
|
|
|
++ size_t index = 0;
|
|
|
++ while (!conn && (ent->mIdleConns.Length() > index)) {
|
|
|
++ conn = ent->mIdleConns[index];
|
|
|
++
|
|
|
++ // non-urgent transactions can only be dispatched on non-urgent
|
|
|
++ // started or used connections.
|
|
|
++ if (respectUrgency && conn->IsUrgentStartPreferred() && !urgentTrans) {
|
|
|
++ LOG((" skipping urgent: [conn=%p]", conn.get()));
|
|
|
++ conn = nullptr;
|
|
|
++ ++index;
|
|
|
++ continue;
|
|
|
++ }
|
|
|
++
|
|
|
++ onlyUrgent = false;
|
|
|
++
|
|
|
++ ent->mIdleConns.RemoveElementAt(index);
|
|
|
++ mNumIdleConns--;
|
|
|
++
|
|
|
++ // we check if the connection can be reused before even checking if
|
|
|
++ // it is a "matching" connection.
|
|
|
++ if (!conn->CanReuse()) {
|
|
|
++ LOG((" dropping stale connection: [conn=%p]\n", conn.get()));
|
|
|
++ conn->Close(NS_ERROR_ABORT);
|
|
|
++ conn = nullptr;
|
|
|
++ }
|
|
|
++ else {
|
|
|
++ LOG((" reusing connection: [conn=%p]\n", conn.get()));
|
|
|
++ conn->EndIdleMonitoring();
|
|
|
++ }
|
|
|
++
|
|
|
++ // If there are no idle connections left at all, we need to make
|
|
|
++ // sure that we are not pruning dead connections anymore.
|
|
|
++ ConditionallyStopPruneDeadConnectionsTimer();
|
|
|
++ }
|
|
|
++
|
|
|
++ if (allUrgent) {
|
|
|
++ *allUrgent = onlyUrgent;
|
|
|
++ }
|
|
|
++
|
|
|
++ if (conn) {
|
|
|
++ // This will update the class of the connection to be the class of
|
|
|
++ // the transaction dispatched on it.
|
|
|
++ AddActiveConn(conn, ent);
|
|
|
++ nsresult rv = DispatchTransaction(ent, trans, conn);
|
|
|
++ NS_ENSURE_SUCCESS(rv, rv);
|
|
|
++
|
|
|
++ return NS_OK;
|
|
|
++ }
|
|
|
++
|
|
|
++ return NS_ERROR_NOT_AVAILABLE;
|
|
|
++}
|
|
|
++
|
|
|
++nsresult
|
|
|
+ nsHttpConnectionMgr::DispatchTransaction(nsConnectionEntry *ent,
|
|
|
+ nsHttpTransaction *trans,
|
|
|
+ nsHttpConnection *conn)
|
|
|
+ {
|
|
|
+ uint32_t caps = trans->Caps();
|
|
|
+ int32_t priority = trans->Priority();
|
|
|
+ nsresult rv;
|
|
|
+
|
|
|
+@@ -1947,26 +2030,28 @@ nsHttpConnectionMgr::ReleaseClaimedSocke
|
|
|
+ }
|
|
|
+
|
|
|
+ nsresult
|
|
|
+ nsHttpConnectionMgr::CreateTransport(nsConnectionEntry *ent,
|
|
|
+ nsAHttpTransaction *trans,
|
|
|
+ uint32_t caps,
|
|
|
+ bool speculative,
|
|
|
+ bool isFromPredictor,
|
|
|
++ bool urgentStart,
|
|
|
+ bool allow1918,
|
|
|
+ PendingTransactionInfo *pendingTransInfo)
|
|
|
+ {
|
|
|
+ MOZ_ASSERT(OnSocketThread(), "not on socket thread");
|
|
|
+ MOZ_ASSERT((speculative && !pendingTransInfo) ||
|
|
|
+ (!speculative && pendingTransInfo));
|
|
|
+
|
|
|
+ RefPtr<nsHalfOpenSocket> sock = new nsHalfOpenSocket(ent, trans, caps,
|
|
|
+ speculative,
|
|
|
+- isFromPredictor);
|
|
|
++ isFromPredictor,
|
|
|
++ urgentStart);
|
|
|
+
|
|
|
+ if (speculative) {
|
|
|
+ sock->SetAllow1918(allow1918);
|
|
|
+ }
|
|
|
+ // The socket stream holds the reference to the half open
|
|
|
+ // socket - so if the stream fails to init the half open
|
|
|
+ // will go away.
|
|
|
+ nsresult rv = sock->SetupPrimaryStreams();
|
|
|
+@@ -3770,18 +3855,18 @@ nsHttpConnectionMgr::OnMsgSpeculativeCon
|
|
|
+ bool keepAlive = args->mTrans->Caps() & NS_HTTP_ALLOW_KEEPALIVE;
|
|
|
+ if (mNumHalfOpenConns < parallelSpeculativeConnectLimit &&
|
|
|
+ ((ignoreIdle && (ent->mIdleConns.Length() < parallelSpeculativeConnectLimit)) ||
|
|
|
+ !ent->mIdleConns.Length()) &&
|
|
|
+ !(keepAlive && RestrictConnections(ent)) &&
|
|
|
+ !AtActiveConnectionLimit(ent, args->mTrans->Caps())) {
|
|
|
+ DebugOnly<nsresult> rv = CreateTransport(ent, args->mTrans,
|
|
|
+ args->mTrans->Caps(), true,
|
|
|
+- isFromPredictor, allow1918,
|
|
|
+- nullptr);
|
|
|
++ isFromPredictor, false,
|
|
|
++ allow1918, nullptr);
|
|
|
+ MOZ_ASSERT(NS_SUCCEEDED(rv));
|
|
|
+ } else {
|
|
|
+ LOG(("OnMsgSpeculativeConnect Transport "
|
|
|
+ "not created due to existing connection count\n"));
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ bool
|
|
|
+@@ -3828,21 +3913,23 @@ NS_INTERFACE_MAP_BEGIN(nsHttpConnectionM
|
|
|
+ } else
|
|
|
+ NS_INTERFACE_MAP_END
|
|
|
+
|
|
|
+ nsHttpConnectionMgr::
|
|
|
+ nsHalfOpenSocket::nsHalfOpenSocket(nsConnectionEntry *ent,
|
|
|
+ nsAHttpTransaction *trans,
|
|
|
+ uint32_t caps,
|
|
|
+ bool speculative,
|
|
|
+- bool isFromPredictor)
|
|
|
++ bool isFromPredictor,
|
|
|
++ bool urgentStart)
|
|
|
+ : mTransaction(trans)
|
|
|
+ , mDispatchedMTransaction(false)
|
|
|
+ , mCaps(caps)
|
|
|
+ , mSpeculative(speculative)
|
|
|
++ , mUrgentStart(urgentStart)
|
|
|
+ , mIsFromPredictor(isFromPredictor)
|
|
|
+ , mAllow1918(true)
|
|
|
+ , mHasConnected(false)
|
|
|
+ , mPrimaryConnectedOK(false)
|
|
|
+ , mBackupConnectedOK(false)
|
|
|
+ , mFreeToUse(true)
|
|
|
+ , mPrimaryStreamStatus(NS_OK)
|
|
|
+ , mFastOpenInProgress(false)
|
|
|
+@@ -4628,16 +4715,25 @@ nsHalfOpenSocket::SetupConn(nsIAsyncOutp
|
|
|
+ if (nullTrans) {
|
|
|
+ conn->BootstrapTimings(nullTrans->Timings());
|
|
|
+ }
|
|
|
+
|
|
|
+ // Some capabilities are needed before a transaciton actually gets
|
|
|
+ // scheduled (e.g. how to negotiate false start)
|
|
|
+ conn->SetTransactionCaps(mTransaction->Caps());
|
|
|
+
|
|
|
++ if (mUrgentStart) {
|
|
|
++ // We deliberately leave this flag unset on the connection when
|
|
|
++ // this half-open was not marked urgent to let the first transaction
|
|
|
++ // dispatched on the connection set it. Then we don't need to update
|
|
|
++ // all the speculative connect APIs to pass the urgency flag while
|
|
|
++ // we still get nearly (if not exactly) the same result.
|
|
|
++ conn->SetUrgentStartPreferred(true);
|
|
|
++ }
|
|
|
++
|
|
|
+ NetAddr peeraddr;
|
|
|
+ nsCOMPtr<nsIInterfaceRequestor> callbacks;
|
|
|
+ mTransaction->GetSecurityCallbacks(getter_AddRefs(callbacks));
|
|
|
+ nsresult rv;
|
|
|
+ if (out == mStreamOut) {
|
|
|
+ TimeDuration rtt = TimeStamp::Now() - mPrimarySynStarted;
|
|
|
+ rv = conn->Init(mEnt->mConnInfo,
|
|
|
+ gHttpHandler->ConnMgr()->mMaxRequestDelay,
|
|
|
+@@ -4791,17 +4887,17 @@ nsHalfOpenSocket::SetupConn(nsIAsyncOutp
|
|
|
+ } else {
|
|
|
+ conn->SetFastOpenStatus(mFastOpenStatus);
|
|
|
+ mFastOpenStatus = TFO_BACKUP_CONN; // Set this to TFO_BACKUP_CONN so
|
|
|
+ // that if a backup connection is
|
|
|
+ // established we do not report
|
|
|
+ // values twice.
|
|
|
+ }
|
|
|
+
|
|
|
+- // If this halfOpenConn was speculative, but at the ende the conn got a
|
|
|
++ // If this halfOpenConn was speculative, but at the end the conn got a
|
|
|
+ // non-null transaction than this halfOpen is not speculative anymore!
|
|
|
+ if (conn->Transaction() && !conn->Transaction()->IsNullTransaction()) {
|
|
|
+ Claim();
|
|
|
+ }
|
|
|
+
|
|
|
+ return rv;
|
|
|
+ }
|
|
|
+
|
|
|
+@@ -4957,16 +5053,24 @@ nsHttpConnectionMgr::nsHalfOpenSocket::G
|
|
|
+ mTransaction->GetSecurityCallbacks(getter_AddRefs(callbacks));
|
|
|
+ if (callbacks)
|
|
|
+ return callbacks->GetInterface(iid, result);
|
|
|
+ }
|
|
|
+ return NS_ERROR_NO_INTERFACE;
|
|
|
+ }
|
|
|
+
|
|
|
+ bool
|
|
|
++nsHttpConnectionMgr::nsHalfOpenSocket::AcceptsTransaction(nsHttpTransaction * trans)
|
|
|
++{
|
|
|
++ // When marked as urgent start, only accept urgent start marked transactions.
|
|
|
++ // Otherwise, accept any kind of transaction.
|
|
|
++ return !mUrgentStart || (trans->Caps() & nsIClassOfService::UrgentStart);
|
|
|
++}
|
|
|
++
|
|
|
++bool
|
|
|
+ nsHttpConnectionMgr::nsHalfOpenSocket::Claim()
|
|
|
+ {
|
|
|
+ if (mSpeculative) {
|
|
|
+ mSpeculative = false;
|
|
|
+ uint32_t flags;
|
|
|
+ if (mSocketTransport && NS_SUCCEEDED(mSocketTransport->GetConnectionFlags(&flags))) {
|
|
|
+ flags &= ~nsISocketTransport::DISABLE_RFC1918;
|
|
|
+ mSocketTransport->SetConnectionFlags(flags);
|
|
|
+diff --git a/netwerk/protocol/http/nsHttpConnectionMgr.h b/netwerk/protocol/http/nsHttpConnectionMgr.h
|
|
|
+--- a/netwerk/protocol/http/nsHttpConnectionMgr.h
|
|
|
++++ b/netwerk/protocol/http/nsHttpConnectionMgr.h
|
|
|
+@@ -391,17 +391,18 @@ private:
|
|
|
+ NS_DECL_NSIINTERFACEREQUESTOR
|
|
|
+ NS_DECL_NSITIMERCALLBACK
|
|
|
+ NS_DECL_NSINAMED
|
|
|
+
|
|
|
+ nsHalfOpenSocket(nsConnectionEntry *ent,
|
|
|
+ nsAHttpTransaction *trans,
|
|
|
+ uint32_t caps,
|
|
|
+ bool speculative,
|
|
|
+- bool isFromPredictor);
|
|
|
++ bool isFromPredictor,
|
|
|
++ bool urgentStart);
|
|
|
+
|
|
|
+ MOZ_MUST_USE nsresult SetupStreams(nsISocketTransport **,
|
|
|
+ nsIAsyncInputStream **,
|
|
|
+ nsIAsyncOutputStream **,
|
|
|
+ bool isBackup);
|
|
|
+ MOZ_MUST_USE nsresult SetupPrimaryStreams();
|
|
|
+ MOZ_MUST_USE nsresult SetupBackupStreams();
|
|
|
+ void SetupBackupTimer();
|
|
|
+@@ -419,16 +420,20 @@ private:
|
|
|
+
|
|
|
+ bool Allow1918() { return mAllow1918; }
|
|
|
+ void SetAllow1918(bool val) { mAllow1918 = val; }
|
|
|
+
|
|
|
+ bool HasConnected() { return mHasConnected; }
|
|
|
+
|
|
|
+ void PrintDiagnostics(nsCString &log);
|
|
|
+
|
|
|
++ // Checks whether the transaction can be dispatched using this
|
|
|
++ // half-open's connection. If this half-open is marked as urgent-start,
|
|
|
++ // it only accepts urgent start transactions. Call only before Claim().
|
|
|
++ bool AcceptsTransaction(nsHttpTransaction* trans);
|
|
|
+ bool Claim();
|
|
|
+ void Unclaim();
|
|
|
+
|
|
|
+ bool FastOpenEnabled() override;
|
|
|
+ nsresult StartFastOpen() override;
|
|
|
+ void SetFastOpenConnected(nsresult, bool aWillRetry) override;
|
|
|
+ void FastOpenNotSupported() override;
|
|
|
+ void SetFastOpenStatus(uint8_t tfoStatus) override;
|
|
|
+@@ -455,16 +460,20 @@ private:
|
|
|
+ // SpeculativeConnect(). It is cleared when a transaction would normally
|
|
|
+ // start a new connection from scratch but instead finds this one in
|
|
|
+ // the half open list and claims it for its own use. (which due to
|
|
|
+ // the vagaries of scheduling from the pending queue might not actually
|
|
|
+ // match up - but it prevents a speculative connection from opening
|
|
|
+ // more connections that are needed.)
|
|
|
+ bool mSpeculative;
|
|
|
+
|
|
|
++ // If created with a non-null urgent transaction, remember it, so we can
|
|
|
++ // mark the connection as urgent rightaway it's created.
|
|
|
++ bool mUrgentStart;
|
|
|
++
|
|
|
+ // mIsFromPredictor is set if the socket originated from the network
|
|
|
+ // Predictor. It is used to gather data on used speculative
|
|
|
+ // connections from the predictor.
|
|
|
+ bool mIsFromPredictor;
|
|
|
+
|
|
|
+ bool mAllow1918;
|
|
|
+
|
|
|
+ TimeStamp mPrimarySynStarted;
|
|
|
+@@ -577,31 +586,35 @@ private:
|
|
|
+ // Return |mMaxPersistConnsPerProxy| or |mMaxPersistConnsPerHost|,
|
|
|
+ // depending whether the proxy is used.
|
|
|
+ uint32_t MaxPersistConnections(nsConnectionEntry *ent) const;
|
|
|
+
|
|
|
+ bool AtActiveConnectionLimit(nsConnectionEntry *, uint32_t caps);
|
|
|
+ MOZ_MUST_USE nsresult TryDispatchTransaction(nsConnectionEntry *ent,
|
|
|
+ bool onlyReusedConnection,
|
|
|
+ PendingTransactionInfo *pendingTransInfo);
|
|
|
++ MOZ_MUST_USE nsresult TryDispatchTransactionOnIdleConn(nsConnectionEntry *ent,
|
|
|
++ PendingTransactionInfo *pendingTransInfo,
|
|
|
++ bool respectUrgency,
|
|
|
++ bool *allUrgent = nullptr);
|
|
|
+ MOZ_MUST_USE nsresult DispatchTransaction(nsConnectionEntry *,
|
|
|
+ nsHttpTransaction *,
|
|
|
+ nsHttpConnection *);
|
|
|
+ MOZ_MUST_USE nsresult DispatchAbstractTransaction(nsConnectionEntry *,
|
|
|
+ nsAHttpTransaction *,
|
|
|
+ uint32_t,
|
|
|
+ nsHttpConnection *,
|
|
|
+ int32_t);
|
|
|
+ bool RestrictConnections(nsConnectionEntry *);
|
|
|
+ MOZ_MUST_USE nsresult ProcessNewTransaction(nsHttpTransaction *);
|
|
|
+ MOZ_MUST_USE nsresult EnsureSocketThreadTarget();
|
|
|
+ void ClosePersistentConnections(nsConnectionEntry *ent);
|
|
|
+ MOZ_MUST_USE nsresult CreateTransport(nsConnectionEntry *,
|
|
|
+ nsAHttpTransaction *, uint32_t, bool,
|
|
|
+- 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
|